Add help overlay with keyboard shortcuts (h/F1/?)
Full-screen popup showing all keybindings grouped by category: navigation, sorting, process management, and general controls. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
79
systats.py
79
systats.py
@@ -437,6 +437,37 @@ C_POPUP_BG = 12
|
||||
C_POPUP_HL = 13
|
||||
|
||||
|
||||
HELP_LINES = [
|
||||
("NAVIGATION", ""),
|
||||
("j / Down", "Move cursor down"),
|
||||
("k / Up", "Move cursor up"),
|
||||
("PgDn", "Scroll down 20"),
|
||||
("PgUp", "Scroll up 20"),
|
||||
("Home", "Go to top"),
|
||||
("End", "Go to bottom"),
|
||||
("", ""),
|
||||
("SORTING", ""),
|
||||
("c", "Sort by CPU%"),
|
||||
("m", "Sort by MEM%"),
|
||||
("p", "Sort by PID"),
|
||||
("n", "Sort by name"),
|
||||
("r", "Reverse sort order"),
|
||||
("", ""),
|
||||
("PROCESS MGMT", ""),
|
||||
("T", "Send SIGTERM to process"),
|
||||
("K", "Send SIGKILL to process"),
|
||||
("F9", "Signal menu (choose signal)"),
|
||||
("+ / F8", "Renice process"),
|
||||
("- / F7", "Renice process (negative)"),
|
||||
("d / F5 / Enter", "Process details"),
|
||||
("/ / f", "Filter processes"),
|
||||
("", ""),
|
||||
("GENERAL", ""),
|
||||
("h / F1 / ?", "Toggle this help"),
|
||||
("q / Q / Esc", "Quit"),
|
||||
]
|
||||
|
||||
|
||||
class ProcessManager:
|
||||
"""Interactive process management: kill, nice, filter, details."""
|
||||
|
||||
@@ -586,6 +617,7 @@ class Renderer:
|
||||
self.data = data
|
||||
self.scroll_offset = 0
|
||||
self.proc_mgr = ProcessManager()
|
||||
self.show_help = False
|
||||
|
||||
def draw(self):
|
||||
self.scr.erase()
|
||||
@@ -623,6 +655,10 @@ class Renderer:
|
||||
# Processes (rest of screen)
|
||||
self._draw_processes(y, 0, w, h - y)
|
||||
|
||||
# Help overlay
|
||||
if self.show_help:
|
||||
self._draw_help(h, w)
|
||||
|
||||
self.scr.refresh()
|
||||
|
||||
def _draw_header(self, y, w):
|
||||
@@ -1029,6 +1065,41 @@ class Renderer:
|
||||
" Enter:apply Esc:cancel ".center(popup_w),
|
||||
curses.color_pair(C_POPUP_BG) | curses.A_DIM)
|
||||
|
||||
def _draw_help(self, h, w):
|
||||
popup_w = min(w - 4, 52)
|
||||
popup_h = min(h - 2, len(HELP_LINES) + 4)
|
||||
mx = (w - popup_w) // 2
|
||||
my = (h - popup_h) // 2
|
||||
|
||||
# Background
|
||||
for row in range(popup_h):
|
||||
safe_addstr(self.scr, my + row, mx, " " * popup_w, curses.color_pair(C_POPUP_BG))
|
||||
|
||||
# Title
|
||||
title = " SYSTATS - Keyboard Shortcuts "
|
||||
safe_addstr(self.scr, my, mx, title.center(popup_w),
|
||||
curses.color_pair(C_POPUP_HL) | curses.A_BOLD)
|
||||
safe_addstr(self.scr, my + 1, mx, "\u2500" * popup_w, curses.color_pair(C_POPUP_BG))
|
||||
|
||||
for i, (key, desc) in enumerate(HELP_LINES):
|
||||
row_y = my + 2 + i
|
||||
if row_y >= my + popup_h - 1:
|
||||
break
|
||||
if not key and not desc:
|
||||
continue
|
||||
if not desc:
|
||||
# Section header
|
||||
safe_addstr(self.scr, row_y, mx + 2, key,
|
||||
curses.color_pair(C_POPUP_HL) | curses.A_BOLD)
|
||||
else:
|
||||
line = f" {key:<20s} {desc}"
|
||||
safe_addstr(self.scr, row_y, mx, line[:popup_w].ljust(popup_w),
|
||||
curses.color_pair(C_POPUP_BG))
|
||||
|
||||
safe_addstr(self.scr, my + popup_h - 1, mx,
|
||||
" Press h, F1 or ? to close ".center(popup_w),
|
||||
curses.color_pair(C_POPUP_BG) | curses.A_DIM)
|
||||
|
||||
def _draw_filter_bar(self, y, x, w):
|
||||
pm = self.proc_mgr
|
||||
bar = f" Filter: {pm.filter_text}_ "
|
||||
@@ -1060,6 +1131,12 @@ def main(stdscr):
|
||||
processes = pm.filtered_processes(data.processes)
|
||||
max_idx = max(0, len(processes) - 1)
|
||||
|
||||
# ── Help overlay ──
|
||||
if renderer.show_help:
|
||||
if key in (ord("h"), ord("?"), curses.KEY_F1, 27):
|
||||
renderer.show_help = False
|
||||
continue
|
||||
|
||||
# ── Filter mode input ──
|
||||
if pm.filter_mode:
|
||||
if key == 27: # ESC
|
||||
@@ -1122,6 +1199,8 @@ def main(stdscr):
|
||||
break
|
||||
elif key == 27: # ESC
|
||||
break
|
||||
elif key in (ord("h"), ord("?"), curses.KEY_F1):
|
||||
renderer.show_help = True
|
||||
elif key == ord("c"):
|
||||
data.process_sort = "cpu"
|
||||
data.process_sort_reverse = True
|
||||
|
||||
Reference in New Issue
Block a user