Skip to content

Fix panels not redrawing on async updates#9

Merged
bluestreak01 merged 3 commits intomasterfrom
vi_bugfix
Mar 29, 2026
Merged

Fix panels not redrawing on async updates#9
bluestreak01 merged 3 commits intomasterfrom
vi_bugfix

Conversation

@bluestreak01
Copy link
Copy Markdown
Member

@bluestreak01 bluestreak01 commented Mar 29, 2026

Summary

  • Bug: CI panel showed "loading" forever after pressing F2 or expanding a tree node. Shell and Claude panels had the same issue — async results arrived but the screen never refreshed until a mouse click.
  • Root cause: Focused panel handlers (handle_ci_action, handle_claude_action, handle_shell_action) intercepted Action::Tick and polled async sources, but never set self.dirty = true. The event loop only redraws when dirty, so results were silently dropped.
  • Fix: Extract all async polling into a single poll_async() method called at the top of handle_action() before focus-based dispatch. This ensures polling and dirty-flagging happen exactly once per tick regardless of which panel has focus.

What changed

The dispatch flow was:

handle_action(Tick)
  ├── if ci_focused → handle_ci_action(Tick) → poll + NO dirty → return
  ├── if claude_focused → handle_claude_action(Tick) → poll + NO dirty → return
  └── main match { Tick => poll + dirty ✓ }   ← never reached when focused

Now:

handle_action(Tick)
  ├── poll_async()  → poll everything + dirty ✓ → return
  │   (CI, Claude, Shell, git, watcher, archive, file search)
  └── handle_action(keypress)
      ├── if ci_focused → handle_ci_action(keypress)  ← input only
      └── main match { ... }

Net -79 lines — duplicated polling code across 4 handlers consolidated into one method.

Test plan

  • F2 to open CI panel — checks load and render without clicking
  • Expand a CI check node — steps appear without clicking
  • Ctrl+O shell — output renders in real time
  • F12 Claude — output renders in real time
  • Ctrl+S file search — results stream in while searching

🤖 Generated with Claude Code

bluestreak01 and others added 3 commits March 29, 2026 02:11
Focused panel handlers (CI, Claude, Shell) intercepted Tick actions
and polled async sources, but never set `self.dirty = true`, so the
event loop skipped redraws. This caused CI checks to show "loading"
forever and panels to appear frozen until a mouse click forced a
redraw.

Refactor: extract `poll_async()` from duplicated Tick arms in 4
handlers into a single method called once at the top of
`handle_action()`, before focus-based input dispatch. This separates
the global "time passed, check the world" concern from the
per-panel "route this keypress" concern, eliminating ~80 lines of
copy-pasted polling code and preventing this class of bug from
recurring.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bluestreak01 bluestreak01 merged commit 76deb4f into master Mar 29, 2026
@bluestreak01 bluestreak01 deleted the vi_bugfix branch April 6, 2026 05:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant