1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-06-15 00:15:32 +02:00

refactor contexts code

This commit is contained in:
Jesse Duffield
2022-01-29 19:09:20 +11:00
parent 1a74ed3214
commit 138be04e65
60 changed files with 1154 additions and 602 deletions

View File

@ -1,71 +1,48 @@
package gui package gui
import ( import (
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
type BasicContext struct { type SimpleContext struct {
OnFocus func(opts ...types.OnFocusOpts) error OnFocus func(opts ...types.OnFocusOpts) error
OnFocusLost func() error OnFocusLost func() error
OnRender func() error OnRender func() error
// this is for pushing some content to the main view // this is for pushing some content to the main view
OnRenderToMain func(opts ...types.OnFocusOpts) error OnRenderToMain func(opts ...types.OnFocusOpts) error
Kind types.ContextKind
Key types.ContextKey
ViewName string
WindowName string
OnGetOptionsMap func() map[string]string
ParentContext types.Context *context.BaseContext
// we can't know on the calling end whether a Context is actually a nil value without reflection, so we're storing this flag here to tell us. There has got to be a better way around this
hasParent bool
} }
var _ types.Context = &BasicContext{} type NewSimpleContextOpts struct {
OnFocus func(opts ...types.OnFocusOpts) error
OnFocusLost func() error
OnRender func() error
// this is for pushing some content to the main view
OnRenderToMain func(opts ...types.OnFocusOpts) error
}
func (self *BasicContext) GetOptionsMap() map[string]string { func NewSimpleContext(baseContext *context.BaseContext, opts NewSimpleContextOpts) *SimpleContext {
if self.OnGetOptionsMap != nil { return &SimpleContext{
return self.OnGetOptionsMap() OnFocus: opts.OnFocus,
OnFocusLost: opts.OnFocusLost,
OnRender: opts.OnRender,
OnRenderToMain: opts.OnRenderToMain,
BaseContext: baseContext,
} }
return nil
} }
func (self *BasicContext) SetParentContext(context types.Context) { var _ types.Context = &SimpleContext{}
self.ParentContext = context
self.hasParent = true
}
func (self *BasicContext) GetParentContext() (types.Context, bool) { func (self *SimpleContext) HandleRender() error {
return self.ParentContext, self.hasParent
}
func (self *BasicContext) SetWindowName(windowName string) {
self.WindowName = windowName
}
func (self *BasicContext) GetWindowName() string {
windowName := self.WindowName
if windowName != "" {
return windowName
}
// TODO: actually set this for everything so we don't default to the view name
return self.ViewName
}
func (self *BasicContext) HandleRender() error {
if self.OnRender != nil { if self.OnRender != nil {
return self.OnRender() return self.OnRender()
} }
return nil return nil
} }
func (self *BasicContext) GetViewName() string { func (self *SimpleContext) HandleFocus(opts ...types.OnFocusOpts) error {
return self.ViewName
}
func (self *BasicContext) HandleFocus(opts ...types.OnFocusOpts) error {
if self.OnFocus != nil { if self.OnFocus != nil {
if err := self.OnFocus(opts...); err != nil { if err := self.OnFocus(opts...); err != nil {
return err return err
@ -81,25 +58,17 @@ func (self *BasicContext) HandleFocus(opts ...types.OnFocusOpts) error {
return nil return nil
} }
func (self *BasicContext) HandleFocusLost() error { func (self *SimpleContext) HandleFocusLost() error {
if self.OnFocusLost != nil { if self.OnFocusLost != nil {
return self.OnFocusLost() return self.OnFocusLost()
} }
return nil return nil
} }
func (self *BasicContext) HandleRenderToMain() error { func (self *SimpleContext) HandleRenderToMain() error {
if self.OnRenderToMain != nil { if self.OnRenderToMain != nil {
return self.OnRenderToMain() return self.OnRenderToMain()
} }
return nil return nil
} }
func (self *BasicContext) GetKind() types.ContextKind {
return self.Kind
}
func (self *BasicContext) GetKey() types.ContextKey {
return self.Key
}

View File

@ -8,7 +8,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/controllers"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
@ -145,7 +144,7 @@ func (gui *Gui) handleForceCheckout() error {
message := gui.c.Tr.SureForceCheckout message := gui.c.Tr.SureForceCheckout
title := gui.c.Tr.ForceCheckoutBranch title := gui.c.Tr.ForceCheckoutBranch
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: title, Title: title,
Prompt: message, Prompt: message,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -159,14 +158,14 @@ func (gui *Gui) handleForceCheckout() error {
} }
func (gui *Gui) handleCheckoutByName() error { func (gui *Gui) handleCheckoutByName() error {
return gui.c.Prompt(popup.PromptOpts{ return gui.c.Prompt(types.PromptOpts{
Title: gui.c.Tr.BranchName + ":", Title: gui.c.Tr.BranchName + ":",
FindSuggestionsFunc: gui.suggestionsHelper.GetRefsSuggestionsFunc(), FindSuggestionsFunc: gui.suggestionsHelper.GetRefsSuggestionsFunc(),
HandleConfirm: func(response string) error { HandleConfirm: func(response string) error {
gui.c.LogAction("Checkout branch") gui.c.LogAction("Checkout branch")
return gui.refHelper.CheckoutRef(response, types.CheckoutRefOptions{ return gui.refHelper.CheckoutRef(response, types.CheckoutRefOptions{
OnRefNotFound: func(ref string) error { OnRefNotFound: func(ref string) error {
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.BranchNotFoundTitle, Title: gui.c.Tr.BranchNotFoundTitle,
Prompt: fmt.Sprintf("%s %s%s", gui.c.Tr.BranchNotFoundPrompt, ref, "?"), Prompt: fmt.Sprintf("%s %s%s", gui.c.Tr.BranchNotFoundPrompt, ref, "?"),
HandleConfirm: func() error { HandleConfirm: func() error {
@ -232,7 +231,7 @@ func (gui *Gui) deleteNamedBranch(selectedBranch *models.Branch, force bool) err
}, },
) )
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: title, Title: title,
Prompt: message, Prompt: message,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -265,7 +264,7 @@ func (gui *Gui) mergeBranchIntoCheckedOutBranch(branchName string) error {
}, },
) )
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.MergingTitle, Title: gui.c.Tr.MergingTitle,
Prompt: prompt, Prompt: prompt,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -299,7 +298,7 @@ func (gui *Gui) handleRebaseOntoBranch(selectedBranchName string) error {
}, },
) )
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.RebasingTitle, Title: gui.c.Tr.RebasingTitle,
Prompt: prompt, Prompt: prompt,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -368,7 +367,7 @@ func (gui *Gui) handleRenameBranch() error {
} }
promptForNewName := func() error { promptForNewName := func() error {
return gui.c.Prompt(popup.PromptOpts{ return gui.c.Prompt(types.PromptOpts{
Title: gui.c.Tr.NewBranchNamePrompt + " " + branch.Name + ":", Title: gui.c.Tr.NewBranchNamePrompt + " " + branch.Name + ":",
InitialContent: branch.Name, InitialContent: branch.Name,
HandleConfirm: func(newBranchName string) error { HandleConfirm: func(newBranchName string) error {
@ -402,7 +401,7 @@ func (gui *Gui) handleRenameBranch() error {
return promptForNewName() return promptForNewName()
} }
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.LcRenameBranch, Title: gui.c.Tr.LcRenameBranch,
Prompt: gui.c.Tr.RenameBranchWarning, Prompt: gui.c.Tr.RenameBranchWarning,
HandleConfirm: promptForNewName, HandleConfirm: promptForNewName,
@ -430,7 +429,7 @@ func (gui *Gui) handleNewBranchOffCurrentItem() error {
prefilledName = strings.SplitAfterN(item.ID(), "/", 2)[1] prefilledName = strings.SplitAfterN(item.ID(), "/", 2)[1]
} }
return gui.c.Prompt(popup.PromptOpts{ return gui.c.Prompt(types.PromptOpts{
Title: message, Title: message,
InitialContent: prefilledName, InitialContent: prefilledName,
HandleConfirm: func(response string) error { HandleConfirm: func(response string) error {

View File

@ -2,7 +2,6 @@ package gui
import ( import (
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
@ -135,7 +134,7 @@ func (gui *Gui) handleCopyCommitRange() error {
// HandlePasteCommits begins a cherry-pick rebase with the commits the user has copied // HandlePasteCommits begins a cherry-pick rebase with the commits the user has copied
func (gui *Gui) HandlePasteCommits() error { func (gui *Gui) HandlePasteCommits() error {
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.CherryPick, Title: gui.c.Tr.CherryPick,
Prompt: gui.c.Tr.SureCherryPick, Prompt: gui.c.Tr.SureCherryPick,
HandleConfirm: func() error { HandleConfirm: func() error {

View File

@ -5,7 +5,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/patch" "github.com/jesseduffield/lazygit/pkg/commands/patch"
"github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/controllers"
"github.com/jesseduffield/lazygit/pkg/gui/filetree" "github.com/jesseduffield/lazygit/pkg/gui/filetree"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
@ -81,7 +80,7 @@ func (gui *Gui) handleDiscardOldFileChange() error {
fileName := gui.getSelectedCommitFileName() fileName := gui.getSelectedCommitFileName()
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.DiscardFileChangesTitle, Title: gui.c.Tr.DiscardFileChangesTitle,
Prompt: gui.c.Tr.DiscardFileChangesPrompt, Prompt: gui.c.Tr.DiscardFileChangesPrompt,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -181,7 +180,7 @@ func (gui *Gui) handleToggleFileForPatch() error {
} }
if gui.git.Patch.PatchManager.Active() && gui.git.Patch.PatchManager.To != gui.State.CommitFileTreeViewModel.GetParent() { if gui.git.Patch.PatchManager.Active() && gui.git.Patch.PatchManager.To != gui.State.CommitFileTreeViewModel.GetParent() {
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.DiscardPatch, Title: gui.c.Tr.DiscardPatch,
Prompt: gui.c.Tr.DiscardPatchConfirm, Prompt: gui.c.Tr.DiscardPatchConfirm,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -229,7 +228,7 @@ func (gui *Gui) enterCommitFile(opts types.OnFocusOpts) error {
} }
if gui.git.Patch.PatchManager.Active() && gui.git.Patch.PatchManager.To != gui.State.CommitFileTreeViewModel.GetParent() { if gui.git.Patch.PatchManager.Active() && gui.git.Patch.PatchManager.To != gui.State.CommitFileTreeViewModel.GetParent() {
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.DiscardPatch, Title: gui.c.Tr.DiscardPatch,
Prompt: gui.c.Tr.DiscardPatchConfirm, Prompt: gui.c.Tr.DiscardPatchConfirm,
HandleConfirm: func() error { HandleConfirm: func() error {

View File

@ -191,12 +191,6 @@ func (gui *Gui) setKeyBindings(opts popup.CreatePopupPanelOpts) error {
onConfirm = gui.wrappedConfirmationFunction(opts.HandlersManageFocus, opts.HandleConfirm) onConfirm = gui.wrappedConfirmationFunction(opts.HandlersManageFocus, opts.HandleConfirm)
} }
type confirmationKeybinding struct {
viewName string
key interface{}
handler func() error
}
keybindingConfig := gui.c.UserConfig.Keybinding keybindingConfig := gui.c.UserConfig.Keybinding
onSuggestionConfirm := gui.wrappedPromptConfirmationFunction( onSuggestionConfirm := gui.wrappedPromptConfirmationFunction(
opts.HandlersManageFocus, opts.HandlersManageFocus,
@ -204,26 +198,30 @@ func (gui *Gui) setKeyBindings(opts popup.CreatePopupPanelOpts) error {
gui.getSelectedSuggestionValue, gui.getSelectedSuggestionValue,
) )
confirmationKeybindings := []confirmationKeybinding{ bindings := []*types.Binding{
{ {
viewName: "confirmation", ViewName: "confirmation",
key: gui.getKey(keybindingConfig.Universal.Confirm), Contexts: []string{string(CONFIRMATION_CONTEXT_KEY)},
handler: onConfirm, Key: gui.getKey(keybindingConfig.Universal.Confirm),
Handler: onConfirm,
}, },
{ {
viewName: "confirmation", ViewName: "confirmation",
key: gui.getKey(keybindingConfig.Universal.ConfirmAlt1), Contexts: []string{string(CONFIRMATION_CONTEXT_KEY)},
handler: onConfirm, Key: gui.getKey(keybindingConfig.Universal.ConfirmAlt1),
Handler: onConfirm,
}, },
{ {
viewName: "confirmation", ViewName: "confirmation",
key: gui.getKey(keybindingConfig.Universal.Return), Contexts: []string{string(CONFIRMATION_CONTEXT_KEY)},
handler: gui.wrappedConfirmationFunction(opts.HandlersManageFocus, opts.HandleClose), Key: gui.getKey(keybindingConfig.Universal.Return),
Handler: gui.wrappedConfirmationFunction(opts.HandlersManageFocus, opts.HandleClose),
}, },
{ {
viewName: "confirmation", ViewName: "confirmation",
key: gui.getKey(keybindingConfig.Universal.TogglePanel), Contexts: []string{string(CONFIRMATION_CONTEXT_KEY)},
handler: func() error { Key: gui.getKey(keybindingConfig.Universal.TogglePanel),
Handler: func() error {
if len(gui.State.Suggestions) > 0 { if len(gui.State.Suggestions) > 0 {
return gui.replaceContext(gui.State.Contexts.Suggestions) return gui.replaceContext(gui.State.Contexts.Suggestions)
} }
@ -231,29 +229,33 @@ func (gui *Gui) setKeyBindings(opts popup.CreatePopupPanelOpts) error {
}, },
}, },
{ {
viewName: "suggestions", ViewName: "suggestions",
key: gui.getKey(keybindingConfig.Universal.Confirm), Contexts: []string{string(CONFIRMATION_CONTEXT_KEY)},
handler: onSuggestionConfirm, Key: gui.getKey(keybindingConfig.Universal.Confirm),
Handler: onSuggestionConfirm,
}, },
{ {
viewName: "suggestions", ViewName: "suggestions",
key: gui.getKey(keybindingConfig.Universal.ConfirmAlt1), Contexts: []string{string(CONFIRMATION_CONTEXT_KEY)},
handler: onSuggestionConfirm, Key: gui.getKey(keybindingConfig.Universal.ConfirmAlt1),
Handler: onSuggestionConfirm,
}, },
{ {
viewName: "suggestions", ViewName: "suggestions",
key: gui.getKey(keybindingConfig.Universal.Return), Contexts: []string{string(CONFIRMATION_CONTEXT_KEY)},
handler: gui.wrappedConfirmationFunction(opts.HandlersManageFocus, opts.HandleClose), Key: gui.getKey(keybindingConfig.Universal.Return),
Handler: gui.wrappedConfirmationFunction(opts.HandlersManageFocus, opts.HandleClose),
}, },
{ {
viewName: "suggestions", ViewName: "suggestions",
key: gui.getKey(keybindingConfig.Universal.TogglePanel), Contexts: []string{string(CONFIRMATION_CONTEXT_KEY)},
handler: func() error { return gui.replaceContext(gui.State.Contexts.Confirmation) }, Key: gui.getKey(keybindingConfig.Universal.TogglePanel),
Handler: func() error { return gui.replaceContext(gui.State.Contexts.Confirmation) },
}, },
} }
for _, binding := range confirmationKeybindings { for _, binding := range bindings {
if err := gui.g.SetKeybinding(binding.viewName, nil, binding.key, gocui.ModNone, gui.wrappedHandler(binding.handler)); err != nil { if err := gui.SetKeybinding(binding); err != nil {
return err return err
} }
} }
@ -271,12 +273,6 @@ func (gui *Gui) clearConfirmationViewKeyBindings() {
_ = gui.g.DeleteKeybinding("suggestions", gui.getKey(keybindingConfig.Universal.Return), gocui.ModNone) _ = gui.g.DeleteKeybinding("suggestions", gui.getKey(keybindingConfig.Universal.Return), gocui.ModNone)
} }
func (gui *Gui) wrappedHandler(f func() error) func(g *gocui.Gui, v *gocui.View) error {
return func(g *gocui.Gui, v *gocui.View) error {
return f()
}
}
func (gui *Gui) refreshSuggestions() { func (gui *Gui) refreshSuggestions() {
gui.suggestionsAsyncHandler.Do(func() func() { gui.suggestionsAsyncHandler.Do(func() func() {
suggestions := gui.findSuggestions(gui.c.GetPromptInput()) suggestions := gui.findSuggestions(gui.c.GetPromptInput())

View File

@ -0,0 +1,67 @@
package context
import "github.com/jesseduffield/lazygit/pkg/gui/types"
type BaseContext struct {
Kind types.ContextKind
Key types.ContextKey
ViewName string
WindowName string
OnGetOptionsMap func() map[string]string
*ParentContextMgr
}
func (self *BaseContext) GetOptionsMap() map[string]string {
if self.OnGetOptionsMap != nil {
return self.OnGetOptionsMap()
}
return nil
}
func (self *BaseContext) SetWindowName(windowName string) {
self.WindowName = windowName
}
func (self *BaseContext) GetWindowName() string {
windowName := self.WindowName
if windowName != "" {
return windowName
}
// TODO: actually set this for everything so we don't default to the view name
return self.ViewName
}
func (self *BaseContext) GetViewName() string {
return self.ViewName
}
func (self *BaseContext) GetKind() types.ContextKind {
return self.Kind
}
func (self *BaseContext) GetKey() types.ContextKey {
return self.Key
}
type NewBaseContextOpts struct {
Kind types.ContextKind
Key types.ContextKey
ViewName string
WindowName string
OnGetOptionsMap func() map[string]string
}
func NewBaseContext(opts NewBaseContextOpts) *BaseContext {
return &BaseContext{
Kind: opts.Kind,
Key: opts.Key,
ViewName: opts.ViewName,
WindowName: opts.WindowName,
OnGetOptionsMap: opts.OnGetOptionsMap,
ParentContextMgr: &ParentContextMgr{},
}
}

View File

@ -10,7 +10,7 @@ type ContextTree struct {
Branches types.IListContext Branches types.IListContext
Remotes types.IListContext Remotes types.IListContext
RemoteBranches types.IListContext RemoteBranches types.IListContext
Tags types.IListContext Tags *TagsContext
BranchCommits types.IListContext BranchCommits types.IListContext
CommitFiles types.IListContext CommitFiles types.IListContext
ReflogCommits types.IListContext ReflogCommits types.IListContext

View File

@ -0,0 +1,231 @@
package context
import (
"fmt"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
)
type Thing interface {
// the boolean here tells us whether the item is nil. This is needed because you can't work it out on the calling end once the pointer is wrapped in an interface (unless you want to use reflection)
GetSelectedItem() (types.ListItem, bool)
}
type ListContextTrait struct {
base types.IBaseContext
thing Thing
listTrait *ListTrait
viewTrait *ViewTrait
takeFocus func() error
GetDisplayStrings func(startIdx int, length int) [][]string
OnFocus func(...types.OnFocusOpts) error
OnRenderToMain func(...types.OnFocusOpts) error
OnFocusLost func() error
// if this is true, we'll call GetDisplayStrings for just the visible part of the
// view and re-render that. This is useful when you need to render different
// content based on the selection (e.g. for showing the selected commit)
RenderSelection bool
c *types.ControllerCommon
}
func (self *ListContextTrait) GetPanelState() types.IListPanelState {
return self.listTrait
}
func (self *ListContextTrait) FocusLine() {
// we need a way of knowing whether we've rendered to the view yet.
self.viewTrait.FocusPoint(self.listTrait.GetSelectedLineIdx())
if self.RenderSelection {
min, max := self.viewTrait.ViewPortYBounds()
displayStrings := self.GetDisplayStrings(min, max)
content := utils.RenderDisplayStrings(displayStrings)
self.viewTrait.SetViewPortContent(content)
}
self.viewTrait.SetFooter(formatListFooter(self.listTrait.GetSelectedLineIdx(), self.listTrait.GetItemsLength()))
}
func formatListFooter(selectedLineIdx int, length int) string {
return fmt.Sprintf("%d of %d", selectedLineIdx+1, length)
}
func (self *ListContextTrait) GetSelectedItemId() string {
item, ok := self.thing.GetSelectedItem()
if !ok {
return ""
}
return item.ID()
}
// OnFocus assumes that the content of the context has already been rendered to the view. OnRender is the function which actually renders the content to the view
func (self *ListContextTrait) HandleRender() error {
if self.GetDisplayStrings != nil {
self.listTrait.RefreshSelectedIdx()
content := utils.RenderDisplayStrings(self.GetDisplayStrings(0, self.listTrait.GetItemsLength()))
self.viewTrait.SetContent(content)
self.c.Render()
}
return nil
}
func (self *ListContextTrait) HandleFocusLost() error {
if self.OnFocusLost != nil {
return self.OnFocusLost()
}
self.viewTrait.SetOriginX(0)
return nil
}
func (self *ListContextTrait) HandleFocus(opts ...types.OnFocusOpts) error {
self.FocusLine()
if self.OnFocus != nil {
if err := self.OnFocus(opts...); err != nil {
return err
}
}
if self.OnRenderToMain != nil {
if err := self.OnRenderToMain(opts...); err != nil {
return err
}
}
return nil
}
func (self *ListContextTrait) HandlePrevLine() error {
return self.handleLineChange(-1)
}
func (self *ListContextTrait) HandleNextLine() error {
return self.handleLineChange(1)
}
func (self *ListContextTrait) HandleScrollLeft() error {
return self.scroll(self.viewTrait.ScrollLeft)
}
func (self *ListContextTrait) HandleScrollRight() error {
return self.scroll(self.viewTrait.ScrollRight)
}
func (self *ListContextTrait) scroll(scrollFunc func()) error {
scrollFunc()
return self.HandleFocus()
}
func (self *ListContextTrait) handleLineChange(change int) error {
before := self.listTrait.GetSelectedLineIdx()
self.listTrait.MoveSelectedLine(change)
after := self.listTrait.GetSelectedLineIdx()
if before != after {
return self.HandleFocus()
}
return nil
}
func (self *ListContextTrait) HandlePrevPage() error {
return self.handleLineChange(-self.viewTrait.PageDelta())
}
func (self *ListContextTrait) HandleNextPage() error {
return self.handleLineChange(self.viewTrait.PageDelta())
}
func (self *ListContextTrait) HandleGotoTop() error {
return self.handleLineChange(-self.listTrait.GetItemsLength())
}
func (self *ListContextTrait) HandleGotoBottom() error {
return self.handleLineChange(self.listTrait.GetItemsLength())
}
func (self *ListContextTrait) HandleClick(onClick func() error) error {
prevSelectedLineIdx := self.listTrait.GetSelectedLineIdx()
// because we're handling a click, we need to determine the new line idx based
// on the view itself.
newSelectedLineIdx := self.viewTrait.SelectedLineIdx()
currentContextKey := self.c.CurrentContext().GetKey()
alreadyFocused := currentContextKey == self.base.GetKey()
// we need to focus the view
if !alreadyFocused {
if err := self.takeFocus(); err != nil {
return err
}
}
if newSelectedLineIdx > self.listTrait.GetItemsLength()-1 {
return nil
}
self.listTrait.SetSelectedLineIdx(newSelectedLineIdx)
if prevSelectedLineIdx == newSelectedLineIdx && alreadyFocused && onClick != nil {
return onClick()
}
return self.HandleFocus()
}
func (self *ListContextTrait) OnSearchSelect(selectedLineIdx int) error {
self.listTrait.SetSelectedLineIdx(selectedLineIdx)
return self.HandleFocus()
}
func (self *ListContextTrait) HandleRenderToMain() error {
if self.OnRenderToMain != nil {
return self.OnRenderToMain()
}
return nil
}
func (self *ListContextTrait) Keybindings(
getKey func(key string) interface{},
config config.KeybindingConfig,
guards types.KeybindingGuards,
) []*types.Binding {
return []*types.Binding{
{Tag: "navigation", Key: getKey(config.Universal.PrevItemAlt), Modifier: gocui.ModNone, Handler: self.HandlePrevLine},
{Tag: "navigation", Key: getKey(config.Universal.PrevItem), Modifier: gocui.ModNone, Handler: self.HandlePrevLine},
{Tag: "navigation", Key: gocui.MouseWheelUp, Modifier: gocui.ModNone, Handler: self.HandlePrevLine},
{Tag: "navigation", Key: getKey(config.Universal.NextItemAlt), Modifier: gocui.ModNone, Handler: self.HandleNextLine},
{Tag: "navigation", Key: getKey(config.Universal.NextItem), Modifier: gocui.ModNone, Handler: self.HandleNextLine},
{Tag: "navigation", Key: getKey(config.Universal.PrevPage), Modifier: gocui.ModNone, Handler: self.HandlePrevPage, Description: self.c.Tr.LcPrevPage},
{Tag: "navigation", Key: getKey(config.Universal.NextPage), Modifier: gocui.ModNone, Handler: self.HandleNextPage, Description: self.c.Tr.LcNextPage},
{Tag: "navigation", Key: getKey(config.Universal.GotoTop), Modifier: gocui.ModNone, Handler: self.HandleGotoTop, Description: self.c.Tr.LcGotoTop},
{Key: gocui.MouseLeft, Modifier: gocui.ModNone, Handler: func() error { return self.HandleClick(nil) }},
{Tag: "navigation", Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, Handler: self.HandleNextLine},
{Tag: "navigation", Key: getKey(config.Universal.ScrollLeft), Modifier: gocui.ModNone, Handler: self.HandleScrollLeft},
{Tag: "navigation", Key: getKey(config.Universal.ScrollRight), Modifier: gocui.ModNone, Handler: self.HandleScrollRight},
{
Key: getKey(config.Universal.StartSearch),
Handler: func() error { self.c.OpenSearch(); return nil },
Description: self.c.Tr.LcStartSearch,
Tag: "navigation",
},
{
Key: getKey(config.Universal.GotoBottom),
Description: self.c.Tr.LcGotoBottom,
Handler: self.HandleGotoBottom,
Tag: "navigation",
},
}
}

View File

@ -0,0 +1,32 @@
package context
import "github.com/jesseduffield/lazygit/pkg/gui/types"
type HasLength interface {
GetItemsLength() int
}
type ListTrait struct {
selectedIdx int
HasLength
}
var _ types.IListPanelState = (*ListTrait)(nil)
func (self *ListTrait) GetSelectedLineIdx() int {
return self.selectedIdx
}
func (self *ListTrait) SetSelectedLineIdx(value int) {
self.selectedIdx = clamp(value, 0, self.GetItemsLength()-1)
}
// moves the cursor up or down by the given amount
func (self *ListTrait) MoveSelectedLine(value int) {
self.SetSelectedLineIdx(self.selectedIdx + value)
}
// to be called when the model might have shrunk so that our selection is not not out of bounds
func (self *ListTrait) RefreshSelectedIdx() {
self.SetSelectedLineIdx(self.selectedIdx)
}

View File

@ -0,0 +1,20 @@
package context
import "github.com/jesseduffield/lazygit/pkg/gui/types"
type ParentContextMgr struct {
ParentContext types.Context
// we can't know on the calling end whether a Context is actually a nil value without reflection, so we're storing this flag here to tell us. There has got to be a better way around this
hasParent bool
}
var _ types.ParentContexter = (*ParentContextMgr)(nil)
func (self *ParentContextMgr) SetParentContext(context types.Context) {
self.ParentContext = context
self.hasParent = true
}
func (self *ParentContextMgr) GetParentContext() (types.Context, bool) {
return self.ParentContext, self.hasParent
}

View File

@ -0,0 +1,107 @@
package context
import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type TagsContext struct {
*TagsContextAux
*BaseContext
*ListContextTrait
}
var _ types.IListContext = (*TagsContext)(nil)
func NewTagsContext(
getModel func() []*models.Tag,
getView func() *gocui.View,
getDisplayStrings func(startIdx int, length int) [][]string,
onFocus func(...types.OnFocusOpts) error,
onRenderToMain func(...types.OnFocusOpts) error,
onFocusLost func() error,
c *types.ControllerCommon,
) *TagsContext {
baseContext := NewBaseContext(NewBaseContextOpts{
ViewName: "branches",
WindowName: "branches",
Key: TAGS_CONTEXT_KEY,
Kind: types.SIDE_CONTEXT,
})
self := &TagsContext{}
takeFocus := func() error { return c.PushContext(self) }
aux := NewTagsContextAux(getModel)
viewTrait := NewViewTrait(getView)
listContextTrait := &ListContextTrait{
base: baseContext,
thing: aux,
listTrait: aux.list,
viewTrait: viewTrait,
GetDisplayStrings: getDisplayStrings,
OnFocus: onFocus,
OnRenderToMain: onRenderToMain,
OnFocusLost: onFocusLost,
takeFocus: takeFocus,
// TODO: handle this in a trait
RenderSelection: false,
c: c,
}
self.BaseContext = baseContext
self.ListContextTrait = listContextTrait
self.TagsContextAux = aux
return self
}
type TagsContextAux struct {
list *ListTrait
getModel func() []*models.Tag
}
func (self *TagsContextAux) GetItemsLength() int {
return len(self.getModel())
}
func (self *TagsContextAux) GetSelectedTag() *models.Tag {
if self.GetItemsLength() == 0 {
return nil
}
return self.getModel()[self.list.GetSelectedLineIdx()]
}
func (self *TagsContextAux) GetSelectedItem() (types.ListItem, bool) {
tag := self.GetSelectedTag()
return tag, tag != nil
}
func NewTagsContextAux(getModel func() []*models.Tag) *TagsContextAux {
self := &TagsContextAux{
getModel: getModel,
}
self.list = &ListTrait{
selectedIdx: 0,
HasLength: self,
}
return self
}
func clamp(x int, min int, max int) int {
if x < min {
return min
} else if x > max {
return max
}
return x
}

View File

@ -0,0 +1,80 @@
package context
import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/utils"
)
const HORIZONTAL_SCROLL_FACTOR = 3
type ViewTrait struct {
getView func() *gocui.View
}
func NewViewTrait(getView func() *gocui.View) *ViewTrait {
return &ViewTrait{getView: getView}
}
func (self *ViewTrait) FocusPoint(yIdx int) {
view := self.getView()
view.FocusPoint(view.OriginX(), yIdx)
}
func (self *ViewTrait) SetViewPortContent(content string) {
view := self.getView()
_, y := view.Origin()
view.OverwriteLines(y, content)
}
func (self *ViewTrait) SetContent(content string) {
self.getView().SetContent(content)
}
func (self *ViewTrait) SetFooter(value string) {
self.getView().Footer = value
}
func (self *ViewTrait) SetOriginX(value int) {
self.getView().SetOriginX(value)
}
// tells us the bounds of line indexes shown in the view currently
func (self *ViewTrait) ViewPortYBounds() (int, int) {
view := self.getView()
_, min := view.Origin()
max := view.InnerHeight() + 1
return min, max
}
func (self *ViewTrait) ScrollLeft() {
view := self.getView()
newOriginX := utils.Max(view.OriginX()-view.InnerWidth()/HORIZONTAL_SCROLL_FACTOR, 0)
_ = view.SetOriginX(newOriginX)
}
func (self *ViewTrait) ScrollRight() {
view := self.getView()
_ = view.SetOriginX(view.OriginX() + view.InnerWidth()/HORIZONTAL_SCROLL_FACTOR)
}
// this returns the amount we'll scroll if we want to scroll by a page.
func (self *ViewTrait) PageDelta() int {
view := self.getView()
_, height := view.Size()
delta := height - 1
if delta == 0 {
return 1
}
return delta
}
func (self *ViewTrait) SelectedLineIdx() int {
return self.getView().SelectedLineIdx()
}

View File

@ -86,12 +86,17 @@ func (gui *Gui) allContexts() []types.Context {
func (gui *Gui) contextTree() context.ContextTree { func (gui *Gui) contextTree() context.ContextTree {
return context.ContextTree{ return context.ContextTree{
Status: &BasicContext{ Status: NewSimpleContext(
OnRenderToMain: OnFocusWrapper(gui.statusRenderToMain), context.NewBaseContext(context.NewBaseContextOpts{
Kind: types.SIDE_CONTEXT, Kind: types.SIDE_CONTEXT,
ViewName: "status", ViewName: "status",
Key: STATUS_CONTEXT_KEY, Key: STATUS_CONTEXT_KEY,
}, WindowName: "status",
}),
NewSimpleContextOpts{
OnRenderToMain: OnFocusWrapper(gui.statusRenderToMain),
},
),
Files: gui.filesListContext(), Files: gui.filesListContext(),
Submodules: gui.submodulesListContext(), Submodules: gui.submodulesListContext(),
Menu: gui.menuListContext(), Menu: gui.menuListContext(),
@ -104,86 +109,130 @@ func (gui *Gui) contextTree() context.ContextTree {
Branches: gui.branchesListContext(), Branches: gui.branchesListContext(),
Tags: gui.tagsListContext(), Tags: gui.tagsListContext(),
Stash: gui.stashListContext(), Stash: gui.stashListContext(),
Normal: &BasicContext{ Suggestions: gui.suggestionsListContext(),
OnFocus: func(opts ...types.OnFocusOpts) error { Normal: NewSimpleContext(
return nil // TODO: should we do something here? We should allow for scrolling the panel context.NewBaseContext(context.NewBaseContextOpts{
Kind: types.MAIN_CONTEXT,
ViewName: "main",
WindowName: "main",
Key: MAIN_NORMAL_CONTEXT_KEY,
}),
NewSimpleContextOpts{
OnFocus: func(opts ...types.OnFocusOpts) error {
return nil // TODO: should we do something here? We should allow for scrolling the panel
},
}, },
Kind: types.MAIN_CONTEXT, ),
ViewName: "main", Staging: NewSimpleContext(
Key: MAIN_NORMAL_CONTEXT_KEY, context.NewBaseContext(context.NewBaseContextOpts{
}, Kind: types.MAIN_CONTEXT,
Staging: &BasicContext{ ViewName: "main",
OnFocus: func(opts ...types.OnFocusOpts) error { WindowName: "main",
forceSecondaryFocused := false Key: MAIN_STAGING_CONTEXT_KEY,
selectedLineIdx := -1 }),
if len(opts) > 0 && opts[0].ClickedViewName != "" { NewSimpleContextOpts{
if opts[0].ClickedViewName == "main" || opts[0].ClickedViewName == "secondary" { OnFocus: func(opts ...types.OnFocusOpts) error {
forceSecondaryFocused := false
selectedLineIdx := -1
if len(opts) > 0 && opts[0].ClickedViewName != "" {
if opts[0].ClickedViewName == "main" || opts[0].ClickedViewName == "secondary" {
selectedLineIdx = opts[0].ClickedViewLineIdx
}
if opts[0].ClickedViewName == "secondary" {
forceSecondaryFocused = true
}
}
return gui.onStagingFocus(forceSecondaryFocused, selectedLineIdx)
},
},
),
PatchBuilding: NewSimpleContext(
context.NewBaseContext(context.NewBaseContextOpts{
Kind: types.MAIN_CONTEXT,
ViewName: "main",
WindowName: "main",
Key: MAIN_PATCH_BUILDING_CONTEXT_KEY,
}),
NewSimpleContextOpts{
OnFocus: func(opts ...types.OnFocusOpts) error {
selectedLineIdx := -1
if len(opts) > 0 && (opts[0].ClickedViewName == "main" || opts[0].ClickedViewName == "secondary") {
selectedLineIdx = opts[0].ClickedViewLineIdx selectedLineIdx = opts[0].ClickedViewLineIdx
} }
if opts[0].ClickedViewName == "secondary" {
forceSecondaryFocused = true
}
}
return gui.onStagingFocus(forceSecondaryFocused, selectedLineIdx)
},
Kind: types.MAIN_CONTEXT,
ViewName: "main",
Key: MAIN_STAGING_CONTEXT_KEY,
},
PatchBuilding: &BasicContext{
OnFocus: func(opts ...types.OnFocusOpts) error {
selectedLineIdx := -1
if len(opts) > 0 && (opts[0].ClickedViewName == "main" || opts[0].ClickedViewName == "secondary") {
selectedLineIdx = opts[0].ClickedViewLineIdx
}
return gui.onPatchBuildingFocus(selectedLineIdx) return gui.onPatchBuildingFocus(selectedLineIdx)
},
}, },
Kind: types.MAIN_CONTEXT, ),
ViewName: "main", Merging: NewSimpleContext(
Key: MAIN_PATCH_BUILDING_CONTEXT_KEY, context.NewBaseContext(context.NewBaseContextOpts{
}, Kind: types.MAIN_CONTEXT,
Merging: &BasicContext{ ViewName: "main",
OnFocus: OnFocusWrapper(func() error { return gui.renderConflictsWithLock(true) }), WindowName: "main",
Kind: types.MAIN_CONTEXT, Key: MAIN_MERGING_CONTEXT_KEY,
ViewName: "main", OnGetOptionsMap: gui.getMergingOptions,
Key: MAIN_MERGING_CONTEXT_KEY, }),
OnGetOptionsMap: gui.getMergingOptions, NewSimpleContextOpts{
}, OnFocus: OnFocusWrapper(func() error { return gui.renderConflictsWithLock(true) }),
Credentials: &BasicContext{
OnFocus: OnFocusWrapper(gui.handleAskFocused),
Kind: types.PERSISTENT_POPUP,
ViewName: "credentials",
Key: CREDENTIALS_CONTEXT_KEY,
},
Confirmation: &BasicContext{
OnFocus: OnFocusWrapper(gui.handleAskFocused),
Kind: types.TEMPORARY_POPUP,
ViewName: "confirmation",
Key: CONFIRMATION_CONTEXT_KEY,
},
Suggestions: gui.suggestionsListContext(),
CommitMessage: &BasicContext{
OnFocus: OnFocusWrapper(gui.handleCommitMessageFocused),
Kind: types.PERSISTENT_POPUP,
ViewName: "commitMessage",
Key: COMMIT_MESSAGE_CONTEXT_KEY,
},
Search: &BasicContext{
Kind: types.PERSISTENT_POPUP,
ViewName: "search",
Key: SEARCH_CONTEXT_KEY,
},
CommandLog: &BasicContext{
Kind: types.EXTRAS_CONTEXT,
ViewName: "extras",
Key: COMMAND_LOG_CONTEXT_KEY,
OnGetOptionsMap: gui.getMergingOptions,
OnFocusLost: func() error {
gui.Views.Extras.Autoscroll = true
return nil
}, },
}, ),
Credentials: NewSimpleContext(
context.NewBaseContext(context.NewBaseContextOpts{
Kind: types.PERSISTENT_POPUP,
ViewName: "credentials",
WindowName: "credentials",
Key: CREDENTIALS_CONTEXT_KEY,
}),
NewSimpleContextOpts{
OnFocus: OnFocusWrapper(gui.handleAskFocused),
},
),
Confirmation: NewSimpleContext(
context.NewBaseContext(context.NewBaseContextOpts{
Kind: types.TEMPORARY_POPUP,
ViewName: "confirmation",
WindowName: "confirmation",
Key: CONFIRMATION_CONTEXT_KEY,
}),
NewSimpleContextOpts{
OnFocus: OnFocusWrapper(gui.handleAskFocused),
},
),
CommitMessage: NewSimpleContext(
context.NewBaseContext(context.NewBaseContextOpts{
Kind: types.PERSISTENT_POPUP,
ViewName: "commitMessage",
WindowName: "commitMessage",
Key: COMMIT_MESSAGE_CONTEXT_KEY,
}),
NewSimpleContextOpts{
OnFocus: OnFocusWrapper(gui.handleCommitMessageFocused),
},
),
Search: NewSimpleContext(
context.NewBaseContext(context.NewBaseContextOpts{
Kind: types.PERSISTENT_POPUP,
ViewName: "search",
WindowName: "search",
Key: SEARCH_CONTEXT_KEY,
}),
NewSimpleContextOpts{},
),
CommandLog: NewSimpleContext(
context.NewBaseContext(context.NewBaseContextOpts{
Kind: types.EXTRAS_CONTEXT,
ViewName: "extras",
WindowName: "extras",
Key: COMMAND_LOG_CONTEXT_KEY,
OnGetOptionsMap: gui.getMergingOptions,
}),
NewSimpleContextOpts{
OnFocusLost: func() error {
gui.Views.Extras.Autoscroll = true
return nil
},
},
),
} }
} }

View File

@ -8,12 +8,11 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
type BisectController struct { type BisectController struct {
c *ControllerCommon c *types.ControllerCommon
getContext func() types.IListContext getContext func() types.IListContext
git *commands.GitCommand git *commands.GitCommand
@ -24,7 +23,7 @@ type BisectController struct {
var _ types.IController = &BisectController{} var _ types.IController = &BisectController{}
func NewBisectController( func NewBisectController(
c *ControllerCommon, c *types.ControllerCommon,
getContext func() types.IListContext, getContext func() types.IListContext,
git *commands.GitCommand, git *commands.GitCommand,
@ -80,7 +79,7 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c
// ref, because we'll be reloading our commits in that case. // ref, because we'll be reloading our commits in that case.
waitToReselect := selectCurrentAfter && !self.git.Bisect.ReachableFromStart(info) waitToReselect := selectCurrentAfter && !self.git.Bisect.ReachableFromStart(info)
menuItems := []*popup.MenuItem{ menuItems := []*types.MenuItem{
{ {
DisplayString: fmt.Sprintf(self.c.Tr.Bisect.Mark, commit.ShortSha(), info.NewTerm()), DisplayString: fmt.Sprintf(self.c.Tr.Bisect.Mark, commit.ShortSha(), info.NewTerm()),
OnPress: func() error { OnPress: func() error {
@ -122,16 +121,16 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c
}, },
} }
return self.c.Menu(popup.CreateMenuOptions{ return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.Bisect.BisectMenuTitle, Title: self.c.Tr.Bisect.BisectMenuTitle,
Items: menuItems, Items: menuItems,
}) })
} }
func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo, commit *models.Commit) error { func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo, commit *models.Commit) error {
return self.c.Menu(popup.CreateMenuOptions{ return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.Bisect.BisectMenuTitle, Title: self.c.Tr.Bisect.BisectMenuTitle,
Items: []*popup.MenuItem{ Items: []*types.MenuItem{
{ {
DisplayString: fmt.Sprintf(self.c.Tr.Bisect.MarkStart, commit.ShortSha(), info.NewTerm()), DisplayString: fmt.Sprintf(self.c.Tr.Bisect.MarkStart, commit.ShortSha(), info.NewTerm()),
OnPress: func() error { OnPress: func() error {
@ -167,7 +166,7 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo,
} }
func (self *BisectController) Reset() error { func (self *BisectController) Reset() error {
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.Bisect.ResetTitle, Title: self.c.Tr.Bisect.ResetTitle,
Prompt: self.c.Tr.Bisect.ResetPrompt, Prompt: self.c.Tr.Bisect.ResetPrompt,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -192,7 +191,7 @@ func (self *BisectController) showBisectCompleteMessage(candidateShas []string)
return self.c.Error(err) return self.c.Error(err)
} }
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.Bisect.CompleteTitle, Title: self.c.Tr.Bisect.CompleteTitle,
Prompt: fmt.Sprintf(prompt, strings.TrimSpace(formattedCommits)), Prompt: fmt.Sprintf(prompt, strings.TrimSpace(formattedCommits)),
HandleConfirm: func() error { HandleConfirm: func() error {

View File

@ -1,10 +0,0 @@
package controllers
import "github.com/jesseduffield/lazygit/pkg/common"
// if Go let me do private struct embedding of structs with public fields (which it should)
// I would just do that. But alas.
type ControllerCommon struct {
*common.Common
IGuiCommon
}

View File

@ -12,7 +12,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/filetree" "github.com/jesseduffield/lazygit/pkg/gui/filetree"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
@ -22,7 +21,7 @@ type FilesController struct {
// case I would actually prefer a _zero_ letter variable name in the form of // case I would actually prefer a _zero_ letter variable name in the form of
// struct embedding, but Go does not allow hiding public fields in an embedded struct // struct embedding, but Go does not allow hiding public fields in an embedded struct
// to the client // to the client
c *ControllerCommon c *types.ControllerCommon
getContext func() types.IListContext getContext func() types.IListContext
git *commands.GitCommand git *commands.GitCommand
os *oscommands.OSCommand os *oscommands.OSCommand
@ -48,7 +47,7 @@ type FilesController struct {
var _ types.IController = &FilesController{} var _ types.IController = &FilesController{}
func NewFilesController( func NewFilesController(
c *ControllerCommon, c *types.ControllerCommon,
getContext func() types.IListContext, getContext func() types.IListContext,
git *commands.GitCommand, git *commands.GitCommand,
os *oscommands.OSCommand, os *oscommands.OSCommand,
@ -344,7 +343,7 @@ func (self *FilesController) ignore(node *filetree.FileNode) error {
} }
if node.GetIsTracked() { if node.GetIsTracked() {
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.IgnoreTracked, Title: self.c.Tr.IgnoreTracked,
Prompt: self.c.Tr.IgnoreTrackedPrompt, Prompt: self.c.Tr.IgnoreTrackedPrompt,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -461,7 +460,7 @@ func (self *FilesController) HandleCommitPress() error {
} }
func (self *FilesController) promptToStageAllAndRetry(retry func() error) error { func (self *FilesController) promptToStageAllAndRetry(retry func() error) error {
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.NoFilesStagedTitle, Title: self.c.Tr.NoFilesStagedTitle,
Prompt: self.c.Tr.NoFilesStagedPrompt, Prompt: self.c.Tr.NoFilesStagedPrompt,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -491,7 +490,7 @@ func (self *FilesController) handleAmendCommitPress() error {
return self.c.ErrorMsg(self.c.Tr.NoCommitToAmend) return self.c.ErrorMsg(self.c.Tr.NoCommitToAmend)
} }
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: strings.Title(self.c.Tr.AmendLastCommit), Title: strings.Title(self.c.Tr.AmendLastCommit),
Prompt: self.c.Tr.SureToAmend, Prompt: self.c.Tr.SureToAmend,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -520,9 +519,9 @@ func (self *FilesController) HandleCommitEditorPress() error {
} }
func (self *FilesController) handleStatusFilterPressed() error { func (self *FilesController) handleStatusFilterPressed() error {
return self.c.Menu(popup.CreateMenuOptions{ return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.FilteringMenuTitle, Title: self.c.Tr.FilteringMenuTitle,
Items: []*popup.MenuItem{ Items: []*types.MenuItem{
{ {
DisplayString: self.c.Tr.FilterStagedFiles, DisplayString: self.c.Tr.FilterStagedFiles,
OnPress: func() error { OnPress: func() error {
@ -577,7 +576,7 @@ func (self *FilesController) switchToMerge() error {
} }
func (self *FilesController) handleCustomCommand() error { func (self *FilesController) handleCustomCommand() error {
return self.c.Prompt(popup.PromptOpts{ return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.CustomCommand, Title: self.c.Tr.CustomCommand,
FindSuggestionsFunc: self.suggestionsHelper.GetCustomCommandsHistorySuggestionsFunc(), FindSuggestionsFunc: self.suggestionsHelper.GetCustomCommandsHistorySuggestionsFunc(),
HandleConfirm: func(command string) error { HandleConfirm: func(command string) error {
@ -602,9 +601,9 @@ func (self *FilesController) handleCustomCommand() error {
} }
func (self *FilesController) createStashMenu() error { func (self *FilesController) createStashMenu() error {
return self.c.Menu(popup.CreateMenuOptions{ return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.LcStashOptions, Title: self.c.Tr.LcStashOptions,
Items: []*popup.MenuItem{ Items: []*types.MenuItem{
{ {
DisplayString: self.c.Tr.LcStashAllChanges, DisplayString: self.c.Tr.LcStashAllChanges,
OnPress: func() error { OnPress: func() error {
@ -665,7 +664,7 @@ func (self *FilesController) toggleTreeView() error {
} }
func (self *FilesController) OpenMergeTool() error { func (self *FilesController) OpenMergeTool() error {
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.MergeToolTitle, Title: self.c.Tr.MergeToolTitle,
Prompt: self.c.Tr.MergeToolPrompt, Prompt: self.c.Tr.MergeToolPrompt,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -704,7 +703,7 @@ func (self *FilesController) handleStashSave(stashFunc func(message string) erro
return self.c.ErrorMsg(self.c.Tr.NoTrackedStagedFilesStash) return self.c.ErrorMsg(self.c.Tr.NoTrackedStagedFilesStash)
} }
return self.c.Prompt(popup.PromptOpts{ return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.StashChanges, Title: self.c.Tr.StashChanges,
HandleConfirm: func(stashComment string) error { HandleConfirm: func(stashComment string) error {
if err := stashFunc(stashComment); err != nil { if err := stashFunc(stashComment); err != nil {

View File

@ -9,7 +9,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
@ -26,7 +25,7 @@ type (
) )
type LocalCommitsController struct { type LocalCommitsController struct {
c *ControllerCommon c *types.ControllerCommon
getContext func() types.IListContext getContext func() types.IListContext
os *oscommands.OSCommand os *oscommands.OSCommand
git *commands.GitCommand git *commands.GitCommand
@ -50,7 +49,7 @@ type LocalCommitsController struct {
var _ types.IController = &LocalCommitsController{} var _ types.IController = &LocalCommitsController{}
func NewLocalCommitsController( func NewLocalCommitsController(
c *ControllerCommon, c *types.ControllerCommon,
getContext func() types.IListContext, getContext func() types.IListContext,
os *oscommands.OSCommand, os *oscommands.OSCommand,
git *commands.GitCommand, git *commands.GitCommand,
@ -241,7 +240,7 @@ func (self *LocalCommitsController) squashDown() error {
return nil return nil
} }
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.Squash, Title: self.c.Tr.Squash,
Prompt: self.c.Tr.SureSquashThisCommit, Prompt: self.c.Tr.SureSquashThisCommit,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -266,7 +265,7 @@ func (self *LocalCommitsController) fixup() error {
return nil return nil
} }
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.Fixup, Title: self.c.Tr.Fixup,
Prompt: self.c.Tr.SureFixupThisCommit, Prompt: self.c.Tr.SureFixupThisCommit,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -293,7 +292,7 @@ func (self *LocalCommitsController) reword(commit *models.Commit) error {
} }
// TODO: use the commit message panel here // TODO: use the commit message panel here
return self.c.Prompt(popup.PromptOpts{ return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.LcRewordCommit, Title: self.c.Tr.LcRewordCommit,
InitialContent: message, InitialContent: message,
HandleConfirm: func(response string) error { HandleConfirm: func(response string) error {
@ -339,7 +338,7 @@ func (self *LocalCommitsController) drop() error {
return nil return nil
} }
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.DeleteCommitTitle, Title: self.c.Tr.DeleteCommitTitle,
Prompt: self.c.Tr.DeleteCommitPrompt, Prompt: self.c.Tr.DeleteCommitPrompt,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -488,7 +487,7 @@ func (self *LocalCommitsController) handleCommitMoveUp() error {
} }
func (self *LocalCommitsController) handleCommitAmendTo() error { func (self *LocalCommitsController) handleCommitAmendTo() error {
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.AmendCommitTitle, Title: self.c.Tr.AmendCommitTitle,
Prompt: self.c.Tr.AmendCommitPrompt, Prompt: self.c.Tr.AmendCommitPrompt,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -505,7 +504,7 @@ func (self *LocalCommitsController) handleCommitRevert(commit *models.Commit) er
if commit.IsMerge() { if commit.IsMerge() {
return self.createRevertMergeCommitMenu(commit) return self.createRevertMergeCommitMenu(commit)
} else { } else {
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.Actions.RevertCommit, Title: self.c.Tr.Actions.RevertCommit,
Prompt: utils.ResolvePlaceholderString( Prompt: utils.ResolvePlaceholderString(
self.c.Tr.ConfirmRevertCommit, self.c.Tr.ConfirmRevertCommit,
@ -524,7 +523,7 @@ func (self *LocalCommitsController) handleCommitRevert(commit *models.Commit) er
} }
func (self *LocalCommitsController) createRevertMergeCommitMenu(commit *models.Commit) error { func (self *LocalCommitsController) createRevertMergeCommitMenu(commit *models.Commit) error {
menuItems := make([]*popup.MenuItem, len(commit.Parents)) menuItems := make([]*types.MenuItem, len(commit.Parents))
for i, parentSha := range commit.Parents { for i, parentSha := range commit.Parents {
i := i i := i
message, err := self.git.Commit.GetCommitMessageFirstLine(parentSha) message, err := self.git.Commit.GetCommitMessageFirstLine(parentSha)
@ -532,7 +531,7 @@ func (self *LocalCommitsController) createRevertMergeCommitMenu(commit *models.C
return self.c.Error(err) return self.c.Error(err)
} }
menuItems[i] = &popup.MenuItem{ menuItems[i] = &types.MenuItem{
DisplayString: fmt.Sprintf("%s: %s", utils.SafeTruncate(parentSha, 8), message), DisplayString: fmt.Sprintf("%s: %s", utils.SafeTruncate(parentSha, 8), message),
OnPress: func() error { OnPress: func() error {
parentNumber := i + 1 parentNumber := i + 1
@ -545,7 +544,7 @@ func (self *LocalCommitsController) createRevertMergeCommitMenu(commit *models.C
} }
} }
return self.c.Menu(popup.CreateMenuOptions{Title: self.c.Tr.SelectParentCommitForMerge, Items: menuItems}) return self.c.Menu(types.CreateMenuOptions{Title: self.c.Tr.SelectParentCommitForMerge, Items: menuItems})
} }
func (self *LocalCommitsController) afterRevertCommit() error { func (self *LocalCommitsController) afterRevertCommit() error {
@ -572,7 +571,7 @@ func (self *LocalCommitsController) handleCreateFixupCommit(commit *models.Commi
}, },
) )
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.CreateFixupCommit, Title: self.c.Tr.CreateFixupCommit,
Prompt: prompt, Prompt: prompt,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -594,7 +593,7 @@ func (self *LocalCommitsController) handleSquashAllAboveFixupCommits(commit *mod
}, },
) )
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.SquashAboveCommits, Title: self.c.Tr.SquashAboveCommits,
Prompt: prompt, Prompt: prompt,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -612,7 +611,7 @@ func (self *LocalCommitsController) handleTagCommit(commit *models.Commit) error
} }
func (self *LocalCommitsController) handleCheckoutCommit(commit *models.Commit) error { func (self *LocalCommitsController) handleCheckoutCommit(commit *models.Commit) error {
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.LcCheckoutCommit, Title: self.c.Tr.LcCheckoutCommit,
Prompt: self.c.Tr.SureCheckoutThisCommit, Prompt: self.c.Tr.SureCheckoutThisCommit,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -669,9 +668,9 @@ func (self *LocalCommitsController) handleCopySelectedCommitMessageToClipboard(c
} }
func (self *LocalCommitsController) handleOpenLogMenu() error { func (self *LocalCommitsController) handleOpenLogMenu() error {
return self.c.Menu(popup.CreateMenuOptions{ return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.LogMenuTitle, Title: self.c.Tr.LogMenuTitle,
Items: []*popup.MenuItem{ Items: []*types.MenuItem{
{ {
DisplayString: self.c.Tr.ToggleShowGitGraphAll, DisplayString: self.c.Tr.ToggleShowGitGraphAll,
OnPress: func() error { OnPress: func() error {
@ -696,9 +695,9 @@ func (self *LocalCommitsController) handleOpenLogMenu() error {
return nil return nil
} }
} }
return self.c.Menu(popup.CreateMenuOptions{ return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.LogMenuTitle, Title: self.c.Tr.LogMenuTitle,
Items: []*popup.MenuItem{ Items: []*types.MenuItem{
{ {
DisplayString: "always", DisplayString: "always",
OnPress: onPress("always"), OnPress: onPress("always"),
@ -728,9 +727,9 @@ func (self *LocalCommitsController) handleOpenLogMenu() error {
} }
} }
return self.c.Menu(popup.CreateMenuOptions{ return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.LogMenuTitle, Title: self.c.Tr.LogMenuTitle,
Items: []*popup.MenuItem{ Items: []*types.MenuItem{
{ {
DisplayString: "topological (topo-order)", DisplayString: "topological (topo-order)",
OnPress: onPress("topo-order"), OnPress: onPress("topo-order"),

View File

@ -3,23 +3,22 @@ package controllers
import ( import (
"github.com/jesseduffield/gocui" "github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
type MenuController struct { type MenuController struct {
c *ControllerCommon c *types.ControllerCommon
getContext func() types.IListContext getContext func() types.IListContext
getSelectedMenuItem func() *popup.MenuItem getSelectedMenuItem func() *types.MenuItem
} }
var _ types.IController = &MenuController{} var _ types.IController = &MenuController{}
func NewMenuController( func NewMenuController(
c *ControllerCommon, c *types.ControllerCommon,
getContext func() types.IListContext, getContext func() types.IListContext,
getSelectedMenuItem func() *popup.MenuItem, getSelectedMenuItem func() *types.MenuItem,
) *MenuController { ) *MenuController {
return &MenuController{ return &MenuController{
c: c, c: c,

View File

@ -6,13 +6,12 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
type RemotesController struct { type RemotesController struct {
c *ControllerCommon c *types.ControllerCommon
getContext func() types.IListContext getContext func() types.IListContext
git *commands.GitCommand git *commands.GitCommand
@ -24,7 +23,7 @@ type RemotesController struct {
var _ types.IController = &RemotesController{} var _ types.IController = &RemotesController{}
func NewRemotesController( func NewRemotesController(
c *ControllerCommon, c *types.ControllerCommon,
getContext func() types.IListContext, getContext func() types.IListContext,
git *commands.GitCommand, git *commands.GitCommand,
getContexts func() context.ContextTree, getContexts func() context.ContextTree,
@ -90,10 +89,10 @@ func (self *RemotesController) enter(remote *models.Remote) error {
} }
func (self *RemotesController) add() error { func (self *RemotesController) add() error {
return self.c.Prompt(popup.PromptOpts{ return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.LcNewRemoteName, Title: self.c.Tr.LcNewRemoteName,
HandleConfirm: func(remoteName string) error { HandleConfirm: func(remoteName string) error {
return self.c.Prompt(popup.PromptOpts{ return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.LcNewRemoteUrl, Title: self.c.Tr.LcNewRemoteUrl,
HandleConfirm: func(remoteUrl string) error { HandleConfirm: func(remoteUrl string) error {
self.c.LogAction(self.c.Tr.Actions.AddRemote) self.c.LogAction(self.c.Tr.Actions.AddRemote)
@ -108,7 +107,7 @@ func (self *RemotesController) add() error {
} }
func (self *RemotesController) remove(remote *models.Remote) error { func (self *RemotesController) remove(remote *models.Remote) error {
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.LcRemoveRemote, Title: self.c.Tr.LcRemoveRemote,
Prompt: self.c.Tr.LcRemoveRemotePrompt + " '" + remote.Name + "'?", Prompt: self.c.Tr.LcRemoveRemotePrompt + " '" + remote.Name + "'?",
HandleConfirm: func() error { HandleConfirm: func() error {
@ -130,7 +129,7 @@ func (self *RemotesController) edit(remote *models.Remote) error {
}, },
) )
return self.c.Prompt(popup.PromptOpts{ return self.c.Prompt(types.PromptOpts{
Title: editNameMessage, Title: editNameMessage,
InitialContent: remote.Name, InitialContent: remote.Name,
HandleConfirm: func(updatedRemoteName string) error { HandleConfirm: func(updatedRemoteName string) error {
@ -154,7 +153,7 @@ func (self *RemotesController) edit(remote *models.Remote) error {
url = urls[0] url = urls[0]
} }
return self.c.Prompt(popup.PromptOpts{ return self.c.Prompt(types.PromptOpts{
Title: editUrlMessage, Title: editUrlMessage,
InitialContent: url, InitialContent: url,
HandleConfirm: func(updatedRemoteUrl string) error { HandleConfirm: func(updatedRemoteUrl string) error {

View File

@ -9,13 +9,12 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
type SubmodulesController struct { type SubmodulesController struct {
c *ControllerCommon c *types.ControllerCommon
context types.IListContext context types.IListContext
git *commands.GitCommand git *commands.GitCommand
@ -26,7 +25,7 @@ type SubmodulesController struct {
var _ types.IController = &SubmodulesController{} var _ types.IController = &SubmodulesController{}
func NewSubmodulesController( func NewSubmodulesController(
c *ControllerCommon, c *types.ControllerCommon,
context types.IListContext, context types.IListContext,
git *commands.GitCommand, git *commands.GitCommand,
enterSubmodule func(submodule *models.SubmoduleConfig) error, enterSubmodule func(submodule *models.SubmoduleConfig) error,
@ -93,17 +92,17 @@ func (self *SubmodulesController) enter(submodule *models.SubmoduleConfig) error
} }
func (self *SubmodulesController) add() error { func (self *SubmodulesController) add() error {
return self.c.Prompt(popup.PromptOpts{ return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.LcNewSubmoduleUrl, Title: self.c.Tr.LcNewSubmoduleUrl,
HandleConfirm: func(submoduleUrl string) error { HandleConfirm: func(submoduleUrl string) error {
nameSuggestion := filepath.Base(strings.TrimSuffix(submoduleUrl, filepath.Ext(submoduleUrl))) nameSuggestion := filepath.Base(strings.TrimSuffix(submoduleUrl, filepath.Ext(submoduleUrl)))
return self.c.Prompt(popup.PromptOpts{ return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.LcNewSubmoduleName, Title: self.c.Tr.LcNewSubmoduleName,
InitialContent: nameSuggestion, InitialContent: nameSuggestion,
HandleConfirm: func(submoduleName string) error { HandleConfirm: func(submoduleName string) error {
return self.c.Prompt(popup.PromptOpts{ return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.LcNewSubmodulePath, Title: self.c.Tr.LcNewSubmodulePath,
InitialContent: submoduleName, InitialContent: submoduleName,
HandleConfirm: func(submodulePath string) error { HandleConfirm: func(submodulePath string) error {
@ -125,7 +124,7 @@ func (self *SubmodulesController) add() error {
} }
func (self *SubmodulesController) editURL(submodule *models.SubmoduleConfig) error { func (self *SubmodulesController) editURL(submodule *models.SubmoduleConfig) error {
return self.c.Prompt(popup.PromptOpts{ return self.c.Prompt(types.PromptOpts{
Title: fmt.Sprintf(self.c.Tr.LcUpdateSubmoduleUrl, submodule.Name), Title: fmt.Sprintf(self.c.Tr.LcUpdateSubmoduleUrl, submodule.Name),
InitialContent: submodule.Url, InitialContent: submodule.Url,
HandleConfirm: func(newUrl string) error { HandleConfirm: func(newUrl string) error {
@ -155,9 +154,9 @@ func (self *SubmodulesController) init(submodule *models.SubmoduleConfig) error
} }
func (self *SubmodulesController) openBulkActionsMenu() error { func (self *SubmodulesController) openBulkActionsMenu() error {
return self.c.Menu(popup.CreateMenuOptions{ return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.LcBulkSubmoduleOptions, Title: self.c.Tr.LcBulkSubmoduleOptions,
Items: []*popup.MenuItem{ Items: []*types.MenuItem{
{ {
DisplayStrings: []string{self.c.Tr.LcBulkInitSubmodules, style.FgGreen.Sprint(self.git.Submodule.BulkInitCmdObj().ToString())}, DisplayStrings: []string{self.c.Tr.LcBulkInitSubmodules, style.FgGreen.Sprint(self.git.Submodule.BulkInitCmdObj().ToString())},
OnPress: func() error { OnPress: func() error {
@ -215,7 +214,7 @@ func (self *SubmodulesController) update(submodule *models.SubmoduleConfig) erro
} }
func (self *SubmodulesController) remove(submodule *models.SubmoduleConfig) error { func (self *SubmodulesController) remove(submodule *models.SubmoduleConfig) error {
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.RemoveSubmodule, Title: self.c.Tr.RemoveSubmodule,
Prompt: fmt.Sprintf(self.c.Tr.RemoveSubmodulePrompt, submodule.Name), Prompt: fmt.Sprintf(self.c.Tr.RemoveSubmodulePrompt, submodule.Name),
HandleConfirm: func() error { HandleConfirm: func() error {

View File

@ -8,7 +8,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
@ -17,7 +16,7 @@ type SyncController struct {
// case I would actually prefer a _zero_ letter variable name in the form of // case I would actually prefer a _zero_ letter variable name in the form of
// struct embedding, but Go does not allow hiding public fields in an embedded struct // struct embedding, but Go does not allow hiding public fields in an embedded struct
// to the client // to the client
c *ControllerCommon c *types.ControllerCommon
git *commands.GitCommand git *commands.GitCommand
getCheckedOutBranch func() *models.Branch getCheckedOutBranch func() *models.Branch
@ -29,7 +28,7 @@ type SyncController struct {
var _ types.IController = &SyncController{} var _ types.IController = &SyncController{}
func NewSyncController( func NewSyncController(
c *ControllerCommon, c *types.ControllerCommon,
git *commands.GitCommand, git *commands.GitCommand,
getCheckedOutBranch func() *models.Branch, getCheckedOutBranch func() *models.Branch,
suggestionsHelper ISuggestionsHelper, suggestionsHelper ISuggestionsHelper,
@ -160,7 +159,7 @@ func (self *SyncController) pull(currentBranch *models.Branch) error {
func (self *SyncController) promptForUpstream(currentBranch *models.Branch, onConfirm func(string) error) error { func (self *SyncController) promptForUpstream(currentBranch *models.Branch, onConfirm func(string) error) error {
suggestedRemote := self.getSuggestedRemote() suggestedRemote := self.getSuggestedRemote()
return self.c.Prompt(popup.PromptOpts{ return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.EnterUpstream, Title: self.c.Tr.EnterUpstream,
InitialContent: suggestedRemote + " " + currentBranch.Name, InitialContent: suggestedRemote + " " + currentBranch.Name,
FindSuggestionsFunc: self.suggestionsHelper.GetRemoteBranchesSuggestionsFunc(" "), FindSuggestionsFunc: self.suggestionsHelper.GetRemoteBranchesSuggestionsFunc(" "),
@ -219,7 +218,7 @@ func (self *SyncController) pushAux(opts pushOpts) error {
_ = self.c.ErrorMsg(self.c.Tr.UpdatesRejectedAndForcePushDisabled) _ = self.c.ErrorMsg(self.c.Tr.UpdatesRejectedAndForcePushDisabled)
return nil return nil
} }
_ = self.c.Ask(popup.AskOpts{ _ = self.c.Ask(types.AskOpts{
Title: self.c.Tr.ForcePush, Title: self.c.Tr.ForcePush,
Prompt: self.c.Tr.ForcePushPrompt, Prompt: self.c.Tr.ForcePushPrompt,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -243,7 +242,7 @@ func (self *SyncController) requestToForcePush(opts pushOpts) error {
return self.c.ErrorMsg(self.c.Tr.ForcePushDisabled) return self.c.ErrorMsg(self.c.Tr.ForcePushDisabled)
} }
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.ForcePush, Title: self.c.Tr.ForcePush,
Prompt: self.c.Tr.ForcePushPrompt, Prompt: self.c.Tr.ForcePushPrompt,
HandleConfirm: func() error { HandleConfirm: func() error {

View File

@ -5,35 +5,32 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
type TagsController struct { type TagsController struct {
c *ControllerCommon c *types.ControllerCommon
getContext func() types.IListContext getContext func() *context.TagsContext
git *commands.GitCommand git *commands.GitCommand
getContexts func() context.ContextTree getContexts func() context.ContextTree
refHelper IRefHelper refHelper IRefHelper
suggestionsHelper ISuggestionsHelper suggestionsHelper ISuggestionsHelper
getSelectedTag func() *models.Tag
switchToSubCommitsContext func(string) error switchToSubCommitsContext func(string) error
} }
var _ types.IController = &TagsController{} var _ types.IController = &TagsController{}
func NewTagsController( func NewTagsController(
c *ControllerCommon, c *types.ControllerCommon,
getContext func() types.IListContext, getContext func() *context.TagsContext,
git *commands.GitCommand, git *commands.GitCommand,
getContexts func() context.ContextTree, getContexts func() context.ContextTree,
refHelper IRefHelper, refHelper IRefHelper,
suggestionsHelper ISuggestionsHelper, suggestionsHelper ISuggestionsHelper,
getSelectedTag func() *models.Tag,
switchToSubCommitsContext func(string) error, switchToSubCommitsContext func(string) error,
) *TagsController { ) *TagsController {
return &TagsController{ return &TagsController{
@ -44,7 +41,6 @@ func NewTagsController(
refHelper: refHelper, refHelper: refHelper,
suggestionsHelper: suggestionsHelper, suggestionsHelper: suggestionsHelper,
getSelectedTag: getSelectedTag,
switchToSubCommitsContext: switchToSubCommitsContext, switchToSubCommitsContext: switchToSubCommitsContext,
} }
} }
@ -107,7 +103,7 @@ func (self *TagsController) delete(tag *models.Tag) error {
}, },
) )
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.DeleteTagTitle, Title: self.c.Tr.DeleteTagTitle,
Prompt: prompt, Prompt: prompt,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -128,7 +124,7 @@ func (self *TagsController) push(tag *models.Tag) error {
}, },
) )
return self.c.Prompt(popup.PromptOpts{ return self.c.Prompt(types.PromptOpts{
Title: title, Title: title,
InitialContent: "origin", InitialContent: "origin",
FindSuggestionsFunc: self.suggestionsHelper.GetRemoteSuggestionsFunc(), FindSuggestionsFunc: self.suggestionsHelper.GetRemoteSuggestionsFunc(),
@ -151,9 +147,9 @@ func (self *TagsController) createResetMenu(tag *models.Tag) error {
} }
func (self *TagsController) CreateTagMenu(commitSha string) error { func (self *TagsController) CreateTagMenu(commitSha string) error {
return self.c.Menu(popup.CreateMenuOptions{ return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.TagMenuTitle, Title: self.c.Tr.TagMenuTitle,
Items: []*popup.MenuItem{ Items: []*types.MenuItem{
{ {
DisplayString: self.c.Tr.LcLightweightTag, DisplayString: self.c.Tr.LcLightweightTag,
OnPress: func() error { OnPress: func() error {
@ -178,10 +174,10 @@ func (self *TagsController) afterTagCreate() error {
} }
func (self *TagsController) handleCreateAnnotatedTag(commitSha string) error { func (self *TagsController) handleCreateAnnotatedTag(commitSha string) error {
return self.c.Prompt(popup.PromptOpts{ return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.TagNameTitle, Title: self.c.Tr.TagNameTitle,
HandleConfirm: func(tagName string) error { HandleConfirm: func(tagName string) error {
return self.c.Prompt(popup.PromptOpts{ return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.TagMessageTitle, Title: self.c.Tr.TagMessageTitle,
HandleConfirm: func(msg string) error { HandleConfirm: func(msg string) error {
self.c.LogAction(self.c.Tr.Actions.CreateAnnotatedTag) self.c.LogAction(self.c.Tr.Actions.CreateAnnotatedTag)
@ -196,7 +192,7 @@ func (self *TagsController) handleCreateAnnotatedTag(commitSha string) error {
} }
func (self *TagsController) handleCreateLightweightTag(commitSha string) error { func (self *TagsController) handleCreateLightweightTag(commitSha string) error {
return self.c.Prompt(popup.PromptOpts{ return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.TagNameTitle, Title: self.c.Tr.TagNameTitle,
HandleConfirm: func(tagName string) error { HandleConfirm: func(tagName string) error {
self.c.LogAction(self.c.Tr.Actions.CreateLightweightTag) self.c.LogAction(self.c.Tr.Actions.CreateLightweightTag)
@ -215,7 +211,7 @@ func (self *TagsController) create() error {
func (self *TagsController) withSelectedTag(f func(tag *models.Tag) error) func() error { func (self *TagsController) withSelectedTag(f func(tag *models.Tag) error) func() error {
return func() error { return func() error {
tag := self.getSelectedTag() tag := self.getContext().GetSelectedTag()
if tag == nil { if tag == nil {
return nil return nil
} }

View File

@ -2,31 +2,9 @@ package controllers
import ( import (
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
type IGuiCommon interface {
popup.IPopupHandler
LogAction(action string)
LogCommand(cmdStr string, isCommandLine bool)
// we call this when we want to refetch some models and render the result. Internally calls PostRefreshUpdate
Refresh(types.RefreshOptions) error
// we call this when we've changed something in the view model but not the actual model,
// e.g. expanding or collapsing a folder in a file view. Calling 'Refresh' in this
// case would be overkill, although refresh will internally call 'PostRefreshUpdate'
PostRefreshUpdate(types.Context) error
RunSubprocessAndRefresh(oscommands.ICmdObj) error
PushContext(context types.Context, opts ...types.OnFocusOpts) error
PopContext() error
GetAppState() *config.AppState
SaveAppState() error
}
type IRefHelper interface { type IRefHelper interface {
CheckoutRef(ref string, options types.CheckoutRefOptions) error CheckoutRef(ref string, options types.CheckoutRefOptions) error
CreateGitResetMenu(ref string) error CreateGitResetMenu(ref string) error

View File

@ -5,7 +5,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/types/enums" "github.com/jesseduffield/lazygit/pkg/commands/types/enums"
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
@ -21,7 +20,7 @@ import (
// two user actions, meaning we end up undoing reflog entry C. Redoing works in a similar way. // two user actions, meaning we end up undoing reflog entry C. Redoing works in a similar way.
type UndoController struct { type UndoController struct {
c *ControllerCommon c *types.ControllerCommon
git *commands.GitCommand git *commands.GitCommand
refHelper IRefHelper refHelper IRefHelper
@ -33,7 +32,7 @@ type UndoController struct {
var _ types.IController = &UndoController{} var _ types.IController = &UndoController{}
func NewUndoController( func NewUndoController(
c *ControllerCommon, c *types.ControllerCommon,
git *commands.GitCommand, git *commands.GitCommand,
refHelper IRefHelper, refHelper IRefHelper,
workingTreeHelper IWorkingTreeHelper, workingTreeHelper IWorkingTreeHelper,
@ -235,7 +234,7 @@ func (self *UndoController) hardResetWithAutoStash(commitSha string, options har
dirtyWorkingTree := self.workingTreeHelper.IsWorkingTreeDirty() dirtyWorkingTree := self.workingTreeHelper.IsWorkingTreeDirty()
if dirtyWorkingTree { if dirtyWorkingTree {
// offer to autostash changes // offer to autostash changes
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.AutoStashTitle, Title: self.c.Tr.AutoStashTitle,
Prompt: self.c.Tr.AutoStashPrompt, Prompt: self.c.Tr.AutoStashPrompt,
HandleConfirm: func() error { HandleConfirm: func() error {

View File

@ -12,7 +12,6 @@ import (
"github.com/jesseduffield/gocui" "github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
@ -49,7 +48,7 @@ func (gui *Gui) resolveTemplate(templateStr string, promptResponses []string) (s
SelectedLocalBranch: gui.getSelectedBranch(), SelectedLocalBranch: gui.getSelectedBranch(),
SelectedRemoteBranch: gui.getSelectedRemoteBranch(), SelectedRemoteBranch: gui.getSelectedRemoteBranch(),
SelectedRemote: gui.getSelectedRemote(), SelectedRemote: gui.getSelectedRemote(),
SelectedTag: gui.getSelectedTag(), SelectedTag: gui.State.Contexts.Tags.GetSelectedTag(),
SelectedStashEntry: gui.getSelectedStashEntry(), SelectedStashEntry: gui.getSelectedStashEntry(),
SelectedCommitFile: gui.getSelectedCommitFile(), SelectedCommitFile: gui.getSelectedCommitFile(),
SelectedCommitFilePath: gui.getSelectedCommitFilePath(), SelectedCommitFilePath: gui.getSelectedCommitFilePath(),
@ -72,7 +71,7 @@ func (gui *Gui) inputPrompt(prompt config.CustomCommandPrompt, promptResponses [
return gui.c.Error(err) return gui.c.Error(err)
} }
return gui.c.Prompt(popup.PromptOpts{ return gui.c.Prompt(types.PromptOpts{
Title: title, Title: title,
InitialContent: initialValue, InitialContent: initialValue,
HandleConfirm: func(str string) error { HandleConfirm: func(str string) error {
@ -84,7 +83,7 @@ func (gui *Gui) inputPrompt(prompt config.CustomCommandPrompt, promptResponses [
func (gui *Gui) menuPrompt(prompt config.CustomCommandPrompt, promptResponses []string, responseIdx int, wrappedF func() error) error { func (gui *Gui) menuPrompt(prompt config.CustomCommandPrompt, promptResponses []string, responseIdx int, wrappedF func() error) error {
// need to make a menu here some how // need to make a menu here some how
menuItems := make([]*popup.MenuItem, len(prompt.Options)) menuItems := make([]*types.MenuItem, len(prompt.Options))
for i, option := range prompt.Options { for i, option := range prompt.Options {
option := option option := option
@ -108,7 +107,7 @@ func (gui *Gui) menuPrompt(prompt config.CustomCommandPrompt, promptResponses []
return gui.c.Error(err) return gui.c.Error(err)
} }
menuItems[i] = &popup.MenuItem{ menuItems[i] = &types.MenuItem{
DisplayStrings: []string{name, style.FgYellow.Sprint(description)}, DisplayStrings: []string{name, style.FgYellow.Sprint(description)},
OnPress: func() error { OnPress: func() error {
promptResponses[responseIdx] = value promptResponses[responseIdx] = value
@ -122,7 +121,7 @@ func (gui *Gui) menuPrompt(prompt config.CustomCommandPrompt, promptResponses []
return gui.c.Error(err) return gui.c.Error(err)
} }
return gui.c.Menu(popup.CreateMenuOptions{Title: title, Items: menuItems}) return gui.c.Menu(types.CreateMenuOptions{Title: title, Items: menuItems})
} }
func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, labelFormat string) ([]commandMenuEntry, error) { func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, labelFormat string) ([]commandMenuEntry, error) {
@ -216,10 +215,10 @@ func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptR
return gui.c.Error(err) return gui.c.Error(err)
} }
menuItems := make([]*popup.MenuItem, len(candidates)) menuItems := make([]*types.MenuItem, len(candidates))
for i := range candidates { for i := range candidates {
i := i i := i
menuItems[i] = &popup.MenuItem{ menuItems[i] = &types.MenuItem{
DisplayStrings: []string{candidates[i].label}, DisplayStrings: []string{candidates[i].label},
OnPress: func() error { OnPress: func() error {
promptResponses[responseIdx] = candidates[i].value promptResponses[responseIdx] = candidates[i].value
@ -233,7 +232,7 @@ func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptR
return gui.c.Error(err) return gui.c.Error(err)
} }
return gui.c.Menu(popup.CreateMenuOptions{Title: title, Items: menuItems}) return gui.c.Menu(types.CreateMenuOptions{Title: title, Items: menuItems})
} }
func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand) func() error { func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand) func() error {

View File

@ -5,7 +5,6 @@ import (
"strings" "strings"
"github.com/jesseduffield/lazygit/pkg/gui/modes/diffing" "github.com/jesseduffield/lazygit/pkg/gui/modes/diffing"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
@ -107,10 +106,10 @@ func (gui *Gui) diffStr() string {
func (gui *Gui) handleCreateDiffingMenuPanel() error { func (gui *Gui) handleCreateDiffingMenuPanel() error {
names := gui.currentDiffTerminals() names := gui.currentDiffTerminals()
menuItems := []*popup.MenuItem{} menuItems := []*types.MenuItem{}
for _, name := range names { for _, name := range names {
name := name name := name
menuItems = append(menuItems, []*popup.MenuItem{ menuItems = append(menuItems, []*types.MenuItem{
{ {
DisplayString: fmt.Sprintf("%s %s", gui.c.Tr.LcDiff, name), DisplayString: fmt.Sprintf("%s %s", gui.c.Tr.LcDiff, name),
OnPress: func() error { OnPress: func() error {
@ -122,11 +121,11 @@ func (gui *Gui) handleCreateDiffingMenuPanel() error {
}...) }...)
} }
menuItems = append(menuItems, []*popup.MenuItem{ menuItems = append(menuItems, []*types.MenuItem{
{ {
DisplayString: gui.c.Tr.LcEnterRefToDiff, DisplayString: gui.c.Tr.LcEnterRefToDiff,
OnPress: func() error { OnPress: func() error {
return gui.c.Prompt(popup.PromptOpts{ return gui.c.Prompt(types.PromptOpts{
Title: gui.c.Tr.LcEnteRefName, Title: gui.c.Tr.LcEnteRefName,
FindSuggestionsFunc: gui.suggestionsHelper.GetRefsSuggestionsFunc(), FindSuggestionsFunc: gui.suggestionsHelper.GetRefsSuggestionsFunc(),
HandleConfirm: func(response string) error { HandleConfirm: func(response string) error {
@ -139,7 +138,7 @@ func (gui *Gui) handleCreateDiffingMenuPanel() error {
}...) }...)
if gui.State.Modes.Diffing.Active() { if gui.State.Modes.Diffing.Active() {
menuItems = append(menuItems, []*popup.MenuItem{ menuItems = append(menuItems, []*types.MenuItem{
{ {
DisplayString: gui.c.Tr.LcSwapDiff, DisplayString: gui.c.Tr.LcSwapDiff,
OnPress: func() error { OnPress: func() error {
@ -157,5 +156,5 @@ func (gui *Gui) handleCreateDiffingMenuPanel() error {
}...) }...)
} }
return gui.c.Menu(popup.CreateMenuOptions{Title: gui.c.Tr.DiffingMenuTitle, Items: menuItems}) return gui.c.Menu(types.CreateMenuOptions{Title: gui.c.Tr.DiffingMenuTitle, Items: menuItems})
} }

View File

@ -1,7 +1,6 @@
package gui package gui
import ( import (
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
@ -11,9 +10,9 @@ func (gui *Gui) handleCreateDiscardMenu() error {
return nil return nil
} }
var menuItems []*popup.MenuItem var menuItems []*types.MenuItem
if node.File == nil { if node.File == nil {
menuItems = []*popup.MenuItem{ menuItems = []*types.MenuItem{
{ {
DisplayString: gui.c.Tr.LcDiscardAllChanges, DisplayString: gui.c.Tr.LcDiscardAllChanges,
OnPress: func() error { OnPress: func() error {
@ -27,7 +26,7 @@ func (gui *Gui) handleCreateDiscardMenu() error {
} }
if node.GetHasStagedChanges() && node.GetHasUnstagedChanges() { if node.GetHasStagedChanges() && node.GetHasUnstagedChanges() {
menuItems = append(menuItems, &popup.MenuItem{ menuItems = append(menuItems, &types.MenuItem{
DisplayString: gui.c.Tr.LcDiscardUnstagedChanges, DisplayString: gui.c.Tr.LcDiscardUnstagedChanges,
OnPress: func() error { OnPress: func() error {
gui.c.LogAction(gui.c.Tr.Actions.DiscardUnstagedChangesInDirectory) gui.c.LogAction(gui.c.Tr.Actions.DiscardUnstagedChangesInDirectory)
@ -46,7 +45,7 @@ func (gui *Gui) handleCreateDiscardMenu() error {
if file.IsSubmodule(submodules) { if file.IsSubmodule(submodules) {
submodule := file.SubmoduleConfig(submodules) submodule := file.SubmoduleConfig(submodules)
menuItems = []*popup.MenuItem{ menuItems = []*types.MenuItem{
{ {
DisplayString: gui.c.Tr.LcSubmoduleStashAndReset, DisplayString: gui.c.Tr.LcSubmoduleStashAndReset,
OnPress: func() error { OnPress: func() error {
@ -55,7 +54,7 @@ func (gui *Gui) handleCreateDiscardMenu() error {
}, },
} }
} else { } else {
menuItems = []*popup.MenuItem{ menuItems = []*types.MenuItem{
{ {
DisplayString: gui.c.Tr.LcDiscardAllChanges, DisplayString: gui.c.Tr.LcDiscardAllChanges,
OnPress: func() error { OnPress: func() error {
@ -69,7 +68,7 @@ func (gui *Gui) handleCreateDiscardMenu() error {
} }
if file.HasStagedChanges && file.HasUnstagedChanges { if file.HasStagedChanges && file.HasUnstagedChanges {
menuItems = append(menuItems, &popup.MenuItem{ menuItems = append(menuItems, &types.MenuItem{
DisplayString: gui.c.Tr.LcDiscardUnstagedChanges, DisplayString: gui.c.Tr.LcDiscardUnstagedChanges,
OnPress: func() error { OnPress: func() error {
gui.c.LogAction(gui.c.Tr.Actions.DiscardAllUnstagedChangesInFile) gui.c.LogAction(gui.c.Tr.Actions.DiscardAllUnstagedChangesInFile)
@ -84,5 +83,5 @@ func (gui *Gui) handleCreateDiscardMenu() error {
} }
} }
return gui.c.Menu(popup.CreateMenuOptions{Title: node.GetPath(), Items: menuItems}) return gui.c.Menu(types.CreateMenuOptions{Title: node.GetPath(), Items: menuItems})
} }

View File

@ -3,14 +3,14 @@ package gui
import ( import (
"io" "io"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types"
) )
func (gui *Gui) handleCreateExtrasMenuPanel() error { func (gui *Gui) handleCreateExtrasMenuPanel() error {
return gui.c.Menu(popup.CreateMenuOptions{ return gui.c.Menu(types.CreateMenuOptions{
Title: gui.c.Tr.CommandLog, Title: gui.c.Tr.CommandLog,
Items: []*popup.MenuItem{ Items: []*types.MenuItem{
{ {
DisplayString: gui.c.Tr.ToggleShowCommandLog, DisplayString: gui.c.Tr.ToggleShowCommandLog,
OnPress: func() error { OnPress: func() error {

View File

@ -4,16 +4,17 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/controllers"
"github.com/jesseduffield/lazygit/pkg/gui/types"
) )
type FileHelper struct { type FileHelper struct {
c *controllers.ControllerCommon c *types.ControllerCommon
git *commands.GitCommand git *commands.GitCommand
os *oscommands.OSCommand os *oscommands.OSCommand
} }
func NewFileHelper( func NewFileHelper(
c *controllers.ControllerCommon, c *types.ControllerCommon,
git *commands.GitCommand, git *commands.GitCommand,
os *oscommands.OSCommand, os *oscommands.OSCommand,
) *FileHelper { ) *FileHelper {

View File

@ -7,7 +7,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/types/enums" "github.com/jesseduffield/lazygit/pkg/commands/types/enums"
"github.com/jesseduffield/lazygit/pkg/gui/filetree" "github.com/jesseduffield/lazygit/pkg/gui/filetree"
"github.com/jesseduffield/lazygit/pkg/gui/mergeconflicts" "github.com/jesseduffield/lazygit/pkg/gui/mergeconflicts"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
@ -252,7 +251,7 @@ func (gui *Gui) refreshStateFiles() error {
func (gui *Gui) promptToContinueRebase() error { func (gui *Gui) promptToContinueRebase() error {
gui.takeOverMergeConflictScrolling() gui.takeOverMergeConflictScrolling()
return gui.PopupHandler.Ask(popup.AskOpts{ return gui.PopupHandler.Ask(types.AskOpts{
Title: "continue", Title: "continue",
Prompt: gui.Tr.ConflictsResolved, Prompt: gui.Tr.ConflictsResolved,
HandleConfirm: func() error { HandleConfirm: func() error {

View File

@ -1,13 +1,12 @@
package gui package gui
import ( import (
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
func (gui *Gui) validateNotInFilterMode() bool { func (gui *Gui) validateNotInFilterMode() bool {
if gui.State.Modes.Filtering.Active() { if gui.State.Modes.Filtering.Active() {
_ = gui.c.Ask(popup.AskOpts{ _ = gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.MustExitFilterModeTitle, Title: gui.c.Tr.MustExitFilterModeTitle,
Prompt: gui.c.Tr.MustExitFilterModePrompt, Prompt: gui.c.Tr.MustExitFilterModePrompt,
HandleConfirm: gui.exitFilterMode, HandleConfirm: gui.exitFilterMode,

View File

@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
func (gui *Gui) handleCreateFilteringMenuPanel() error { func (gui *Gui) handleCreateFilteringMenuPanel() error {
@ -22,10 +22,10 @@ func (gui *Gui) handleCreateFilteringMenuPanel() error {
} }
} }
menuItems := []*popup.MenuItem{} menuItems := []*types.MenuItem{}
if fileName != "" { if fileName != "" {
menuItems = append(menuItems, &popup.MenuItem{ menuItems = append(menuItems, &types.MenuItem{
DisplayString: fmt.Sprintf("%s '%s'", gui.c.Tr.LcFilterBy, fileName), DisplayString: fmt.Sprintf("%s '%s'", gui.c.Tr.LcFilterBy, fileName),
OnPress: func() error { OnPress: func() error {
return gui.setFiltering(fileName) return gui.setFiltering(fileName)
@ -33,10 +33,10 @@ func (gui *Gui) handleCreateFilteringMenuPanel() error {
}) })
} }
menuItems = append(menuItems, &popup.MenuItem{ menuItems = append(menuItems, &types.MenuItem{
DisplayString: gui.c.Tr.LcFilterPathOption, DisplayString: gui.c.Tr.LcFilterPathOption,
OnPress: func() error { OnPress: func() error {
return gui.c.Prompt(popup.PromptOpts{ return gui.c.Prompt(types.PromptOpts{
FindSuggestionsFunc: gui.suggestionsHelper.GetFilePathSuggestionsFunc(), FindSuggestionsFunc: gui.suggestionsHelper.GetFilePathSuggestionsFunc(),
Title: gui.c.Tr.EnterFileName, Title: gui.c.Tr.EnterFileName,
HandleConfirm: func(response string) error { HandleConfirm: func(response string) error {
@ -47,11 +47,11 @@ func (gui *Gui) handleCreateFilteringMenuPanel() error {
}) })
if gui.State.Modes.Filtering.Active() { if gui.State.Modes.Filtering.Active() {
menuItems = append(menuItems, &popup.MenuItem{ menuItems = append(menuItems, &types.MenuItem{
DisplayString: gui.c.Tr.LcExitFilterMode, DisplayString: gui.c.Tr.LcExitFilterMode,
OnPress: gui.clearFiltering, OnPress: gui.clearFiltering,
}) })
} }
return gui.c.Menu(popup.CreateMenuOptions{Title: gui.c.Tr.FilteringMenuTitle, Items: menuItems}) return gui.c.Menu(types.CreateMenuOptions{Title: gui.c.Tr.FilteringMenuTitle, Items: menuItems})
} }

View File

@ -3,7 +3,7 @@ package gui
import ( import (
"fmt" "fmt"
"github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
@ -21,7 +21,7 @@ func (gui *Gui) handleCreateGitFlowMenu() error {
return func() error { return func() error {
title := utils.ResolvePlaceholderString(gui.c.Tr.NewGitFlowBranchPrompt, map[string]string{"branchType": branchType}) title := utils.ResolvePlaceholderString(gui.c.Tr.NewGitFlowBranchPrompt, map[string]string{"branchType": branchType})
return gui.c.Prompt(popup.PromptOpts{ return gui.c.Prompt(types.PromptOpts{
Title: title, Title: title,
HandleConfirm: func(name string) error { HandleConfirm: func(name string) error {
gui.c.LogAction(gui.c.Tr.Actions.GitFlowStart) gui.c.LogAction(gui.c.Tr.Actions.GitFlowStart)
@ -33,9 +33,9 @@ func (gui *Gui) handleCreateGitFlowMenu() error {
} }
} }
return gui.c.Menu(popup.CreateMenuOptions{ return gui.c.Menu(types.CreateMenuOptions{
Title: "git flow", Title: "git flow",
Items: []*popup.MenuItem{ Items: []*types.MenuItem{
{ {
// not localising here because it's one to one with the actual git flow commands // not localising here because it's one to one with the actual git flow commands
DisplayString: fmt.Sprintf("finish branch '%s'", branch.Name), DisplayString: fmt.Sprintf("finish branch '%s'", branch.Name),

View File

@ -124,7 +124,7 @@ type Gui struct {
suggestionsAsyncHandler *tasks.AsyncHandler suggestionsAsyncHandler *tasks.AsyncHandler
PopupHandler popup.IPopupHandler PopupHandler types.IPopupHandler
IsNewRepo bool IsNewRepo bool
@ -143,7 +143,7 @@ type Gui struct {
PrevLayout PrevLayout PrevLayout PrevLayout
c *controllers.ControllerCommon c *types.ControllerCommon
refHelper *RefHelper refHelper *RefHelper
suggestionsHelper *SuggestionsHelper suggestionsHelper *SuggestionsHelper
fileHelper *FileHelper fileHelper *FileHelper
@ -189,7 +189,7 @@ type GuiRepoState struct {
// Suggestions will sometimes appear when typing into a prompt // Suggestions will sometimes appear when typing into a prompt
Suggestions []*types.Suggestion Suggestions []*types.Suggestion
MenuItems []*popup.MenuItem MenuItems []*types.MenuItem
BisectInfo *git_commands.BisectInfo BisectInfo *git_commands.BisectInfo
Updating bool Updating bool
Panels *panelStates Panels *panelStates
@ -284,10 +284,6 @@ type remoteBranchesState struct {
listPanelState listPanelState
} }
type tagsPanelState struct {
listPanelState
}
type commitPanelState struct { type commitPanelState struct {
listPanelState listPanelState
@ -336,7 +332,6 @@ type panelStates struct {
Branches *branchPanelState Branches *branchPanelState
Remotes *remotePanelState Remotes *remotePanelState
RemoteBranches *remoteBranchesState RemoteBranches *remoteBranchesState
Tags *tagsPanelState
Commits *commitPanelState Commits *commitPanelState
ReflogCommits *reflogCommitPanelState ReflogCommits *reflogCommitPanelState
SubCommits *subCommitPanelState SubCommits *subCommitPanelState
@ -453,7 +448,6 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) {
Branches: &branchPanelState{listPanelState{SelectedLineIdx: 0}}, Branches: &branchPanelState{listPanelState{SelectedLineIdx: 0}},
Remotes: &remotePanelState{listPanelState{SelectedLineIdx: 0}}, Remotes: &remotePanelState{listPanelState{SelectedLineIdx: 0}},
RemoteBranches: &remoteBranchesState{listPanelState{SelectedLineIdx: -1}}, RemoteBranches: &remoteBranchesState{listPanelState{SelectedLineIdx: -1}},
Tags: &tagsPanelState{listPanelState{SelectedLineIdx: -1}},
Commits: &commitPanelState{listPanelState: listPanelState{SelectedLineIdx: 0}, LimitCommits: true}, Commits: &commitPanelState{listPanelState: listPanelState{SelectedLineIdx: 0}, LimitCommits: true},
ReflogCommits: &reflogCommitPanelState{listPanelState{SelectedLineIdx: 0}}, ReflogCommits: &reflogCommitPanelState{listPanelState{SelectedLineIdx: 0}},
SubCommits: &subCommitPanelState{listPanelState: listPanelState{SelectedLineIdx: 0}, refName: ""}, SubCommits: &subCommitPanelState{listPanelState: listPanelState{SelectedLineIdx: 0}, refName: ""},
@ -557,7 +551,7 @@ func NewGui(
) )
guiCommon := &guiCommon{gui: gui, IPopupHandler: gui.PopupHandler} guiCommon := &guiCommon{gui: gui, IPopupHandler: gui.PopupHandler}
controllerCommon := &controllers.ControllerCommon{IGuiCommon: guiCommon, Common: cmn} controllerCommon := &types.ControllerCommon{IGuiCommon: guiCommon, Common: cmn}
// storing this stuff on the gui for now to ease refactoring // storing this stuff on the gui for now to ease refactoring
// TODO: reset these controllers upon changing repos due to state changing // TODO: reset these controllers upon changing repos due to state changing
@ -589,12 +583,11 @@ func (gui *Gui) setControllers() {
tagsController := controllers.NewTagsController( tagsController := controllers.NewTagsController(
controllerCommon, controllerCommon,
func() types.IListContext { return gui.State.Contexts.Tags }, func() *context.TagsContext { return gui.State.Contexts.Tags },
gui.git, gui.git,
getContexts, getContexts,
refHelper, refHelper,
gui.suggestionsHelper, gui.suggestionsHelper,
gui.getSelectedTag,
gui.switchToSubCommitsContext, gui.switchToSubCommitsContext,
) )
@ -921,7 +914,7 @@ func (gui *Gui) showIntroPopupMessage(done chan struct{}) error {
return gui.c.SaveAppState() return gui.c.SaveAppState()
} }
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: "", Title: "",
Prompt: gui.c.Tr.IntroPopupMessage, Prompt: gui.c.Tr.IntroPopupMessage,
HandleConfirm: onConfirm, HandleConfirm: onConfirm,
@ -956,7 +949,7 @@ func (gui *Gui) startBackgroundFetch() {
} }
err := gui.backgroundFetch() err := gui.backgroundFetch()
if err != nil && strings.Contains(err.Error(), "exit status 128") && isNew { if err != nil && strings.Contains(err.Error(), "exit status 128") && isNew {
_ = gui.c.Ask(popup.AskOpts{ _ = gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.NoAutomaticGitFetchTitle, Title: gui.c.Tr.NoAutomaticGitFetchTitle,
Prompt: gui.c.Tr.NoAutomaticGitFetchBody, Prompt: gui.c.Tr.NoAutomaticGitFetchBody,
}) })

View File

@ -3,18 +3,16 @@ package gui
import ( import (
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/controllers"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
// hacking this by including the gui struct for now until we split more things out // hacking this by including the gui struct for now until we split more things out
type guiCommon struct { type guiCommon struct {
gui *Gui gui *Gui
popup.IPopupHandler types.IPopupHandler
} }
var _ controllers.IGuiCommon = &guiCommon{} var _ types.IGuiCommon = &guiCommon{}
func (self *guiCommon) LogAction(msg string) { func (self *guiCommon) LogAction(msg string) {
self.gui.LogAction(msg) self.gui.LogAction(msg)
@ -44,6 +42,10 @@ func (self *guiCommon) PopContext() error {
return self.gui.returnFromContext() return self.gui.returnFromContext()
} }
func (self *guiCommon) CurrentContext() types.Context {
return self.gui.currentContext()
}
func (self *guiCommon) GetAppState() *config.AppState { func (self *guiCommon) GetAppState() *config.AppState {
return self.gui.Config.GetAppState() return self.gui.Config.GetAppState()
} }
@ -51,3 +53,11 @@ func (self *guiCommon) GetAppState() *config.AppState {
func (self *guiCommon) SaveAppState() error { func (self *guiCommon) SaveAppState() error {
return self.gui.Config.SaveAppState() return self.gui.Config.SaveAppState()
} }
func (self *guiCommon) Render() {
self.gui.render()
}
func (self *guiCommon) OpenSearch() {
_ = self.gui.handleOpenSearch(self.gui.currentViewName())
}

View File

@ -1492,7 +1492,7 @@ func (gui *Gui) keybindings() error {
bindings = append(bindings, gui.GetInitialKeybindings()...) bindings = append(bindings, gui.GetInitialKeybindings()...)
for _, binding := range bindings { for _, binding := range bindings {
if err := gui.g.SetKeybinding(binding.ViewName, binding.Contexts, binding.Key, binding.Modifier, gui.wrappedHandler(binding.Handler)); err != nil { if err := gui.SetKeybinding(binding); err != nil {
return err return err
} }
} }
@ -1508,3 +1508,29 @@ func (gui *Gui) keybindings() error {
return nil return nil
} }
func (gui *Gui) wrappedHandler(f func() error) func(g *gocui.Gui, v *gocui.View) error {
return func(g *gocui.Gui, v *gocui.View) error {
return f()
}
}
func (gui *Gui) SetKeybinding(binding *types.Binding) error {
handler := binding.Handler
if isMouseKey(binding.Key) {
handler = func() error {
// we ignore click events on views that aren't popup panels, when a popup panel is focused
if gui.popupPanelFocused() && gui.currentViewName() != binding.ViewName {
return nil
}
return binding.Handler()
}
}
return gui.g.SetKeybinding(binding.ViewName, binding.Contexts, binding.Key, binding.Modifier, gui.wrappedHandler(handler))
}
func isMouseKey(key interface{}) bool {
return key == gocui.MouseLeft || key == gocui.MouseRight || key == gocui.MouseMiddle || key == gocui.MouseRelease || key == gocui.MouseWheelUp || key == gocui.MouseWheelDown || key == gocui.MouseWheelLeft || key == gocui.MouseWheelRight
}

View File

@ -5,6 +5,7 @@ import (
"github.com/jesseduffield/gocui" "github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
@ -25,7 +26,7 @@ type ListContext struct {
Gui *Gui Gui *Gui
*BasicContext *context.BaseContext
} }
var _ types.IListContext = &ListContext{} var _ types.IListContext = &ListContext{}
@ -46,7 +47,7 @@ func (self *ListContext) FocusLine() {
if self.RenderSelection { if self.RenderSelection {
_, originY := view.Origin() _, originY := view.Origin()
displayStrings := self.GetDisplayStrings(originY, view.InnerHeight()+1) displayStrings := self.GetDisplayStrings(originY, view.InnerHeight()+1)
self.Gui.renderDisplayStringsAtPos(view, originY, displayStrings) self.Gui.renderDisplayStringsInViewPort(view, displayStrings)
} }
view.Footer = formatListFooter(self.GetPanelState().GetSelectedLineIdx(), self.GetItemsLength()) view.Footer = formatListFooter(self.GetPanelState().GetSelectedLineIdx(), self.GetItemsLength())
} }
@ -101,16 +102,8 @@ func (self *ListContext) HandleFocusLost() error {
} }
func (self *ListContext) HandleFocus(opts ...types.OnFocusOpts) error { func (self *ListContext) HandleFocus(opts ...types.OnFocusOpts) error {
if self.Gui.popupPanelFocused() {
return nil
}
self.FocusLine() self.FocusLine()
if self.Gui.State.Modes.Diffing.Active() {
return self.Gui.renderDiff()
}
if self.OnFocus != nil { if self.OnFocus != nil {
if err := self.OnFocus(opts...); err != nil { if err := self.OnFocus(opts...); err != nil {
return err return err

View File

@ -3,7 +3,10 @@ package gui
import ( import (
"log" "log"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/presentation"
"github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
@ -11,12 +14,12 @@ import (
func (gui *Gui) menuListContext() types.IListContext { func (gui *Gui) menuListContext() types.IListContext {
return &ListContext{ return &ListContext{
BasicContext: &BasicContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{
ViewName: "menu", ViewName: "menu",
Key: "menu", Key: "menu",
Kind: types.PERSISTENT_POPUP, Kind: types.PERSISTENT_POPUP,
OnGetOptionsMap: gui.getMenuOptions, OnGetOptionsMap: gui.getMenuOptions,
}, }),
GetItemsLength: func() int { return gui.Views.Menu.LinesHeight() }, GetItemsLength: func() int { return gui.Views.Menu.LinesHeight() },
OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Menu }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Menu },
Gui: gui, Gui: gui,
@ -27,16 +30,16 @@ func (gui *Gui) menuListContext() types.IListContext {
func (gui *Gui) filesListContext() types.IListContext { func (gui *Gui) filesListContext() types.IListContext {
return &ListContext{ return &ListContext{
BasicContext: &BasicContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{
ViewName: "files", ViewName: "files",
WindowName: "files", WindowName: "files",
Key: FILES_CONTEXT_KEY, Key: FILES_CONTEXT_KEY,
Kind: types.SIDE_CONTEXT, Kind: types.SIDE_CONTEXT,
}, }),
GetItemsLength: func() int { return gui.State.FileTreeViewModel.GetItemsLength() }, GetItemsLength: func() int { return gui.State.FileTreeViewModel.GetItemsLength() },
OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Files }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Files },
OnFocus: OnFocusWrapper(gui.onFocusFile), OnFocus: OnFocusWrapper(gui.onFocusFile),
OnRenderToMain: OnFocusWrapper(gui.filesRenderToMain), OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.filesRenderToMain)),
Gui: gui, Gui: gui,
GetDisplayStrings: func(startIdx int, length int) [][]string { GetDisplayStrings: func(startIdx int, length int) [][]string {
lines := presentation.RenderFileTree(gui.State.FileTreeViewModel, gui.State.Modes.Diffing.Ref, gui.State.Submodules) lines := presentation.RenderFileTree(gui.State.FileTreeViewModel, gui.State.Modes.Diffing.Ref, gui.State.Submodules)
@ -56,15 +59,15 @@ func (gui *Gui) filesListContext() types.IListContext {
func (gui *Gui) branchesListContext() types.IListContext { func (gui *Gui) branchesListContext() types.IListContext {
return &ListContext{ return &ListContext{
BasicContext: &BasicContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{
ViewName: "branches", ViewName: "branches",
WindowName: "branches", WindowName: "branches",
Key: LOCAL_BRANCHES_CONTEXT_KEY, Key: LOCAL_BRANCHES_CONTEXT_KEY,
Kind: types.SIDE_CONTEXT, Kind: types.SIDE_CONTEXT,
}, }),
GetItemsLength: func() int { return len(gui.State.Branches) }, GetItemsLength: func() int { return len(gui.State.Branches) },
OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Branches }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Branches },
OnRenderToMain: OnFocusWrapper(gui.branchesRenderToMain), OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.branchesRenderToMain)),
Gui: gui, Gui: gui,
GetDisplayStrings: func(startIdx int, length int) [][]string { GetDisplayStrings: func(startIdx int, length int) [][]string {
return presentation.GetBranchListDisplayStrings(gui.State.Branches, gui.State.ScreenMode != SCREEN_NORMAL, gui.State.Modes.Diffing.Ref) return presentation.GetBranchListDisplayStrings(gui.State.Branches, gui.State.ScreenMode != SCREEN_NORMAL, gui.State.Modes.Diffing.Ref)
@ -78,15 +81,15 @@ func (gui *Gui) branchesListContext() types.IListContext {
func (gui *Gui) remotesListContext() types.IListContext { func (gui *Gui) remotesListContext() types.IListContext {
return &ListContext{ return &ListContext{
BasicContext: &BasicContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{
ViewName: "branches", ViewName: "branches",
WindowName: "branches", WindowName: "branches",
Key: REMOTES_CONTEXT_KEY, Key: REMOTES_CONTEXT_KEY,
Kind: types.SIDE_CONTEXT, Kind: types.SIDE_CONTEXT,
}, }),
GetItemsLength: func() int { return len(gui.State.Remotes) }, GetItemsLength: func() int { return len(gui.State.Remotes) },
OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Remotes }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Remotes },
OnRenderToMain: OnFocusWrapper(gui.remotesRenderToMain), OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.remotesRenderToMain)),
Gui: gui, Gui: gui,
GetDisplayStrings: func(startIdx int, length int) [][]string { GetDisplayStrings: func(startIdx int, length int) [][]string {
return presentation.GetRemoteListDisplayStrings(gui.State.Remotes, gui.State.Modes.Diffing.Ref) return presentation.GetRemoteListDisplayStrings(gui.State.Remotes, gui.State.Modes.Diffing.Ref)
@ -100,15 +103,15 @@ func (gui *Gui) remotesListContext() types.IListContext {
func (gui *Gui) remoteBranchesListContext() types.IListContext { func (gui *Gui) remoteBranchesListContext() types.IListContext {
return &ListContext{ return &ListContext{
BasicContext: &BasicContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{
ViewName: "branches", ViewName: "branches",
WindowName: "branches", WindowName: "branches",
Key: REMOTE_BRANCHES_CONTEXT_KEY, Key: REMOTE_BRANCHES_CONTEXT_KEY,
Kind: types.SIDE_CONTEXT, Kind: types.SIDE_CONTEXT,
}, }),
GetItemsLength: func() int { return len(gui.State.RemoteBranches) }, GetItemsLength: func() int { return len(gui.State.RemoteBranches) },
OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.RemoteBranches }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.RemoteBranches },
OnRenderToMain: OnFocusWrapper(gui.remoteBranchesRenderToMain), OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.remoteBranchesRenderToMain)),
Gui: gui, Gui: gui,
GetDisplayStrings: func(startIdx int, length int) [][]string { GetDisplayStrings: func(startIdx int, length int) [][]string {
return presentation.GetRemoteBranchListDisplayStrings(gui.State.RemoteBranches, gui.State.Modes.Diffing.Ref) return presentation.GetRemoteBranchListDisplayStrings(gui.State.RemoteBranches, gui.State.Modes.Diffing.Ref)
@ -120,41 +123,43 @@ func (gui *Gui) remoteBranchesListContext() types.IListContext {
} }
} }
func (gui *Gui) tagsListContext() types.IListContext { func (gui *Gui) withDiffModeCheck(f func() error) func() error {
return &ListContext{ return func() error {
BasicContext: &BasicContext{ if gui.State.Modes.Diffing.Active() {
ViewName: "branches", return gui.renderDiff()
WindowName: "branches", }
Key: TAGS_CONTEXT_KEY,
Kind: types.SIDE_CONTEXT, return f()
}, }
GetItemsLength: func() int { return len(gui.State.Tags) }, }
OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Tags },
OnRenderToMain: OnFocusWrapper(gui.tagsRenderToMain), func (gui *Gui) tagsListContext() *context.TagsContext {
Gui: gui, return context.NewTagsContext(
GetDisplayStrings: func(startIdx int, length int) [][]string { func() []*models.Tag { return gui.State.Tags },
func() *gocui.View { return gui.Views.Branches },
func(startIdx int, length int) [][]string {
return presentation.GetTagListDisplayStrings(gui.State.Tags, gui.State.Modes.Diffing.Ref) return presentation.GetTagListDisplayStrings(gui.State.Tags, gui.State.Modes.Diffing.Ref)
}, },
SelectedItem: func() (types.ListItem, bool) { nil,
item := gui.getSelectedTag() OnFocusWrapper(gui.withDiffModeCheck(gui.tagsRenderToMain)),
return item, item != nil nil,
}, gui.c,
} )
} }
func (gui *Gui) branchCommitsListContext() types.IListContext { func (gui *Gui) branchCommitsListContext() types.IListContext {
parseEmoji := gui.c.UserConfig.Git.ParseEmoji parseEmoji := gui.c.UserConfig.Git.ParseEmoji
return &ListContext{ return &ListContext{
BasicContext: &BasicContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{
ViewName: "commits", ViewName: "commits",
WindowName: "commits", WindowName: "commits",
Key: BRANCH_COMMITS_CONTEXT_KEY, Key: BRANCH_COMMITS_CONTEXT_KEY,
Kind: types.SIDE_CONTEXT, Kind: types.SIDE_CONTEXT,
}, }),
GetItemsLength: func() int { return len(gui.State.Commits) }, GetItemsLength: func() int { return len(gui.State.Commits) },
OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Commits }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Commits },
OnFocus: OnFocusWrapper(gui.onCommitFocus), OnFocus: OnFocusWrapper(gui.onCommitFocus),
OnRenderToMain: OnFocusWrapper(gui.branchCommitsRenderToMain), OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.branchCommitsRenderToMain)),
Gui: gui, Gui: gui,
GetDisplayStrings: func(startIdx int, length int) [][]string { GetDisplayStrings: func(startIdx int, length int) [][]string {
selectedCommitSha := "" selectedCommitSha := ""
@ -188,15 +193,15 @@ func (gui *Gui) branchCommitsListContext() types.IListContext {
func (gui *Gui) subCommitsListContext() types.IListContext { func (gui *Gui) subCommitsListContext() types.IListContext {
parseEmoji := gui.c.UserConfig.Git.ParseEmoji parseEmoji := gui.c.UserConfig.Git.ParseEmoji
return &ListContext{ return &ListContext{
BasicContext: &BasicContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{
ViewName: "branches", ViewName: "branches",
WindowName: "branches", WindowName: "branches",
Key: SUB_COMMITS_CONTEXT_KEY, Key: SUB_COMMITS_CONTEXT_KEY,
Kind: types.SIDE_CONTEXT, Kind: types.SIDE_CONTEXT,
}, }),
GetItemsLength: func() int { return len(gui.State.SubCommits) }, GetItemsLength: func() int { return len(gui.State.SubCommits) },
OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.SubCommits }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.SubCommits },
OnRenderToMain: OnFocusWrapper(gui.subCommitsRenderToMain), OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.subCommitsRenderToMain)),
Gui: gui, Gui: gui,
GetDisplayStrings: func(startIdx int, length int) [][]string { GetDisplayStrings: func(startIdx int, length int) [][]string {
selectedCommitSha := "" selectedCommitSha := ""
@ -249,15 +254,15 @@ func (gui *Gui) shouldShowGraph() bool {
func (gui *Gui) reflogCommitsListContext() types.IListContext { func (gui *Gui) reflogCommitsListContext() types.IListContext {
parseEmoji := gui.c.UserConfig.Git.ParseEmoji parseEmoji := gui.c.UserConfig.Git.ParseEmoji
return &ListContext{ return &ListContext{
BasicContext: &BasicContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{
ViewName: "commits", ViewName: "commits",
WindowName: "commits", WindowName: "commits",
Key: REFLOG_COMMITS_CONTEXT_KEY, Key: REFLOG_COMMITS_CONTEXT_KEY,
Kind: types.SIDE_CONTEXT, Kind: types.SIDE_CONTEXT,
}, }),
GetItemsLength: func() int { return len(gui.State.FilteredReflogCommits) }, GetItemsLength: func() int { return len(gui.State.FilteredReflogCommits) },
OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.ReflogCommits }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.ReflogCommits },
OnRenderToMain: OnFocusWrapper(gui.reflogCommitsRenderToMain), OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.reflogCommitsRenderToMain)),
Gui: gui, Gui: gui,
GetDisplayStrings: func(startIdx int, length int) [][]string { GetDisplayStrings: func(startIdx int, length int) [][]string {
return presentation.GetReflogCommitListDisplayStrings( return presentation.GetReflogCommitListDisplayStrings(
@ -277,15 +282,15 @@ func (gui *Gui) reflogCommitsListContext() types.IListContext {
func (gui *Gui) stashListContext() types.IListContext { func (gui *Gui) stashListContext() types.IListContext {
return &ListContext{ return &ListContext{
BasicContext: &BasicContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{
ViewName: "stash", ViewName: "stash",
WindowName: "stash", WindowName: "stash",
Key: STASH_CONTEXT_KEY, Key: STASH_CONTEXT_KEY,
Kind: types.SIDE_CONTEXT, Kind: types.SIDE_CONTEXT,
}, }),
GetItemsLength: func() int { return len(gui.State.StashEntries) }, GetItemsLength: func() int { return len(gui.State.StashEntries) },
OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Stash }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Stash },
OnRenderToMain: OnFocusWrapper(gui.stashRenderToMain), OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.stashRenderToMain)),
Gui: gui, Gui: gui,
GetDisplayStrings: func(startIdx int, length int) [][]string { GetDisplayStrings: func(startIdx int, length int) [][]string {
return presentation.GetStashEntryListDisplayStrings(gui.State.StashEntries, gui.State.Modes.Diffing.Ref) return presentation.GetStashEntryListDisplayStrings(gui.State.StashEntries, gui.State.Modes.Diffing.Ref)
@ -299,16 +304,16 @@ func (gui *Gui) stashListContext() types.IListContext {
func (gui *Gui) commitFilesListContext() types.IListContext { func (gui *Gui) commitFilesListContext() types.IListContext {
return &ListContext{ return &ListContext{
BasicContext: &BasicContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{
ViewName: "commitFiles", ViewName: "commitFiles",
WindowName: "commits", WindowName: "commits",
Key: COMMIT_FILES_CONTEXT_KEY, Key: COMMIT_FILES_CONTEXT_KEY,
Kind: types.SIDE_CONTEXT, Kind: types.SIDE_CONTEXT,
}, }),
GetItemsLength: func() int { return gui.State.CommitFileTreeViewModel.GetItemsLength() }, GetItemsLength: func() int { return gui.State.CommitFileTreeViewModel.GetItemsLength() },
OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.CommitFiles }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.CommitFiles },
OnFocus: OnFocusWrapper(gui.onCommitFileFocus), OnFocus: OnFocusWrapper(gui.onCommitFileFocus),
OnRenderToMain: OnFocusWrapper(gui.commitFilesRenderToMain), OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.commitFilesRenderToMain)),
Gui: gui, Gui: gui,
GetDisplayStrings: func(startIdx int, length int) [][]string { GetDisplayStrings: func(startIdx int, length int) [][]string {
if gui.State.CommitFileTreeViewModel.GetItemsLength() == 0 { if gui.State.CommitFileTreeViewModel.GetItemsLength() == 0 {
@ -332,15 +337,15 @@ func (gui *Gui) commitFilesListContext() types.IListContext {
func (gui *Gui) submodulesListContext() types.IListContext { func (gui *Gui) submodulesListContext() types.IListContext {
return &ListContext{ return &ListContext{
BasicContext: &BasicContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{
ViewName: "files", ViewName: "files",
WindowName: "files", WindowName: "files",
Key: SUBMODULES_CONTEXT_KEY, Key: SUBMODULES_CONTEXT_KEY,
Kind: types.SIDE_CONTEXT, Kind: types.SIDE_CONTEXT,
}, }),
GetItemsLength: func() int { return len(gui.State.Submodules) }, GetItemsLength: func() int { return len(gui.State.Submodules) },
OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Submodules }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Submodules },
OnRenderToMain: OnFocusWrapper(gui.submodulesRenderToMain), OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.submodulesRenderToMain)),
Gui: gui, Gui: gui,
GetDisplayStrings: func(startIdx int, length int) [][]string { GetDisplayStrings: func(startIdx int, length int) [][]string {
return presentation.GetSubmoduleListDisplayStrings(gui.State.Submodules) return presentation.GetSubmoduleListDisplayStrings(gui.State.Submodules)
@ -354,12 +359,12 @@ func (gui *Gui) submodulesListContext() types.IListContext {
func (gui *Gui) suggestionsListContext() types.IListContext { func (gui *Gui) suggestionsListContext() types.IListContext {
return &ListContext{ return &ListContext{
BasicContext: &BasicContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{
ViewName: "suggestions", ViewName: "suggestions",
WindowName: "suggestions", WindowName: "suggestions",
Key: SUGGESTIONS_CONTEXT_KEY, Key: SUGGESTIONS_CONTEXT_KEY,
Kind: types.PERSISTENT_POPUP, Kind: types.PERSISTENT_POPUP,
}, }),
GetItemsLength: func() int { return len(gui.State.Suggestions) }, GetItemsLength: func() int { return len(gui.State.Suggestions) },
OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Suggestions }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Suggestions },
Gui: gui, Gui: gui,

View File

@ -4,7 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/theme" "github.com/jesseduffield/lazygit/pkg/theme"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
@ -24,10 +24,10 @@ func (gui *Gui) handleMenuClose() error {
} }
// note: items option is mutated by this function // note: items option is mutated by this function
func (gui *Gui) createMenu(opts popup.CreateMenuOptions) error { func (gui *Gui) createMenu(opts types.CreateMenuOptions) error {
if !opts.HideCancel { if !opts.HideCancel {
// this is mutative but I'm okay with that for now // this is mutative but I'm okay with that for now
opts.Items = append(opts.Items, &popup.MenuItem{ opts.Items = append(opts.Items, &types.MenuItem{
DisplayStrings: []string{gui.c.Tr.LcCancel}, DisplayStrings: []string{gui.c.Tr.LcCancel},
OnPress: func() error { OnPress: func() error {
return nil return nil
@ -69,7 +69,7 @@ func (gui *Gui) createMenu(opts popup.CreateMenuOptions) error {
return gui.c.PushContext(gui.State.Contexts.Menu) return gui.c.PushContext(gui.State.Contexts.Menu)
} }
func (gui *Gui) getSelectedMenuItem() *popup.MenuItem { func (gui *Gui) getSelectedMenuItem() *types.MenuItem {
if len(gui.State.MenuItems) == 0 { if len(gui.State.MenuItems) == 0 {
return nil return nil
} }

View File

@ -4,7 +4,6 @@ import (
"strings" "strings"
"github.com/jesseduffield/gocui" "github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
@ -56,11 +55,11 @@ func (gui *Gui) handleCreateOptionsMenu() error {
bindings := gui.getBindings(view) bindings := gui.getBindings(view)
menuItems := make([]*popup.MenuItem, len(bindings)) menuItems := make([]*types.MenuItem, len(bindings))
for i, binding := range bindings { for i, binding := range bindings {
binding := binding // note to self, never close over loop variables binding := binding // note to self, never close over loop variables
menuItems[i] = &popup.MenuItem{ menuItems[i] = &types.MenuItem{
DisplayStrings: []string{GetKeyDisplay(binding.Key), gui.displayDescription(binding)}, DisplayStrings: []string{GetKeyDisplay(binding.Key), gui.displayDescription(binding)},
OnPress: func() error { OnPress: func() error {
if binding.Key == nil { if binding.Key == nil {
@ -74,7 +73,7 @@ func (gui *Gui) handleCreateOptionsMenu() error {
} }
} }
return gui.c.Menu(popup.CreateMenuOptions{ return gui.c.Menu(types.CreateMenuOptions{
Title: strings.Title(gui.c.Tr.LcMenu), Title: strings.Title(gui.c.Tr.LcMenu),
Items: menuItems, Items: menuItems,
HideCancel: true, HideCancel: true,

View File

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"github.com/jesseduffield/lazygit/pkg/commands/types/enums" "github.com/jesseduffield/lazygit/pkg/commands/types/enums"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
@ -13,7 +12,7 @@ func (gui *Gui) handleCreatePatchOptionsMenu() error {
return gui.c.ErrorMsg(gui.c.Tr.NoPatchError) return gui.c.ErrorMsg(gui.c.Tr.NoPatchError)
} }
menuItems := []*popup.MenuItem{ menuItems := []*types.MenuItem{
{ {
DisplayString: "reset patch", DisplayString: "reset patch",
OnPress: gui.handleResetPatch, OnPress: gui.handleResetPatch,
@ -29,7 +28,7 @@ func (gui *Gui) handleCreatePatchOptionsMenu() error {
} }
if gui.git.Patch.PatchManager.CanRebase && gui.git.Status.WorkingTreeState() == enums.REBASE_MODE_NONE { if gui.git.Patch.PatchManager.CanRebase && gui.git.Status.WorkingTreeState() == enums.REBASE_MODE_NONE {
menuItems = append(menuItems, []*popup.MenuItem{ menuItems = append(menuItems, []*types.MenuItem{
{ {
DisplayString: fmt.Sprintf("remove patch from original commit (%s)", gui.git.Patch.PatchManager.To), DisplayString: fmt.Sprintf("remove patch from original commit (%s)", gui.git.Patch.PatchManager.To),
OnPress: gui.handleDeletePatchFromCommit, OnPress: gui.handleDeletePatchFromCommit,
@ -51,7 +50,7 @@ func (gui *Gui) handleCreatePatchOptionsMenu() error {
menuItems = append( menuItems = append(
menuItems[:1], menuItems[:1],
append( append(
[]*popup.MenuItem{ []*types.MenuItem{
{ {
DisplayString: fmt.Sprintf("move patch to selected commit (%s)", selectedCommit.Sha), DisplayString: fmt.Sprintf("move patch to selected commit (%s)", selectedCommit.Sha),
OnPress: gui.handleMovePatchToSelectedCommit, OnPress: gui.handleMovePatchToSelectedCommit,
@ -63,7 +62,7 @@ func (gui *Gui) handleCreatePatchOptionsMenu() error {
} }
} }
return gui.c.Menu(popup.CreateMenuOptions{Title: gui.c.Tr.PatchOptionsTitle, Items: menuItems}) return gui.c.Menu(types.CreateMenuOptions{Title: gui.c.Tr.PatchOptionsTitle, Items: menuItems})
} }
func (gui *Gui) getPatchCommitIndex() int { func (gui *Gui) getPatchCommitIndex() int {
@ -142,7 +141,7 @@ func (gui *Gui) handleMovePatchIntoWorkingTree() error {
} }
if gui.workingTreeHelper.IsWorkingTreeDirty() { if gui.workingTreeHelper.IsWorkingTreeDirty() {
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.MustStashTitle, Title: gui.c.Tr.MustStashTitle,
Prompt: gui.c.Tr.MustStashWarning, Prompt: gui.c.Tr.MustStashWarning,
HandleConfirm: func() error { HandleConfirm: func() error {

View File

@ -11,83 +11,27 @@ import (
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
type IPopupHandler interface {
ErrorMsg(message string) error
Error(err error) error
Ask(opts AskOpts) error
Prompt(opts PromptOpts) error
WithLoaderPanel(message string, f func() error) error
WithWaitingStatus(message string, f func() error) error
Menu(opts CreateMenuOptions) error
Toast(message string)
GetPromptInput() string
}
type CreateMenuOptions struct {
Title string
Items []*MenuItem
HideCancel bool
}
type CreatePopupPanelOpts struct {
HasLoader bool
Editable bool
Title string
Prompt string
HandleConfirm func() error
HandleConfirmPrompt func(string) error
HandleClose func() error
// when HandlersManageFocus is true, do not return from the confirmation context automatically. It's expected that the handlers will manage focus, whether that means switching to another context, or manually returning the context.
HandlersManageFocus bool
FindSuggestionsFunc func(string) []*types.Suggestion
}
type AskOpts struct {
Title string
Prompt string
HandleConfirm func() error
HandleClose func() error
HandlersManageFocus bool
}
type PromptOpts struct {
Title string
InitialContent string
FindSuggestionsFunc func(string) []*types.Suggestion
HandleConfirm func(string) error
}
type MenuItem struct {
DisplayString string
DisplayStrings []string
OnPress func() error
// only applies when displayString is used
OpensMenu bool
}
type RealPopupHandler struct { type RealPopupHandler struct {
*common.Common *common.Common
index int index int
sync.Mutex sync.Mutex
createPopupPanelFn func(CreatePopupPanelOpts) error createPopupPanelFn func(types.CreatePopupPanelOpts) error
onErrorFn func() error onErrorFn func() error
closePopupFn func() error closePopupFn func() error
createMenuFn func(CreateMenuOptions) error createMenuFn func(types.CreateMenuOptions) error
withWaitingStatusFn func(message string, f func() error) error withWaitingStatusFn func(message string, f func() error) error
toastFn func(message string) toastFn func(message string)
getPromptInputFn func() string getPromptInputFn func() string
} }
var _ IPopupHandler = &RealPopupHandler{} var _ types.IPopupHandler = &RealPopupHandler{}
func NewPopupHandler( func NewPopupHandler(
common *common.Common, common *common.Common,
createPopupPanelFn func(CreatePopupPanelOpts) error, createPopupPanelFn func(types.CreatePopupPanelOpts) error,
onErrorFn func() error, onErrorFn func() error,
closePopupFn func() error, closePopupFn func() error,
createMenuFn func(CreateMenuOptions) error, createMenuFn func(types.CreateMenuOptions) error,
withWaitingStatusFn func(message string, f func() error) error, withWaitingStatusFn func(message string, f func() error) error,
toastFn func(message string), toastFn func(message string),
getPromptInputFn func() string, getPromptInputFn func() string,
@ -105,7 +49,7 @@ func NewPopupHandler(
} }
} }
func (self *RealPopupHandler) Menu(opts CreateMenuOptions) error { func (self *RealPopupHandler) Menu(opts types.CreateMenuOptions) error {
return self.createMenuFn(opts) return self.createMenuFn(opts)
} }
@ -135,18 +79,18 @@ func (self *RealPopupHandler) ErrorMsg(message string) error {
return err return err
} }
return self.Ask(AskOpts{ return self.Ask(types.AskOpts{
Title: self.Tr.Error, Title: self.Tr.Error,
Prompt: coloredMessage, Prompt: coloredMessage,
}) })
} }
func (self *RealPopupHandler) Ask(opts AskOpts) error { func (self *RealPopupHandler) Ask(opts types.AskOpts) error {
self.Lock() self.Lock()
self.index++ self.index++
self.Unlock() self.Unlock()
return self.createPopupPanelFn(CreatePopupPanelOpts{ return self.createPopupPanelFn(types.CreatePopupPanelOpts{
Title: opts.Title, Title: opts.Title,
Prompt: opts.Prompt, Prompt: opts.Prompt,
HandleConfirm: opts.HandleConfirm, HandleConfirm: opts.HandleConfirm,
@ -155,12 +99,12 @@ func (self *RealPopupHandler) Ask(opts AskOpts) error {
}) })
} }
func (self *RealPopupHandler) Prompt(opts PromptOpts) error { func (self *RealPopupHandler) Prompt(opts types.PromptOpts) error {
self.Lock() self.Lock()
self.index++ self.index++
self.Unlock() self.Unlock()
return self.createPopupPanelFn(CreatePopupPanelOpts{ return self.createPopupPanelFn(types.CreatePopupPanelOpts{
Title: opts.Title, Title: opts.Title,
Prompt: opts.InitialContent, Prompt: opts.InitialContent,
Editable: true, Editable: true,
@ -176,7 +120,7 @@ func (self *RealPopupHandler) WithLoaderPanel(message string, f func() error) er
index = self.index index = self.index
self.Unlock() self.Unlock()
err := self.createPopupPanelFn(CreatePopupPanelOpts{ err := self.createPopupPanelFn(types.CreatePopupPanelOpts{
Prompt: message, Prompt: message,
HasLoader: true, HasLoader: true,
}) })
@ -208,11 +152,11 @@ func (self *RealPopupHandler) GetPromptInput() string {
type TestPopupHandler struct { type TestPopupHandler struct {
OnErrorMsg func(message string) error OnErrorMsg func(message string) error
OnAsk func(opts AskOpts) error OnAsk func(opts types.AskOpts) error
OnPrompt func(opts PromptOpts) error OnPrompt func(opts types.PromptOpts) error
} }
var _ IPopupHandler = &TestPopupHandler{} var _ types.IPopupHandler = &TestPopupHandler{}
func (self *TestPopupHandler) Error(err error) error { func (self *TestPopupHandler) Error(err error) error {
return self.ErrorMsg(err.Error()) return self.ErrorMsg(err.Error())
@ -222,11 +166,11 @@ func (self *TestPopupHandler) ErrorMsg(message string) error {
return self.OnErrorMsg(message) return self.OnErrorMsg(message)
} }
func (self *TestPopupHandler) Ask(opts AskOpts) error { func (self *TestPopupHandler) Ask(opts types.AskOpts) error {
return self.OnAsk(opts) return self.OnAsk(opts)
} }
func (self *TestPopupHandler) Prompt(opts PromptOpts) error { func (self *TestPopupHandler) Prompt(opts types.PromptOpts) error {
return self.OnPrompt(opts) return self.OnPrompt(opts)
} }
@ -238,7 +182,7 @@ func (self *TestPopupHandler) WithWaitingStatus(message string, f func() error)
return f() return f()
} }
func (self *TestPopupHandler) Menu(opts CreateMenuOptions) error { func (self *TestPopupHandler) Menu(opts types.CreateMenuOptions) error {
panic("not yet implemented") panic("not yet implemented")
} }

View File

@ -5,18 +5,18 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/hosting_service" "github.com/jesseduffield/lazygit/pkg/commands/hosting_service"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutBranch *models.Branch) error { func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutBranch *models.Branch) error {
menuItems := make([]*popup.MenuItem, 0, 4) menuItems := make([]*types.MenuItem, 0, 4)
fromToDisplayStrings := func(from string, to string) []string { fromToDisplayStrings := func(from string, to string) []string {
return []string{fmt.Sprintf("%s → %s", from, to)} return []string{fmt.Sprintf("%s → %s", from, to)}
} }
menuItemsForBranch := func(branch *models.Branch) []*popup.MenuItem { menuItemsForBranch := func(branch *models.Branch) []*types.MenuItem {
return []*popup.MenuItem{ return []*types.MenuItem{
{ {
DisplayStrings: fromToDisplayStrings(branch.Name, gui.c.Tr.LcDefaultBranch), DisplayStrings: fromToDisplayStrings(branch.Name, gui.c.Tr.LcDefaultBranch),
OnPress: func() error { OnPress: func() error {
@ -26,7 +26,7 @@ func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutB
{ {
DisplayStrings: fromToDisplayStrings(branch.Name, gui.c.Tr.LcSelectBranch), DisplayStrings: fromToDisplayStrings(branch.Name, gui.c.Tr.LcSelectBranch),
OnPress: func() error { OnPress: func() error {
return gui.c.Prompt(popup.PromptOpts{ return gui.c.Prompt(types.PromptOpts{
Title: branch.Name + " →", Title: branch.Name + " →",
FindSuggestionsFunc: gui.suggestionsHelper.GetBranchNameSuggestionsFunc(), FindSuggestionsFunc: gui.suggestionsHelper.GetBranchNameSuggestionsFunc(),
HandleConfirm: func(targetBranchName string) error { HandleConfirm: func(targetBranchName string) error {
@ -40,7 +40,7 @@ func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutB
if selectedBranch != checkedOutBranch { if selectedBranch != checkedOutBranch {
menuItems = append(menuItems, menuItems = append(menuItems,
&popup.MenuItem{ &types.MenuItem{
DisplayStrings: fromToDisplayStrings(checkedOutBranch.Name, selectedBranch.Name), DisplayStrings: fromToDisplayStrings(checkedOutBranch.Name, selectedBranch.Name),
OnPress: func() error { OnPress: func() error {
return gui.createPullRequest(checkedOutBranch.Name, selectedBranch.Name) return gui.createPullRequest(checkedOutBranch.Name, selectedBranch.Name)
@ -52,7 +52,7 @@ func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutB
menuItems = append(menuItems, menuItemsForBranch(selectedBranch)...) menuItems = append(menuItems, menuItemsForBranch(selectedBranch)...)
return gui.c.Menu(popup.CreateMenuOptions{Title: fmt.Sprintf(gui.c.Tr.CreatePullRequestOptions), Items: menuItems}) return gui.c.Menu(types.CreateMenuOptions{Title: fmt.Sprintf(gui.c.Tr.CreatePullRequestOptions), Items: menuItems})
} }
func (gui *Gui) createPullRequest(from string, to string) error { func (gui *Gui) createPullRequest(from string, to string) error {

View File

@ -4,7 +4,7 @@ import (
"os" "os"
"github.com/jesseduffield/gocui" "github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
// when a user runs lazygit with the LAZYGIT_NEW_DIR_FILE env variable defined // when a user runs lazygit with the LAZYGIT_NEW_DIR_FILE env variable defined
@ -73,7 +73,7 @@ func (gui *Gui) quit() error {
} }
if gui.c.UserConfig.ConfirmOnQuit { if gui.c.UserConfig.ConfirmOnQuit {
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: "", Title: "",
Prompt: gui.c.Tr.ConfirmQuit, Prompt: gui.c.Tr.ConfirmQuit,
HandleConfirm: func() error { HandleConfirm: func() error {

View File

@ -5,7 +5,6 @@ import (
"strings" "strings"
"github.com/jesseduffield/lazygit/pkg/commands/types/enums" "github.com/jesseduffield/lazygit/pkg/commands/types/enums"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
@ -24,11 +23,11 @@ func (gui *Gui) handleCreateRebaseOptionsMenu() error {
options = append(options, REBASE_OPTION_SKIP) options = append(options, REBASE_OPTION_SKIP)
} }
menuItems := make([]*popup.MenuItem, len(options)) menuItems := make([]*types.MenuItem, len(options))
for i, option := range options { for i, option := range options {
// note to self. Never, EVER, close over loop variables in a function // note to self. Never, EVER, close over loop variables in a function
option := option option := option
menuItems[i] = &popup.MenuItem{ menuItems[i] = &types.MenuItem{
DisplayString: option, DisplayString: option,
OnPress: func() error { OnPress: func() error {
return gui.genericMergeCommand(option) return gui.genericMergeCommand(option)
@ -43,7 +42,7 @@ func (gui *Gui) handleCreateRebaseOptionsMenu() error {
title = gui.c.Tr.RebaseOptionsTitle title = gui.c.Tr.RebaseOptionsTitle
} }
return gui.c.Menu(popup.CreateMenuOptions{Title: title, Items: menuItems}) return gui.c.Menu(types.CreateMenuOptions{Title: title, Items: menuItems})
} }
func (gui *Gui) genericMergeCommand(command string) error { func (gui *Gui) genericMergeCommand(command string) error {
@ -112,7 +111,7 @@ func (gui *Gui) checkMergeOrRebase(result error) error {
// assume in this case that we're already done // assume in this case that we're already done
return nil return nil
} else if isMergeConflictErr(result.Error()) { } else if isMergeConflictErr(result.Error()) {
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.FoundConflictsTitle, Title: gui.c.Tr.FoundConflictsTitle,
Prompt: gui.c.Tr.FoundConflicts, Prompt: gui.c.Tr.FoundConflicts,
HandlersManageFocus: true, HandlersManageFocus: true,
@ -135,7 +134,7 @@ func (gui *Gui) checkMergeOrRebase(result error) error {
func (gui *Gui) abortMergeOrRebaseWithConfirm() error { func (gui *Gui) abortMergeOrRebaseWithConfirm() error {
// prompt user to confirm that they want to abort, then do it // prompt user to confirm that they want to abort, then do it
mode := gui.workingTreeStateNoun() mode := gui.workingTreeStateNoun()
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: fmt.Sprintf(gui.c.Tr.AbortTitle, mode), Title: fmt.Sprintf(gui.c.Tr.AbortTitle, mode),
Prompt: fmt.Sprintf(gui.c.Tr.AbortPrompt, mode), Prompt: fmt.Sprintf(gui.c.Tr.AbortPrompt, mode),
HandleConfirm: func() error { HandleConfirm: func() error {

View File

@ -7,8 +7,8 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/git_config" "github.com/jesseduffield/lazygit/pkg/commands/git_config"
"github.com/jesseduffield/lazygit/pkg/env" "github.com/jesseduffield/lazygit/pkg/env"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
@ -17,10 +17,10 @@ func (gui *Gui) handleCreateRecentReposMenu() error {
reposCount := utils.Min(len(recentRepoPaths), 20) reposCount := utils.Min(len(recentRepoPaths), 20)
// we won't show the current repo hence the -1 // we won't show the current repo hence the -1
menuItems := make([]*popup.MenuItem, reposCount-1) menuItems := make([]*types.MenuItem, reposCount-1)
for i, path := range recentRepoPaths[1:reposCount] { for i, path := range recentRepoPaths[1:reposCount] {
path := path // cos we're closing over the loop variable path := path // cos we're closing over the loop variable
menuItems[i] = &popup.MenuItem{ menuItems[i] = &types.MenuItem{
DisplayStrings: []string{ DisplayStrings: []string{
filepath.Base(path), filepath.Base(path),
style.FgMagenta.Sprint(path), style.FgMagenta.Sprint(path),
@ -34,7 +34,7 @@ func (gui *Gui) handleCreateRecentReposMenu() error {
} }
} }
return gui.c.Menu(popup.CreateMenuOptions{Title: gui.c.Tr.RecentRepos, Items: menuItems}) return gui.c.Menu(types.CreateMenuOptions{Title: gui.c.Tr.RecentRepos, Items: menuItems})
} }
func (gui *Gui) handleShowAllBranchLogs() error { func (gui *Gui) handleShowAllBranchLogs() error {

View File

@ -7,20 +7,19 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/controllers"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
type RefHelper struct { type RefHelper struct {
c *controllers.ControllerCommon c *types.ControllerCommon
git *commands.GitCommand git *commands.GitCommand
getState func() *GuiRepoState getState func() *GuiRepoState
} }
func NewRefHelper( func NewRefHelper(
c *controllers.ControllerCommon, c *types.ControllerCommon,
git *commands.GitCommand, git *commands.GitCommand,
getState func() *GuiRepoState, getState func() *GuiRepoState,
) *RefHelper { ) *RefHelper {
@ -58,7 +57,7 @@ func (self *RefHelper) CheckoutRef(ref string, options types.CheckoutRefOptions)
if strings.Contains(err.Error(), "Please commit your changes or stash them before you switch branch") { if strings.Contains(err.Error(), "Please commit your changes or stash them before you switch branch") {
// offer to autostash changes // offer to autostash changes
return self.c.Ask(popup.AskOpts{ return self.c.Ask(types.AskOpts{
Title: self.c.Tr.AutoStashTitle, Title: self.c.Tr.AutoStashTitle,
Prompt: self.c.Tr.AutoStashPrompt, Prompt: self.c.Tr.AutoStashPrompt,
@ -115,10 +114,10 @@ func (self *RefHelper) ResetToRef(ref string, strength string, envVars []string)
func (self *RefHelper) CreateGitResetMenu(ref string) error { func (self *RefHelper) CreateGitResetMenu(ref string) error {
strengths := []string{"soft", "mixed", "hard"} strengths := []string{"soft", "mixed", "hard"}
menuItems := make([]*popup.MenuItem, len(strengths)) menuItems := make([]*types.MenuItem, len(strengths))
for i, strength := range strengths { for i, strength := range strengths {
strength := strength strength := strength
menuItems[i] = &popup.MenuItem{ menuItems[i] = &types.MenuItem{
DisplayStrings: []string{ DisplayStrings: []string{
fmt.Sprintf("%s reset", strength), fmt.Sprintf("%s reset", strength),
style.FgRed.Sprintf("reset --%s %s", strength, ref), style.FgRed.Sprintf("reset --%s %s", strength, ref),
@ -130,7 +129,7 @@ func (self *RefHelper) CreateGitResetMenu(ref string) error {
} }
} }
return self.c.Menu(popup.CreateMenuOptions{ return self.c.Menu(types.CreateMenuOptions{
Title: fmt.Sprintf("%s %s", self.c.Tr.LcResetTo, ref), Title: fmt.Sprintf("%s %s", self.c.Tr.LcResetTo, ref),
Items: menuItems, Items: menuItems,
}) })

View File

@ -3,7 +3,6 @@ package gui
import ( import (
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/controllers"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
@ -90,7 +89,7 @@ func (gui *Gui) CheckoutReflogCommit() error {
return nil return nil
} }
err := gui.c.Ask(popup.AskOpts{ err := gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.LcCheckoutCommit, Title: gui.c.Tr.LcCheckoutCommit,
Prompt: gui.c.Tr.SureCheckoutThisCommit, Prompt: gui.c.Tr.SureCheckoutThisCommit,
HandleConfirm: func() error { HandleConfirm: func() error {

View File

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
@ -54,7 +53,7 @@ func (gui *Gui) handleDeleteRemoteBranch() error {
} }
message := fmt.Sprintf("%s '%s'?", gui.c.Tr.DeleteRemoteBranchMessage, remoteBranch.FullName()) message := fmt.Sprintf("%s '%s'?", gui.c.Tr.DeleteRemoteBranchMessage, remoteBranch.FullName())
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.DeleteRemoteBranch, Title: gui.c.Tr.DeleteRemoteBranch,
Prompt: message, Prompt: message,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -88,7 +87,7 @@ func (gui *Gui) handleSetBranchUpstream() error {
}, },
) )
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.SetUpstreamTitle, Title: gui.c.Tr.SetUpstreamTitle,
Prompt: message, Prompt: message,
HandleConfirm: func() error { HandleConfirm: func() error {

View File

@ -4,7 +4,6 @@ import (
"strings" "strings"
"github.com/jesseduffield/lazygit/pkg/commands/patch" "github.com/jesseduffield/lazygit/pkg/commands/patch"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
@ -114,7 +113,7 @@ func (gui *Gui) handleResetSelection() error {
} }
if !gui.c.UserConfig.Gui.SkipUnstageLineWarning { if !gui.c.UserConfig.Gui.SkipUnstageLineWarning {
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.UnstageLinesTitle, Title: gui.c.Tr.UnstageLinesTitle,
Prompt: gui.c.Tr.UnstageLinesPrompt, Prompt: gui.c.Tr.UnstageLinesPrompt,
HandleConfirm: func() error { HandleConfirm: func() error {

View File

@ -3,7 +3,6 @@ package gui
import ( import (
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/controllers"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
@ -66,7 +65,7 @@ func (gui *Gui) handleStashApply() error {
return apply() return apply()
} }
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.StashApply, Title: gui.c.Tr.StashApply,
Prompt: gui.c.Tr.SureApplyStashEntry, Prompt: gui.c.Tr.SureApplyStashEntry,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -97,7 +96,7 @@ func (gui *Gui) handleStashPop() error {
return pop() return pop()
} }
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.StashPop, Title: gui.c.Tr.StashPop,
Prompt: gui.c.Tr.SurePopStashEntry, Prompt: gui.c.Tr.SurePopStashEntry,
HandleConfirm: func() error { HandleConfirm: func() error {
@ -112,7 +111,7 @@ func (gui *Gui) handleStashDrop() error {
return nil return nil
} }
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.StashDrop, Title: gui.c.Tr.StashDrop,
Prompt: gui.c.Tr.SureDropStashEntry, Prompt: gui.c.Tr.SureDropStashEntry,
HandleConfirm: func() error { HandleConfirm: func() error {

View File

@ -7,9 +7,9 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/types/enums" "github.com/jesseduffield/lazygit/pkg/commands/types/enums"
"github.com/jesseduffield/lazygit/pkg/constants" "github.com/jesseduffield/lazygit/pkg/constants"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/presentation"
"github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
@ -139,17 +139,17 @@ func (gui *Gui) askForConfigFile(action func(file string) error) error {
case 1: case 1:
return action(confPaths[0]) return action(confPaths[0])
default: default:
menuItems := make([]*popup.MenuItem, len(confPaths)) menuItems := make([]*types.MenuItem, len(confPaths))
for i, file := range confPaths { for i, file := range confPaths {
i := i i := i
menuItems[i] = &popup.MenuItem{ menuItems[i] = &types.MenuItem{
DisplayString: file, DisplayString: file,
OnPress: func() error { OnPress: func() error {
return action(confPaths[i]) return action(confPaths[i])
}, },
} }
} }
return gui.c.Menu(popup.CreateMenuOptions{ return gui.c.Menu(types.CreateMenuOptions{
Title: gui.c.Tr.SelectConfigFile, Title: gui.c.Tr.SelectConfigFile,
Items: menuItems, Items: menuItems,
HideCancel: true, HideCancel: true,

View File

@ -4,7 +4,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/loaders" "github.com/jesseduffield/lazygit/pkg/commands/loaders"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/controllers"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
@ -45,7 +44,7 @@ func (gui *Gui) handleCheckoutSubCommit() error {
return nil return nil
} }
err := gui.c.Ask(popup.AskOpts{ err := gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.LcCheckoutCommit, Title: gui.c.Tr.LcCheckoutCommit,
Prompt: gui.c.Tr.SureCheckoutThisCommit, Prompt: gui.c.Tr.SureCheckoutThisCommit,
HandleConfirm: func() error { HandleConfirm: func() error {

View File

@ -23,7 +23,7 @@ import (
// exists for fetching a particular model. // exists for fetching a particular model.
type SuggestionsHelper struct { type SuggestionsHelper struct {
c *controllers.ControllerCommon c *types.ControllerCommon
getState func() *GuiRepoState getState func() *GuiRepoState
refreshSuggestionsFn func() refreshSuggestionsFn func()
@ -32,7 +32,7 @@ type SuggestionsHelper struct {
var _ controllers.ISuggestionsHelper = &SuggestionsHelper{} var _ controllers.ISuggestionsHelper = &SuggestionsHelper{}
func NewSuggestionsHelper( func NewSuggestionsHelper(
c *controllers.ControllerCommon, c *types.ControllerCommon,
getState func() *GuiRepoState, getState func() *GuiRepoState,
refreshSuggestionsFn func(), refreshSuggestionsFn func(),
) *SuggestionsHelper { ) *SuggestionsHelper {

View File

@ -1,21 +1,8 @@
package gui package gui
import (
"github.com/jesseduffield/lazygit/pkg/commands/models"
)
func (self *Gui) getSelectedTag() *models.Tag {
selectedLine := self.State.Panels.Tags.SelectedLineIdx
if selectedLine == -1 || len(self.State.Tags) == 0 {
return nil
}
return self.State.Tags[selectedLine]
}
func (self *Gui) tagsRenderToMain() error { func (self *Gui) tagsRenderToMain() error {
var task updateTask var task updateTask
tag := self.getSelectedTag() tag := self.State.Contexts.Tags.GetSelectedTag()
if tag == nil { if tag == nil {
task = NewRenderStringTask("No tags") task = NewRenderStringTask("No tags")
} else { } else {
@ -31,7 +18,6 @@ func (self *Gui) tagsRenderToMain() error {
}) })
} }
// this is a controller: it can't access tags directly. Or can it? It should be able to get but not set. But that's exactly what I'm doing here, setting it. but through a mutator which encapsulates the event.
func (self *Gui) refreshTags() error { func (self *Gui) refreshTags() error {
tags, err := self.git.Loaders.Tags.GetTags() tags, err := self.git.Loaders.Tags.GetTags()
if err != nil { if err != nil {

94
pkg/gui/types/common.go Normal file
View File

@ -0,0 +1,94 @@
package types
import (
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/config"
)
// if Go let me do private struct embedding of structs with public fields (which it should)
// I would just do that. But alas.
type ControllerCommon struct {
*common.Common
IGuiCommon
}
type IGuiCommon interface {
IPopupHandler
LogAction(action string)
LogCommand(cmdStr string, isCommandLine bool)
// we call this when we want to refetch some models and render the result. Internally calls PostRefreshUpdate
Refresh(RefreshOptions) error
// we call this when we've changed something in the view model but not the actual model,
// e.g. expanding or collapsing a folder in a file view. Calling 'Refresh' in this
// case would be overkill, although refresh will internally call 'PostRefreshUpdate'
PostRefreshUpdate(Context) error
// this just re-renders the screen
Render()
RunSubprocessAndRefresh(oscommands.ICmdObj) error
PushContext(context Context, opts ...OnFocusOpts) error
PopContext() error
CurrentContext() Context
// enters search mode for the current view
OpenSearch()
GetAppState() *config.AppState
SaveAppState() error
}
type IPopupHandler interface {
ErrorMsg(message string) error
Error(err error) error
Ask(opts AskOpts) error
Prompt(opts PromptOpts) error
WithLoaderPanel(message string, f func() error) error
WithWaitingStatus(message string, f func() error) error
Menu(opts CreateMenuOptions) error
Toast(message string)
GetPromptInput() string
}
type CreateMenuOptions struct {
Title string
Items []*MenuItem
HideCancel bool
}
type CreatePopupPanelOpts struct {
HasLoader bool
Editable bool
Title string
Prompt string
HandleConfirm func() error
HandleConfirmPrompt func(string) error
HandleClose func() error
// when HandlersManageFocus is true, do not return from the confirmation context automatically. It's expected that the handlers will manage focus, whether that means switching to another context, or manually returning the context.
HandlersManageFocus bool
FindSuggestionsFunc func(string) []*Suggestion
}
type AskOpts struct {
Title string
Prompt string
HandleConfirm func() error
HandleClose func() error
HandlersManageFocus bool
}
type PromptOpts struct {
Title string
InitialContent string
FindSuggestionsFunc func(string) []*Suggestion
HandleConfirm func(string) error
}
type MenuItem struct {
DisplayString string
DisplayStrings []string
OnPress func() error
// only applies when displayString is used
OpensMenu bool
}

View File

@ -12,23 +12,33 @@ const (
EXTRAS_CONTEXT EXTRAS_CONTEXT
) )
type Context interface { type ParentContexter interface {
HandleFocus(opts ...OnFocusOpts) error SetParentContext(Context)
HandleFocusLost() error // we return a bool here to tell us whether or not the returned value just wraps a nil
HandleRender() error GetParentContext() (Context, bool)
HandleRenderToMain() error }
type IBaseContext interface {
ParentContexter
GetKind() ContextKind GetKind() ContextKind
GetViewName() string GetViewName() string
GetWindowName() string GetWindowName() string
SetWindowName(string) SetWindowName(string)
GetKey() ContextKey GetKey() ContextKey
SetParentContext(Context)
// we return a bool here to tell us whether or not the returned value just wraps a nil
GetParentContext() (Context, bool)
GetOptionsMap() map[string]string GetOptionsMap() map[string]string
} }
type Context interface {
IBaseContext
HandleFocus(opts ...OnFocusOpts) error
HandleFocusLost() error
HandleRender() error
HandleRenderToMain() error
}
type OnFocusOpts struct { type OnFocusOpts struct {
ClickedViewName string ClickedViewName string
ClickedViewLineIdx int ClickedViewLineIdx int

View File

@ -4,11 +4,11 @@ import (
"fmt" "fmt"
"github.com/jesseduffield/gocui" "github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
func (gui *Gui) showUpdatePrompt(newVersion string) error { func (gui *Gui) showUpdatePrompt(newVersion string) error {
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: "New version available!", Title: "New version available!",
Prompt: fmt.Sprintf("Download version %s? (enter/esc)", newVersion), Prompt: fmt.Sprintf("Download version %s? (enter/esc)", newVersion),
HandleConfirm: func() error { HandleConfirm: func() error {
@ -65,7 +65,7 @@ func (gui *Gui) onUpdateFinish(statusId int, err error) error {
} }
func (gui *Gui) createUpdateQuitConfirmation() error { func (gui *Gui) createUpdateQuitConfirmation() error {
return gui.c.Ask(popup.AskOpts{ return gui.c.Ask(types.AskOpts{
Title: "Currently Updating", Title: "Currently Updating",
Prompt: "An update is in progress. Are you sure you want to quit?", Prompt: "An update is in progress. Are you sure you want to quit?",
HandleConfirm: func() error { HandleConfirm: func() error {

View File

@ -254,8 +254,9 @@ func (gui *Gui) renderDisplayStrings(v *gocui.View, displayStrings [][]string) {
v.SetContent(list) v.SetContent(list)
} }
func (gui *Gui) renderDisplayStringsAtPos(v *gocui.View, y int, displayStrings [][]string) { func (gui *Gui) renderDisplayStringsInViewPort(v *gocui.View, displayStrings [][]string) {
list := utils.RenderDisplayStrings(displayStrings) list := utils.RenderDisplayStrings(displayStrings)
_, y := v.Origin()
v.OverwriteLines(y, list) v.OverwriteLines(y, list)
} }

View File

@ -3,7 +3,6 @@ package gui
import ( import (
"fmt" "fmt"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
@ -16,7 +15,7 @@ func (gui *Gui) handleCreateResetMenu() error {
nukeStr = fmt.Sprintf("%s (%s)", nukeStr, gui.c.Tr.LcAndResetSubmodules) nukeStr = fmt.Sprintf("%s (%s)", nukeStr, gui.c.Tr.LcAndResetSubmodules)
} }
menuItems := []*popup.MenuItem{ menuItems := []*types.MenuItem{
{ {
DisplayStrings: []string{ DisplayStrings: []string{
gui.c.Tr.LcDiscardAllChangesToAllFiles, gui.c.Tr.LcDiscardAllChangesToAllFiles,
@ -103,5 +102,5 @@ func (gui *Gui) handleCreateResetMenu() error {
}, },
} }
return gui.c.Menu(popup.CreateMenuOptions{Title: "", Items: menuItems}) return gui.c.Menu(types.CreateMenuOptions{Title: "", Items: menuItems})
} }