use erase() instead of clear() in per-keystroke TUI redraw loops

clear() forces a full physical screen repaint on the next refresh();
erase() just blanks the buffer content and lets curses diff against
what's already on the terminal, sending only the changed cells. The
main cert list and the cert-entry form both redraw on every keystroke,
so clear() there meant retransmitting the whole screen on every arrow
key / typed character — slow and flickery over a low-bandwidth link
like a serial console.

One-shot dialogs (show_confirm, _msg, _error) draw once and don't
loop-redraw, so they keep clear() as-is — no benefit to changing them
and it's one less thing to get wrong.

Also handle curses.KEY_RESIZE explicitly in the main list loop: force
one real clear() right after a detected resize, since erase()'s diff
against the pre-resize screen model isn't reliable across a genuine
dimension change. Screen-size changes were already picked up on the
next redraw before this (draw() runs unconditionally every loop
iteration), this just guarantees a clean repaint at the moment of the
actual resize instead of trusting the diff engine through it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Vlad Doloman
2026-07-08 17:45:13 +03:00
parent 92d512f0d2
commit 2640dbf81d
3 changed files with 48 additions and 2 deletions

View File

@@ -749,7 +749,7 @@ def show_cert_form(
curses.curs_set(1)
while True:
win.clear()
win.erase() # see show_main_screen's draw() for why not clear()
draw_box(win, "Certificate Details")
for name in _FORM_FIELDS:
fy = _FORM_FIELD_Y[name]
@@ -897,7 +897,11 @@ def show_main_screen(
def menu_item(idx): return _MENU_ITEMS[idx - n_certs] if idx >= n_certs else None
def draw():
stdscr.clear()
# erase() (not clear()) so refresh() only transmits the cells that
# actually changed instead of repainting the whole screen on every
# keystroke — clear() forces a full repaint and is slow/flickery
# over a low-bandwidth link like a serial console.
stdscr.erase()
sh, sw = stdscr.getmaxyx()
# Header bar — shows current filter mode
@@ -967,6 +971,13 @@ def show_main_screen(
draw()
key = stdscr.getch()
if key == curses.KEY_RESIZE:
# Force one true full repaint on the actual new dimensions —
# erase()+refresh() diffs against the pre-resize screen model,
# which isn't reliable across a genuine size change.
stdscr.clear()
continue
if key == 27: # Esc
if esc_pending:
return ScreenResult(action=Action.EXIT)