mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-04-25 12:24:47 +02:00
Per-repo config files (and reloading of edited config files) (#3787)
- **PR Description** Support per-repo user 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. In addition, we support re-loading edited config files. This makes it much easier to experiment with config settings, especially the ones that affect the layout or color scheme, because you see the effect immediately without having to restart lazygit.
This commit is contained in:
commit
aa55995924
1
.github/pull_request_template.md
vendored
1
.github/pull_request_template.md
vendored
@ -6,6 +6,7 @@
|
|||||||
* [ ] Code has been formatted (see [here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
|
* [ ] 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)
|
* [ ] 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))
|
* [ ] 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
|
* [ ] Docs have been updated if necessary
|
||||||
* [ ] You've read through your own file changes for silly mistakes etc
|
* [ ] You've read through your own file changes for silly mistakes etc
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# User Config
|
# User Config
|
||||||
|
|
||||||
Default path for the config file:
|
Default path for the global config file:
|
||||||
|
|
||||||
- Linux: `~/.config/lazygit/config.yml`
|
- Linux: `~/.config/lazygit/config.yml`
|
||||||
- MacOS: `~/Library/Application\ Support/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"`
|
- MacOS: `export XDG_CONFIG_HOME="$HOME/.config"`
|
||||||
|
|
||||||
|
In addition to the global config file you can create repo-specific config files in `<repo>/.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
|
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
|
```yaml
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
* `pkg/commands/models`: Contains model structs that represent commits, branches, files, etc.
|
* `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/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/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/constants`: Contains some constant strings (e.g. links to docs)
|
||||||
* `pkg/env`: Contains code relating to setting/getting environment variables
|
* `pkg/env`: Contains code relating to setting/getting environment variables
|
||||||
* `pkg/i18n`: Contains internationalised strings
|
* `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)`.
|
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
|
## 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).
|
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).
|
||||||
|
2
go.mod
2
go.mod
@ -16,7 +16,7 @@ require (
|
|||||||
github.com/integrii/flaggy v1.4.0
|
github.com/integrii/flaggy v1.4.0
|
||||||
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
|
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
|
||||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d
|
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/kill v0.0.0-20220618033138-bfbe04675d10
|
||||||
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
|
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
|
||||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
||||||
|
4
go.sum
4
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/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 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/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.20240818082312-49cc572a9ffa h1:XZX6Rf60E3IuF1K+fvxjIr29f4p9kNY83mveGoJ5Uuo=
|
||||||
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/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 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0=
|
||||||
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo=
|
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=
|
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=
|
||||||
|
@ -63,22 +63,20 @@ func Run(
|
|||||||
func NewCommon(config config.AppConfigurer) (*common.Common, error) {
|
func NewCommon(config config.AppConfigurer) (*common.Common, error) {
|
||||||
userConfig := config.GetUserConfig()
|
userConfig := config.GetUserConfig()
|
||||||
appState := config.GetAppState()
|
appState := config.GetAppState()
|
||||||
|
|
||||||
var err error
|
|
||||||
log := newLogger(config)
|
log := newLogger(config)
|
||||||
tr, err := i18n.NewTranslationSetFromConfig(log, userConfig.Gui.Language)
|
// Initialize with English for the time being; the real translation set for
|
||||||
if err != nil {
|
// the configured language will be read after reading the user config
|
||||||
return nil, err
|
tr := i18n.EnglishTranslationSet()
|
||||||
}
|
|
||||||
|
|
||||||
return &common.Common{
|
cmn := &common.Common{
|
||||||
Log: log,
|
Log: log,
|
||||||
Tr: tr,
|
Tr: tr,
|
||||||
UserConfig: userConfig,
|
|
||||||
AppState: appState,
|
AppState: appState,
|
||||||
Debug: config.GetDebug(),
|
Debug: config.GetDebug(),
|
||||||
Fs: afero.NewOsFs(),
|
Fs: afero.NewOsFs(),
|
||||||
}, nil
|
}
|
||||||
|
cmn.SetUserConfig(userConfig)
|
||||||
|
return cmn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLogger(cfg config.AppConfigurer) *logrus.Entry {
|
func newLogger(cfg config.AppConfigurer) *logrus.Entry {
|
||||||
@ -195,7 +193,7 @@ func (app *App) setupRepo(
|
|||||||
|
|
||||||
var shouldInitRepo bool
|
var shouldInitRepo bool
|
||||||
initialBranchArg := ""
|
initialBranchArg := ""
|
||||||
switch app.UserConfig.NotARepository {
|
switch app.UserConfig().NotARepository {
|
||||||
case "prompt":
|
case "prompt":
|
||||||
// Offer to initialize a new repository in current directory.
|
// Offer to initialize a new repository in current directory.
|
||||||
fmt.Print(app.Tr.CreateRepo)
|
fmt.Print(app.Tr.CreateRepo)
|
||||||
|
@ -136,6 +136,12 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes
|
|||||||
|
|
||||||
if integrationTest != nil {
|
if integrationTest != nil {
|
||||||
integrationTest.SetupConfig(appConfig)
|
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)
|
common, err := NewCommon(appConfig)
|
||||||
|
@ -63,6 +63,11 @@ func generateAtDir(cheatsheetDir string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
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)
|
mApp, _ := app.NewApp(mConfig, nil, common)
|
||||||
path := cheatsheetDir + "/Keybindings_" + lang + ".md"
|
path := cheatsheetDir + "/Keybindings_" + lang + ".md"
|
||||||
file, err := os.Create(path)
|
file, err := os.Create(path)
|
||||||
|
@ -145,7 +145,7 @@ func (self *BranchCommands) GetGraph(branchName string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *BranchCommands) GetGraphCmdObj(branchName string) oscommands.ICmdObj {
|
func (self *BranchCommands) GetGraphCmdObj(branchName string) oscommands.ICmdObj {
|
||||||
branchLogCmdTemplate := self.UserConfig.Git.BranchLogCmd
|
branchLogCmdTemplate := self.UserConfig().Git.BranchLogCmd
|
||||||
templateValues := map[string]string{
|
templateValues := map[string]string{
|
||||||
"branchName": self.cmd.Quote(branchName),
|
"branchName": self.cmd.Quote(branchName),
|
||||||
}
|
}
|
||||||
@ -236,7 +236,7 @@ func (self *BranchCommands) Merge(branchName string, opts MergeOpts) error {
|
|||||||
}
|
}
|
||||||
cmdArgs := NewGitCmd("merge").
|
cmdArgs := NewGitCmd("merge").
|
||||||
Arg("--no-edit").
|
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.FastForwardOnly, "--ff-only").
|
||||||
ArgIf(opts.Squash, "--squash", "--ff").
|
ArgIf(opts.Squash, "--squash", "--ff").
|
||||||
Arg(branchName).
|
Arg(branchName).
|
||||||
@ -248,9 +248,9 @@ func (self *BranchCommands) Merge(branchName string, opts MergeOpts) error {
|
|||||||
func (self *BranchCommands) AllBranchesLogCmdObj() oscommands.ICmdObj {
|
func (self *BranchCommands) AllBranchesLogCmdObj() oscommands.ICmdObj {
|
||||||
// Only choose between non-empty, non-identical commands
|
// Only choose between non-empty, non-identical commands
|
||||||
candidates := lo.Uniq(lo.WithoutEmpty(append([]string{
|
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)
|
n := len(candidates)
|
||||||
|
@ -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 {
|
onWorker(func() error {
|
||||||
return self.GetBehindBaseBranchValuesForAllBranches(branches, mainBranches, renderFunc)
|
return self.GetBehindBaseBranchValuesForAllBranches(branches, mainBranches, renderFunc)
|
||||||
})
|
})
|
||||||
|
@ -88,7 +88,7 @@ func (self *CommitCommands) ResetToCommit(hash string, strength string, envVars
|
|||||||
func (self *CommitCommands) CommitCmdObj(summary string, description string) oscommands.ICmdObj {
|
func (self *CommitCommands) CommitCmdObj(summary string, description string) oscommands.ICmdObj {
|
||||||
messageArgs := self.commitMessageArgs(summary, description)
|
messageArgs := self.commitMessageArgs(summary, description)
|
||||||
|
|
||||||
skipHookPrefix := self.UserConfig.Git.SkipHookPrefix
|
skipHookPrefix := self.UserConfig().Git.SkipHookPrefix
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("commit").
|
cmdArgs := NewGitCmd("commit").
|
||||||
ArgIf(skipHookPrefix != "" && strings.HasPrefix(summary, skipHookPrefix), "--no-verify").
|
ArgIf(skipHookPrefix != "" && strings.HasPrefix(summary, skipHookPrefix), "--no-verify").
|
||||||
@ -148,7 +148,7 @@ func (self *CommitCommands) CommitEditorCmdObj() oscommands.ICmdObj {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitCommands) signoffFlag() string {
|
func (self *CommitCommands) signoffFlag() string {
|
||||||
if self.UserConfig.Git.Commit.SignOff {
|
if self.UserConfig().Git.Commit.SignOff {
|
||||||
return "--signoff"
|
return "--signoff"
|
||||||
} else {
|
} else {
|
||||||
return ""
|
return ""
|
||||||
@ -258,13 +258,13 @@ func (self *CommitCommands) AmendHeadCmdObj() oscommands.ICmdObj {
|
|||||||
func (self *CommitCommands) ShowCmdObj(hash string, filterPath string) oscommands.ICmdObj {
|
func (self *CommitCommands) ShowCmdObj(hash string, filterPath string) oscommands.ICmdObj {
|
||||||
contextSize := self.AppState.DiffContextSize
|
contextSize := self.AppState.DiffContextSize
|
||||||
|
|
||||||
extDiffCmd := self.UserConfig.Git.Paging.ExternalDiffCommand
|
extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand
|
||||||
cmdArgs := NewGitCmd("show").
|
cmdArgs := NewGitCmd("show").
|
||||||
Config("diff.noprefix=false").
|
Config("diff.noprefix=false").
|
||||||
ConfigIf(extDiffCmd != "", "diff.external="+extDiffCmd).
|
ConfigIf(extDiffCmd != "", "diff.external="+extDiffCmd).
|
||||||
ArgIfElse(extDiffCmd != "", "--ext-diff", "--no-ext-diff").
|
ArgIfElse(extDiffCmd != "", "--ext-diff", "--no-ext-diff").
|
||||||
Arg("--submodule").
|
Arg("--submodule").
|
||||||
Arg("--color="+self.UserConfig.Git.Paging.ColorArg).
|
Arg("--color="+self.UserConfig().Git.Paging.ColorArg).
|
||||||
Arg(fmt.Sprintf("--unified=%d", contextSize)).
|
Arg(fmt.Sprintf("--unified=%d", contextSize)).
|
||||||
Arg("--stat").
|
Arg("--stat").
|
||||||
Arg("--decorate").
|
Arg("--decorate").
|
||||||
|
@ -322,9 +322,9 @@ func TestGetCommits(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
common.UserConfig.Git.MainBranches = scenario.mainBranches
|
common.UserConfig().Git.MainBranches = scenario.mainBranches
|
||||||
opts := scenario.opts
|
opts := scenario.opts
|
||||||
opts.MainBranches = NewMainBranches(scenario.mainBranches, cmd)
|
opts.MainBranches = NewMainBranches(common, cmd)
|
||||||
commits, err := builder.GetCommits(opts)
|
commits, err := builder.GetCommits(opts)
|
||||||
|
|
||||||
assert.Equal(t, scenario.expectedCommits, commits)
|
assert.Equal(t, scenario.expectedCommits, commits)
|
||||||
|
@ -43,7 +43,7 @@ func (self *ConfigCommands) ConfiguredPager() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *ConfigCommands) GetPager(width int) string {
|
func (self *ConfigCommands) GetPager(width int) string {
|
||||||
useConfig := self.UserConfig.Git.Paging.UseConfig
|
useConfig := self.UserConfig().Git.Paging.UseConfig
|
||||||
if useConfig {
|
if useConfig {
|
||||||
pager := self.ConfiguredPager()
|
pager := self.ConfiguredPager()
|
||||||
return strings.Split(pager, "| less")[0]
|
return strings.Split(pager, "| less")[0]
|
||||||
@ -53,14 +53,14 @@ func (self *ConfigCommands) GetPager(width int) string {
|
|||||||
"columnWidth": strconv.Itoa(width/2 - 6),
|
"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)
|
return utils.ResolvePlaceholderString(pagerTemplate, templateValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UsingGpg tells us whether the user has gpg enabled so that we can know
|
// 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
|
// whether we need to run a subprocess to allow them to enter their password
|
||||||
func (self *ConfigCommands) UsingGpg() bool {
|
func (self *ConfigCommands) UsingGpg() bool {
|
||||||
overrideGpg := self.UserConfig.Git.OverrideGpg
|
overrideGpg := self.UserConfig().Git.OverrideGpg
|
||||||
if overrideGpg {
|
if overrideGpg {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -58,9 +58,9 @@ func buildGitCommon(deps commonDeps) *GitCommon {
|
|||||||
}
|
}
|
||||||
gitCommon.cmd = cmd
|
gitCommon.cmd = cmd
|
||||||
|
|
||||||
gitCommon.Common.UserConfig = deps.userConfig
|
gitCommon.Common.SetUserConfig(deps.userConfig)
|
||||||
if gitCommon.Common.UserConfig == nil {
|
if gitCommon.Common.UserConfig() == nil {
|
||||||
gitCommon.Common.UserConfig = config.GetDefaultConfig()
|
gitCommon.Common.SetUserConfig(config.GetDefaultConfig())
|
||||||
}
|
}
|
||||||
|
|
||||||
gitCommon.version = deps.gitVersion
|
gitCommon.version = deps.gitVersion
|
||||||
|
@ -17,7 +17,7 @@ func NewDiffCommands(gitCommon *GitCommon) *DiffCommands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *DiffCommands) DiffCmdObj(diffArgs []string) oscommands.ICmdObj {
|
func (self *DiffCommands) DiffCmdObj(diffArgs []string) oscommands.ICmdObj {
|
||||||
extDiffCmd := self.UserConfig.Git.Paging.ExternalDiffCommand
|
extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand
|
||||||
useExtDiff := extDiffCmd != ""
|
useExtDiff := extDiffCmd != ""
|
||||||
|
|
||||||
return self.cmd.New(
|
return self.cmd.New(
|
||||||
@ -26,7 +26,7 @@ func (self *DiffCommands) DiffCmdObj(diffArgs []string) oscommands.ICmdObj {
|
|||||||
ConfigIf(useExtDiff, "diff.external="+extDiffCmd).
|
ConfigIf(useExtDiff, "diff.external="+extDiffCmd).
|
||||||
ArgIfElse(useExtDiff, "--ext-diff", "--no-ext-diff").
|
ArgIfElse(useExtDiff, "--ext-diff", "--no-ext-diff").
|
||||||
Arg("--submodule").
|
Arg("--submodule").
|
||||||
Arg(fmt.Sprintf("--color=%s", self.UserConfig.Git.Paging.ColorArg)).
|
Arg(fmt.Sprintf("--color=%s", self.UserConfig().Git.Paging.ColorArg)).
|
||||||
Arg(diffArgs...).
|
Arg(diffArgs...).
|
||||||
Dir(self.repoPaths.worktreePath).
|
Dir(self.repoPaths.worktreePath).
|
||||||
ToArgv(),
|
ToArgv(),
|
||||||
|
@ -31,7 +31,7 @@ func (self *FileCommands) Cat(fileName string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *FileCommands) GetEditCmdStrLegacy(filename string, lineNumber int) (string, error) {
|
func (self *FileCommands) GetEditCmdStrLegacy(filename string, lineNumber int) (string, error) {
|
||||||
editor := self.UserConfig.OS.EditCommand
|
editor := self.UserConfig().OS.EditCommand
|
||||||
|
|
||||||
if editor == "" {
|
if editor == "" {
|
||||||
editor = self.config.GetCoreEditor()
|
editor = self.config.GetCoreEditor()
|
||||||
@ -60,7 +60,7 @@ func (self *FileCommands) GetEditCmdStrLegacy(filename string, lineNumber int) (
|
|||||||
"line": strconv.Itoa(lineNumber),
|
"line": strconv.Itoa(lineNumber),
|
||||||
}
|
}
|
||||||
|
|
||||||
editCmdTemplate := self.UserConfig.OS.EditCommandTemplate
|
editCmdTemplate := self.UserConfig().OS.EditCommandTemplate
|
||||||
if len(editCmdTemplate) == 0 {
|
if len(editCmdTemplate) == 0 {
|
||||||
switch editor {
|
switch editor {
|
||||||
case "emacs", "nano", "vi", "vim", "nvim":
|
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) {
|
func (self *FileCommands) GetEditCmdStr(filenames []string) (string, bool) {
|
||||||
// Legacy support for old config; to be removed at some point
|
// 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.
|
// If multiple files are selected, we'll simply edit just the first one.
|
||||||
// It's not worth fixing this for the legacy support.
|
// It's not worth fixing this for the legacy support.
|
||||||
if cmdStr, err := self.GetEditCmdStrLegacy(filenames[0], 1); err == nil {
|
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) })
|
quotedFilenames := lo.Map(filenames, func(filename string, _ int) string { return self.cmd.Quote(filename) })
|
||||||
|
|
||||||
templateValues := map[string]string{
|
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) {
|
func (self *FileCommands) GetEditAtLineCmdStr(filename string, lineNumber int) (string, bool) {
|
||||||
// Legacy support for old config; to be removed at some point
|
// 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 {
|
if cmdStr, err := self.GetEditCmdStrLegacy(filename, lineNumber); err == nil {
|
||||||
return cmdStr, true
|
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{
|
templateValues := map[string]string{
|
||||||
"filename": self.cmd.Quote(filename),
|
"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 {
|
func (self *FileCommands) GetEditAtLineAndWaitCmdStr(filename string, lineNumber int) string {
|
||||||
// Legacy support for old config; to be removed at some point
|
// 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 {
|
if cmdStr, err := self.GetEditCmdStrLegacy(filename, lineNumber); err == nil {
|
||||||
return cmdStr
|
return cmdStr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template := config.GetEditAtLineAndWaitTemplate(&self.UserConfig.OS, self.guessDefaultEditor)
|
template := config.GetEditAtLineAndWaitTemplate(&self.UserConfig().OS, self.guessDefaultEditor)
|
||||||
|
|
||||||
templateValues := map[string]string{
|
templateValues := map[string]string{
|
||||||
"filename": self.cmd.Quote(filename),
|
"filename": self.cmd.Quote(filename),
|
||||||
@ -136,7 +136,7 @@ func (self *FileCommands) GetEditAtLineAndWaitCmdStr(filename string, lineNumber
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *FileCommands) GetOpenDirInEditorCmdStr(path string) (string, bool) {
|
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{
|
templateValues := map[string]string{
|
||||||
"dir": self.cmd.Quote(path),
|
"dir": self.cmd.Quote(path),
|
||||||
|
@ -5,29 +5,31 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/common"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"github.com/sasha-s/go-deadlock"
|
"github.com/sasha-s/go-deadlock"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MainBranches struct {
|
type MainBranches struct {
|
||||||
// List of main branches configured by the user. Just the bare names.
|
c *common.Common
|
||||||
configuredMainBranches []string
|
// Which of the configured main branches actually exist in the repository. Full
|
||||||
// Which of these actually exist in the repository. Full ref names, and it
|
// ref names, and it could be either "refs/heads/..." or "refs/remotes/origin/..."
|
||||||
// could be either "refs/heads/..." or "refs/remotes/origin/..." depending
|
// depending on which one exists for a given bare name.
|
||||||
// on which one exists for a given bare name.
|
|
||||||
existingMainBranches []string
|
existingMainBranches []string
|
||||||
|
|
||||||
|
previousMainBranches []string
|
||||||
|
|
||||||
cmd oscommands.ICmdObjBuilder
|
cmd oscommands.ICmdObjBuilder
|
||||||
mutex *deadlock.Mutex
|
mutex *deadlock.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMainBranches(
|
func NewMainBranches(
|
||||||
configuredMainBranches []string,
|
cmn *common.Common,
|
||||||
cmd oscommands.ICmdObjBuilder,
|
cmd oscommands.ICmdObjBuilder,
|
||||||
) *MainBranches {
|
) *MainBranches {
|
||||||
return &MainBranches{
|
return &MainBranches{
|
||||||
configuredMainBranches: configuredMainBranches,
|
c: cmn,
|
||||||
existingMainBranches: nil,
|
existingMainBranches: nil,
|
||||||
cmd: cmd,
|
cmd: cmd,
|
||||||
mutex: &deadlock.Mutex{},
|
mutex: &deadlock.Mutex{},
|
||||||
@ -40,8 +42,11 @@ func (self *MainBranches) Get() []string {
|
|||||||
self.mutex.Lock()
|
self.mutex.Lock()
|
||||||
defer self.mutex.Unlock()
|
defer self.mutex.Unlock()
|
||||||
|
|
||||||
if self.existingMainBranches == nil {
|
configuredMainBranches := self.c.UserConfig().Git.MainBranches
|
||||||
self.existingMainBranches = self.determineMainBranches()
|
|
||||||
|
if self.existingMainBranches == nil || !utils.EqualSlices(self.previousMainBranches, configuredMainBranches) {
|
||||||
|
self.existingMainBranches = self.determineMainBranches(configuredMainBranches)
|
||||||
|
self.previousMainBranches = configuredMainBranches
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.existingMainBranches
|
return self.existingMainBranches
|
||||||
@ -71,13 +76,13 @@ func (self *MainBranches) GetMergeBase(refName string) string {
|
|||||||
return ignoringWarnings(output)
|
return ignoringWarnings(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *MainBranches) determineMainBranches() []string {
|
func (self *MainBranches) determineMainBranches(configuredMainBranches []string) []string {
|
||||||
var existingBranches []string
|
var existingBranches []string
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
existingBranches = make([]string, len(self.configuredMainBranches))
|
existingBranches = make([]string, len(configuredMainBranches))
|
||||||
|
|
||||||
for i, branchName := range self.configuredMainBranches {
|
for i, branchName := range configuredMainBranches {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go utils.Safe(func() {
|
go utils.Safe(func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
@ -3,7 +3,6 @@ package git_commands
|
|||||||
import (
|
import (
|
||||||
ioFs "io/fs"
|
ioFs "io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -64,9 +63,9 @@ func (self *RepoPaths) IsBareRepo() bool {
|
|||||||
func MockRepoPaths(currentPath string) *RepoPaths {
|
func MockRepoPaths(currentPath string) *RepoPaths {
|
||||||
return &RepoPaths{
|
return &RepoPaths{
|
||||||
worktreePath: currentPath,
|
worktreePath: currentPath,
|
||||||
worktreeGitDirPath: path.Join(currentPath, ".git"),
|
worktreeGitDirPath: filepath.Join(currentPath, ".git"),
|
||||||
repoPath: currentPath,
|
repoPath: currentPath,
|
||||||
repoGitDirPath: path.Join(currentPath, ".git"),
|
repoGitDirPath: filepath.Join(currentPath, ".git"),
|
||||||
repoName: "lazygit",
|
repoName: "lazygit",
|
||||||
isBareRepo: false,
|
isBareRepo: false,
|
||||||
}
|
}
|
||||||
@ -116,9 +115,9 @@ func GetRepoPathsForDir(
|
|||||||
if isSubmodule {
|
if isSubmodule {
|
||||||
repoPath = worktreePath
|
repoPath = worktreePath
|
||||||
} else {
|
} else {
|
||||||
repoPath = path.Dir(repoGitDirPath)
|
repoPath = filepath.Dir(repoGitDirPath)
|
||||||
}
|
}
|
||||||
repoName := path.Base(repoPath)
|
repoName := filepath.Base(repoPath)
|
||||||
|
|
||||||
return &RepoPaths{
|
return &RepoPaths{
|
||||||
worktreePath: worktreePath,
|
worktreePath: worktreePath,
|
||||||
@ -154,7 +153,7 @@ func linkedWortkreePaths(fs afero.Fs, repoGitDirPath string) []string {
|
|||||||
result := []string{}
|
result := []string{}
|
||||||
// For each directory in this path we're going to cat the `gitdir` file and append its contents to our result
|
// 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.
|
// 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
|
// ensure the directory exists
|
||||||
_, err := fs.Stat(worktreeGitDirsPath)
|
_, err := fs.Stat(worktreeGitDirsPath)
|
||||||
@ -171,7 +170,7 @@ func linkedWortkreePaths(fs afero.Fs, repoGitDirPath string) []string {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
gitDirPath := path.Join(currPath, "gitdir")
|
gitDirPath := filepath.Join(currPath, "gitdir")
|
||||||
gitDirBytes, err := afero.ReadFile(fs, gitDirPath)
|
gitDirBytes, err := afero.ReadFile(fs, gitDirPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// ignoring error
|
// ignoring error
|
||||||
@ -179,7 +178,7 @@ func linkedWortkreePaths(fs afero.Fs, repoGitDirPath string) []string {
|
|||||||
}
|
}
|
||||||
trimmedGitDir := strings.TrimSpace(string(gitDirBytes))
|
trimmedGitDir := strings.TrimSpace(string(gitDirBytes))
|
||||||
// removing the .git part
|
// removing the .git part
|
||||||
worktreeDir := path.Dir(trimmedGitDir)
|
worktreeDir := filepath.Dir(trimmedGitDir)
|
||||||
result = append(result, worktreeDir)
|
result = append(result, worktreeDir)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
@ -2,11 +2,13 @@ package git_commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
|
"github.com/samber/lo"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -29,7 +31,17 @@ func TestGetRepoPaths(t *testing.T) {
|
|||||||
Name: "typical case",
|
Name: "typical case",
|
||||||
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
||||||
// setup for main worktree
|
// 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
|
// --show-toplevel
|
||||||
"/path/to/repo",
|
"/path/to/repo",
|
||||||
// --git-dir
|
// --git-dir
|
||||||
@ -39,28 +51,45 @@ func TestGetRepoPaths(t *testing.T) {
|
|||||||
// --is-bare-repository
|
// --is-bare-repository
|
||||||
"false",
|
"false",
|
||||||
// --show-superproject-working-tree
|
// --show-superproject-working-tree
|
||||||
}
|
})
|
||||||
runner.ExpectGitArgs(
|
runner.ExpectGitArgs(
|
||||||
append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--is-bare-repository", "--show-superproject-working-tree"),
|
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)
|
nil)
|
||||||
},
|
},
|
||||||
Path: "/path/to/repo",
|
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",
|
worktreePath: "/path/to/repo",
|
||||||
worktreeGitDirPath: "/path/to/repo/.git",
|
worktreeGitDirPath: "/path/to/repo/.git",
|
||||||
repoPath: "/path/to/repo",
|
repoPath: "/path/to/repo",
|
||||||
repoGitDirPath: "/path/to/repo/.git",
|
repoGitDirPath: "/path/to/repo/.git",
|
||||||
repoName: "repo",
|
repoName: "repo",
|
||||||
isBareRepo: false,
|
isBareRepo: false,
|
||||||
},
|
}),
|
||||||
Err: nil,
|
Err: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "bare repo",
|
Name: "bare repo",
|
||||||
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
||||||
// setup for main worktree
|
// 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
|
// --show-toplevel
|
||||||
"/path/to/repo",
|
"/path/to/repo",
|
||||||
// --git-dir
|
// --git-dir
|
||||||
@ -70,27 +99,45 @@ func TestGetRepoPaths(t *testing.T) {
|
|||||||
// --is-bare-repository
|
// --is-bare-repository
|
||||||
"true",
|
"true",
|
||||||
// --show-superproject-working-tree
|
// --show-superproject-working-tree
|
||||||
}
|
})
|
||||||
runner.ExpectGitArgs(
|
runner.ExpectGitArgs(
|
||||||
append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--is-bare-repository", "--show-superproject-working-tree"),
|
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)
|
nil)
|
||||||
},
|
},
|
||||||
Path: "/path/to/repo",
|
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",
|
worktreePath: "/path/to/repo",
|
||||||
worktreeGitDirPath: "/path/to/bare_repo/bare.git",
|
worktreeGitDirPath: "/path/to/bare_repo/bare.git",
|
||||||
repoPath: "/path/to/bare_repo",
|
repoPath: "/path/to/bare_repo",
|
||||||
repoGitDirPath: "/path/to/bare_repo/bare.git",
|
repoGitDirPath: "/path/to/bare_repo/bare.git",
|
||||||
repoName: "bare_repo",
|
repoName: "bare_repo",
|
||||||
isBareRepo: true,
|
isBareRepo: true,
|
||||||
},
|
}),
|
||||||
Err: nil,
|
Err: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "submodule",
|
Name: "submodule",
|
||||||
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
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
|
// --show-toplevel
|
||||||
"/path/to/repo/submodule1",
|
"/path/to/repo/submodule1",
|
||||||
// --git-dir
|
// --git-dir
|
||||||
@ -101,21 +148,28 @@ func TestGetRepoPaths(t *testing.T) {
|
|||||||
"false",
|
"false",
|
||||||
// --show-superproject-working-tree
|
// --show-superproject-working-tree
|
||||||
"/path/to/repo",
|
"/path/to/repo",
|
||||||
}
|
})
|
||||||
runner.ExpectGitArgs(
|
runner.ExpectGitArgs(
|
||||||
append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--is-bare-repository", "--show-superproject-working-tree"),
|
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)
|
nil)
|
||||||
},
|
},
|
||||||
Path: "/path/to/repo/submodule1",
|
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",
|
worktreePath: "/path/to/repo/submodule1",
|
||||||
worktreeGitDirPath: "/path/to/repo/.git/modules/submodule1",
|
worktreeGitDirPath: "/path/to/repo/.git/modules/submodule1",
|
||||||
repoPath: "/path/to/repo/submodule1",
|
repoPath: "/path/to/repo/submodule1",
|
||||||
repoGitDirPath: "/path/to/repo/.git/modules/submodule1",
|
repoGitDirPath: "/path/to/repo/.git/modules/submodule1",
|
||||||
repoName: "submodule1",
|
repoName: "submodule1",
|
||||||
isBareRepo: false,
|
isBareRepo: false,
|
||||||
},
|
}),
|
||||||
Err: nil,
|
Err: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -84,7 +84,7 @@ func (self *StashCommands) ShowStashEntryCmdObj(index int) oscommands.ICmdObj {
|
|||||||
cmdArgs := NewGitCmd("stash").Arg("show").
|
cmdArgs := NewGitCmd("stash").Arg("show").
|
||||||
Arg("-p").
|
Arg("-p").
|
||||||
Arg("--stat").
|
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)).
|
Arg(fmt.Sprintf("--unified=%d", self.AppState.DiffContextSize)).
|
||||||
ArgIf(self.AppState.IgnoreWhitespaceInDiffView, "--ignore-all-space").
|
ArgIf(self.AppState.IgnoreWhitespaceInDiffView, "--ignore-all-space").
|
||||||
Arg(fmt.Sprintf("--find-renames=%d%%", self.AppState.RenameSimilarityThreshold)).
|
Arg(fmt.Sprintf("--find-renames=%d%%", self.AppState.RenameSimilarityThreshold)).
|
||||||
|
@ -60,7 +60,7 @@ func (self *SyncCommands) fetchCommandBuilder(fetchAll bool) *GitCommandBuilder
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *SyncCommands) FetchCmdObj(task gocui.Task) oscommands.ICmdObj {
|
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 := self.cmd.New(cmdArgs)
|
||||||
cmdObj.PromptOnCredentialRequest(task)
|
cmdObj.PromptOnCredentialRequest(task)
|
||||||
@ -72,7 +72,7 @@ func (self *SyncCommands) Fetch(task gocui.Task) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *SyncCommands) FetchBackgroundCmdObj() oscommands.ICmdObj {
|
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 := self.cmd.New(cmdArgs)
|
||||||
cmdObj.DontLog().FailOnCredentialRequest()
|
cmdObj.DontLog().FailOnCredentialRequest()
|
||||||
|
@ -133,7 +133,7 @@ func TestSyncFetch(t *testing.T) {
|
|||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
instance := buildSyncCommands(commonDeps{})
|
instance := buildSyncCommands(commonDeps{})
|
||||||
instance.UserConfig.Git.FetchAll = s.fetchAllConfig
|
instance.UserConfig().Git.FetchAll = s.fetchAllConfig
|
||||||
task := gocui.NewFakeTask()
|
task := gocui.NewFakeTask()
|
||||||
s.test(instance.FetchCmdObj(task))
|
s.test(instance.FetchCmdObj(task))
|
||||||
})
|
})
|
||||||
@ -171,7 +171,7 @@ func TestSyncFetchBackground(t *testing.T) {
|
|||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
instance := buildSyncCommands(commonDeps{})
|
instance := buildSyncCommands(commonDeps{})
|
||||||
instance.UserConfig.Git.FetchAll = s.fetchAllConfig
|
instance.UserConfig().Git.FetchAll = s.fetchAllConfig
|
||||||
s.test(instance.FetchBackgroundCmdObj())
|
s.test(instance.FetchBackgroundCmdObj())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ package git_commands
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"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
|
// Exclude adds a file to the .git/info/exclude for the repo
|
||||||
func (self *WorkingTreeCommands) Exclude(filename string) error {
|
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)
|
return self.os.AppendLineToFile(excludeFile, filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,7 +245,7 @@ func (self *WorkingTreeCommands) WorktreeFileDiff(file *models.File, plain bool,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *WorkingTreeCommands) WorktreeFileDiffCmdObj(node models.IFile, plain bool, cached bool) oscommands.ICmdObj {
|
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 {
|
if plain {
|
||||||
colorArg = "never"
|
colorArg = "never"
|
||||||
}
|
}
|
||||||
@ -253,7 +253,7 @@ func (self *WorkingTreeCommands) WorktreeFileDiffCmdObj(node models.IFile, plain
|
|||||||
contextSize := self.AppState.DiffContextSize
|
contextSize := self.AppState.DiffContextSize
|
||||||
prevPath := node.GetPreviousPath()
|
prevPath := node.GetPreviousPath()
|
||||||
noIndex := !node.GetIsTracked() && !node.GetHasStagedChanges() && !cached && node.GetIsFile()
|
noIndex := !node.GetIsTracked() && !node.GetHasStagedChanges() && !cached && node.GetIsFile()
|
||||||
extDiffCmd := self.UserConfig.Git.Paging.ExternalDiffCommand
|
extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand
|
||||||
useExtDiff := extDiffCmd != "" && !plain
|
useExtDiff := extDiffCmd != "" && !plain
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("diff").
|
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 {
|
func (self *WorkingTreeCommands) ShowFileDiffCmdObj(from string, to string, reverse bool, fileName string, plain bool) oscommands.ICmdObj {
|
||||||
contextSize := self.AppState.DiffContextSize
|
contextSize := self.AppState.DiffContextSize
|
||||||
|
|
||||||
colorArg := self.UserConfig.Git.Paging.ColorArg
|
colorArg := self.UserConfig().Git.Paging.ColorArg
|
||||||
if plain {
|
if plain {
|
||||||
colorArg = "never"
|
colorArg = "never"
|
||||||
}
|
}
|
||||||
|
|
||||||
extDiffCmd := self.UserConfig.Git.Paging.ExternalDiffCommand
|
extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand
|
||||||
useExtDiff := extDiffCmd != "" && !plain
|
useExtDiff := extDiffCmd != "" && !plain
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("diff").
|
cmdArgs := NewGitCmd("diff").
|
||||||
|
@ -80,10 +80,10 @@ func FileType(path string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *OSCommand) OpenFile(filename string) error {
|
func (c *OSCommand) OpenFile(filename string) error {
|
||||||
commandTemplate := c.UserConfig.OS.Open
|
commandTemplate := c.UserConfig().OS.Open
|
||||||
if commandTemplate == "" {
|
if commandTemplate == "" {
|
||||||
// Legacy support
|
// Legacy support
|
||||||
commandTemplate = c.UserConfig.OS.OpenCommand
|
commandTemplate = c.UserConfig().OS.OpenCommand
|
||||||
}
|
}
|
||||||
if commandTemplate == "" {
|
if commandTemplate == "" {
|
||||||
commandTemplate = config.GetPlatformDefaultConfig().Open
|
commandTemplate = config.GetPlatformDefaultConfig().Open
|
||||||
@ -96,10 +96,10 @@ func (c *OSCommand) OpenFile(filename string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *OSCommand) OpenLink(link string) error {
|
func (c *OSCommand) OpenLink(link string) error {
|
||||||
commandTemplate := c.UserConfig.OS.OpenLink
|
commandTemplate := c.UserConfig().OS.OpenLink
|
||||||
if commandTemplate == "" {
|
if commandTemplate == "" {
|
||||||
// Legacy support
|
// Legacy support
|
||||||
commandTemplate = c.UserConfig.OS.OpenLinkCommand
|
commandTemplate = c.UserConfig().OS.OpenLinkCommand
|
||||||
}
|
}
|
||||||
if commandTemplate == "" {
|
if commandTemplate == "" {
|
||||||
commandTemplate = config.GetPlatformDefaultConfig().OpenLink
|
commandTemplate = config.GetPlatformDefaultConfig().OpenLink
|
||||||
@ -294,8 +294,8 @@ func (c *OSCommand) CopyToClipboard(str string) error {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
c.LogCommand(msg, false)
|
c.LogCommand(msg, false)
|
||||||
if c.UserConfig.OS.CopyToClipboardCmd != "" {
|
if c.UserConfig().OS.CopyToClipboardCmd != "" {
|
||||||
cmdStr := utils.ResolvePlaceholderString(c.UserConfig.OS.CopyToClipboardCmd, map[string]string{
|
cmdStr := utils.ResolvePlaceholderString(c.UserConfig().OS.CopyToClipboardCmd, map[string]string{
|
||||||
"text": c.Cmd.Quote(str),
|
"text": c.Cmd.Quote(str),
|
||||||
})
|
})
|
||||||
return c.Cmd.NewShell(cmdStr).Run()
|
return c.Cmd.NewShell(cmdStr).Run()
|
||||||
@ -307,8 +307,8 @@ func (c *OSCommand) CopyToClipboard(str string) error {
|
|||||||
func (c *OSCommand) PasteFromClipboard() (string, error) {
|
func (c *OSCommand) PasteFromClipboard() (string, error) {
|
||||||
var s string
|
var s string
|
||||||
var err error
|
var err error
|
||||||
if c.UserConfig.OS.CopyToClipboardCmd != "" {
|
if c.UserConfig().OS.CopyToClipboardCmd != "" {
|
||||||
cmdStr := c.UserConfig.OS.ReadFromClipboardCmd
|
cmdStr := c.UserConfig().OS.ReadFromClipboardCmd
|
||||||
s, err = c.Cmd.NewShell(cmdStr).RunWithOutput()
|
s, err = c.Cmd.NewShell(cmdStr).RunWithOutput()
|
||||||
} else {
|
} else {
|
||||||
s, err = clipboard.ReadAll()
|
s, err = clipboard.ReadAll()
|
||||||
|
@ -75,7 +75,7 @@ func TestOSCommandOpenFileDarwin(t *testing.T) {
|
|||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
oSCmd := NewDummyOSCommandWithRunner(s.runner)
|
oSCmd := NewDummyOSCommandWithRunner(s.runner)
|
||||||
oSCmd.Platform.OS = "darwin"
|
oSCmd.Platform.OS = "darwin"
|
||||||
oSCmd.UserConfig.OS.Open = "open {{filename}}"
|
oSCmd.UserConfig().OS.Open = "open {{filename}}"
|
||||||
|
|
||||||
s.test(oSCmd.OpenFile(s.filename))
|
s.test(oSCmd.OpenFile(s.filename))
|
||||||
}
|
}
|
||||||
@ -135,7 +135,7 @@ func TestOSCommandOpenFileLinux(t *testing.T) {
|
|||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
oSCmd := NewDummyOSCommandWithRunner(s.runner)
|
oSCmd := NewDummyOSCommandWithRunner(s.runner)
|
||||||
oSCmd.Platform.OS = "linux"
|
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))
|
s.test(oSCmd.OpenFile(s.filename))
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ func TestOSCommandOpenFileWindows(t *testing.T) {
|
|||||||
}
|
}
|
||||||
oSCmd.Platform = platform
|
oSCmd.Platform = platform
|
||||||
oSCmd.Cmd.platform = platform
|
oSCmd.Cmd.platform = platform
|
||||||
oSCmd.UserConfig.OS.OpenCommand = `start "" {{filename}}`
|
oSCmd.UserConfig().OS.OpenCommand = `start "" {{filename}}`
|
||||||
|
|
||||||
s.test(oSCmd.OpenFile(s.filename))
|
s.test(oSCmd.OpenFile(s.filename))
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
"github.com/jesseduffield/lazygit/pkg/i18n"
|
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@ -11,10 +13,18 @@ import (
|
|||||||
type Common struct {
|
type Common struct {
|
||||||
Log *logrus.Entry
|
Log *logrus.Entry
|
||||||
Tr *i18n.TranslationSet
|
Tr *i18n.TranslationSet
|
||||||
UserConfig *config.UserConfig
|
userConfig atomic.Pointer[config.UserConfig]
|
||||||
AppState *config.AppState
|
AppState *config.AppState
|
||||||
Debug bool
|
Debug bool
|
||||||
// for interacting with the filesystem. We use afero rather than the default
|
// for interacting with the filesystem. We use afero rather than the default
|
||||||
// `os` package for the sake of mocking the filesystem in tests
|
// `os` package for the sake of mocking the filesystem in tests
|
||||||
Fs afero.Fs
|
Fs afero.Fs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Common) UserConfig() *config.UserConfig {
|
||||||
|
return c.userConfig.Load()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Common) SetUserConfig(userConfig *config.UserConfig) {
|
||||||
|
c.userConfig.Store(userConfig)
|
||||||
|
}
|
||||||
|
@ -2,29 +2,31 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/adrg/xdg"
|
"github.com/adrg/xdg"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils/yaml_utils"
|
"github.com/jesseduffield/lazygit/pkg/utils/yaml_utils"
|
||||||
|
"github.com/samber/lo"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AppConfig contains the base configuration fields required for lazygit.
|
// AppConfig contains the base configuration fields required for lazygit.
|
||||||
type AppConfig struct {
|
type AppConfig struct {
|
||||||
Debug bool `long:"debug" env:"DEBUG" default:"false"`
|
debug bool `long:"debug" env:"DEBUG" default:"false"`
|
||||||
Version string `long:"version" env:"VERSION" default:"unversioned"`
|
version string `long:"version" env:"VERSION" default:"unversioned"`
|
||||||
BuildDate string `long:"build-date" env:"BUILD_DATE"`
|
buildDate string `long:"build-date" env:"BUILD_DATE"`
|
||||||
Name string `long:"name" env:"NAME" default:"lazygit"`
|
name string `long:"name" env:"NAME" default:"lazygit"`
|
||||||
BuildSource string `long:"build-source" env:"BUILD_SOURCE" default:""`
|
buildSource string `long:"build-source" env:"BUILD_SOURCE" default:""`
|
||||||
UserConfig *UserConfig
|
userConfig *UserConfig
|
||||||
UserConfigPaths []string
|
globalUserConfigFiles []*ConfigFile
|
||||||
DeafultConfFiles bool
|
userConfigFiles []*ConfigFile
|
||||||
UserConfigDir string
|
userConfigDir string
|
||||||
TempDir string
|
tempDir string
|
||||||
AppState *AppState
|
appState *AppState
|
||||||
IsNewRepo bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppConfigurer interface {
|
type AppConfigurer interface {
|
||||||
@ -38,13 +40,29 @@ type AppConfigurer interface {
|
|||||||
GetUserConfig() *UserConfig
|
GetUserConfig() *UserConfig
|
||||||
GetUserConfigPaths() []string
|
GetUserConfigPaths() []string
|
||||||
GetUserConfigDir() string
|
GetUserConfigDir() string
|
||||||
ReloadUserConfig() error
|
ReloadUserConfigForRepo(repoConfigFiles []*ConfigFile) error
|
||||||
|
ReloadChangedUserConfigFiles() (error, bool)
|
||||||
GetTempDir() string
|
GetTempDir() string
|
||||||
|
|
||||||
GetAppState() *AppState
|
GetAppState() *AppState
|
||||||
SaveAppState() error
|
SaveAppState() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ConfigFilePolicy int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ConfigFilePolicyCreateIfMissing ConfigFilePolicy = iota
|
||||||
|
ConfigFilePolicyErrorIfMissing
|
||||||
|
ConfigFilePolicySkipIfMissing
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConfigFile struct {
|
||||||
|
Path string
|
||||||
|
Policy ConfigFilePolicy
|
||||||
|
modDate time.Time
|
||||||
|
exists bool
|
||||||
|
}
|
||||||
|
|
||||||
// NewAppConfig makes a new app config
|
// NewAppConfig makes a new app config
|
||||||
func NewAppConfig(
|
func NewAppConfig(
|
||||||
name string,
|
name string,
|
||||||
@ -60,17 +78,22 @@ func NewAppConfig(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var userConfigPaths []string
|
var configFiles []*ConfigFile
|
||||||
customConfigFiles := os.Getenv("LG_CONFIG_FILE")
|
customConfigFiles := os.Getenv("LG_CONFIG_FILE")
|
||||||
if customConfigFiles != "" {
|
if customConfigFiles != "" {
|
||||||
// Load user defined config files
|
// 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 {
|
} else {
|
||||||
// Load default config files
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -92,26 +115,22 @@ func NewAppConfig(
|
|||||||
}
|
}
|
||||||
|
|
||||||
appConfig := &AppConfig{
|
appConfig := &AppConfig{
|
||||||
Name: name,
|
name: name,
|
||||||
Version: version,
|
version: version,
|
||||||
BuildDate: date,
|
buildDate: date,
|
||||||
Debug: debuggingFlag,
|
debug: debuggingFlag,
|
||||||
BuildSource: buildSource,
|
buildSource: buildSource,
|
||||||
UserConfig: userConfig,
|
userConfig: userConfig,
|
||||||
UserConfigPaths: userConfigPaths,
|
globalUserConfigFiles: configFiles,
|
||||||
UserConfigDir: configDir,
|
userConfigFiles: configFiles,
|
||||||
TempDir: tempDir,
|
userConfigDir: configDir,
|
||||||
AppState: appState,
|
tempDir: tempDir,
|
||||||
IsNewRepo: false,
|
appState: appState,
|
||||||
}
|
}
|
||||||
|
|
||||||
return appConfig, nil
|
return appConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isCustomConfigFile(path string) bool {
|
|
||||||
return path != filepath.Join(ConfigDir(), ConfigFilename)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ConfigDir() string {
|
func ConfigDir() string {
|
||||||
_, filePath := findConfigFile("config.yml")
|
_, filePath := findConfigFile("config.yml")
|
||||||
|
|
||||||
@ -123,23 +142,31 @@ func findOrCreateConfigDir() (string, error) {
|
|||||||
return folder, os.MkdirAll(folder, 0o755)
|
return folder, os.MkdirAll(folder, 0o755)
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadUserConfigWithDefaults(configFiles []string) (*UserConfig, error) {
|
func loadUserConfigWithDefaults(configFiles []*ConfigFile) (*UserConfig, error) {
|
||||||
return loadUserConfig(configFiles, GetDefaultConfig())
|
return loadUserConfig(configFiles, GetDefaultConfig())
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadUserConfig(configFiles []string, base *UserConfig) (*UserConfig, error) {
|
func loadUserConfig(configFiles []*ConfigFile, base *UserConfig) (*UserConfig, error) {
|
||||||
for _, path := range configFiles {
|
for _, configFile := range configFiles {
|
||||||
if _, err := os.Stat(path); err != nil {
|
path := configFile.Path
|
||||||
|
statInfo, err := os.Stat(path)
|
||||||
|
if err == nil {
|
||||||
|
configFile.exists = true
|
||||||
|
configFile.modDate = statInfo.ModTime()
|
||||||
|
} else {
|
||||||
if !os.IsNotExist(err) {
|
if !os.IsNotExist(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// if use has supplied their own custom config file path(s), we assume
|
switch configFile.Policy {
|
||||||
// the files have already been created, so we won't go and create them here.
|
case ConfigFilePolicyErrorIfMissing:
|
||||||
if isCustomConfigFile(path) {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
|
||||||
|
|
||||||
|
case ConfigFilePolicySkipIfMissing:
|
||||||
|
configFile.exists = false
|
||||||
|
continue
|
||||||
|
|
||||||
|
case ConfigFilePolicyCreateIfMissing:
|
||||||
file, err := os.Create(path)
|
file, err := os.Create(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsPermission(err) {
|
if os.IsPermission(err) {
|
||||||
@ -149,6 +176,14 @@ func loadUserConfig(configFiles []string, base *UserConfig) (*UserConfig, error)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
file.Close()
|
file.Close()
|
||||||
|
|
||||||
|
configFile.exists = true
|
||||||
|
statInfo, err := os.Stat(configFile.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
configFile.modDate = statInfo.ModTime()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
content, err := os.ReadFile(path)
|
content, err := os.ReadFile(path)
|
||||||
@ -220,53 +255,81 @@ func changeNullKeybindingsToDisabled(changedContent []byte) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *AppConfig) GetDebug() bool {
|
func (c *AppConfig) GetDebug() bool {
|
||||||
return c.Debug
|
return c.debug
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AppConfig) GetVersion() string {
|
func (c *AppConfig) GetVersion() string {
|
||||||
return c.Version
|
return c.version
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AppConfig) GetName() string {
|
func (c *AppConfig) GetName() string {
|
||||||
return c.Name
|
return c.name
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBuildSource returns the source of the build. For builds from goreleaser
|
// GetBuildSource returns the source of the build. For builds from goreleaser
|
||||||
// this will be binaryBuild
|
// this will be binaryBuild
|
||||||
func (c *AppConfig) GetBuildSource() string {
|
func (c *AppConfig) GetBuildSource() string {
|
||||||
return c.BuildSource
|
return c.buildSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserConfig returns the user config
|
// GetUserConfig returns the user config
|
||||||
func (c *AppConfig) GetUserConfig() *UserConfig {
|
func (c *AppConfig) GetUserConfig() *UserConfig {
|
||||||
return c.UserConfig
|
return c.userConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAppState returns the app state
|
// GetAppState returns the app state
|
||||||
func (c *AppConfig) GetAppState() *AppState {
|
func (c *AppConfig) GetAppState() *AppState {
|
||||||
return c.AppState
|
return c.appState
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AppConfig) GetUserConfigPaths() []string {
|
func (c *AppConfig) GetUserConfigPaths() []string {
|
||||||
return c.UserConfigPaths
|
return lo.FilterMap(c.userConfigFiles, func(f *ConfigFile, _ int) (string, bool) {
|
||||||
|
return f.Path, f.exists
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AppConfig) GetUserConfigDir() string {
|
func (c *AppConfig) GetUserConfigDir() string {
|
||||||
return c.UserConfigDir
|
return c.userConfigDir
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AppConfig) ReloadUserConfig() error {
|
func (c *AppConfig) ReloadUserConfigForRepo(repoConfigFiles []*ConfigFile) error {
|
||||||
userConfig, err := loadUserConfigWithDefaults(c.UserConfigPaths)
|
configFiles := append(c.globalUserConfigFiles, repoConfigFiles...)
|
||||||
|
userConfig, err := loadUserConfigWithDefaults(configFiles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.UserConfig = userConfig
|
c.userConfig = userConfig
|
||||||
|
c.userConfigFiles = configFiles
|
||||||
return nil
|
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 {
|
func (c *AppConfig) GetTempDir() string {
|
||||||
return c.TempDir
|
return c.tempDir
|
||||||
}
|
}
|
||||||
|
|
||||||
// findConfigFile looks for a possibly existing config file.
|
// findConfigFile looks for a possibly existing config file.
|
||||||
@ -305,14 +368,9 @@ func stateFilePath(filename string) (string, error) {
|
|||||||
return xdg.StateFile(filepath.Join("lazygit", filename))
|
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
|
// SaveAppState marshalls the AppState struct and writes it to the disk
|
||||||
func (c *AppConfig) SaveAppState() error {
|
func (c *AppConfig) SaveAppState() error {
|
||||||
marshalledAppState, err := yaml.Marshal(c.AppState)
|
marshalledAppState, err := yaml.Marshal(c.appState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -363,6 +421,24 @@ func loadAppState() (*AppState, error) {
|
|||||||
return appState, nil
|
return appState, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SaveGlobalUserConfig saves the UserConfig back to disk. This is only used in
|
||||||
|
// integration tests, so we are a bit sloppy with error handling.
|
||||||
|
func (c *AppConfig) SaveGlobalUserConfig() {
|
||||||
|
if len(c.globalUserConfigFiles) != 1 {
|
||||||
|
panic("expected exactly one global user config file")
|
||||||
|
}
|
||||||
|
|
||||||
|
yamlContent, err := yaml.Marshal(c.userConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error marshalling user config: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(c.globalUserConfigFiles[0].Path, yamlContent, 0o644)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error saving user config: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AppState stores data between runs of the app like when the last update check
|
// AppState stores data between runs of the app like when the last update check
|
||||||
// was performed and which other repos have been checked out
|
// was performed and which other repos have been checked out
|
||||||
type AppState struct {
|
type AppState struct {
|
||||||
|
@ -7,12 +7,12 @@ import (
|
|||||||
// NewDummyAppConfig creates a new dummy AppConfig for testing
|
// NewDummyAppConfig creates a new dummy AppConfig for testing
|
||||||
func NewDummyAppConfig() *AppConfig {
|
func NewDummyAppConfig() *AppConfig {
|
||||||
appConfig := &AppConfig{
|
appConfig := &AppConfig{
|
||||||
Name: "lazygit",
|
name: "lazygit",
|
||||||
Version: "unversioned",
|
version: "unversioned",
|
||||||
Debug: false,
|
debug: false,
|
||||||
UserConfig: GetDefaultConfig(),
|
userConfig: GetDefaultConfig(),
|
||||||
AppState: &AppState{},
|
appState: &AppState{},
|
||||||
}
|
}
|
||||||
_ = yaml.Unmarshal([]byte{}, appConfig.AppState)
|
_ = yaml.Unmarshal([]byte{}, appConfig.appState)
|
||||||
return appConfig
|
return appConfig
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ func (self *BackgroundRoutineMgr) PauseBackgroundRefreshes(pause bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *BackgroundRoutineMgr) startBackgroundRoutines() {
|
func (self *BackgroundRoutineMgr) startBackgroundRoutines() {
|
||||||
userConfig := self.gui.UserConfig
|
userConfig := self.gui.UserConfig()
|
||||||
|
|
||||||
if userConfig.Git.AutoFetch {
|
if userConfig.Git.AutoFetch {
|
||||||
fetchInterval := userConfig.Refresher.FetchInterval
|
fetchInterval := userConfig.Refresher.FetchInterval
|
||||||
@ -77,7 +77,7 @@ func (self *BackgroundRoutineMgr) startBackgroundFetch() {
|
|||||||
self.gui.waitForIntro.Wait()
|
self.gui.waitForIntro.Wait()
|
||||||
|
|
||||||
isNew := self.gui.IsNewRepo
|
isNew := self.gui.IsNewRepo
|
||||||
userConfig := self.gui.UserConfig
|
userConfig := self.gui.UserConfig()
|
||||||
if !isNew {
|
if !isNew {
|
||||||
time.After(time.Duration(userConfig.Refresher.FetchInterval) * time.Second)
|
time.After(time.Duration(userConfig.Refresher.FetchInterval) * time.Second)
|
||||||
}
|
}
|
||||||
|
@ -55,11 +55,11 @@ func (gui *Gui) LogCommand(cmdStr string, commandLine bool) {
|
|||||||
func (gui *Gui) printCommandLogHeader() {
|
func (gui *Gui) printCommandLogHeader() {
|
||||||
introStr := fmt.Sprintf(
|
introStr := fmt.Sprintf(
|
||||||
gui.c.Tr.CommandLogHeader,
|
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))
|
fmt.Fprintln(gui.Views.Extras, style.FgCyan.Sprint(introStr))
|
||||||
|
|
||||||
if gui.c.UserConfig.Gui.ShowRandomTip {
|
if gui.c.UserConfig().Gui.ShowRandomTip {
|
||||||
fmt.Fprintf(
|
fmt.Fprintf(
|
||||||
gui.Views.Extras,
|
gui.Views.Extras,
|
||||||
"%s: %s",
|
"%s: %s",
|
||||||
@ -70,7 +70,7 @@ func (gui *Gui) printCommandLogHeader() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) getRandomTip() string {
|
func (gui *Gui) getRandomTip() string {
|
||||||
config := gui.c.UserConfig.Keybinding
|
config := gui.c.UserConfig().Keybinding
|
||||||
|
|
||||||
formattedKey := func(key string) string {
|
formattedKey := func(key string) string {
|
||||||
return keybindings.Label(key)
|
return keybindings.Label(key)
|
||||||
|
@ -32,7 +32,7 @@ func NewBranchesContext(c *ContextCommon) *BranchesContext {
|
|||||||
c.Modes().Diffing.Ref,
|
c.Modes().Diffing.Ref,
|
||||||
c.Views().Branches.Width(),
|
c.Views().Branches.Width(),
|
||||||
c.Tr,
|
c.Tr,
|
||||||
c.UserConfig,
|
c.UserConfig(),
|
||||||
c.Model().Worktrees,
|
c.Model().Worktrees,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ func NewCommitFilesContext(c *ContextCommon) *CommitFilesContext {
|
|||||||
viewModel := filetree.NewCommitFileTreeViewModel(
|
viewModel := filetree.NewCommitFileTreeViewModel(
|
||||||
func() []*models.CommitFile { return c.Model().CommitFiles },
|
func() []*models.CommitFile { return c.Model().CommitFiles },
|
||||||
c.Log,
|
c.Log,
|
||||||
c.UserConfig.Gui.ShowFileTree,
|
c.UserConfig().Gui.ShowFileTree,
|
||||||
)
|
)
|
||||||
|
|
||||||
getDisplayStrings := func(_ int, _ int) [][]string {
|
getDisplayStrings := func(_ int, _ int) [][]string {
|
||||||
@ -36,7 +36,7 @@ func NewCommitFilesContext(c *ContextCommon) *CommitFilesContext {
|
|||||||
return [][]string{{style.FgRed.Sprint("(none)")}}
|
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)
|
lines := presentation.RenderCommitFileTree(viewModel, c.Git().Patch.PatchBuilder, showFileIcons)
|
||||||
return lo.Map(lines, func(line string, _ int) []string {
|
return lo.Map(lines, func(line string, _ int) []string {
|
||||||
return []string{line}
|
return []string{line}
|
||||||
|
@ -113,19 +113,19 @@ func (self *CommitMessageContext) SetPanelState(
|
|||||||
|
|
||||||
self.c.Views().CommitDescription.Subtitle = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionSubTitle,
|
self.c.Views().CommitDescription.Subtitle = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionSubTitle,
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"togglePanelKeyBinding": keybindings.Label(self.c.UserConfig.Keybinding.Universal.TogglePanel),
|
"togglePanelKeyBinding": keybindings.Label(self.c.UserConfig().Keybinding.Universal.TogglePanel),
|
||||||
"commitMenuKeybinding": keybindings.Label(self.c.UserConfig.Keybinding.CommitMessage.CommitMenu),
|
"commitMenuKeybinding": keybindings.Label(self.c.UserConfig().Keybinding.CommitMessage.CommitMenu),
|
||||||
})
|
})
|
||||||
|
|
||||||
self.c.Views().CommitDescription.Visible = true
|
self.c.Views().CommitDescription.Visible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitMessageContext) RenderCommitLength() {
|
func (self *CommitMessageContext) RenderCommitLength() {
|
||||||
if !self.c.UserConfig.Gui.CommitLength.Show {
|
if self.c.UserConfig().Gui.CommitLength.Show {
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
self.c.Views().CommitMessage.Subtitle = getBufferLength(self.c.Views().CommitMessage)
|
self.c.Views().CommitMessage.Subtitle = getBufferLength(self.c.Views().CommitMessage)
|
||||||
|
} else {
|
||||||
|
self.c.Views().CommitMessage.Subtitle = ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBufferLength(view *gocui.View) string {
|
func getBufferLength(view *gocui.View) string {
|
||||||
|
@ -54,10 +54,10 @@ func NewLocalCommitsContext(c *ContextCommon) *LocalCommitsContext {
|
|||||||
c.Modes().CherryPicking.SelectedHashSet(),
|
c.Modes().CherryPicking.SelectedHashSet(),
|
||||||
c.Modes().Diffing.Ref,
|
c.Modes().Diffing.Ref,
|
||||||
c.Modes().MarkedBaseCommit.GetHash(),
|
c.Modes().MarkedBaseCommit.GetHash(),
|
||||||
c.UserConfig.Gui.TimeFormat,
|
c.UserConfig().Gui.TimeFormat,
|
||||||
c.UserConfig.Gui.ShortTimeFormat,
|
c.UserConfig().Gui.ShortTimeFormat,
|
||||||
time.Now(),
|
time.Now(),
|
||||||
c.UserConfig.Git.ParseEmoji,
|
c.UserConfig().Git.ParseEmoji,
|
||||||
selectedCommitHash,
|
selectedCommitHash,
|
||||||
startIdx,
|
startIdx,
|
||||||
endIdx,
|
endIdx,
|
||||||
@ -110,7 +110,7 @@ func NewLocalCommitsViewModel(getModel func() []*models.Commit, c *ContextCommon
|
|||||||
self := &LocalCommitsViewModel{
|
self := &LocalCommitsViewModel{
|
||||||
ListViewModel: NewListViewModel(getModel),
|
ListViewModel: NewListViewModel(getModel),
|
||||||
limitCommits: true,
|
limitCommits: true,
|
||||||
showWholeGitGraph: c.UserConfig.Git.Log.ShowWholeGraph,
|
showWholeGitGraph: c.UserConfig().Git.Log.ShowWholeGraph,
|
||||||
}
|
}
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
@ -139,7 +139,7 @@ func (self *MenuViewModel) GetNonModelItems() []*NonModelItem {
|
|||||||
// Don't display section headers when we are filtering, and the filter mode
|
// 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
|
// 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.
|
// (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
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,9 +33,9 @@ func NewReflogCommitsContext(c *ContextCommon) *ReflogCommitsContext {
|
|||||||
c.Modes().CherryPicking.SelectedHashSet(),
|
c.Modes().CherryPicking.SelectedHashSet(),
|
||||||
c.Modes().Diffing.Ref,
|
c.Modes().Diffing.Ref,
|
||||||
time.Now(),
|
time.Now(),
|
||||||
c.UserConfig.Gui.TimeFormat,
|
c.UserConfig().Gui.TimeFormat,
|
||||||
c.UserConfig.Gui.ShortTimeFormat,
|
c.UserConfig().Gui.ShortTimeFormat,
|
||||||
c.UserConfig.Git.ParseEmoji,
|
c.UserConfig().Git.ParseEmoji,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ func NewRemotesContext(c *ContextCommon) *RemotesContext {
|
|||||||
|
|
||||||
getDisplayStrings := func(_ int, _ int) [][]string {
|
getDisplayStrings := func(_ int, _ int) [][]string {
|
||||||
return presentation.GetRemoteListDisplayStrings(
|
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{
|
return &RemotesContext{
|
||||||
|
@ -51,7 +51,7 @@ func (self *SearchTrait) onSelectItemWrapper(innerFunc func(int) error) func(int
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *SearchTrait) RenderSearchStatus(index int, total int) {
|
func (self *SearchTrait) RenderSearchStatus(index int, total int) {
|
||||||
keybindingConfig := self.c.UserConfig.Keybinding
|
keybindingConfig := self.c.UserConfig().Keybinding
|
||||||
|
|
||||||
if total == 0 {
|
if total == 0 {
|
||||||
self.c.SetViewContent(
|
self.c.SetViewContent(
|
||||||
|
@ -68,10 +68,10 @@ func NewSubCommitsContext(
|
|||||||
c.Modes().CherryPicking.SelectedHashSet(),
|
c.Modes().CherryPicking.SelectedHashSet(),
|
||||||
c.Modes().Diffing.Ref,
|
c.Modes().Diffing.Ref,
|
||||||
"",
|
"",
|
||||||
c.UserConfig.Gui.TimeFormat,
|
c.UserConfig().Gui.TimeFormat,
|
||||||
c.UserConfig.Gui.ShortTimeFormat,
|
c.UserConfig().Gui.ShortTimeFormat,
|
||||||
time.Now(),
|
time.Now(),
|
||||||
c.UserConfig.Git.ParseEmoji,
|
c.UserConfig().Git.ParseEmoji,
|
||||||
selectedCommitHash,
|
selectedCommitHash,
|
||||||
startIdx,
|
startIdx,
|
||||||
endIdx,
|
endIdx,
|
||||||
|
@ -30,7 +30,7 @@ func NewTagsContext(
|
|||||||
return presentation.GetTagListDisplayStrings(
|
return presentation.GetTagListDisplayStrings(
|
||||||
viewModel.GetItems(),
|
viewModel.GetItems(),
|
||||||
c.State().GetItemOperation,
|
c.State().GetItemOperation,
|
||||||
c.Modes().Diffing.Ref, c.Tr, c.UserConfig)
|
c.Modes().Diffing.Ref, c.Tr, c.UserConfig())
|
||||||
}
|
}
|
||||||
|
|
||||||
return &TagsContext{
|
return &TagsContext{
|
||||||
|
@ -25,11 +25,11 @@ func NewWorkingTreeContext(c *ContextCommon) *WorkingTreeContext {
|
|||||||
viewModel := filetree.NewFileTreeViewModel(
|
viewModel := filetree.NewFileTreeViewModel(
|
||||||
func() []*models.File { return c.Model().Files },
|
func() []*models.File { return c.Model().Files },
|
||||||
c.Log,
|
c.Log,
|
||||||
c.UserConfig.Gui.ShowFileTree,
|
c.UserConfig().Gui.ShowFileTree,
|
||||||
)
|
)
|
||||||
|
|
||||||
getDisplayStrings := func(_ int, _ int) [][]string {
|
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)
|
lines := presentation.RenderFileTree(viewModel, c.Model().Submodules, showFileIcons)
|
||||||
return lo.Map(lines, func(line string, _ int) []string {
|
return lo.Map(lines, func(line string, _ int) []string {
|
||||||
return []string{line}
|
return []string{line}
|
||||||
|
@ -311,8 +311,8 @@ func (self *BasicCommitsController) canCopyCommits(selectedCommits []*models.Com
|
|||||||
func (self *BasicCommitsController) handleOldCherryPickKey() error {
|
func (self *BasicCommitsController) handleOldCherryPickKey() error {
|
||||||
msg := utils.ResolvePlaceholderString(self.c.Tr.OldCherryPickKeyWarning,
|
msg := utils.ResolvePlaceholderString(self.c.Tr.OldCherryPickKeyWarning,
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"copy": keybindings.Label(self.c.UserConfig.Keybinding.Commits.CherryPickCopy),
|
"copy": keybindings.Label(self.c.UserConfig().Keybinding.Commits.CherryPickCopy),
|
||||||
"paste": keybindings.Label(self.c.UserConfig.Keybinding.Commits.PasteCommits),
|
"paste": keybindings.Label(self.c.UserConfig().Keybinding.Commits.PasteCommits),
|
||||||
})
|
})
|
||||||
|
|
||||||
return errors.New(msg)
|
return errors.New(msg)
|
||||||
|
@ -118,8 +118,8 @@ func (self *CommitMessageController) setCommitMessageAtIndex(index int) (bool, e
|
|||||||
}
|
}
|
||||||
return false, errors.New(self.c.Tr.CommitWithoutMessageErr)
|
return false, errors.New(self.c.Tr.CommitWithoutMessageErr)
|
||||||
}
|
}
|
||||||
if self.c.UserConfig.Git.Commit.AutoWrapCommitMessage {
|
if self.c.UserConfig().Git.Commit.AutoWrapCommitMessage {
|
||||||
commitMessage = helpers.TryRemoveHardLineBreaks(commitMessage, self.c.UserConfig.Git.Commit.AutoWrapWidth)
|
commitMessage = helpers.TryRemoveHardLineBreaks(commitMessage, self.c.UserConfig().Git.Commit.AutoWrapWidth)
|
||||||
}
|
}
|
||||||
self.c.Helpers().Commits.UpdateCommitPanelView(commitMessage)
|
self.c.Helpers().Commits.UpdateCommitPanelView(commitMessage)
|
||||||
return true, nil
|
return true, nil
|
||||||
|
@ -46,7 +46,7 @@ func (self *ConfirmationController) GetKeybindings(opts types.KeybindingsOpts) [
|
|||||||
// We assume that whenever things are deletable, they
|
// We assume that whenever things are deletable, they
|
||||||
// are also editable, so we show both keybindings
|
// are also editable, so we show both keybindings
|
||||||
subtitle = fmt.Sprintf(self.c.Tr.SuggestionsSubtitle,
|
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
|
self.c.Views().Suggestions.Subtitle = subtitle
|
||||||
return self.c.Context().Replace(self.c.Contexts().Suggestions)
|
return self.c.Context().Replace(self.c.Contexts().Suggestions)
|
||||||
|
@ -258,7 +258,7 @@ func (self *FilesController) GetOnRenderToMain() func() error {
|
|||||||
pair = self.c.MainViewPairs().Staging
|
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()
|
mainShowsStaged := !split && node.GetHasStagedChanges()
|
||||||
|
|
||||||
cmdObj := self.c.Git().WorkingTree.WorktreeFileDiffCmdObj(node, false, mainShowsStaged)
|
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}})
|
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(
|
Tooltip: utils.ResolvePlaceholderString(
|
||||||
self.c.Tr.DiscardAllTooltip,
|
self.c.Tr.DiscardAllTooltip,
|
||||||
map[string]string{
|
map[string]string{
|
||||||
|
@ -81,16 +81,16 @@ func (self *AppStatusHelper) HasStatus() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *AppStatusHelper) GetStatusString() string {
|
func (self *AppStatusHelper) GetStatusString() string {
|
||||||
appStatus, _ := self.statusMgr().GetStatusString(self.c.UserConfig)
|
appStatus, _ := self.statusMgr().GetStatusString(self.c.UserConfig())
|
||||||
return appStatus
|
return appStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *AppStatusHelper) renderAppStatus() {
|
func (self *AppStatusHelper) renderAppStatus() {
|
||||||
self.c.OnWorker(func(_ gocui.Task) error {
|
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()
|
defer ticker.Stop()
|
||||||
for range ticker.C {
|
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.Views().AppStatus.FgColor = color
|
||||||
self.c.OnUIThread(func() error {
|
self.c.OnUIThread(func() error {
|
||||||
self.c.SetViewContent(self.c.Views().AppStatus, appStatus)
|
self.c.SetViewContent(self.c.Views().AppStatus, appStatus)
|
||||||
@ -124,7 +124,7 @@ func (self *AppStatusHelper) renderAppStatusSync(stop chan struct{}) {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
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.Views().AppStatus.FgColor = color
|
||||||
self.c.SetViewContent(self.c.Views().AppStatus, appStatus)
|
self.c.SetViewContent(self.c.Views().AppStatus, appStatus)
|
||||||
// Redraw all views of the bottom line:
|
// Redraw all views of the bottom line:
|
||||||
|
@ -173,7 +173,7 @@ func (self *ConfirmationHelper) prepareConfirmationPanel(
|
|||||||
suggestionsView.FgColor = theme.GocuiDefaultTextColor
|
suggestionsView.FgColor = theme.GocuiDefaultTextColor
|
||||||
suggestionsContext.SetSuggestions(opts.FindSuggestionsFunc(""))
|
suggestionsContext.SetSuggestions(opts.FindSuggestionsFunc(""))
|
||||||
suggestionsView.Visible = true
|
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 = ""
|
suggestionsView.Subtitle = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ func (self *GpgHelper) runAndStream(cmdObj oscommands.ICmdObj, waitingStatus str
|
|||||||
if err := cmdObj.StreamOutput().Run(); err != nil {
|
if err := cmdObj.StreamOutput().Run(); err != nil {
|
||||||
_ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
_ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
self.c.Tr.GitCommandFailed, self.c.UserConfig.Keybinding.Universal.ExtrasMenu,
|
self.c.Tr.GitCommandFailed, self.c.UserConfig().Keybinding.Universal.ExtrasMenu,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +46,6 @@ func (self *HostHelper) getHostingServiceMgr() (*hosting_service.HostingServiceM
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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
|
return hosting_service.NewHostingServiceMgr(self.c.Log, self.c.Tr, remoteUrl, configServices), nil
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ func (self *InlineStatusHelper) start(opts InlineStatusOpts) {
|
|||||||
self.contextsWithInlineStatus[opts.ContextKey] = info
|
self.contextsWithInlineStatus[opts.ContextKey] = info
|
||||||
|
|
||||||
go utils.Safe(func() {
|
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()
|
defer ticker.Stop()
|
||||||
outer:
|
outer:
|
||||||
for {
|
for {
|
||||||
|
@ -112,7 +112,7 @@ func (self *MergeAndRebaseHelper) genericMergeCommand(command string) error {
|
|||||||
// we should end up with a command like 'git merge --continue'
|
// 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
|
// 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
|
// 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
|
// tasks whose output the user will want to see in the terminal
|
||||||
(status == enums.REBASE_MODE_REBASING && command != REBASE_OPTION_ABORT && self.hasExecTodos())
|
(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 {
|
if err = self.CheckMergeOrRebase(err); err != nil {
|
||||||
return err
|
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,
|
"selectedRef": refName,
|
||||||
"currentBranch": checkedOutBranchName,
|
"currentBranch": checkedOutBranchName,
|
||||||
})
|
})
|
||||||
|
@ -737,7 +737,7 @@ func (self *RefreshHelper) refreshStatus() {
|
|||||||
|
|
||||||
repoName := self.c.Git().RepoPaths.RepoName()
|
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)
|
self.c.SetViewContent(self.c.Views().Status, status)
|
||||||
}
|
}
|
||||||
|
@ -275,7 +275,7 @@ func (self *RefsHelper) NewBranch(from string, fromFormattedName string, suggest
|
|||||||
)
|
)
|
||||||
|
|
||||||
if suggestedBranchName == "" {
|
if suggestedBranchName == "" {
|
||||||
suggestedBranchName = self.c.UserConfig.Git.BranchPrefix
|
suggestedBranchName = self.c.UserConfig().Git.BranchPrefix
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.c.Prompt(types.PromptOpts{
|
return self.c.Prompt(types.PromptOpts{
|
||||||
|
@ -76,7 +76,7 @@ func (self *SearchHelper) DisplayFilterStatus(context types.IFilterableContext)
|
|||||||
self.searchPrefixView().SetContent(self.c.Tr.FilterPrefix)
|
self.searchPrefixView().SetContent(self.c.Tr.FilterPrefix)
|
||||||
|
|
||||||
promptView := self.promptView()
|
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)))
|
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:
|
case types.IFilterableContext:
|
||||||
context.SetSelection(0)
|
context.SetSelection(0)
|
||||||
_ = context.GetView().SetOriginY(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)
|
_ = self.c.PostRefreshUpdate(context)
|
||||||
case types.ISearchableContext:
|
case types.ISearchableContext:
|
||||||
// do nothing
|
// do nothing
|
||||||
@ -246,7 +246,7 @@ func (self *SearchHelper) ReApplyFilter(context types.Context) {
|
|||||||
filterableContext.SetSelection(0)
|
filterableContext.SetSelection(0)
|
||||||
_ = filterableContext.GetView().SetOriginY(0)
|
_ = filterableContext.GetView().SetOriginY(0)
|
||||||
}
|
}
|
||||||
filterableContext.ReApplyFilter(self.c.UserConfig.Gui.UseFuzzySearch())
|
filterableContext.ReApplyFilter(self.c.UserConfig().Gui.UseFuzzySearch())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ func matchesToSuggestions(matches []string) []*types.Suggestion {
|
|||||||
func (self *SuggestionsHelper) GetRemoteSuggestionsFunc() func(string) []*types.Suggestion {
|
func (self *SuggestionsHelper) GetRemoteSuggestionsFunc() func(string) []*types.Suggestion {
|
||||||
remoteNames := self.getRemoteNames()
|
remoteNames := self.getRemoteNames()
|
||||||
|
|
||||||
return FilterFunc(remoteNames, self.c.UserConfig.Gui.UseFuzzySearch())
|
return FilterFunc(remoteNames, self.c.UserConfig().Gui.UseFuzzySearch())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SuggestionsHelper) getBranchNames() []string {
|
func (self *SuggestionsHelper) getBranchNames() []string {
|
||||||
@ -83,7 +83,7 @@ func (self *SuggestionsHelper) GetBranchNameSuggestionsFunc() func(string) []*ty
|
|||||||
if input == "" {
|
if input == "" {
|
||||||
matchingBranchNames = branchNames
|
matchingBranchNames = branchNames
|
||||||
} else {
|
} 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 {
|
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 {
|
return func(input string) []*types.Suggestion {
|
||||||
matchingNames := []string{}
|
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 {
|
_ = self.c.Model().FilesTrie.VisitFuzzy(patricia.Prefix(input), true, func(prefix patricia.Prefix, item patricia.Item, skipped int) error {
|
||||||
matchingNames = append(matchingNames, item.(string))
|
matchingNames = append(matchingNames, item.(string))
|
||||||
return nil
|
return nil
|
||||||
@ -163,7 +163,7 @@ func (self *SuggestionsHelper) getRemoteBranchNames(separator string) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *SuggestionsHelper) GetRemoteBranchesSuggestionsFunc(separator string) func(string) []*types.Suggestion {
|
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 {
|
func (self *SuggestionsHelper) getTagNames() []string {
|
||||||
@ -175,7 +175,7 @@ func (self *SuggestionsHelper) getTagNames() []string {
|
|||||||
func (self *SuggestionsHelper) GetTagsSuggestionsFunc() func(string) []*types.Suggestion {
|
func (self *SuggestionsHelper) GetTagsSuggestionsFunc() func(string) []*types.Suggestion {
|
||||||
tagNames := self.getTagNames()
|
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 {
|
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...)
|
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 {
|
func (self *SuggestionsHelper) GetAuthorsSuggestionsFunc() func(string) []*types.Suggestion {
|
||||||
@ -196,7 +196,7 @@ func (self *SuggestionsHelper) GetAuthorsSuggestionsFunc() func(string) []*types
|
|||||||
|
|
||||||
slices.Sort(authors)
|
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 {
|
func FilterFunc(options []string, useFuzzySearch bool) func(string) []*types.Suggestion {
|
||||||
|
@ -48,8 +48,8 @@ func (self *TagsHelper) OpenCreateTagPrompt(ref string, onCreate func()) error {
|
|||||||
self.c.Tr.ForceTagPrompt,
|
self.c.Tr.ForceTagPrompt,
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"tagName": tagName,
|
"tagName": tagName,
|
||||||
"cancelKey": self.c.UserConfig.Keybinding.Universal.Return,
|
"cancelKey": self.c.UserConfig().Keybinding.Universal.Return,
|
||||||
"confirmKey": self.c.UserConfig.Keybinding.Universal.Confirm,
|
"confirmKey": self.c.UserConfig().Keybinding.Universal.Confirm,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return self.c.Confirm(types.ConfirmOpts{
|
return self.c.Confirm(types.ConfirmOpts{
|
||||||
|
@ -31,7 +31,7 @@ func (self *UpdateHelper) CheckForUpdateInBackground() {
|
|||||||
if newVersion == "" {
|
if newVersion == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if self.c.UserConfig.Update.Method == "background" {
|
if self.c.UserConfig().Update.Method == "background" {
|
||||||
self.startUpdating(newVersion)
|
self.startUpdating(newVersion)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ func (self *WindowArrangementHelper) GetWindowDimensions(informationStr string,
|
|||||||
args := WindowArrangementArgs{
|
args := WindowArrangementArgs{
|
||||||
Width: width,
|
Width: width,
|
||||||
Height: height,
|
Height: height,
|
||||||
UserConfig: self.c.UserConfig,
|
UserConfig: self.c.UserConfig(),
|
||||||
CurrentWindow: self.windowHelper.CurrentWindow(),
|
CurrentWindow: self.windowHelper.CurrentWindow(),
|
||||||
CurrentSideWindow: self.c.Context().CurrentSide().GetWindowName(),
|
CurrentSideWindow: self.c.Context().CurrentSide().GetWindowName(),
|
||||||
CurrentStaticWindow: self.c.Context().CurrentStatic().GetWindowName(),
|
CurrentStaticWindow: self.c.Context().CurrentStatic().GetWindowName(),
|
||||||
|
@ -136,7 +136,7 @@ func (self *WorkingTreeHelper) HandleCommitEditorPress() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *WorkingTreeHelper) HandleWIPCommitPress() error {
|
func (self *WorkingTreeHelper) HandleWIPCommitPress() error {
|
||||||
skipHookPrefix := self.c.UserConfig.Git.SkipHookPrefix
|
skipHookPrefix := self.c.UserConfig().Git.SkipHookPrefix
|
||||||
if skipHookPrefix == "" {
|
if skipHookPrefix == "" {
|
||||||
return errors.New(self.c.Tr.SkipHookPrefixNotConfigured)
|
return errors.New(self.c.Tr.SkipHookPrefixNotConfigured)
|
||||||
}
|
}
|
||||||
@ -209,7 +209,7 @@ func (self *WorkingTreeHelper) syncRefresh() error {
|
|||||||
|
|
||||||
func (self *WorkingTreeHelper) prepareFilesForCommit() error {
|
func (self *WorkingTreeHelper) prepareFilesForCommit() error {
|
||||||
noStagedFiles := !self.AnyStagedFiles()
|
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)
|
self.c.LogAction(self.c.Tr.Actions.StageAllFiles)
|
||||||
err := self.c.Git().WorkingTree.StageAll()
|
err := self.c.Git().WorkingTree.StageAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -223,10 +223,10 @@ func (self *WorkingTreeHelper) prepareFilesForCommit() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *WorkingTreeHelper) commitPrefixConfigForRepo() *config.CommitPrefixConfig {
|
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 {
|
if ok {
|
||||||
return &cfg
|
return &cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.c.UserConfig.Git.CommitPrefix
|
return self.c.UserConfig().Git.CommitPrefix
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ func (self *ListController) HandleScrollRight() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *ListController) HandleScrollUp() error {
|
func (self *ListController) HandleScrollUp() error {
|
||||||
scrollHeight := self.c.UserConfig.Gui.ScrollHeight
|
scrollHeight := self.c.UserConfig().Gui.ScrollHeight
|
||||||
self.context.GetViewTrait().ScrollUp(scrollHeight)
|
self.context.GetViewTrait().ScrollUp(scrollHeight)
|
||||||
if self.context.RenderOnlyVisibleLines() {
|
if self.context.RenderOnlyVisibleLines() {
|
||||||
return self.context.HandleRender()
|
return self.context.HandleRender()
|
||||||
@ -61,7 +61,7 @@ func (self *ListController) HandleScrollUp() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *ListController) HandleScrollDown() error {
|
func (self *ListController) HandleScrollDown() error {
|
||||||
scrollHeight := self.c.UserConfig.Gui.ScrollHeight
|
scrollHeight := self.c.UserConfig().Gui.ScrollHeight
|
||||||
self.context.GetViewTrait().ScrollDown(scrollHeight)
|
self.context.GetViewTrait().ScrollDown(scrollHeight)
|
||||||
if self.context.RenderOnlyVisibleLines() {
|
if self.context.RenderOnlyVisibleLines() {
|
||||||
return self.context.HandleRender()
|
return self.context.HandleRender()
|
||||||
@ -106,10 +106,10 @@ func (self *ListController) handleLineChangeAux(f func(int), change int) error {
|
|||||||
cursorMoved := before != after
|
cursorMoved := before != after
|
||||||
if cursorMoved {
|
if cursorMoved {
|
||||||
if change == -1 {
|
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))
|
self.context.ModelIndexToViewIndex(before), self.context.ModelIndexToViewIndex(after))
|
||||||
} else if change == 1 {
|
} 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))
|
self.context.ModelIndexToViewIndex(before), self.context.ModelIndexToViewIndex(after))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -357,8 +357,8 @@ func (self *LocalCommitsController) reword(commit *models.Commit) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if self.c.UserConfig.Git.Commit.AutoWrapCommitMessage {
|
if self.c.UserConfig().Git.Commit.AutoWrapCommitMessage {
|
||||||
commitMessage = helpers.TryRemoveHardLineBreaks(commitMessage, self.c.UserConfig.Git.Commit.AutoWrapWidth)
|
commitMessage = helpers.TryRemoveHardLineBreaks(commitMessage, self.c.UserConfig().Git.Commit.AutoWrapWidth)
|
||||||
}
|
}
|
||||||
return self.c.Helpers().Commits.OpenCommitMessagePanel(
|
return self.c.Helpers().Commits.OpenCommitMessagePanel(
|
||||||
&helpers.OpenCommitMessagePanelOpts{
|
&helpers.OpenCommitMessagePanelOpts{
|
||||||
@ -438,7 +438,7 @@ func (self *LocalCommitsController) doRewordEditor() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) rewordEditor(commit *models.Commit) error {
|
func (self *LocalCommitsController) rewordEditor(commit *models.Commit) error {
|
||||||
if self.c.UserConfig.Gui.SkipRewordInEditorWarning {
|
if self.c.UserConfig().Gui.SkipRewordInEditorWarning {
|
||||||
return self.doRewordEditor()
|
return self.doRewordEditor()
|
||||||
} else {
|
} else {
|
||||||
return self.c.Confirm(types.ConfirmOpts{
|
return self.c.Confirm(types.ConfirmOpts{
|
||||||
@ -564,7 +564,7 @@ func (self *LocalCommitsController) findCommitForQuickStartInteractiveRebase() (
|
|||||||
|
|
||||||
if !ok || index == 0 {
|
if !ok || index == 0 {
|
||||||
errorMsg := utils.ResolvePlaceholderString(self.c.Tr.CannotQuickStartInteractiveRebase, map[string]string{
|
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)
|
return nil, errors.New(errorMsg)
|
||||||
@ -905,8 +905,8 @@ func (self *LocalCommitsController) createAmendCommit(commit *models.Commit, inc
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if self.c.UserConfig.Git.Commit.AutoWrapCommitMessage {
|
if self.c.UserConfig().Git.Commit.AutoWrapCommitMessage {
|
||||||
commitMessage = helpers.TryRemoveHardLineBreaks(commitMessage, self.c.UserConfig.Git.Commit.AutoWrapWidth)
|
commitMessage = helpers.TryRemoveHardLineBreaks(commitMessage, self.c.UserConfig().Git.Commit.AutoWrapWidth)
|
||||||
}
|
}
|
||||||
originalSubject, _, _ := strings.Cut(commitMessage, "\n")
|
originalSubject, _, _ := strings.Cut(commitMessage, "\n")
|
||||||
return self.c.Helpers().Commits.OpenCommitMessagePanel(
|
return self.c.Helpers().Commits.OpenCommitMessagePanel(
|
||||||
|
@ -173,14 +173,14 @@ func (self *MergeConflictsController) GetOnFocusLost() func(types.OnFocusLostOpt
|
|||||||
|
|
||||||
func (self *MergeConflictsController) HandleScrollUp() error {
|
func (self *MergeConflictsController) HandleScrollUp() error {
|
||||||
self.context().SetUserScrolling(true)
|
self.context().SetUserScrolling(true)
|
||||||
self.context().GetViewTrait().ScrollUp(self.c.UserConfig.Gui.ScrollHeight)
|
self.context().GetViewTrait().ScrollUp(self.c.UserConfig().Gui.ScrollHeight)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *MergeConflictsController) HandleScrollDown() error {
|
func (self *MergeConflictsController) HandleScrollDown() error {
|
||||||
self.context().SetUserScrolling(true)
|
self.context().SetUserScrolling(true)
|
||||||
self.context().GetViewTrait().ScrollDown(self.c.UserConfig.Gui.ScrollHeight)
|
self.context().GetViewTrait().ScrollDown(self.c.UserConfig().Gui.ScrollHeight)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -173,7 +173,7 @@ func (self *PatchExplorerController) HandlePrevLine() error {
|
|||||||
after := self.context.GetState().GetSelectedLineIdx()
|
after := self.context.GetState().GetSelectedLineIdx()
|
||||||
|
|
||||||
if self.context.GetState().SelectingLine() {
|
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
|
return nil
|
||||||
@ -185,7 +185,7 @@ func (self *PatchExplorerController) HandleNextLine() error {
|
|||||||
after := self.context.GetState().GetSelectedLineIdx()
|
after := self.context.GetState().GetSelectedLineIdx()
|
||||||
|
|
||||||
if self.context.GetState().SelectingLine() {
|
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
|
return nil
|
||||||
|
@ -25,7 +25,7 @@ func (self *QuitActions) quitAux() error {
|
|||||||
return self.confirmQuitDuringUpdate()
|
return self.confirmQuitDuringUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.c.UserConfig.ConfirmOnQuit {
|
if self.c.UserConfig().ConfirmOnQuit {
|
||||||
return self.c.Confirm(types.ConfirmOpts{
|
return self.c.Confirm(types.ConfirmOpts{
|
||||||
Title: "",
|
Title: "",
|
||||||
Prompt: self.c.Tr.ConfirmQuit,
|
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)
|
return self.c.Helpers().Repos.DispatchSwitchToRepo(repoPathStack.Pop(), context.NO_CONTEXT)
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.c.UserConfig.QuitOnTopLevelReturn {
|
if self.c.UserConfig().QuitOnTopLevelReturn {
|
||||||
return self.Quit()
|
return self.Quit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ func (self *ShellCommandAction) GetShellCommandsHistorySuggestionsFunc() func(st
|
|||||||
return func(input string) []*types.Suggestion {
|
return func(input string) []*types.Suggestion {
|
||||||
history := self.c.GetAppState().ShellCommandsHistory
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ func (self *StagingController) ToggleStaged() error {
|
|||||||
func (self *StagingController) DiscardSelection() error {
|
func (self *StagingController) DiscardSelection() error {
|
||||||
reset := func() error { return self.applySelectionAndRefresh(true) }
|
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{
|
return self.c.Confirm(types.ConfirmOpts{
|
||||||
Title: self.c.Tr.DiscardChangeTitle,
|
Title: self.c.Tr.DiscardChangeTitle,
|
||||||
Prompt: self.c.Tr.DiscardChangePrompt,
|
Prompt: self.c.Tr.DiscardChangePrompt,
|
||||||
|
@ -114,7 +114,7 @@ func (self *StashController) handleStashApply(stashEntry *models.StashEntry) err
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.c.UserConfig.Gui.SkipStashWarning {
|
if self.c.UserConfig().Gui.SkipStashWarning {
|
||||||
return apply()
|
return apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ func (self *StashController) handleStashPop(stashEntry *models.StashEntry) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.c.UserConfig.Gui.SkipStashWarning {
|
if self.c.UserConfig().Gui.SkipStashWarning {
|
||||||
return pop()
|
return pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,15 +89,15 @@ func (self *StatusController) onClickMain(opts gocui.ViewMouseBindingOpts) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *StatusController) GetOnRenderToMain() func() error {
|
func (self *StatusController) GetOnRenderToMain() func() error {
|
||||||
config := self.c.UserConfig.Gui
|
return func() error {
|
||||||
|
switch self.c.UserConfig().Gui.StatusPanelView {
|
||||||
switch config.StatusPanelView {
|
|
||||||
case "dashboard":
|
case "dashboard":
|
||||||
return self.showDashboard
|
return self.showDashboard()
|
||||||
case "allBranchesLog":
|
case "allBranchesLog":
|
||||||
return self.showAllBranchLogs
|
return self.showAllBranchLogs()
|
||||||
default:
|
default:
|
||||||
return self.showDashboard
|
return self.showDashboard()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ func (self *StatusController) onClick(opts gocui.ViewMouseBindingOpts) error {
|
|||||||
return err
|
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()
|
repoName := self.c.Git().RepoPaths.RepoName()
|
||||||
workingTreeState := self.c.Git().Status.WorkingTreeState()
|
workingTreeState := self.c.Git().Status.WorkingTreeState()
|
||||||
switch workingTreeState {
|
switch workingTreeState {
|
||||||
|
@ -210,7 +210,7 @@ func (self *SyncController) pushAux(currentBranch *models.Branch, opts pushOpts)
|
|||||||
return errors.New(self.c.Tr.UpdatesRejected)
|
return errors.New(self.c.Tr.UpdatesRejected)
|
||||||
}
|
}
|
||||||
|
|
||||||
forcePushDisabled := self.c.UserConfig.Git.DisableForcePushing
|
forcePushDisabled := self.c.UserConfig().Git.DisableForcePushing
|
||||||
if forcePushDisabled {
|
if forcePushDisabled {
|
||||||
return errors.New(self.c.Tr.UpdatesRejectedAndForcePushDisabled)
|
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 {
|
func (self *SyncController) requestToForcePush(currentBranch *models.Branch, opts pushOpts) error {
|
||||||
forcePushDisabled := self.c.UserConfig.Git.DisableForcePushing
|
forcePushDisabled := self.c.UserConfig().Git.DisableForcePushing
|
||||||
if forcePushDisabled {
|
if forcePushDisabled {
|
||||||
return errors.New(self.c.Tr.ForcePushDisabled)
|
return errors.New(self.c.Tr.ForcePushDisabled)
|
||||||
}
|
}
|
||||||
@ -252,8 +252,8 @@ func (self *SyncController) forcePushPrompt() string {
|
|||||||
return utils.ResolvePlaceholderString(
|
return utils.ResolvePlaceholderString(
|
||||||
self.c.Tr.ForcePushPrompt,
|
self.c.Tr.ForcePushPrompt,
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"cancelKey": self.c.UserConfig.Keybinding.Universal.Return,
|
"cancelKey": self.c.UserConfig().Keybinding.Universal.Return,
|
||||||
"confirmKey": self.c.UserConfig.Keybinding.Universal.Confirm,
|
"confirmKey": self.c.UserConfig().Keybinding.Universal.Confirm,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -65,13 +65,13 @@ func (self *VerticalScrollController) GetMouseKeybindings(opts types.Keybindings
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *VerticalScrollController) HandleScrollUp() error {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VerticalScrollController) HandleScrollDown() error {
|
func (self *VerticalScrollController) HandleScrollDown() error {
|
||||||
scrollHeight := self.c.UserConfig.Gui.ScrollHeight
|
scrollHeight := self.c.UserConfig().Gui.ScrollHeight
|
||||||
self.context.GetViewTrait().ScrollDown(scrollHeight)
|
self.context.GetViewTrait().ScrollDown(scrollHeight)
|
||||||
|
|
||||||
if manager, ok := (*self.viewBufferManagerMap)[self.context.GetViewName()]; ok {
|
if manager, ok := (*self.viewBufferManagerMap)[self.context.GetViewName()]; ok {
|
||||||
|
@ -35,7 +35,7 @@ func (self *FilesController) createResetMenu() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.c.UserConfig.Gui.AnimateExplosion {
|
if self.c.UserConfig().Gui.AnimateExplosion {
|
||||||
self.animateExplosion()
|
self.animateExplosion()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,11 +13,11 @@ import (
|
|||||||
const HORIZONTAL_SCROLL_FACTOR = 3
|
const HORIZONTAL_SCROLL_FACTOR = 3
|
||||||
|
|
||||||
func (gui *Gui) scrollUpView(view *gocui.View) {
|
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) {
|
func (gui *Gui) scrollDownView(view *gocui.View) {
|
||||||
scrollHeight := gui.c.UserConfig.Gui.ScrollHeight
|
scrollHeight := gui.c.UserConfig().Gui.ScrollHeight
|
||||||
view.ScrollDown(scrollHeight)
|
view.ScrollDown(scrollHeight)
|
||||||
|
|
||||||
if manager, ok := gui.viewBufferManagerMap[view.Name()]; ok {
|
if manager, ok := gui.viewBufferManagerMap[view.Name()]; ok {
|
||||||
@ -123,7 +123,7 @@ func (gui *Gui) handleCopySelectedSideContextItemToClipboard() error {
|
|||||||
|
|
||||||
func (gui *Gui) handleCopySelectedSideContextItemCommitHashToClipboard() error {
|
func (gui *Gui) handleCopySelectedSideContextItemCommitHashToClipboard() error {
|
||||||
return gui.handleCopySelectedSideContextItemToClipboardWithTruncation(
|
return gui.handleCopySelectedSideContextItemToClipboardWithTruncation(
|
||||||
gui.UserConfig.Git.TruncateCopiedCommitHashesTo)
|
gui.UserConfig().Git.TruncateCopiedCommitHashesTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleCopySelectedSideContextItemToClipboardWithTruncation(maxWidth int) error {
|
func (gui *Gui) handleCopySelectedSideContextItemToClipboardWithTruncation(maxWidth int) error {
|
||||||
|
194
pkg/gui/gui.go
194
pkg/gui/gui.go
@ -5,6 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -35,6 +37,7 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/gui/status"
|
"github.com/jesseduffield/lazygit/pkg/gui/status"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||||
"github.com/jesseduffield/lazygit/pkg/integration/components"
|
"github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types"
|
integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/tasks"
|
"github.com/jesseduffield/lazygit/pkg/tasks"
|
||||||
@ -137,6 +140,8 @@ type Gui struct {
|
|||||||
c *helpers.HelperCommon
|
c *helpers.HelperCommon
|
||||||
helpers *helpers.Helpers
|
helpers *helpers.Helpers
|
||||||
|
|
||||||
|
previousLanguageConfig string
|
||||||
|
|
||||||
integrationTest integrationTypes.IntegrationTest
|
integrationTest integrationTypes.IntegrationTest
|
||||||
|
|
||||||
afterLayoutFuncs chan func() error
|
afterLayoutFuncs chan func() error
|
||||||
@ -307,6 +312,16 @@ func (gui *Gui) onNewRepo(startArgs appTypes.StartArgs, contextKey types.Context
|
|||||||
return err
|
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)
|
contextToPush := gui.resetState(startArgs)
|
||||||
|
|
||||||
gui.resetHelpersAndControllers()
|
gui.resetHelpersAndControllers()
|
||||||
@ -317,8 +332,28 @@ func (gui *Gui) onNewRepo(startArgs appTypes.StartArgs, contextKey types.Context
|
|||||||
|
|
||||||
gui.g.SetFocusHandler(func(Focused bool) error {
|
gui.g.SetFocusHandler(func(Focused bool) error {
|
||||||
if Focused {
|
if Focused {
|
||||||
|
oldConfig := gui.Config.GetUserConfig()
|
||||||
|
reloadErr, didChange := gui.Config.ReloadChangedUserConfigFiles()
|
||||||
|
if didChange && reloadErr == nil {
|
||||||
|
gui.c.Log.Info("User config changed - reloading")
|
||||||
|
reloadErr = gui.onUserConfigLoaded()
|
||||||
|
if err := gui.resetKeybindings(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := gui.checkForChangedConfigsThatDontAutoReload(oldConfig, gui.Config.GetUserConfig()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gui.c.Log.Info("Receiving focus - refreshing")
|
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
|
return nil
|
||||||
@ -342,6 +377,119 @@ func (gui *Gui) onNewRepo(startArgs appTypes.StartArgs, contextKey types.Context
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) getPerRepoConfigFiles() []*config.ConfigFile {
|
||||||
|
repoConfigFiles := []*config.ConfigFile{
|
||||||
|
// TODO: add filepath.Join(gui.git.RepoPaths.RepoPath(), ".lazygit.yml"),
|
||||||
|
// with trust prompt
|
||||||
|
{
|
||||||
|
Path: filepath.Join(gui.git.RepoPaths.RepoGitDirPath(), "lazygit.yml"),
|
||||||
|
Policy: config.ConfigFilePolicySkipIfMissing,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
prevDir := gui.c.Git().RepoPaths.RepoPath()
|
||||||
|
dir := filepath.Dir(prevDir)
|
||||||
|
for dir != prevDir {
|
||||||
|
repoConfigFiles = utils.Prepend(repoConfigFiles, &config.ConfigFile{
|
||||||
|
Path: filepath.Join(dir, ".lazygit.yml"),
|
||||||
|
Policy: config.ConfigFilePolicySkipIfMissing,
|
||||||
|
})
|
||||||
|
prevDir = dir
|
||||||
|
dir = filepath.Dir(dir)
|
||||||
|
}
|
||||||
|
return repoConfigFiles
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) onUserConfigLoaded() error {
|
||||||
|
userConfig := gui.Config.GetUserConfig()
|
||||||
|
gui.Common.SetUserConfig(userConfig)
|
||||||
|
|
||||||
|
gui.setColorScheme()
|
||||||
|
gui.configureViewProperties()
|
||||||
|
|
||||||
|
gui.g.SearchEscapeKey = keybindings.GetKey(userConfig.Keybinding.Universal.Return)
|
||||||
|
gui.g.NextSearchMatchKey = keybindings.GetKey(userConfig.Keybinding.Universal.NextMatch)
|
||||||
|
gui.g.PrevSearchMatchKey = keybindings.GetKey(userConfig.Keybinding.Universal.PrevMatch)
|
||||||
|
|
||||||
|
gui.g.ShowListFooter = userConfig.Gui.ShowListFooter
|
||||||
|
|
||||||
|
gui.g.Mouse = userConfig.Gui.MouseEvents
|
||||||
|
|
||||||
|
if gui.previousLanguageConfig != userConfig.Gui.Language {
|
||||||
|
tr, err := i18n.NewTranslationSetFromConfig(gui.Log, userConfig.Gui.Language)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
gui.c.Tr = tr
|
||||||
|
gui.previousLanguageConfig = userConfig.Gui.Language
|
||||||
|
}
|
||||||
|
|
||||||
|
// originally we could only hide the command log permanently via the config
|
||||||
|
// but now we do it via state. So we need to still support the config for the
|
||||||
|
// sake of backwards compatibility. We're making use of short circuiting here
|
||||||
|
gui.ShowExtrasWindow = userConfig.Gui.ShowCommandLog && !gui.c.GetAppState().HideCommandLog
|
||||||
|
|
||||||
|
authors.SetCustomAuthors(userConfig.Gui.AuthorColors)
|
||||||
|
if userConfig.Gui.NerdFontsVersion != "" {
|
||||||
|
icons.SetNerdFontsVersion(userConfig.Gui.NerdFontsVersion)
|
||||||
|
} else if userConfig.Gui.ShowIcons {
|
||||||
|
icons.SetNerdFontsVersion("2")
|
||||||
|
}
|
||||||
|
presentation.SetCustomBranches(userConfig.Gui.BranchColors)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) checkForChangedConfigsThatDontAutoReload(oldConfig *config.UserConfig, newConfig *config.UserConfig) error {
|
||||||
|
configsThatDontAutoReload := []string{
|
||||||
|
"Git.AutoFetch",
|
||||||
|
"Git.AutoRefresh",
|
||||||
|
"Refresher.RefreshInterval",
|
||||||
|
"Refresher.FetchInterval",
|
||||||
|
"Update.Method",
|
||||||
|
"Update.Days",
|
||||||
|
}
|
||||||
|
|
||||||
|
changedConfigs := []string{}
|
||||||
|
for _, config := range configsThatDontAutoReload {
|
||||||
|
old := reflect.ValueOf(oldConfig).Elem()
|
||||||
|
new := reflect.ValueOf(newConfig).Elem()
|
||||||
|
fieldNames := strings.Split(config, ".")
|
||||||
|
userFacingPath := make([]string, 0, len(fieldNames))
|
||||||
|
// navigate to the leaves in old and new config
|
||||||
|
for _, fieldName := range fieldNames {
|
||||||
|
f, _ := old.Type().FieldByName(fieldName)
|
||||||
|
userFacingName := f.Tag.Get("yaml")
|
||||||
|
if userFacingName == "" {
|
||||||
|
userFacingName = fieldName
|
||||||
|
}
|
||||||
|
userFacingPath = append(userFacingPath, userFacingName)
|
||||||
|
old = old.FieldByName(fieldName)
|
||||||
|
new = new.FieldByName(fieldName)
|
||||||
|
}
|
||||||
|
// if the value has changed, ...
|
||||||
|
if !old.Equal(new) {
|
||||||
|
// ... append it to the list of changed configs
|
||||||
|
changedConfigs = append(changedConfigs, strings.Join(userFacingPath, "."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(changedConfigs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
message := utils.ResolvePlaceholderString(
|
||||||
|
gui.c.Tr.NonReloadableConfigWarning,
|
||||||
|
map[string]string{
|
||||||
|
"configs": strings.Join(changedConfigs, "\n"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return gui.c.Confirm(types.ConfirmOpts{
|
||||||
|
Title: gui.c.Tr.NonReloadableConfigWarningTitle,
|
||||||
|
Prompt: message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// resetState reuses the repo state from our repo state map, if the repo was
|
// resetState reuses the repo state from our repo state map, if the repo was
|
||||||
// open before; otherwise it creates a new one.
|
// open before; otherwise it creates a new one.
|
||||||
func (gui *Gui) resetState(startArgs appTypes.StartArgs) types.Context {
|
func (gui *Gui) resetState(startArgs appTypes.StartArgs) types.Context {
|
||||||
@ -379,7 +527,7 @@ func (gui *Gui) resetState(startArgs appTypes.StartArgs) types.Context {
|
|||||||
BisectInfo: git_commands.NewNullBisectInfo(),
|
BisectInfo: git_commands.NewNullBisectInfo(),
|
||||||
FilesTrie: patricia.NewTrie(),
|
FilesTrie: patricia.NewTrie(),
|
||||||
Authors: map[string]*models.Author{},
|
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{
|
Modes: &types.Modes{
|
||||||
Filtering: filtering.New(startArgs.FilterPath, ""),
|
Filtering: filtering.New(startArgs.FilterPath, ""),
|
||||||
@ -478,10 +626,10 @@ func NewGui(
|
|||||||
RepoStateMap: map[Repo]*GuiRepoState{},
|
RepoStateMap: map[Repo]*GuiRepoState{},
|
||||||
GuiLog: []string{},
|
GuiLog: []string{},
|
||||||
|
|
||||||
// originally we could only hide the command log permanently via the config
|
// initializing this to true for the time being; it will be reset to the
|
||||||
// but now we do it via state. So we need to still support the config for the
|
// real value after loading the user config:
|
||||||
// sake of backwards compatibility. We're making use of short circuiting here
|
ShowExtrasWindow: true,
|
||||||
ShowExtrasWindow: cmn.UserConfig.Gui.ShowCommandLog && !config.GetAppState().HideCommandLog,
|
|
||||||
Mutexes: types.Mutexes{
|
Mutexes: types.Mutexes{
|
||||||
RefreshingFilesMutex: &deadlock.Mutex{},
|
RefreshingFilesMutex: &deadlock.Mutex{},
|
||||||
RefreshingBranchesMutex: &deadlock.Mutex{},
|
RefreshingBranchesMutex: &deadlock.Mutex{},
|
||||||
@ -538,14 +686,6 @@ func NewGui(
|
|||||||
// TODO: reset these controllers upon changing repos due to state changing
|
// TODO: reset these controllers upon changing repos due to state changing
|
||||||
gui.c = helperCommon
|
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.BackgroundRoutineMgr = &BackgroundRoutineMgr{gui: gui}
|
||||||
gui.stateAccessor = &StateAccessor{gui: gui}
|
gui.stateAccessor = &StateAccessor{gui: gui}
|
||||||
|
|
||||||
@ -658,25 +798,7 @@ func (gui *Gui) Run(startArgs appTypes.StartArgs) error {
|
|||||||
// breakpoints and stepping through code can easily take more than 30s.
|
// breakpoints and stepping through code can easily take more than 30s.
|
||||||
deadlock.Opts.Disable = !gui.Debug || os.Getenv(components.WAIT_FOR_DEBUGGER_ENV_VAR) != ""
|
deadlock.Opts.Disable = !gui.Debug || os.Getenv(components.WAIT_FOR_DEBUGGER_ENV_VAR) != ""
|
||||||
|
|
||||||
if err := gui.Config.ReloadUserConfig(); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
userConfig := gui.UserConfig
|
|
||||||
|
|
||||||
gui.g.OnSearchEscape = func() error { gui.helpers.Search.Cancel(); return nil }
|
gui.g.OnSearchEscape = func() error { gui.helpers.Search.Cancel(); return nil }
|
||||||
gui.g.SearchEscapeKey = keybindings.GetKey(userConfig.Keybinding.Universal.Return)
|
|
||||||
gui.g.NextSearchMatchKey = keybindings.GetKey(userConfig.Keybinding.Universal.NextMatch)
|
|
||||||
gui.g.PrevSearchMatchKey = keybindings.GetKey(userConfig.Keybinding.Universal.PrevMatch)
|
|
||||||
|
|
||||||
gui.g.ShowListFooter = userConfig.Gui.ShowListFooter
|
|
||||||
|
|
||||||
if userConfig.Gui.MouseEvents {
|
|
||||||
gui.g.Mouse = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := gui.setColorScheme(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
gui.g.SetManager(gocui.ManagerFunc(gui.layout))
|
gui.g.SetManager(gocui.ManagerFunc(gui.layout))
|
||||||
|
|
||||||
@ -735,7 +857,7 @@ func (gui *Gui) RunAndHandleError(startArgs appTypes.StartArgs) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) checkForDeprecatedEditConfigs() {
|
func (gui *Gui) checkForDeprecatedEditConfigs() {
|
||||||
osConfig := &gui.UserConfig.OS
|
osConfig := &gui.UserConfig().OS
|
||||||
deprecatedConfigs := []struct {
|
deprecatedConfigs := []struct {
|
||||||
config string
|
config string
|
||||||
oldName string
|
oldName string
|
||||||
@ -934,16 +1056,14 @@ func (gui *Gui) showBreakingChangesMessage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// setColorScheme sets the color scheme for the app based on the user config
|
// 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
|
userConfig := gui.UserConfig()
|
||||||
theme.UpdateTheme(userConfig.Gui.Theme)
|
theme.UpdateTheme(userConfig.Gui.Theme)
|
||||||
|
|
||||||
gui.g.FgColor = theme.InactiveBorderColor
|
gui.g.FgColor = theme.InactiveBorderColor
|
||||||
gui.g.SelFgColor = theme.ActiveBorderColor
|
gui.g.SelFgColor = theme.ActiveBorderColor
|
||||||
gui.g.FrameColor = theme.InactiveBorderColor
|
gui.g.FrameColor = theme.InactiveBorderColor
|
||||||
gui.g.SelFrameColor = theme.ActiveBorderColor
|
gui.g.SelFrameColor = theme.ActiveBorderColor
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) onUIThread(f func() error) {
|
func (gui *Gui) onUIThread(f func() error) {
|
||||||
|
@ -60,7 +60,7 @@ func (self *Gui) GetCheatsheetKeybindings() []*types.Binding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *Gui) keybindingOpts() types.KeybindingsOpts {
|
func (self *Gui) keybindingOpts() types.KeybindingsOpts {
|
||||||
config := self.c.UserConfig.Keybinding
|
config := self.c.UserConfig().Keybinding
|
||||||
|
|
||||||
guards := types.KeybindingGuards{
|
guards := types.KeybindingGuards{
|
||||||
OutsideFilterMode: self.outsideFilterMode,
|
OutsideFilterMode: self.outsideFilterMode,
|
||||||
|
@ -260,7 +260,7 @@ func (gui *Gui) onRepoViewReset() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) onInitialViewsCreation() error {
|
func (gui *Gui) onInitialViewsCreation() error {
|
||||||
if !gui.c.UserConfig.DisableStartupPopups {
|
if !gui.c.UserConfig().DisableStartupPopups {
|
||||||
storedPopupVersion := gui.c.GetAppState().StartupPopupVersion
|
storedPopupVersion := gui.c.GetAppState().StartupPopupVersion
|
||||||
if storedPopupVersion < StartupPopupVersion {
|
if storedPopupVersion < StartupPopupVersion {
|
||||||
gui.showIntroPopupMessage()
|
gui.showIntroPopupMessage()
|
||||||
|
@ -324,7 +324,7 @@ func Test_getBranchDisplayStrings(t *testing.T) {
|
|||||||
|
|
||||||
for i, s := range scenarios {
|
for i, s := range scenarios {
|
||||||
icons.SetNerdFontsVersion(lo.Ternary(s.useIcons, "3", ""))
|
icons.SetNerdFontsVersion(lo.Ternary(s.useIcons, "3", ""))
|
||||||
c.UserConfig.Gui.ShowDivergenceFromBaseBranch = s.showDivergenceCfg
|
c.UserConfig().Gui.ShowDivergenceFromBaseBranch = s.showDivergenceCfg
|
||||||
|
|
||||||
worktrees := []*models.Worktree{}
|
worktrees := []*models.Worktree{}
|
||||||
if s.checkedOutByWorktree {
|
if s.checkedOutByWorktree {
|
||||||
@ -332,7 +332,7 @@ func Test_getBranchDisplayStrings(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t.Run(fmt.Sprintf("getBranchDisplayStrings_%d", i), func(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)
|
assert.Equal(t, s.expected, strings)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -173,7 +173,7 @@ func GetCommitListDisplayStrings(
|
|||||||
// Don't show a marker for the current branch
|
// Don't show a marker for the current branch
|
||||||
b.Name != currentBranchName &&
|
b.Name != currentBranchName &&
|
||||||
// Don't show a marker for main branches
|
// 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
|
// Don't show a marker for the head commit unless the
|
||||||
// rebase.updateRefs config is on
|
// rebase.updateRefs config is on
|
||||||
(hasRebaseUpdateRefsConfig || b.CommitHash != commits[0].Hash)
|
(hasRebaseUpdateRefsConfig || b.CommitHash != commits[0].Hash)
|
||||||
@ -370,7 +370,7 @@ func displayCommit(
|
|||||||
|
|
||||||
hashString := ""
|
hashString := ""
|
||||||
hashColor := getHashColor(commit, diffName, cherryPickedCommitHashSet, bisectStatus, bisectInfo)
|
hashColor := getHashColor(commit, diffName, cherryPickedCommitHashSet, bisectStatus, bisectInfo)
|
||||||
hashLength := common.UserConfig.Gui.CommitHashLength
|
hashLength := common.UserConfig().Gui.CommitHashLength
|
||||||
if hashLength >= len(commit.Hash) {
|
if hashLength >= len(commit.Hash) {
|
||||||
hashString = hashColor.Sprint(commit.Hash)
|
hashString = hashColor.Sprint(commit.Hash)
|
||||||
} else if hashLength > 0 {
|
} else if hashLength > 0 {
|
||||||
@ -440,9 +440,9 @@ func displayCommit(
|
|||||||
mark = fmt.Sprintf("%s ", willBeRebased)
|
mark = fmt.Sprintf("%s ", willBeRebased)
|
||||||
}
|
}
|
||||||
|
|
||||||
authorLength := common.UserConfig.Gui.CommitAuthorShortLength
|
authorLength := common.UserConfig().Gui.CommitAuthorShortLength
|
||||||
if fullDescription {
|
if fullDescription {
|
||||||
authorLength = common.UserConfig.Gui.CommitAuthorLongLength
|
authorLength = common.UserConfig().Gui.CommitAuthorLongLength
|
||||||
}
|
}
|
||||||
author := authors.AuthorWithLength(commit.AuthorName, authorLength)
|
author := authors.AuthorWithLength(commit.AuthorName, authorLength)
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package custom_commands
|
package custom_commands
|
||||||
|
|
||||||
import (
|
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/controllers/helpers"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"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.
|
// 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.
|
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Custom_Command_Keybindings.md for more info.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
customCommands []config.CustomCommand
|
c *common.Common
|
||||||
handlerCreator *HandlerCreator
|
handlerCreator *HandlerCreator
|
||||||
keybindingCreator *KeybindingCreator
|
keybindingCreator *KeybindingCreator
|
||||||
}
|
}
|
||||||
@ -26,10 +26,9 @@ func NewClient(
|
|||||||
helpers.MergeAndRebase,
|
helpers.MergeAndRebase,
|
||||||
)
|
)
|
||||||
keybindingCreator := NewKeybindingCreator(c)
|
keybindingCreator := NewKeybindingCreator(c)
|
||||||
customCommands := c.UserConfig.CustomCommands
|
|
||||||
|
|
||||||
return &Client{
|
return &Client{
|
||||||
customCommands: customCommands,
|
c: c.Common,
|
||||||
keybindingCreator: keybindingCreator,
|
keybindingCreator: keybindingCreator,
|
||||||
handlerCreator: handlerCreator,
|
handlerCreator: handlerCreator,
|
||||||
}
|
}
|
||||||
@ -37,7 +36,7 @@ func NewClient(
|
|||||||
|
|
||||||
func (self *Client) GetCustomCommandKeybindings() ([]*types.Binding, error) {
|
func (self *Client) GetCustomCommandKeybindings() ([]*types.Binding, error) {
|
||||||
bindings := []*types.Binding{}
|
bindings := []*types.Binding{}
|
||||||
for _, customCommand := range self.customCommands {
|
for _, customCommand := range self.c.UserConfig().CustomCommands {
|
||||||
handler := self.handlerCreator.call(customCommand)
|
handler := self.handlerCreator.call(customCommand)
|
||||||
compoundBindings, err := self.keybindingCreator.call(customCommand, handler)
|
compoundBindings, err := self.keybindingCreator.call(customCommand, handler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -73,26 +73,12 @@ func (gui *Gui) orderedViewNameMappings() []viewNameMapping {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) createAllViews() error {
|
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
|
var err error
|
||||||
for _, mapping := range gui.orderedViewNameMappings() {
|
for _, mapping := range gui.orderedViewNameMappings() {
|
||||||
*mapping.viewPtr, err = gui.prepareView(mapping.name)
|
*mapping.viewPtr, err = gui.prepareView(mapping.name)
|
||||||
if err != nil && !gocui.IsUnknownView(err) {
|
if err != nil && !gocui.IsUnknownView(err) {
|
||||||
return 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
|
gui.Views.Options.Frame = false
|
||||||
@ -131,7 +117,6 @@ func (gui *Gui) createAllViews() error {
|
|||||||
view.Title = gui.c.Tr.DiffTitle
|
view.Title = gui.c.Tr.DiffTitle
|
||||||
view.Wrap = true
|
view.Wrap = true
|
||||||
view.IgnoreCarriageReturns = true
|
view.IgnoreCarriageReturns = true
|
||||||
view.CanScrollPastBottom = gui.c.UserConfig.Gui.ScrollPastBottom
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gui.Views.Staging.Title = gui.c.Tr.UnstagedChanges
|
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.Visible = false
|
||||||
gui.Views.CommitDescription.Title = gui.c.Tr.CommitDescriptionTitle
|
gui.Views.CommitDescription.Title = gui.c.Tr.CommitDescriptionTitle
|
||||||
gui.Views.CommitDescription.FgColor = theme.GocuiDefaultTextColor
|
|
||||||
gui.Views.CommitDescription.Editable = true
|
gui.Views.CommitDescription.Editable = true
|
||||||
gui.Views.CommitDescription.Editor = gocui.EditorFunc(gui.commitDescriptionEditor)
|
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.Visible = false
|
||||||
gui.Views.Confirmation.Editor = gocui.EditorFunc(gui.promptEditor)
|
gui.Views.Confirmation.Editor = gocui.EditorFunc(gui.promptEditor)
|
||||||
@ -192,8 +174,39 @@ func (gui *Gui) createAllViews() error {
|
|||||||
gui.Views.Snake.Title = gui.c.Tr.SnakeTitle
|
gui.Views.Snake.Title = gui.c.Tr.SnakeTitle
|
||||||
gui.Views.Snake.FgColor = gocui.ColorGreen
|
gui.Views.Snake.FgColor = gocui.ColorGreen
|
||||||
|
|
||||||
if gui.c.UserConfig.Gui.ShowPanelJumps {
|
return nil
|
||||||
jumpBindings := gui.c.UserConfig.Keybinding.Universal.JumpToBlock
|
}
|
||||||
|
|
||||||
|
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 {
|
jumpLabels := lo.Map(jumpBindings, func(binding string, _ int) string {
|
||||||
return fmt.Sprintf("[%s]", binding)
|
return fmt.Sprintf("[%s]", binding)
|
||||||
})
|
})
|
||||||
@ -212,7 +225,20 @@ func (gui *Gui) createAllViews() error {
|
|||||||
gui.Views.ReflogCommits.TitlePrefix = jumpLabels[3]
|
gui.Views.ReflogCommits.TitlePrefix = jumpLabels[3]
|
||||||
|
|
||||||
gui.Views.Stash.TitlePrefix = jumpLabels[4]
|
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 = ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -225,6 +225,8 @@ type TranslationSet struct {
|
|||||||
MergeToolPrompt string
|
MergeToolPrompt string
|
||||||
IntroPopupMessage string
|
IntroPopupMessage string
|
||||||
DeprecatedEditConfigWarning string
|
DeprecatedEditConfigWarning string
|
||||||
|
NonReloadableConfigWarningTitle string
|
||||||
|
NonReloadableConfigWarning string
|
||||||
GitconfigParseErr string
|
GitconfigParseErr string
|
||||||
EditFile string
|
EditFile string
|
||||||
EditFileTooltip 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
|
// exporting this so we can use it in tests
|
||||||
func EnglishTranslationSet() *TranslationSet {
|
func EnglishTranslationSet() *TranslationSet {
|
||||||
return &TranslationSet{
|
return &TranslationSet{
|
||||||
@ -1199,6 +1205,8 @@ func EnglishTranslationSet() *TranslationSet {
|
|||||||
MergeToolPrompt: "Are you sure you want to open `git mergetool`?",
|
MergeToolPrompt: "Are you sure you want to open `git mergetool`?",
|
||||||
IntroPopupMessage: englishIntroPopupMessage,
|
IntroPopupMessage: englishIntroPopupMessage,
|
||||||
DeprecatedEditConfigWarning: englishDeprecatedEditConfigWarning,
|
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.`,
|
GitconfigParseErr: `Gogit failed to parse your gitconfig file due to the presence of unquoted '\' characters. Removing these should fix the issue.`,
|
||||||
EditFile: `Edit file`,
|
EditFile: `Edit file`,
|
||||||
EditFileTooltip: "Open file in external editor.",
|
EditFileTooltip: "Open file in external editor.",
|
||||||
|
@ -15,7 +15,7 @@ var Basic = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
CreateNCommits(10)
|
CreateNCommits(10)
|
||||||
},
|
},
|
||||||
SetupConfig: func(cfg *config.AppConfig) {
|
SetupConfig: func(cfg *config.AppConfig) {
|
||||||
cfg.AppState.GitLogShowGraph = "never"
|
cfg.GetAppState().GitLogShowGraph = "never"
|
||||||
},
|
},
|
||||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
markCommitAsBad := func() {
|
markCommitAsBad := func() {
|
||||||
|
@ -15,7 +15,7 @@ var ChooseTerms = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
CreateNCommits(10)
|
CreateNCommits(10)
|
||||||
},
|
},
|
||||||
SetupConfig: func(cfg *config.AppConfig) {
|
SetupConfig: func(cfg *config.AppConfig) {
|
||||||
cfg.AppState.GitLogShowGraph = "never"
|
cfg.GetAppState().GitLogShowGraph = "never"
|
||||||
},
|
},
|
||||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
markCommitAsFixed := func() {
|
markCommitAsFixed := func() {
|
||||||
|
@ -14,7 +14,7 @@ var Skip = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
CreateNCommits(10)
|
CreateNCommits(10)
|
||||||
},
|
},
|
||||||
SetupConfig: func(cfg *config.AppConfig) {
|
SetupConfig: func(cfg *config.AppConfig) {
|
||||||
cfg.AppState.GitLogShowGraph = "never"
|
cfg.GetAppState().GitLogShowGraph = "never"
|
||||||
},
|
},
|
||||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
t.Views().Commits().
|
t.Views().Commits().
|
||||||
|
@ -11,7 +11,7 @@ var RebaseCopiedBranch = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Skip: false,
|
Skip: false,
|
||||||
GitVersion: AtLeast("2.38.0"),
|
GitVersion: AtLeast("2.38.0"),
|
||||||
SetupConfig: func(config *config.AppConfig) {
|
SetupConfig: func(config *config.AppConfig) {
|
||||||
config.AppState.GitLogShowGraph = "never"
|
config.GetAppState().GitLogShowGraph = "never"
|
||||||
},
|
},
|
||||||
SetupRepo: func(shell *Shell) {
|
SetupRepo: func(shell *Shell) {
|
||||||
shell.
|
shell.
|
||||||
|
@ -10,7 +10,7 @@ var RebaseOntoBaseBranch = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
ExtraCmdArgs: []string{},
|
ExtraCmdArgs: []string{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
SetupConfig: func(config *config.AppConfig) {
|
SetupConfig: func(config *config.AppConfig) {
|
||||||
config.UserConfig.Gui.ShowDivergenceFromBaseBranch = "arrowAndNumber"
|
config.GetUserConfig().Gui.ShowDivergenceFromBaseBranch = "arrowAndNumber"
|
||||||
},
|
},
|
||||||
SetupRepo: func(shell *Shell) {
|
SetupRepo: func(shell *Shell) {
|
||||||
shell.
|
shell.
|
||||||
|
@ -10,7 +10,7 @@ var ShowDivergenceFromBaseBranch = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
ExtraCmdArgs: []string{},
|
ExtraCmdArgs: []string{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
SetupConfig: func(config *config.AppConfig) {
|
SetupConfig: func(config *config.AppConfig) {
|
||||||
config.UserConfig.Gui.ShowDivergenceFromBaseBranch = "arrowAndNumber"
|
config.GetUserConfig().Gui.ShowDivergenceFromBaseBranch = "arrowAndNumber"
|
||||||
},
|
},
|
||||||
SetupRepo: func(shell *Shell) {
|
SetupRepo: func(shell *Shell) {
|
||||||
shell.
|
shell.
|
||||||
|
@ -10,7 +10,7 @@ var CherryPickDuringRebase = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
ExtraCmdArgs: []string{},
|
ExtraCmdArgs: []string{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
SetupConfig: func(config *config.AppConfig) {
|
SetupConfig: func(config *config.AppConfig) {
|
||||||
config.AppState.GitLogShowGraph = "never"
|
config.GetAppState().GitLogShowGraph = "never"
|
||||||
},
|
},
|
||||||
SetupRepo: func(shell *Shell) {
|
SetupRepo: func(shell *Shell) {
|
||||||
shell.
|
shell.
|
||||||
|
@ -11,7 +11,7 @@ var AutoWrapMessage = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Skip: false,
|
Skip: false,
|
||||||
SetupConfig: func(config *config.AppConfig) {
|
SetupConfig: func(config *config.AppConfig) {
|
||||||
// Use a ridiculously small width so that we don't have to use so much test data
|
// 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) {
|
SetupRepo: func(shell *Shell) {
|
||||||
shell.CreateFile("file", "file content")
|
shell.CreateFile("file", "file content")
|
||||||
|
@ -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.",
|
Description: "Commit with skip hook and config commitPrefix is defined. Prefix is ignored when creating WIP commits.",
|
||||||
ExtraCmdArgs: []string{},
|
ExtraCmdArgs: []string{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
SetupConfig: func(testConfig *config.AppConfig) {
|
SetupConfig: func(cfg *config.AppConfig) {
|
||||||
testConfig.UserConfig.Git.CommitPrefixes = map[string]config.CommitPrefixConfig{"repo": {Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[$1]: "}}
|
cfg.GetUserConfig().Git.CommitPrefixes = map[string]config.CommitPrefixConfig{"repo": {Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[$1]: "}}
|
||||||
},
|
},
|
||||||
SetupRepo: func(shell *Shell) {
|
SetupRepo: func(shell *Shell) {
|
||||||
shell.NewBranch("feature/TEST-002")
|
shell.NewBranch("feature/TEST-002")
|
||||||
|
@ -9,8 +9,8 @@ var CommitWithGlobalPrefix = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Description: "Commit with defined config commitPrefix",
|
Description: "Commit with defined config commitPrefix",
|
||||||
ExtraCmdArgs: []string{},
|
ExtraCmdArgs: []string{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
SetupConfig: func(testConfig *config.AppConfig) {
|
SetupConfig: func(cfg *config.AppConfig) {
|
||||||
testConfig.UserConfig.Git.CommitPrefix = &config.CommitPrefixConfig{Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[$1]: "}
|
cfg.GetUserConfig().Git.CommitPrefix = &config.CommitPrefixConfig{Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[$1]: "}
|
||||||
},
|
},
|
||||||
SetupRepo: func(shell *Shell) {
|
SetupRepo: func(shell *Shell) {
|
||||||
shell.NewBranch("feature/TEST-001")
|
shell.NewBranch("feature/TEST-001")
|
||||||
|
@ -9,8 +9,8 @@ var CommitWithNonMatchingBranchName = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Description: "Commit with defined config commitPrefixes",
|
Description: "Commit with defined config commitPrefixes",
|
||||||
ExtraCmdArgs: []string{},
|
ExtraCmdArgs: []string{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
SetupConfig: func(testConfig *config.AppConfig) {
|
SetupConfig: func(cfg *config.AppConfig) {
|
||||||
testConfig.UserConfig.Git.CommitPrefix = &config.CommitPrefixConfig{
|
cfg.GetUserConfig().Git.CommitPrefix = &config.CommitPrefixConfig{
|
||||||
Pattern: "^\\w+\\/(\\w+-\\w+).*",
|
Pattern: "^\\w+\\/(\\w+-\\w+).*",
|
||||||
Replace: "[$1]: ",
|
Replace: "[$1]: ",
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@ var CommitWithPrefix = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Description: "Commit with defined config commitPrefixes",
|
Description: "Commit with defined config commitPrefixes",
|
||||||
ExtraCmdArgs: []string{},
|
ExtraCmdArgs: []string{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
SetupConfig: func(testConfig *config.AppConfig) {
|
SetupConfig: func(cfg *config.AppConfig) {
|
||||||
testConfig.UserConfig.Git.CommitPrefixes = map[string]config.CommitPrefixConfig{"repo": {Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[$1]: "}}
|
cfg.GetUserConfig().Git.CommitPrefixes = map[string]config.CommitPrefixConfig{"repo": {Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[$1]: "}}
|
||||||
},
|
},
|
||||||
SetupRepo: func(shell *Shell) {
|
SetupRepo: func(shell *Shell) {
|
||||||
shell.NewBranch("feature/TEST-001")
|
shell.NewBranch("feature/TEST-001")
|
||||||
|
@ -10,7 +10,7 @@ var Highlight = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
ExtraCmdArgs: []string{},
|
ExtraCmdArgs: []string{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
SetupConfig: func(config *config.AppConfig) {
|
SetupConfig: func(config *config.AppConfig) {
|
||||||
config.AppState.GitLogShowGraph = "always"
|
config.GetAppState().GitLogShowGraph = "always"
|
||||||
config.GetUserConfig().Gui.AuthorColors = map[string]string{
|
config.GetUserConfig().Gui.AuthorColors = map[string]string{
|
||||||
"CI": "red",
|
"CI": "red",
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ var NewBranchWithPrefix = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
ExtraCmdArgs: []string{},
|
ExtraCmdArgs: []string{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
SetupConfig: func(cfg *config.AppConfig) {
|
SetupConfig: func(cfg *config.AppConfig) {
|
||||||
cfg.UserConfig.Git.BranchPrefix = "myprefix/"
|
cfg.GetUserConfig().Git.BranchPrefix = "myprefix/"
|
||||||
},
|
},
|
||||||
SetupRepo: func(shell *Shell) {
|
SetupRepo: func(shell *Shell) {
|
||||||
shell.
|
shell.
|
||||||
|
@ -10,8 +10,8 @@ var PasteCommitMessage = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
ExtraCmdArgs: []string{},
|
ExtraCmdArgs: []string{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
SetupConfig: func(config *config.AppConfig) {
|
SetupConfig: func(config *config.AppConfig) {
|
||||||
config.UserConfig.OS.CopyToClipboardCmd = "echo {{text}} > ../clipboard"
|
config.GetUserConfig().OS.CopyToClipboardCmd = "echo {{text}} > ../clipboard"
|
||||||
config.UserConfig.OS.ReadFromClipboardCmd = "cat ../clipboard"
|
config.GetUserConfig().OS.ReadFromClipboardCmd = "cat ../clipboard"
|
||||||
},
|
},
|
||||||
SetupRepo: func(shell *Shell) {
|
SetupRepo: func(shell *Shell) {
|
||||||
shell.EmptyCommit("subject\n\nbody 1st line\nbody 2nd line")
|
shell.EmptyCommit("subject\n\nbody 1st line\nbody 2nd line")
|
||||||
|
@ -10,8 +10,8 @@ var PasteCommitMessageOverExisting = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
ExtraCmdArgs: []string{},
|
ExtraCmdArgs: []string{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
SetupConfig: func(config *config.AppConfig) {
|
SetupConfig: func(config *config.AppConfig) {
|
||||||
config.UserConfig.OS.CopyToClipboardCmd = "echo {{text}} > ../clipboard"
|
config.GetUserConfig().OS.CopyToClipboardCmd = "echo {{text}} > ../clipboard"
|
||||||
config.UserConfig.OS.ReadFromClipboardCmd = "cat ../clipboard"
|
config.GetUserConfig().OS.ReadFromClipboardCmd = "cat ../clipboard"
|
||||||
},
|
},
|
||||||
SetupRepo: func(shell *Shell) {
|
SetupRepo: func(shell *Shell) {
|
||||||
shell.EmptyCommit("subject\n\nbody 1st line\nbody 2nd line")
|
shell.EmptyCommit("subject\n\nbody 1st line\nbody 2nd line")
|
||||||
|
@ -15,7 +15,7 @@ var AccessCommitProperties = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
shell.EmptyCommit("my change")
|
shell.EmptyCommit("my change")
|
||||||
},
|
},
|
||||||
SetupConfig: func(cfg *config.AppConfig) {
|
SetupConfig: func(cfg *config.AppConfig) {
|
||||||
cfg.UserConfig.CustomCommands = []config.CustomCommand{
|
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
|
||||||
{
|
{
|
||||||
Key: "X",
|
Key: "X",
|
||||||
Context: "commits",
|
Context: "commits",
|
||||||
|
@ -13,7 +13,7 @@ var BasicCommand = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
shell.EmptyCommit("blah")
|
shell.EmptyCommit("blah")
|
||||||
},
|
},
|
||||||
SetupConfig: func(cfg *config.AppConfig) {
|
SetupConfig: func(cfg *config.AppConfig) {
|
||||||
cfg.UserConfig.CustomCommands = []config.CustomCommand{
|
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
|
||||||
{
|
{
|
||||||
Key: "a",
|
Key: "a",
|
||||||
Context: "files",
|
Context: "files",
|
||||||
|
@ -14,7 +14,7 @@ var CheckForConflicts = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
shared.MergeConflictsSetup(shell)
|
shared.MergeConflictsSetup(shell)
|
||||||
},
|
},
|
||||||
SetupConfig: func(cfg *config.AppConfig) {
|
SetupConfig: func(cfg *config.AppConfig) {
|
||||||
cfg.UserConfig.CustomCommands = []config.CustomCommand{
|
cfg.GetUserConfig().CustomCommands = []config.CustomCommand{
|
||||||
{
|
{
|
||||||
Key: "m",
|
Key: "m",
|
||||||
Context: "localBranches",
|
Context: "localBranches",
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user