Add arrow key scrolling for output when focused

- Up/Down move cursor one line (scrolls view)
- Page Up/Down move 20 lines at a time
- Home/End jump to top/bottom
- Keys only active when output buffer is focused (Tab to switch)
- Updated help text with scroll shortcuts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
dullfig 2026-01-11 15:11:07 -08:00
parent fbb6c28ab7
commit 10daf0ce70

View file

@ -201,6 +201,54 @@ class TUIConsole:
"""Switch focus between output and input.""" """Switch focus between output and input."""
event.app.layout.focus_previous() event.app.layout.focus_previous()
# Arrow keys for scrolling output (move cursor to scroll view)
@kb.add("up", filter=lambda: self.app.layout.has_focus(self.output.buffer))
def handle_output_up(event):
"""Scroll output up."""
buf = self.output.buffer
# Move cursor up one line
doc = buf.document
if doc.cursor_position_row > 0:
new_pos = doc.translate_row_col_to_index(doc.cursor_position_row - 1, 0)
buf.cursor_position = new_pos
@kb.add("down", filter=lambda: self.app.layout.has_focus(self.output.buffer))
def handle_output_down(event):
"""Scroll output down."""
buf = self.output.buffer
doc = buf.document
if doc.cursor_position_row < doc.line_count - 1:
new_pos = doc.translate_row_col_to_index(doc.cursor_position_row + 1, 0)
buf.cursor_position = new_pos
@kb.add("pageup", filter=lambda: self.app.layout.has_focus(self.output.buffer))
def handle_output_pageup(event):
"""Scroll output up a page."""
buf = self.output.buffer
doc = buf.document
new_row = max(0, doc.cursor_position_row - 20)
new_pos = doc.translate_row_col_to_index(new_row, 0)
buf.cursor_position = new_pos
@kb.add("pagedown", filter=lambda: self.app.layout.has_focus(self.output.buffer))
def handle_output_pagedown(event):
"""Scroll output down a page."""
buf = self.output.buffer
doc = buf.document
new_row = min(doc.line_count - 1, doc.cursor_position_row + 20)
new_pos = doc.translate_row_col_to_index(new_row, 0)
buf.cursor_position = new_pos
@kb.add("home", filter=lambda: self.app.layout.has_focus(self.output.buffer))
def handle_output_home(event):
"""Scroll to top of output."""
self.output.buffer.cursor_position = 0
@kb.add("end", filter=lambda: self.app.layout.has_focus(self.output.buffer))
def handle_output_end(event):
"""Scroll to bottom of output."""
self.output.buffer.cursor_position = len(self.output.buffer.text)
# Output uses BufferControl for native scrolling # Output uses BufferControl for native scrolling
output_control = BufferControl( output_control = BufferControl(
buffer=self.output.buffer, buffer=self.output.buffer,
@ -422,9 +470,10 @@ class TUIConsole:
self.print_raw("Shortcuts:", "output.system") self.print_raw("Shortcuts:", "output.system")
self.print_raw(" Ctrl+C / Ctrl+D Quit", "output.dim") self.print_raw(" Ctrl+C / Ctrl+D Quit", "output.dim")
self.print_raw(" Ctrl+L Clear output", "output.dim") self.print_raw(" Ctrl+L Clear output", "output.dim")
self.print_raw(" Up/Down Command history", "output.dim") self.print_raw(" Up/Down Command history (in input)", "output.dim")
self.print_raw(" Tab Switch focus (input/output)", "output.dim") self.print_raw(" Tab Switch focus (input/output)", "output.dim")
self.print_raw(" Arrow keys Scroll when output focused", "output.dim") self.print_raw(" Up/Down/PgUp/PgDn Scroll (when output focused)", "output.dim")
self.print_raw(" Home/End Jump to top/bottom of output", "output.dim")
async def _cmd_status(self, args: str): async def _cmd_status(self, args: str):
"""Show status.""" """Show status."""