mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-12 08:36:25 -04:00
Add gui.startupPanel config for the initially focused panel
The startup panel was hard-coded to Files unless a positional argument (lazygit log / branches / stash) or a filter path picked another one — tig-style users who live in the commits panel had to type the argument every launch (#5877). gui.startupPanel now selects the focused side panel for argument-less launches: one of worktrees, submodules, branches, remotes, tags, commits, reflog, or stash. CLI arguments and filter paths keep precedence, an unrecognized value falls back to files, and the validation lives in a pure normalizeStartupPanel so the accepted vocabulary is pinned by unit tests.
This commit is contained in:
parent
ea91639546
commit
600b9aa340
|
|
@ -103,6 +103,10 @@ gui:
|
|||
|
||||
# If true, increase the height of the focused side window; creating an accordion
|
||||
# effect.
|
||||
# The side panel to focus on startup (when no positional argument like
|
||||
# `lazygit log` is given). One of: files, worktrees, submodules, branches,
|
||||
# remotes, tags, commits, reflog, stash. Anything else falls back to files.
|
||||
startupPanel: files
|
||||
expandFocusedSidePanel: false
|
||||
|
||||
# The weight of the expanded side panel, relative to the other panels. 2 means
|
||||
|
|
|
|||
|
|
@ -113,6 +113,12 @@ type GuiConfig struct {
|
|||
ExpandedSidePanelWeight int `yaml:"expandedSidePanelWeight"`
|
||||
// If true, don't give a side panel more height than it needs to show its content; when all panels fit, the leftover height is shared among them so that they still fill the screen.
|
||||
ShrinkSidePanelsToContent bool `yaml:"shrinkSidePanelsToContent"`
|
||||
// The side panel to focus on startup, when lazygit is launched without
|
||||
// a positional argument (e.g. `lazygit log`). Valid values are:
|
||||
// 'files', 'worktrees', 'submodules', 'branches', 'remotes', 'tags', 'commits', 'reflog', 'stash'.
|
||||
// An unrecognized value falls back to 'files'.
|
||||
StartupPanel string `yaml:"startupPanel"`
|
||||
|
||||
// The side panels, in the order they appear from top to bottom.
|
||||
// Each entry is a list of one or more names that share a single panel as tabs (cycle through them with the next-tab/previous-tab keys).
|
||||
// Omit a name to hide it; give a name its own one-element list to promote a tab to a top-level panel.
|
||||
|
|
|
|||
|
|
@ -664,7 +664,7 @@ func (gui *Gui) resetState(startArgs appTypes.StartArgs) types.Context {
|
|||
|
||||
gui.applySidePanelConfig()
|
||||
|
||||
return initialContext(contextTree, startArgs)
|
||||
return initialContext(contextTree, startArgs, gui.Config.GetUserConfig())
|
||||
}
|
||||
|
||||
func (gui *Gui) loadCachedPullRequests() []*models.GithubPullRequest {
|
||||
|
|
@ -752,7 +752,19 @@ func parseScreenModeArg(screenModeArg string) types.ScreenMode {
|
|||
}
|
||||
}
|
||||
|
||||
func initialContext(contextTree *context.ContextTree, startArgs appTypes.StartArgs) types.IListContext {
|
||||
// normalizeStartupPanel validates gui.startupPanel: a recognized panel name
|
||||
// passes through, and anything else (including the empty string and the
|
||||
// default "files", which initialContext already starts on) normalizes to ""
|
||||
// so the caller keeps the Files panel (#5877).
|
||||
func normalizeStartupPanel(name string) string {
|
||||
switch name {
|
||||
case "worktrees", "submodules", "branches", "remotes", "tags", "commits", "reflog", "stash":
|
||||
return name
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
func initialContext(contextTree *context.ContextTree, startArgs appTypes.StartArgs, userConfig *config.UserConfig) types.IListContext {
|
||||
var initialContext types.IListContext = contextTree.Files
|
||||
|
||||
if startArgs.FilterPath != "" {
|
||||
|
|
@ -770,8 +782,28 @@ func initialContext(contextTree *context.ContextTree, startArgs appTypes.StartAr
|
|||
default:
|
||||
panic("unhandled git arg")
|
||||
}
|
||||
} else if panel := normalizeStartupPanel(userConfig.Gui.StartupPanel); panel != "" {
|
||||
// An explicit config wins over the default Files panel when no CLI
|
||||
// argument selected one (#5877); anything unrecognized stays on Files.
|
||||
switch panel {
|
||||
case "worktrees":
|
||||
initialContext = contextTree.Worktrees
|
||||
case "submodules":
|
||||
initialContext = contextTree.Submodules
|
||||
case "branches":
|
||||
initialContext = contextTree.Branches
|
||||
case "remotes":
|
||||
initialContext = contextTree.Remotes
|
||||
case "tags":
|
||||
initialContext = contextTree.Tags
|
||||
case "commits":
|
||||
initialContext = contextTree.LocalCommits
|
||||
case "reflog":
|
||||
initialContext = contextTree.ReflogCommits
|
||||
case "stash":
|
||||
initialContext = contextTree.Stash
|
||||
}
|
||||
}
|
||||
|
||||
return initialContext
|
||||
}
|
||||
|
||||
|
|
|
|||
57
pkg/gui/initial_context_test.go
Normal file
57
pkg/gui/initial_context_test.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// normalizeStartupPanel is the validation half of gui.startupPanel (#5877):
|
||||
// recognized names pass through, everything else (empty, "files" — the
|
||||
// default the caller already starts on — and typos) normalizes to "" so the
|
||||
// Files panel stays focused.
|
||||
func TestNormalizeStartupPanel(t *testing.T) {
|
||||
for _, name := range []string{
|
||||
"worktrees", "submodules", "branches", "remotes",
|
||||
"tags", "commits", "reflog", "stash",
|
||||
} {
|
||||
assert.Equal(t, name, normalizeStartupPanel(name), name)
|
||||
}
|
||||
for _, name := range []string{"", "files", "status", "Files", "commit", "nonsense"} {
|
||||
assert.Equal(t, "", normalizeStartupPanel(name), name)
|
||||
}
|
||||
}
|
||||
|
||||
// The wiring half: initialContext consults the config only when no CLI
|
||||
// argument selected a panel, and each recognized name selects the matching
|
||||
// tree field. Source-structural pin (the repo's established pattern for
|
||||
// context-graph assertions) because building a real ContextTree requires the
|
||||
// full view harness.
|
||||
func TestInitialContextWiring(t *testing.T) {
|
||||
b, err := os.ReadFile("gui.go")
|
||||
assert.NoError(t, err)
|
||||
source := string(b)
|
||||
|
||||
assert.Contains(t, source,
|
||||
"} else if panel := normalizeStartupPanel(userConfig.Gui.StartupPanel); panel != \"\" {",
|
||||
"the config branch must come after the FilterPath/GitArg branches so CLI arguments win")
|
||||
assert.Contains(t, source,
|
||||
"initialContext(contextTree, startArgs, gui.Config.GetUserConfig())",
|
||||
"the caller must pass the user config through")
|
||||
|
||||
for _, pair := range [][2]string{
|
||||
{"worktrees", "contextTree.Worktrees"},
|
||||
{"submodules", "contextTree.Submodules"},
|
||||
{"branches", "contextTree.Branches"},
|
||||
{"remotes", "contextTree.Remotes"},
|
||||
{"tags", "contextTree.Tags"},
|
||||
{"commits", "contextTree.LocalCommits"},
|
||||
{"reflog", "contextTree.ReflogCommits"},
|
||||
{"stash", "contextTree.Stash"},
|
||||
} {
|
||||
assert.Contains(t, source,
|
||||
"case \""+pair[0]+"\":\n\t\t\tinitialContext = "+pair[1],
|
||||
"startupPanel "+pair[0]+" must select "+pair[1])
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue