Files
lazygit/pkg/gui/controllers/global_controller.go

285 lines
9.1 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.CycleDiffRenderers),
Handler: opts.Guards.NoPopupPanel(self.cycleDiffRenderers),
GetDisabledReason: self.canCycleDiffRenderers,
Description: self.c.Tr.CycleDiffRenderers,
Tooltip: self.c.Tr.CycleDiffRenderersTooltip,
},
{
Keys: opts.GetKeys(opts.Config.Universal.CycleDiffRenderersReverse),
Handler: opts.Guards.NoPopupPanel(self.cycleDiffRenderersBackward),
GetDisabledReason: self.canCycleDiffRenderers,
Description: self.c.Tr.CycleDiffRenderersReverse,
Tooltip: self.c.Tr.CycleDiffRenderersReverseTooltip,
},
{
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,
},
{
Keys: opts.GetKeys(opts.Config.Universal.EditConfig),
Handler: self.editConfig,
Description: self.c.Tr.EditConfig,
Tooltip: self.c.Tr.EditFileTooltip,
},
}
}
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{})
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) cycleDiffRenderers() error {
self.c.State().GetDiffRendererConfigManager().CycleDiffRenderers()
self.onDiffRenderersChanged()
return nil
}
func (self *GlobalController) cycleDiffRenderersBackward() error {
self.c.State().GetDiffRendererConfigManager().CycleDiffRenderersBackward()
self.onDiffRenderersChanged()
return nil
}
// onDiffRenderersChanged re-renders the main view so the newly selected diff renderer
// takes effect, and shows a toast naming it.
func (self *GlobalController) onDiffRenderersChanged() {
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 {
// The new renderer lays the same diff out its own way, so the line you were
// looking at ends up elsewhere in the view; keep it in front of you.
self.c.Helpers().DiffLine.PreserveDiffPositionOnRerender(self.c.Contexts().Normal.GetView())
self.c.Helpers().DiffLine.PreserveDiffPositionOnRerender(self.c.Contexts().NormalSecondary.GetView())
currentSide.HandleRenderToMain()
}
diffRendererConfigManager := self.c.State().GetDiffRendererConfigManager()
current, total := diffRendererConfigManager.CurrentDiffRendererIndex()
name := diffRendererConfigManager.CurrentDiffRendererName(self.c.Tr)
self.c.Toast(utils.ResolvePlaceholderString(self.c.Tr.SelectedDiffRenderers, map[string]string{
"name": name,
"current": strconv.Itoa(current + 1),
"total": strconv.Itoa(total),
}))
}
func (self *GlobalController) canCycleDiffRenderers() *types.DisabledReason {
_, total := self.c.State().GetDiffRendererConfigManager().CurrentDiffRendererIndex()
if total <= 1 {
return &types.DisabledReason{
Text: self.c.Tr.CycleDiffRenderersDisabledReason,
}
}
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) editConfig() error {
return (&EditConfigAction{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
}