1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2026-06-20 01:19:23 +02:00

Re-apply the side panel config on a live config reload

When the config file changes and lazygit regains focus it reloads the
config, but the side panel window assignments, default views, tab
strips, and z-order were only ever set up on repo entry, so a changed
sidePanels wouldn't take effect until restart. Re-apply it from the
reload path: reassign windows and default views and restore each panel's
default tab.

The focused panel needs care: resetting it to its default tab would
leave the focused tab hidden behind that default tab, so the panel looks
unfocused even though its tab is selected. Re-focus the current context
so its tab stays shown and highlighted; only when the new config hides
the focused panel entirely do we move focus to the default side panel.
Tab strips are already refreshed via configureViewProperties.
This commit is contained in:
Stefan Haller
2026-06-15 09:03:44 +02:00
parent 615e3b146b
commit d4392a1195
4 changed files with 81 additions and 1 deletions
+1
View File
@@ -357,6 +357,7 @@ func (gui *Gui) onNewRepo(startArgs appTypes.StartArgs, contextKey types.Context
if didChange && reloadErr == nil {
gui.c.Log.Info("User config changed - reloading")
reloadErr = gui.onUserConfigLoaded()
gui.reloadSidePanels()
if err := gui.resetKeybindings(); err != nil {
return err
}
+28 -1
View File
@@ -3,6 +3,7 @@ package gui
import (
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/samber/lo"
)
// sidePanelViewNames maps each gui.sidePanels name to the gocui view it controls.
@@ -58,7 +59,8 @@ func sidePanelContexts(contextTree *context.ContextTree) map[string]types.Contex
// applySidePanelConfig (re)assigns each side context's window and resets each
// window's default view from the current gui.sidePanels config. It runs against
// the current repo's contexts, so gui.State must already be set. We call it on
// every repo entry (a repo's per-repo config can differ from the previous one's).
// every repo entry (a repo's per-repo config can differ from the previous one's)
// and on a live config reload.
func (gui *Gui) applySidePanelConfig() {
contextTree := gui.State.Contexts
gui.assignSidePanelWindows(contextTree)
@@ -76,6 +78,31 @@ func (gui *Gui) moveDefaultTabsToTop() {
}
}
// reloadSidePanels re-applies the side panel config to the current repo after a
// live config reload: it reassigns windows and default views, restores each
// panel's default tab, and keeps the focused panel in a consistent state.
func (gui *Gui) reloadSidePanels() {
gui.applySidePanelConfig()
gui.moveDefaultTabsToTop()
// applySidePanelConfig reset every window to show its first configured tab,
// which would leave the focused tab hidden behind its panel's default tab
// (the panel would look unfocused even though its tab is selected). Re-focus
// the current context so its tab stays shown and highlighted. If the new
// config has hidden the focused panel entirely, move focus to the default
// side panel instead.
current := gui.c.Context().Current()
if current.GetKind() != types.SIDE_CONTEXT {
return
}
if lo.Contains(gui.helpers.Window.SideWindows(), current.GetWindowName()) {
gui.c.Context().Activate(current, types.OnFocusOpts{})
} else {
gui.c.Context().Push(gui.defaultSideContext(), types.OnFocusOpts{})
}
}
// assignSidePanelWindows sets each side context's window name from the config so
// that contexts grouped into one panel share a window (the window name being the
// panel's first tab). Side panels the user hasn't listed get their own window
+1
View File
@@ -480,6 +480,7 @@ var tests = []*components.IntegrationTest{
ui.OpenLinkFailure,
ui.PromoteTabToSidePanel,
ui.RangeSelect,
ui.ReloadSidePanels,
ui.ReorderSidePanels,
ui.SwitchTabFromMenu,
ui.SwitchTabWithPanelJumpKeys,
@@ -0,0 +1,51 @@
package ui
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var ReloadSidePanels = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Editing the side panel config and refocusing the window re-applies the layout live, keeping the focused panel focused",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(cfg *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shell.CreateNCommits(2)
// Start with worktrees promoted to its own panel.
shell.CreateFile(".git/lazygit.yml", `
gui:
sidePanels:
- [status]
- [files, submodules]
- [worktrees]
- [branches, remotes, tags]
- [commits, reflog]
- [stash]`)
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
// Worktrees is its own panel in the third position.
t.Views().Files().IsFocused().
Press(keys.Universal.JumpToBlock[2])
t.Views().Worktrees().IsFocused()
// Demote worktrees back into the files panel, then refocus the window to
// trigger a live reload of the changed config.
t.Shell().UpdateFile(".git/lazygit.yml", `
gui:
sidePanels:
- [status]
- [files, worktrees, submodules]
- [branches, remotes, tags]
- [commits, reflog]
- [stash]`)
t.FocusIn()
// Worktrees is now a tab of the files panel. It stays focused, and is shown
// in front rather than being hidden behind the files tab (which would leave
// the panel looking unfocused).
t.Views().Worktrees().IsActiveTab().IsFocused().
Press(keys.Universal.PrevTab)
t.Views().Files().IsActiveTab().IsFocused()
},
})