From 0d1caf5c22c17e785fb625dd04ac5231f706e89b Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Thu, 7 May 2026 08:28:50 +0200 Subject: [PATCH] Bounce refreshView to the UI thread An async refresh dispatches refreshXyz on a worker goroutine, which then calls refreshView -> PostRefreshUpdate -> HandleRender. Today the final self.c.Render() inside ListContextTrait.HandleRender is what triggers a UI flush from the worker. We're going to remove that Render() call, so prepare by wrapping refreshView's body in OnUIThread. This moves the entire rendering of the view (and the ReApplyFilter/ReApplySearch stuff) to the UI thread, not just the layout. I don't expect this to make a difference in practice, and it is already one step towards my long-term goal of moving all view rendering to the UI thread (see https://github.com/jesseduffield/lazygit/issues/2974#issuecomment-1729154768). --- pkg/gui/controllers/helpers/refresh_helper.go | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/pkg/gui/controllers/helpers/refresh_helper.go b/pkg/gui/controllers/helpers/refresh_helper.go index 4a61bde18..6638d150c 100644 --- a/pkg/gui/controllers/helpers/refresh_helper.go +++ b/pkg/gui/controllers/helpers/refresh_helper.go @@ -780,22 +780,27 @@ func (self *RefreshHelper) refForLog() string { } func (self *RefreshHelper) refreshView(context types.Context) { - // Re-applying the filter must be done before re-rendering the view, so that - // the filtered list model is up to date for rendering. - self.searchHelper.ReApplyFilter(context) + // refreshView is called from the worker goroutine that drives async + // refreshes, so bounce to the UI thread before mutating view content. + self.c.OnUIThread(func() error { + // Re-applying the filter must be done before re-rendering the view, so that + // the filtered list model is up to date for rendering. + self.searchHelper.ReApplyFilter(context) - self.c.PostRefreshUpdate(context) + self.c.PostRefreshUpdate(context) - self.c.AfterLayout(func() error { - // Re-applying the search must be done after re-rendering the view though, - // so that the "x of y" status is shown correctly. - // - // Also, it must be done after layout, because otherwise FocusPoint - // hasn't been called yet (see ListContextTrait.FocusLine), which means - // that the scroll position might be such that the entire visible - // content is outside the viewport. And this would cause problems in - // searchModelCommits. - self.searchHelper.ReApplySearch(context) + self.c.AfterLayout(func() error { + // Re-applying the search must be done after re-rendering the view though, + // so that the "x of y" status is shown correctly. + // + // Also, it must be done after layout, because otherwise FocusPoint + // hasn't been called yet (see ListContextTrait.FocusLine), which means + // that the scroll position might be such that the entire visible + // content is outside the viewport. And this would cause problems in + // searchModelCommits. + self.searchHelper.ReApplySearch(context) + return nil + }) return nil }) }