diff --git a/src/command_palette.py b/src/command_palette.py index 5c369a1a..97a1498e 100644 --- a/src/command_palette.py +++ b/src/command_palette.py @@ -101,3 +101,57 @@ def _count_gaps(query: str, target: str) -> int: last_match = ti qi += 1 return gaps + + +def render_palette_modal(app: Any, commands: List[Command]) -> None: + if not getattr(app, "show_command_palette", False): + return + + from imgui_bundle import imgui + + viewport = imgui.get_main_viewport() + center = viewport.get_center() + imgui.set_next_window_pos((center.x - 300, center.y - 200)) + imgui.set_next_window_size((600, 400)) + + if not hasattr(app, "_command_palette_query"): + app._command_palette_query = "" + if not hasattr(app, "_command_palette_selected"): + app._command_palette_selected = 0 + + if imgui.is_key_pressed(imgui.Key.escape): + app.show_command_palette = False + return + + expanded, _ = imgui.begin("Command Palette##manual_slop", closable=True) + if not expanded: + app.show_command_palette = False + imgui.end() + return + + imgui.set_next_item_width(-1) + changed, app._command_palette_query = imgui.input_text("##query", app._command_palette_query, 256) + imgui.set_keyboard_focus_here() + + results = fuzzy_match(app._command_palette_query, commands, top_n=20) + + if imgui.begin_child("##results", (0, -1)): + for i, scored in enumerate(results): + is_selected = (i == app._command_palette_selected) + label = f"[{scored.command.category}] {scored.command.title}" + clicked, _ = imgui.selectable(label, is_selected) + if clicked: + app._command_palette_selected = i + if is_selected: + imgui.set_item_default_focus() + if imgui.is_key_pressed(imgui.Key.enter) or imgui.is_key_pressed(imgui.Key.keypad_enter): + if scored.command.action: + scored.command.action(app) + app.show_command_palette = False + app._command_palette_query = "" + app._command_palette_selected = 0 + if not results: + imgui.text_disabled("No matching commands.") + imgui.end_child() + + imgui.end()