package controllers import ( "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) type StashController struct { baseController *ListControllerTrait[*models.StashEntry] c *ControllerCommon } var _ types.IController = &StashController{} func NewStashController( c *ControllerCommon, ) *StashController { return &StashController{ baseController: baseController{}, ListControllerTrait: NewListControllerTrait( c, c.Contexts().Stash, c.Contexts().Stash.GetSelected, c.Contexts().Stash.GetSelectedItems, ), c: c, } } func (self *StashController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { Key: opts.GetKey(opts.Config.Universal.Select), Handler: self.withItem(self.handleStashApply), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Apply, Tooltip: self.c.Tr.StashApplyTooltip, DisplayOnScreen: true, }, { Key: opts.GetKey(opts.Config.Stash.PopStash), Handler: self.withItem(self.handleStashPop), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.Pop, Tooltip: self.c.Tr.StashPopTooltip, DisplayOnScreen: true, }, { Key: opts.GetKey(opts.Config.Universal.Remove), Handler: self.withItems(self.handleStashDrop), GetDisabledReason: self.require(self.itemRangeSelected()), Description: self.c.Tr.Drop, Tooltip: self.c.Tr.StashDropTooltip, DisplayOnScreen: true, }, { Key: opts.GetKey(opts.Config.Universal.New), Handler: self.withItem(self.handleNewBranchOffStashEntry), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.NewBranch, Tooltip: self.c.Tr.NewBranchFromStashTooltip, }, { Key: opts.GetKey(opts.Config.Stash.RenameStash), Handler: self.withItem(self.handleRenameStashEntry), GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.RenameStash, }, } return bindings } func (self *StashController) GetOnRenderToMain() func() { return func() { self.c.Helpers().Diff.WithDiffModeCheck(func() { var task types.UpdateTask stashEntry := self.context().GetSelected() if stashEntry == nil { task = types.NewRenderStringTask(self.c.Tr.NoStashEntries) } else { task = types.NewRunPtyTask( self.c.Git().Stash.ShowStashEntryCmdObj(stashEntry.Index).GetCmd(), ) } self.c.RenderToMainViews(types.RefreshMainOpts{ Pair: self.c.MainViewPairs().Normal, Main: &types.ViewUpdateOpts{ Title: "Stash", SubTitle: self.c.Helpers().Diff.IgnoringWhitespaceSubTitle(), Task: task, }, }) }) } } func (self *StashController) context() *context.StashContext { return self.c.Contexts().Stash } func (self *StashController) handleStashApply(stashEntry *models.StashEntry) error { apply := func() error { self.c.LogAction(self.c.Tr.Actions.Stash) err := self.c.Git().Stash.Apply(stashEntry.Index) _ = self.postStashRefresh() if err != nil { return err } if self.c.UserConfig().Gui.SwitchToFilesAfterStashApply { self.c.Context().Push(self.c.Contexts().Files, types.OnFocusOpts{}) } return nil } if self.c.UserConfig().Gui.SkipStashWarning { return apply() } self.c.Confirm(types.ConfirmOpts{ Title: self.c.Tr.StashApply, Prompt: self.c.Tr.SureApplyStashEntry, HandleConfirm: func() error { return apply() }, }) return nil } func (self *StashController) handleStashPop(stashEntry *models.StashEntry) error { pop := func() error { self.c.LogAction(self.c.Tr.Actions.Stash) err := self.c.Git().Stash.Pop(stashEntry.Index) _ = self.postStashRefresh() if err != nil { return err } if self.c.UserConfig().Gui.SwitchToFilesAfterStashPop { self.c.Context().Push(self.c.Contexts().Files, types.OnFocusOpts{}) } return nil } if self.c.UserConfig().Gui.SkipStashWarning { return pop() } self.c.Confirm(types.ConfirmOpts{ Title: self.c.Tr.StashPop, Prompt: self.c.Tr.SurePopStashEntry, HandleConfirm: func() error { return pop() }, }) return nil } func (self *StashController) handleStashDrop(stashEntries []*models.StashEntry) error { self.c.Confirm(types.ConfirmOpts{ Title: self.c.Tr.StashDrop, Prompt: self.c.Tr.SureDropStashEntry, HandleConfirm: func() error { self.c.LogAction(self.c.Tr.Actions.Stash) startIndex := stashEntries[0].Index for range stashEntries { err := self.c.Git().Stash.Drop(startIndex) _ = self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}}) if err != nil { return err } } return nil }, }) return nil } func (self *StashController) postStashRefresh() error { return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH, types.FILES}}) } func (self *StashController) handleNewBranchOffStashEntry(stashEntry *models.StashEntry) error { return self.c.Helpers().Refs.NewBranch(stashEntry.RefName(), stashEntry.Description(), "") } func (self *StashController) handleRenameStashEntry(stashEntry *models.StashEntry) error { message := utils.ResolvePlaceholderString( self.c.Tr.RenameStashPrompt, map[string]string{ "stashName": stashEntry.RefName(), }, ) self.c.Prompt(types.PromptOpts{ Title: message, InitialContent: stashEntry.Name, HandleConfirm: func(response string) error { self.c.LogAction(self.c.Tr.Actions.RenameStash) err := self.c.Git().Stash.Rename(stashEntry.Index, response) if err != nil { _ = self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}}) return err } self.context().SetSelection(0) // Select the renamed stash self.context().FocusLine() return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}}) }, }) return nil }