mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 07:36:27 -04:00
When cycling pagers, "Selected pager 2 of 3" gives no clue which pager you landed on; with several configured you have to remember the order. Include the pager's name in the toast instead. The name is normally derived from the first word of the pager command, but that isn't always enough: two entries can share a command but differ in options (e.g. "delta" and "delta --side-by-side"), and an entry may have no command at all (the default entry, or when using useExternalDiffGitConfig). So add an optional `name` field that overrides the derived name. The message was also hardcoded in English; localize it while we're here. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
259 lines
7.8 KiB
Go
259 lines
7.8 KiB
Go
package controllers
|
|
|
|
import (
|
|
"strconv"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
|
)
|
|
|
|
type GlobalController struct {
|
|
baseController
|
|
c *ControllerCommon
|
|
}
|
|
|
|
func NewGlobalController(
|
|
c *ControllerCommon,
|
|
) *GlobalController {
|
|
return &GlobalController{
|
|
baseController: baseController{},
|
|
c: c,
|
|
}
|
|
}
|
|
|
|
func (self *GlobalController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
|
return []*types.Binding{
|
|
{
|
|
Keys: opts.GetKeys(opts.Config.Universal.ExecuteShellCommand),
|
|
Handler: self.shellCommand,
|
|
Description: self.c.Tr.ExecuteShellCommand,
|
|
Tooltip: self.c.Tr.ExecuteShellCommandTooltip,
|
|
OpensMenu: true,
|
|
},
|
|
{
|
|
Keys: opts.GetKeys(opts.Config.Universal.CreatePatchOptionsMenu),
|
|
Handler: self.createCustomPatchOptionsMenu,
|
|
Description: self.c.Tr.ViewPatchOptions,
|
|
OpensMenu: true,
|
|
},
|
|
{
|
|
Keys: opts.GetKeys(opts.Config.Universal.CreateRebaseOptionsMenu),
|
|
Handler: opts.Guards.NoPopupPanel(self.c.Helpers().MergeAndRebase.CreateRebaseOptionsMenu),
|
|
Description: self.c.Tr.ViewMergeRebaseOptions,
|
|
Tooltip: self.c.Tr.ViewMergeRebaseOptionsTooltip,
|
|
OpensMenu: true,
|
|
GetDisabledReason: self.canShowRebaseOptions,
|
|
},
|
|
{
|
|
Keys: opts.GetKeys(opts.Config.Universal.Refresh),
|
|
Handler: opts.Guards.NoPopupPanel(self.refresh),
|
|
Description: self.c.Tr.Refresh,
|
|
Tooltip: self.c.Tr.RefreshTooltip,
|
|
},
|
|
{
|
|
Keys: opts.GetKeys(opts.Config.Universal.NextScreenMode),
|
|
Handler: opts.Guards.NoPopupPanel(self.nextScreenMode),
|
|
Description: self.c.Tr.NextScreenMode,
|
|
},
|
|
{
|
|
Keys: opts.GetKeys(opts.Config.Universal.PrevScreenMode),
|
|
Handler: opts.Guards.NoPopupPanel(self.prevScreenMode),
|
|
Description: self.c.Tr.PrevScreenMode,
|
|
},
|
|
{
|
|
Keys: opts.GetKeys(opts.Config.Universal.CyclePagers),
|
|
Handler: opts.Guards.NoPopupPanel(self.cyclePagers),
|
|
GetDisabledReason: self.canCyclePagers,
|
|
Description: self.c.Tr.CyclePagers,
|
|
Tooltip: self.c.Tr.CyclePagersTooltip,
|
|
},
|
|
{
|
|
Keys: opts.GetKeys(opts.Config.Universal.Return),
|
|
Handler: self.escape,
|
|
Description: self.c.Tr.Cancel,
|
|
DescriptionFunc: self.escapeDescription,
|
|
GetDisabledReason: self.escapeEnabled,
|
|
DisplayOnScreen: true,
|
|
},
|
|
{
|
|
ViewName: "",
|
|
Keys: opts.GetKeys(opts.Config.Universal.OptionMenu),
|
|
Description: self.c.Tr.OpenKeybindingsMenu,
|
|
ShortDescription: self.c.Tr.Keybindings,
|
|
Handler: self.createOptionsMenu,
|
|
GetDisabledReason: self.optionsMenuDisabledReason,
|
|
OpensMenu: true,
|
|
DisplayOnScreen: true,
|
|
},
|
|
{
|
|
ViewName: "",
|
|
Keys: opts.GetKeys(opts.Config.Universal.FilteringMenu),
|
|
Handler: opts.Guards.NoPopupPanel(self.createFilteringMenu),
|
|
Description: self.c.Tr.OpenFilteringMenu,
|
|
Tooltip: self.c.Tr.OpenFilteringMenuTooltip,
|
|
OpensMenu: true,
|
|
},
|
|
{
|
|
Keys: opts.GetKeys(opts.Config.Universal.DiffingMenu),
|
|
Handler: opts.Guards.NoPopupPanel(self.createDiffingMenu),
|
|
Description: self.c.Tr.ViewDiffingOptions,
|
|
Tooltip: self.c.Tr.ViewDiffingOptionsTooltip,
|
|
OpensMenu: true,
|
|
},
|
|
{
|
|
Keys: opts.GetKeys(opts.Config.Universal.Quit),
|
|
Description: self.c.Tr.Quit,
|
|
Handler: self.quit,
|
|
},
|
|
{
|
|
Keys: opts.GetKeys(opts.Config.Universal.QuitWithoutChangingDirectory),
|
|
Handler: self.quitWithoutChangingDirectory,
|
|
},
|
|
{
|
|
Keys: opts.GetKeys(opts.Config.Universal.SuspendApp),
|
|
Handler: self.c.Helpers().SuspendResume.SuspendApp,
|
|
Description: self.c.Tr.SuspendApp,
|
|
GetDisabledReason: func() *types.DisabledReason {
|
|
if !self.c.Helpers().SuspendResume.CanSuspendApp() {
|
|
return &types.DisabledReason{
|
|
Text: self.c.Tr.CannotSuspendApp,
|
|
}
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
Keys: opts.GetKeys(opts.Config.Universal.ToggleWhitespaceInDiffView),
|
|
Handler: self.toggleWhitespace,
|
|
Description: self.c.Tr.ToggleWhitespaceInDiffView,
|
|
Tooltip: self.c.Tr.ToggleWhitespaceInDiffViewTooltip,
|
|
},
|
|
}
|
|
}
|
|
|
|
func (self *GlobalController) Context() types.Context {
|
|
return nil
|
|
}
|
|
|
|
func (self *GlobalController) shellCommand() error {
|
|
return (&ShellCommandAction{c: self.c}).Call()
|
|
}
|
|
|
|
func (self *GlobalController) createCustomPatchOptionsMenu() error {
|
|
return (&CustomPatchOptionsMenuAction{c: self.c}).Call()
|
|
}
|
|
|
|
func (self *GlobalController) refresh() error {
|
|
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
|
return nil
|
|
}
|
|
|
|
func (self *GlobalController) nextScreenMode() error {
|
|
return (&ScreenModeActions{c: self.c}).Next()
|
|
}
|
|
|
|
func (self *GlobalController) prevScreenMode() error {
|
|
return (&ScreenModeActions{c: self.c}).Prev()
|
|
}
|
|
|
|
func (self *GlobalController) cyclePagers() error {
|
|
self.c.State().GetPagerConfig().CyclePagers()
|
|
currentSide := self.c.Context().CurrentSide()
|
|
currentKey := self.c.Context().Current().GetKey()
|
|
if currentSide.GetKey() == currentKey ||
|
|
currentKey == context.NORMAL_MAIN_CONTEXT_KEY ||
|
|
currentKey == context.NORMAL_SECONDARY_CONTEXT_KEY {
|
|
currentSide.HandleRenderToMain()
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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()
|
|
}
|
|
|
|
func (self *GlobalController) optionsMenuDisabledReason() *types.DisabledReason {
|
|
ctx := self.c.Context().Current()
|
|
// Don't show options menu while displaying popup.
|
|
if ctx.GetKind() == types.PERSISTENT_POPUP || ctx.GetKind() == types.TEMPORARY_POPUP {
|
|
// The empty error text is intentional. We don't want to show an error
|
|
// toast for this, but only hide it from the options map.
|
|
return &types.DisabledReason{Text: ""}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (self *GlobalController) createFilteringMenu() error {
|
|
return (&FilteringMenuAction{c: self.c}).Call()
|
|
}
|
|
|
|
func (self *GlobalController) createDiffingMenu() error {
|
|
return (&DiffingMenuAction{c: self.c}).Call()
|
|
}
|
|
|
|
func (self *GlobalController) quit() error {
|
|
return (&QuitActions{c: self.c}).Quit()
|
|
}
|
|
|
|
func (self *GlobalController) quitWithoutChangingDirectory() error {
|
|
return (&QuitActions{c: self.c}).QuitWithoutChangingDirectory()
|
|
}
|
|
|
|
func (self *GlobalController) escape() error {
|
|
return (&QuitActions{c: self.c}).Escape()
|
|
}
|
|
|
|
func (self *GlobalController) escapeDescription() string {
|
|
return (&QuitActions{c: self.c}).EscapeDescription()
|
|
}
|
|
|
|
func (self *GlobalController) escapeEnabled() *types.DisabledReason {
|
|
if (&QuitActions{c: self.c}).EscapeEnabled() {
|
|
return nil
|
|
}
|
|
|
|
// The empty error text is intentional. We don't want to show an error
|
|
// toast for this, but only hide it from the options map.
|
|
return &types.DisabledReason{Text: ""}
|
|
}
|
|
|
|
func (self *GlobalController) toggleWhitespace() error {
|
|
return (&ToggleWhitespaceAction{c: self.c}).Call()
|
|
}
|
|
|
|
func (self *GlobalController) canShowRebaseOptions() *types.DisabledReason {
|
|
if self.c.Model().WorkingTreeStateAtLastCommitRefresh.None() {
|
|
return &types.DisabledReason{
|
|
Text: self.c.Tr.NotMergingOrRebasing,
|
|
}
|
|
}
|
|
return nil
|
|
}
|