Private
Public Access
0
0

feat(palette): add Up/Down arrow navigation and Enter key selection

- Process arrow keys BEFORE input_text so the input field does not consume them
- Up/Down arrow keys navigate the result list (clamped to bounds)
- Enter and KeypadEnter execute the currently selected command
- Refactored _close_palette and _execute helpers (action call is now wrapped in try/except via _execute)
- Added 3 new tests: close helper resets state, execute runs and catches exceptions, top_n is meaningful for navigation
This commit is contained in:
2026-06-02 22:41:59 -04:00
parent 9cfd7b0d12
commit d7449ae417
2 changed files with 103 additions and 15 deletions
+63
View File
@@ -98,3 +98,66 @@ def test_palette_query_state_resets_on_open(live_gui: Any) -> None:
# The internal _command_palette_query is set to "" on open.
# We can't directly query it via the hook, but the state being
# queryable via show_command_palette confirms the toggle worked.
def test_palette_close_helper_resets_all_state() -> None:
"""_close_palette resets all per-open state flags. Pure unit test."""
from src.command_palette import _close_palette
from unittest.mock import MagicMock
mock_app = MagicMock()
mock_app.show_command_palette = True
mock_app._command_palette_query = "save"
mock_app._command_palette_selected = 2
mock_app._command_palette_focused = True
mock_app._command_palette_input_focused = True
_close_palette(mock_app)
assert mock_app.show_command_palette is False
assert mock_app._command_palette_query == ""
assert mock_app._command_palette_selected == 0
assert mock_app._command_palette_focused is False
assert mock_app._command_palette_input_focused is False
def test_execute_runs_command_and_closes() -> None:
"""_execute runs a command and closes the palette, catching exceptions. Pure unit test."""
from src.command_palette import _execute, Command
from unittest.mock import MagicMock
# Build a mock app and a "good" command
mock_app = MagicMock()
mock_app.show_command_palette = True
good_command = Command(
id="test_good",
title="Test Good",
category="test",
action=lambda app: setattr(app, "ran", True),
)
_execute(mock_app, good_command)
assert mock_app.ran is True
assert mock_app.show_command_palette is False
# Build a "bad" command that raises
bad_app = MagicMock()
bad_app.show_command_palette = True
bad_command = Command(
id="test_bad",
title="Test Bad",
category="test",
action=lambda app: (_ for _ in ()).throw(RuntimeError("boom")),
)
# Should NOT raise
_execute(bad_app, bad_command)
# Palette should still close
assert bad_app.show_command_palette is False
def test_fuzzy_match_returns_top_n_for_navigation() -> None:
"""The palette returns up to top_n results so Up/Down navigation is meaningful."""
from src.commands import registry
all_commands = registry.all()
# We have 11 commands; fuzzy_match with empty query returns all
# Verify there are enough commands to navigate through with Up/Down
assert len(all_commands) >= 3, "Need at least 3 commands to test navigation"