From ed054707327b70477865f4fe0be5210d278b84fa Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 8 Oct 2025 16:12:52 +0200 Subject: [PATCH 1/5] Cleanup: remove unused method ConfiguredPager This could have been removed in commit 9657b4346fe2. --- pkg/commands/git_commands/config.go | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/pkg/commands/git_commands/config.go b/pkg/commands/git_commands/config.go index 1bed989859f..40cf041b3f4 100644 --- a/pkg/commands/git_commands/config.go +++ b/pkg/commands/git_commands/config.go @@ -1,9 +1,7 @@ package git_commands import ( - "os" "strconv" - "strings" gogit "github.com/jesseduffield/go-git/v5" "github.com/jesseduffield/go-git/v5/config" @@ -31,17 +29,6 @@ func NewConfigCommands( } } -func (self *ConfigCommands) ConfiguredPager() string { - if os.Getenv("GIT_PAGER") != "" { - return os.Getenv("GIT_PAGER") - } - if os.Getenv("PAGER") != "" { - return os.Getenv("PAGER") - } - output := self.gitConfig.Get("core.pager") - return strings.Split(output, "\n")[0] -} - func (self *ConfigCommands) GetPager(width int) string { templateValues := map[string]string{ "columnWidth": strconv.Itoa(width/2 - 6), From 765c9eb85c80129791062e0884b0baef674f358c Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Thu, 9 Oct 2025 15:42:45 +0200 Subject: [PATCH 2/5] Add PagerConfig This is an object that is owned by Gui, is accessible through GuiCommon.State(), and also passed down to GitCommand, where it is mostly needed. Right now it simply wraps access to the Git.Paging config, which isn't very exciting, but we'll extend it in the next commit to handle a slice of pagers (and maintain the currently selected pager index), and doing this refactoring up front allows us to make that change without having to touch clients. --- pkg/commands/git.go | 6 +++- pkg/commands/git_commands/commit.go | 6 ++-- pkg/commands/git_commands/common.go | 30 +++++++++++-------- pkg/commands/git_commands/config.go | 12 -------- pkg/commands/git_commands/deps_test.go | 4 +++ pkg/commands/git_commands/diff.go | 6 ++-- pkg/commands/git_commands/stash.go | 6 ++-- pkg/commands/git_commands/working_tree.go | 12 ++++---- pkg/config/pager_config.go | 36 +++++++++++++++++++++++ pkg/gui/gui.go | 15 ++++++++-- pkg/gui/pty.go | 6 ++-- pkg/gui/types/common.go | 1 + 12 files changed, 93 insertions(+), 47 deletions(-) create mode 100644 pkg/config/pager_config.go diff --git a/pkg/commands/git.go b/pkg/commands/git.go index 4aba9a7a845..90514cbd62a 100644 --- a/pkg/commands/git.go +++ b/pkg/commands/git.go @@ -12,6 +12,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/patch" "github.com/jesseduffield/lazygit/pkg/common" + "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -59,6 +60,7 @@ func NewGitCommand( version *git_commands.GitVersion, osCommand *oscommands.OSCommand, gitConfig git_config.IGitConfig, + pagerConfig *config.PagerConfig, ) (*GitCommand, error) { repoPaths, err := git_commands.GetRepoPaths(osCommand.Cmd, version) if err != nil { @@ -88,6 +90,7 @@ func NewGitCommand( gitConfig, repoPaths, repository, + pagerConfig, ), nil } @@ -98,6 +101,7 @@ func NewGitCommandAux( gitConfig git_config.IGitConfig, repoPaths *git_commands.RepoPaths, repo *gogit.Repository, + pagerConfig *config.PagerConfig, ) *GitCommand { cmd := NewGitCmdObjBuilder(cmn.Log, osCommand.Cmd) @@ -108,7 +112,7 @@ func NewGitCommandAux( // common ones are: cmn, osCommand, dotGitDir, configCommands configCommands := git_commands.NewConfigCommands(cmn, gitConfig, repo) - gitCommon := git_commands.NewGitCommon(cmn, version, cmd, osCommand, repoPaths, repo, configCommands) + gitCommon := git_commands.NewGitCommon(cmn, version, cmd, osCommand, repoPaths, repo, configCommands, pagerConfig) fileLoader := git_commands.NewFileLoader(gitCommon, cmd, configCommands) statusCommands := git_commands.NewStatusCommands(gitCommon) diff --git a/pkg/commands/git_commands/commit.go b/pkg/commands/git_commands/commit.go index 084a6c8d4c7..89063be82bf 100644 --- a/pkg/commands/git_commands/commit.go +++ b/pkg/commands/git_commands/commit.go @@ -256,14 +256,14 @@ func (self *CommitCommands) AmendHeadCmdObj() *oscommands.CmdObj { func (self *CommitCommands) ShowCmdObj(hash string, filterPaths []string) *oscommands.CmdObj { contextSize := self.UserConfig().Git.DiffContextSize - extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand - useExtDiffGitConfig := self.UserConfig().Git.Paging.UseExternalDiffGitConfig + extDiffCmd := self.pagerConfig.GetExternalDiffCommand() + useExtDiffGitConfig := self.pagerConfig.GetUseExternalDiffGitConfig() cmdArgs := NewGitCmd("show"). Config("diff.noprefix=false"). ConfigIf(extDiffCmd != "", "diff.external="+extDiffCmd). ArgIfElse(extDiffCmd != "" || useExtDiffGitConfig, "--ext-diff", "--no-ext-diff"). Arg("--submodule"). - Arg("--color="+self.UserConfig().Git.Paging.ColorArg). + Arg("--color="+self.pagerConfig.GetColorArg()). Arg(fmt.Sprintf("--unified=%d", contextSize)). Arg("--stat"). Arg("--decorate"). diff --git a/pkg/commands/git_commands/common.go b/pkg/commands/git_commands/common.go index b9537165c61..28dd78e8bb7 100644 --- a/pkg/commands/git_commands/common.go +++ b/pkg/commands/git_commands/common.go @@ -4,16 +4,18 @@ import ( gogit "github.com/jesseduffield/go-git/v5" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/common" + "github.com/jesseduffield/lazygit/pkg/config" ) type GitCommon struct { *common.Common - version *GitVersion - cmd oscommands.ICmdObjBuilder - os *oscommands.OSCommand - repoPaths *RepoPaths - repo *gogit.Repository - config *ConfigCommands + version *GitVersion + cmd oscommands.ICmdObjBuilder + os *oscommands.OSCommand + repoPaths *RepoPaths + repo *gogit.Repository + config *ConfigCommands + pagerConfig *config.PagerConfig } func NewGitCommon( @@ -24,14 +26,16 @@ func NewGitCommon( repoPaths *RepoPaths, repo *gogit.Repository, config *ConfigCommands, + pagerConfig *config.PagerConfig, ) *GitCommon { return &GitCommon{ - Common: cmn, - version: version, - cmd: cmd, - os: osCommand, - repoPaths: repoPaths, - repo: repo, - config: config, + Common: cmn, + version: version, + cmd: cmd, + os: osCommand, + repoPaths: repoPaths, + repo: repo, + config: config, + pagerConfig: pagerConfig, } } diff --git a/pkg/commands/git_commands/config.go b/pkg/commands/git_commands/config.go index 40cf041b3f4..fa657035693 100644 --- a/pkg/commands/git_commands/config.go +++ b/pkg/commands/git_commands/config.go @@ -1,13 +1,10 @@ package git_commands import ( - "strconv" - gogit "github.com/jesseduffield/go-git/v5" "github.com/jesseduffield/go-git/v5/config" "github.com/jesseduffield/lazygit/pkg/commands/git_config" "github.com/jesseduffield/lazygit/pkg/common" - "github.com/jesseduffield/lazygit/pkg/utils" ) type ConfigCommands struct { @@ -29,15 +26,6 @@ func NewConfigCommands( } } -func (self *ConfigCommands) GetPager(width int) string { - templateValues := map[string]string{ - "columnWidth": strconv.Itoa(width/2 - 6), - } - - pagerTemplate := string(self.UserConfig().Git.Paging.Pager) - return utils.ResolvePlaceholderString(pagerTemplate, templateValues) -} - type GpgConfigKey string const ( diff --git a/pkg/commands/git_commands/deps_test.go b/pkg/commands/git_commands/deps_test.go index a8fff5edded..3c4bd5a144d 100644 --- a/pkg/commands/git_commands/deps_test.go +++ b/pkg/commands/git_commands/deps_test.go @@ -61,6 +61,10 @@ func buildGitCommon(deps commonDeps) *GitCommon { gitCommon.Common.SetUserConfig(config.GetDefaultConfig()) } + gitCommon.pagerConfig = config.NewPagerConfig(func() *config.UserConfig { + return gitCommon.Common.UserConfig() + }) + gitCommon.version = deps.gitVersion if gitCommon.version == nil { gitCommon.version = &GitVersion{2, 0, 0, ""} diff --git a/pkg/commands/git_commands/diff.go b/pkg/commands/git_commands/diff.go index 76b67788464..4feeb4d7ff9 100644 --- a/pkg/commands/git_commands/diff.go +++ b/pkg/commands/git_commands/diff.go @@ -19,9 +19,9 @@ 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 { - extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand + extDiffCmd := self.pagerConfig.GetExternalDiffCommand() useExtDiff := extDiffCmd != "" - useExtDiffGitConfig := self.UserConfig().Git.Paging.UseExternalDiffGitConfig + useExtDiffGitConfig := self.pagerConfig.GetUseExternalDiffGitConfig() ignoreWhitespace := self.UserConfig().Git.IgnoreWhitespaceInDiffView return self.cmd.New( @@ -30,7 +30,7 @@ func (self *DiffCommands) DiffCmdObj(diffArgs []string) *oscommands.CmdObj { ConfigIf(useExtDiff, "diff.external="+extDiffCmd). ArgIfElse(useExtDiff || useExtDiffGitConfig, "--ext-diff", "--no-ext-diff"). Arg("--submodule"). - Arg(fmt.Sprintf("--color=%s", self.UserConfig().Git.Paging.ColorArg)). + Arg(fmt.Sprintf("--color=%s", self.pagerConfig.GetColorArg())). ArgIf(ignoreWhitespace, "--ignore-all-space"). Arg(fmt.Sprintf("--unified=%d", self.UserConfig().Git.DiffContextSize)). Arg(diffArgs...). diff --git a/pkg/commands/git_commands/stash.go b/pkg/commands/git_commands/stash.go index f6b69ae7da6..0e5eb299d50 100644 --- a/pkg/commands/git_commands/stash.go +++ b/pkg/commands/git_commands/stash.go @@ -81,8 +81,8 @@ func (self *StashCommands) Hash(index int) (string, error) { } func (self *StashCommands) ShowStashEntryCmdObj(index int) *oscommands.CmdObj { - extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand - useExtDiffGitConfig := self.UserConfig().Git.Paging.UseExternalDiffGitConfig + extDiffCmd := self.pagerConfig.GetExternalDiffCommand() + useExtDiffGitConfig := self.pagerConfig.GetUseExternalDiffGitConfig() // "-u" is the same as "--include-untracked", but the latter fails in older git versions for some reason cmdArgs := NewGitCmd("stash").Arg("show"). @@ -91,7 +91,7 @@ func (self *StashCommands) ShowStashEntryCmdObj(index int) *oscommands.CmdObj { Arg("-u"). ConfigIf(extDiffCmd != "", "diff.external="+extDiffCmd). ArgIfElse(extDiffCmd != "" || useExtDiffGitConfig, "--ext-diff", "--no-ext-diff"). - Arg(fmt.Sprintf("--color=%s", self.UserConfig().Git.Paging.ColorArg)). + Arg(fmt.Sprintf("--color=%s", self.pagerConfig.GetColorArg())). Arg(fmt.Sprintf("--unified=%d", self.UserConfig().Git.DiffContextSize)). ArgIf(self.UserConfig().Git.IgnoreWhitespaceInDiffView, "--ignore-all-space"). Arg(fmt.Sprintf("--find-renames=%d%%", self.UserConfig().Git.RenameSimilarityThreshold)). diff --git a/pkg/commands/git_commands/working_tree.go b/pkg/commands/git_commands/working_tree.go index ffa1d99b6d8..1cba0d5114e 100644 --- a/pkg/commands/git_commands/working_tree.go +++ b/pkg/commands/git_commands/working_tree.go @@ -258,7 +258,7 @@ func (self *WorkingTreeCommands) WorktreeFileDiff(file *models.File, plain bool, } func (self *WorkingTreeCommands) WorktreeFileDiffCmdObj(node models.IFile, plain bool, cached bool) *oscommands.CmdObj { - colorArg := self.UserConfig().Git.Paging.ColorArg + colorArg := self.pagerConfig.GetColorArg() if plain { colorArg = "never" } @@ -266,9 +266,9 @@ func (self *WorkingTreeCommands) WorktreeFileDiffCmdObj(node models.IFile, plain contextSize := self.UserConfig().Git.DiffContextSize prevPath := node.GetPreviousPath() noIndex := !node.GetIsTracked() && !node.GetHasStagedChanges() && !cached && node.GetIsFile() - extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand + extDiffCmd := self.pagerConfig.GetExternalDiffCommand() useExtDiff := extDiffCmd != "" && !plain - useExtDiffGitConfig := self.UserConfig().Git.Paging.UseExternalDiffGitConfig && !plain + useExtDiffGitConfig := self.pagerConfig.GetUseExternalDiffGitConfig() && !plain cmdArgs := NewGitCmd("diff"). ConfigIf(useExtDiff, "diff.external="+extDiffCmd). @@ -299,14 +299,14 @@ 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.CmdObj { contextSize := self.UserConfig().Git.DiffContextSize - colorArg := self.UserConfig().Git.Paging.ColorArg + colorArg := self.pagerConfig.GetColorArg() if plain { colorArg = "never" } - extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand + extDiffCmd := self.pagerConfig.GetExternalDiffCommand() useExtDiff := extDiffCmd != "" && !plain - useExtDiffGitConfig := self.UserConfig().Git.Paging.UseExternalDiffGitConfig && !plain + useExtDiffGitConfig := self.pagerConfig.GetUseExternalDiffGitConfig() && !plain cmdArgs := NewGitCmd("diff"). Config("diff.noprefix=false"). diff --git a/pkg/config/pager_config.go b/pkg/config/pager_config.go new file mode 100644 index 00000000000..6d7d3973931 --- /dev/null +++ b/pkg/config/pager_config.go @@ -0,0 +1,36 @@ +package config + +import ( + "strconv" + + "github.com/jesseduffield/lazygit/pkg/utils" +) + +type PagerConfig struct { + getUserConfig func() *UserConfig +} + +func NewPagerConfig(getUserConfig func() *UserConfig) *PagerConfig { + return &PagerConfig{getUserConfig: getUserConfig} +} + +func (self *PagerConfig) GetPagerCommand(width int) string { + templateValues := map[string]string{ + "columnWidth": strconv.Itoa(width/2 - 6), + } + + pagerTemplate := string(self.getUserConfig().Git.Paging.Pager) + return utils.ResolvePlaceholderString(pagerTemplate, templateValues) +} + +func (self *PagerConfig) GetColorArg() string { + return self.getUserConfig().Git.Paging.ColorArg +} + +func (self *PagerConfig) GetExternalDiffCommand() string { + return self.getUserConfig().Git.Paging.ExternalDiffCommand +} + +func (self *PagerConfig) GetUseExternalDiffGitConfig() bool { + return self.getUserConfig().Git.Paging.UseExternalDiffGitConfig +} diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index c9252e03d60..2727df3c45a 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -69,6 +69,8 @@ type Gui struct { // this is the state of the GUI for the current repo State *GuiRepoState + pagerConfig *config.PagerConfig + CustomCommandsClient *custom_commands.Client // this is a mapping of repos to gui states, so that we can restore the original @@ -169,6 +171,10 @@ func (self *StateAccessor) GetRepoState() types.IRepoStateAccessor { return self.gui.State } +func (self *StateAccessor) GetPagerConfig() *config.PagerConfig { + return self.gui.pagerConfig +} + func (self *StateAccessor) GetIsRefreshingFiles() bool { return self.gui.IsRefreshingFiles } @@ -307,6 +313,7 @@ func (gui *Gui) onNewRepo(startArgs appTypes.StartArgs, contextKey types.Context gui.gitVersion, gui.os, git_config.NewStdCachedGitConfig(gui.Log), + gui.pagerConfig, ) if err != nil { return err @@ -653,7 +660,7 @@ func (gui *Gui) Contexts() *context.ContextTree { // NewGui builds a new gui handler func NewGui( cmn *common.Common, - config config.AppConfigurer, + configurer config.AppConfigurer, gitVersion *git_commands.GitVersion, updater *updates.Updater, showRecentRepos bool, @@ -663,7 +670,7 @@ func NewGui( gui := &Gui{ Common: cmn, gitVersion: gitVersion, - Config: config, + Config: configurer, Updater: updater, statusManager: status.NewStatusManager(), viewBufferManagerMap: map[string]*tasks.ViewBufferManager{}, @@ -713,7 +720,7 @@ func NewGui( credentialsHelper.PromptUserForCredential, ) - osCommand := oscommands.NewOSCommand(cmn, config, oscommands.GetPlatform(), guiIO) + osCommand := oscommands.NewOSCommand(cmn, configurer, oscommands.GetPlatform(), guiIO) gui.os = osCommand @@ -724,6 +731,8 @@ func NewGui( gui.BackgroundRoutineMgr = &BackgroundRoutineMgr{gui: gui} gui.stateAccessor = &StateAccessor{gui: gui} + gui.pagerConfig = config.NewPagerConfig(func() *config.UserConfig { return gui.UserConfig() }) + return gui, nil } diff --git a/pkg/gui/pty.go b/pkg/gui/pty.go index 4253438bb8e..688240dff32 100644 --- a/pkg/gui/pty.go +++ b/pkg/gui/pty.go @@ -45,8 +45,8 @@ func (gui *Gui) onResize() error { // command. func (gui *Gui) newPtyTask(view *gocui.View, cmd *exec.Cmd, prefix string) error { width := view.InnerWidth() - pager := gui.git.Config.GetPager(width) - externalDiffCommand := gui.Config.GetUserConfig().Git.Paging.ExternalDiffCommand + pager := gui.stateAccessor.GetPagerConfig().GetPagerCommand(width) + externalDiffCommand := gui.stateAccessor.GetPagerConfig().GetExternalDiffCommand() if pager == "" && externalDiffCommand == "" { // if we're not using a custom pager we don't need to use a pty @@ -58,7 +58,7 @@ func (gui *Gui) newPtyTask(view *gocui.View, cmd *exec.Cmd, prefix string) error // Need to get the width and the pager again because the layout might have // changed the size of the view width = view.InnerWidth() - pager = gui.git.Config.GetPager(width) + pager := gui.stateAccessor.GetPagerConfig().GetPagerCommand(width) cmdStr := strings.Join(cmd.Args, " ") diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go index 6f7087d8e7e..905a9b65d50 100644 --- a/pkg/gui/types/common.go +++ b/pkg/gui/types/common.go @@ -356,6 +356,7 @@ type HasUrn interface { type IStateAccessor interface { GetRepoPathStack() *utils.StringStack GetRepoState() IRepoStateAccessor + GetPagerConfig() *config.PagerConfig // tells us whether we're currently updating lazygit GetUpdating() bool SetUpdating(bool) From e44d6ec3300290ddffb3bbf9d320980bef7ebc6c Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 8 Oct 2025 16:22:17 +0200 Subject: [PATCH 3/5] Replace paging config with an array of pagers --- docs/Config.md | 43 ++++++++++--------- docs/Custom_Pagers.md | 45 +++++++++++--------- pkg/commands/git_commands/commit_test.go | 22 +++++----- pkg/commands/git_commands/stash_test.go | 12 +++--- pkg/config/pager_config.go | 54 ++++++++++++++++++++++-- pkg/config/user_config.go | 34 ++++++++++++--- pkg/gui/controllers/global_controller.go | 30 +++++++++++++ pkg/i18n/english.go | 6 +++ schema/config.json | 23 +++++----- 9 files changed, 191 insertions(+), 78 deletions(-) diff --git a/docs/Config.md b/docs/Config.md index 11fe2987778..0cdc8ff836a 100644 --- a/docs/Config.md +++ b/docs/Config.md @@ -319,26 +319,30 @@ gui: # Config relating to git git: + # Array of pagers. Each entry has the following format: + # + # # Value of the --color arg in the git diff command. Some pagers want + # # this to be set to 'always' and some want it set to 'never' + # colorArg: "always" + # + # # e.g. + # # diff-so-fancy + # # delta --dark --paging=never + # # ydiff -p cat -s --wrap --width={{columnWidth}} + # pager: "" + # + # # e.g. 'difft --color=always' + # externalDiffCommand: "" + # + # # If true, Lazygit will use git's `diff.external` config for paging. + # # The advantage over `externalDiffCommand` is that this can be + # # configured per file type in .gitattributes; see + # # https://git-scm.com/docs/gitattributes#_defining_an_external_diff_driver. + # useExternalDiffGitConfig: false + # # See https://github.com/jesseduffield/lazygit/blob/master/docs/Custom_Pagers.md - paging: - # Value of the --color arg in the git diff command. Some pagers want this to be - # set to 'always' and some want it set to 'never' - colorArg: always - - # e.g. - # diff-so-fancy - # delta --dark --paging=never - # ydiff -p cat -s --wrap --width={{columnWidth}} - pager: "" - - # e.g. 'difft --color=always' - externalDiffCommand: "" - - # If true, Lazygit will use git's `diff.external` config for paging. The - # advantage over `externalDiffCommand` is that this can be configured per file - # type in .gitattributes; see - # https://git-scm.com/docs/gitattributes#_defining_an_external_diff_driver. - useExternalDiffGitConfig: false + # for more information. + pagers: [] # Config relating to committing commit: @@ -638,6 +642,7 @@ keybinding: prevTab: '[' nextScreenMode: + prevScreenMode: _ + cyclePagers: '|' undo: z redo: Z filteringMenu: diff --git a/docs/Custom_Pagers.md b/docs/Custom_Pagers.md index 5e5d51372b5..c6616cecf7e 100644 --- a/docs/Custom_Pagers.md +++ b/docs/Custom_Pagers.md @@ -4,23 +4,27 @@ Lazygit supports custom pagers, [configured](/docs/Config.md) in the config.yml Support does not extend to Windows users, because we're making use of a package which doesn't have Windows support. However, see [below](#emulating-custom-pagers-on-windows) for a workaround. -## Default: +Multiple pagers are supported; you can cycle through them with the `|` key. This can be useful if you usually prefer a particular pager, but want to use a different one for certain kinds of diffs. + +Pagers are configured with the `pagers` array in the git section; here's an example for a multi-pager setup: ```yaml git: - paging: - colorArg: always + pagers: + - pager: delta --dark --paging=never + - pager: ydiff -p cat -s --wrap --width={{columnWidth}} + colorArg: never + - externalDiffCommand: difft --color=always ``` -the `colorArg` key is for whether you want the `--color=always` arg in your `git diff` command. Some pagers want it set to `always`, others want it set to `never`. +The `colorArg` key is for whether you want the `--color=always` arg in your `git diff` command. Some pagers want it set to `always`, others want it set to `never`. The default is `always`, since that's what most pagers need. ## Delta: ```yaml git: - paging: - colorArg: always - pager: delta --dark --paging=never + pagers: + - pager: delta --dark --paging=never ``` ![](https://i.imgur.com/QJpQkF3.png) @@ -31,9 +35,8 @@ A cool feature of delta is --hyperlinks, which renders clickable links for the l ```yaml git: - paging: - colorArg: always - pager: diff-so-fancy + pagers: + - pager: diff-so-fancy ``` ![](https://i.imgur.com/rjH1TpT.png) @@ -44,9 +47,9 @@ git: gui: sidePanelWidth: 0.2 # gives you more space to show things side-by-side git: - paging: - colorArg: never - pager: ydiff -p cat -s --wrap --width={{columnWidth}} + pagers: + - colorArg: never + pager: ydiff -p cat -s --wrap --width={{columnWidth}} ``` ![](https://i.imgur.com/vaa8z0H.png) @@ -61,8 +64,8 @@ These can be used in lazygit by using the `externalDiffCommand` config; in the c ```yaml git: - paging: - externalDiffCommand: difft --color=always + pagers: + - externalDiffCommand: difft --color=always ``` The `colorArg` and `pager` options are not used in this case. @@ -71,16 +74,16 @@ You can add whatever extra arguments you prefer for your difftool; for instance ```yaml git: - paging: - externalDiffCommand: difft --color=always --display=inline --syntax-highlight=off + pagers: + - externalDiffCommand: difft --color=always --display=inline --syntax-highlight=off ``` Instead of setting this command in lazygit's `externalDiffCommand` config, you can also tell lazygit to use the external diff command that is configured in git itself (`diff.external`), by using ```yaml git: - paging: - useExternalDiffGitConfig: true + pagers: + - useExternalDiffGitConfig: true ``` This can be useful if you also want to use it for diffs on the command line, and it also has the advantage that you can configure it per file type in `.gitattributes`; see https://git-scm.com/docs/gitattributes#_defining_an_external_diff_driver. @@ -106,8 +109,8 @@ In your lazygit config, use ```yml git: - paging: - externalDiffCommand: "C:/wherever/lazygit-pager.ps1" + pagers: + - externalDiffCommand: "C:/wherever/lazygit-pager.ps1" ``` The main limitation of this approach compared to a "real" pager is that renames are not displayed correctly; they are shown as if they were modifications of the old file. (This affects only the hunk headers; the diff itself is always correct.) diff --git a/pkg/commands/git_commands/commit_test.go b/pkg/commands/git_commands/commit_test.go index 8460164ccde..6ea914c6402 100644 --- a/pkg/commands/git_commands/commit_test.go +++ b/pkg/commands/git_commands/commit_test.go @@ -255,8 +255,7 @@ func TestCommitShowCmdObj(t *testing.T) { contextSize uint64 similarityThreshold int ignoreWhitespace bool - extDiffCmd string - useExtDiffGitConfig bool + pagerConfig *config.PagingConfig expected []string } @@ -267,7 +266,7 @@ func TestCommitShowCmdObj(t *testing.T) { contextSize: 3, similarityThreshold: 50, ignoreWhitespace: false, - extDiffCmd: "", + pagerConfig: nil, expected: []string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--find-renames=50%", "--"}, }, { @@ -276,7 +275,7 @@ func TestCommitShowCmdObj(t *testing.T) { contextSize: 3, similarityThreshold: 50, ignoreWhitespace: false, - extDiffCmd: "", + pagerConfig: nil, expected: []string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--find-renames=50%", "--", "file.txt"}, }, { @@ -285,7 +284,7 @@ func TestCommitShowCmdObj(t *testing.T) { contextSize: 77, similarityThreshold: 50, ignoreWhitespace: false, - extDiffCmd: "", + pagerConfig: nil, expected: []string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890", "--find-renames=50%", "--"}, }, { @@ -294,7 +293,7 @@ func TestCommitShowCmdObj(t *testing.T) { contextSize: 3, similarityThreshold: 33, ignoreWhitespace: false, - extDiffCmd: "", + pagerConfig: nil, expected: []string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--find-renames=33%", "--"}, }, { @@ -303,7 +302,7 @@ func TestCommitShowCmdObj(t *testing.T) { contextSize: 77, similarityThreshold: 50, ignoreWhitespace: true, - extDiffCmd: "", + pagerConfig: nil, expected: []string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890", "--ignore-all-space", "--find-renames=50%", "--"}, }, { @@ -312,7 +311,7 @@ func TestCommitShowCmdObj(t *testing.T) { contextSize: 3, similarityThreshold: 50, ignoreWhitespace: false, - extDiffCmd: "difft --color=always", + pagerConfig: &config.PagingConfig{ExternalDiffCommand: "difft --color=always"}, expected: []string{"-C", "/path/to/worktree", "-c", "diff.external=difft --color=always", "-c", "diff.noprefix=false", "show", "--ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--find-renames=50%", "--"}, }, { @@ -321,7 +320,7 @@ func TestCommitShowCmdObj(t *testing.T) { contextSize: 3, similarityThreshold: 50, ignoreWhitespace: false, - useExtDiffGitConfig: true, + pagerConfig: &config.PagingConfig{UseExternalDiffGitConfig: true}, expected: []string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "show", "--ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--find-renames=50%", "--"}, }, } @@ -329,11 +328,12 @@ func TestCommitShowCmdObj(t *testing.T) { for _, s := range scenarios { t.Run(s.testName, func(t *testing.T) { userConfig := config.GetDefaultConfig() - userConfig.Git.Paging.ExternalDiffCommand = s.extDiffCmd + if s.pagerConfig != nil { + userConfig.Git.Pagers = []config.PagingConfig{*s.pagerConfig} + } userConfig.Git.IgnoreWhitespaceInDiffView = s.ignoreWhitespace userConfig.Git.DiffContextSize = s.contextSize userConfig.Git.RenameSimilarityThreshold = s.similarityThreshold - userConfig.Git.Paging.UseExternalDiffGitConfig = s.useExtDiffGitConfig runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expected, "", nil) repoPaths := RepoPaths{ diff --git a/pkg/commands/git_commands/stash_test.go b/pkg/commands/git_commands/stash_test.go index 6b21c0b838f..a942a4e98a9 100644 --- a/pkg/commands/git_commands/stash_test.go +++ b/pkg/commands/git_commands/stash_test.go @@ -103,8 +103,7 @@ func TestStashStashEntryCmdObj(t *testing.T) { contextSize uint64 similarityThreshold int ignoreWhitespace bool - extDiffCmd string - useExtDiffGitConfig bool + pagerConfig *config.PagingConfig expected []string } @@ -139,7 +138,7 @@ func TestStashStashEntryCmdObj(t *testing.T) { contextSize: 3, similarityThreshold: 50, ignoreWhitespace: false, - extDiffCmd: "difft --color=always", + pagerConfig: &config.PagingConfig{ExternalDiffCommand: "difft --color=always"}, expected: []string{"git", "-C", "/path/to/worktree", "-c", "diff.external=difft --color=always", "stash", "show", "-p", "--stat", "-u", "--ext-diff", "--color=always", "--unified=3", "--find-renames=50%", "refs/stash@{5}"}, }, { @@ -148,7 +147,7 @@ func TestStashStashEntryCmdObj(t *testing.T) { contextSize: 3, similarityThreshold: 50, ignoreWhitespace: false, - useExtDiffGitConfig: true, + pagerConfig: &config.PagingConfig{UseExternalDiffGitConfig: true}, expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "-u", "--ext-diff", "--color=always", "--unified=3", "--find-renames=50%", "refs/stash@{5}"}, }, { @@ -167,8 +166,9 @@ func TestStashStashEntryCmdObj(t *testing.T) { userConfig.Git.IgnoreWhitespaceInDiffView = s.ignoreWhitespace userConfig.Git.DiffContextSize = s.contextSize userConfig.Git.RenameSimilarityThreshold = s.similarityThreshold - userConfig.Git.Paging.ExternalDiffCommand = s.extDiffCmd - userConfig.Git.Paging.UseExternalDiffGitConfig = s.useExtDiffGitConfig + if s.pagerConfig != nil { + userConfig.Git.Pagers = []config.PagingConfig{*s.pagerConfig} + } repoPaths := RepoPaths{ worktreePath: "/path/to/worktree", } diff --git a/pkg/config/pager_config.go b/pkg/config/pager_config.go index 6d7d3973931..e721da0e8f9 100644 --- a/pkg/config/pager_config.go +++ b/pkg/config/pager_config.go @@ -8,29 +8,75 @@ import ( type PagerConfig struct { getUserConfig func() *UserConfig + pagerIndex int } func NewPagerConfig(getUserConfig func() *UserConfig) *PagerConfig { return &PagerConfig{getUserConfig: getUserConfig} } +func (self *PagerConfig) currentPagerConfig() *PagingConfig { + pagers := self.getUserConfig().Git.Pagers + if len(pagers) == 0 { + return nil + } + + // Guard against the pager index being out of range, which can happen if the user + // has removed pagers from their config file while lazygit is running. + if self.pagerIndex >= len(pagers) { + self.pagerIndex = 0 + } + + return &pagers[self.pagerIndex] +} + func (self *PagerConfig) GetPagerCommand(width int) string { + currentPagerConfig := self.currentPagerConfig() + if currentPagerConfig == nil { + return "" + } + templateValues := map[string]string{ "columnWidth": strconv.Itoa(width/2 - 6), } - pagerTemplate := string(self.getUserConfig().Git.Paging.Pager) + pagerTemplate := string(currentPagerConfig.Pager) return utils.ResolvePlaceholderString(pagerTemplate, templateValues) } func (self *PagerConfig) GetColorArg() string { - return self.getUserConfig().Git.Paging.ColorArg + currentPagerConfig := self.currentPagerConfig() + if currentPagerConfig == nil { + return "always" + } + + colorArg := currentPagerConfig.ColorArg + if colorArg == "" { + return "always" + } + return colorArg } func (self *PagerConfig) GetExternalDiffCommand() string { - return self.getUserConfig().Git.Paging.ExternalDiffCommand + currentPagerConfig := self.currentPagerConfig() + if currentPagerConfig == nil { + return "" + } + return currentPagerConfig.ExternalDiffCommand } func (self *PagerConfig) GetUseExternalDiffGitConfig() bool { - return self.getUserConfig().Git.Paging.UseExternalDiffGitConfig + currentPagerConfig := self.currentPagerConfig() + if currentPagerConfig == nil { + return false + } + return currentPagerConfig.UseExternalDiffGitConfig +} + +func (self *PagerConfig) CyclePagers() { + self.pagerIndex = (self.pagerIndex + 1) % len(self.getUserConfig().Git.Pagers) +} + +func (self *PagerConfig) CurrentPagerIndex() (int, int) { + return self.pagerIndex, len(self.getUserConfig().Git.Pagers) } diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index a951de2e2ed..6635ff06ab8 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -233,8 +233,30 @@ type SpinnerConfig struct { } type GitConfig struct { - // See https://github.com/jesseduffield/lazygit/blob/master/docs/Custom_Pagers.md - Paging PagingConfig `yaml:"paging"` + // Array of pagers. Each entry has the following format: + // [dev] The following documentation is duplicated from the PagingConfig struct below. + // + // # Value of the --color arg in the git diff command. Some pagers want + // # this to be set to 'always' and some want it set to 'never' + // colorArg: "always" + // + // # e.g. + // # diff-so-fancy + // # delta --dark --paging=never + // # ydiff -p cat -s --wrap --width={{columnWidth}} + // pager: "" + // + // # e.g. 'difft --color=always' + // externalDiffCommand: "" + // + // # If true, Lazygit will use git's `diff.external` config for paging. + // # The advantage over `externalDiffCommand` is that this can be + // # configured per file type in .gitattributes; see + // # https://git-scm.com/docs/gitattributes#_defining_an_external_diff_driver. + // useExternalDiffGitConfig: false + // + // See https://github.com/jesseduffield/lazygit/blob/master/docs/Custom_Pagers.md for more information. + Pagers []PagingConfig `yaml:"pagers"` // Config relating to committing Commit CommitConfig `yaml:"commit"` // Config relating to merging @@ -301,6 +323,7 @@ func (PagerType) JSONSchemaExtend(schema *jsonschema.Schema) { } } +// [dev] This documentation is duplicated in the GitConfig struct. If you make changes here, make them there too. type PagingConfig struct { // Value of the --color arg in the git diff command. Some pagers want this to be set to 'always' and some want it set to 'never' ColorArg string `yaml:"colorArg" jsonschema:"enum=always,enum=never"` @@ -441,6 +464,7 @@ type KeybindingUniversalConfig struct { PrevTab string `yaml:"prevTab"` NextScreenMode string `yaml:"nextScreenMode"` PrevScreenMode string `yaml:"prevScreenMode"` + CyclePagers string `yaml:"cyclePagers"` Undo string `yaml:"undo"` Redo string `yaml:"redo"` FilteringMenu string `yaml:"filteringMenu"` @@ -784,11 +808,6 @@ func GetDefaultConfig() *UserConfig { SwitchTabsWithPanelJumpKeys: false, }, Git: GitConfig{ - Paging: PagingConfig{ - ColorArg: "always", - Pager: "", - ExternalDiffCommand: "", - }, Commit: CommitConfig{ SignOff: false, AutoWrapCommitMessage: true, @@ -904,6 +923,7 @@ func GetDefaultConfig() *UserConfig { PrevTab: "[", NextScreenMode: "+", PrevScreenMode: "_", + CyclePagers: "|", Undo: "z", Redo: "Z", FilteringMenu: "", diff --git a/pkg/gui/controllers/global_controller.go b/pkg/gui/controllers/global_controller.go index 734e6551608..1ae56068561 100644 --- a/pkg/gui/controllers/global_controller.go +++ b/pkg/gui/controllers/global_controller.go @@ -1,6 +1,8 @@ package controllers import ( + "fmt" + "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -58,6 +60,13 @@ func (self *GlobalController) GetKeybindings(opts types.KeybindingsOpts) []*type Handler: opts.Guards.NoPopupPanel(self.prevScreenMode), Description: self.c.Tr.PrevScreenMode, }, + { + Key: opts.GetKey(opts.Config.Universal.CyclePagers), + Handler: opts.Guards.NoPopupPanel(self.cyclePagers), + GetDisabledReason: self.canCyclePagers, + Description: self.c.Tr.CyclePagers, + Tooltip: self.c.Tr.CyclePagersTooltip, + }, { Key: opts.GetKey(opts.Config.Universal.Return), Modifier: gocui.ModNone, @@ -171,6 +180,27 @@ func (self *GlobalController) prevScreenMode() error { return (&ScreenModeActions{c: self.c}).Prev() } +func (self *GlobalController) cyclePagers() error { + self.c.State().GetPagerConfig().CyclePagers() + if self.c.Context().CurrentSide().GetKey() == self.c.Context().Current().GetKey() { + self.c.Context().CurrentSide().HandleFocus(types.OnFocusOpts{}) + } + + current, total := self.c.State().GetPagerConfig().CurrentPagerIndex() + self.c.Toast(fmt.Sprintf("Selected pager %d of %d", current+1, total)) + return nil +} + +func (self *GlobalController) canCyclePagers() *types.DisabledReason { + _, total := self.c.State().GetPagerConfig().CurrentPagerIndex() + if total <= 1 { + return &types.DisabledReason{ + Text: self.c.Tr.CyclePagersDisabledReason, + } + } + return nil +} + func (self *GlobalController) createOptionsMenu() error { return (&OptionsMenuAction{c: self.c}).Call() } diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 30123efaaa2..86ba163aadb 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -585,6 +585,9 @@ type TranslationSet struct { ViewResetToUpstreamOptions string NextScreenMode string PrevScreenMode string + CyclePagers string + CyclePagersTooltip string + CyclePagersDisabledReason string StartSearch string StartFilter string Keybindings string @@ -1678,6 +1681,9 @@ func EnglishTranslationSet() *TranslationSet { ViewResetToUpstreamOptions: "View upstream reset options", NextScreenMode: "Next screen mode (normal/half/fullscreen)", PrevScreenMode: "Prev screen mode", + CyclePagers: "Cycle pagers", + CyclePagersTooltip: "Choose the next pager in the list of configured pagers", + CyclePagersDisabledReason: "No other pagers configured", StartSearch: "Search the current view by text", StartFilter: "Filter the current view by text", KeybindingsLegend: "Legend: `` means ctrl+b, `` means alt+b, `B` means shift+b", diff --git a/schema/config.json b/schema/config.json index 19554058b5e..db86f4f0037 100644 --- a/schema/config.json +++ b/schema/config.json @@ -285,9 +285,12 @@ }, "GitConfig": { "properties": { - "paging": { - "$ref": "#/$defs/PagingConfig", - "description": "See https://github.com/jesseduffield/lazygit/blob/master/docs/Custom_Pagers.md" + "pagers": { + "items": { + "$ref": "#/$defs/PagingConfig" + }, + "type": "array", + "description": "Array of pagers. Each entry has the following format:\n\n # Value of the --color arg in the git diff command. Some pagers want\n # this to be set to 'always' and some want it set to 'never'\n colorArg: \"always\"\n\n # e.g.\n # diff-so-fancy\n # delta --dark --paging=never\n # ydiff -p cat -s --wrap --width={{columnWidth}}\n pager: \"\"\n\n # e.g. 'difft --color=always'\n externalDiffCommand: \"\"\n\n # If true, Lazygit will use git's `diff.external` config for paging.\n # The advantage over `externalDiffCommand` is that this can be\n # configured per file type in .gitattributes; see\n # https://git-scm.com/docs/gitattributes#_defining_an_external_diff_driver.\n useExternalDiffGitConfig: false\n\nSee https://github.com/jesseduffield/lazygit/blob/master/docs/Custom_Pagers.md for more information." }, "commit": { "$ref": "#/$defs/CommitConfig", @@ -1464,6 +1467,10 @@ "type": "string", "default": "_" }, + "cyclePagers": { + "type": "string", + "default": "|" + }, "undo": { "type": "string", "default": "z" @@ -1667,13 +1674,11 @@ "always", "never" ], - "description": "Value of the --color arg in the git diff command. Some pagers want this to be set to 'always' and some want it set to 'never'", - "default": "always" + "description": "Value of the --color arg in the git diff command. Some pagers want this to be set to 'always' and some want it set to 'never'" }, "pager": { "type": "string", "description": "e.g.\ndiff-so-fancy\ndelta --dark --paging=never\nydiff -p cat -s --wrap --width={{columnWidth}}", - "default": "", "examples": [ "delta --dark --paging=never", "diff-so-fancy", @@ -1686,13 +1691,11 @@ }, "useExternalDiffGitConfig": { "type": "boolean", - "description": "If true, Lazygit will use git's `diff.external` config for paging. The advantage over `externalDiffCommand` is that this can be configured per file type in .gitattributes; see https://git-scm.com/docs/gitattributes#_defining_an_external_diff_driver.", - "default": false + "description": "If true, Lazygit will use git's `diff.external` config for paging. The advantage over `externalDiffCommand` is that this can be configured per file type in .gitattributes; see https://git-scm.com/docs/gitattributes#_defining_an_external_diff_driver." } }, "additionalProperties": false, - "type": "object", - "description": "See https://github.com/jesseduffield/lazygit/blob/master/docs/Custom_Pagers.md" + "type": "object" }, "RefresherConfig": { "properties": { From 823b2e9aabf763f0287888ceefc9cb2b9cf477d9 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 8 Oct 2025 17:31:17 +0200 Subject: [PATCH 4/5] Update cheatsheets --- docs/keybindings/Keybindings_en.md | 1 + docs/keybindings/Keybindings_ja.md | 1 + docs/keybindings/Keybindings_ko.md | 1 + docs/keybindings/Keybindings_nl.md | 1 + docs/keybindings/Keybindings_pl.md | 1 + docs/keybindings/Keybindings_pt.md | 1 + docs/keybindings/Keybindings_ru.md | 1 + docs/keybindings/Keybindings_zh-CN.md | 1 + docs/keybindings/Keybindings_zh-TW.md | 1 + 9 files changed, 9 insertions(+) diff --git a/docs/keybindings/Keybindings_en.md b/docs/keybindings/Keybindings_en.md index e42ebee1c51..cf78b8574a8 100644 --- a/docs/keybindings/Keybindings_en.md +++ b/docs/keybindings/Keybindings_en.md @@ -24,6 +24,7 @@ _Legend: `` means ctrl+b, `` means alt+b, `B` means shift+b_ | `` R `` | Refresh | Refresh the git state (i.e. run `git status`, `git branch`, etc in background to update the contents of panels). This does not run `git fetch`. | | `` + `` | Next screen mode (normal/half/fullscreen) | | | `` _ `` | Prev screen mode | | +| `` | `` | Cycle pagers | Choose the next pager in the list of configured pagers | | `` `` | Cancel | | | `` ? `` | Open keybindings menu | | | `` `` | View filter options | View options for filtering the commit log, so that only commits matching the filter are shown. | diff --git a/docs/keybindings/Keybindings_ja.md b/docs/keybindings/Keybindings_ja.md index 207b0d39749..198578d0929 100644 --- a/docs/keybindings/Keybindings_ja.md +++ b/docs/keybindings/Keybindings_ja.md @@ -24,6 +24,7 @@ _凡例:`<c-b>` はctrl+b、`<a-b>` はalt+b、`B` はshift+bを意味 | `` R `` | 更新 | Gitの状態を更新します(`git status`、`git branch`などをバックグラウンドで実行してパネルの内容を更新します)。これは`git fetch`を実行しません。 | | `` + `` | 次の画面モード(通常/半分/全画面) | | | `` _ `` | 前の画面モード | | +| `` | `` | Cycle pagers | Choose the next pager in the list of configured pagers | | `` `` | キャンセル | | | `` ? `` | キーバインディングメニューを開く | | | `` `` | フィルターオプションを表示 | コミットログのフィルタリングオプションを表示し、フィルタに一致するコミットのみを表示します。 | diff --git a/docs/keybindings/Keybindings_ko.md b/docs/keybindings/Keybindings_ko.md index e0d83760a54..5c4f1ad7b3a 100644 --- a/docs/keybindings/Keybindings_ko.md +++ b/docs/keybindings/Keybindings_ko.md @@ -24,6 +24,7 @@ _Legend: `` means ctrl+b, `` means alt+b, `B` means shift+b_ | `` R `` | 새로고침 | Refresh the git state (i.e. run `git status`, `git branch`, etc in background to update the contents of panels). This does not run `git fetch`. | | `` + `` | 다음 스크린 모드 (normal/half/fullscreen) | | | `` _ `` | 이전 스크린 모드 | | +| `` | `` | Cycle pagers | Choose the next pager in the list of configured pagers | | `` `` | 취소 | | | `` ? `` | 매뉴 열기 | | | `` `` | View filter-by-path options | View options for filtering the commit log, so that only commits matching the filter are shown. | diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md index 9fea316a725..d74247d717d 100644 --- a/docs/keybindings/Keybindings_nl.md +++ b/docs/keybindings/Keybindings_nl.md @@ -24,6 +24,7 @@ _Legend: `` means ctrl+b, `` means alt+b, `B` means shift+b_ | `` R `` | Verversen | Refresh the git state (i.e. run `git status`, `git branch`, etc in background to update the contents of panels). This does not run `git fetch`. | | `` + `` | Volgende scherm modus (normaal/half/groot) | | | `` _ `` | Vorige scherm modus | | +| `` | `` | Cycle pagers | Choose the next pager in the list of configured pagers | | `` `` | Annuleren | | | `` ? `` | Open menu | | | `` `` | Bekijk scoping opties | View options for filtering the commit log, so that only commits matching the filter are shown. | diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md index 92b9c63880f..5d5d53609d3 100644 --- a/docs/keybindings/Keybindings_pl.md +++ b/docs/keybindings/Keybindings_pl.md @@ -24,6 +24,7 @@ _Legenda: `` oznacza ctrl+b, `` oznacza alt+b, `B` oznacza shift+b_ | `` R `` | Odśwież | Odśwież stan git (tj. uruchom `git status`, `git branch`, itp. w tle, aby zaktualizować zawartość paneli). To nie uruchamia `git fetch`. | | `` + `` | Następny tryb ekranu (normalny/półpełny/pełnoekranowy) | | | `` _ `` | Poprzedni tryb ekranu | | +| `` | `` | Cycle pagers | Choose the next pager in the list of configured pagers | | `` `` | Anuluj | | | `` ? `` | Otwórz menu przypisań klawiszy | | | `` `` | Pokaż opcje filtrowania | Pokaż opcje filtrowania dziennika commitów, tak aby pokazywane były tylko commity pasujące do filtra. | diff --git a/docs/keybindings/Keybindings_pt.md b/docs/keybindings/Keybindings_pt.md index 1ae9178c1c2..34094ba2bb2 100644 --- a/docs/keybindings/Keybindings_pt.md +++ b/docs/keybindings/Keybindings_pt.md @@ -24,6 +24,7 @@ _Legend: `` means ctrl+b, `` means alt+b, `B` means shift+b_ | `` R `` | Atualizar | Atualize o estado do git (ou seja, execute `git status`, `git branch`, etc em segundo plano para atualizar o conteúdo de painéis). Isso não executa `git fetch`. | | `` + `` | Next screen mode (normal/half/fullscreen) | | | `` _ `` | Prev screen mode | | +| `` | `` | Cycle pagers | Choose the next pager in the list of configured pagers | | `` `` | Cancelar | | | `` ? `` | Open keybindings menu | | | `` `` | View filter options | View options for filtering the commit log, so that only commits matching the filter are shown. | diff --git a/docs/keybindings/Keybindings_ru.md b/docs/keybindings/Keybindings_ru.md index 4c46c54793e..c1cd6f53c13 100644 --- a/docs/keybindings/Keybindings_ru.md +++ b/docs/keybindings/Keybindings_ru.md @@ -24,6 +24,7 @@ _Связки клавиш_ | `` R `` | Обновить | Refresh the git state (i.e. run `git status`, `git branch`, etc in background to update the contents of panels). This does not run `git fetch`. | | `` + `` | Следующий режим экрана (нормальный/полуэкранный/полноэкранный) | | | `` _ `` | Предыдущий режим экрана | | +| `` | `` | Cycle pagers | Choose the next pager in the list of configured pagers | | `` `` | Отменить | | | `` ? `` | Открыть меню | | | `` `` | Просмотреть параметры фильтрации по пути | View options for filtering the commit log, so that only commits matching the filter are shown. | diff --git a/docs/keybindings/Keybindings_zh-CN.md b/docs/keybindings/Keybindings_zh-CN.md index ffc50aedae9..799d7e511b2 100644 --- a/docs/keybindings/Keybindings_zh-CN.md +++ b/docs/keybindings/Keybindings_zh-CN.md @@ -24,6 +24,7 @@ _图例:`` 意味着ctrl+b, `意味着Alt+b, `B` 意味着shift+b_ | `` R `` | 刷新 | 刷新git状态(即在后台上运行`git status`,`git branch`等命令以更新面板内容) 不会运行`git fetch` | | `` + `` | 下一屏模式(正常/半屏/全屏) | | | `` _ `` | 上一屏模式 | | +| `` | `` | Cycle pagers | Choose the next pager in the list of configured pagers | | `` `` | 取消 | | | `` ? `` | 打开菜单 | | | `` `` | 查看按路径过滤选项 | 查看用于过滤提交日志的选项,以便仅显示与过滤器匹配的提交。 | diff --git a/docs/keybindings/Keybindings_zh-TW.md b/docs/keybindings/Keybindings_zh-TW.md index 2e7e58e7e17..9c9f2e913e8 100644 --- a/docs/keybindings/Keybindings_zh-TW.md +++ b/docs/keybindings/Keybindings_zh-TW.md @@ -24,6 +24,7 @@ _說明:`` 表示 Ctrl+B、`` 表示 Alt+B,`B`表示 Shift+B | `` R `` | 重新整理 | Refresh the git state (i.e. run `git status`, `git branch`, etc in background to update the contents of panels). This does not run `git fetch`. | | `` + `` | 下一個螢幕模式(常規/半螢幕/全螢幕) | | | `` _ `` | 上一個螢幕模式 | | +| `` | `` | Cycle pagers | Choose the next pager in the list of configured pagers | | `` `` | 取消 | | | `` ? `` | 開啟選單 | | | `` `` | 檢視篩選路徑選項 | View options for filtering the commit log, so that only commits matching the filter are shown. | From 32bf6d685c328a8867fa100a05694f645c74ded8 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Fri, 10 Oct 2025 15:23:32 +0200 Subject: [PATCH 5/5] Add config migration of paging section to pagers array --- pkg/config/app_config.go | 36 +++++++++++++ pkg/config/app_config_test.go | 95 +++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index dde4b538248..8205f7ef6cf 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -310,6 +310,11 @@ func computeMigratedConfig(path string, content []byte, changes *ChangesSet) ([] return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %w", path, err) } + err = migratePagers(&rootNode, changes) + if err != nil { + return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %w", path, err) + } + // Add more migrations here... if reflect.DeepEqual(rootNode, originalCopy) { @@ -469,6 +474,37 @@ func migrateAllBranchesLogCmd(rootNode *yaml.Node, changes *ChangesSet) error { }) } +func migratePagers(rootNode *yaml.Node, changes *ChangesSet) error { + return yaml_utils.TransformNode(rootNode, []string{"git"}, func(gitNode *yaml.Node) error { + pagingKeyNode, pagingValueNode := yaml_utils.LookupKey(gitNode, "paging") + if pagingKeyNode == nil || pagingValueNode.Kind != yaml.MappingNode { + // If there's no "paging" section (or it's not an object), there's nothing to do + return nil + } + + pagersKeyNode, _ := yaml_utils.LookupKey(gitNode, "pagers") + if pagersKeyNode != nil { + // Conversely, if there *is* already a "pagers" array, we also have nothing to do. + // This covers the case where the user keeps both the "paging" section and the "pagers" + // array for the sake of easier testing of old versions. + return nil + } + + pagingKeyNode.Value = "pagers" + pagingContentCopy := pagingValueNode.Content + pagingValueNode.Kind = yaml.SequenceNode + pagingValueNode.Tag = "!!seq" + pagingValueNode.Content = []*yaml.Node{{ + Kind: yaml.MappingNode, + Content: pagingContentCopy, + }} + + changes.Add("Moved git.paging object to git.pagers array") + + return nil + }) +} + func (c *AppConfig) GetDebug() bool { return c.debug } diff --git a/pkg/config/app_config_test.go b/pkg/config/app_config_test.go index cc7ffea790d..1109256a9d3 100644 --- a/pkg/config/app_config_test.go +++ b/pkg/config/app_config_test.go @@ -1089,3 +1089,98 @@ func TestAllBranchesLogCmdMigrations(t *testing.T) { }) } } + +func TestPagerMigration(t *testing.T) { + scenarios := []struct { + name string + input string + expected string + expectedDidChange bool + expectedChanges []string + }{ + { + name: "Incomplete Configuration Passes uneventfully", + input: "git:", + expectedDidChange: false, + expectedChanges: []string{}, + }, + { + name: "No paging section", + input: `git: + autoFetch: true +`, + expected: `git: + autoFetch: true +`, + expectedDidChange: false, + expectedChanges: []string{}, + }, + { + name: "Both paging and pagers exist", + input: `git: + paging: + pager: delta --dark --paging=never + pagers: + - diff: diff-so-fancy +`, + expected: `git: + paging: + pager: delta --dark --paging=never + pagers: + - diff: diff-so-fancy +`, + expectedDidChange: false, + expectedChanges: []string{}, + }, + { + name: "paging is not an object", + input: `git: + paging: 5 +`, + expected: `git: + paging: 5 +`, + expectedDidChange: false, + expectedChanges: []string{}, + }, + { + name: "paging is moved to pagers array (keeping the order)", + input: `git: + paging: + pager: delta --dark --paging=never + autoFetch: true +`, + expected: `git: + pagers: + - pager: delta --dark --paging=never + autoFetch: true +`, + expectedDidChange: true, + expectedChanges: []string{"Moved git.paging object to git.pagers array"}, + }, + { + name: "paging is moved to pagers array even if empty", + input: `git: + paging: {} +`, + expected: `git: + pagers: [{}] +`, + expectedDidChange: true, + expectedChanges: []string{"Moved git.paging object to git.pagers array"}, + }, + } + + for _, s := range scenarios { + t.Run(s.name, func(t *testing.T) { + changes := NewChangesSet() + actual, didChange, err := computeMigratedConfig("path doesn't matter", []byte(s.input), changes) + assert.NoError(t, err) + assert.Equal(t, s.expectedDidChange, didChange) + if didChange { + assert.Equal(t, s.expected, string(actual)) + } + assert.Equal(t, s.expectedChanges, changes.ToSliceFromOldest()) + }) + } +}