From 07dd8a2b0712382718f033ef4e9fcc2f14c4e41e Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Thu, 1 Aug 2024 11:59:53 +0200 Subject: [PATCH 01/29] Bump gocui --- go.mod | 2 +- go.sum | 4 ++-- vendor/github.com/jesseduffield/gocui/gui.go | 17 ++++++++++++----- vendor/modules.txt | 2 +- 4 files changed, 16 insertions(+), 9 deletions(-) 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/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 From 75a95865ffad111fff67d1ed5d982f1cf183b8df Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 31 Jul 2024 14:41:33 +0200 Subject: [PATCH 02/29] Use filepath instead of path for file path operations In practice, using path seems to work too, since Windows seems to be capable of dealing with a path like C:/x/y instead of C:\x\y; but it's cleaner to do this properly. --- pkg/commands/git_commands/repo_paths.go | 15 ++-- pkg/commands/git_commands/repo_paths_test.go | 84 ++++++++++++++++---- pkg/commands/git_commands/working_tree.go | 4 +- 3 files changed, 78 insertions(+), 25 deletions(-) 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/working_tree.go b/pkg/commands/git_commands/working_tree.go index 2364f2a68..5e3758ad5 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) } From a19bb0bbfe22fe2067f1852caa5796dff96955da Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 13 Jul 2024 18:19:38 +0200 Subject: [PATCH 03/29] Cleanup: remove unused field DeafultConfFiles It was also embarrassingly misspelled, so it's good that it's gone. :-) --- pkg/config/app_config.go | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index ef76d7274..fcdabb269 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -13,18 +13,17 @@ import ( // 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 + UserConfigPaths []string + UserConfigDir string + TempDir string + AppState *AppState + IsNewRepo bool } type AppConfigurer interface { From dbf6716b9bbae7cd4aba7484bf99ffaaff6000bb Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 13 Jul 2024 18:20:19 +0200 Subject: [PATCH 04/29] Cleanup: remove unused field IsNewRepo --- pkg/config/app_config.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index fcdabb269..3364ba554 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -23,7 +23,6 @@ type AppConfig struct { UserConfigDir string TempDir string AppState *AppState - IsNewRepo bool } type AppConfigurer interface { @@ -101,7 +100,6 @@ func NewAppConfig( UserConfigDir: configDir, TempDir: tempDir, AppState: appState, - IsNewRepo: false, } return appConfig, nil From 54765d2236e792f97eeed81e979915ec09371785 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 14 Jul 2024 14:03:44 +0200 Subject: [PATCH 05/29] Cleanup: remove unused method AppConfig.ConfigFilename --- pkg/config/app_config.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index 3364ba554..151a8b65a 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -302,11 +302,6 @@ 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) From 55d8e801f148f5e2dc97c3a5cb9e9fc2f73afc66 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 14 Jul 2024 14:22:36 +0200 Subject: [PATCH 06/29] Use getters for AppState and UserConfig instead of accessing the fields directly This will allow us to make them private. --- pkg/integration/tests/bisect/basic.go | 2 +- pkg/integration/tests/bisect/choose_terms.go | 2 +- pkg/integration/tests/bisect/skip.go | 2 +- pkg/integration/tests/branch/rebase_copied_branch.go | 2 +- pkg/integration/tests/branch/rebase_onto_base_branch.go | 2 +- .../tests/branch/show_divergence_from_base_branch.go | 2 +- .../tests/cherry_pick/cherry_pick_during_rebase.go | 2 +- pkg/integration/tests/commit/auto_wrap_message.go | 2 +- pkg/integration/tests/commit/commit_wip_with_prefix.go | 4 ++-- pkg/integration/tests/commit/commit_with_global_prefix.go | 4 ++-- .../tests/commit/commit_with_non_matching_branch_name.go | 4 ++-- pkg/integration/tests/commit/commit_with_prefix.go | 4 ++-- pkg/integration/tests/commit/highlight.go | 2 +- pkg/integration/tests/commit/new_branch_with_prefix.go | 2 +- pkg/integration/tests/commit/paste_commit_message.go | 4 ++-- .../tests/commit/paste_commit_message_over_existing.go | 4 ++-- .../tests/custom_commands/access_commit_properties.go | 2 +- pkg/integration/tests/custom_commands/basic_command.go | 2 +- .../tests/custom_commands/check_for_conflicts.go | 2 +- pkg/integration/tests/custom_commands/form_prompts.go | 2 +- pkg/integration/tests/custom_commands/global_context.go | 2 +- .../tests/custom_commands/menu_from_command.go | 2 +- .../tests/custom_commands/menu_from_commands_output.go | 2 +- .../tests/custom_commands/multiple_contexts.go | 2 +- pkg/integration/tests/custom_commands/multiple_prompts.go | 2 +- pkg/integration/tests/custom_commands/selected_commit.go | 2 +- pkg/integration/tests/custom_commands/selected_path.go | 2 +- .../tests/custom_commands/show_output_in_panel.go | 2 +- .../tests/custom_commands/suggestions_command.go | 2 +- .../tests/custom_commands/suggestions_preset.go | 2 +- pkg/integration/tests/demo/amend_old_commit.go | 2 +- pkg/integration/tests/demo/custom_command.go | 2 +- pkg/integration/tests/demo/diff_commits.go | 4 ++-- pkg/integration/tests/demo/nuke_working_tree.go | 2 +- pkg/integration/tests/demo/shared.go | 4 ++-- pkg/integration/tests/demo/stage_lines.go | 4 ++-- pkg/integration/tests/file/copy_menu.go | 2 +- pkg/integration/tests/filter_and_search/filter_fuzzy.go | 2 +- .../filter_and_search/filter_menu_with_no_keybindings.go | 2 +- pkg/integration/tests/filter_by_author/select_author.go | 2 +- .../dont_show_branch_heads_for_todo_items.go | 2 +- .../drop_commit_in_copied_branch_with_update_ref.go | 2 +- .../drop_todo_commit_with_update_ref.go | 2 +- .../interactive_rebase_of_copied_branch.go | 2 +- .../interactive_rebase/quick_start_keep_selection.go | 2 +- .../quick_start_keep_selection_range.go | 2 +- .../tests/interactive_rebase/show_exec_todos.go | 2 +- .../interactive_rebase/view_files_of_todo_entries.go | 2 +- pkg/integration/tests/misc/confirm_on_quit.go | 2 +- pkg/integration/tests/misc/copy_to_clipboard.go | 2 +- pkg/integration/tests/misc/disabled_keybindings.go | 8 ++++---- pkg/integration/tests/misc/initial_open.go | 2 +- .../do_not_show_branch_markers_in_reflog_subcommits.go | 2 +- pkg/integration/tests/status/log_cmd.go | 4 ++-- .../tests/status/show_divergence_from_base_branch.go | 2 +- pkg/integration/tests/submodule/enter.go | 2 +- pkg/integration/tests/submodule/reset.go | 2 +- .../ui/keybinding_suggestions_when_switching_repos.go | 2 +- pkg/integration/tests/ui/open_link_failure.go | 2 +- .../tests/worktree/bare_repo_worktree_config.go | 2 +- pkg/integration/tests/worktree/custom_command.go | 2 +- .../tests/worktree/double_nested_linked_submodule.go | 2 +- .../tests/worktree/symlink_into_repo_subdir.go | 2 +- 63 files changed, 76 insertions(+), 76 deletions(-) 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: From 48bb3a9dcefb28be347466c7a3dd0db5e94c7d04 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 14 Jul 2024 14:26:42 +0200 Subject: [PATCH 07/29] Make fields of AppConfig private We are going to make a few changes to the fields in this branch, and we can make them with more peace of mind when we can be sure they are not accessed from outside this package. --- pkg/config/app_config.go | 64 ++++++++++++++++++++-------------------- pkg/config/dummies.go | 12 ++++---- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index 151a8b65a..dd1635f6f 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -13,16 +13,16 @@ import ( // 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 - UserConfigDir string - TempDir string - AppState *AppState + 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 + userConfigDir string + tempDir string + appState *AppState } type AppConfigurer interface { @@ -90,16 +90,16 @@ func NewAppConfig( } appConfig := &AppConfig{ - Name: name, - Version: version, - BuildDate: date, - Debug: debuggingFlag, - BuildSource: buildSource, - UserConfig: userConfig, - UserConfigPaths: userConfigPaths, - UserConfigDir: configDir, - TempDir: tempDir, - AppState: appState, + name: name, + version: version, + buildDate: date, + debug: debuggingFlag, + buildSource: buildSource, + userConfig: userConfig, + userConfigPaths: userConfigPaths, + userConfigDir: configDir, + tempDir: tempDir, + appState: appState, } return appConfig, nil @@ -217,53 +217,53 @@ 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 c.userConfigPaths } func (c *AppConfig) GetUserConfigDir() string { - return c.UserConfigDir + return c.userConfigDir } func (c *AppConfig) ReloadUserConfig() error { - userConfig, err := loadUserConfigWithDefaults(c.UserConfigPaths) + userConfig, err := loadUserConfigWithDefaults(c.userConfigPaths) if err != nil { return err } - c.UserConfig = userConfig + c.userConfig = userConfig return nil } func (c *AppConfig) GetTempDir() string { - return c.TempDir + return c.tempDir } // findConfigFile looks for a possibly existing config file. @@ -304,7 +304,7 @@ func stateFilePath(filename string) (string, error) { // 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 } 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 } From cd0f72d66a73358192c68ee85db7f06d7cdc2c82 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 30 Mar 2024 15:07:52 +0100 Subject: [PATCH 08/29] Remove pointless reloading of UserConfig It was added in 043cb2ea44, and the commit message was "reload config whenever returning to gui". I don't understand what this means; Run() is called exactly once after startup, so it would just reload the config again for no reason. We will add a real way of reloading the config whenever it has changed later in this branch. --- pkg/config/app_config.go | 11 ----------- pkg/gui/gui.go | 3 --- 2 files changed, 14 deletions(-) diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index dd1635f6f..16f98cfb5 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -36,7 +36,6 @@ type AppConfigurer interface { GetUserConfig() *UserConfig GetUserConfigPaths() []string GetUserConfigDir() string - ReloadUserConfig() error GetTempDir() string GetAppState() *AppState @@ -252,16 +251,6 @@ func (c *AppConfig) GetUserConfigDir() string { return c.userConfigDir } -func (c *AppConfig) ReloadUserConfig() error { - userConfig, err := loadUserConfigWithDefaults(c.userConfigPaths) - if err != nil { - return err - } - - c.userConfig = userConfig - return nil -} - func (c *AppConfig) GetTempDir() string { return c.tempDir } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index b65dd80e0..04e038d9c 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -658,9 +658,6 @@ 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 } From e71fc43952bf70737be8ee9b4ca92b40e599104a Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 14 Jul 2024 16:29:15 +0200 Subject: [PATCH 09/29] Remove return value of Gui.setColorScheme It always returns nil. --- pkg/gui/gui.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 04e038d9c..68566867a 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -671,9 +671,7 @@ func (gui *Gui) Run(startArgs appTypes.StartArgs) error { gui.g.Mouse = true } - if err := gui.setColorScheme(); err != nil { - return err - } + gui.setColorScheme() gui.g.SetManager(gocui.ManagerFunc(gui.layout)) @@ -931,7 +929,7 @@ func (gui *Gui) showBreakingChangesMessage() { } // setColorScheme sets the color scheme for the app based on the user config -func (gui *Gui) setColorScheme() error { +func (gui *Gui) setColorScheme() { userConfig := gui.UserConfig theme.UpdateTheme(userConfig.Gui.Theme) @@ -939,8 +937,6 @@ func (gui *Gui) setColorScheme() error { gui.g.SelFgColor = theme.ActiveBorderColor gui.g.FrameColor = theme.InactiveBorderColor gui.g.SelFrameColor = theme.ActiveBorderColor - - return nil } func (gui *Gui) onUIThread(f func() error) { From be0fa98d114e91d7d4358a52d60c6f92b208a650 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 14 Jul 2024 16:11:09 +0200 Subject: [PATCH 10/29] Split createAllViews Split it so createAllViews instanciates the views, and sets those properties that are independent of the user config, and configureViewProperties which sets those things that do depend on the user config. For now we call the second right after the first, but later we'll call configureViewProperties after reloading the user config. --- pkg/gui/gui.go | 2 ++ pkg/gui/views.go | 66 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 68566867a..f7319b796 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -679,6 +679,8 @@ func (gui *Gui) Run(startArgs appTypes.StartArgs) error { return err } + gui.configureViewProperties() + // onNewRepo must be called after g.SetManager because SetManager deletes keybindings if err := gui.onNewRepo(startArgs, context.NO_CONTEXT); err != nil { return err diff --git a/pkg/gui/views.go b/pkg/gui/views.go index 9a4fa0a47..ec23a5590 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,6 +174,37 @@ func (gui *Gui) createAllViews() error { gui.Views.Snake.Title = gui.c.Tr.SnakeTitle gui.Views.Snake.FgColor = gocui.ColorGreen + 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 { @@ -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 = "" + } } From 940700dc56ef40ecc62f7d5f8c03ec72df45df83 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 13 Jul 2024 18:07:48 +0200 Subject: [PATCH 11/29] Introduce ConfigFile struct This makes it more explicit how to deal with the different types of config files: a user-supplied config file (via the LG_CONFIG_FILE env var) is required to exist, whereas the default config file will be created if it is missing. We will later extend this with repo-specific config files, which will be skipped if missing. --- pkg/config/app_config.go | 67 +++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index 16f98cfb5..3460c4b00 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -8,6 +8,7 @@ import ( "github.com/adrg/xdg" "github.com/jesseduffield/lazygit/pkg/utils/yaml_utils" + "github.com/samber/lo" "gopkg.in/yaml.v3" ) @@ -19,7 +20,7 @@ type AppConfig struct { name string `long:"name" env:"NAME" default:"lazygit"` buildSource string `long:"build-source" env:"BUILD_SOURCE" default:""` userConfig *UserConfig - userConfigPaths []string + userConfigFiles []*ConfigFile userConfigDir string tempDir string appState *AppState @@ -42,6 +43,18 @@ type AppConfigurer interface { SaveAppState() error } +type ConfigFilePolicy int + +const ( + ConfigFilePolicyCreateIfMissing ConfigFilePolicy = iota + ConfigFilePolicyErrorIfMissing +) + +type ConfigFile struct { + Path string + Policy ConfigFilePolicy +} + // NewAppConfig makes a new app config func NewAppConfig( name string, @@ -57,17 +70,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 } @@ -95,7 +113,7 @@ func NewAppConfig( debug: debuggingFlag, buildSource: buildSource, userConfig: userConfig, - userConfigPaths: userConfigPaths, + userConfigFiles: configFiles, userConfigDir: configDir, tempDir: tempDir, appState: appState, @@ -104,10 +122,6 @@ func NewAppConfig( return appConfig, nil } -func isCustomConfigFile(path string) bool { - return path != filepath.Join(ConfigDir(), ConfigFilename) -} - func ConfigDir() string { _, filePath := findConfigFile("config.yml") @@ -119,32 +133,33 @@ 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 { +func loadUserConfig(configFiles []*ConfigFile, base *UserConfig) (*UserConfig, error) { + for _, configFile := range configFiles { + path := configFile.Path if _, err := os.Stat(path); err != nil { 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 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() } - file.Close() } content, err := os.ReadFile(path) @@ -244,7 +259,9 @@ func (c *AppConfig) GetAppState() *AppState { } func (c *AppConfig) GetUserConfigPaths() []string { - return c.userConfigPaths + return lo.Map(c.userConfigFiles, func(f *ConfigFile, _ int) string { + return f.Path + }) } func (c *AppConfig) GetUserConfigDir() string { From f114321322c05281fb0ed93700a7beeae253b30a Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Mon, 15 Jul 2024 09:58:58 +0200 Subject: [PATCH 12/29] Save changed user config back to disk in integration tests At the moment, the user config is only read once at startup, so there's no point in writing it back to disk. However, later in this branch we will add code that reloads the user config when switching repos, which does happen quite a bit in integration tests; this would undo the changes that a test made in its SetupConfig function, so write those changes to disk to prevent that from happening. --- pkg/app/entry_point.go | 6 ++++++ pkg/config/app_config.go | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) 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/config/app_config.go b/pkg/config/app_config.go index 3460c4b00..e30ff4a26 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -2,6 +2,7 @@ package config import ( "fmt" + "log" "os" "path/filepath" "strings" @@ -361,6 +362,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.userConfigFiles) != 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.userConfigFiles[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 { From f98b57aa5e148246312af0ec99dc5dcf09c0843e Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Thu, 1 Aug 2024 12:20:05 +0200 Subject: [PATCH 13/29] Change direct access to Common.UserConfig to a getter This will allow us to turn the field into an atomic.Value for safe concurrent access. --- pkg/app/app.go | 19 +++++++------ pkg/commands/git_commands/branch.go | 8 +++--- pkg/commands/git_commands/branch_loader.go | 2 +- pkg/commands/git_commands/commit.go | 8 +++--- .../git_commands/commit_loader_test.go | 2 +- pkg/commands/git_commands/config.go | 6 ++-- pkg/commands/git_commands/deps_test.go | 6 ++-- pkg/commands/git_commands/diff.go | 4 +-- pkg/commands/git_commands/file.go | 18 ++++++------ pkg/commands/git_commands/stash.go | 2 +- pkg/commands/git_commands/sync.go | 4 +-- pkg/commands/git_commands/sync_test.go | 4 +-- pkg/commands/git_commands/working_tree.go | 8 +++--- pkg/commands/oscommands/os.go | 16 +++++------ pkg/commands/oscommands/os_default_test.go | 4 +-- pkg/commands/oscommands/os_windows_test.go | 2 +- pkg/common/common.go | 10 ++++++- pkg/gui/background.go | 4 +-- pkg/gui/command_log_panel.go | 6 ++-- pkg/gui/context/branches_context.go | 2 +- pkg/gui/context/commit_files_context.go | 4 +-- pkg/gui/context/commit_message_context.go | 6 ++-- pkg/gui/context/local_commits_context.go | 8 +++--- pkg/gui/context/menu_context.go | 2 +- pkg/gui/context/reflog_commits_context.go | 6 ++-- pkg/gui/context/remotes_context.go | 2 +- pkg/gui/context/search_trait.go | 2 +- pkg/gui/context/sub_commits_context.go | 6 ++-- pkg/gui/context/tags_context.go | 2 +- pkg/gui/context/working_tree_context.go | 4 +-- .../controllers/basic_commits_controller.go | 4 +-- .../controllers/commit_message_controller.go | 4 +-- .../controllers/confirmation_controller.go | 2 +- pkg/gui/controllers/files_controller.go | 4 +-- .../controllers/helpers/app_status_helper.go | 8 +++--- .../helpers/confirmation_helper.go | 2 +- pkg/gui/controllers/helpers/gpg_helper.go | 2 +- pkg/gui/controllers/helpers/host_helper.go | 2 +- .../helpers/inline_status_helper.go | 2 +- .../helpers/merge_and_rebase_helper.go | 4 +-- pkg/gui/controllers/helpers/refresh_helper.go | 2 +- pkg/gui/controllers/helpers/refs_helper.go | 2 +- pkg/gui/controllers/helpers/search_helper.go | 6 ++-- .../controllers/helpers/suggestions_helper.go | 14 +++++----- pkg/gui/controllers/helpers/tags_helper.go | 4 +-- pkg/gui/controllers/helpers/update_helper.go | 2 +- .../helpers/window_arrangement_helper.go | 2 +- .../helpers/working_tree_helper.go | 8 +++--- pkg/gui/controllers/list_controller.go | 8 +++--- .../controllers/local_commits_controller.go | 12 ++++---- .../controllers/merge_conflicts_controller.go | 4 +-- .../controllers/patch_explorer_controller.go | 4 +-- pkg/gui/controllers/quit_actions.go | 4 +-- pkg/gui/controllers/shell_command_action.go | 2 +- pkg/gui/controllers/staging_controller.go | 2 +- pkg/gui/controllers/stash_controller.go | 4 +-- pkg/gui/controllers/status_controller.go | 4 +-- pkg/gui/controllers/sync_controller.go | 8 +++--- .../controllers/vertical_scroll_controller.go | 4 +-- .../controllers/workspace_reset_controller.go | 2 +- pkg/gui/global_handlers.go | 6 ++-- pkg/gui/gui.go | 28 +++++++++---------- pkg/gui/keybindings.go | 2 +- pkg/gui/layout.go | 2 +- pkg/gui/presentation/branches_test.go | 4 +-- pkg/gui/presentation/commits.go | 8 +++--- pkg/gui/services/custom_commands/client.go | 2 +- pkg/gui/views.go | 12 ++++---- pkg/updates/updates.go | 2 +- pkg/utils/dummies.go | 22 ++++++++------- 70 files changed, 204 insertions(+), 193 deletions(-) diff --git a/pkg/app/app.go b/pkg/app/app.go index 755f707c4..bbe714458 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -71,14 +71,15 @@ func NewCommon(config config.AppConfigurer) (*common.Common, error) { return nil, err } - 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 +196,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/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..9c9138062 100644 --- a/pkg/commands/git_commands/commit_loader_test.go +++ b/pkg/commands/git_commands/commit_loader_test.go @@ -322,7 +322,7 @@ 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) commits, err := builder.GetCommits(opts) 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/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 5e3758ad5..d0148bfe9 100644 --- a/pkg/commands/git_commands/working_tree.go +++ b/pkg/commands/git_commands/working_tree.go @@ -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..2a18cf0e1 100644 --- a/pkg/common/common.go +++ b/pkg/common/common.go @@ -11,10 +11,18 @@ import ( type Common struct { Log *logrus.Entry Tr *i18n.TranslationSet - UserConfig *config.UserConfig + userConfig *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 +} + +func (c *Common) SetUserConfig(userConfig *config.UserConfig) { + c.userConfig = userConfig +} 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..ab62b1625 100644 --- a/pkg/gui/context/commit_message_context.go +++ b/pkg/gui/context/commit_message_context.go @@ -113,15 +113,15 @@ 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 { + if !self.c.UserConfig().Gui.CommitLength.Show { return } 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..3008f08c0 100644 --- a/pkg/gui/controllers/status_controller.go +++ b/pkg/gui/controllers/status_controller.go @@ -89,7 +89,7 @@ func (self *StatusController) onClickMain(opts gocui.ViewMouseBindingOpts) error } func (self *StatusController) GetOnRenderToMain() func() error { - config := self.c.UserConfig.Gui + config := self.c.UserConfig().Gui switch config.StatusPanelView { case "dashboard": @@ -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 f7319b796..cd2cdf983 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -379,7 +379,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.UserConfig().Git.MainBranches, gui.os.Cmd), }, Modes: &types.Modes{ Filtering: filtering.New(startArgs.FilterPath, ""), @@ -481,7 +481,7 @@ func NewGui( // 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, + ShowExtrasWindow: cmn.UserConfig().Gui.ShowCommandLog && !config.GetAppState().HideCommandLog, Mutexes: types.Mutexes{ RefreshingFilesMutex: &deadlock.Mutex{}, RefreshingBranchesMutex: &deadlock.Mutex{}, @@ -538,13 +538,13 @@ 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 { + 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) + presentation.SetCustomBranches(gui.UserConfig().Gui.BranchColors) gui.BackgroundRoutineMgr = &BackgroundRoutineMgr{gui: gui} gui.stateAccessor = &StateAccessor{gui: gui} @@ -661,13 +661,13 @@ func (gui *Gui) Run(startArgs appTypes.StartArgs) error { 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.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.ShowListFooter = userConfig().Gui.ShowListFooter - if userConfig.Gui.MouseEvents { + if userConfig().Gui.MouseEvents { gui.g.Mouse = true } @@ -732,7 +732,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 @@ -932,7 +932,7 @@ func (gui *Gui) showBreakingChangesMessage() { // setColorScheme sets the color scheme for the app based on the user config func (gui *Gui) setColorScheme() { - userConfig := gui.UserConfig + userConfig := gui.UserConfig() theme.UpdateTheme(userConfig.Gui.Theme) gui.g.FgColor = theme.InactiveBorderColor 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..4e49d0cf1 100644 --- a/pkg/gui/services/custom_commands/client.go +++ b/pkg/gui/services/custom_commands/client.go @@ -26,7 +26,7 @@ func NewClient( helpers.MergeAndRebase, ) keybindingCreator := NewKeybindingCreator(c) - customCommands := c.UserConfig.CustomCommands + customCommands := c.UserConfig().CustomCommands return &Client{ customCommands: customCommands, diff --git a/pkg/gui/views.go b/pkg/gui/views.go index ec23a5590..e76ed24d3 100644 --- a/pkg/gui/views.go +++ b/pkg/gui/views.go @@ -179,7 +179,7 @@ func (gui *Gui) createAllViews() error { func (gui *Gui) configureViewProperties() { frameRunes := []rune{'─', '│', '┌', '┐', '└', '┘'} - switch gui.c.UserConfig.Gui.Border { + switch gui.c.UserConfig().Gui.Border { case "double": frameRunes = []rune{'═', '║', '╔', '╗', '╚', '╝'} case "rounded": @@ -198,15 +198,15 @@ func (gui *Gui) configureViewProperties() { } 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 + 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 + 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 + 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) }) 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 } From d6d48f2866c2b307d439f5edfbfaacf6b3a45929 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Thu, 1 Aug 2024 12:25:10 +0200 Subject: [PATCH 14/29] Make common.UserConfig an atomic.Pointer for safe concurrent access Currently, userConfig is only read once at startup and then never changes. Later in this branch, we will add the possibility to reload the user config; this can happen either when switching repositories, or when the user has edited the config file. In both cases, reloading happens on the main thread, but the user config could be accessed concurrently from background threads, so we need to make this safe. --- pkg/common/common.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pkg/common/common.go b/pkg/common/common.go index 2a18cf0e1..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,7 +13,7 @@ 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 @@ -20,9 +22,9 @@ type Common struct { } func (c *Common) UserConfig() *config.UserConfig { - return c.userConfig + return c.userConfig.Load() } func (c *Common) SetUserConfig(userConfig *config.UserConfig) { - c.userConfig = userConfig + c.userConfig.Store(userConfig) } From 74ed1ac584edb108291a76494ed1a08b9674eb24 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Mon, 15 Jul 2024 13:48:00 +0200 Subject: [PATCH 15/29] Support per-repo config files For now we only support .git/lazygit.yml; in the future we would also like to support ./.lazygit.yml, but that one will need a trust prompt as it could be versioned, which adds quite a bit of complexity, so we leave that for later. We do, however, support config files in parent directories (all the way up to the root directory). This makes it possible to add a config file that applies to multiple repos at once. Useful if you want to set different options for all your work repos vs. all your open-source repos, for instance. --- pkg/config/app_config.go | 76 +++++++++++++++++++++++++++------------- pkg/gui/gui.go | 44 +++++++++++++++++++++++ 2 files changed, 95 insertions(+), 25 deletions(-) diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index e30ff4a26..b2cc1eafe 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -15,16 +15,17 @@ import ( // 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 - userConfigFiles []*ConfigFile - userConfigDir string - tempDir string - appState *AppState + 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,6 +39,7 @@ type AppConfigurer interface { GetUserConfig() *UserConfig GetUserConfigPaths() []string GetUserConfigDir() string + ReloadUserConfigForRepo(repoConfigFiles []*ConfigFile) error GetTempDir() string GetAppState() *AppState @@ -49,11 +51,13 @@ type ConfigFilePolicy int const ( ConfigFilePolicyCreateIfMissing ConfigFilePolicy = iota ConfigFilePolicyErrorIfMissing + ConfigFilePolicySkipIfMissing ) type ConfigFile struct { Path string Policy ConfigFilePolicy + exists bool } // NewAppConfig makes a new app config @@ -108,16 +112,17 @@ func NewAppConfig( } appConfig := &AppConfig{ - name: name, - version: version, - buildDate: date, - debug: debuggingFlag, - buildSource: buildSource, - userConfig: userConfig, - userConfigFiles: configFiles, - userConfigDir: configDir, - tempDir: tempDir, - appState: appState, + 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 @@ -141,7 +146,10 @@ func loadUserConfigWithDefaults(configFiles []*ConfigFile) (*UserConfig, error) func loadUserConfig(configFiles []*ConfigFile, base *UserConfig) (*UserConfig, error) { for _, configFile := range configFiles { path := configFile.Path - if _, err := os.Stat(path); err != nil { + _, err := os.Stat(path) + if err == nil { + configFile.exists = true + } else { if !os.IsNotExist(err) { return nil, err } @@ -150,6 +158,10 @@ func loadUserConfig(configFiles []*ConfigFile, base *UserConfig) (*UserConfig, e case ConfigFilePolicyErrorIfMissing: return nil, err + case ConfigFilePolicySkipIfMissing: + configFile.exists = false + continue + case ConfigFilePolicyCreateIfMissing: file, err := os.Create(path) if err != nil { @@ -160,6 +172,8 @@ func loadUserConfig(configFiles []*ConfigFile, base *UserConfig) (*UserConfig, e return nil, err } file.Close() + + configFile.exists = true } } @@ -260,8 +274,8 @@ func (c *AppConfig) GetAppState() *AppState { } func (c *AppConfig) GetUserConfigPaths() []string { - return lo.Map(c.userConfigFiles, func(f *ConfigFile, _ int) string { - return f.Path + return lo.FilterMap(c.userConfigFiles, func(f *ConfigFile, _ int) (string, bool) { + return f.Path, f.exists }) } @@ -269,6 +283,18 @@ func (c *AppConfig) GetUserConfigDir() string { return c.userConfigDir } +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.userConfigFiles = configFiles + return nil +} + func (c *AppConfig) GetTempDir() string { return c.tempDir } @@ -365,7 +391,7 @@ func loadAppState() (*AppState, error) { // 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.userConfigFiles) != 1 { + if len(c.globalUserConfigFiles) != 1 { panic("expected exactly one global user config file") } @@ -374,7 +400,7 @@ func (c *AppConfig) SaveGlobalUserConfig() { log.Fatalf("error marshalling user config: %v", err) } - err = os.WriteFile(c.userConfigFiles[0].Path, yamlContent, 0o644) + err = os.WriteFile(c.globalUserConfigFiles[0].Path, yamlContent, 0o644) if err != nil { log.Fatalf("error saving user config: %v", err) } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index cd2cdf983..015aec1fa 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "os" + "path/filepath" "sort" "strings" "sync" @@ -307,6 +308,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() @@ -342,6 +353,39 @@ 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() + + return nil +} + // 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 { From 2499a6c8a32902fd36014cf2c0add6b4af3764af Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 27 Jul 2024 21:39:46 +0200 Subject: [PATCH 16/29] Initialize translation set after reading user config This allows having per-repo config files with different languages per repo. Now granted, this is not an important use case that we need to support; however, the goal is to eventually make all configs hot-reloadable (as opposed to loading them only once at startup), so this is one step in that direction. --- pkg/app/app.go | 9 +++------ pkg/cheatsheet/generate.go | 5 +++++ pkg/gui/gui.go | 12 ++++++++++++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/pkg/app/app.go b/pkg/app/app.go index bbe714458..a999a902b 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -63,13 +63,10 @@ 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() cmn := &common.Common{ Log: log, 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/gui/gui.go b/pkg/gui/gui.go index 015aec1fa..582047ab9 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -36,6 +36,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" @@ -138,6 +139,8 @@ type Gui struct { c *helpers.HelperCommon helpers *helpers.Helpers + previousLanguageConfig string + integrationTest integrationTypes.IntegrationTest afterLayoutFuncs chan func() error @@ -383,6 +386,15 @@ func (gui *Gui) onUserConfigLoaded() error { gui.setColorScheme() gui.configureViewProperties() + 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 + } + return nil } From 4a272afc6726655b216cce91e2d1c33447875467 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 27 Jul 2024 21:55:41 +0200 Subject: [PATCH 17/29] Reinitialize gui.ShowExtrasWindow after loading user config --- pkg/gui/gui.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 582047ab9..109ac7ce9 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -395,6 +395,11 @@ func (gui *Gui) onUserConfigLoaded() error { 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 + return nil } @@ -534,10 +539,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{}, From 65a2eccfdb5f7352b2ee5a1eb317d07c3a3c7aa6 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 27 Jul 2024 21:59:55 +0200 Subject: [PATCH 18/29] Set custom author and branch colors and nerd font version after loading user config --- pkg/gui/gui.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 109ac7ce9..e1eeb143f 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -400,6 +400,14 @@ func (gui *Gui) onUserConfigLoaded() error { // 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 } @@ -599,14 +607,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} From 04d7907864934844fb888cbfe6f4716ada836434 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 30 Jul 2024 11:43:15 +0200 Subject: [PATCH 19/29] Move initialization of global gocui properties to onUserConfigLoaded --- pkg/gui/gui.go | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index e1eeb143f..05e68d3f7 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -386,6 +386,14 @@ func (gui *Gui) onUserConfigLoaded() error { 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 { @@ -719,20 +727,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) != "" - 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 - } - - gui.setColorScheme() gui.g.SetManager(gocui.ManagerFunc(gui.layout)) @@ -740,8 +735,6 @@ func (gui *Gui) Run(startArgs appTypes.StartArgs) error { return err } - gui.configureViewProperties() - // onNewRepo must be called after g.SetManager because SetManager deletes keybindings if err := gui.onNewRepo(startArgs, context.NO_CONTEXT); err != nil { return err From 5872779faa5abf857b24320a3c505a1936aec5a9 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 30 Jul 2024 14:40:26 +0200 Subject: [PATCH 20/29] Make gui.statusPanelView config hot-reloadable It still doesn't update the view immediately when reloading the config, only the next time the status panel is focused. But at least it does it then; writing the code to update the panel when reloading the config is probably not justifiable. --- pkg/gui/controllers/status_controller.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pkg/gui/controllers/status_controller.go b/pkg/gui/controllers/status_controller.go index 3008f08c0..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() + } } } From aef8e71b82c8f1a458ccb9142cf5038a10175bc0 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 30 Jul 2024 14:46:22 +0200 Subject: [PATCH 21/29] Make gui.commitLength hot-reloadable --- pkg/gui/context/commit_message_context.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/gui/context/commit_message_context.go b/pkg/gui/context/commit_message_context.go index ab62b1625..776043abe 100644 --- a/pkg/gui/context/commit_message_context.go +++ b/pkg/gui/context/commit_message_context.go @@ -121,11 +121,11 @@ func (self *CommitMessageContext) SetPanelState( } 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 { From 3d6d6774532fcef45f8078aaccd70c1b234f52fb Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 30 Jul 2024 19:29:03 +0200 Subject: [PATCH 22/29] Store Common instead of just the list of configured main branches in MainBranches This will make it possible to change the configured main branches at runtime. We'll support this in the next commit. --- .../git_commands/commit_loader_test.go | 2 +- pkg/commands/git_commands/main_branches.go | 25 ++++++++++--------- pkg/gui/gui.go | 2 +- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/pkg/commands/git_commands/commit_loader_test.go b/pkg/commands/git_commands/commit_loader_test.go index 9c9138062..f9c4cdff6 100644 --- a/pkg/commands/git_commands/commit_loader_test.go +++ b/pkg/commands/git_commands/commit_loader_test.go @@ -324,7 +324,7 @@ func TestGetCommits(t *testing.T) { 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/main_branches.go b/pkg/commands/git_commands/main_branches.go index 341232b04..85ac6f174 100644 --- a/pkg/commands/git_commands/main_branches.go +++ b/pkg/commands/git_commands/main_branches.go @@ -5,17 +5,17 @@ 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 cmd oscommands.ICmdObjBuilder @@ -23,14 +23,14 @@ type MainBranches struct { } 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{}, } } @@ -75,9 +75,10 @@ func (self *MainBranches) determineMainBranches() []string { var existingBranches []string var wg sync.WaitGroup - existingBranches = make([]string, len(self.configuredMainBranches)) + configuredMainBranches := self.c.UserConfig().Git.MainBranches + 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/gui/gui.go b/pkg/gui/gui.go index 05e68d3f7..7f305c0bd 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -456,7 +456,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, ""), From fd8e4803633ba802e67652266ee5131841f1bf49 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 30 Jul 2024 19:38:36 +0200 Subject: [PATCH 23/29] Re-determine existing main branches if mainBranches config changed --- pkg/commands/git_commands/main_branches.go | 12 ++++++++---- pkg/utils/slice.go | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/pkg/commands/git_commands/main_branches.go b/pkg/commands/git_commands/main_branches.go index 85ac6f174..8cf08840a 100644 --- a/pkg/commands/git_commands/main_branches.go +++ b/pkg/commands/git_commands/main_branches.go @@ -18,6 +18,8 @@ type MainBranches struct { // depending on which one exists for a given bare name. existingMainBranches []string + previousMainBranches []string + cmd oscommands.ICmdObjBuilder 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,11 +76,10 @@ 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 - configuredMainBranches := self.c.UserConfig().Git.MainBranches existingBranches = make([]string, len(configuredMainBranches)) for i, branchName := range configuredMainBranches { 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 +} From 18ad975573dce227f3d2a9dda03f6b22f6b35a64 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 3 Aug 2024 18:46:49 +0200 Subject: [PATCH 24/29] Make custom commands reload when switching repos Since onNewRepo calls resetKeybindings, which reinitializes the keybindings for custom commands, all we have to do for this is store a pointer to a config instead of storing the customCommands, so we get the up-to-date ones every time. --- pkg/gui/services/custom_commands/client.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pkg/gui/services/custom_commands/client.go b/pkg/gui/services/custom_commands/client.go index 4e49d0cf1..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 { From ce50533689b128bca55d818afa949e656e674f13 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Mon, 15 Jul 2024 13:44:31 +0200 Subject: [PATCH 25/29] Reload changed user config files on terminal focus --- pkg/config/app_config.go | 41 ++++++++++++++++++++++++++++++++++++---- pkg/gui/gui.go | 17 ++++++++++++++++- 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index b2cc1eafe..936dcb64a 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -6,6 +6,7 @@ import ( "os" "path/filepath" "strings" + "time" "github.com/adrg/xdg" "github.com/jesseduffield/lazygit/pkg/utils/yaml_utils" @@ -40,6 +41,7 @@ type AppConfigurer interface { GetUserConfigPaths() []string GetUserConfigDir() string ReloadUserConfigForRepo(repoConfigFiles []*ConfigFile) error + ReloadChangedUserConfigFiles() (error, bool) GetTempDir() string GetAppState() *AppState @@ -55,9 +57,10 @@ const ( ) type ConfigFile struct { - Path string - Policy ConfigFilePolicy - exists bool + Path string + Policy ConfigFilePolicy + modDate time.Time + exists bool } // NewAppConfig makes a new app config @@ -146,9 +149,10 @@ func loadUserConfigWithDefaults(configFiles []*ConfigFile) (*UserConfig, error) func loadUserConfig(configFiles []*ConfigFile, base *UserConfig) (*UserConfig, error) { for _, configFile := range configFiles { path := configFile.Path - _, err := os.Stat(path) + statInfo, err := os.Stat(path) if err == nil { configFile.exists = true + configFile.modDate = statInfo.ModTime() } else { if !os.IsNotExist(err) { return nil, err @@ -174,6 +178,11 @@ func loadUserConfig(configFiles []*ConfigFile, base *UserConfig) (*UserConfig, e file.Close() configFile.exists = true + statInfo, err := os.Stat(configFile.Path) + if err != nil { + return nil, err + } + configFile.modDate = statInfo.ModTime() } } @@ -295,6 +304,30 @@ func (c *AppConfig) ReloadUserConfigForRepo(repoConfigFiles []*ConfigFile) error 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 } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 7f305c0bd..9d5aad97a 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -331,8 +331,23 @@ func (gui *Gui) onNewRepo(startArgs appTypes.StartArgs, contextKey types.Context gui.g.SetFocusHandler(func(Focused bool) error { if Focused { + 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 + } + } + 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 From 57de11b70929a92814cbb5ea8eb5161d32334aa9 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 4 Aug 2024 15:09:38 +0200 Subject: [PATCH 26/29] Show a confirmation when changing a config that can't be auto-reloaded --- pkg/gui/gui.go | 56 +++++++++++++++++++++++++++++++++++++++++++++ pkg/i18n/english.go | 8 +++++++ 2 files changed, 64 insertions(+) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 9d5aad97a..c26774fd0 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -6,6 +6,7 @@ import ( "io" "os" "path/filepath" + "reflect" "sort" "strings" "sync" @@ -331,6 +332,7 @@ 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") @@ -338,6 +340,10 @@ func (gui *Gui) onNewRepo(startArgs appTypes.StartArgs, contextKey types.Context 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") @@ -434,6 +440,56 @@ func (gui *Gui) onUserConfigLoaded() error { 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 { 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.", From 38b12551198519314e15c13fbf452e95c0e37cc3 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 4 Aug 2024 14:32:04 +0200 Subject: [PATCH 27/29] Add information about per-repo config files to Config.md --- docs/Config.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 From 73696629d91408aa0e3eb27bb02c64fc3b83e3d5 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Thu, 1 Aug 2024 14:36:56 +0200 Subject: [PATCH 28/29] Add dev documentation about using UserConfig --- docs/dev/Codebase_Guide.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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). From 5431c269d3dd6f3f711155ff2e5a52248cdaf56f Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Thu, 1 Aug 2024 14:40:12 +0200 Subject: [PATCH 29/29] Add checkbox to PR template to make sure UserConfig entries can be hot-reloaded --- .github/pull_request_template.md | 1 + 1 file changed, 1 insertion(+) 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