dev-resources.site
for different kinds of informations.
Develop a ulauncher extension with a command database
Published at
1/6/2025
Categories
vim
ulauncher
python
json
Author
ubuntupunk
Author
10 person written this
ubuntupunk
open
Over the weekend, I picked up a project via Reddit involving a plugin for the Flow Launcher. I created a fzf and rofi version for my Ubuntu Linux environment, and then thought, how hard can it be to port it to uLauncher?
Here I document what I did.
1. Inside ~/.local/share/ulauncher/extensions/
create a new dir. In my case, I created ~/.local/share/ulauncher/extensions/com.github.ubuntupunk.ulauncher-vim
2. Touch the following files:
βββ images
β βββ icon.png
βββ versions.json
βββ manifest.json
βββ main.py
3. In versions.json
place the following boilerplate:
[
{"required_api_version": "2", "commit": "master"}
]
4. In manifest.json
{
"required_api_version": "2",
"name": "Demo extension",
"description": "Extension Description",
"developer_name": "John Doe",
"icon": "images/icon.png",
"options": {
"query_debounce": 0.1
},
"preferences": [
{
"id": "demo_kw",
"type": "keyword",
"name": "Demo",
"description": "Demo extension",
"default_value": "dm"
}
]
}
5. In main.py
from ulauncher.api.client.Extension import Extension
from ulauncher.api.client.EventListener import EventListener
from ulauncher.api.shared.event import KeywordQueryEvent, ItemEnterEvent
from ulauncher.api.shared.item.ExtensionResultItem import ExtensionResultItem
from ulauncher.api.shared.action.RenderResultListAction import RenderResultListAction
from ulauncher.api.shared.action.HideWindowAction import HideWindowAction
class DemoExtension(Extension):
def __init__(self):
super().__init__()
self.subscribe(KeywordQueryEvent, KeywordQueryEventListener())
class KeywordQueryEventListener(EventListener):
def on_event(self, event, extension):
items = []
for i in range(5):
items.append(ExtensionResultItem(icon='images/icon.png',
name='Item %s' % i,
description='Item description %s' % i,
on_enter=HideWindowAction()))
return RenderResultListAction(items)
if __name__ == '__main__':
DemoExtension().run()
6. Now edit manifest.json
{
"required_api_version": "2",
"name": "Vim Prompter",
"description": "Vim cheatsheet helper",
"developer_name": "David Robert Lewis",
"icon": "images/icon.png",
"options": {
"query_debounce": 0.1
},
"preferences": [
{
"id": "vm_kw",
"type": "keyword",
"name": "Vim",
"description": "Search for Vim commands",
"default_value": "vm"
}
]
7. Add command loading function to main.py
class VmExtension(Extension):
def load_vim_commands(self):
"""Load Vim commands from JSON file."""
package_dir = os.path.dirname(os.path.abspath(__file__))
full_path = os.path.join(package_dir, 'db', 'commands.json')
with open(full_path, 'r') as file:
return json.load(file)
def __init__(self):
super().__init__()
self.vim_commands = self.load_vim_commands()
self.subscribe(KeywordQueryEvent, KeywordQueryEventListener())
8. Create a db folder with the following:
commands.json
example structure:
{
"categories": {
"navigation": {
"name": "Navigation",
"patterns": [
"scroll",
"jump",
"goto",
"position"
],
"subcategories": {
"cursor": {
"name": "Cursor Movement",
"patterns": [
"move[s]? cursor",
"^[hjkl]$",
"^[HJKL]$",
"^[wWeEbB]$"
]
},
You can see the entire commands.json here.
9. Modify the KeywordQueryEventListener
to implement the search functionality.
class KeywordQueryEventListener(EventListener):
def on_event(self, event, extension):
query = event.get_argument() or ""
items = []
# If no query, show all commands (limited to first 8)
commands_to_show = extension.vim_commands
# If there's a query, filter commands
if query:
commands_to_show = [
cmd for cmd in extension.vim_commands
if query.lower() in cmd['command'].lower() or
query.lower() in cmd['description'].lower()
]
# Limit results to first 8 matches
for cmd in commands_to_show[:8]:
items.append(ExtensionResultItem(
icon='images/icon.png',
name=cmd['command'],
description=f"{cmd['name']} - {cmd['description']}",
on_enter=HideWindowAction()
))
return RenderResultListAction(items)
10. Add the URL opening functionality. We'll need to import webbrowser and modify the on_enter action to open the Vim command URL
from ulauncher.api.shared.action.OpenUrlAction import OpenUrlAction
class KeywordQueryEventListener(EventListener):
def on_event(self, event, extension):
query = event.get_argument() or ""
items = []
commands_to_show = extension.vim_commands
if query:
commands_to_show = [
cmd for cmd in extension.vim_commands
if query.lower() in cmd['command'].lower() or
query.lower() in cmd['description'].lower()
]
for cmd in commands_to_show[:8]:
url = f"https://vim.rtorr.com/#:~:text={cmd['rtorr_description']}"
items.append(ExtensionResultItem(
icon='images/icon.png',
name=cmd['command'],
description=f"{cmd['name']} - {cmd['description']}",
on_enter=OpenUrlAction(url)
))
return RenderResultListAction(items)
11. Key changes are:
- Added OpenUrlAction import
- Replaced HideWindowAction with OpenUrlAction
- Constructed the URL using the command's rtorr_description
12. The full project code can be viewed here:
and the ulauncher extension here
References
json Article's
30 articles in total
How to Fetch URL Content, Set It into a Dictionary, and Extract Specific Keys in iOS Shortcuts
read article
Dynamic Routes in Astro (+load parameters from JSON)
read article
Effortlessly Host Static JSON Files with JSONsilo.com
read article
How to Implement Authentication in React Using JWT (JSON Web Tokens)
read article
Converting documents for LLM processing β A modern approach
read article
Import JSON Data in Astro (with Typescript)
read article
Devise not accepting JSON Token
read article
Integration for FormatJS/react-intl: Automated Translations with doloc
read article
βDefuβ usage in unbuild source code.
read article
Converting documents for LLM processing β A modern approach
read article
How to crawl and parse JSON data with Python crawler
read article
JSON Visual Edit
read article
Develop a ulauncher extension with a command database
currently reading
Building a Smart Feedback Agent with Copilot Studio, Adaptive cards and Power Automate
read article
Simplifying JSON Validation with Ajv (Another JSON Validator)
read article
A Straightforward Guide to Building and Using aΒ JSON Database File
read article
AI prompt sample - a full chat content that demonstrates how to get a professional looking website in a few munities
read article
Fixing and Validating JSON with Ease: An In-Depth Guide
read article
Useful too to work with your JSON files - jq
read article
what is jq? a program for json files
read article
Code. Gleam. Extract fields from JSON
read article
Build an Application Without SQL Server Database (Avoiding RPrometheusedis, MongoDB, and )
read article
FAQ β Bloomer Mock Data Generator
read article
My React Journey: Day 18
read article
Working with JSON in MySQL
read article
JSON for Biggners
read article
angular and json
read article
iter.json: A Powerful and Efficient Way to Iterate and Manipulate JSON in Go
read article
This unknown Currency API is served over 50 Billion times a month !
read article
Common Data Formats in JavaScript: A Comprehensive Guide With Examples
read article
Featured ones: