fix(tui): add block cursor navigation bindings

ISSUES CLOSED: #10371
This commit is contained in:
2026-06-16 17:16:49 -04:00
committed by Forgejo
parent e7dcf03916
commit d1318b9fb2
3 changed files with 13 additions and 7 deletions
@@ -4,14 +4,8 @@ Feature: TDD Issue #10371 — Block cursor navigation (alt+up/alt+down) not impl
This test captures bug #10371: the TUI application is missing ``alt+up``
and ``alt+down`` key bindings for block cursor navigation.
The scenario is tagged ``@tdd_expected_fail`` so the underlying assertion
failure (confirming the bug exists) is inverted to a CI pass. Once the
fix for #10371 is merged, remove the ``@tdd_expected_fail`` tag from the
scenario and this test will run normally as a regression guard.
See CONTRIBUTING.md > Bug Fix Workflow > TDD Issue Test Tags.
@tdd_expected_fail
Scenario: TUI app BINDINGS includes alt+up and alt+down for block cursor navigation
Given the TUI app module is imported with mocked Textual
When I inspect the TUI app BINDINGS for block cursor navigation
+1 -1
View File
@@ -47,7 +47,7 @@ Feature: TUI App Coverage
Given a mock command router and persona state
When I instantiate the Textual TUI app
Then the app class should have CSS_PATH set to "cleveragents.tcss"
And the app class should have 4 key bindings
And the app class should have 6 key bindings
# --- compose method (lines 102-112) ---
+12
View File
@@ -278,6 +278,8 @@ if _TEXTUAL_AVAILABLE:
("ctrl+q", "quit", "Quit"),
("f1", "help", "Help"),
("ctrl+t", "cycle_preset", "Cycle Preset"),
("alt+up", "cursor_up", "Previous Block"),
("alt+down", "cursor_down", "Next Block"),
("escape", "escape", "Close Overlay"),
]
@@ -313,6 +315,7 @@ if _TEXTUAL_AVAILABLE:
settings=load_conversation_settings()
)
self._conversation_stream.bootstrap(welcome_text="CleverAgents TUI")
self._block_cursor_index: int = 0
def compose(self) -> Any:
yield _Header(show_clock=True)
@@ -375,6 +378,15 @@ if _TEXTUAL_AVAILABLE:
self._persona_state.cycle_preset(self._session.session_id)
self._refresh_persona_bar()
def action_cursor_up(self) -> None:
"""Move the block cursor to the previous transcript block."""
self._block_cursor_index = max(0, self._block_cursor_index - 1)
def action_cursor_down(self) -> None:
"""Move the block cursor to the next transcript block."""
last_index = max(0, len(self._session.transcript) - 1)
self._block_cursor_index = min(last_index, self._block_cursor_index + 1)
def action_escape(self) -> None:
prompt = self.query_one("#prompt", PromptInput)