diff --git a/pkg/commands/git_commands/commit.go b/pkg/commands/git_commands/commit.go index 11b75c8f05a..11190956932 100644 --- a/pkg/commands/git_commands/commit.go +++ b/pkg/commands/git_commands/commit.go @@ -254,8 +254,10 @@ func (self *CommitCommands) AmendHeadCmdObj() *oscommands.CmdObj { } func (self *CommitCommands) ShowCmdObj(hash string, filterPath string) *oscommands.CmdObj { - contextSize := self.UserConfig().Git.DiffContextSize + return self.ShowCmdObjWithContextSize(hash, filterPath, self.UserConfig().Git.DiffContextSize) +} +func (self *CommitCommands) ShowCmdObjWithContextSize(hash string, filterPath string, contextSize uint64) *oscommands.CmdObj { extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand cmdArgs := NewGitCmd("show"). Config("diff.noprefix=false"). diff --git a/pkg/commands/git_commands/diff.go b/pkg/commands/git_commands/diff.go index 5f1db045f36..c679c30c3ff 100644 --- a/pkg/commands/git_commands/diff.go +++ b/pkg/commands/git_commands/diff.go @@ -19,6 +19,10 @@ func NewDiffCommands(gitCommon *GitCommon) *DiffCommands { // This is for generating diffs to be shown in the UI (e.g. rendering a range // diff to the main view). It uses a custom pager if one is configured. func (self *DiffCommands) DiffCmdObj(diffArgs []string) *oscommands.CmdObj { + return self.DiffCmdObjWithContextSize(diffArgs, self.UserConfig().Git.DiffContextSize) +} + +func (self *DiffCommands) DiffCmdObjWithContextSize(diffArgs []string, contextSize uint64) *oscommands.CmdObj { extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand useExtDiff := extDiffCmd != "" ignoreWhitespace := self.UserConfig().Git.IgnoreWhitespaceInDiffView @@ -31,7 +35,7 @@ func (self *DiffCommands) DiffCmdObj(diffArgs []string) *oscommands.CmdObj { Arg("--submodule"). Arg(fmt.Sprintf("--color=%s", self.UserConfig().Git.Paging.ColorArg)). ArgIf(ignoreWhitespace, "--ignore-all-space"). - Arg(fmt.Sprintf("--unified=%d", self.UserConfig().Git.DiffContextSize)). + Arg(fmt.Sprintf("--unified=%d", contextSize)). Arg(diffArgs...). Dir(self.repoPaths.worktreePath). ToArgv(), diff --git a/pkg/commands/git_commands/stash.go b/pkg/commands/git_commands/stash.go index 86dccff24ff..fa39d27f229 100644 --- a/pkg/commands/git_commands/stash.go +++ b/pkg/commands/git_commands/stash.go @@ -81,13 +81,17 @@ func (self *StashCommands) Hash(index int) (string, error) { } func (self *StashCommands) ShowStashEntryCmdObj(index int) *oscommands.CmdObj { + return self.ShowStashEntryCmdObjWithContextSize(index, self.UserConfig().Git.DiffContextSize) +} + +func (self *StashCommands) ShowStashEntryCmdObjWithContextSize(index int, contextSize uint64) *oscommands.CmdObj { // "-u" is the same as "--include-untracked", but the latter fails in older git versions for some reason cmdArgs := NewGitCmd("stash").Arg("show"). Arg("-p"). Arg("--stat"). Arg("-u"). Arg(fmt.Sprintf("--color=%s", self.UserConfig().Git.Paging.ColorArg)). - Arg(fmt.Sprintf("--unified=%d", self.UserConfig().Git.DiffContextSize)). + Arg(fmt.Sprintf("--unified=%d", contextSize)). ArgIf(self.UserConfig().Git.IgnoreWhitespaceInDiffView, "--ignore-all-space"). Arg(fmt.Sprintf("--find-renames=%d%%", self.UserConfig().Git.RenameSimilarityThreshold)). Arg(fmt.Sprintf("refs/stash@{%d}", index)). diff --git a/pkg/commands/git_commands/working_tree.go b/pkg/commands/git_commands/working_tree.go index deb9e6a5922..656aff05a1a 100644 --- a/pkg/commands/git_commands/working_tree.go +++ b/pkg/commands/git_commands/working_tree.go @@ -255,12 +255,14 @@ func (self *WorkingTreeCommands) WorktreeFileDiff(file *models.File, plain bool, } func (self *WorkingTreeCommands) WorktreeFileDiffCmdObj(node models.IFile, plain bool, cached bool) *oscommands.CmdObj { + return self.WorktreeFileDiffCmdObjWithContextSize(node, plain, cached, self.UserConfig().Git.DiffContextSize) +} + +func (self *WorkingTreeCommands) WorktreeFileDiffCmdObjWithContextSize(node models.IFile, plain bool, cached bool, contextSize uint64) *oscommands.CmdObj { colorArg := self.UserConfig().Git.Paging.ColorArg if plain { colorArg = "never" } - - contextSize := self.UserConfig().Git.DiffContextSize prevPath := node.GetPreviousPath() noIndex := !node.GetIsTracked() && !node.GetHasStagedChanges() && !cached && node.GetIsFile() extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 5465a376c11..e975548b0d8 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -235,6 +235,21 @@ type SpinnerConfig struct { Rate int `yaml:"rate" jsonschema:"minimum=1"` } +type AdaptiveContextConfig struct { + // Whether to enable adaptive diff context sizes based on the current context + Enabled bool `yaml:"enabled"` + // Context size when viewing individual files + Files uint64 `yaml:"files"` + // Context size when viewing commit diffs + Commits uint64 `yaml:"commits"` + // Context size when viewing stash diffs + Stash uint64 `yaml:"stash"` + // Context size when in staging mode + Staging uint64 `yaml:"staging"` + // Context size when building custom patches + PatchBuilding uint64 `yaml:"patchBuilding"` +} + type GitConfig struct { // See https://github.com/jesseduffield/lazygit/blob/master/docs/Custom_Pagers.md Paging PagingConfig `yaml:"paging"` @@ -268,6 +283,8 @@ type GitConfig struct { IgnoreWhitespaceInDiffView bool `yaml:"ignoreWhitespaceInDiffView"` // The number of lines of context to show around each diff hunk. Can be changed from within Lazygit with the `{` and `}` keys. DiffContextSize uint64 `yaml:"diffContextSize"` + // Adaptive diff context sizes based on the current context + AdaptiveContext AdaptiveContextConfig `yaml:"adaptiveContext"` // The threshold for considering a file to be renamed, in percent. Can be changed from within Lazygit with the `(` and `)` keys. RenameSimilarityThreshold int `yaml:"renameSimilarityThreshold" jsonschema:"minimum=0,maximum=100"` // If true, do not spawn a separate process when using GPG @@ -827,6 +844,14 @@ func GetDefaultConfig() *UserConfig { AllBranchesLogCmds: []string{"git log --graph --all --color=always --abbrev-commit --decorate --date=relative --pretty=medium"}, IgnoreWhitespaceInDiffView: false, DiffContextSize: 3, + AdaptiveContext: AdaptiveContextConfig{ + Enabled: false, + Files: 1000, + Commits: 10, + Stash: 5, + Staging: 20, + PatchBuilding: 50, + }, RenameSimilarityThreshold: 50, DisableForcePushing: false, CommitPrefixes: map[string][]CommitPrefixConfig(nil), diff --git a/pkg/gui/controllers/common.go b/pkg/gui/controllers/common.go index 3498ad59d62..f62a6c7671e 100644 --- a/pkg/gui/controllers/common.go +++ b/pkg/gui/controllers/common.go @@ -1,7 +1,9 @@ package controllers import ( + "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) type ControllerCommon struct { @@ -22,3 +24,39 @@ func NewControllerCommon( IGetHelpers: IGetHelpers, } } + +// getContextSizeForCurrentContext returns the appropriate context size based on the current context +func (self *ControllerCommon) getContextSizeForCurrentContext() uint64 { + adaptiveConfig := self.UserConfig().Git.AdaptiveContext + if !adaptiveConfig.Enabled { + return self.UserConfig().Git.DiffContextSize + } + + currentContext := self.currentSidePanel().GetKey() + switch currentContext { + case context.FILES_CONTEXT_KEY, context.COMMIT_FILES_CONTEXT_KEY: + return adaptiveConfig.Files + case context.LOCAL_COMMITS_CONTEXT_KEY, context.SUB_COMMITS_CONTEXT_KEY: + return adaptiveConfig.Commits + case context.STASH_CONTEXT_KEY: + return adaptiveConfig.Stash + case context.STAGING_MAIN_CONTEXT_KEY, context.STAGING_SECONDARY_CONTEXT_KEY: + return adaptiveConfig.Staging + case context.PATCH_BUILDING_MAIN_CONTEXT_KEY, context.PATCH_BUILDING_SECONDARY_CONTEXT_KEY: + return adaptiveConfig.PatchBuilding + default: + return self.UserConfig().Git.DiffContextSize + } +} + +func (self *ControllerCommon) currentSidePanel() types.Context { + currentContext := self.Context().CurrentStatic() + if currentContext.GetKey() == context.NORMAL_MAIN_CONTEXT_KEY || + currentContext.GetKey() == context.NORMAL_SECONDARY_CONTEXT_KEY { + if sidePanelContext := self.Context().NextInStack(currentContext); sidePanelContext != nil { + return sidePanelContext + } + } + + return currentContext +} diff --git a/pkg/gui/controllers/context_lines_controller.go b/pkg/gui/controllers/context_lines_controller.go index 5e0f9d60660..4fbf9a7a912 100644 --- a/pkg/gui/controllers/context_lines_controller.go +++ b/pkg/gui/controllers/context_lines_controller.go @@ -71,9 +71,7 @@ func (self *ContextLinesController) Increase() error { return err } - if self.c.UserConfig().Git.DiffContextSize < math.MaxUint64 { - self.c.UserConfig().Git.DiffContextSize++ - } + self.incrementContextSize() return self.applyChange() } @@ -86,17 +84,93 @@ func (self *ContextLinesController) Decrease() error { return err } + self.decrementContextSize() + return self.applyChange() + } + + return nil +} + +// incrementContextSize increases the context size for the current context +func (self *ContextLinesController) incrementContextSize() { + adaptiveConfig := &self.c.UserConfig().Git.AdaptiveContext + if !adaptiveConfig.Enabled { + if self.c.UserConfig().Git.DiffContextSize < math.MaxUint64 { + self.c.UserConfig().Git.DiffContextSize++ + } + return + } + + currentContext := self.currentSidePanel().GetKey() + switch currentContext { + case context.FILES_CONTEXT_KEY, context.COMMIT_FILES_CONTEXT_KEY: + if adaptiveConfig.Files < math.MaxUint64 { + adaptiveConfig.Files++ + } + case context.LOCAL_COMMITS_CONTEXT_KEY, context.SUB_COMMITS_CONTEXT_KEY: + if adaptiveConfig.Commits < math.MaxUint64 { + adaptiveConfig.Commits++ + } + case context.STASH_CONTEXT_KEY: + if adaptiveConfig.Stash < math.MaxUint64 { + adaptiveConfig.Stash++ + } + case context.STAGING_MAIN_CONTEXT_KEY, context.STAGING_SECONDARY_CONTEXT_KEY: + if adaptiveConfig.Staging < math.MaxUint64 { + adaptiveConfig.Staging++ + } + case context.PATCH_BUILDING_MAIN_CONTEXT_KEY, context.PATCH_BUILDING_SECONDARY_CONTEXT_KEY: + if adaptiveConfig.PatchBuilding < math.MaxUint64 { + adaptiveConfig.PatchBuilding++ + } + default: + if self.c.UserConfig().Git.DiffContextSize < math.MaxUint64 { + self.c.UserConfig().Git.DiffContextSize++ + } + } +} + +// decrementContextSize decreases the context size for the current context +func (self *ContextLinesController) decrementContextSize() { + adaptiveConfig := &self.c.UserConfig().Git.AdaptiveContext + if !adaptiveConfig.Enabled { if self.c.UserConfig().Git.DiffContextSize > 0 { self.c.UserConfig().Git.DiffContextSize-- } - return self.applyChange() + return } - return nil + currentContext := self.currentSidePanel().GetKey() + switch currentContext { + case context.FILES_CONTEXT_KEY, context.COMMIT_FILES_CONTEXT_KEY: + if adaptiveConfig.Files > 0 { + adaptiveConfig.Files-- + } + case context.LOCAL_COMMITS_CONTEXT_KEY, context.SUB_COMMITS_CONTEXT_KEY: + if adaptiveConfig.Commits > 0 { + adaptiveConfig.Commits-- + } + case context.STASH_CONTEXT_KEY: + if adaptiveConfig.Stash > 0 { + adaptiveConfig.Stash-- + } + case context.STAGING_MAIN_CONTEXT_KEY, context.STAGING_SECONDARY_CONTEXT_KEY: + if adaptiveConfig.Staging > 0 { + adaptiveConfig.Staging-- + } + case context.PATCH_BUILDING_MAIN_CONTEXT_KEY, context.PATCH_BUILDING_SECONDARY_CONTEXT_KEY: + if adaptiveConfig.PatchBuilding > 0 { + adaptiveConfig.PatchBuilding-- + } + default: + if self.c.UserConfig().Git.DiffContextSize > 0 { + self.c.UserConfig().Git.DiffContextSize-- + } + } } func (self *ContextLinesController) applyChange() error { - self.c.Toast(fmt.Sprintf(self.c.Tr.DiffContextSizeChanged, self.c.UserConfig().Git.DiffContextSize)) + self.c.Toast(fmt.Sprintf(self.c.Tr.DiffContextSizeChanged, self.getContextSizeForCurrentContext())) currentContext := self.currentSidePanel() switch currentContext.GetKey() { @@ -127,13 +201,10 @@ func (self *ContextLinesController) isShowingDiff() bool { } func (self *ContextLinesController) currentSidePanel() types.Context { - currentContext := self.c.Context().CurrentStatic() - if currentContext.GetKey() == context.NORMAL_MAIN_CONTEXT_KEY || - currentContext.GetKey() == context.NORMAL_SECONDARY_CONTEXT_KEY { - if sidePanelContext := self.c.Context().NextInStack(currentContext); sidePanelContext != nil { - return sidePanelContext - } - } + return self.c.currentSidePanel() +} - return currentContext +// getContextSizeForCurrentContext returns the appropriate context size based on the current context +func (self *ContextLinesController) getContextSizeForCurrentContext() uint64 { + return self.c.getContextSizeForCurrentContext() } diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index 9f95c86f64a..240dd737af4 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -282,7 +282,8 @@ func (self *FilesController) GetOnRenderToMain() func() { split := self.c.UserConfig().Gui.SplitDiff == "always" || (node.GetHasUnstagedChanges() && node.GetHasStagedChanges()) mainShowsStaged := !split && node.GetHasStagedChanges() - cmdObj := self.c.Git().WorkingTree.WorktreeFileDiffCmdObj(node, false, mainShowsStaged) + contextSize := self.c.getContextSizeForCurrentContext() + cmdObj := self.c.Git().WorkingTree.WorktreeFileDiffCmdObjWithContextSize(node, false, mainShowsStaged, contextSize) title := self.c.Tr.UnstagedChanges if mainShowsStaged { title = self.c.Tr.StagedChanges @@ -297,7 +298,8 @@ func (self *FilesController) GetOnRenderToMain() func() { } if split { - cmdObj := self.c.Git().WorkingTree.WorktreeFileDiffCmdObj(node, false, true) + contextSize := self.c.getContextSizeForCurrentContext() + cmdObj := self.c.Git().WorkingTree.WorktreeFileDiffCmdObjWithContextSize(node, false, true, contextSize) title := self.c.Tr.StagedChanges if mainShowsStaged {