diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index cb517784f..b81288da2 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -6,6 +6,7 @@ * [ ] Code has been formatted (see [here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting)) * [ ] Tests have been added/updated (see [here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md) for the integration test guide) * [ ] Text is internationalised (see [here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation)) +* [ ] If a new UserConfig entry was added, make sure it can be hot-reloaded (see [here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig)) * [ ] Docs have been updated if necessary * [ ] You've read through your own file changes for silly mistakes etc diff --git a/docs/Config.md b/docs/Config.md index f0c28ff42..ce0c4bee1 100644 --- a/docs/Config.md +++ b/docs/Config.md @@ -1,6 +1,6 @@ # User Config -Default path for the config file: +Default path for the global config file: - Linux: `~/.config/lazygit/config.yml` - MacOS: `~/Library/Application\ Support/lazygit/config.yml` @@ -16,6 +16,8 @@ If you want to change the config directory: - MacOS: `export XDG_CONFIG_HOME="$HOME/.config"` +In addition to the global config file you can create repo-specific config files in `/.git/lazygit.yml`. Settings in these files override settings in the global config file. In addition, files called `.lazygit.yml` in any of the parent directories of a repo will also be loaded; this can be useful if you have settings that you want to apply to a group of repositories. + JSON schema is available for `config.yml` so that IntelliSense in Visual Studio Code (completion and error checking) is automatically enabled when the [YAML Red Hat][yaml] extension is installed. However, note that automatic schema detection only works if your config file is in one of the standard paths mentioned above. If you override the path to the file, you can still make IntelliSense work by adding ```yaml diff --git a/docs/dev/Codebase_Guide.md b/docs/dev/Codebase_Guide.md index 7f9752f5d..aaa6b358b 100644 --- a/docs/dev/Codebase_Guide.md +++ b/docs/dev/Codebase_Guide.md @@ -12,7 +12,7 @@ * `pkg/commands/models`: Contains model structs that represent commits, branches, files, etc. * `pkg/commands/patch`: Contains code for parsing and working with git patches * `pkg/common`: Contains the `Common` struct which holds common dependencies like the logger, i18n, and the user config. Most structs in the code will have a field named `c` which holds a common struct (or a derivative of the common struct). -* `pkg/config`: Contains code relating to the Lazygit user config. Specifically `pkg/config/user_config/go` defines the user config struct and its default values. +* `pkg/config`: Contains code relating to the Lazygit user config. Specifically `pkg/config/user_config/go` defines the user config struct and its default values. See [below](#using-userconfig) for some important information about using it. * `pkg/constants`: Contains some constant strings (e.g. links to docs) * `pkg/env`: Contains code relating to setting/getting environment variables * `pkg/i18n`: Contains internationalised strings @@ -86,6 +86,12 @@ The event loop is managed in the `MainLoop` function of `vendor/github.com/jesse Often, as part of handling a keypress, we'll want to run some code asynchronously so that it doesn't block the UI thread. For this we'll typically run `self.c.OnWorker(myFunc)`. If the worker wants to then do something on the UI thread again it can call `self.c.OnUIThread(myOtherFunc)`. +## Using UserConfig + +The UserConfig struct is loaded from lazygit's global config file (and possibly repo-specific config files). It can be re-loaded while lazygit is running, e.g. when the user edits one of the config files. In this case we should make sure that any new or changed config values take effect immediately. The easiest way to achieve this is what we do in most controllers or helpers: these have a pointer to the `common.Common` struct, which contains the UserConfig, and access it from there. Since the UserConfig instance in `common.Common` is updated whenever we reload the config, the code can be sure that it always uses an up-to-date value, and there's nothing else to do. + +If that's not possible for some reason, see if you can add code to `Gui.onUserConfigLoaded` to update things from the new config; there are some examples in that function to use as a guide. If that's too hard to do too, add the config to the list in `Gui.checkForChangedConfigsThatDontAutoReload` so that the user is asked to quit and restart lazygit. + ## Legacy code structure Before we had controllers and contexts, all the code lived directly in the gui package under a gui God Struct. This was fairly bloated and so we split things out to have a better separation of concerns. Nonetheless, it's a big effort to migrate all the code so we still have some logic in the gui struct that ought to live somewhere else. Likewise, we have some keybindings defined in `pkg/gui/keybindings.go` that ought to live on a controller (all keybindings used to be defined in that one file). diff --git a/go.mod b/go.mod index c815a69d8..b065c3c14 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/integrii/flaggy v1.4.0 github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d - github.com/jesseduffield/gocui v0.3.1-0.20240817084901-ea75eca94702 + github.com/jesseduffield/gocui v0.3.1-0.20240818082312-49cc572a9ffa github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e diff --git a/go.sum b/go.sum index 12c9309a4..c5993d6c4 100644 --- a/go.sum +++ b/go.sum @@ -188,8 +188,8 @@ github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 h1:EQP2Tv8T github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE= github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o= -github.com/jesseduffield/gocui v0.3.1-0.20240817084901-ea75eca94702 h1:9fkowh/FchykVmSXXcNS3XsJ2HWW3MeTlPwQmG1liJM= -github.com/jesseduffield/gocui v0.3.1-0.20240817084901-ea75eca94702/go.mod h1:XtEbqCbn45keRXEu+OMZkjN5gw6AEob59afsgHjokZ8= +github.com/jesseduffield/gocui v0.3.1-0.20240818082312-49cc572a9ffa h1:XZX6Rf60E3IuF1K+fvxjIr29f4p9kNY83mveGoJ5Uuo= +github.com/jesseduffield/gocui v0.3.1-0.20240818082312-49cc572a9ffa/go.mod h1:XtEbqCbn45keRXEu+OMZkjN5gw6AEob59afsgHjokZ8= github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0= github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo= github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY= diff --git a/pkg/app/app.go b/pkg/app/app.go index 755f707c4..a999a902b 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -63,22 +63,20 @@ func Run( func NewCommon(config config.AppConfigurer) (*common.Common, error) { userConfig := config.GetUserConfig() appState := config.GetAppState() - - var err error log := newLogger(config) - tr, err := i18n.NewTranslationSetFromConfig(log, userConfig.Gui.Language) - if err != nil { - return nil, err - } + // Initialize with English for the time being; the real translation set for + // the configured language will be read after reading the user config + tr := i18n.EnglishTranslationSet() - return &common.Common{ - Log: log, - Tr: tr, - UserConfig: userConfig, - AppState: appState, - Debug: config.GetDebug(), - Fs: afero.NewOsFs(), - }, nil + cmn := &common.Common{ + Log: log, + Tr: tr, + AppState: appState, + Debug: config.GetDebug(), + Fs: afero.NewOsFs(), + } + cmn.SetUserConfig(userConfig) + return cmn, nil } func newLogger(cfg config.AppConfigurer) *logrus.Entry { @@ -195,7 +193,7 @@ func (app *App) setupRepo( var shouldInitRepo bool initialBranchArg := "" - switch app.UserConfig.NotARepository { + switch app.UserConfig().NotARepository { case "prompt": // Offer to initialize a new repository in current directory. fmt.Print(app.Tr.CreateRepo) diff --git a/pkg/app/entry_point.go b/pkg/app/entry_point.go index 96f6176c7..d23519a98 100644 --- a/pkg/app/entry_point.go +++ b/pkg/app/entry_point.go @@ -136,6 +136,12 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes if integrationTest != nil { integrationTest.SetupConfig(appConfig) + + // Preserve the changes that the test setup just made to the config, so + // they don't get lost when we reload the config while running the test + // (which happens when switching between repos, going in and out of + // submodules, etc). + appConfig.SaveGlobalUserConfig() } common, err := NewCommon(appConfig) diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index 5f0d7549d..100245f62 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -63,6 +63,11 @@ func generateAtDir(cheatsheetDir string) { if err != nil { log.Fatal(err) } + tr, err := i18n.NewTranslationSetFromConfig(common.Log, lang) + if err != nil { + log.Fatal(err) + } + common.Tr = tr mApp, _ := app.NewApp(mConfig, nil, common) path := cheatsheetDir + "/Keybindings_" + lang + ".md" file, err := os.Create(path) diff --git a/pkg/commands/git_commands/branch.go b/pkg/commands/git_commands/branch.go index 6c9aa8740..c63087a80 100644 --- a/pkg/commands/git_commands/branch.go +++ b/pkg/commands/git_commands/branch.go @@ -145,7 +145,7 @@ func (self *BranchCommands) GetGraph(branchName string) (string, error) { } func (self *BranchCommands) GetGraphCmdObj(branchName string) oscommands.ICmdObj { - branchLogCmdTemplate := self.UserConfig.Git.BranchLogCmd + branchLogCmdTemplate := self.UserConfig().Git.BranchLogCmd templateValues := map[string]string{ "branchName": self.cmd.Quote(branchName), } @@ -236,7 +236,7 @@ func (self *BranchCommands) Merge(branchName string, opts MergeOpts) error { } cmdArgs := NewGitCmd("merge"). Arg("--no-edit"). - Arg(strings.Fields(self.UserConfig.Git.Merging.Args)...). + Arg(strings.Fields(self.UserConfig().Git.Merging.Args)...). ArgIf(opts.FastForwardOnly, "--ff-only"). ArgIf(opts.Squash, "--squash", "--ff"). Arg(branchName). @@ -248,9 +248,9 @@ func (self *BranchCommands) Merge(branchName string, opts MergeOpts) error { func (self *BranchCommands) AllBranchesLogCmdObj() oscommands.ICmdObj { // Only choose between non-empty, non-identical commands candidates := lo.Uniq(lo.WithoutEmpty(append([]string{ - self.UserConfig.Git.AllBranchesLogCmd, + self.UserConfig().Git.AllBranchesLogCmd, }, - self.UserConfig.Git.AllBranchesLogCmds..., + self.UserConfig().Git.AllBranchesLogCmds..., ))) n := len(candidates) diff --git a/pkg/commands/git_commands/branch_loader.go b/pkg/commands/git_commands/branch_loader.go index 929d5964d..cf36cfe23 100644 --- a/pkg/commands/git_commands/branch_loader.go +++ b/pkg/commands/git_commands/branch_loader.go @@ -140,7 +140,7 @@ func (self *BranchLoader) Load(reflogCommits []*models.Commit, } } - if loadBehindCounts && self.UserConfig.Gui.ShowDivergenceFromBaseBranch != "none" { + if loadBehindCounts && self.UserConfig().Gui.ShowDivergenceFromBaseBranch != "none" { onWorker(func() error { return self.GetBehindBaseBranchValuesForAllBranches(branches, mainBranches, renderFunc) }) diff --git a/pkg/commands/git_commands/commit.go b/pkg/commands/git_commands/commit.go index 1ff7c095f..45582c6bd 100644 --- a/pkg/commands/git_commands/commit.go +++ b/pkg/commands/git_commands/commit.go @@ -88,7 +88,7 @@ func (self *CommitCommands) ResetToCommit(hash string, strength string, envVars func (self *CommitCommands) CommitCmdObj(summary string, description string) oscommands.ICmdObj { messageArgs := self.commitMessageArgs(summary, description) - skipHookPrefix := self.UserConfig.Git.SkipHookPrefix + skipHookPrefix := self.UserConfig().Git.SkipHookPrefix cmdArgs := NewGitCmd("commit"). ArgIf(skipHookPrefix != "" && strings.HasPrefix(summary, skipHookPrefix), "--no-verify"). @@ -148,7 +148,7 @@ func (self *CommitCommands) CommitEditorCmdObj() oscommands.ICmdObj { } func (self *CommitCommands) signoffFlag() string { - if self.UserConfig.Git.Commit.SignOff { + if self.UserConfig().Git.Commit.SignOff { return "--signoff" } else { return "" @@ -258,13 +258,13 @@ func (self *CommitCommands) AmendHeadCmdObj() oscommands.ICmdObj { func (self *CommitCommands) ShowCmdObj(hash string, filterPath string) oscommands.ICmdObj { contextSize := self.AppState.DiffContextSize - extDiffCmd := self.UserConfig.Git.Paging.ExternalDiffCommand + extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand cmdArgs := NewGitCmd("show"). Config("diff.noprefix=false"). ConfigIf(extDiffCmd != "", "diff.external="+extDiffCmd). ArgIfElse(extDiffCmd != "", "--ext-diff", "--no-ext-diff"). Arg("--submodule"). - Arg("--color="+self.UserConfig.Git.Paging.ColorArg). + Arg("--color="+self.UserConfig().Git.Paging.ColorArg). Arg(fmt.Sprintf("--unified=%d", contextSize)). Arg("--stat"). Arg("--decorate"). diff --git a/pkg/commands/git_commands/commit_loader_test.go b/pkg/commands/git_commands/commit_loader_test.go index a8ef9e69a..f9c4cdff6 100644 --- a/pkg/commands/git_commands/commit_loader_test.go +++ b/pkg/commands/git_commands/commit_loader_test.go @@ -322,9 +322,9 @@ func TestGetCommits(t *testing.T) { }, } - common.UserConfig.Git.MainBranches = scenario.mainBranches + common.UserConfig().Git.MainBranches = scenario.mainBranches opts := scenario.opts - opts.MainBranches = NewMainBranches(scenario.mainBranches, cmd) + opts.MainBranches = NewMainBranches(common, cmd) commits, err := builder.GetCommits(opts) assert.Equal(t, scenario.expectedCommits, commits) diff --git a/pkg/commands/git_commands/config.go b/pkg/commands/git_commands/config.go index 014591556..9771f01d3 100644 --- a/pkg/commands/git_commands/config.go +++ b/pkg/commands/git_commands/config.go @@ -43,7 +43,7 @@ func (self *ConfigCommands) ConfiguredPager() string { } func (self *ConfigCommands) GetPager(width int) string { - useConfig := self.UserConfig.Git.Paging.UseConfig + useConfig := self.UserConfig().Git.Paging.UseConfig if useConfig { pager := self.ConfiguredPager() return strings.Split(pager, "| less")[0] @@ -53,14 +53,14 @@ func (self *ConfigCommands) GetPager(width int) string { "columnWidth": strconv.Itoa(width/2 - 6), } - pagerTemplate := string(self.UserConfig.Git.Paging.Pager) + pagerTemplate := string(self.UserConfig().Git.Paging.Pager) return utils.ResolvePlaceholderString(pagerTemplate, templateValues) } // UsingGpg tells us whether the user has gpg enabled so that we can know // whether we need to run a subprocess to allow them to enter their password func (self *ConfigCommands) UsingGpg() bool { - overrideGpg := self.UserConfig.Git.OverrideGpg + overrideGpg := self.UserConfig().Git.OverrideGpg if overrideGpg { return false } diff --git a/pkg/commands/git_commands/deps_test.go b/pkg/commands/git_commands/deps_test.go index eaf53306a..a7412bd38 100644 --- a/pkg/commands/git_commands/deps_test.go +++ b/pkg/commands/git_commands/deps_test.go @@ -58,9 +58,9 @@ func buildGitCommon(deps commonDeps) *GitCommon { } gitCommon.cmd = cmd - gitCommon.Common.UserConfig = deps.userConfig - if gitCommon.Common.UserConfig == nil { - gitCommon.Common.UserConfig = config.GetDefaultConfig() + gitCommon.Common.SetUserConfig(deps.userConfig) + if gitCommon.Common.UserConfig() == nil { + gitCommon.Common.SetUserConfig(config.GetDefaultConfig()) } gitCommon.version = deps.gitVersion diff --git a/pkg/commands/git_commands/diff.go b/pkg/commands/git_commands/diff.go index 979279914..8eb4799b6 100644 --- a/pkg/commands/git_commands/diff.go +++ b/pkg/commands/git_commands/diff.go @@ -17,7 +17,7 @@ func NewDiffCommands(gitCommon *GitCommon) *DiffCommands { } func (self *DiffCommands) DiffCmdObj(diffArgs []string) oscommands.ICmdObj { - extDiffCmd := self.UserConfig.Git.Paging.ExternalDiffCommand + extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand useExtDiff := extDiffCmd != "" return self.cmd.New( @@ -26,7 +26,7 @@ func (self *DiffCommands) DiffCmdObj(diffArgs []string) oscommands.ICmdObj { ConfigIf(useExtDiff, "diff.external="+extDiffCmd). ArgIfElse(useExtDiff, "--ext-diff", "--no-ext-diff"). Arg("--submodule"). - Arg(fmt.Sprintf("--color=%s", self.UserConfig.Git.Paging.ColorArg)). + Arg(fmt.Sprintf("--color=%s", self.UserConfig().Git.Paging.ColorArg)). Arg(diffArgs...). Dir(self.repoPaths.worktreePath). ToArgv(), diff --git a/pkg/commands/git_commands/file.go b/pkg/commands/git_commands/file.go index 9401e6d54..8997c34c0 100644 --- a/pkg/commands/git_commands/file.go +++ b/pkg/commands/git_commands/file.go @@ -31,7 +31,7 @@ func (self *FileCommands) Cat(fileName string) (string, error) { } func (self *FileCommands) GetEditCmdStrLegacy(filename string, lineNumber int) (string, error) { - editor := self.UserConfig.OS.EditCommand + editor := self.UserConfig().OS.EditCommand if editor == "" { editor = self.config.GetCoreEditor() @@ -60,7 +60,7 @@ func (self *FileCommands) GetEditCmdStrLegacy(filename string, lineNumber int) ( "line": strconv.Itoa(lineNumber), } - editCmdTemplate := self.UserConfig.OS.EditCommandTemplate + editCmdTemplate := self.UserConfig().OS.EditCommandTemplate if len(editCmdTemplate) == 0 { switch editor { case "emacs", "nano", "vi", "vim", "nvim": @@ -78,7 +78,7 @@ func (self *FileCommands) GetEditCmdStrLegacy(filename string, lineNumber int) ( func (self *FileCommands) GetEditCmdStr(filenames []string) (string, bool) { // Legacy support for old config; to be removed at some point - if self.UserConfig.OS.Edit == "" && self.UserConfig.OS.EditCommandTemplate != "" { + if self.UserConfig().OS.Edit == "" && self.UserConfig().OS.EditCommandTemplate != "" { // If multiple files are selected, we'll simply edit just the first one. // It's not worth fixing this for the legacy support. if cmdStr, err := self.GetEditCmdStrLegacy(filenames[0], 1); err == nil { @@ -86,7 +86,7 @@ func (self *FileCommands) GetEditCmdStr(filenames []string) (string, bool) { } } - template, suspend := config.GetEditTemplate(&self.UserConfig.OS, self.guessDefaultEditor) + template, suspend := config.GetEditTemplate(&self.UserConfig().OS, self.guessDefaultEditor) quotedFilenames := lo.Map(filenames, func(filename string, _ int) string { return self.cmd.Quote(filename) }) templateValues := map[string]string{ @@ -99,13 +99,13 @@ func (self *FileCommands) GetEditCmdStr(filenames []string) (string, bool) { func (self *FileCommands) GetEditAtLineCmdStr(filename string, lineNumber int) (string, bool) { // Legacy support for old config; to be removed at some point - if self.UserConfig.OS.EditAtLine == "" && self.UserConfig.OS.EditCommandTemplate != "" { + if self.UserConfig().OS.EditAtLine == "" && self.UserConfig().OS.EditCommandTemplate != "" { if cmdStr, err := self.GetEditCmdStrLegacy(filename, lineNumber); err == nil { return cmdStr, true } } - template, suspend := config.GetEditAtLineTemplate(&self.UserConfig.OS, self.guessDefaultEditor) + template, suspend := config.GetEditAtLineTemplate(&self.UserConfig().OS, self.guessDefaultEditor) templateValues := map[string]string{ "filename": self.cmd.Quote(filename), @@ -118,13 +118,13 @@ func (self *FileCommands) GetEditAtLineCmdStr(filename string, lineNumber int) ( func (self *FileCommands) GetEditAtLineAndWaitCmdStr(filename string, lineNumber int) string { // Legacy support for old config; to be removed at some point - if self.UserConfig.OS.EditAtLineAndWait == "" && self.UserConfig.OS.EditCommandTemplate != "" { + if self.UserConfig().OS.EditAtLineAndWait == "" && self.UserConfig().OS.EditCommandTemplate != "" { if cmdStr, err := self.GetEditCmdStrLegacy(filename, lineNumber); err == nil { return cmdStr } } - template := config.GetEditAtLineAndWaitTemplate(&self.UserConfig.OS, self.guessDefaultEditor) + template := config.GetEditAtLineAndWaitTemplate(&self.UserConfig().OS, self.guessDefaultEditor) templateValues := map[string]string{ "filename": self.cmd.Quote(filename), @@ -136,7 +136,7 @@ func (self *FileCommands) GetEditAtLineAndWaitCmdStr(filename string, lineNumber } func (self *FileCommands) GetOpenDirInEditorCmdStr(path string) (string, bool) { - template, suspend := config.GetOpenDirInEditorTemplate(&self.UserConfig.OS, self.guessDefaultEditor) + template, suspend := config.GetOpenDirInEditorTemplate(&self.UserConfig().OS, self.guessDefaultEditor) templateValues := map[string]string{ "dir": self.cmd.Quote(path), diff --git a/pkg/commands/git_commands/main_branches.go b/pkg/commands/git_commands/main_branches.go index 341232b04..8cf08840a 100644 --- a/pkg/commands/git_commands/main_branches.go +++ b/pkg/commands/git_commands/main_branches.go @@ -5,32 +5,34 @@ import ( "sync" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/jesseduffield/lazygit/pkg/common" "github.com/jesseduffield/lazygit/pkg/utils" "github.com/samber/lo" "github.com/sasha-s/go-deadlock" ) type MainBranches struct { - // List of main branches configured by the user. Just the bare names. - configuredMainBranches []string - // Which of these actually exist in the repository. Full ref names, and it - // could be either "refs/heads/..." or "refs/remotes/origin/..." depending - // on which one exists for a given bare name. + c *common.Common + // Which of the configured main branches actually exist in the repository. Full + // ref names, and it could be either "refs/heads/..." or "refs/remotes/origin/..." + // depending on which one exists for a given bare name. existingMainBranches []string + previousMainBranches []string + cmd oscommands.ICmdObjBuilder mutex *deadlock.Mutex } func NewMainBranches( - configuredMainBranches []string, + cmn *common.Common, cmd oscommands.ICmdObjBuilder, ) *MainBranches { return &MainBranches{ - configuredMainBranches: configuredMainBranches, - existingMainBranches: nil, - cmd: cmd, - mutex: &deadlock.Mutex{}, + c: cmn, + existingMainBranches: nil, + cmd: cmd, + mutex: &deadlock.Mutex{}, } } @@ -40,8 +42,11 @@ func (self *MainBranches) Get() []string { self.mutex.Lock() defer self.mutex.Unlock() - if self.existingMainBranches == nil { - self.existingMainBranches = self.determineMainBranches() + configuredMainBranches := self.c.UserConfig().Git.MainBranches + + if self.existingMainBranches == nil || !utils.EqualSlices(self.previousMainBranches, configuredMainBranches) { + self.existingMainBranches = self.determineMainBranches(configuredMainBranches) + self.previousMainBranches = configuredMainBranches } return self.existingMainBranches @@ -71,13 +76,13 @@ func (self *MainBranches) GetMergeBase(refName string) string { return ignoringWarnings(output) } -func (self *MainBranches) determineMainBranches() []string { +func (self *MainBranches) determineMainBranches(configuredMainBranches []string) []string { var existingBranches []string var wg sync.WaitGroup - existingBranches = make([]string, len(self.configuredMainBranches)) + existingBranches = make([]string, len(configuredMainBranches)) - for i, branchName := range self.configuredMainBranches { + for i, branchName := range configuredMainBranches { wg.Add(1) go utils.Safe(func() { defer wg.Done() diff --git a/pkg/commands/git_commands/repo_paths.go b/pkg/commands/git_commands/repo_paths.go index c2e77d446..a355a45ba 100644 --- a/pkg/commands/git_commands/repo_paths.go +++ b/pkg/commands/git_commands/repo_paths.go @@ -3,7 +3,6 @@ package git_commands import ( ioFs "io/fs" "os" - "path" "path/filepath" "strings" @@ -64,9 +63,9 @@ func (self *RepoPaths) IsBareRepo() bool { func MockRepoPaths(currentPath string) *RepoPaths { return &RepoPaths{ worktreePath: currentPath, - worktreeGitDirPath: path.Join(currentPath, ".git"), + worktreeGitDirPath: filepath.Join(currentPath, ".git"), repoPath: currentPath, - repoGitDirPath: path.Join(currentPath, ".git"), + repoGitDirPath: filepath.Join(currentPath, ".git"), repoName: "lazygit", isBareRepo: false, } @@ -116,9 +115,9 @@ func GetRepoPathsForDir( if isSubmodule { repoPath = worktreePath } else { - repoPath = path.Dir(repoGitDirPath) + repoPath = filepath.Dir(repoGitDirPath) } - repoName := path.Base(repoPath) + repoName := filepath.Base(repoPath) return &RepoPaths{ worktreePath: worktreePath, @@ -154,7 +153,7 @@ func linkedWortkreePaths(fs afero.Fs, repoGitDirPath string) []string { result := []string{} // For each directory in this path we're going to cat the `gitdir` file and append its contents to our result // That file points us to the `.git` file in the worktree. - worktreeGitDirsPath := path.Join(repoGitDirPath, "worktrees") + worktreeGitDirsPath := filepath.Join(repoGitDirPath, "worktrees") // ensure the directory exists _, err := fs.Stat(worktreeGitDirsPath) @@ -171,7 +170,7 @@ func linkedWortkreePaths(fs afero.Fs, repoGitDirPath string) []string { return nil } - gitDirPath := path.Join(currPath, "gitdir") + gitDirPath := filepath.Join(currPath, "gitdir") gitDirBytes, err := afero.ReadFile(fs, gitDirPath) if err != nil { // ignoring error @@ -179,7 +178,7 @@ func linkedWortkreePaths(fs afero.Fs, repoGitDirPath string) []string { } trimmedGitDir := strings.TrimSpace(string(gitDirBytes)) // removing the .git part - worktreeDir := path.Dir(trimmedGitDir) + worktreeDir := filepath.Dir(trimmedGitDir) result = append(result, worktreeDir) return nil }) diff --git a/pkg/commands/git_commands/repo_paths_test.go b/pkg/commands/git_commands/repo_paths_test.go index 9ee41a3fc..77f451671 100644 --- a/pkg/commands/git_commands/repo_paths_test.go +++ b/pkg/commands/git_commands/repo_paths_test.go @@ -2,11 +2,13 @@ package git_commands import ( "fmt" + "runtime" "strings" "testing" "github.com/go-errors/errors" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/samber/lo" "github.com/stretchr/testify/assert" ) @@ -29,7 +31,17 @@ func TestGetRepoPaths(t *testing.T) { Name: "typical case", BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) { // setup for main worktree - expectedOutput := []string{ + mockOutput := lo.Ternary(runtime.GOOS == "windows", []string{ + // --show-toplevel + `C:\path\to\repo`, + // --git-dir + `C:\path\to\repo\.git`, + // --git-common-dir + `C:\path\to\repo\.git`, + // --is-bare-repository + "false", + // --show-superproject-working-tree + }, []string{ // --show-toplevel "/path/to/repo", // --git-dir @@ -39,28 +51,45 @@ func TestGetRepoPaths(t *testing.T) { // --is-bare-repository "false", // --show-superproject-working-tree - } + }) runner.ExpectGitArgs( append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--is-bare-repository", "--show-superproject-working-tree"), - strings.Join(expectedOutput, "\n"), + strings.Join(mockOutput, "\n"), nil) }, Path: "/path/to/repo", - Expected: &RepoPaths{ + Expected: lo.Ternary(runtime.GOOS == "windows", &RepoPaths{ + worktreePath: `C:\path\to\repo`, + worktreeGitDirPath: `C:\path\to\repo\.git`, + repoPath: `C:\path\to\repo`, + repoGitDirPath: `C:\path\to\repo\.git`, + repoName: `repo`, + isBareRepo: false, + }, &RepoPaths{ worktreePath: "/path/to/repo", worktreeGitDirPath: "/path/to/repo/.git", repoPath: "/path/to/repo", repoGitDirPath: "/path/to/repo/.git", repoName: "repo", isBareRepo: false, - }, + }), Err: nil, }, { Name: "bare repo", BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) { // setup for main worktree - expectedOutput := []string{ + mockOutput := lo.Ternary(runtime.GOOS == "windows", []string{ + // --show-toplevel + `C:\path\to\repo`, + // --git-dir + `C:\path\to\bare_repo\bare.git`, + // --git-common-dir + `C:\path\to\bare_repo\bare.git`, + // --is-bare-repository + `true`, + // --show-superproject-working-tree + }, []string{ // --show-toplevel "/path/to/repo", // --git-dir @@ -70,27 +99,45 @@ func TestGetRepoPaths(t *testing.T) { // --is-bare-repository "true", // --show-superproject-working-tree - } + }) runner.ExpectGitArgs( append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--is-bare-repository", "--show-superproject-working-tree"), - strings.Join(expectedOutput, "\n"), + strings.Join(mockOutput, "\n"), nil) }, Path: "/path/to/repo", - Expected: &RepoPaths{ + Expected: lo.Ternary(runtime.GOOS == "windows", &RepoPaths{ + worktreePath: `C:\path\to\repo`, + worktreeGitDirPath: `C:\path\to\bare_repo\bare.git`, + repoPath: `C:\path\to\bare_repo`, + repoGitDirPath: `C:\path\to\bare_repo\bare.git`, + repoName: `bare_repo`, + isBareRepo: true, + }, &RepoPaths{ worktreePath: "/path/to/repo", worktreeGitDirPath: "/path/to/bare_repo/bare.git", repoPath: "/path/to/bare_repo", repoGitDirPath: "/path/to/bare_repo/bare.git", repoName: "bare_repo", isBareRepo: true, - }, + }), Err: nil, }, { Name: "submodule", BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) { - expectedOutput := []string{ + mockOutput := lo.Ternary(runtime.GOOS == "windows", []string{ + // --show-toplevel + `C:\path\to\repo\submodule1`, + // --git-dir + `C:\path\to\repo\.git\modules\submodule1`, + // --git-common-dir + `C:\path\to\repo\.git\modules\submodule1`, + // --is-bare-repository + `false`, + // --show-superproject-working-tree + `C:\path\to\repo`, + }, []string{ // --show-toplevel "/path/to/repo/submodule1", // --git-dir @@ -101,21 +148,28 @@ func TestGetRepoPaths(t *testing.T) { "false", // --show-superproject-working-tree "/path/to/repo", - } + }) runner.ExpectGitArgs( append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--is-bare-repository", "--show-superproject-working-tree"), - strings.Join(expectedOutput, "\n"), + strings.Join(mockOutput, "\n"), nil) }, Path: "/path/to/repo/submodule1", - Expected: &RepoPaths{ + Expected: lo.Ternary(runtime.GOOS == "windows", &RepoPaths{ + worktreePath: `C:\path\to\repo\submodule1`, + worktreeGitDirPath: `C:\path\to\repo\.git\modules\submodule1`, + repoPath: `C:\path\to\repo\submodule1`, + repoGitDirPath: `C:\path\to\repo\.git\modules\submodule1`, + repoName: `submodule1`, + isBareRepo: false, + }, &RepoPaths{ worktreePath: "/path/to/repo/submodule1", worktreeGitDirPath: "/path/to/repo/.git/modules/submodule1", repoPath: "/path/to/repo/submodule1", repoGitDirPath: "/path/to/repo/.git/modules/submodule1", repoName: "submodule1", isBareRepo: false, - }, + }), Err: nil, }, { diff --git a/pkg/commands/git_commands/stash.go b/pkg/commands/git_commands/stash.go index 047985e38..e3a91c887 100644 --- a/pkg/commands/git_commands/stash.go +++ b/pkg/commands/git_commands/stash.go @@ -84,7 +84,7 @@ func (self *StashCommands) ShowStashEntryCmdObj(index int) oscommands.ICmdObj { cmdArgs := NewGitCmd("stash").Arg("show"). Arg("-p"). Arg("--stat"). - Arg(fmt.Sprintf("--color=%s", self.UserConfig.Git.Paging.ColorArg)). + Arg(fmt.Sprintf("--color=%s", self.UserConfig().Git.Paging.ColorArg)). Arg(fmt.Sprintf("--unified=%d", self.AppState.DiffContextSize)). ArgIf(self.AppState.IgnoreWhitespaceInDiffView, "--ignore-all-space"). Arg(fmt.Sprintf("--find-renames=%d%%", self.AppState.RenameSimilarityThreshold)). diff --git a/pkg/commands/git_commands/sync.go b/pkg/commands/git_commands/sync.go index 7ab209c0e..8eab2f7c8 100644 --- a/pkg/commands/git_commands/sync.go +++ b/pkg/commands/git_commands/sync.go @@ -60,7 +60,7 @@ func (self *SyncCommands) fetchCommandBuilder(fetchAll bool) *GitCommandBuilder } func (self *SyncCommands) FetchCmdObj(task gocui.Task) oscommands.ICmdObj { - cmdArgs := self.fetchCommandBuilder(self.UserConfig.Git.FetchAll).ToArgv() + cmdArgs := self.fetchCommandBuilder(self.UserConfig().Git.FetchAll).ToArgv() cmdObj := self.cmd.New(cmdArgs) cmdObj.PromptOnCredentialRequest(task) @@ -72,7 +72,7 @@ func (self *SyncCommands) Fetch(task gocui.Task) error { } func (self *SyncCommands) FetchBackgroundCmdObj() oscommands.ICmdObj { - cmdArgs := self.fetchCommandBuilder(self.UserConfig.Git.FetchAll).ToArgv() + cmdArgs := self.fetchCommandBuilder(self.UserConfig().Git.FetchAll).ToArgv() cmdObj := self.cmd.New(cmdArgs) cmdObj.DontLog().FailOnCredentialRequest() diff --git a/pkg/commands/git_commands/sync_test.go b/pkg/commands/git_commands/sync_test.go index 353ac72aa..183912c31 100644 --- a/pkg/commands/git_commands/sync_test.go +++ b/pkg/commands/git_commands/sync_test.go @@ -133,7 +133,7 @@ func TestSyncFetch(t *testing.T) { for _, s := range scenarios { t.Run(s.testName, func(t *testing.T) { instance := buildSyncCommands(commonDeps{}) - instance.UserConfig.Git.FetchAll = s.fetchAllConfig + instance.UserConfig().Git.FetchAll = s.fetchAllConfig task := gocui.NewFakeTask() s.test(instance.FetchCmdObj(task)) }) @@ -171,7 +171,7 @@ func TestSyncFetchBackground(t *testing.T) { for _, s := range scenarios { t.Run(s.testName, func(t *testing.T) { instance := buildSyncCommands(commonDeps{}) - instance.UserConfig.Git.FetchAll = s.fetchAllConfig + instance.UserConfig().Git.FetchAll = s.fetchAllConfig s.test(instance.FetchBackgroundCmdObj()) }) } diff --git a/pkg/commands/git_commands/working_tree.go b/pkg/commands/git_commands/working_tree.go index 2364f2a68..d0148bfe9 100644 --- a/pkg/commands/git_commands/working_tree.go +++ b/pkg/commands/git_commands/working_tree.go @@ -3,7 +3,7 @@ package git_commands import ( "fmt" "os" - "path" + "path/filepath" "github.com/go-errors/errors" "github.com/jesseduffield/lazygit/pkg/commands/models" @@ -233,7 +233,7 @@ func (self *WorkingTreeCommands) Ignore(filename string) error { // Exclude adds a file to the .git/info/exclude for the repo func (self *WorkingTreeCommands) Exclude(filename string) error { - excludeFile := path.Join(self.repoPaths.repoGitDirPath, "info", "exclude") + excludeFile := filepath.Join(self.repoPaths.repoGitDirPath, "info", "exclude") return self.os.AppendLineToFile(excludeFile, filename) } @@ -245,7 +245,7 @@ func (self *WorkingTreeCommands) WorktreeFileDiff(file *models.File, plain bool, } func (self *WorkingTreeCommands) WorktreeFileDiffCmdObj(node models.IFile, plain bool, cached bool) oscommands.ICmdObj { - colorArg := self.UserConfig.Git.Paging.ColorArg + colorArg := self.UserConfig().Git.Paging.ColorArg if plain { colorArg = "never" } @@ -253,7 +253,7 @@ func (self *WorkingTreeCommands) WorktreeFileDiffCmdObj(node models.IFile, plain contextSize := self.AppState.DiffContextSize prevPath := node.GetPreviousPath() noIndex := !node.GetIsTracked() && !node.GetHasStagedChanges() && !cached && node.GetIsFile() - extDiffCmd := self.UserConfig.Git.Paging.ExternalDiffCommand + extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand useExtDiff := extDiffCmd != "" && !plain cmdArgs := NewGitCmd("diff"). @@ -285,12 +285,12 @@ func (self *WorkingTreeCommands) ShowFileDiff(from string, to string, reverse bo func (self *WorkingTreeCommands) ShowFileDiffCmdObj(from string, to string, reverse bool, fileName string, plain bool) oscommands.ICmdObj { contextSize := self.AppState.DiffContextSize - colorArg := self.UserConfig.Git.Paging.ColorArg + colorArg := self.UserConfig().Git.Paging.ColorArg if plain { colorArg = "never" } - extDiffCmd := self.UserConfig.Git.Paging.ExternalDiffCommand + extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand useExtDiff := extDiffCmd != "" && !plain cmdArgs := NewGitCmd("diff"). diff --git a/pkg/commands/oscommands/os.go b/pkg/commands/oscommands/os.go index 7f31b5332..cbeb99d43 100644 --- a/pkg/commands/oscommands/os.go +++ b/pkg/commands/oscommands/os.go @@ -80,10 +80,10 @@ func FileType(path string) string { } func (c *OSCommand) OpenFile(filename string) error { - commandTemplate := c.UserConfig.OS.Open + commandTemplate := c.UserConfig().OS.Open if commandTemplate == "" { // Legacy support - commandTemplate = c.UserConfig.OS.OpenCommand + commandTemplate = c.UserConfig().OS.OpenCommand } if commandTemplate == "" { commandTemplate = config.GetPlatformDefaultConfig().Open @@ -96,10 +96,10 @@ func (c *OSCommand) OpenFile(filename string) error { } func (c *OSCommand) OpenLink(link string) error { - commandTemplate := c.UserConfig.OS.OpenLink + commandTemplate := c.UserConfig().OS.OpenLink if commandTemplate == "" { // Legacy support - commandTemplate = c.UserConfig.OS.OpenLinkCommand + commandTemplate = c.UserConfig().OS.OpenLinkCommand } if commandTemplate == "" { commandTemplate = config.GetPlatformDefaultConfig().OpenLink @@ -294,8 +294,8 @@ func (c *OSCommand) CopyToClipboard(str string) error { }, ) c.LogCommand(msg, false) - if c.UserConfig.OS.CopyToClipboardCmd != "" { - cmdStr := utils.ResolvePlaceholderString(c.UserConfig.OS.CopyToClipboardCmd, map[string]string{ + if c.UserConfig().OS.CopyToClipboardCmd != "" { + cmdStr := utils.ResolvePlaceholderString(c.UserConfig().OS.CopyToClipboardCmd, map[string]string{ "text": c.Cmd.Quote(str), }) return c.Cmd.NewShell(cmdStr).Run() @@ -307,8 +307,8 @@ func (c *OSCommand) CopyToClipboard(str string) error { func (c *OSCommand) PasteFromClipboard() (string, error) { var s string var err error - if c.UserConfig.OS.CopyToClipboardCmd != "" { - cmdStr := c.UserConfig.OS.ReadFromClipboardCmd + if c.UserConfig().OS.CopyToClipboardCmd != "" { + cmdStr := c.UserConfig().OS.ReadFromClipboardCmd s, err = c.Cmd.NewShell(cmdStr).RunWithOutput() } else { s, err = clipboard.ReadAll() diff --git a/pkg/commands/oscommands/os_default_test.go b/pkg/commands/oscommands/os_default_test.go index 7291b2d3a..94da4b078 100644 --- a/pkg/commands/oscommands/os_default_test.go +++ b/pkg/commands/oscommands/os_default_test.go @@ -75,7 +75,7 @@ func TestOSCommandOpenFileDarwin(t *testing.T) { for _, s := range scenarios { oSCmd := NewDummyOSCommandWithRunner(s.runner) oSCmd.Platform.OS = "darwin" - oSCmd.UserConfig.OS.Open = "open {{filename}}" + oSCmd.UserConfig().OS.Open = "open {{filename}}" s.test(oSCmd.OpenFile(s.filename)) } @@ -135,7 +135,7 @@ func TestOSCommandOpenFileLinux(t *testing.T) { for _, s := range scenarios { oSCmd := NewDummyOSCommandWithRunner(s.runner) oSCmd.Platform.OS = "linux" - oSCmd.UserConfig.OS.Open = `xdg-open {{filename}} > /dev/null` + oSCmd.UserConfig().OS.Open = `xdg-open {{filename}} > /dev/null` s.test(oSCmd.OpenFile(s.filename)) } diff --git a/pkg/commands/oscommands/os_windows_test.go b/pkg/commands/oscommands/os_windows_test.go index cf9c1e68a..fd71a22f7 100644 --- a/pkg/commands/oscommands/os_windows_test.go +++ b/pkg/commands/oscommands/os_windows_test.go @@ -71,7 +71,7 @@ func TestOSCommandOpenFileWindows(t *testing.T) { } oSCmd.Platform = platform oSCmd.Cmd.platform = platform - oSCmd.UserConfig.OS.OpenCommand = `start "" {{filename}}` + oSCmd.UserConfig().OS.OpenCommand = `start "" {{filename}}` s.test(oSCmd.OpenFile(s.filename)) } diff --git a/pkg/common/common.go b/pkg/common/common.go index 39de6e0d8..837af7bea 100644 --- a/pkg/common/common.go +++ b/pkg/common/common.go @@ -1,6 +1,8 @@ package common import ( + "sync/atomic" + "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/i18n" "github.com/sirupsen/logrus" @@ -11,10 +13,18 @@ import ( type Common struct { Log *logrus.Entry Tr *i18n.TranslationSet - UserConfig *config.UserConfig + userConfig atomic.Pointer[config.UserConfig] AppState *config.AppState Debug bool // for interacting with the filesystem. We use afero rather than the default // `os` package for the sake of mocking the filesystem in tests Fs afero.Fs } + +func (c *Common) UserConfig() *config.UserConfig { + return c.userConfig.Load() +} + +func (c *Common) SetUserConfig(userConfig *config.UserConfig) { + c.userConfig.Store(userConfig) +} diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index ef76d7274..936dcb64a 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -2,29 +2,31 @@ package config import ( "fmt" + "log" "os" "path/filepath" "strings" + "time" "github.com/adrg/xdg" "github.com/jesseduffield/lazygit/pkg/utils/yaml_utils" + "github.com/samber/lo" "gopkg.in/yaml.v3" ) // AppConfig contains the base configuration fields required for lazygit. type AppConfig struct { - Debug bool `long:"debug" env:"DEBUG" default:"false"` - Version string `long:"version" env:"VERSION" default:"unversioned"` - BuildDate string `long:"build-date" env:"BUILD_DATE"` - Name string `long:"name" env:"NAME" default:"lazygit"` - BuildSource string `long:"build-source" env:"BUILD_SOURCE" default:""` - UserConfig *UserConfig - UserConfigPaths []string - DeafultConfFiles bool - UserConfigDir string - TempDir string - AppState *AppState - IsNewRepo bool + debug bool `long:"debug" env:"DEBUG" default:"false"` + version string `long:"version" env:"VERSION" default:"unversioned"` + buildDate string `long:"build-date" env:"BUILD_DATE"` + name string `long:"name" env:"NAME" default:"lazygit"` + buildSource string `long:"build-source" env:"BUILD_SOURCE" default:""` + userConfig *UserConfig + globalUserConfigFiles []*ConfigFile + userConfigFiles []*ConfigFile + userConfigDir string + tempDir string + appState *AppState } type AppConfigurer interface { @@ -38,13 +40,29 @@ type AppConfigurer interface { GetUserConfig() *UserConfig GetUserConfigPaths() []string GetUserConfigDir() string - ReloadUserConfig() error + ReloadUserConfigForRepo(repoConfigFiles []*ConfigFile) error + ReloadChangedUserConfigFiles() (error, bool) GetTempDir() string GetAppState() *AppState SaveAppState() error } +type ConfigFilePolicy int + +const ( + ConfigFilePolicyCreateIfMissing ConfigFilePolicy = iota + ConfigFilePolicyErrorIfMissing + ConfigFilePolicySkipIfMissing +) + +type ConfigFile struct { + Path string + Policy ConfigFilePolicy + modDate time.Time + exists bool +} + // NewAppConfig makes a new app config func NewAppConfig( name string, @@ -60,17 +78,22 @@ func NewAppConfig( return nil, err } - var userConfigPaths []string + var configFiles []*ConfigFile customConfigFiles := os.Getenv("LG_CONFIG_FILE") if customConfigFiles != "" { // Load user defined config files - userConfigPaths = strings.Split(customConfigFiles, ",") + userConfigPaths := strings.Split(customConfigFiles, ",") + configFiles = lo.Map(userConfigPaths, func(path string, _ int) *ConfigFile { + return &ConfigFile{Path: path, Policy: ConfigFilePolicyErrorIfMissing} + }) } else { // Load default config files - userConfigPaths = []string{filepath.Join(configDir, ConfigFilename)} + path := filepath.Join(configDir, ConfigFilename) + configFile := &ConfigFile{Path: path, Policy: ConfigFilePolicyCreateIfMissing} + configFiles = []*ConfigFile{configFile} } - userConfig, err := loadUserConfigWithDefaults(userConfigPaths) + userConfig, err := loadUserConfigWithDefaults(configFiles) if err != nil { return nil, err } @@ -92,26 +115,22 @@ func NewAppConfig( } appConfig := &AppConfig{ - Name: name, - Version: version, - BuildDate: date, - Debug: debuggingFlag, - BuildSource: buildSource, - UserConfig: userConfig, - UserConfigPaths: userConfigPaths, - UserConfigDir: configDir, - TempDir: tempDir, - AppState: appState, - IsNewRepo: false, + name: name, + version: version, + buildDate: date, + debug: debuggingFlag, + buildSource: buildSource, + userConfig: userConfig, + globalUserConfigFiles: configFiles, + userConfigFiles: configFiles, + userConfigDir: configDir, + tempDir: tempDir, + appState: appState, } return appConfig, nil } -func isCustomConfigFile(path string) bool { - return path != filepath.Join(ConfigDir(), ConfigFilename) -} - func ConfigDir() string { _, filePath := findConfigFile("config.yml") @@ -123,32 +142,48 @@ func findOrCreateConfigDir() (string, error) { return folder, os.MkdirAll(folder, 0o755) } -func loadUserConfigWithDefaults(configFiles []string) (*UserConfig, error) { +func loadUserConfigWithDefaults(configFiles []*ConfigFile) (*UserConfig, error) { return loadUserConfig(configFiles, GetDefaultConfig()) } -func loadUserConfig(configFiles []string, base *UserConfig) (*UserConfig, error) { - for _, path := range configFiles { - if _, err := os.Stat(path); err != nil { +func loadUserConfig(configFiles []*ConfigFile, base *UserConfig) (*UserConfig, error) { + for _, configFile := range configFiles { + path := configFile.Path + statInfo, err := os.Stat(path) + if err == nil { + configFile.exists = true + configFile.modDate = statInfo.ModTime() + } else { if !os.IsNotExist(err) { return nil, err } - // if use has supplied their own custom config file path(s), we assume - // the files have already been created, so we won't go and create them here. - if isCustomConfigFile(path) { + switch configFile.Policy { + case ConfigFilePolicyErrorIfMissing: return nil, err - } - file, err := os.Create(path) - if err != nil { - if os.IsPermission(err) { - // apparently when people have read-only permissions they prefer us to fail silently - continue + case ConfigFilePolicySkipIfMissing: + configFile.exists = false + continue + + case ConfigFilePolicyCreateIfMissing: + file, err := os.Create(path) + if err != nil { + if os.IsPermission(err) { + // apparently when people have read-only permissions they prefer us to fail silently + continue + } + return nil, err } - return nil, err + file.Close() + + configFile.exists = true + statInfo, err := os.Stat(configFile.Path) + if err != nil { + return nil, err + } + configFile.modDate = statInfo.ModTime() } - file.Close() } content, err := os.ReadFile(path) @@ -220,53 +255,81 @@ func changeNullKeybindingsToDisabled(changedContent []byte) ([]byte, error) { } func (c *AppConfig) GetDebug() bool { - return c.Debug + return c.debug } func (c *AppConfig) GetVersion() string { - return c.Version + return c.version } func (c *AppConfig) GetName() string { - return c.Name + return c.name } // GetBuildSource returns the source of the build. For builds from goreleaser // this will be binaryBuild func (c *AppConfig) GetBuildSource() string { - return c.BuildSource + return c.buildSource } // GetUserConfig returns the user config func (c *AppConfig) GetUserConfig() *UserConfig { - return c.UserConfig + return c.userConfig } // GetAppState returns the app state func (c *AppConfig) GetAppState() *AppState { - return c.AppState + return c.appState } func (c *AppConfig) GetUserConfigPaths() []string { - return c.UserConfigPaths + return lo.FilterMap(c.userConfigFiles, func(f *ConfigFile, _ int) (string, bool) { + return f.Path, f.exists + }) } func (c *AppConfig) GetUserConfigDir() string { - return c.UserConfigDir + return c.userConfigDir } -func (c *AppConfig) ReloadUserConfig() error { - userConfig, err := loadUserConfigWithDefaults(c.UserConfigPaths) +func (c *AppConfig) ReloadUserConfigForRepo(repoConfigFiles []*ConfigFile) error { + configFiles := append(c.globalUserConfigFiles, repoConfigFiles...) + userConfig, err := loadUserConfigWithDefaults(configFiles) if err != nil { return err } - c.UserConfig = userConfig + c.userConfig = userConfig + c.userConfigFiles = configFiles return nil } +func (c *AppConfig) ReloadChangedUserConfigFiles() (error, bool) { + fileHasChanged := func(f *ConfigFile) bool { + info, err := os.Stat(f.Path) + if err != nil && !os.IsNotExist(err) { + // If we can't stat the file, assume it hasn't changed + return false + } + exists := err == nil + return exists != f.exists || (exists && info.ModTime() != f.modDate) + } + + if lo.NoneBy(c.userConfigFiles, fileHasChanged) { + return nil, false + } + + userConfig, err := loadUserConfigWithDefaults(c.userConfigFiles) + if err != nil { + return err, false + } + + c.userConfig = userConfig + return nil, true +} + func (c *AppConfig) GetTempDir() string { - return c.TempDir + return c.tempDir } // findConfigFile looks for a possibly existing config file. @@ -305,14 +368,9 @@ func stateFilePath(filename string) (string, error) { return xdg.StateFile(filepath.Join("lazygit", filename)) } -// ConfigFilename returns the filename of the default config file -func (c *AppConfig) ConfigFilename() string { - return filepath.Join(c.UserConfigDir, ConfigFilename) -} - // SaveAppState marshalls the AppState struct and writes it to the disk func (c *AppConfig) SaveAppState() error { - marshalledAppState, err := yaml.Marshal(c.AppState) + marshalledAppState, err := yaml.Marshal(c.appState) if err != nil { return err } @@ -363,6 +421,24 @@ func loadAppState() (*AppState, error) { return appState, nil } +// SaveGlobalUserConfig saves the UserConfig back to disk. This is only used in +// integration tests, so we are a bit sloppy with error handling. +func (c *AppConfig) SaveGlobalUserConfig() { + if len(c.globalUserConfigFiles) != 1 { + panic("expected exactly one global user config file") + } + + yamlContent, err := yaml.Marshal(c.userConfig) + if err != nil { + log.Fatalf("error marshalling user config: %v", err) + } + + err = os.WriteFile(c.globalUserConfigFiles[0].Path, yamlContent, 0o644) + if err != nil { + log.Fatalf("error saving user config: %v", err) + } +} + // AppState stores data between runs of the app like when the last update check // was performed and which other repos have been checked out type AppState struct { diff --git a/pkg/config/dummies.go b/pkg/config/dummies.go index 077c93c57..06c8755a6 100644 --- a/pkg/config/dummies.go +++ b/pkg/config/dummies.go @@ -7,12 +7,12 @@ import ( // NewDummyAppConfig creates a new dummy AppConfig for testing func NewDummyAppConfig() *AppConfig { appConfig := &AppConfig{ - Name: "lazygit", - Version: "unversioned", - Debug: false, - UserConfig: GetDefaultConfig(), - AppState: &AppState{}, + name: "lazygit", + version: "unversioned", + debug: false, + userConfig: GetDefaultConfig(), + appState: &AppState{}, } - _ = yaml.Unmarshal([]byte{}, appConfig.AppState) + _ = yaml.Unmarshal([]byte{}, appConfig.appState) return appConfig } diff --git a/pkg/gui/background.go b/pkg/gui/background.go index 061502a43..7c81def39 100644 --- a/pkg/gui/background.go +++ b/pkg/gui/background.go @@ -25,7 +25,7 @@ func (self *BackgroundRoutineMgr) PauseBackgroundRefreshes(pause bool) { } func (self *BackgroundRoutineMgr) startBackgroundRoutines() { - userConfig := self.gui.UserConfig + userConfig := self.gui.UserConfig() if userConfig.Git.AutoFetch { fetchInterval := userConfig.Refresher.FetchInterval @@ -77,7 +77,7 @@ func (self *BackgroundRoutineMgr) startBackgroundFetch() { self.gui.waitForIntro.Wait() isNew := self.gui.IsNewRepo - userConfig := self.gui.UserConfig + userConfig := self.gui.UserConfig() if !isNew { time.After(time.Duration(userConfig.Refresher.FetchInterval) * time.Second) } diff --git a/pkg/gui/command_log_panel.go b/pkg/gui/command_log_panel.go index 2faee3572..fda8124c2 100644 --- a/pkg/gui/command_log_panel.go +++ b/pkg/gui/command_log_panel.go @@ -55,11 +55,11 @@ func (gui *Gui) LogCommand(cmdStr string, commandLine bool) { func (gui *Gui) printCommandLogHeader() { introStr := fmt.Sprintf( gui.c.Tr.CommandLogHeader, - keybindings.Label(gui.c.UserConfig.Keybinding.Universal.ExtrasMenu), + keybindings.Label(gui.c.UserConfig().Keybinding.Universal.ExtrasMenu), ) fmt.Fprintln(gui.Views.Extras, style.FgCyan.Sprint(introStr)) - if gui.c.UserConfig.Gui.ShowRandomTip { + if gui.c.UserConfig().Gui.ShowRandomTip { fmt.Fprintf( gui.Views.Extras, "%s: %s", @@ -70,7 +70,7 @@ func (gui *Gui) printCommandLogHeader() { } func (gui *Gui) getRandomTip() string { - config := gui.c.UserConfig.Keybinding + config := gui.c.UserConfig().Keybinding formattedKey := func(key string) string { return keybindings.Label(key) diff --git a/pkg/gui/context/branches_context.go b/pkg/gui/context/branches_context.go index d289f2729..3c274d684 100644 --- a/pkg/gui/context/branches_context.go +++ b/pkg/gui/context/branches_context.go @@ -32,7 +32,7 @@ func NewBranchesContext(c *ContextCommon) *BranchesContext { c.Modes().Diffing.Ref, c.Views().Branches.Width(), c.Tr, - c.UserConfig, + c.UserConfig(), c.Model().Worktrees, ) } diff --git a/pkg/gui/context/commit_files_context.go b/pkg/gui/context/commit_files_context.go index b56798fea..97c1728d1 100644 --- a/pkg/gui/context/commit_files_context.go +++ b/pkg/gui/context/commit_files_context.go @@ -28,7 +28,7 @@ func NewCommitFilesContext(c *ContextCommon) *CommitFilesContext { viewModel := filetree.NewCommitFileTreeViewModel( func() []*models.CommitFile { return c.Model().CommitFiles }, c.Log, - c.UserConfig.Gui.ShowFileTree, + c.UserConfig().Gui.ShowFileTree, ) getDisplayStrings := func(_ int, _ int) [][]string { @@ -36,7 +36,7 @@ func NewCommitFilesContext(c *ContextCommon) *CommitFilesContext { return [][]string{{style.FgRed.Sprint("(none)")}} } - showFileIcons := icons.IsIconEnabled() && c.UserConfig.Gui.ShowFileIcons + showFileIcons := icons.IsIconEnabled() && c.UserConfig().Gui.ShowFileIcons lines := presentation.RenderCommitFileTree(viewModel, c.Git().Patch.PatchBuilder, showFileIcons) return lo.Map(lines, func(line string, _ int) []string { return []string{line} diff --git a/pkg/gui/context/commit_message_context.go b/pkg/gui/context/commit_message_context.go index 402f9b12e..776043abe 100644 --- a/pkg/gui/context/commit_message_context.go +++ b/pkg/gui/context/commit_message_context.go @@ -113,19 +113,19 @@ func (self *CommitMessageContext) SetPanelState( self.c.Views().CommitDescription.Subtitle = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionSubTitle, map[string]string{ - "togglePanelKeyBinding": keybindings.Label(self.c.UserConfig.Keybinding.Universal.TogglePanel), - "commitMenuKeybinding": keybindings.Label(self.c.UserConfig.Keybinding.CommitMessage.CommitMenu), + "togglePanelKeyBinding": keybindings.Label(self.c.UserConfig().Keybinding.Universal.TogglePanel), + "commitMenuKeybinding": keybindings.Label(self.c.UserConfig().Keybinding.CommitMessage.CommitMenu), }) self.c.Views().CommitDescription.Visible = true } func (self *CommitMessageContext) RenderCommitLength() { - if !self.c.UserConfig.Gui.CommitLength.Show { - return + if self.c.UserConfig().Gui.CommitLength.Show { + self.c.Views().CommitMessage.Subtitle = getBufferLength(self.c.Views().CommitMessage) + } else { + self.c.Views().CommitMessage.Subtitle = "" } - - self.c.Views().CommitMessage.Subtitle = getBufferLength(self.c.Views().CommitMessage) } func getBufferLength(view *gocui.View) string { diff --git a/pkg/gui/context/local_commits_context.go b/pkg/gui/context/local_commits_context.go index aeab10e66..0cb7a628c 100644 --- a/pkg/gui/context/local_commits_context.go +++ b/pkg/gui/context/local_commits_context.go @@ -54,10 +54,10 @@ func NewLocalCommitsContext(c *ContextCommon) *LocalCommitsContext { c.Modes().CherryPicking.SelectedHashSet(), c.Modes().Diffing.Ref, c.Modes().MarkedBaseCommit.GetHash(), - c.UserConfig.Gui.TimeFormat, - c.UserConfig.Gui.ShortTimeFormat, + c.UserConfig().Gui.TimeFormat, + c.UserConfig().Gui.ShortTimeFormat, time.Now(), - c.UserConfig.Git.ParseEmoji, + c.UserConfig().Git.ParseEmoji, selectedCommitHash, startIdx, endIdx, @@ -110,7 +110,7 @@ func NewLocalCommitsViewModel(getModel func() []*models.Commit, c *ContextCommon self := &LocalCommitsViewModel{ ListViewModel: NewListViewModel(getModel), limitCommits: true, - showWholeGitGraph: c.UserConfig.Git.Log.ShowWholeGraph, + showWholeGitGraph: c.UserConfig().Git.Log.ShowWholeGraph, } return self diff --git a/pkg/gui/context/menu_context.go b/pkg/gui/context/menu_context.go index 06cdf8b46..ec738681c 100644 --- a/pkg/gui/context/menu_context.go +++ b/pkg/gui/context/menu_context.go @@ -139,7 +139,7 @@ func (self *MenuViewModel) GetNonModelItems() []*NonModelItem { // Don't display section headers when we are filtering, and the filter mode // is fuzzy. The reason is that filtering changes the order of the items // (they are sorted by best match), so all the sections would be messed up. - if self.FilteredListViewModel.IsFiltering() && self.c.UserConfig.Gui.UseFuzzySearch() { + if self.FilteredListViewModel.IsFiltering() && self.c.UserConfig().Gui.UseFuzzySearch() { return result } diff --git a/pkg/gui/context/reflog_commits_context.go b/pkg/gui/context/reflog_commits_context.go index cec54988d..403e5e91c 100644 --- a/pkg/gui/context/reflog_commits_context.go +++ b/pkg/gui/context/reflog_commits_context.go @@ -33,9 +33,9 @@ func NewReflogCommitsContext(c *ContextCommon) *ReflogCommitsContext { c.Modes().CherryPicking.SelectedHashSet(), c.Modes().Diffing.Ref, time.Now(), - c.UserConfig.Gui.TimeFormat, - c.UserConfig.Gui.ShortTimeFormat, - c.UserConfig.Git.ParseEmoji, + c.UserConfig().Gui.TimeFormat, + c.UserConfig().Gui.ShortTimeFormat, + c.UserConfig().Git.ParseEmoji, ) } diff --git a/pkg/gui/context/remotes_context.go b/pkg/gui/context/remotes_context.go index ae01bb56b..237783dca 100644 --- a/pkg/gui/context/remotes_context.go +++ b/pkg/gui/context/remotes_context.go @@ -26,7 +26,7 @@ func NewRemotesContext(c *ContextCommon) *RemotesContext { getDisplayStrings := func(_ int, _ int) [][]string { return presentation.GetRemoteListDisplayStrings( - viewModel.GetItems(), c.Modes().Diffing.Ref, c.State().GetItemOperation, c.Tr, c.UserConfig) + viewModel.GetItems(), c.Modes().Diffing.Ref, c.State().GetItemOperation, c.Tr, c.UserConfig()) } return &RemotesContext{ diff --git a/pkg/gui/context/search_trait.go b/pkg/gui/context/search_trait.go index b8faf0757..0b01ee8d6 100644 --- a/pkg/gui/context/search_trait.go +++ b/pkg/gui/context/search_trait.go @@ -51,7 +51,7 @@ func (self *SearchTrait) onSelectItemWrapper(innerFunc func(int) error) func(int } func (self *SearchTrait) RenderSearchStatus(index int, total int) { - keybindingConfig := self.c.UserConfig.Keybinding + keybindingConfig := self.c.UserConfig().Keybinding if total == 0 { self.c.SetViewContent( diff --git a/pkg/gui/context/sub_commits_context.go b/pkg/gui/context/sub_commits_context.go index 7a9dfa476..d1a63b750 100644 --- a/pkg/gui/context/sub_commits_context.go +++ b/pkg/gui/context/sub_commits_context.go @@ -68,10 +68,10 @@ func NewSubCommitsContext( c.Modes().CherryPicking.SelectedHashSet(), c.Modes().Diffing.Ref, "", - c.UserConfig.Gui.TimeFormat, - c.UserConfig.Gui.ShortTimeFormat, + c.UserConfig().Gui.TimeFormat, + c.UserConfig().Gui.ShortTimeFormat, time.Now(), - c.UserConfig.Git.ParseEmoji, + c.UserConfig().Git.ParseEmoji, selectedCommitHash, startIdx, endIdx, diff --git a/pkg/gui/context/tags_context.go b/pkg/gui/context/tags_context.go index b956c77f4..39ae60702 100644 --- a/pkg/gui/context/tags_context.go +++ b/pkg/gui/context/tags_context.go @@ -30,7 +30,7 @@ func NewTagsContext( return presentation.GetTagListDisplayStrings( viewModel.GetItems(), c.State().GetItemOperation, - c.Modes().Diffing.Ref, c.Tr, c.UserConfig) + c.Modes().Diffing.Ref, c.Tr, c.UserConfig()) } return &TagsContext{ diff --git a/pkg/gui/context/working_tree_context.go b/pkg/gui/context/working_tree_context.go index 76eb56d57..88d2ab9fe 100644 --- a/pkg/gui/context/working_tree_context.go +++ b/pkg/gui/context/working_tree_context.go @@ -25,11 +25,11 @@ func NewWorkingTreeContext(c *ContextCommon) *WorkingTreeContext { viewModel := filetree.NewFileTreeViewModel( func() []*models.File { return c.Model().Files }, c.Log, - c.UserConfig.Gui.ShowFileTree, + c.UserConfig().Gui.ShowFileTree, ) getDisplayStrings := func(_ int, _ int) [][]string { - showFileIcons := icons.IsIconEnabled() && c.UserConfig.Gui.ShowFileIcons + showFileIcons := icons.IsIconEnabled() && c.UserConfig().Gui.ShowFileIcons lines := presentation.RenderFileTree(viewModel, c.Model().Submodules, showFileIcons) return lo.Map(lines, func(line string, _ int) []string { return []string{line} diff --git a/pkg/gui/controllers/basic_commits_controller.go b/pkg/gui/controllers/basic_commits_controller.go index 22e3da9d5..9d3595a61 100644 --- a/pkg/gui/controllers/basic_commits_controller.go +++ b/pkg/gui/controllers/basic_commits_controller.go @@ -311,8 +311,8 @@ func (self *BasicCommitsController) canCopyCommits(selectedCommits []*models.Com func (self *BasicCommitsController) handleOldCherryPickKey() error { msg := utils.ResolvePlaceholderString(self.c.Tr.OldCherryPickKeyWarning, map[string]string{ - "copy": keybindings.Label(self.c.UserConfig.Keybinding.Commits.CherryPickCopy), - "paste": keybindings.Label(self.c.UserConfig.Keybinding.Commits.PasteCommits), + "copy": keybindings.Label(self.c.UserConfig().Keybinding.Commits.CherryPickCopy), + "paste": keybindings.Label(self.c.UserConfig().Keybinding.Commits.PasteCommits), }) return errors.New(msg) diff --git a/pkg/gui/controllers/commit_message_controller.go b/pkg/gui/controllers/commit_message_controller.go index d989086c4..ec60b4da5 100644 --- a/pkg/gui/controllers/commit_message_controller.go +++ b/pkg/gui/controllers/commit_message_controller.go @@ -118,8 +118,8 @@ func (self *CommitMessageController) setCommitMessageAtIndex(index int) (bool, e } return false, errors.New(self.c.Tr.CommitWithoutMessageErr) } - if self.c.UserConfig.Git.Commit.AutoWrapCommitMessage { - commitMessage = helpers.TryRemoveHardLineBreaks(commitMessage, self.c.UserConfig.Git.Commit.AutoWrapWidth) + if self.c.UserConfig().Git.Commit.AutoWrapCommitMessage { + commitMessage = helpers.TryRemoveHardLineBreaks(commitMessage, self.c.UserConfig().Git.Commit.AutoWrapWidth) } self.c.Helpers().Commits.UpdateCommitPanelView(commitMessage) return true, nil diff --git a/pkg/gui/controllers/confirmation_controller.go b/pkg/gui/controllers/confirmation_controller.go index 542458a71..042f83115 100644 --- a/pkg/gui/controllers/confirmation_controller.go +++ b/pkg/gui/controllers/confirmation_controller.go @@ -46,7 +46,7 @@ func (self *ConfirmationController) GetKeybindings(opts types.KeybindingsOpts) [ // We assume that whenever things are deletable, they // are also editable, so we show both keybindings subtitle = fmt.Sprintf(self.c.Tr.SuggestionsSubtitle, - self.c.UserConfig.Keybinding.Universal.Remove, self.c.UserConfig.Keybinding.Universal.Edit) + self.c.UserConfig().Keybinding.Universal.Remove, self.c.UserConfig().Keybinding.Universal.Edit) } self.c.Views().Suggestions.Subtitle = subtitle return self.c.Context().Replace(self.c.Contexts().Suggestions) diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index 934aca511..65ea941fd 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -258,7 +258,7 @@ func (self *FilesController) GetOnRenderToMain() func() error { pair = self.c.MainViewPairs().Staging } - split := self.c.UserConfig.Gui.SplitDiff == "always" || (node.GetHasUnstagedChanges() && node.GetHasStagedChanges()) + split := self.c.UserConfig().Gui.SplitDiff == "always" || (node.GetHasUnstagedChanges() && node.GetHasStagedChanges()) mainShowsStaged := !split && node.GetHasStagedChanges() cmdObj := self.c.Git().WorkingTree.WorktreeFileDiffCmdObj(node, false, mainShowsStaged) @@ -1083,7 +1083,7 @@ func (self *FilesController) remove(selectedNodes []*filetree.FileNode) error { return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES, types.WORKTREES}}) }, - Key: self.c.KeybindingsOpts().GetKey(self.c.UserConfig.Keybinding.Files.ConfirmDiscard), + Key: self.c.KeybindingsOpts().GetKey(self.c.UserConfig().Keybinding.Files.ConfirmDiscard), Tooltip: utils.ResolvePlaceholderString( self.c.Tr.DiscardAllTooltip, map[string]string{ diff --git a/pkg/gui/controllers/helpers/app_status_helper.go b/pkg/gui/controllers/helpers/app_status_helper.go index b0d1b3818..cf94c58cd 100644 --- a/pkg/gui/controllers/helpers/app_status_helper.go +++ b/pkg/gui/controllers/helpers/app_status_helper.go @@ -81,16 +81,16 @@ func (self *AppStatusHelper) HasStatus() bool { } func (self *AppStatusHelper) GetStatusString() string { - appStatus, _ := self.statusMgr().GetStatusString(self.c.UserConfig) + appStatus, _ := self.statusMgr().GetStatusString(self.c.UserConfig()) return appStatus } func (self *AppStatusHelper) renderAppStatus() { self.c.OnWorker(func(_ gocui.Task) error { - ticker := time.NewTicker(time.Millisecond * time.Duration(self.c.UserConfig.Gui.Spinner.Rate)) + ticker := time.NewTicker(time.Millisecond * time.Duration(self.c.UserConfig().Gui.Spinner.Rate)) defer ticker.Stop() for range ticker.C { - appStatus, color := self.statusMgr().GetStatusString(self.c.UserConfig) + appStatus, color := self.statusMgr().GetStatusString(self.c.UserConfig()) self.c.Views().AppStatus.FgColor = color self.c.OnUIThread(func() error { self.c.SetViewContent(self.c.Views().AppStatus, appStatus) @@ -124,7 +124,7 @@ func (self *AppStatusHelper) renderAppStatusSync(stop chan struct{}) { for { select { case <-ticker.C: - appStatus, color := self.statusMgr().GetStatusString(self.c.UserConfig) + appStatus, color := self.statusMgr().GetStatusString(self.c.UserConfig()) self.c.Views().AppStatus.FgColor = color self.c.SetViewContent(self.c.Views().AppStatus, appStatus) // Redraw all views of the bottom line: diff --git a/pkg/gui/controllers/helpers/confirmation_helper.go b/pkg/gui/controllers/helpers/confirmation_helper.go index fa2b502a9..25f05906b 100644 --- a/pkg/gui/controllers/helpers/confirmation_helper.go +++ b/pkg/gui/controllers/helpers/confirmation_helper.go @@ -173,7 +173,7 @@ func (self *ConfirmationHelper) prepareConfirmationPanel( suggestionsView.FgColor = theme.GocuiDefaultTextColor suggestionsContext.SetSuggestions(opts.FindSuggestionsFunc("")) suggestionsView.Visible = true - suggestionsView.Title = fmt.Sprintf(self.c.Tr.SuggestionsTitle, self.c.UserConfig.Keybinding.Universal.TogglePanel) + suggestionsView.Title = fmt.Sprintf(self.c.Tr.SuggestionsTitle, self.c.UserConfig().Keybinding.Universal.TogglePanel) suggestionsView.Subtitle = "" } diff --git a/pkg/gui/controllers/helpers/gpg_helper.go b/pkg/gui/controllers/helpers/gpg_helper.go index a49c0cb38..6974e1c5c 100644 --- a/pkg/gui/controllers/helpers/gpg_helper.go +++ b/pkg/gui/controllers/helpers/gpg_helper.go @@ -46,7 +46,7 @@ func (self *GpgHelper) runAndStream(cmdObj oscommands.ICmdObj, waitingStatus str if err := cmdObj.StreamOutput().Run(); err != nil { _ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) return fmt.Errorf( - self.c.Tr.GitCommandFailed, self.c.UserConfig.Keybinding.Universal.ExtrasMenu, + self.c.Tr.GitCommandFailed, self.c.UserConfig().Keybinding.Universal.ExtrasMenu, ) } diff --git a/pkg/gui/controllers/helpers/host_helper.go b/pkg/gui/controllers/helpers/host_helper.go index bbd464ba8..ab8631d36 100644 --- a/pkg/gui/controllers/helpers/host_helper.go +++ b/pkg/gui/controllers/helpers/host_helper.go @@ -46,6 +46,6 @@ func (self *HostHelper) getHostingServiceMgr() (*hosting_service.HostingServiceM if err != nil { return nil, err } - configServices := self.c.UserConfig.Services + configServices := self.c.UserConfig().Services return hosting_service.NewHostingServiceMgr(self.c.Log, self.c.Tr, remoteUrl, configServices), nil } diff --git a/pkg/gui/controllers/helpers/inline_status_helper.go b/pkg/gui/controllers/helpers/inline_status_helper.go index b13f19473..cc9da86ea 100644 --- a/pkg/gui/controllers/helpers/inline_status_helper.go +++ b/pkg/gui/controllers/helpers/inline_status_helper.go @@ -99,7 +99,7 @@ func (self *InlineStatusHelper) start(opts InlineStatusOpts) { self.contextsWithInlineStatus[opts.ContextKey] = info go utils.Safe(func() { - ticker := time.NewTicker(time.Millisecond * time.Duration(self.c.UserConfig.Gui.Spinner.Rate)) + ticker := time.NewTicker(time.Millisecond * time.Duration(self.c.UserConfig().Gui.Spinner.Rate)) defer ticker.Stop() outer: for { diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go index 73c345070..7ce60701d 100644 --- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go +++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go @@ -112,7 +112,7 @@ func (self *MergeAndRebaseHelper) genericMergeCommand(command string) error { // we should end up with a command like 'git merge --continue' // it's impossible for a rebase to require a commit so we'll use a subprocess only if it's a merge - needsSubprocess := (status == enums.REBASE_MODE_MERGING && command != REBASE_OPTION_ABORT && self.c.UserConfig.Git.Merging.ManualCommit) || + needsSubprocess := (status == enums.REBASE_MODE_MERGING && command != REBASE_OPTION_ABORT && self.c.UserConfig().Git.Merging.ManualCommit) || // but we'll also use a subprocess if we have exec todos; those are likely to be lengthy build // tasks whose output the user will want to see in the terminal (status == enums.REBASE_MODE_REBASING && command != REBASE_OPTION_ABORT && self.hasExecTodos()) @@ -435,7 +435,7 @@ func (self *MergeAndRebaseHelper) SquashMergeCommitted(refName, checkedOutBranch if err = self.CheckMergeOrRebase(err); err != nil { return err } - message := utils.ResolvePlaceholderString(self.c.UserConfig.Git.Merging.SquashMergeMessage, map[string]string{ + message := utils.ResolvePlaceholderString(self.c.UserConfig().Git.Merging.SquashMergeMessage, map[string]string{ "selectedRef": refName, "currentBranch": checkedOutBranchName, }) diff --git a/pkg/gui/controllers/helpers/refresh_helper.go b/pkg/gui/controllers/helpers/refresh_helper.go index 4295c11ab..e29879b9d 100644 --- a/pkg/gui/controllers/helpers/refresh_helper.go +++ b/pkg/gui/controllers/helpers/refresh_helper.go @@ -737,7 +737,7 @@ func (self *RefreshHelper) refreshStatus() { repoName := self.c.Git().RepoPaths.RepoName() - status := presentation.FormatStatus(repoName, currentBranch, types.ItemOperationNone, linkedWorktreeName, workingTreeState, self.c.Tr, self.c.UserConfig) + status := presentation.FormatStatus(repoName, currentBranch, types.ItemOperationNone, linkedWorktreeName, workingTreeState, self.c.Tr, self.c.UserConfig()) self.c.SetViewContent(self.c.Views().Status, status) } diff --git a/pkg/gui/controllers/helpers/refs_helper.go b/pkg/gui/controllers/helpers/refs_helper.go index ceadc8dfa..63a288f80 100644 --- a/pkg/gui/controllers/helpers/refs_helper.go +++ b/pkg/gui/controllers/helpers/refs_helper.go @@ -275,7 +275,7 @@ func (self *RefsHelper) NewBranch(from string, fromFormattedName string, suggest ) if suggestedBranchName == "" { - suggestedBranchName = self.c.UserConfig.Git.BranchPrefix + suggestedBranchName = self.c.UserConfig().Git.BranchPrefix } return self.c.Prompt(types.PromptOpts{ diff --git a/pkg/gui/controllers/helpers/search_helper.go b/pkg/gui/controllers/helpers/search_helper.go index b282f0c66..0480cd095 100644 --- a/pkg/gui/controllers/helpers/search_helper.go +++ b/pkg/gui/controllers/helpers/search_helper.go @@ -76,7 +76,7 @@ func (self *SearchHelper) DisplayFilterStatus(context types.IFilterableContext) self.searchPrefixView().SetContent(self.c.Tr.FilterPrefix) promptView := self.promptView() - keybindingConfig := self.c.UserConfig.Keybinding + keybindingConfig := self.c.UserConfig().Keybinding promptView.SetContent(fmt.Sprintf("matches for '%s' ", searchString) + theme.OptionsFgColor.Sprintf(self.c.Tr.ExitTextFilterMode, keybindings.Label(keybindingConfig.Universal.Return))) } @@ -229,7 +229,7 @@ func (self *SearchHelper) OnPromptContentChanged(searchString string) { case types.IFilterableContext: context.SetSelection(0) _ = context.GetView().SetOriginY(0) - context.SetFilter(searchString, self.c.UserConfig.Gui.UseFuzzySearch()) + context.SetFilter(searchString, self.c.UserConfig().Gui.UseFuzzySearch()) _ = self.c.PostRefreshUpdate(context) case types.ISearchableContext: // do nothing @@ -246,7 +246,7 @@ func (self *SearchHelper) ReApplyFilter(context types.Context) { filterableContext.SetSelection(0) _ = filterableContext.GetView().SetOriginY(0) } - filterableContext.ReApplyFilter(self.c.UserConfig.Gui.UseFuzzySearch()) + filterableContext.ReApplyFilter(self.c.UserConfig().Gui.UseFuzzySearch()) } } diff --git a/pkg/gui/controllers/helpers/suggestions_helper.go b/pkg/gui/controllers/helpers/suggestions_helper.go index ff8aeea71..441a488b5 100644 --- a/pkg/gui/controllers/helpers/suggestions_helper.go +++ b/pkg/gui/controllers/helpers/suggestions_helper.go @@ -66,7 +66,7 @@ func matchesToSuggestions(matches []string) []*types.Suggestion { func (self *SuggestionsHelper) GetRemoteSuggestionsFunc() func(string) []*types.Suggestion { remoteNames := self.getRemoteNames() - return FilterFunc(remoteNames, self.c.UserConfig.Gui.UseFuzzySearch()) + return FilterFunc(remoteNames, self.c.UserConfig().Gui.UseFuzzySearch()) } func (self *SuggestionsHelper) getBranchNames() []string { @@ -83,7 +83,7 @@ func (self *SuggestionsHelper) GetBranchNameSuggestionsFunc() func(string) []*ty if input == "" { matchingBranchNames = branchNames } else { - matchingBranchNames = utils.FilterStrings(input, branchNames, self.c.UserConfig.Gui.UseFuzzySearch()) + matchingBranchNames = utils.FilterStrings(input, branchNames, self.c.UserConfig().Gui.UseFuzzySearch()) } return lo.Map(matchingBranchNames, func(branchName string, _ int) *types.Suggestion { @@ -129,7 +129,7 @@ func (self *SuggestionsHelper) GetFilePathSuggestionsFunc() func(string) []*type return func(input string) []*types.Suggestion { matchingNames := []string{} - if self.c.UserConfig.Gui.UseFuzzySearch() { + if self.c.UserConfig().Gui.UseFuzzySearch() { _ = self.c.Model().FilesTrie.VisitFuzzy(patricia.Prefix(input), true, func(prefix patricia.Prefix, item patricia.Item, skipped int) error { matchingNames = append(matchingNames, item.(string)) return nil @@ -163,7 +163,7 @@ func (self *SuggestionsHelper) getRemoteBranchNames(separator string) []string { } func (self *SuggestionsHelper) GetRemoteBranchesSuggestionsFunc(separator string) func(string) []*types.Suggestion { - return FilterFunc(self.getRemoteBranchNames(separator), self.c.UserConfig.Gui.UseFuzzySearch()) + return FilterFunc(self.getRemoteBranchNames(separator), self.c.UserConfig().Gui.UseFuzzySearch()) } func (self *SuggestionsHelper) getTagNames() []string { @@ -175,7 +175,7 @@ func (self *SuggestionsHelper) getTagNames() []string { func (self *SuggestionsHelper) GetTagsSuggestionsFunc() func(string) []*types.Suggestion { tagNames := self.getTagNames() - return FilterFunc(tagNames, self.c.UserConfig.Gui.UseFuzzySearch()) + return FilterFunc(tagNames, self.c.UserConfig().Gui.UseFuzzySearch()) } func (self *SuggestionsHelper) GetRefsSuggestionsFunc() func(string) []*types.Suggestion { @@ -186,7 +186,7 @@ func (self *SuggestionsHelper) GetRefsSuggestionsFunc() func(string) []*types.Su refNames := append(append(append(remoteBranchNames, localBranchNames...), tagNames...), additionalRefNames...) - return FilterFunc(refNames, self.c.UserConfig.Gui.UseFuzzySearch()) + return FilterFunc(refNames, self.c.UserConfig().Gui.UseFuzzySearch()) } func (self *SuggestionsHelper) GetAuthorsSuggestionsFunc() func(string) []*types.Suggestion { @@ -196,7 +196,7 @@ func (self *SuggestionsHelper) GetAuthorsSuggestionsFunc() func(string) []*types slices.Sort(authors) - return FilterFunc(authors, self.c.UserConfig.Gui.UseFuzzySearch()) + return FilterFunc(authors, self.c.UserConfig().Gui.UseFuzzySearch()) } func FilterFunc(options []string, useFuzzySearch bool) func(string) []*types.Suggestion { diff --git a/pkg/gui/controllers/helpers/tags_helper.go b/pkg/gui/controllers/helpers/tags_helper.go index 542037fba..8725eb054 100644 --- a/pkg/gui/controllers/helpers/tags_helper.go +++ b/pkg/gui/controllers/helpers/tags_helper.go @@ -48,8 +48,8 @@ func (self *TagsHelper) OpenCreateTagPrompt(ref string, onCreate func()) error { self.c.Tr.ForceTagPrompt, map[string]string{ "tagName": tagName, - "cancelKey": self.c.UserConfig.Keybinding.Universal.Return, - "confirmKey": self.c.UserConfig.Keybinding.Universal.Confirm, + "cancelKey": self.c.UserConfig().Keybinding.Universal.Return, + "confirmKey": self.c.UserConfig().Keybinding.Universal.Confirm, }, ) return self.c.Confirm(types.ConfirmOpts{ diff --git a/pkg/gui/controllers/helpers/update_helper.go b/pkg/gui/controllers/helpers/update_helper.go index f50a757de..e01bae3c6 100644 --- a/pkg/gui/controllers/helpers/update_helper.go +++ b/pkg/gui/controllers/helpers/update_helper.go @@ -31,7 +31,7 @@ func (self *UpdateHelper) CheckForUpdateInBackground() { if newVersion == "" { return nil } - if self.c.UserConfig.Update.Method == "background" { + if self.c.UserConfig().Update.Method == "background" { self.startUpdating(newVersion) return nil } diff --git a/pkg/gui/controllers/helpers/window_arrangement_helper.go b/pkg/gui/controllers/helpers/window_arrangement_helper.go index d27e9aa82..d4ac4ee60 100644 --- a/pkg/gui/controllers/helpers/window_arrangement_helper.go +++ b/pkg/gui/controllers/helpers/window_arrangement_helper.go @@ -87,7 +87,7 @@ func (self *WindowArrangementHelper) GetWindowDimensions(informationStr string, args := WindowArrangementArgs{ Width: width, Height: height, - UserConfig: self.c.UserConfig, + UserConfig: self.c.UserConfig(), CurrentWindow: self.windowHelper.CurrentWindow(), CurrentSideWindow: self.c.Context().CurrentSide().GetWindowName(), CurrentStaticWindow: self.c.Context().CurrentStatic().GetWindowName(), diff --git a/pkg/gui/controllers/helpers/working_tree_helper.go b/pkg/gui/controllers/helpers/working_tree_helper.go index 51a6bc553..96baaeebe 100644 --- a/pkg/gui/controllers/helpers/working_tree_helper.go +++ b/pkg/gui/controllers/helpers/working_tree_helper.go @@ -136,7 +136,7 @@ func (self *WorkingTreeHelper) HandleCommitEditorPress() error { } func (self *WorkingTreeHelper) HandleWIPCommitPress() error { - skipHookPrefix := self.c.UserConfig.Git.SkipHookPrefix + skipHookPrefix := self.c.UserConfig().Git.SkipHookPrefix if skipHookPrefix == "" { return errors.New(self.c.Tr.SkipHookPrefixNotConfigured) } @@ -209,7 +209,7 @@ func (self *WorkingTreeHelper) syncRefresh() error { func (self *WorkingTreeHelper) prepareFilesForCommit() error { noStagedFiles := !self.AnyStagedFiles() - if noStagedFiles && self.c.UserConfig.Gui.SkipNoStagedFilesWarning { + if noStagedFiles && self.c.UserConfig().Gui.SkipNoStagedFilesWarning { self.c.LogAction(self.c.Tr.Actions.StageAllFiles) err := self.c.Git().WorkingTree.StageAll() if err != nil { @@ -223,10 +223,10 @@ func (self *WorkingTreeHelper) prepareFilesForCommit() error { } func (self *WorkingTreeHelper) commitPrefixConfigForRepo() *config.CommitPrefixConfig { - cfg, ok := self.c.UserConfig.Git.CommitPrefixes[self.c.Git().RepoPaths.RepoName()] + cfg, ok := self.c.UserConfig().Git.CommitPrefixes[self.c.Git().RepoPaths.RepoName()] if ok { return &cfg } - return self.c.UserConfig.Git.CommitPrefix + return self.c.UserConfig().Git.CommitPrefix } diff --git a/pkg/gui/controllers/list_controller.go b/pkg/gui/controllers/list_controller.go index b63954501..7e51c504d 100644 --- a/pkg/gui/controllers/list_controller.go +++ b/pkg/gui/controllers/list_controller.go @@ -51,7 +51,7 @@ func (self *ListController) HandleScrollRight() error { } func (self *ListController) HandleScrollUp() error { - scrollHeight := self.c.UserConfig.Gui.ScrollHeight + scrollHeight := self.c.UserConfig().Gui.ScrollHeight self.context.GetViewTrait().ScrollUp(scrollHeight) if self.context.RenderOnlyVisibleLines() { return self.context.HandleRender() @@ -61,7 +61,7 @@ func (self *ListController) HandleScrollUp() error { } func (self *ListController) HandleScrollDown() error { - scrollHeight := self.c.UserConfig.Gui.ScrollHeight + scrollHeight := self.c.UserConfig().Gui.ScrollHeight self.context.GetViewTrait().ScrollDown(scrollHeight) if self.context.RenderOnlyVisibleLines() { return self.context.HandleRender() @@ -106,10 +106,10 @@ func (self *ListController) handleLineChangeAux(f func(int), change int) error { cursorMoved := before != after if cursorMoved { if change == -1 { - checkScrollUp(self.context.GetViewTrait(), self.c.UserConfig, + checkScrollUp(self.context.GetViewTrait(), self.c.UserConfig(), self.context.ModelIndexToViewIndex(before), self.context.ModelIndexToViewIndex(after)) } else if change == 1 { - checkScrollDown(self.context.GetViewTrait(), self.c.UserConfig, + checkScrollDown(self.context.GetViewTrait(), self.c.UserConfig(), self.context.ModelIndexToViewIndex(before), self.context.ModelIndexToViewIndex(after)) } } diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index 913601b5c..3900d7f32 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -357,8 +357,8 @@ func (self *LocalCommitsController) reword(commit *models.Commit) error { if err != nil { return err } - if self.c.UserConfig.Git.Commit.AutoWrapCommitMessage { - commitMessage = helpers.TryRemoveHardLineBreaks(commitMessage, self.c.UserConfig.Git.Commit.AutoWrapWidth) + if self.c.UserConfig().Git.Commit.AutoWrapCommitMessage { + commitMessage = helpers.TryRemoveHardLineBreaks(commitMessage, self.c.UserConfig().Git.Commit.AutoWrapWidth) } return self.c.Helpers().Commits.OpenCommitMessagePanel( &helpers.OpenCommitMessagePanelOpts{ @@ -438,7 +438,7 @@ func (self *LocalCommitsController) doRewordEditor() error { } func (self *LocalCommitsController) rewordEditor(commit *models.Commit) error { - if self.c.UserConfig.Gui.SkipRewordInEditorWarning { + if self.c.UserConfig().Gui.SkipRewordInEditorWarning { return self.doRewordEditor() } else { return self.c.Confirm(types.ConfirmOpts{ @@ -564,7 +564,7 @@ func (self *LocalCommitsController) findCommitForQuickStartInteractiveRebase() ( if !ok || index == 0 { errorMsg := utils.ResolvePlaceholderString(self.c.Tr.CannotQuickStartInteractiveRebase, map[string]string{ - "editKey": keybindings.Label(self.c.UserConfig.Keybinding.Universal.Edit), + "editKey": keybindings.Label(self.c.UserConfig().Keybinding.Universal.Edit), }) return nil, errors.New(errorMsg) @@ -905,8 +905,8 @@ func (self *LocalCommitsController) createAmendCommit(commit *models.Commit, inc if err != nil { return err } - if self.c.UserConfig.Git.Commit.AutoWrapCommitMessage { - commitMessage = helpers.TryRemoveHardLineBreaks(commitMessage, self.c.UserConfig.Git.Commit.AutoWrapWidth) + if self.c.UserConfig().Git.Commit.AutoWrapCommitMessage { + commitMessage = helpers.TryRemoveHardLineBreaks(commitMessage, self.c.UserConfig().Git.Commit.AutoWrapWidth) } originalSubject, _, _ := strings.Cut(commitMessage, "\n") return self.c.Helpers().Commits.OpenCommitMessagePanel( diff --git a/pkg/gui/controllers/merge_conflicts_controller.go b/pkg/gui/controllers/merge_conflicts_controller.go index 7ed5762f7..06bfda94f 100644 --- a/pkg/gui/controllers/merge_conflicts_controller.go +++ b/pkg/gui/controllers/merge_conflicts_controller.go @@ -173,14 +173,14 @@ func (self *MergeConflictsController) GetOnFocusLost() func(types.OnFocusLostOpt func (self *MergeConflictsController) HandleScrollUp() error { self.context().SetUserScrolling(true) - self.context().GetViewTrait().ScrollUp(self.c.UserConfig.Gui.ScrollHeight) + self.context().GetViewTrait().ScrollUp(self.c.UserConfig().Gui.ScrollHeight) return nil } func (self *MergeConflictsController) HandleScrollDown() error { self.context().SetUserScrolling(true) - self.context().GetViewTrait().ScrollDown(self.c.UserConfig.Gui.ScrollHeight) + self.context().GetViewTrait().ScrollDown(self.c.UserConfig().Gui.ScrollHeight) return nil } diff --git a/pkg/gui/controllers/patch_explorer_controller.go b/pkg/gui/controllers/patch_explorer_controller.go index 2df62b0f3..6d3290f04 100644 --- a/pkg/gui/controllers/patch_explorer_controller.go +++ b/pkg/gui/controllers/patch_explorer_controller.go @@ -173,7 +173,7 @@ func (self *PatchExplorerController) HandlePrevLine() error { after := self.context.GetState().GetSelectedLineIdx() if self.context.GetState().SelectingLine() { - checkScrollUp(self.context.GetViewTrait(), self.c.UserConfig, before, after) + checkScrollUp(self.context.GetViewTrait(), self.c.UserConfig(), before, after) } return nil @@ -185,7 +185,7 @@ func (self *PatchExplorerController) HandleNextLine() error { after := self.context.GetState().GetSelectedLineIdx() if self.context.GetState().SelectingLine() { - checkScrollDown(self.context.GetViewTrait(), self.c.UserConfig, before, after) + checkScrollDown(self.context.GetViewTrait(), self.c.UserConfig(), before, after) } return nil diff --git a/pkg/gui/controllers/quit_actions.go b/pkg/gui/controllers/quit_actions.go index f7cd8e56f..762260331 100644 --- a/pkg/gui/controllers/quit_actions.go +++ b/pkg/gui/controllers/quit_actions.go @@ -25,7 +25,7 @@ func (self *QuitActions) quitAux() error { return self.confirmQuitDuringUpdate() } - if self.c.UserConfig.ConfirmOnQuit { + if self.c.UserConfig().ConfirmOnQuit { return self.c.Confirm(types.ConfirmOpts{ Title: "", Prompt: self.c.Tr.ConfirmQuit, @@ -88,7 +88,7 @@ func (self *QuitActions) Escape() error { return self.c.Helpers().Repos.DispatchSwitchToRepo(repoPathStack.Pop(), context.NO_CONTEXT) } - if self.c.UserConfig.QuitOnTopLevelReturn { + if self.c.UserConfig().QuitOnTopLevelReturn { return self.Quit() } diff --git a/pkg/gui/controllers/shell_command_action.go b/pkg/gui/controllers/shell_command_action.go index 7393c188c..943006ff9 100644 --- a/pkg/gui/controllers/shell_command_action.go +++ b/pkg/gui/controllers/shell_command_action.go @@ -60,7 +60,7 @@ func (self *ShellCommandAction) GetShellCommandsHistorySuggestionsFunc() func(st return func(input string) []*types.Suggestion { history := self.c.GetAppState().ShellCommandsHistory - return helpers.FilterFunc(history, self.c.UserConfig.Gui.UseFuzzySearch())(input) + return helpers.FilterFunc(history, self.c.UserConfig().Gui.UseFuzzySearch())(input) } } diff --git a/pkg/gui/controllers/staging_controller.go b/pkg/gui/controllers/staging_controller.go index c3dcbafde..deac75a6c 100644 --- a/pkg/gui/controllers/staging_controller.go +++ b/pkg/gui/controllers/staging_controller.go @@ -190,7 +190,7 @@ func (self *StagingController) ToggleStaged() error { func (self *StagingController) DiscardSelection() error { reset := func() error { return self.applySelectionAndRefresh(true) } - if !self.staged && !self.c.UserConfig.Gui.SkipDiscardChangeWarning { + if !self.staged && !self.c.UserConfig().Gui.SkipDiscardChangeWarning { return self.c.Confirm(types.ConfirmOpts{ Title: self.c.Tr.DiscardChangeTitle, Prompt: self.c.Tr.DiscardChangePrompt, diff --git a/pkg/gui/controllers/stash_controller.go b/pkg/gui/controllers/stash_controller.go index 403c22b67..9f6884b59 100644 --- a/pkg/gui/controllers/stash_controller.go +++ b/pkg/gui/controllers/stash_controller.go @@ -114,7 +114,7 @@ func (self *StashController) handleStashApply(stashEntry *models.StashEntry) err return nil } - if self.c.UserConfig.Gui.SkipStashWarning { + if self.c.UserConfig().Gui.SkipStashWarning { return apply() } @@ -138,7 +138,7 @@ func (self *StashController) handleStashPop(stashEntry *models.StashEntry) error return nil } - if self.c.UserConfig.Gui.SkipStashWarning { + if self.c.UserConfig().Gui.SkipStashWarning { return pop() } diff --git a/pkg/gui/controllers/status_controller.go b/pkg/gui/controllers/status_controller.go index cdfa08257..05b3181c1 100644 --- a/pkg/gui/controllers/status_controller.go +++ b/pkg/gui/controllers/status_controller.go @@ -89,15 +89,15 @@ func (self *StatusController) onClickMain(opts gocui.ViewMouseBindingOpts) error } func (self *StatusController) GetOnRenderToMain() func() error { - config := self.c.UserConfig.Gui - - switch config.StatusPanelView { - case "dashboard": - return self.showDashboard - case "allBranchesLog": - return self.showAllBranchLogs - default: - return self.showDashboard + return func() error { + switch self.c.UserConfig().Gui.StatusPanelView { + case "dashboard": + return self.showDashboard() + case "allBranchesLog": + return self.showAllBranchLogs() + default: + return self.showDashboard() + } } } @@ -117,7 +117,7 @@ func (self *StatusController) onClick(opts gocui.ViewMouseBindingOpts) error { return err } - upstreamStatus := utils.Decolorise(presentation.BranchStatus(currentBranch, types.ItemOperationNone, self.c.Tr, time.Now(), self.c.UserConfig)) + upstreamStatus := utils.Decolorise(presentation.BranchStatus(currentBranch, types.ItemOperationNone, self.c.Tr, time.Now(), self.c.UserConfig())) repoName := self.c.Git().RepoPaths.RepoName() workingTreeState := self.c.Git().Status.WorkingTreeState() switch workingTreeState { diff --git a/pkg/gui/controllers/sync_controller.go b/pkg/gui/controllers/sync_controller.go index 8c7334031..b97289438 100644 --- a/pkg/gui/controllers/sync_controller.go +++ b/pkg/gui/controllers/sync_controller.go @@ -210,7 +210,7 @@ func (self *SyncController) pushAux(currentBranch *models.Branch, opts pushOpts) return errors.New(self.c.Tr.UpdatesRejected) } - forcePushDisabled := self.c.UserConfig.Git.DisableForcePushing + forcePushDisabled := self.c.UserConfig().Git.DisableForcePushing if forcePushDisabled { return errors.New(self.c.Tr.UpdatesRejectedAndForcePushDisabled) } @@ -233,7 +233,7 @@ func (self *SyncController) pushAux(currentBranch *models.Branch, opts pushOpts) } func (self *SyncController) requestToForcePush(currentBranch *models.Branch, opts pushOpts) error { - forcePushDisabled := self.c.UserConfig.Git.DisableForcePushing + forcePushDisabled := self.c.UserConfig().Git.DisableForcePushing if forcePushDisabled { return errors.New(self.c.Tr.ForcePushDisabled) } @@ -252,8 +252,8 @@ func (self *SyncController) forcePushPrompt() string { return utils.ResolvePlaceholderString( self.c.Tr.ForcePushPrompt, map[string]string{ - "cancelKey": self.c.UserConfig.Keybinding.Universal.Return, - "confirmKey": self.c.UserConfig.Keybinding.Universal.Confirm, + "cancelKey": self.c.UserConfig().Keybinding.Universal.Return, + "confirmKey": self.c.UserConfig().Keybinding.Universal.Confirm, }, ) } diff --git a/pkg/gui/controllers/vertical_scroll_controller.go b/pkg/gui/controllers/vertical_scroll_controller.go index 90958fadd..b168e86a8 100644 --- a/pkg/gui/controllers/vertical_scroll_controller.go +++ b/pkg/gui/controllers/vertical_scroll_controller.go @@ -65,13 +65,13 @@ func (self *VerticalScrollController) GetMouseKeybindings(opts types.Keybindings } func (self *VerticalScrollController) HandleScrollUp() error { - self.context.GetViewTrait().ScrollUp(self.c.UserConfig.Gui.ScrollHeight) + self.context.GetViewTrait().ScrollUp(self.c.UserConfig().Gui.ScrollHeight) return nil } func (self *VerticalScrollController) HandleScrollDown() error { - scrollHeight := self.c.UserConfig.Gui.ScrollHeight + scrollHeight := self.c.UserConfig().Gui.ScrollHeight self.context.GetViewTrait().ScrollDown(scrollHeight) if manager, ok := (*self.viewBufferManagerMap)[self.context.GetViewName()]; ok { diff --git a/pkg/gui/controllers/workspace_reset_controller.go b/pkg/gui/controllers/workspace_reset_controller.go index 3115d6f68..48ae6de36 100644 --- a/pkg/gui/controllers/workspace_reset_controller.go +++ b/pkg/gui/controllers/workspace_reset_controller.go @@ -35,7 +35,7 @@ func (self *FilesController) createResetMenu() error { return err } - if self.c.UserConfig.Gui.AnimateExplosion { + if self.c.UserConfig().Gui.AnimateExplosion { self.animateExplosion() } diff --git a/pkg/gui/global_handlers.go b/pkg/gui/global_handlers.go index 98089321e..e75dfb8f5 100644 --- a/pkg/gui/global_handlers.go +++ b/pkg/gui/global_handlers.go @@ -13,11 +13,11 @@ import ( const HORIZONTAL_SCROLL_FACTOR = 3 func (gui *Gui) scrollUpView(view *gocui.View) { - view.ScrollUp(gui.c.UserConfig.Gui.ScrollHeight) + view.ScrollUp(gui.c.UserConfig().Gui.ScrollHeight) } func (gui *Gui) scrollDownView(view *gocui.View) { - scrollHeight := gui.c.UserConfig.Gui.ScrollHeight + scrollHeight := gui.c.UserConfig().Gui.ScrollHeight view.ScrollDown(scrollHeight) if manager, ok := gui.viewBufferManagerMap[view.Name()]; ok { @@ -123,7 +123,7 @@ func (gui *Gui) handleCopySelectedSideContextItemToClipboard() error { func (gui *Gui) handleCopySelectedSideContextItemCommitHashToClipboard() error { return gui.handleCopySelectedSideContextItemToClipboardWithTruncation( - gui.UserConfig.Git.TruncateCopiedCommitHashesTo) + gui.UserConfig().Git.TruncateCopiedCommitHashesTo) } func (gui *Gui) handleCopySelectedSideContextItemToClipboardWithTruncation(maxWidth int) error { diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index b65dd80e0..c26774fd0 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -5,6 +5,8 @@ import ( "fmt" "io" "os" + "path/filepath" + "reflect" "sort" "strings" "sync" @@ -35,6 +37,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/status" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/jesseduffield/lazygit/pkg/i18n" "github.com/jesseduffield/lazygit/pkg/integration/components" integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types" "github.com/jesseduffield/lazygit/pkg/tasks" @@ -137,6 +140,8 @@ type Gui struct { c *helpers.HelperCommon helpers *helpers.Helpers + previousLanguageConfig string + integrationTest integrationTypes.IntegrationTest afterLayoutFuncs chan func() error @@ -307,6 +312,16 @@ func (gui *Gui) onNewRepo(startArgs appTypes.StartArgs, contextKey types.Context return err } + err = gui.Config.ReloadUserConfigForRepo(gui.getPerRepoConfigFiles()) + if err != nil { + return err + } + + err = gui.onUserConfigLoaded() + if err != nil { + return err + } + contextToPush := gui.resetState(startArgs) gui.resetHelpersAndControllers() @@ -317,8 +332,28 @@ func (gui *Gui) onNewRepo(startArgs appTypes.StartArgs, contextKey types.Context gui.g.SetFocusHandler(func(Focused bool) error { if Focused { + oldConfig := gui.Config.GetUserConfig() + reloadErr, didChange := gui.Config.ReloadChangedUserConfigFiles() + if didChange && reloadErr == nil { + gui.c.Log.Info("User config changed - reloading") + reloadErr = gui.onUserConfigLoaded() + if err := gui.resetKeybindings(); err != nil { + return err + } + + if err := gui.checkForChangedConfigsThatDontAutoReload(oldConfig, gui.Config.GetUserConfig()); err != nil { + return err + } + } + gui.c.Log.Info("Receiving focus - refreshing") - return gui.helpers.Refresh.Refresh(types.RefreshOptions{Mode: types.ASYNC}) + refreshErr := gui.helpers.Refresh.Refresh(types.RefreshOptions{Mode: types.ASYNC}) + if reloadErr != nil { + // An error from reloading the config is the more important one + // to report to the user + return reloadErr + } + return refreshErr } return nil @@ -342,6 +377,119 @@ func (gui *Gui) onNewRepo(startArgs appTypes.StartArgs, contextKey types.Context return nil } +func (gui *Gui) getPerRepoConfigFiles() []*config.ConfigFile { + repoConfigFiles := []*config.ConfigFile{ + // TODO: add filepath.Join(gui.git.RepoPaths.RepoPath(), ".lazygit.yml"), + // with trust prompt + { + Path: filepath.Join(gui.git.RepoPaths.RepoGitDirPath(), "lazygit.yml"), + Policy: config.ConfigFilePolicySkipIfMissing, + }, + } + + prevDir := gui.c.Git().RepoPaths.RepoPath() + dir := filepath.Dir(prevDir) + for dir != prevDir { + repoConfigFiles = utils.Prepend(repoConfigFiles, &config.ConfigFile{ + Path: filepath.Join(dir, ".lazygit.yml"), + Policy: config.ConfigFilePolicySkipIfMissing, + }) + prevDir = dir + dir = filepath.Dir(dir) + } + return repoConfigFiles +} + +func (gui *Gui) onUserConfigLoaded() error { + userConfig := gui.Config.GetUserConfig() + gui.Common.SetUserConfig(userConfig) + + gui.setColorScheme() + gui.configureViewProperties() + + gui.g.SearchEscapeKey = keybindings.GetKey(userConfig.Keybinding.Universal.Return) + gui.g.NextSearchMatchKey = keybindings.GetKey(userConfig.Keybinding.Universal.NextMatch) + gui.g.PrevSearchMatchKey = keybindings.GetKey(userConfig.Keybinding.Universal.PrevMatch) + + gui.g.ShowListFooter = userConfig.Gui.ShowListFooter + + gui.g.Mouse = userConfig.Gui.MouseEvents + + if gui.previousLanguageConfig != userConfig.Gui.Language { + tr, err := i18n.NewTranslationSetFromConfig(gui.Log, userConfig.Gui.Language) + if err != nil { + return err + } + gui.c.Tr = tr + gui.previousLanguageConfig = userConfig.Gui.Language + } + + // originally we could only hide the command log permanently via the config + // but now we do it via state. So we need to still support the config for the + // sake of backwards compatibility. We're making use of short circuiting here + gui.ShowExtrasWindow = userConfig.Gui.ShowCommandLog && !gui.c.GetAppState().HideCommandLog + + authors.SetCustomAuthors(userConfig.Gui.AuthorColors) + if userConfig.Gui.NerdFontsVersion != "" { + icons.SetNerdFontsVersion(userConfig.Gui.NerdFontsVersion) + } else if userConfig.Gui.ShowIcons { + icons.SetNerdFontsVersion("2") + } + presentation.SetCustomBranches(userConfig.Gui.BranchColors) + + return nil +} + +func (gui *Gui) checkForChangedConfigsThatDontAutoReload(oldConfig *config.UserConfig, newConfig *config.UserConfig) error { + configsThatDontAutoReload := []string{ + "Git.AutoFetch", + "Git.AutoRefresh", + "Refresher.RefreshInterval", + "Refresher.FetchInterval", + "Update.Method", + "Update.Days", + } + + changedConfigs := []string{} + for _, config := range configsThatDontAutoReload { + old := reflect.ValueOf(oldConfig).Elem() + new := reflect.ValueOf(newConfig).Elem() + fieldNames := strings.Split(config, ".") + userFacingPath := make([]string, 0, len(fieldNames)) + // navigate to the leaves in old and new config + for _, fieldName := range fieldNames { + f, _ := old.Type().FieldByName(fieldName) + userFacingName := f.Tag.Get("yaml") + if userFacingName == "" { + userFacingName = fieldName + } + userFacingPath = append(userFacingPath, userFacingName) + old = old.FieldByName(fieldName) + new = new.FieldByName(fieldName) + } + // if the value has changed, ... + if !old.Equal(new) { + // ... append it to the list of changed configs + changedConfigs = append(changedConfigs, strings.Join(userFacingPath, ".")) + } + } + + if len(changedConfigs) == 0 { + return nil + } + + message := utils.ResolvePlaceholderString( + gui.c.Tr.NonReloadableConfigWarning, + map[string]string{ + "configs": strings.Join(changedConfigs, "\n"), + }, + ) + return gui.c.Confirm(types.ConfirmOpts{ + Title: gui.c.Tr.NonReloadableConfigWarningTitle, + Prompt: message, + }) +} + // resetState reuses the repo state from our repo state map, if the repo was // open before; otherwise it creates a new one. func (gui *Gui) resetState(startArgs appTypes.StartArgs) types.Context { @@ -379,7 +527,7 @@ func (gui *Gui) resetState(startArgs appTypes.StartArgs) types.Context { BisectInfo: git_commands.NewNullBisectInfo(), FilesTrie: patricia.NewTrie(), Authors: map[string]*models.Author{}, - MainBranches: git_commands.NewMainBranches(gui.UserConfig.Git.MainBranches, gui.os.Cmd), + MainBranches: git_commands.NewMainBranches(gui.c.Common, gui.os.Cmd), }, Modes: &types.Modes{ Filtering: filtering.New(startArgs.FilterPath, ""), @@ -478,10 +626,10 @@ func NewGui( RepoStateMap: map[Repo]*GuiRepoState{}, GuiLog: []string{}, - // originally we could only hide the command log permanently via the config - // but now we do it via state. So we need to still support the config for the - // sake of backwards compatibility. We're making use of short circuiting here - ShowExtrasWindow: cmn.UserConfig.Gui.ShowCommandLog && !config.GetAppState().HideCommandLog, + // initializing this to true for the time being; it will be reset to the + // real value after loading the user config: + ShowExtrasWindow: true, + Mutexes: types.Mutexes{ RefreshingFilesMutex: &deadlock.Mutex{}, RefreshingBranchesMutex: &deadlock.Mutex{}, @@ -538,14 +686,6 @@ func NewGui( // TODO: reset these controllers upon changing repos due to state changing gui.c = helperCommon - authors.SetCustomAuthors(gui.UserConfig.Gui.AuthorColors) - if gui.UserConfig.Gui.NerdFontsVersion != "" { - icons.SetNerdFontsVersion(gui.UserConfig.Gui.NerdFontsVersion) - } else if gui.UserConfig.Gui.ShowIcons { - icons.SetNerdFontsVersion("2") - } - presentation.SetCustomBranches(gui.UserConfig.Gui.BranchColors) - gui.BackgroundRoutineMgr = &BackgroundRoutineMgr{gui: gui} gui.stateAccessor = &StateAccessor{gui: gui} @@ -658,25 +798,7 @@ func (gui *Gui) Run(startArgs appTypes.StartArgs) error { // breakpoints and stepping through code can easily take more than 30s. deadlock.Opts.Disable = !gui.Debug || os.Getenv(components.WAIT_FOR_DEBUGGER_ENV_VAR) != "" - if err := gui.Config.ReloadUserConfig(); err != nil { - return nil - } - userConfig := gui.UserConfig - gui.g.OnSearchEscape = func() error { gui.helpers.Search.Cancel(); return nil } - gui.g.SearchEscapeKey = keybindings.GetKey(userConfig.Keybinding.Universal.Return) - gui.g.NextSearchMatchKey = keybindings.GetKey(userConfig.Keybinding.Universal.NextMatch) - gui.g.PrevSearchMatchKey = keybindings.GetKey(userConfig.Keybinding.Universal.PrevMatch) - - gui.g.ShowListFooter = userConfig.Gui.ShowListFooter - - if userConfig.Gui.MouseEvents { - gui.g.Mouse = true - } - - if err := gui.setColorScheme(); err != nil { - return err - } gui.g.SetManager(gocui.ManagerFunc(gui.layout)) @@ -735,7 +857,7 @@ func (gui *Gui) RunAndHandleError(startArgs appTypes.StartArgs) error { } func (gui *Gui) checkForDeprecatedEditConfigs() { - osConfig := &gui.UserConfig.OS + osConfig := &gui.UserConfig().OS deprecatedConfigs := []struct { config string oldName string @@ -934,16 +1056,14 @@ func (gui *Gui) showBreakingChangesMessage() { } // setColorScheme sets the color scheme for the app based on the user config -func (gui *Gui) setColorScheme() error { - userConfig := gui.UserConfig +func (gui *Gui) setColorScheme() { + userConfig := gui.UserConfig() theme.UpdateTheme(userConfig.Gui.Theme) gui.g.FgColor = theme.InactiveBorderColor gui.g.SelFgColor = theme.ActiveBorderColor gui.g.FrameColor = theme.InactiveBorderColor gui.g.SelFrameColor = theme.ActiveBorderColor - - return nil } func (gui *Gui) onUIThread(f func() error) { diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 83f72c074..c12d2777e 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -60,7 +60,7 @@ func (self *Gui) GetCheatsheetKeybindings() []*types.Binding { } func (self *Gui) keybindingOpts() types.KeybindingsOpts { - config := self.c.UserConfig.Keybinding + config := self.c.UserConfig().Keybinding guards := types.KeybindingGuards{ OutsideFilterMode: self.outsideFilterMode, diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go index ff7923117..62c2233dd 100644 --- a/pkg/gui/layout.go +++ b/pkg/gui/layout.go @@ -260,7 +260,7 @@ func (gui *Gui) onRepoViewReset() error { } func (gui *Gui) onInitialViewsCreation() error { - if !gui.c.UserConfig.DisableStartupPopups { + if !gui.c.UserConfig().DisableStartupPopups { storedPopupVersion := gui.c.GetAppState().StartupPopupVersion if storedPopupVersion < StartupPopupVersion { gui.showIntroPopupMessage() diff --git a/pkg/gui/presentation/branches_test.go b/pkg/gui/presentation/branches_test.go index 71dc89c8a..d91784674 100644 --- a/pkg/gui/presentation/branches_test.go +++ b/pkg/gui/presentation/branches_test.go @@ -324,7 +324,7 @@ func Test_getBranchDisplayStrings(t *testing.T) { for i, s := range scenarios { icons.SetNerdFontsVersion(lo.Ternary(s.useIcons, "3", "")) - c.UserConfig.Gui.ShowDivergenceFromBaseBranch = s.showDivergenceCfg + c.UserConfig().Gui.ShowDivergenceFromBaseBranch = s.showDivergenceCfg worktrees := []*models.Worktree{} if s.checkedOutByWorktree { @@ -332,7 +332,7 @@ func Test_getBranchDisplayStrings(t *testing.T) { } t.Run(fmt.Sprintf("getBranchDisplayStrings_%d", i), func(t *testing.T) { - strings := getBranchDisplayStrings(s.branch, s.itemOperation, s.fullDescription, false, s.viewWidth, c.Tr, c.UserConfig, worktrees, time.Time{}) + strings := getBranchDisplayStrings(s.branch, s.itemOperation, s.fullDescription, false, s.viewWidth, c.Tr, c.UserConfig(), worktrees, time.Time{}) assert.Equal(t, s.expected, strings) }) } diff --git a/pkg/gui/presentation/commits.go b/pkg/gui/presentation/commits.go index 92327462f..f9bdb4eb7 100644 --- a/pkg/gui/presentation/commits.go +++ b/pkg/gui/presentation/commits.go @@ -173,7 +173,7 @@ func GetCommitListDisplayStrings( // Don't show a marker for the current branch b.Name != currentBranchName && // Don't show a marker for main branches - !lo.Contains(common.UserConfig.Git.MainBranches, b.Name) && + !lo.Contains(common.UserConfig().Git.MainBranches, b.Name) && // Don't show a marker for the head commit unless the // rebase.updateRefs config is on (hasRebaseUpdateRefsConfig || b.CommitHash != commits[0].Hash) @@ -370,7 +370,7 @@ func displayCommit( hashString := "" hashColor := getHashColor(commit, diffName, cherryPickedCommitHashSet, bisectStatus, bisectInfo) - hashLength := common.UserConfig.Gui.CommitHashLength + hashLength := common.UserConfig().Gui.CommitHashLength if hashLength >= len(commit.Hash) { hashString = hashColor.Sprint(commit.Hash) } else if hashLength > 0 { @@ -440,9 +440,9 @@ func displayCommit( mark = fmt.Sprintf("%s ", willBeRebased) } - authorLength := common.UserConfig.Gui.CommitAuthorShortLength + authorLength := common.UserConfig().Gui.CommitAuthorShortLength if fullDescription { - authorLength = common.UserConfig.Gui.CommitAuthorLongLength + authorLength = common.UserConfig().Gui.CommitAuthorLongLength } author := authors.AuthorWithLength(commit.AuthorName, authorLength) diff --git a/pkg/gui/services/custom_commands/client.go b/pkg/gui/services/custom_commands/client.go index 571445424..6cb1bf19c 100644 --- a/pkg/gui/services/custom_commands/client.go +++ b/pkg/gui/services/custom_commands/client.go @@ -1,7 +1,7 @@ package custom_commands import ( - "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/common" "github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -9,7 +9,7 @@ import ( // Client is the entry point to this package. It returns a list of keybindings based on the config's user-defined custom commands. // See https://github.com/jesseduffield/lazygit/blob/master/docs/Custom_Command_Keybindings.md for more info. type Client struct { - customCommands []config.CustomCommand + c *common.Common handlerCreator *HandlerCreator keybindingCreator *KeybindingCreator } @@ -26,10 +26,9 @@ func NewClient( helpers.MergeAndRebase, ) keybindingCreator := NewKeybindingCreator(c) - customCommands := c.UserConfig.CustomCommands return &Client{ - customCommands: customCommands, + c: c.Common, keybindingCreator: keybindingCreator, handlerCreator: handlerCreator, } @@ -37,7 +36,7 @@ func NewClient( func (self *Client) GetCustomCommandKeybindings() ([]*types.Binding, error) { bindings := []*types.Binding{} - for _, customCommand := range self.customCommands { + for _, customCommand := range self.c.UserConfig().CustomCommands { handler := self.handlerCreator.call(customCommand) compoundBindings, err := self.keybindingCreator.call(customCommand, handler) if err != nil { diff --git a/pkg/gui/views.go b/pkg/gui/views.go index 9a4fa0a47..e76ed24d3 100644 --- a/pkg/gui/views.go +++ b/pkg/gui/views.go @@ -73,26 +73,12 @@ func (gui *Gui) orderedViewNameMappings() []viewNameMapping { } func (gui *Gui) createAllViews() error { - frameRunes := []rune{'─', '│', '┌', '┐', '└', '┘'} - switch gui.c.UserConfig.Gui.Border { - case "double": - frameRunes = []rune{'═', '║', '╔', '╗', '╚', '╝'} - case "rounded": - frameRunes = []rune{'─', '│', '╭', '╮', '╰', '╯'} - case "hidden": - frameRunes = []rune{' ', ' ', ' ', ' ', ' ', ' '} - } - var err error for _, mapping := range gui.orderedViewNameMappings() { *mapping.viewPtr, err = gui.prepareView(mapping.name) if err != nil && !gocui.IsUnknownView(err) { return err } - (*mapping.viewPtr).FrameRunes = frameRunes - (*mapping.viewPtr).FgColor = theme.GocuiDefaultTextColor - (*mapping.viewPtr).SelBgColor = theme.GocuiSelectedLineBgColor - (*mapping.viewPtr).InactiveViewSelBgColor = theme.GocuiInactiveViewSelectedLineBgColor } gui.Views.Options.Frame = false @@ -131,7 +117,6 @@ func (gui *Gui) createAllViews() error { view.Title = gui.c.Tr.DiffTitle view.Wrap = true view.IgnoreCarriageReturns = true - view.CanScrollPastBottom = gui.c.UserConfig.Gui.ScrollPastBottom } gui.Views.Staging.Title = gui.c.Tr.UnstagedChanges @@ -166,11 +151,8 @@ func (gui *Gui) createAllViews() error { gui.Views.CommitDescription.Visible = false gui.Views.CommitDescription.Title = gui.c.Tr.CommitDescriptionTitle - gui.Views.CommitDescription.FgColor = theme.GocuiDefaultTextColor gui.Views.CommitDescription.Editable = true gui.Views.CommitDescription.Editor = gocui.EditorFunc(gui.commitDescriptionEditor) - gui.Views.CommitDescription.TextArea.AutoWrap = gui.c.UserConfig.Git.Commit.AutoWrapCommitMessage - gui.Views.CommitDescription.TextArea.AutoWrapWidth = gui.c.UserConfig.Git.Commit.AutoWrapWidth gui.Views.Confirmation.Visible = false gui.Views.Confirmation.Editor = gocui.EditorFunc(gui.promptEditor) @@ -192,8 +174,39 @@ func (gui *Gui) createAllViews() error { gui.Views.Snake.Title = gui.c.Tr.SnakeTitle gui.Views.Snake.FgColor = gocui.ColorGreen - if gui.c.UserConfig.Gui.ShowPanelJumps { - jumpBindings := gui.c.UserConfig.Keybinding.Universal.JumpToBlock + return nil +} + +func (gui *Gui) configureViewProperties() { + frameRunes := []rune{'─', '│', '┌', '┐', '└', '┘'} + switch gui.c.UserConfig().Gui.Border { + case "double": + frameRunes = []rune{'═', '║', '╔', '╗', '╚', '╝'} + case "rounded": + frameRunes = []rune{'─', '│', '╭', '╮', '╰', '╯'} + case "hidden": + frameRunes = []rune{' ', ' ', ' ', ' ', ' ', ' '} + } + + for _, mapping := range gui.orderedViewNameMappings() { + (*mapping.viewPtr).FrameRunes = frameRunes + (*mapping.viewPtr).BgColor = gui.g.BgColor + (*mapping.viewPtr).FgColor = theme.GocuiDefaultTextColor + (*mapping.viewPtr).SelBgColor = theme.GocuiSelectedLineBgColor + (*mapping.viewPtr).SelFgColor = gui.g.SelFgColor + (*mapping.viewPtr).InactiveViewSelBgColor = theme.GocuiInactiveViewSelectedLineBgColor + } + + for _, view := range []*gocui.View{gui.Views.Main, gui.Views.Secondary, gui.Views.Staging, gui.Views.StagingSecondary, gui.Views.PatchBuilding, gui.Views.PatchBuildingSecondary, gui.Views.MergeConflicts} { + view.CanScrollPastBottom = gui.c.UserConfig().Gui.ScrollPastBottom + } + + gui.Views.CommitDescription.FgColor = theme.GocuiDefaultTextColor + gui.Views.CommitDescription.TextArea.AutoWrap = gui.c.UserConfig().Git.Commit.AutoWrapCommitMessage + gui.Views.CommitDescription.TextArea.AutoWrapWidth = gui.c.UserConfig().Git.Commit.AutoWrapWidth + + if gui.c.UserConfig().Gui.ShowPanelJumps { + jumpBindings := gui.c.UserConfig().Keybinding.Universal.JumpToBlock jumpLabels := lo.Map(jumpBindings, func(binding string, _ int) string { return fmt.Sprintf("[%s]", binding) }) @@ -212,7 +225,20 @@ func (gui *Gui) createAllViews() error { gui.Views.ReflogCommits.TitlePrefix = jumpLabels[3] gui.Views.Stash.TitlePrefix = jumpLabels[4] - } + } else { + gui.Views.Status.TitlePrefix = "" - return nil + gui.Views.Files.TitlePrefix = "" + gui.Views.Worktrees.TitlePrefix = "" + gui.Views.Submodules.TitlePrefix = "" + + gui.Views.Branches.TitlePrefix = "" + gui.Views.Remotes.TitlePrefix = "" + gui.Views.Tags.TitlePrefix = "" + + gui.Views.Commits.TitlePrefix = "" + gui.Views.ReflogCommits.TitlePrefix = "" + + gui.Views.Stash.TitlePrefix = "" + } } diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index f2503e2e6..f4520a3ee 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -225,6 +225,8 @@ type TranslationSet struct { MergeToolPrompt string IntroPopupMessage string DeprecatedEditConfigWarning string + NonReloadableConfigWarningTitle string + NonReloadableConfigWarning string GitconfigParseErr string EditFile string EditFileTooltip string @@ -985,6 +987,10 @@ for up-to-date information how to configure your editor. ` +const englishNonReloadableConfigWarning = `The following config settings were changed, but the change doesn't take effect immediately. Please quit and restart lazygit for changes to take effect: + +{{configs}}` + // exporting this so we can use it in tests func EnglishTranslationSet() *TranslationSet { return &TranslationSet{ @@ -1199,6 +1205,8 @@ func EnglishTranslationSet() *TranslationSet { MergeToolPrompt: "Are you sure you want to open `git mergetool`?", IntroPopupMessage: englishIntroPopupMessage, DeprecatedEditConfigWarning: englishDeprecatedEditConfigWarning, + NonReloadableConfigWarningTitle: "Config changed", + NonReloadableConfigWarning: englishNonReloadableConfigWarning, GitconfigParseErr: `Gogit failed to parse your gitconfig file due to the presence of unquoted '\' characters. Removing these should fix the issue.`, EditFile: `Edit file`, EditFileTooltip: "Open file in external editor.", diff --git a/pkg/integration/tests/bisect/basic.go b/pkg/integration/tests/bisect/basic.go index 43eeefb88..c0188a7dc 100644 --- a/pkg/integration/tests/bisect/basic.go +++ b/pkg/integration/tests/bisect/basic.go @@ -15,7 +15,7 @@ var Basic = NewIntegrationTest(NewIntegrationTestArgs{ CreateNCommits(10) }, SetupConfig: func(cfg *config.AppConfig) { - cfg.AppState.GitLogShowGraph = "never" + cfg.GetAppState().GitLogShowGraph = "never" }, Run: func(t *TestDriver, keys config.KeybindingConfig) { markCommitAsBad := func() { diff --git a/pkg/integration/tests/bisect/choose_terms.go b/pkg/integration/tests/bisect/choose_terms.go index dc57bdab8..7b9c4740e 100644 --- a/pkg/integration/tests/bisect/choose_terms.go +++ b/pkg/integration/tests/bisect/choose_terms.go @@ -15,7 +15,7 @@ var ChooseTerms = NewIntegrationTest(NewIntegrationTestArgs{ CreateNCommits(10) }, SetupConfig: func(cfg *config.AppConfig) { - cfg.AppState.GitLogShowGraph = "never" + cfg.GetAppState().GitLogShowGraph = "never" }, Run: func(t *TestDriver, keys config.KeybindingConfig) { markCommitAsFixed := func() { diff --git a/pkg/integration/tests/bisect/skip.go b/pkg/integration/tests/bisect/skip.go index 15d53c70d..a8a9616d5 100644 --- a/pkg/integration/tests/bisect/skip.go +++ b/pkg/integration/tests/bisect/skip.go @@ -14,7 +14,7 @@ var Skip = NewIntegrationTest(NewIntegrationTestArgs{ CreateNCommits(10) }, SetupConfig: func(cfg *config.AppConfig) { - cfg.AppState.GitLogShowGraph = "never" + cfg.GetAppState().GitLogShowGraph = "never" }, Run: func(t *TestDriver, keys config.KeybindingConfig) { t.Views().Commits(). diff --git a/pkg/integration/tests/branch/rebase_copied_branch.go b/pkg/integration/tests/branch/rebase_copied_branch.go index bc9fcb4a6..330feb6c4 100644 --- a/pkg/integration/tests/branch/rebase_copied_branch.go +++ b/pkg/integration/tests/branch/rebase_copied_branch.go @@ -11,7 +11,7 @@ var RebaseCopiedBranch = NewIntegrationTest(NewIntegrationTestArgs{ Skip: false, GitVersion: AtLeast("2.38.0"), SetupConfig: func(config *config.AppConfig) { - config.AppState.GitLogShowGraph = "never" + config.GetAppState().GitLogShowGraph = "never" }, SetupRepo: func(shell *Shell) { shell. diff --git a/pkg/integration/tests/branch/rebase_onto_base_branch.go b/pkg/integration/tests/branch/rebase_onto_base_branch.go index 3944f4fe6..0617c936b 100644 --- a/pkg/integration/tests/branch/rebase_onto_base_branch.go +++ b/pkg/integration/tests/branch/rebase_onto_base_branch.go @@ -10,7 +10,7 @@ var RebaseOntoBaseBranch = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.UserConfig.Gui.ShowDivergenceFromBaseBranch = "arrowAndNumber" + config.GetUserConfig().Gui.ShowDivergenceFromBaseBranch = "arrowAndNumber" }, SetupRepo: func(shell *Shell) { shell. diff --git a/pkg/integration/tests/branch/show_divergence_from_base_branch.go b/pkg/integration/tests/branch/show_divergence_from_base_branch.go index 3efc0d76c..95e51370e 100644 --- a/pkg/integration/tests/branch/show_divergence_from_base_branch.go +++ b/pkg/integration/tests/branch/show_divergence_from_base_branch.go @@ -10,7 +10,7 @@ var ShowDivergenceFromBaseBranch = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.UserConfig.Gui.ShowDivergenceFromBaseBranch = "arrowAndNumber" + config.GetUserConfig().Gui.ShowDivergenceFromBaseBranch = "arrowAndNumber" }, SetupRepo: func(shell *Shell) { shell. diff --git a/pkg/integration/tests/cherry_pick/cherry_pick_during_rebase.go b/pkg/integration/tests/cherry_pick/cherry_pick_during_rebase.go index 93f940fd8..6e2e2e6e4 100644 --- a/pkg/integration/tests/cherry_pick/cherry_pick_during_rebase.go +++ b/pkg/integration/tests/cherry_pick/cherry_pick_during_rebase.go @@ -10,7 +10,7 @@ var CherryPickDuringRebase = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.AppState.GitLogShowGraph = "never" + config.GetAppState().GitLogShowGraph = "never" }, SetupRepo: func(shell *Shell) { shell. diff --git a/pkg/integration/tests/commit/auto_wrap_message.go b/pkg/integration/tests/commit/auto_wrap_message.go index 477bfae62..f65c18226 100644 --- a/pkg/integration/tests/commit/auto_wrap_message.go +++ b/pkg/integration/tests/commit/auto_wrap_message.go @@ -11,7 +11,7 @@ var AutoWrapMessage = NewIntegrationTest(NewIntegrationTestArgs{ Skip: false, SetupConfig: func(config *config.AppConfig) { // Use a ridiculously small width so that we don't have to use so much test data - config.UserConfig.Git.Commit.AutoWrapWidth = 20 + config.GetUserConfig().Git.Commit.AutoWrapWidth = 20 }, SetupRepo: func(shell *Shell) { shell.CreateFile("file", "file content") diff --git a/pkg/integration/tests/commit/commit_wip_with_prefix.go b/pkg/integration/tests/commit/commit_wip_with_prefix.go index 42696e190..a39a168fe 100644 --- a/pkg/integration/tests/commit/commit_wip_with_prefix.go +++ b/pkg/integration/tests/commit/commit_wip_with_prefix.go @@ -9,8 +9,8 @@ var CommitWipWithPrefix = NewIntegrationTest(NewIntegrationTestArgs{ Description: "Commit with skip hook and config commitPrefix is defined. Prefix is ignored when creating WIP commits.", ExtraCmdArgs: []string{}, Skip: false, - SetupConfig: func(testConfig *config.AppConfig) { - testConfig.UserConfig.Git.CommitPrefixes = map[string]config.CommitPrefixConfig{"repo": {Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[$1]: "}} + SetupConfig: func(cfg *config.AppConfig) { + cfg.GetUserConfig().Git.CommitPrefixes = map[string]config.CommitPrefixConfig{"repo": {Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[$1]: "}} }, SetupRepo: func(shell *Shell) { shell.NewBranch("feature/TEST-002") diff --git a/pkg/integration/tests/commit/commit_with_global_prefix.go b/pkg/integration/tests/commit/commit_with_global_prefix.go index 80835682e..f5e67fba3 100644 --- a/pkg/integration/tests/commit/commit_with_global_prefix.go +++ b/pkg/integration/tests/commit/commit_with_global_prefix.go @@ -9,8 +9,8 @@ var CommitWithGlobalPrefix = NewIntegrationTest(NewIntegrationTestArgs{ Description: "Commit with defined config commitPrefix", ExtraCmdArgs: []string{}, Skip: false, - SetupConfig: func(testConfig *config.AppConfig) { - testConfig.UserConfig.Git.CommitPrefix = &config.CommitPrefixConfig{Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[$1]: "} + SetupConfig: func(cfg *config.AppConfig) { + cfg.GetUserConfig().Git.CommitPrefix = &config.CommitPrefixConfig{Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[$1]: "} }, SetupRepo: func(shell *Shell) { shell.NewBranch("feature/TEST-001") diff --git a/pkg/integration/tests/commit/commit_with_non_matching_branch_name.go b/pkg/integration/tests/commit/commit_with_non_matching_branch_name.go index 1075c7bb1..98f35d6d2 100644 --- a/pkg/integration/tests/commit/commit_with_non_matching_branch_name.go +++ b/pkg/integration/tests/commit/commit_with_non_matching_branch_name.go @@ -9,8 +9,8 @@ var CommitWithNonMatchingBranchName = NewIntegrationTest(NewIntegrationTestArgs{ Description: "Commit with defined config commitPrefixes", ExtraCmdArgs: []string{}, Skip: false, - SetupConfig: func(testConfig *config.AppConfig) { - testConfig.UserConfig.Git.CommitPrefix = &config.CommitPrefixConfig{ + SetupConfig: func(cfg *config.AppConfig) { + cfg.GetUserConfig().Git.CommitPrefix = &config.CommitPrefixConfig{ Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[$1]: ", } diff --git a/pkg/integration/tests/commit/commit_with_prefix.go b/pkg/integration/tests/commit/commit_with_prefix.go index 53a6904f4..c2675f103 100644 --- a/pkg/integration/tests/commit/commit_with_prefix.go +++ b/pkg/integration/tests/commit/commit_with_prefix.go @@ -9,8 +9,8 @@ var CommitWithPrefix = NewIntegrationTest(NewIntegrationTestArgs{ Description: "Commit with defined config commitPrefixes", ExtraCmdArgs: []string{}, Skip: false, - SetupConfig: func(testConfig *config.AppConfig) { - testConfig.UserConfig.Git.CommitPrefixes = map[string]config.CommitPrefixConfig{"repo": {Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[$1]: "}} + SetupConfig: func(cfg *config.AppConfig) { + cfg.GetUserConfig().Git.CommitPrefixes = map[string]config.CommitPrefixConfig{"repo": {Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[$1]: "}} }, SetupRepo: func(shell *Shell) { shell.NewBranch("feature/TEST-001") diff --git a/pkg/integration/tests/commit/highlight.go b/pkg/integration/tests/commit/highlight.go index c184308e7..077a42b9d 100644 --- a/pkg/integration/tests/commit/highlight.go +++ b/pkg/integration/tests/commit/highlight.go @@ -10,7 +10,7 @@ var Highlight = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.AppState.GitLogShowGraph = "always" + config.GetAppState().GitLogShowGraph = "always" config.GetUserConfig().Gui.AuthorColors = map[string]string{ "CI": "red", } diff --git a/pkg/integration/tests/commit/new_branch_with_prefix.go b/pkg/integration/tests/commit/new_branch_with_prefix.go index 21381630e..2b489648f 100644 --- a/pkg/integration/tests/commit/new_branch_with_prefix.go +++ b/pkg/integration/tests/commit/new_branch_with_prefix.go @@ -10,7 +10,7 @@ var NewBranchWithPrefix = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.Git.BranchPrefix = "myprefix/" + cfg.GetUserConfig().Git.BranchPrefix = "myprefix/" }, SetupRepo: func(shell *Shell) { shell. diff --git a/pkg/integration/tests/commit/paste_commit_message.go b/pkg/integration/tests/commit/paste_commit_message.go index 130d1885f..2e38ae41c 100644 --- a/pkg/integration/tests/commit/paste_commit_message.go +++ b/pkg/integration/tests/commit/paste_commit_message.go @@ -10,8 +10,8 @@ var PasteCommitMessage = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.UserConfig.OS.CopyToClipboardCmd = "echo {{text}} > ../clipboard" - config.UserConfig.OS.ReadFromClipboardCmd = "cat ../clipboard" + config.GetUserConfig().OS.CopyToClipboardCmd = "echo {{text}} > ../clipboard" + config.GetUserConfig().OS.ReadFromClipboardCmd = "cat ../clipboard" }, SetupRepo: func(shell *Shell) { shell.EmptyCommit("subject\n\nbody 1st line\nbody 2nd line") diff --git a/pkg/integration/tests/commit/paste_commit_message_over_existing.go b/pkg/integration/tests/commit/paste_commit_message_over_existing.go index 52f6d44f5..bb55e5998 100644 --- a/pkg/integration/tests/commit/paste_commit_message_over_existing.go +++ b/pkg/integration/tests/commit/paste_commit_message_over_existing.go @@ -10,8 +10,8 @@ var PasteCommitMessageOverExisting = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.UserConfig.OS.CopyToClipboardCmd = "echo {{text}} > ../clipboard" - config.UserConfig.OS.ReadFromClipboardCmd = "cat ../clipboard" + config.GetUserConfig().OS.CopyToClipboardCmd = "echo {{text}} > ../clipboard" + config.GetUserConfig().OS.ReadFromClipboardCmd = "cat ../clipboard" }, SetupRepo: func(shell *Shell) { shell.EmptyCommit("subject\n\nbody 1st line\nbody 2nd line") diff --git a/pkg/integration/tests/custom_commands/access_commit_properties.go b/pkg/integration/tests/custom_commands/access_commit_properties.go index 6ac77faf8..22d1d0631 100644 --- a/pkg/integration/tests/custom_commands/access_commit_properties.go +++ b/pkg/integration/tests/custom_commands/access_commit_properties.go @@ -15,7 +15,7 @@ var AccessCommitProperties = NewIntegrationTest(NewIntegrationTestArgs{ shell.EmptyCommit("my change") }, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "X", Context: "commits", diff --git a/pkg/integration/tests/custom_commands/basic_command.go b/pkg/integration/tests/custom_commands/basic_command.go index 219974596..10a9058b7 100644 --- a/pkg/integration/tests/custom_commands/basic_command.go +++ b/pkg/integration/tests/custom_commands/basic_command.go @@ -13,7 +13,7 @@ var BasicCommand = NewIntegrationTest(NewIntegrationTestArgs{ shell.EmptyCommit("blah") }, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "a", Context: "files", diff --git a/pkg/integration/tests/custom_commands/check_for_conflicts.go b/pkg/integration/tests/custom_commands/check_for_conflicts.go index cb8ac7c77..024f32733 100644 --- a/pkg/integration/tests/custom_commands/check_for_conflicts.go +++ b/pkg/integration/tests/custom_commands/check_for_conflicts.go @@ -14,7 +14,7 @@ var CheckForConflicts = NewIntegrationTest(NewIntegrationTestArgs{ shared.MergeConflictsSetup(shell) }, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "m", Context: "localBranches", diff --git a/pkg/integration/tests/custom_commands/form_prompts.go b/pkg/integration/tests/custom_commands/form_prompts.go index a64c1aa4c..ccb2339de 100644 --- a/pkg/integration/tests/custom_commands/form_prompts.go +++ b/pkg/integration/tests/custom_commands/form_prompts.go @@ -13,7 +13,7 @@ var FormPrompts = NewIntegrationTest(NewIntegrationTestArgs{ shell.EmptyCommit("blah") }, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "a", Context: "files", diff --git a/pkg/integration/tests/custom_commands/global_context.go b/pkg/integration/tests/custom_commands/global_context.go index 8f8518559..9f975d04c 100644 --- a/pkg/integration/tests/custom_commands/global_context.go +++ b/pkg/integration/tests/custom_commands/global_context.go @@ -13,7 +13,7 @@ var GlobalContext = NewIntegrationTest(NewIntegrationTestArgs{ shell.EmptyCommit("my change") }, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "X", Context: "global", diff --git a/pkg/integration/tests/custom_commands/menu_from_command.go b/pkg/integration/tests/custom_commands/menu_from_command.go index 9e5f39615..10b8192ba 100644 --- a/pkg/integration/tests/custom_commands/menu_from_command.go +++ b/pkg/integration/tests/custom_commands/menu_from_command.go @@ -19,7 +19,7 @@ var MenuFromCommand = NewIntegrationTest(NewIntegrationTestArgs{ NewBranch("feature/foo") }, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "a", Context: "localBranches", diff --git a/pkg/integration/tests/custom_commands/menu_from_commands_output.go b/pkg/integration/tests/custom_commands/menu_from_commands_output.go index 7cbd16506..591daa5af 100644 --- a/pkg/integration/tests/custom_commands/menu_from_commands_output.go +++ b/pkg/integration/tests/custom_commands/menu_from_commands_output.go @@ -18,7 +18,7 @@ var MenuFromCommandsOutput = NewIntegrationTest(NewIntegrationTestArgs{ EmptyCommit("baz") }, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "a", Context: "localBranches", diff --git a/pkg/integration/tests/custom_commands/multiple_contexts.go b/pkg/integration/tests/custom_commands/multiple_contexts.go index 3edc6e907..a5c982ee3 100644 --- a/pkg/integration/tests/custom_commands/multiple_contexts.go +++ b/pkg/integration/tests/custom_commands/multiple_contexts.go @@ -13,7 +13,7 @@ var MultipleContexts = NewIntegrationTest(NewIntegrationTestArgs{ shell.EmptyCommit("my change") }, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "X", Context: "commits, reflogCommits", diff --git a/pkg/integration/tests/custom_commands/multiple_prompts.go b/pkg/integration/tests/custom_commands/multiple_prompts.go index d36c40d65..b40aa77f2 100644 --- a/pkg/integration/tests/custom_commands/multiple_prompts.go +++ b/pkg/integration/tests/custom_commands/multiple_prompts.go @@ -13,7 +13,7 @@ var MultiplePrompts = NewIntegrationTest(NewIntegrationTestArgs{ shell.EmptyCommit("blah") }, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "a", Context: "files", diff --git a/pkg/integration/tests/custom_commands/selected_commit.go b/pkg/integration/tests/custom_commands/selected_commit.go index 0dda19546..6288634f1 100644 --- a/pkg/integration/tests/custom_commands/selected_commit.go +++ b/pkg/integration/tests/custom_commands/selected_commit.go @@ -13,7 +13,7 @@ var SelectedCommit = NewIntegrationTest(NewIntegrationTestArgs{ shell.CreateNCommits(3) }, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "X", Context: "global", diff --git a/pkg/integration/tests/custom_commands/selected_path.go b/pkg/integration/tests/custom_commands/selected_path.go index f76fb3fba..9dc63ed43 100644 --- a/pkg/integration/tests/custom_commands/selected_path.go +++ b/pkg/integration/tests/custom_commands/selected_path.go @@ -17,7 +17,7 @@ var SelectedPath = NewIntegrationTest(NewIntegrationTestArgs{ shell.CreateFile("folder2/file2", "") }, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "X", Context: "global", diff --git a/pkg/integration/tests/custom_commands/show_output_in_panel.go b/pkg/integration/tests/custom_commands/show_output_in_panel.go index e98f372e6..171a477d8 100644 --- a/pkg/integration/tests/custom_commands/show_output_in_panel.go +++ b/pkg/integration/tests/custom_commands/show_output_in_panel.go @@ -15,7 +15,7 @@ var ShowOutputInPanel = NewIntegrationTest(NewIntegrationTestArgs{ shell.EmptyCommit("my change") }, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "X", Context: "commits", diff --git a/pkg/integration/tests/custom_commands/suggestions_command.go b/pkg/integration/tests/custom_commands/suggestions_command.go index 592c472cf..4b6aa0f4e 100644 --- a/pkg/integration/tests/custom_commands/suggestions_command.go +++ b/pkg/integration/tests/custom_commands/suggestions_command.go @@ -20,7 +20,7 @@ var SuggestionsCommand = NewIntegrationTest(NewIntegrationTestArgs{ shell.EmptyCommit("blah") }, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "a", Context: "localBranches", diff --git a/pkg/integration/tests/custom_commands/suggestions_preset.go b/pkg/integration/tests/custom_commands/suggestions_preset.go index d4ae422ad..aa599946f 100644 --- a/pkg/integration/tests/custom_commands/suggestions_preset.go +++ b/pkg/integration/tests/custom_commands/suggestions_preset.go @@ -20,7 +20,7 @@ var SuggestionsPreset = NewIntegrationTest(NewIntegrationTestArgs{ shell.EmptyCommit("blah") }, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "a", Context: "localBranches", diff --git a/pkg/integration/tests/demo/amend_old_commit.go b/pkg/integration/tests/demo/amend_old_commit.go index ac91a34e7..de76aee21 100644 --- a/pkg/integration/tests/demo/amend_old_commit.go +++ b/pkg/integration/tests/demo/amend_old_commit.go @@ -12,7 +12,7 @@ var AmendOldCommit = NewIntegrationTest(NewIntegrationTestArgs{ IsDemo: true, SetupConfig: func(config *config.AppConfig) { setDefaultDemoConfig(config) - config.UserConfig.Gui.ShowFileTree = false + config.GetUserConfig().Gui.ShowFileTree = false }, SetupRepo: func(shell *Shell) { shell.CreateNCommitsWithRandomMessages(60) diff --git a/pkg/integration/tests/demo/custom_command.go b/pkg/integration/tests/demo/custom_command.go index 147a63ba4..a65c2c073 100644 --- a/pkg/integration/tests/demo/custom_command.go +++ b/pkg/integration/tests/demo/custom_command.go @@ -26,7 +26,7 @@ var CustomCommand = NewIntegrationTest(NewIntegrationTestArgs{ SetupConfig: func(cfg *config.AppConfig) { setDefaultDemoConfig(cfg) - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "a", Context: "localBranches", diff --git a/pkg/integration/tests/demo/diff_commits.go b/pkg/integration/tests/demo/diff_commits.go index da83564a7..ddc7b7ba7 100644 --- a/pkg/integration/tests/demo/diff_commits.go +++ b/pkg/integration/tests/demo/diff_commits.go @@ -13,8 +13,8 @@ var DiffCommits = NewIntegrationTest(NewIntegrationTestArgs{ SetupConfig: func(config *config.AppConfig) { setDefaultDemoConfig(config) - config.UserConfig.Gui.ShowFileTree = false - config.UserConfig.Gui.ShowCommandLog = false + config.GetUserConfig().Gui.ShowFileTree = false + config.GetUserConfig().Gui.ShowCommandLog = false }, SetupRepo: func(shell *Shell) { shell.CreateNCommitsWithRandomMessages(50) diff --git a/pkg/integration/tests/demo/nuke_working_tree.go b/pkg/integration/tests/demo/nuke_working_tree.go index 5fb21967d..8adfb32d7 100644 --- a/pkg/integration/tests/demo/nuke_working_tree.go +++ b/pkg/integration/tests/demo/nuke_working_tree.go @@ -12,7 +12,7 @@ var NukeWorkingTree = NewIntegrationTest(NewIntegrationTestArgs{ IsDemo: true, SetupConfig: func(config *config.AppConfig) { setDefaultDemoConfig(config) - config.UserConfig.Gui.AnimateExplosion = true + config.GetUserConfig().Gui.AnimateExplosion = true }, SetupRepo: func(shell *Shell) { shell.EmptyCommit("blah") diff --git a/pkg/integration/tests/demo/shared.go b/pkg/integration/tests/demo/shared.go index 3b99ddac7..88fbd348f 100644 --- a/pkg/integration/tests/demo/shared.go +++ b/pkg/integration/tests/demo/shared.go @@ -4,7 +4,7 @@ import "github.com/jesseduffield/lazygit/pkg/config" // Gives us nicer colours when we generate a git repo history with `shell.CreateRepoHistory()` func setGeneratedAuthorColours(config *config.AppConfig) { - config.UserConfig.Gui.AuthorColors = map[string]string{ + config.GetUserConfig().Gui.AuthorColors = map[string]string{ "Fredrica Greenhill": "#fb5aa3", "Oscar Reuenthal": "#86c82f", "Paul Oberstein": "#ffd500", @@ -15,5 +15,5 @@ func setGeneratedAuthorColours(config *config.AppConfig) { func setDefaultDemoConfig(config *config.AppConfig) { // demos look much nicers with icons shown - config.UserConfig.Gui.NerdFontsVersion = "3" + config.GetUserConfig().Gui.NerdFontsVersion = "3" } diff --git a/pkg/integration/tests/demo/stage_lines.go b/pkg/integration/tests/demo/stage_lines.go index 4614db29e..1304d39e5 100644 --- a/pkg/integration/tests/demo/stage_lines.go +++ b/pkg/integration/tests/demo/stage_lines.go @@ -40,8 +40,8 @@ var StageLines = NewIntegrationTest(NewIntegrationTestArgs{ IsDemo: true, SetupConfig: func(config *config.AppConfig) { setDefaultDemoConfig(config) - config.UserConfig.Gui.ShowFileTree = false - config.UserConfig.Gui.ShowCommandLog = false + config.GetUserConfig().Gui.ShowFileTree = false + config.GetUserConfig().Gui.ShowCommandLog = false }, SetupRepo: func(shell *Shell) { shell.NewBranch("docs-fix") diff --git a/pkg/integration/tests/file/copy_menu.go b/pkg/integration/tests/file/copy_menu.go index 6e4f537af..1adb9989c 100644 --- a/pkg/integration/tests/file/copy_menu.go +++ b/pkg/integration/tests/file/copy_menu.go @@ -17,7 +17,7 @@ var CopyMenu = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.UserConfig.OS.CopyToClipboardCmd = "echo {{text}} > clipboard" + config.GetUserConfig().OS.CopyToClipboardCmd = "echo {{text}} > clipboard" }, SetupRepo: func(shell *Shell) {}, Run: func(t *TestDriver, keys config.KeybindingConfig) { diff --git a/pkg/integration/tests/filter_and_search/filter_fuzzy.go b/pkg/integration/tests/filter_and_search/filter_fuzzy.go index 63df903d8..1412f2da2 100644 --- a/pkg/integration/tests/filter_and_search/filter_fuzzy.go +++ b/pkg/integration/tests/filter_and_search/filter_fuzzy.go @@ -10,7 +10,7 @@ var FilterFuzzy = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.UserConfig.Gui.FilterMode = "fuzzy" + config.GetUserConfig().Gui.FilterMode = "fuzzy" }, SetupRepo: func(shell *Shell) { shell.NewBranch("this-is-my-branch") diff --git a/pkg/integration/tests/filter_and_search/filter_menu_with_no_keybindings.go b/pkg/integration/tests/filter_and_search/filter_menu_with_no_keybindings.go index 40aa8a3d1..1d9ef589f 100644 --- a/pkg/integration/tests/filter_and_search/filter_menu_with_no_keybindings.go +++ b/pkg/integration/tests/filter_and_search/filter_menu_with_no_keybindings.go @@ -10,7 +10,7 @@ var FilterMenuWithNoKeybindings = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.UserConfig.Keybinding.Universal.ToggleWhitespaceInDiffView = "" + config.GetUserConfig().Keybinding.Universal.ToggleWhitespaceInDiffView = "" }, SetupRepo: func(shell *Shell) { }, diff --git a/pkg/integration/tests/filter_by_author/select_author.go b/pkg/integration/tests/filter_by_author/select_author.go index 692b4dca9..b9603aa87 100644 --- a/pkg/integration/tests/filter_by_author/select_author.go +++ b/pkg/integration/tests/filter_by_author/select_author.go @@ -10,7 +10,7 @@ var SelectAuthor = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.AppState.GitLogShowGraph = "never" + config.GetAppState().GitLogShowGraph = "never" }, SetupRepo: func(shell *Shell) { commonSetup(shell) diff --git a/pkg/integration/tests/interactive_rebase/dont_show_branch_heads_for_todo_items.go b/pkg/integration/tests/interactive_rebase/dont_show_branch_heads_for_todo_items.go index 7b433fa17..7c2599f0b 100644 --- a/pkg/integration/tests/interactive_rebase/dont_show_branch_heads_for_todo_items.go +++ b/pkg/integration/tests/interactive_rebase/dont_show_branch_heads_for_todo_items.go @@ -11,7 +11,7 @@ var DontShowBranchHeadsForTodoItems = NewIntegrationTest(NewIntegrationTestArgs{ Skip: false, GitVersion: AtLeast("2.38.0"), SetupConfig: func(config *config.AppConfig) { - config.AppState.GitLogShowGraph = "never" + config.GetAppState().GitLogShowGraph = "never" }, SetupRepo: func(shell *Shell) { shell. diff --git a/pkg/integration/tests/interactive_rebase/drop_commit_in_copied_branch_with_update_ref.go b/pkg/integration/tests/interactive_rebase/drop_commit_in_copied_branch_with_update_ref.go index 8ea13c6e2..4ad1b0bec 100644 --- a/pkg/integration/tests/interactive_rebase/drop_commit_in_copied_branch_with_update_ref.go +++ b/pkg/integration/tests/interactive_rebase/drop_commit_in_copied_branch_with_update_ref.go @@ -11,7 +11,7 @@ var DropCommitInCopiedBranchWithUpdateRef = NewIntegrationTest(NewIntegrationTes Skip: false, GitVersion: AtLeast("2.38.0"), SetupConfig: func(config *config.AppConfig) { - config.AppState.GitLogShowGraph = "never" + config.GetAppState().GitLogShowGraph = "never" }, SetupRepo: func(shell *Shell) { shell. diff --git a/pkg/integration/tests/interactive_rebase/drop_todo_commit_with_update_ref.go b/pkg/integration/tests/interactive_rebase/drop_todo_commit_with_update_ref.go index 94e851efa..5b960129f 100644 --- a/pkg/integration/tests/interactive_rebase/drop_todo_commit_with_update_ref.go +++ b/pkg/integration/tests/interactive_rebase/drop_todo_commit_with_update_ref.go @@ -12,7 +12,7 @@ var DropTodoCommitWithUpdateRef = NewIntegrationTest(NewIntegrationTestArgs{ GitVersion: AtLeast("2.38.0"), SetupConfig: func(config *config.AppConfig) { config.GetUserConfig().Git.MainBranches = []string{"master"} - config.AppState.GitLogShowGraph = "never" + config.GetAppState().GitLogShowGraph = "never" }, SetupRepo: func(shell *Shell) { shell. diff --git a/pkg/integration/tests/interactive_rebase/interactive_rebase_of_copied_branch.go b/pkg/integration/tests/interactive_rebase/interactive_rebase_of_copied_branch.go index 4bb3b86c7..402d54b52 100644 --- a/pkg/integration/tests/interactive_rebase/interactive_rebase_of_copied_branch.go +++ b/pkg/integration/tests/interactive_rebase/interactive_rebase_of_copied_branch.go @@ -11,7 +11,7 @@ var InteractiveRebaseOfCopiedBranch = NewIntegrationTest(NewIntegrationTestArgs{ Skip: false, GitVersion: AtLeast("2.38.0"), SetupConfig: func(config *config.AppConfig) { - config.AppState.GitLogShowGraph = "never" + config.GetAppState().GitLogShowGraph = "never" }, SetupRepo: func(shell *Shell) { shell. diff --git a/pkg/integration/tests/interactive_rebase/quick_start_keep_selection.go b/pkg/integration/tests/interactive_rebase/quick_start_keep_selection.go index ba694b222..e17d59fc3 100644 --- a/pkg/integration/tests/interactive_rebase/quick_start_keep_selection.go +++ b/pkg/integration/tests/interactive_rebase/quick_start_keep_selection.go @@ -12,7 +12,7 @@ var QuickStartKeepSelection = NewIntegrationTest(NewIntegrationTestArgs{ GitVersion: AtLeast("2.38.0"), SetupConfig: func(config *config.AppConfig) { config.GetUserConfig().Git.MainBranches = []string{"master"} - config.AppState.GitLogShowGraph = "never" + config.GetAppState().GitLogShowGraph = "never" }, SetupRepo: func(shell *Shell) { shell. diff --git a/pkg/integration/tests/interactive_rebase/quick_start_keep_selection_range.go b/pkg/integration/tests/interactive_rebase/quick_start_keep_selection_range.go index ea863e408..12c2a87aa 100644 --- a/pkg/integration/tests/interactive_rebase/quick_start_keep_selection_range.go +++ b/pkg/integration/tests/interactive_rebase/quick_start_keep_selection_range.go @@ -12,7 +12,7 @@ var QuickStartKeepSelectionRange = NewIntegrationTest(NewIntegrationTestArgs{ GitVersion: AtLeast("2.38.0"), SetupConfig: func(config *config.AppConfig) { config.GetUserConfig().Git.MainBranches = []string{"master"} - config.AppState.GitLogShowGraph = "never" + config.GetAppState().GitLogShowGraph = "never" }, SetupRepo: func(shell *Shell) { shell. diff --git a/pkg/integration/tests/interactive_rebase/show_exec_todos.go b/pkg/integration/tests/interactive_rebase/show_exec_todos.go index b66036d02..82f459924 100644 --- a/pkg/integration/tests/interactive_rebase/show_exec_todos.go +++ b/pkg/integration/tests/interactive_rebase/show_exec_todos.go @@ -10,7 +10,7 @@ var ShowExecTodos = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "X", Context: "commits", diff --git a/pkg/integration/tests/interactive_rebase/view_files_of_todo_entries.go b/pkg/integration/tests/interactive_rebase/view_files_of_todo_entries.go index 837c418d0..4140e1a0f 100644 --- a/pkg/integration/tests/interactive_rebase/view_files_of_todo_entries.go +++ b/pkg/integration/tests/interactive_rebase/view_files_of_todo_entries.go @@ -11,7 +11,7 @@ var ViewFilesOfTodoEntries = NewIntegrationTest(NewIntegrationTestArgs{ Skip: false, GitVersion: AtLeast("2.38.0"), SetupConfig: func(config *config.AppConfig) { - config.AppState.GitLogShowGraph = "never" + config.GetAppState().GitLogShowGraph = "never" }, SetupRepo: func(shell *Shell) { shell. diff --git a/pkg/integration/tests/misc/confirm_on_quit.go b/pkg/integration/tests/misc/confirm_on_quit.go index d3a8abaaa..676c11a3e 100644 --- a/pkg/integration/tests/misc/confirm_on_quit.go +++ b/pkg/integration/tests/misc/confirm_on_quit.go @@ -10,7 +10,7 @@ var ConfirmOnQuit = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.UserConfig.ConfirmOnQuit = true + config.GetUserConfig().ConfirmOnQuit = true }, SetupRepo: func(shell *Shell) {}, Run: func(t *TestDriver, keys config.KeybindingConfig) { diff --git a/pkg/integration/tests/misc/copy_to_clipboard.go b/pkg/integration/tests/misc/copy_to_clipboard.go index 7afa31310..96b628c00 100644 --- a/pkg/integration/tests/misc/copy_to_clipboard.go +++ b/pkg/integration/tests/misc/copy_to_clipboard.go @@ -12,7 +12,7 @@ var CopyToClipboard = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.UserConfig.OS.CopyToClipboardCmd = "echo {{text}} > clipboard" + config.GetUserConfig().OS.CopyToClipboardCmd = "echo {{text}} > clipboard" }, SetupRepo: func(shell *Shell) { diff --git a/pkg/integration/tests/misc/disabled_keybindings.go b/pkg/integration/tests/misc/disabled_keybindings.go index 55e07034d..7ab1ba42a 100644 --- a/pkg/integration/tests/misc/disabled_keybindings.go +++ b/pkg/integration/tests/misc/disabled_keybindings.go @@ -10,10 +10,10 @@ var DisabledKeybindings = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.UserConfig.Keybinding.Universal.PrevItem = "" - config.UserConfig.Keybinding.Universal.NextItem = "" - config.UserConfig.Keybinding.Universal.NextTab = "" - config.UserConfig.Keybinding.Universal.PrevTab = "" + config.GetUserConfig().Keybinding.Universal.PrevItem = "" + config.GetUserConfig().Keybinding.Universal.NextItem = "" + config.GetUserConfig().Keybinding.Universal.NextTab = "" + config.GetUserConfig().Keybinding.Universal.PrevTab = "" }, SetupRepo: func(shell *Shell) {}, Run: func(t *TestDriver, keys config.KeybindingConfig) { diff --git a/pkg/integration/tests/misc/initial_open.go b/pkg/integration/tests/misc/initial_open.go index e2f085504..4237a6fea 100644 --- a/pkg/integration/tests/misc/initial_open.go +++ b/pkg/integration/tests/misc/initial_open.go @@ -10,7 +10,7 @@ var InitialOpen = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.UserConfig.DisableStartupPopups = false + config.GetUserConfig().DisableStartupPopups = false }, SetupRepo: func(shell *Shell) {}, Run: func(t *TestDriver, keys config.KeybindingConfig) { diff --git a/pkg/integration/tests/reflog/do_not_show_branch_markers_in_reflog_subcommits.go b/pkg/integration/tests/reflog/do_not_show_branch_markers_in_reflog_subcommits.go index e57abe914..1cac5a7a1 100644 --- a/pkg/integration/tests/reflog/do_not_show_branch_markers_in_reflog_subcommits.go +++ b/pkg/integration/tests/reflog/do_not_show_branch_markers_in_reflog_subcommits.go @@ -10,7 +10,7 @@ var DoNotShowBranchMarkersInReflogSubcommits = NewIntegrationTest(NewIntegration ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.AppState.GitLogShowGraph = "never" + config.GetAppState().GitLogShowGraph = "never" }, SetupRepo: func(shell *Shell) { shell.NewBranch("branch1") diff --git a/pkg/integration/tests/status/log_cmd.go b/pkg/integration/tests/status/log_cmd.go index 7928cb1b6..eb421f6fe 100644 --- a/pkg/integration/tests/status/log_cmd.go +++ b/pkg/integration/tests/status/log_cmd.go @@ -10,8 +10,8 @@ var LogCmd = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.UserConfig.Git.AllBranchesLogCmd = `echo "view1"` - config.UserConfig.Git.AllBranchesLogCmds = []string{`echo "view2"`} + config.GetUserConfig().Git.AllBranchesLogCmd = `echo "view1"` + config.GetUserConfig().Git.AllBranchesLogCmds = []string{`echo "view2"`} }, SetupRepo: func(shell *Shell) {}, Run: func(t *TestDriver, keys config.KeybindingConfig) { diff --git a/pkg/integration/tests/status/show_divergence_from_base_branch.go b/pkg/integration/tests/status/show_divergence_from_base_branch.go index 53ab0ab2f..141108683 100644 --- a/pkg/integration/tests/status/show_divergence_from_base_branch.go +++ b/pkg/integration/tests/status/show_divergence_from_base_branch.go @@ -10,7 +10,7 @@ var ShowDivergenceFromBaseBranch = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.UserConfig.Gui.ShowDivergenceFromBaseBranch = "arrowAndNumber" + config.GetUserConfig().Gui.ShowDivergenceFromBaseBranch = "arrowAndNumber" }, SetupRepo: func(shell *Shell) { shell.CreateNCommits(2) diff --git a/pkg/integration/tests/submodule/enter.go b/pkg/integration/tests/submodule/enter.go index 29e983b7f..363f2f1ba 100644 --- a/pkg/integration/tests/submodule/enter.go +++ b/pkg/integration/tests/submodule/enter.go @@ -10,7 +10,7 @@ var Enter = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "e", Context: "files", diff --git a/pkg/integration/tests/submodule/reset.go b/pkg/integration/tests/submodule/reset.go index a723561fc..85b379214 100644 --- a/pkg/integration/tests/submodule/reset.go +++ b/pkg/integration/tests/submodule/reset.go @@ -10,7 +10,7 @@ var Reset = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "e", Context: "files", diff --git a/pkg/integration/tests/ui/keybinding_suggestions_when_switching_repos.go b/pkg/integration/tests/ui/keybinding_suggestions_when_switching_repos.go index 62cb16b60..d9c24aeb7 100644 --- a/pkg/integration/tests/ui/keybinding_suggestions_when_switching_repos.go +++ b/pkg/integration/tests/ui/keybinding_suggestions_when_switching_repos.go @@ -13,7 +13,7 @@ var KeybindingSuggestionsWhenSwitchingRepos = NewIntegrationTest(NewIntegrationT Skip: false, SetupConfig: func(config *config.AppConfig) { otherRepo, _ := filepath.Abs("../other") - config.AppState.RecentRepos = []string{otherRepo} + config.GetAppState().RecentRepos = []string{otherRepo} }, SetupRepo: func(shell *Shell) { shell.CloneNonBare("other") diff --git a/pkg/integration/tests/ui/open_link_failure.go b/pkg/integration/tests/ui/open_link_failure.go index c7a223555..0bb45fb59 100644 --- a/pkg/integration/tests/ui/open_link_failure.go +++ b/pkg/integration/tests/ui/open_link_failure.go @@ -10,7 +10,7 @@ var OpenLinkFailure = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.UserConfig.OS.OpenLink = "exit 42" + config.GetUserConfig().OS.OpenLink = "exit 42" }, SetupRepo: func(shell *Shell) {}, Run: func(t *TestDriver, keys config.KeybindingConfig) { diff --git a/pkg/integration/tests/worktree/bare_repo_worktree_config.go b/pkg/integration/tests/worktree/bare_repo_worktree_config.go index ae4681455..364134cc2 100644 --- a/pkg/integration/tests/worktree/bare_repo_worktree_config.go +++ b/pkg/integration/tests/worktree/bare_repo_worktree_config.go @@ -15,7 +15,7 @@ var BareRepoWorktreeConfig = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{"--git-dir={{.actualPath}}/.bare"}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.UserConfig.Gui.ShowFileTree = false + config.GetUserConfig().Gui.ShowFileTree = false }, SetupRepo: func(shell *Shell) { // we're going to have a directory structure like this: diff --git a/pkg/integration/tests/worktree/custom_command.go b/pkg/integration/tests/worktree/custom_command.go index 2276e59be..c10ed6749 100644 --- a/pkg/integration/tests/worktree/custom_command.go +++ b/pkg/integration/tests/worktree/custom_command.go @@ -10,7 +10,7 @@ var CustomCommand = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(cfg *config.AppConfig) { - cfg.UserConfig.CustomCommands = []config.CustomCommand{ + cfg.GetUserConfig().CustomCommands = []config.CustomCommand{ { Key: "d", Context: "worktrees", diff --git a/pkg/integration/tests/worktree/double_nested_linked_submodule.go b/pkg/integration/tests/worktree/double_nested_linked_submodule.go index c964251a9..aa49f058c 100644 --- a/pkg/integration/tests/worktree/double_nested_linked_submodule.go +++ b/pkg/integration/tests/worktree/double_nested_linked_submodule.go @@ -13,7 +13,7 @@ var DoubleNestedLinkedSubmodule = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.UserConfig.Gui.ShowFileTree = false + config.GetUserConfig().Gui.ShowFileTree = false }, SetupRepo: func(shell *Shell) { // we're going to have a directory structure like this: diff --git a/pkg/integration/tests/worktree/symlink_into_repo_subdir.go b/pkg/integration/tests/worktree/symlink_into_repo_subdir.go index a77a95d72..66bc28a1e 100644 --- a/pkg/integration/tests/worktree/symlink_into_repo_subdir.go +++ b/pkg/integration/tests/worktree/symlink_into_repo_subdir.go @@ -10,7 +10,7 @@ var SymlinkIntoRepoSubdir = NewIntegrationTest(NewIntegrationTestArgs{ ExtraCmdArgs: []string{}, Skip: false, SetupConfig: func(config *config.AppConfig) { - config.UserConfig.Gui.ShowFileTree = false + config.GetUserConfig().Gui.ShowFileTree = false }, SetupRepo: func(shell *Shell) { // we're going to have a directory structure like this: diff --git a/pkg/updates/updates.go b/pkg/updates/updates.go index e98a995b1..60788de8e 100644 --- a/pkg/updates/updates.go +++ b/pkg/updates/updates.go @@ -168,7 +168,7 @@ func (u *Updater) skipUpdateCheck() bool { return true } - userConfig := u.UserConfig + userConfig := u.UserConfig() if userConfig.Update.Method == "never" { u.Log.Info("Update method is set to never so we won't check for an update") return true diff --git a/pkg/utils/dummies.go b/pkg/utils/dummies.go index b84a9e38e..1a2348b7a 100644 --- a/pkg/utils/dummies.go +++ b/pkg/utils/dummies.go @@ -19,23 +19,25 @@ func NewDummyLog() *logrus.Entry { func NewDummyCommon() *common.Common { tr := i18n.EnglishTranslationSet() - return &common.Common{ - Log: NewDummyLog(), - Tr: tr, - UserConfig: config.GetDefaultConfig(), - Fs: afero.NewOsFs(), + cmn := &common.Common{ + Log: NewDummyLog(), + Tr: tr, + Fs: afero.NewOsFs(), } + cmn.SetUserConfig(config.GetDefaultConfig()) + return cmn } func NewDummyCommonWithUserConfigAndAppState(userConfig *config.UserConfig, appState *config.AppState) *common.Common { tr := i18n.EnglishTranslationSet() - return &common.Common{ - Log: NewDummyLog(), - Tr: tr, - UserConfig: userConfig, - AppState: appState, + cmn := &common.Common{ + Log: NewDummyLog(), + Tr: tr, + AppState: appState, // TODO: remove dependency on actual filesystem in tests and switch to using // in-memory for everything Fs: afero.NewOsFs(), } + cmn.SetUserConfig(userConfig) + return cmn } diff --git a/pkg/utils/slice.go b/pkg/utils/slice.go index 0dc9e64e4..c84217b77 100644 --- a/pkg/utils/slice.go +++ b/pkg/utils/slice.go @@ -179,3 +179,18 @@ func Shift[T any](slice []T) (T, []T) { slice = slice[1:] return value, slice } + +// Compares two slices for equality +func EqualSlices[T comparable](slice1 []T, slice2 []T) bool { + if len(slice1) != len(slice2) { + return false + } + + for i := range slice1 { + if slice1[i] != slice2[i] { + return false + } + } + + return true +} diff --git a/vendor/github.com/jesseduffield/gocui/gui.go b/vendor/github.com/jesseduffield/gocui/gui.go index 0c64e6925..7ede647aa 100644 --- a/vendor/github.com/jesseduffield/gocui/gui.go +++ b/vendor/github.com/jesseduffield/gocui/gui.go @@ -751,13 +751,20 @@ func (g *Gui) MainLoop() error { } }() - if g.Mouse { - Screen.EnableMouse() - } - Screen.EnableFocus() + previousEnableMouse := false for { + if g.Mouse != previousEnableMouse { + if g.Mouse { + Screen.EnableMouse() + } else { + Screen.DisableMouse() + } + + previousEnableMouse = g.Mouse + } + err := g.processEvent() if err != nil { return err @@ -1084,7 +1091,7 @@ func (g *Gui) drawTitle(v *View, fgColor, bgColor Attribute) error { if i >= currentTabStart && i <= currentTabEnd { currentFgColor = v.SelFgColor if v != g.currentView { - currentFgColor -= AttrBold + currentFgColor &= ^AttrBold } } if err := g.SetRune(x, v.y0, ch, currentFgColor, currentBgColor); err != nil { diff --git a/vendor/modules.txt b/vendor/modules.txt index 5c121e84b..5c9946acc 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -172,7 +172,7 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/filesystem github.com/jesseduffield/go-git/v5/utils/merkletrie/index github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame github.com/jesseduffield/go-git/v5/utils/merkletrie/noder -# github.com/jesseduffield/gocui v0.3.1-0.20240817084901-ea75eca94702 +# github.com/jesseduffield/gocui v0.3.1-0.20240818082312-49cc572a9ffa ## explicit; go 1.12 github.com/jesseduffield/gocui # github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10