jesseduffield.lazygit/pkg/gui
Stefan Haller b96b8a9753 Add RefreshBlockingInput to buffer keypresses until a refresh has landed
A refresh from the UI thread returns immediately and applies its model
and view updates as queued UI-thread callbacks. A key pressed before
those have run is handled against the stale, pre-refresh state. For most
keys that's harmless, but some handlers turn that state into git
commands: pressing space twice in quick succession in the staging panel
builds the second patch from the already-applied diff and fails with
'patch does not apply', because the refresh after the first press is
what moves the selection to the next stageable hunk.

Notably, this is not just a regression of the recent change that made
UI-thread refreshes non-blocking; the window was merely much narrower
before. A blocking refresh parked the UI thread while the scopes'
bounces were queued, and the event loop drains pending keyboard input
with priority over queued user events, so a key pressed during the
blocked window still beat the queued state updates. The guarantee that
the next keypress sees post-refresh state had already ended when the
scopes' state updates moved from worker-side mutex-guarded writes to
UI-thread bounces.

Fix it with the input-blocking mechanism we already use for commit
surgery, exposed as a new RefreshBlockingInput entry point: it begins
blocking events synchronously in the calling handler, and ends the
block from a callback that the finishing step queues behind the
refresh's own updates. Keys pressed while the refresh is in flight are
buffered and replayed, in order, against the fully refreshed state;
since a replayed key's handler re-enters this same path, a burst of
keypresses applies sequentially, each one seeing the previous one's
refresh. Unlike the old blocking refreshes, this doesn't freeze the UI
thread: rendering, spinners, resizing, and mouse scrolling keep working
while input is withheld.

Blocking input is opt-in per call site rather than the default for all
UI-thread refreshes, because most refreshes (the focus-in and startup
refreshes, say) don't produce state that the next keypress depends on,
and blocking on them would delay typing for no reason. It should also be
limited to quick, narrow-scoped refreshes: a full refresh, or any scope
that pulls in COMMITS, can take very long in large repos and should
usually not hold up input.

The staging panel's stage/discard/edit-hunk refreshes use it now.
2026-07-22 08:31:11 +02:00
..
context Capture suggestions inputs on the UI thread 2026-07-17 12:35:54 +02:00
controllers Add RefreshBlockingInput to buffer keypresses until a refresh has landed 2026-07-22 08:31:11 +02:00
filetree Clamp the commit-file tree selection when the tree is rebuilt 2026-07-07 18:09:33 +02:00
mergeconflicts Pick both hunks, not the common ancestor, in diff3 conflicts 2026-07-01 09:57:26 +02:00
modes Make Commit.Hash a getter for an unexported hash field 2025-04-29 14:57:15 +02:00
patch_exploring Copy gocui files into lazygit repo under pkg/gocui 2026-04-30 14:29:08 +02:00
popup Retire WithWaitingStatusSync 2026-07-17 12:32:32 +02:00
presentation Show renamed files in the custom patch builder 2026-07-04 13:05:09 +02:00
services/custom_commands Remove the RefreshMode field 2026-07-17 12:32:32 +02:00
status Render the app status in a single background render loop 2026-07-17 15:55:01 +02:00
style Modernize all codes 2025-11-15 10:46:23 +01:00
types Add RefreshBlockingInput to buffer keypresses until a refresh has landed 2026-07-22 08:31:11 +02:00
background.go Read the gui's per-repo pointers on the UI thread in background routines 2026-07-20 17:07:39 +02:00
command_log_panel.go Write the command log on the UI thread 2026-07-09 08:41:10 +02:00
context.go Bump gocui (and tcell) 2025-12-23 16:49:16 +01:00
context_config.go Remove some unused code 2025-07-08 15:14:45 +02:00
controllers.go Redesign the 'w' worktree-creation flow 2026-07-03 18:53:05 +02:00
dummies.go Move NewDummyCommon to pkg/common 2025-05-06 09:43:26 +02:00
editors.go Capture suggestions inputs on the UI thread 2026-07-17 12:35:54 +02:00
extras_panel.go Rename Key to Keys in Binding, KeybindingsOpts, and MenuItem 2026-05-25 15:18:18 +02:00
global_handlers.go Read lines based on scroll position instead of a fixed per-notch delta 2026-07-09 09:32:35 +02:00
gui.go Don't refuse a repo switch during a pure refresh 2026-07-20 17:07:39 +02:00
gui_common.go Add RefreshBlockingInput to buffer keypresses until a refresh has landed 2026-07-22 08:31:11 +02:00
gui_driver.go Add a way for integration tests to press keys in rapid succession 2026-07-21 22:23:58 +02:00
information_panel.go Rename ModeStatus.Description to InfoLabel 2025-08-14 17:59:38 +02:00
keybindings.go Fold remaining alt bindings into their main fields 2026-05-25 15:32:47 +02:00
layout.go Don't show a transient view whose window is not part of the layout 2026-07-17 12:07:24 +02:00
main_panels.go Run moveMainContextPairToTop before queueing main-view tasks 2026-07-02 17:32:01 +02:00
menu_panel.go Fold remaining alt bindings into their main fields 2026-05-25 15:32:47 +02:00
options_map.go Cleanup: filter out empty keybindings earlier 2026-05-28 19:26:43 +02:00
pty.go Snapshot the view width for command-task rendering on the UI thread 2026-07-17 12:35:54 +02:00
recent_repos_panel.go Remove unused field gui.IsNewRepo 2024-12-01 10:44:26 +01:00
side_panels.go Assign the transient contexts' initial windows from the side panel config 2026-07-17 12:07:24 +02:00
side_panels_test.go Assign the transient contexts' initial windows from the side panel config 2026-07-17 12:07:24 +02:00
tasks_adapter.go Snapshot the view width for command-task rendering on the UI thread 2026-07-17 12:35:54 +02:00
test_mode.go Dump goroutine stacks when the test watchdog fires 2026-07-20 14:26:25 +02:00
test_timeout_norace.go Scale the integration test watchdog up under the race detector 2026-07-20 14:26:25 +02:00
test_timeout_race.go Scale the integration test watchdog up under the race detector 2026-07-20 14:26:25 +02:00
view_helpers.go Render content-only when a task reads more lines into a view 2026-07-09 09:32:35 +02:00
views.go Clear tab strips on views that are no longer tabs 2026-06-23 14:15:18 +02:00