diff --git a/docs-master/Config.md b/docs-master/Config.md index 6de2ad978..07942c659 100644 --- a/docs-master/Config.md +++ b/docs-master/Config.md @@ -342,6 +342,11 @@ gui: git: # Array of pagers. Each entry has the following format: # + # # A name for the pager, shown in the notification when cycling pagers. + # # If not set, the name is derived from the first word of the pager + # # command (or of the external diff command). + # name: "" + # # # 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" diff --git a/pkg/config/pager_config.go b/pkg/config/pager_config.go index e721da0e8..1b562ccd7 100644 --- a/pkg/config/pager_config.go +++ b/pkg/config/pager_config.go @@ -2,6 +2,7 @@ package config import ( "strconv" + "strings" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -80,3 +81,41 @@ func (self *PagerConfig) CyclePagers() { func (self *PagerConfig) CurrentPagerIndex() (int, int) { return self.pagerIndex, len(self.getUserConfig().Git.Pagers) } + +// CurrentPagerName returns a name for the current pager, suitable for showing +// to the user. It returns an empty string if no name can be derived; callers +// should substitute a localized fallback in that case. +func (self *PagerConfig) CurrentPagerName() string { + currentPagerConfig := self.currentPagerConfig() + if currentPagerConfig == nil { + return "" + } + return currentPagerConfig.displayName() +} + +// CurrentPagerUsesGitConfigDiff reports whether the current pager defers to +// git's own external diff config. Such an entry has no name we can derive (the +// actual command may even vary per file via .gitattributes), so callers show a +// generic label rather than treating it like the default no-pager entry. +func (self *PagerConfig) CurrentPagerUsesGitConfigDiff() bool { + currentPagerConfig := self.currentPagerConfig() + return currentPagerConfig != nil && currentPagerConfig.UseExternalDiffGitConfig +} + +func (self *PagingConfig) displayName() string { + if self.Name != "" { + return self.Name + } + if word := firstWord(string(self.Pager)); word != "" { + return word + } + return firstWord(self.ExternalDiffCommand) +} + +func firstWord(command string) string { + fields := strings.Fields(command) + if len(fields) == 0 { + return "" + } + return fields[0] +} diff --git a/pkg/config/pager_config_test.go b/pkg/config/pager_config_test.go new file mode 100644 index 000000000..e2618d5bd --- /dev/null +++ b/pkg/config/pager_config_test.go @@ -0,0 +1,57 @@ +package config + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCurrentPagerName(t *testing.T) { + scenarios := []struct { + name string + pager PagingConfig + expected string + }{ + { + name: "explicit name takes precedence over the command", + pager: PagingConfig{Name: "delta side-by-side", Pager: "delta --side-by-side"}, + expected: "delta side-by-side", + }, + { + name: "derived from the first word of the pager command", + pager: PagingConfig{Pager: "delta --side-by-side"}, + expected: "delta", + }, + { + name: "surrounding whitespace in the command is ignored", + pager: PagingConfig{Pager: " diff-so-fancy "}, + expected: "diff-so-fancy", + }, + { + name: "falls back to the external diff command when there is no pager", + pager: PagingConfig{ExternalDiffCommand: "difft --color=always"}, + expected: "difft", + }, + { + name: "no name can be derived", + pager: PagingConfig{UseExternalDiffGitConfig: true}, + expected: "", + }, + } + + for _, s := range scenarios { + t.Run(s.name, func(t *testing.T) { + userConfig := &UserConfig{} + userConfig.Git.Pagers = []PagingConfig{s.pager} + config := NewPagerConfig(func() *UserConfig { return userConfig }) + + assert.Equal(t, s.expected, config.CurrentPagerName()) + }) + } +} + +func TestCurrentPagerNameWithoutPagers(t *testing.T) { + config := NewPagerConfig(func() *UserConfig { return &UserConfig{} }) + + assert.Equal(t, "", config.CurrentPagerName()) +} diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index acadc8e80..aa2d945d6 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -256,6 +256,11 @@ type GitConfig struct { // Array of pagers. Each entry has the following format: // [dev] The following documentation is duplicated from the PagingConfig struct below. // + // # A name for the pager, shown in the notification when cycling pagers. + // # If not set, the name is derived from the first word of the pager + // # command (or of the external diff command). + // name: "" + // // # 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" @@ -347,6 +352,8 @@ 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 { + // A name for the pager, shown in the notification when cycling pagers. If not set, the name is derived from the first word of the pager command (or of the external diff command). + Name string `yaml:"name"` // 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"` // e.g. diff --git a/pkg/gui/controllers/global_controller.go b/pkg/gui/controllers/global_controller.go index d2ca28c60..7879ab7ac 100644 --- a/pkg/gui/controllers/global_controller.go +++ b/pkg/gui/controllers/global_controller.go @@ -1,10 +1,11 @@ package controllers import ( - "fmt" + "strconv" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/jesseduffield/lazygit/pkg/utils" ) type GlobalController struct { @@ -166,8 +167,21 @@ func (self *GlobalController) cyclePagers() error { currentSide.HandleRenderToMain() } - current, total := self.c.State().GetPagerConfig().CurrentPagerIndex() - self.c.Toast(fmt.Sprintf("Selected pager %d of %d", current+1, total)) + pagerConfig := self.c.State().GetPagerConfig() + current, total := pagerConfig.CurrentPagerIndex() + name := pagerConfig.CurrentPagerName() + if name == "" { + if pagerConfig.CurrentPagerUsesGitConfigDiff() { + name = self.c.Tr.ExternalDiffPagerName + } else { + name = self.c.Tr.DefaultPagerName + } + } + self.c.Toast(utils.ResolvePlaceholderString(self.c.Tr.SelectedPager, map[string]string{ + "name": name, + "current": strconv.Itoa(current + 1), + "total": strconv.Itoa(total), + })) return nil } diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index ef996a198..7ff5137f6 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -608,6 +608,9 @@ type TranslationSet struct { CyclePagers string CyclePagersTooltip string CyclePagersDisabledReason string + SelectedPager string + DefaultPagerName string + ExternalDiffPagerName string StartSearch string StartFilter string SelectRemoteRepository string @@ -1739,6 +1742,9 @@ func EnglishTranslationSet() *TranslationSet { CyclePagers: "Cycle pagers", CyclePagersTooltip: "Choose the next pager in the list of configured pagers.", CyclePagersDisabledReason: "No other pagers configured", + SelectedPager: "Pager: {{.name}} ({{.current}} of {{.total}})", + DefaultPagerName: "(default)", + ExternalDiffPagerName: "(external diff)", StartSearch: "Search the current view by text", StartFilter: "Filter the current view by text", SelectRemoteRepository: "Select base repository for pull requests", diff --git a/schema-master/config.json b/schema-master/config.json index 9042986aa..816c46213 100644 --- a/schema-master/config.json +++ b/schema-master/config.json @@ -321,7 +321,7 @@ "$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\n'pager', 'externalDiffCommand', and 'useExternalDiffGitConfig' are mutually exclusive; set at most one per entry.\n\nSee https://github.com/jesseduffield/lazygit/blob/master/docs/Custom_Pagers.md for more information." + "description": "Array of pagers. Each entry has the following format:\n\n # A name for the pager, shown in the notification when cycling pagers.\n # If not set, the name is derived from the first word of the pager\n # command (or of the external diff command).\n name: \"\"\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\n'pager', 'externalDiffCommand', and 'useExternalDiffGitConfig' are mutually exclusive; set at most one per entry.\n\nSee https://github.com/jesseduffield/lazygit/blob/master/docs/Custom_Pagers.md for more information." }, "commit": { "$ref": "#/$defs/CommitConfig", @@ -3488,6 +3488,10 @@ }, "PagingConfig": { "properties": { + "name": { + "type": "string", + "description": "A name for the pager, shown in the notification when cycling pagers. If not set, the name is derived from the first word of the pager command (or of the external diff command)." + }, "colorArg": { "type": "string", "enum": [