feat: Add help popup with keyboard shortcuts triggered by "?"
This commit is contained in:
parent
8eaad2ae49
commit
78eaaf35e2
107
gtm
107
gtm
|
|
@ -145,6 +145,9 @@ class AppState:
|
|||
search_query: str = ""
|
||||
search_matches: List[int] = field(default_factory=list) # Line numbers of matches
|
||||
current_match_idx: int = -1 # Index in search_matches
|
||||
|
||||
# Help popup
|
||||
show_help: bool = False
|
||||
|
||||
# --- Actions (Controller) ---
|
||||
|
||||
|
|
@ -646,6 +649,99 @@ def draw_selection(stdscr, state):
|
|||
except curses.error:
|
||||
pass
|
||||
|
||||
def draw_help_popup(stdscr, state):
|
||||
"""Draw a popup with keyboard shortcut help."""
|
||||
if not state.show_help:
|
||||
return
|
||||
|
||||
# Calculate popup dimensions and position
|
||||
popup_width = 60
|
||||
popup_height = 20
|
||||
popup_x = max(0, (state.width - popup_width) // 2)
|
||||
popup_y = max(0, (state.height - popup_height) // 2)
|
||||
|
||||
# Draw popup border
|
||||
for y in range(popup_y, popup_y + popup_height):
|
||||
for x in range(popup_x, popup_x + popup_width):
|
||||
if y == popup_y or y == popup_y + popup_height - 1:
|
||||
# Top and bottom borders
|
||||
try:
|
||||
stdscr.addch(y, x, curses.ACS_HLINE)
|
||||
except curses.error:
|
||||
pass
|
||||
elif x == popup_x or x == popup_x + popup_width - 1:
|
||||
# Left and right borders
|
||||
try:
|
||||
stdscr.addch(y, x, curses.ACS_VLINE)
|
||||
except curses.error:
|
||||
pass
|
||||
|
||||
# Draw corners
|
||||
try:
|
||||
stdscr.addch(popup_y, popup_x, curses.ACS_ULCORNER)
|
||||
stdscr.addch(popup_y, popup_x + popup_width - 1, curses.ACS_URCORNER)
|
||||
stdscr.addch(popup_y + popup_height - 1, popup_x, curses.ACS_LLCORNER)
|
||||
stdscr.addch(popup_y + popup_height - 1, popup_x + popup_width - 1, curses.ACS_LRCORNER)
|
||||
except curses.error:
|
||||
pass
|
||||
|
||||
# Draw title
|
||||
title = " Keyboard Shortcuts "
|
||||
title_x = popup_x + (popup_width - len(title)) // 2
|
||||
try:
|
||||
stdscr.addstr(popup_y, title_x, title, curses.A_BOLD)
|
||||
except curses.error:
|
||||
pass
|
||||
|
||||
# Define help content
|
||||
help_items = [
|
||||
("Navigation", ""),
|
||||
("j / Down", "Scroll down"),
|
||||
("k / Up", "Scroll up"),
|
||||
("Space / Page Down", "Page down"),
|
||||
("b / Page Up", "Page up"),
|
||||
("h / Left", "Focus left pane"),
|
||||
("l / Right", "Focus right pane"),
|
||||
("", ""),
|
||||
("Features", ""),
|
||||
("/ (slash)", "Search in file"),
|
||||
("n", "Next search match"),
|
||||
("N", "Previous search match"),
|
||||
("c", "Next change"),
|
||||
("C", "Previous change"),
|
||||
("s", "Toggle sidebar"),
|
||||
("w", "Toggle line wrapping"),
|
||||
("L", "Toggle line numbers"),
|
||||
("q / Esc", "Quit"),
|
||||
("? (question mark)", "Show/hide this help")
|
||||
]
|
||||
|
||||
# Draw help content
|
||||
for i, (key, desc) in enumerate(help_items):
|
||||
y = popup_y + 2 + i
|
||||
if y < popup_y + popup_height - 1:
|
||||
if key == "Navigation" or key == "Features":
|
||||
# Section headers
|
||||
try:
|
||||
stdscr.addstr(y, popup_x + 2, key, curses.A_BOLD | curses.A_UNDERLINE)
|
||||
except curses.error:
|
||||
pass
|
||||
elif key:
|
||||
# Key and description
|
||||
try:
|
||||
stdscr.addstr(y, popup_x + 2, key, curses.A_BOLD)
|
||||
stdscr.addstr(y, popup_x + 16, desc)
|
||||
except curses.error:
|
||||
pass
|
||||
|
||||
# Draw footer
|
||||
footer = " Press any key to close "
|
||||
footer_x = popup_x + (popup_width - len(footer)) // 2
|
||||
try:
|
||||
stdscr.addstr(popup_y + popup_height - 1, footer_x, footer, curses.A_BOLD)
|
||||
except curses.error:
|
||||
pass
|
||||
|
||||
def draw_status_bars(stdscr, state):
|
||||
# We'll use height-1 for the single status bar
|
||||
visible_height = state.height - 1
|
||||
|
|
@ -780,6 +876,7 @@ def draw_ui(stdscr, state):
|
|||
draw_divider(stdscr, state)
|
||||
draw_status_bars(stdscr, state)
|
||||
draw_selection(stdscr, state)
|
||||
draw_help_popup(stdscr, state)
|
||||
stdscr.refresh()
|
||||
|
||||
# --- Input Handling Functions (Controller) ---
|
||||
|
|
@ -972,6 +1069,10 @@ def handle_mouse_input(stdscr, state: AppState) -> AppState:
|
|||
return state
|
||||
|
||||
def handle_keyboard_input(key, state: AppState) -> AppState:
|
||||
# If help popup is open, any key closes it
|
||||
if state.show_help:
|
||||
return replace(state, show_help=False)
|
||||
|
||||
# If in search mode, handle search input
|
||||
if state.search_mode:
|
||||
if key == 27: # Escape key - exit search mode
|
||||
|
|
@ -993,10 +1094,14 @@ def handle_keyboard_input(key, state: AppState) -> AppState:
|
|||
if key in [ord('q')]:
|
||||
return replace(state, should_exit=True)
|
||||
elif key == 27: # Escape key
|
||||
if state.is_selecting:
|
||||
if state.show_help:
|
||||
return replace(state, show_help=False)
|
||||
elif state.is_selecting:
|
||||
return replace(state, is_selecting=False, selection_start_coord=None, selection_end_coord=None)
|
||||
else:
|
||||
return replace(state, should_exit=True)
|
||||
elif key == ord('?'): # Toggle help popup
|
||||
return replace(state, show_help=not state.show_help)
|
||||
elif key == ord('/'): # Start search
|
||||
return replace(state, search_mode=True, search_query="")
|
||||
elif key == ord('s'):
|
||||
|
|
|
|||
Loading…
Reference in New Issue