Skip to content

Commit fcf1bd5

Browse files
authored
Merge pull request #8 from jtpio/query-commands
Support discovering commands with a query
2 parents 5d5e158 + 33d595e commit fcf1bd5

File tree

2 files changed

+58
-7
lines changed

2 files changed

+58
-7
lines changed

jupyterlab_commands_toolkit/tools.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,26 +85,53 @@ def handle_command_result(event_data):
8585
future.set_result(event_data)
8686

8787

88-
async def list_all_commands() -> dict:
88+
async def list_all_commands(query: Optional[str] = None) -> dict:
8989
"""
9090
Retrieve a list of all available JupyterLab commands.
9191
9292
This function emits a request to the JupyterLab frontend to retrieve all
9393
registered commands in the application. It waits for the response and
9494
returns the complete list of available commands with their metadata.
9595
96+
Args:
97+
query (Optional[str], optional): An optional search query to filter commands.
98+
When provided, only commands whose ID, label,
99+
caption, or description contain the query string
100+
(case-insensitive) will be returned. If None or
101+
omitted, all commands will be returned.
102+
Defaults to None.
103+
96104
Returns:
97105
dict: A dictionary containing the command list response from JupyterLab.
98106
The structure typically includes:
99107
- success (bool): Whether the operation succeeded
100-
- commands (list): List of available command objects, with arguments and types
108+
- commandCount (int): Number of commands returned
109+
- commands (list): List of available command objects, each with:
110+
- id (str): The command identifier
111+
- label (str, optional): Human-readable command label
112+
- caption (str, optional): Short description
113+
- description (str, optional): Detailed usage information
114+
- args (dict, optional): Command argument schema
101115
- error (str, optional): Error message if the operation failed
102116
103117
Raises:
104118
asyncio.TimeoutError: If the frontend doesn't respond within the timeout period
119+
120+
Examples:
121+
>>> # Get all commands
122+
>>> await list_all_commands()
123+
{'success': True, 'commandCount': 150, 'commands': [...]}
124+
125+
>>> # Filter commands by query
126+
>>> await list_all_commands(query="notebook")
127+
{'success': True, 'commandCount': 25, 'commands': [...]}
105128
"""
129+
args = {}
130+
if query is not None:
131+
args["query"] = query
132+
106133
return await emit_and_wait_for_result(
107-
{"name": "jupyterlab-commands-toolkit:list-all-commands", "args": {}}
134+
{"name": "jupyterlab-commands-toolkit:list-all-commands", "args": args}
108135
)
109136

110137

src/index.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,9 @@ const plugin: JupyterFrontEndPlugin<void> = {
103103
describedBy: {
104104
args: {}
105105
},
106-
execute: async () => {
106+
execute: async (args: any) => {
107+
const query = args['query'] as string | undefined;
108+
107109
const commandList: Array<{
108110
id: string;
109111
label?: string;
@@ -112,23 +114,45 @@ const plugin: JupyterFrontEndPlugin<void> = {
112114
args?: any;
113115
}> = [];
114116

117+
// Get all command IDs
115118
const commandIds = commands.listCommands();
116119

117120
for (const id of commandIds) {
121+
// Get command metadata using various CommandRegistry methods
118122
const description = await commands.describedBy(id);
119123
const label = commands.label(id);
120124
const caption = commands.caption(id);
121125
const usage = commands.usage(id);
122126

123-
commandList.push({
127+
const command = {
124128
id,
125129
label: label || undefined,
126130
caption: caption || undefined,
127131
description: usage || undefined,
128132
args: description?.args || undefined
129-
});
133+
};
134+
135+
// Filter by query if provided
136+
if (query) {
137+
const searchTerm = query.toLowerCase();
138+
const matchesQuery =
139+
id.toLowerCase().includes(searchTerm) ||
140+
label?.toLowerCase().includes(searchTerm) ||
141+
caption?.toLowerCase().includes(searchTerm) ||
142+
usage?.toLowerCase().includes(searchTerm);
143+
144+
if (matchesQuery) {
145+
commandList.push(command);
146+
}
147+
} else {
148+
commandList.push(command);
149+
}
130150
}
131-
return commandList;
151+
return {
152+
success: true,
153+
commandCount: commandList.length,
154+
commands: commandList
155+
};
132156
}
133157
});
134158
}

0 commit comments

Comments
 (0)