From b2f221691f88af382c30b6a1d9060b75ea7c19dd Mon Sep 17 00:00:00 2001 From: blasty Date: Sat, 25 Jul 2026 18:59:43 +0200 Subject: decomp: repaint on a same-viewport jump (Esc back looked like it did nothing) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Esc in the pseudocode view navigated correctly but the pane kept showing the old cursor line until you pressed something else. The listing view was fine because its path goes through load(), which relayouts and repaints. DecompView.goto() sets `cursor`, which is reactive(repaint=False), and then leaves redrawing to _apply_scroll — but that only repaints via call_after_refresh, which needs a refresh to actually happen. Jump somewhere inside the viewport already on screen (exactly what Esc-back within a function does) and the scroll doesn't change, so nothing asked the widget to redraw: the old highlight stayed and the status line had already updated, which is why it looked like the jump half-worked. _move() doesn't hit this because it repaints the old and new rows via _refresh_lines. goto() now refreshes explicitly. Verification note: a render_line-level probe CANNOT see this bug — render_line reads self.cursor live, so it always reports the new position. The staleness is in Textual's compositor cache, which only a repaint request clears. Verified by spying on the widget's refresh instead: a same-viewport goto now requests one (it requested none before). Suite 192/0. --- idatui/app.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/idatui/app.py b/idatui/app.py index e96483b..db237cb 100644 --- a/idatui/app.py +++ b/idatui/app.py @@ -1574,6 +1574,13 @@ class DecompView(SearchMixin, NavMixin, ColumnCursor, ScrollView, can_focus=True else: scroll_x = sx self._apply_scroll(min(max(scroll_y, 0), max(total - 1, 0)), max(scroll_x, 0)) + # `cursor` is reactive(repaint=False) and _apply_scroll only repaints via + # call_after_refresh, so a jump that lands in the SAME viewport (Esc back + # to another spot in the function already on screen) moved the cursor + # with nothing to redraw it — the pane kept showing the old highlight + # until the next keypress. Repaint here; _move does the same via + # _refresh_lines. + self.refresh() self._after_cursor_move() def get_loading_widget(self): # type: ignore[override] -- cgit v1.3.1-sl0p