Have renderAppStatus trigger a full layout when the appStatus width changes

In 0d195077e4 we improved the performance of the status bar spinner by
avoiding a layout. This is fine from one spinner tick to the next, but it's a
problem when spinning starts or ends (or in the hypothetical case that the
status text changes in the middle of the operation, which we never do in
lazygit, but theoretically could). In this case a layout is needed so that the
rest of the status bar gets pushed over appropriately (or moves back to the left
when the spinner ends), and also so that the bottom line is shown or hidden
properly for users who set gui.showBottomLine to false.

To fix this, keep track of the status string width and force a layout whenever
it changes. This includes the beginning and end of an operation when it changes
from empty to non-empty or vice versa.

There is currently no observable misbehavior from this bug, but that's only
because we must have a HandleRender call somewhere that forces a full layout
when an operation starts or ends. We will remove the Render() call from
HandleRender at the end of this branch, at which point the misbehavior would be
visible if we didn't fix it here.
This commit is contained in:
Stefan Haller
2026-05-09 13:58:33 +02:00
parent b3deef31ad
commit 670565c175
@@ -6,6 +6,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/status"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
)
type AppStatusHelper struct {
@@ -93,13 +94,24 @@ func (self *AppStatusHelper) renderAppStatus() {
self.c.OnWorker(func(_ gocui.Task) error {
ticker := time.NewTicker(time.Millisecond * time.Duration(self.c.UserConfig().Gui.Spinner.Rate))
defer ticker.Stop()
prevAppStatus := ""
for range ticker.C {
appStatus, color := self.statusMgr().GetStatusString(self.c.UserConfig())
self.c.Views().AppStatus.FgColor = color
self.c.OnUIThreadContentOnly(func() error {
update := self.c.OnUIThreadContentOnly
if utils.StringWidth(appStatus) != utils.StringWidth(prevAppStatus) {
// Need a full layout whenever the width of the status string changes. This can't
// happen during normal spinning because we validate that all spinner frames have
// the same width, so typically this will only be triggered at the beginning and end
// of a status, or if the status string changes midway for some reason.
update = self.c.OnUIThread
}
update(func() error {
self.c.SetViewContent(self.c.Views().AppStatus, appStatus)
return nil
})
prevAppStatus = appStatus
if appStatus == "" {
break