1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2024-11-28 09:08:41 +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
import (
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type BasicContext struct {
type SimpleContext 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
Kind types.ContextKind
Key types.ContextKey
ViewName string
WindowName string
OnGetOptionsMap func() map[string]string
OnRenderToMain func(opts ...types.OnFocusOpts) error
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
*context.BaseContext
}
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 {
if self.OnGetOptionsMap != nil {
return self.OnGetOptionsMap()
func NewSimpleContext(baseContext *context.BaseContext, opts NewSimpleContextOpts) *SimpleContext {
return &SimpleContext{
OnFocus: opts.OnFocus,
OnFocusLost: opts.OnFocusLost,
OnRender: opts.OnRender,
OnRenderToMain: opts.OnRenderToMain,
BaseContext: baseContext,
}
return nil
}
func (self *BasicContext) SetParentContext(context types.Context) {
self.ParentContext = context
self.hasParent = true
}
var _ types.Context = &SimpleContext{}
func (self *BasicContext) GetParentContext() (types.Context, bool) {
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 {
func (self *SimpleContext) HandleRender() error {
if self.OnRender != nil {
return self.OnRender()
}
return nil
}
func (self *BasicContext) GetViewName() string {
return self.ViewName
}
func (self *BasicContext) HandleFocus(opts ...types.OnFocusOpts) error {
func (self *SimpleContext) HandleFocus(opts ...types.OnFocusOpts) error {
if self.OnFocus != nil {
if err := self.OnFocus(opts...); err != nil {
return err
@ -81,25 +58,17 @@ func (self *BasicContext) HandleFocus(opts ...types.OnFocusOpts) error {
return nil
}
func (self *BasicContext) HandleFocusLost() error {
func (self *SimpleContext) HandleFocusLost() error {
if self.OnFocusLost != nil {
return self.OnFocusLost()
}
return nil
}
func (self *BasicContext) HandleRenderToMain() error {
func (self *SimpleContext) HandleRenderToMain() error {
if self.OnRenderToMain != nil {
return self.OnRenderToMain()
}
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/models"
"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/utils"
)
@ -145,7 +144,7 @@ func (gui *Gui) handleForceCheckout() error {
message := gui.c.Tr.SureForceCheckout
title := gui.c.Tr.ForceCheckoutBranch
return gui.c.Ask(popup.AskOpts{
return gui.c.Ask(types.AskOpts{
Title: title,
Prompt: message,
HandleConfirm: func() error {
@ -159,14 +158,14 @@ func (gui *Gui) handleForceCheckout() error {
}
func (gui *Gui) handleCheckoutByName() error {
return gui.c.Prompt(popup.PromptOpts{
return gui.c.Prompt(types.PromptOpts{
Title: gui.c.Tr.BranchName + ":",
FindSuggestionsFunc: gui.suggestionsHelper.GetRefsSuggestionsFunc(),
HandleConfirm: func(response string) error {
gui.c.LogAction("Checkout branch")
return gui.refHelper.CheckoutRef(response, types.CheckoutRefOptions{
OnRefNotFound: func(ref string) error {
return gui.c.Ask(popup.AskOpts{
return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.BranchNotFoundTitle,
Prompt: fmt.Sprintf("%s %s%s", gui.c.Tr.BranchNotFoundPrompt, ref, "?"),
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,
Prompt: message,
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,
Prompt: prompt,
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,
Prompt: prompt,
HandleConfirm: func() error {
@ -368,7 +367,7 @@ func (gui *Gui) handleRenameBranch() error {
}
promptForNewName := func() error {
return gui.c.Prompt(popup.PromptOpts{
return gui.c.Prompt(types.PromptOpts{
Title: gui.c.Tr.NewBranchNamePrompt + " " + branch.Name + ":",
InitialContent: branch.Name,
HandleConfirm: func(newBranchName string) error {
@ -402,7 +401,7 @@ func (gui *Gui) handleRenameBranch() error {
return promptForNewName()
}
return gui.c.Ask(popup.AskOpts{
return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.LcRenameBranch,
Prompt: gui.c.Tr.RenameBranchWarning,
HandleConfirm: promptForNewName,
@ -430,7 +429,7 @@ func (gui *Gui) handleNewBranchOffCurrentItem() error {
prefilledName = strings.SplitAfterN(item.ID(), "/", 2)[1]
}
return gui.c.Prompt(popup.PromptOpts{
return gui.c.Prompt(types.PromptOpts{
Title: message,
InitialContent: prefilledName,
HandleConfirm: func(response string) error {

View File

@ -2,7 +2,6 @@ package gui
import (
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"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
func (gui *Gui) HandlePasteCommits() error {
return gui.c.Ask(popup.AskOpts{
return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.CherryPick,
Prompt: gui.c.Tr.SureCherryPick,
HandleConfirm: func() error {

View File

@ -5,7 +5,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/patch"
"github.com/jesseduffield/lazygit/pkg/gui/controllers"
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
@ -81,7 +80,7 @@ func (gui *Gui) handleDiscardOldFileChange() error {
fileName := gui.getSelectedCommitFileName()
return gui.c.Ask(popup.AskOpts{
return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.DiscardFileChangesTitle,
Prompt: gui.c.Tr.DiscardFileChangesPrompt,
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() {
return gui.c.Ask(popup.AskOpts{
return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.DiscardPatch,
Prompt: gui.c.Tr.DiscardPatchConfirm,
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() {
return gui.c.Ask(popup.AskOpts{
return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.DiscardPatch,
Prompt: gui.c.Tr.DiscardPatchConfirm,
HandleConfirm: func() error {

View File

@ -191,12 +191,6 @@ func (gui *Gui) setKeyBindings(opts popup.CreatePopupPanelOpts) error {
onConfirm = gui.wrappedConfirmationFunction(opts.HandlersManageFocus, opts.HandleConfirm)
}
type confirmationKeybinding struct {
viewName string
key interface{}
handler func() error
}
keybindingConfig := gui.c.UserConfig.Keybinding
onSuggestionConfirm := gui.wrappedPromptConfirmationFunction(
opts.HandlersManageFocus,
@ -204,26 +198,30 @@ func (gui *Gui) setKeyBindings(opts popup.CreatePopupPanelOpts) error {
gui.getSelectedSuggestionValue,
)
confirmationKeybindings := []confirmationKeybinding{
bindings := []*types.Binding{
{
viewName: "confirmation",
key: gui.getKey(keybindingConfig.Universal.Confirm),
handler: onConfirm,
ViewName: "confirmation",
Contexts: []string{string(CONFIRMATION_CONTEXT_KEY)},
Key: gui.getKey(keybindingConfig.Universal.Confirm),
Handler: onConfirm,
},
{
viewName: "confirmation",
key: gui.getKey(keybindingConfig.Universal.ConfirmAlt1),
handler: onConfirm,
ViewName: "confirmation",
Contexts: []string{string(CONFIRMATION_CONTEXT_KEY)},
Key: gui.getKey(keybindingConfig.Universal.ConfirmAlt1),
Handler: onConfirm,
},
{
viewName: "confirmation",
key: gui.getKey(keybindingConfig.Universal.Return),
handler: gui.wrappedConfirmationFunction(opts.HandlersManageFocus, opts.HandleClose),
ViewName: "confirmation",
Contexts: []string{string(CONFIRMATION_CONTEXT_KEY)},
Key: gui.getKey(keybindingConfig.Universal.Return),
Handler: gui.wrappedConfirmationFunction(opts.HandlersManageFocus, opts.HandleClose),
},
{
viewName: "confirmation",
key: gui.getKey(keybindingConfig.Universal.TogglePanel),
handler: func() error {
ViewName: "confirmation",
Contexts: []string{string(CONFIRMATION_CONTEXT_KEY)},
Key: gui.getKey(keybindingConfig.Universal.TogglePanel),
Handler: func() error {
if len(gui.State.Suggestions) > 0 {
return gui.replaceContext(gui.State.Contexts.Suggestions)
}
@ -231,29 +229,33 @@ func (gui *Gui) setKeyBindings(opts popup.CreatePopupPanelOpts) error {
},
},
{
viewName: "suggestions",
key: gui.getKey(keybindingConfig.Universal.Confirm),
handler: onSuggestionConfirm,
ViewName: "suggestions",
Contexts: []string{string(CONFIRMATION_CONTEXT_KEY)},
Key: gui.getKey(keybindingConfig.Universal.Confirm),
Handler: onSuggestionConfirm,
},
{
viewName: "suggestions",
key: gui.getKey(keybindingConfig.Universal.ConfirmAlt1),
handler: onSuggestionConfirm,
ViewName: "suggestions",
Contexts: []string{string(CONFIRMATION_CONTEXT_KEY)},
Key: gui.getKey(keybindingConfig.Universal.ConfirmAlt1),
Handler: onSuggestionConfirm,
},
{
viewName: "suggestions",
key: gui.getKey(keybindingConfig.Universal.Return),
handler: gui.wrappedConfirmationFunction(opts.HandlersManageFocus, opts.HandleClose),
ViewName: "suggestions",
Contexts: []string{string(CONFIRMATION_CONTEXT_KEY)},
Key: gui.getKey(keybindingConfig.Universal.Return),
Handler: gui.wrappedConfirmationFunction(opts.HandlersManageFocus, opts.HandleClose),
},
{
viewName: "suggestions",
key: gui.getKey(keybindingConfig.Universal.TogglePanel),
handler: func() error { return gui.replaceContext(gui.State.Contexts.Confirmation) },
ViewName: "suggestions",
Contexts: []string{string(CONFIRMATION_CONTEXT_KEY)},
Key: gui.getKey(keybindingConfig.Universal.TogglePanel),
Handler: func() error { return gui.replaceContext(gui.State.Contexts.Confirmation) },
},
}
for _, binding := range confirmationKeybindings {
if err := gui.g.SetKeybinding(binding.viewName, nil, binding.key, gocui.ModNone, gui.wrappedHandler(binding.handler)); err != nil {
for _, binding := range bindings {
if err := gui.SetKeybinding(binding); err != nil {
return err
}
}
@ -271,12 +273,6 @@ func (gui *Gui) clearConfirmationViewKeyBindings() {
_ = 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() {
gui.suggestionsAsyncHandler.Do(func() func() {
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
Remotes types.IListContext
RemoteBranches types.IListContext
Tags types.IListContext
Tags *TagsContext
BranchCommits types.IListContext
CommitFiles 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 {
return context.ContextTree{
Status: &BasicContext{
OnRenderToMain: OnFocusWrapper(gui.statusRenderToMain),
Kind: types.SIDE_CONTEXT,
ViewName: "status",
Key: STATUS_CONTEXT_KEY,
},
Status: NewSimpleContext(
context.NewBaseContext(context.NewBaseContextOpts{
Kind: types.SIDE_CONTEXT,
ViewName: "status",
Key: STATUS_CONTEXT_KEY,
WindowName: "status",
}),
NewSimpleContextOpts{
OnRenderToMain: OnFocusWrapper(gui.statusRenderToMain),
},
),
Files: gui.filesListContext(),
Submodules: gui.submodulesListContext(),
Menu: gui.menuListContext(),
@ -104,86 +109,130 @@ func (gui *Gui) contextTree() context.ContextTree {
Branches: gui.branchesListContext(),
Tags: gui.tagsListContext(),
Stash: gui.stashListContext(),
Normal: &BasicContext{
OnFocus: func(opts ...types.OnFocusOpts) error {
return nil // TODO: should we do something here? We should allow for scrolling the panel
Suggestions: gui.suggestionsListContext(),
Normal: NewSimpleContext(
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",
Key: MAIN_NORMAL_CONTEXT_KEY,
},
Staging: &BasicContext{
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" {
),
Staging: NewSimpleContext(
context.NewBaseContext(context.NewBaseContextOpts{
Kind: types.MAIN_CONTEXT,
ViewName: "main",
WindowName: "main",
Key: MAIN_STAGING_CONTEXT_KEY,
}),
NewSimpleContextOpts{
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
}
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",
Key: MAIN_PATCH_BUILDING_CONTEXT_KEY,
},
Merging: &BasicContext{
OnFocus: OnFocusWrapper(func() error { return gui.renderConflictsWithLock(true) }),
Kind: types.MAIN_CONTEXT,
ViewName: "main",
Key: MAIN_MERGING_CONTEXT_KEY,
OnGetOptionsMap: gui.getMergingOptions,
},
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
),
Merging: NewSimpleContext(
context.NewBaseContext(context.NewBaseContextOpts{
Kind: types.MAIN_CONTEXT,
ViewName: "main",
WindowName: "main",
Key: MAIN_MERGING_CONTEXT_KEY,
OnGetOptionsMap: gui.getMergingOptions,
}),
NewSimpleContextOpts{
OnFocus: OnFocusWrapper(func() error { return gui.renderConflictsWithLock(true) }),
},
},
),
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/models"
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type BisectController struct {
c *ControllerCommon
c *types.ControllerCommon
getContext func() types.IListContext
git *commands.GitCommand
@ -24,7 +23,7 @@ type BisectController struct {
var _ types.IController = &BisectController{}
func NewBisectController(
c *ControllerCommon,
c *types.ControllerCommon,
getContext func() types.IListContext,
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.
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()),
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,
Items: menuItems,
})
}
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,
Items: []*popup.MenuItem{
Items: []*types.MenuItem{
{
DisplayString: fmt.Sprintf(self.c.Tr.Bisect.MarkStart, commit.ShortSha(), info.NewTerm()),
OnPress: func() error {
@ -167,7 +166,7 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo,
}
func (self *BisectController) Reset() error {
return self.c.Ask(popup.AskOpts{
return self.c.Ask(types.AskOpts{
Title: self.c.Tr.Bisect.ResetTitle,
Prompt: self.c.Tr.Bisect.ResetPrompt,
HandleConfirm: func() error {
@ -192,7 +191,7 @@ func (self *BisectController) showBisectCompleteMessage(candidateShas []string)
return self.c.Error(err)
}
return self.c.Ask(popup.AskOpts{
return self.c.Ask(types.AskOpts{
Title: self.c.Tr.Bisect.CompleteTitle,
Prompt: fmt.Sprintf(prompt, strings.TrimSpace(formattedCommits)),
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/gui/context"
"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/utils"
)
@ -22,7 +21,7 @@ type FilesController struct {
// 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
// to the client
c *ControllerCommon
c *types.ControllerCommon
getContext func() types.IListContext
git *commands.GitCommand
os *oscommands.OSCommand
@ -48,7 +47,7 @@ type FilesController struct {
var _ types.IController = &FilesController{}
func NewFilesController(
c *ControllerCommon,
c *types.ControllerCommon,
getContext func() types.IListContext,
git *commands.GitCommand,
os *oscommands.OSCommand,
@ -344,7 +343,7 @@ func (self *FilesController) ignore(node *filetree.FileNode) error {
}
if node.GetIsTracked() {
return self.c.Ask(popup.AskOpts{
return self.c.Ask(types.AskOpts{
Title: self.c.Tr.IgnoreTracked,
Prompt: self.c.Tr.IgnoreTrackedPrompt,
HandleConfirm: func() error {
@ -461,7 +460,7 @@ func (self *FilesController) HandleCommitPress() 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,
Prompt: self.c.Tr.NoFilesStagedPrompt,
HandleConfirm: func() error {
@ -491,7 +490,7 @@ func (self *FilesController) handleAmendCommitPress() error {
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),
Prompt: self.c.Tr.SureToAmend,
HandleConfirm: func() error {
@ -520,9 +519,9 @@ func (self *FilesController) HandleCommitEditorPress() error {
}
func (self *FilesController) handleStatusFilterPressed() error {
return self.c.Menu(popup.CreateMenuOptions{
return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.FilteringMenuTitle,
Items: []*popup.MenuItem{
Items: []*types.MenuItem{
{
DisplayString: self.c.Tr.FilterStagedFiles,
OnPress: func() error {
@ -577,7 +576,7 @@ func (self *FilesController) switchToMerge() error {
}
func (self *FilesController) handleCustomCommand() error {
return self.c.Prompt(popup.PromptOpts{
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.CustomCommand,
FindSuggestionsFunc: self.suggestionsHelper.GetCustomCommandsHistorySuggestionsFunc(),
HandleConfirm: func(command string) error {
@ -602,9 +601,9 @@ func (self *FilesController) handleCustomCommand() error {
}
func (self *FilesController) createStashMenu() error {
return self.c.Menu(popup.CreateMenuOptions{
return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.LcStashOptions,
Items: []*popup.MenuItem{
Items: []*types.MenuItem{
{
DisplayString: self.c.Tr.LcStashAllChanges,
OnPress: func() error {
@ -665,7 +664,7 @@ func (self *FilesController) toggleTreeView() error {
}
func (self *FilesController) OpenMergeTool() error {
return self.c.Ask(popup.AskOpts{
return self.c.Ask(types.AskOpts{
Title: self.c.Tr.MergeToolTitle,
Prompt: self.c.Tr.MergeToolPrompt,
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.Prompt(popup.PromptOpts{
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.StashChanges,
HandleConfirm: func(stashComment string) error {
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/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/utils"
)
@ -26,7 +25,7 @@ type (
)
type LocalCommitsController struct {
c *ControllerCommon
c *types.ControllerCommon
getContext func() types.IListContext
os *oscommands.OSCommand
git *commands.GitCommand
@ -50,7 +49,7 @@ type LocalCommitsController struct {
var _ types.IController = &LocalCommitsController{}
func NewLocalCommitsController(
c *ControllerCommon,
c *types.ControllerCommon,
getContext func() types.IListContext,
os *oscommands.OSCommand,
git *commands.GitCommand,
@ -241,7 +240,7 @@ func (self *LocalCommitsController) squashDown() error {
return nil
}
return self.c.Ask(popup.AskOpts{
return self.c.Ask(types.AskOpts{
Title: self.c.Tr.Squash,
Prompt: self.c.Tr.SureSquashThisCommit,
HandleConfirm: func() error {
@ -266,7 +265,7 @@ func (self *LocalCommitsController) fixup() error {
return nil
}
return self.c.Ask(popup.AskOpts{
return self.c.Ask(types.AskOpts{
Title: self.c.Tr.Fixup,
Prompt: self.c.Tr.SureFixupThisCommit,
HandleConfirm: func() error {
@ -293,7 +292,7 @@ func (self *LocalCommitsController) reword(commit *models.Commit) error {
}
// TODO: use the commit message panel here
return self.c.Prompt(popup.PromptOpts{
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.LcRewordCommit,
InitialContent: message,
HandleConfirm: func(response string) error {
@ -339,7 +338,7 @@ func (self *LocalCommitsController) drop() error {
return nil
}
return self.c.Ask(popup.AskOpts{
return self.c.Ask(types.AskOpts{
Title: self.c.Tr.DeleteCommitTitle,
Prompt: self.c.Tr.DeleteCommitPrompt,
HandleConfirm: func() error {
@ -488,7 +487,7 @@ func (self *LocalCommitsController) handleCommitMoveUp() error {
}
func (self *LocalCommitsController) handleCommitAmendTo() error {
return self.c.Ask(popup.AskOpts{
return self.c.Ask(types.AskOpts{
Title: self.c.Tr.AmendCommitTitle,
Prompt: self.c.Tr.AmendCommitPrompt,
HandleConfirm: func() error {
@ -505,7 +504,7 @@ func (self *LocalCommitsController) handleCommitRevert(commit *models.Commit) er
if commit.IsMerge() {
return self.createRevertMergeCommitMenu(commit)
} else {
return self.c.Ask(popup.AskOpts{
return self.c.Ask(types.AskOpts{
Title: self.c.Tr.Actions.RevertCommit,
Prompt: utils.ResolvePlaceholderString(
self.c.Tr.ConfirmRevertCommit,
@ -524,7 +523,7 @@ func (self *LocalCommitsController) handleCommitRevert(commit *models.Commit) er
}
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 {
i := i
message, err := self.git.Commit.GetCommitMessageFirstLine(parentSha)
@ -532,7 +531,7 @@ func (self *LocalCommitsController) createRevertMergeCommitMenu(commit *models.C
return self.c.Error(err)
}
menuItems[i] = &popup.MenuItem{
menuItems[i] = &types.MenuItem{
DisplayString: fmt.Sprintf("%s: %s", utils.SafeTruncate(parentSha, 8), message),
OnPress: func() error {
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 {
@ -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,
Prompt: prompt,
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,
Prompt: prompt,
HandleConfirm: func() error {
@ -612,7 +611,7 @@ func (self *LocalCommitsController) handleTagCommit(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,
Prompt: self.c.Tr.SureCheckoutThisCommit,
HandleConfirm: func() error {
@ -669,9 +668,9 @@ func (self *LocalCommitsController) handleCopySelectedCommitMessageToClipboard(c
}
func (self *LocalCommitsController) handleOpenLogMenu() error {
return self.c.Menu(popup.CreateMenuOptions{
return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.LogMenuTitle,
Items: []*popup.MenuItem{
Items: []*types.MenuItem{
{
DisplayString: self.c.Tr.ToggleShowGitGraphAll,
OnPress: func() error {
@ -696,9 +695,9 @@ func (self *LocalCommitsController) handleOpenLogMenu() error {
return nil
}
}
return self.c.Menu(popup.CreateMenuOptions{
return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.LogMenuTitle,
Items: []*popup.MenuItem{
Items: []*types.MenuItem{
{
DisplayString: "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,
Items: []*popup.MenuItem{
Items: []*types.MenuItem{
{
DisplayString: "topological (topo-order)",
OnPress: onPress("topo-order"),

View File

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

View File

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

View File

@ -9,13 +9,12 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"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/types"
)
type SubmodulesController struct {
c *ControllerCommon
c *types.ControllerCommon
context types.IListContext
git *commands.GitCommand
@ -26,7 +25,7 @@ type SubmodulesController struct {
var _ types.IController = &SubmodulesController{}
func NewSubmodulesController(
c *ControllerCommon,
c *types.ControllerCommon,
context types.IListContext,
git *commands.GitCommand,
enterSubmodule func(submodule *models.SubmoduleConfig) error,
@ -93,17 +92,17 @@ func (self *SubmodulesController) enter(submodule *models.SubmoduleConfig) error
}
func (self *SubmodulesController) add() error {
return self.c.Prompt(popup.PromptOpts{
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.LcNewSubmoduleUrl,
HandleConfirm: func(submoduleUrl string) error {
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,
InitialContent: nameSuggestion,
HandleConfirm: func(submoduleName string) error {
return self.c.Prompt(popup.PromptOpts{
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.LcNewSubmodulePath,
InitialContent: submoduleName,
HandleConfirm: func(submodulePath string) error {
@ -125,7 +124,7 @@ func (self *SubmodulesController) add() 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),
InitialContent: submodule.Url,
HandleConfirm: func(newUrl string) error {
@ -155,9 +154,9 @@ func (self *SubmodulesController) init(submodule *models.SubmoduleConfig) error
}
func (self *SubmodulesController) openBulkActionsMenu() error {
return self.c.Menu(popup.CreateMenuOptions{
return self.c.Menu(types.CreateMenuOptions{
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())},
OnPress: func() error {
@ -215,7 +214,7 @@ func (self *SubmodulesController) update(submodule *models.SubmoduleConfig) erro
}
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,
Prompt: fmt.Sprintf(self.c.Tr.RemoveSubmodulePrompt, submodule.Name),
HandleConfirm: func() error {

View File

@ -8,7 +8,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"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
// struct embedding, but Go does not allow hiding public fields in an embedded struct
// to the client
c *ControllerCommon
c *types.ControllerCommon
git *commands.GitCommand
getCheckedOutBranch func() *models.Branch
@ -29,7 +28,7 @@ type SyncController struct {
var _ types.IController = &SyncController{}
func NewSyncController(
c *ControllerCommon,
c *types.ControllerCommon,
git *commands.GitCommand,
getCheckedOutBranch func() *models.Branch,
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 {
suggestedRemote := self.getSuggestedRemote()
return self.c.Prompt(popup.PromptOpts{
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.EnterUpstream,
InitialContent: suggestedRemote + " " + currentBranch.Name,
FindSuggestionsFunc: self.suggestionsHelper.GetRemoteBranchesSuggestionsFunc(" "),
@ -219,7 +218,7 @@ func (self *SyncController) pushAux(opts pushOpts) error {
_ = self.c.ErrorMsg(self.c.Tr.UpdatesRejectedAndForcePushDisabled)
return nil
}
_ = self.c.Ask(popup.AskOpts{
_ = self.c.Ask(types.AskOpts{
Title: self.c.Tr.ForcePush,
Prompt: self.c.Tr.ForcePushPrompt,
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.Ask(popup.AskOpts{
return self.c.Ask(types.AskOpts{
Title: self.c.Tr.ForcePush,
Prompt: self.c.Tr.ForcePushPrompt,
HandleConfirm: func() error {

View File

@ -5,35 +5,32 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/config"
"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/utils"
)
type TagsController struct {
c *ControllerCommon
getContext func() types.IListContext
c *types.ControllerCommon
getContext func() *context.TagsContext
git *commands.GitCommand
getContexts func() context.ContextTree
refHelper IRefHelper
suggestionsHelper ISuggestionsHelper
getSelectedTag func() *models.Tag
switchToSubCommitsContext func(string) error
}
var _ types.IController = &TagsController{}
func NewTagsController(
c *ControllerCommon,
getContext func() types.IListContext,
c *types.ControllerCommon,
getContext func() *context.TagsContext,
git *commands.GitCommand,
getContexts func() context.ContextTree,
refHelper IRefHelper,
suggestionsHelper ISuggestionsHelper,
getSelectedTag func() *models.Tag,
switchToSubCommitsContext func(string) error,
) *TagsController {
return &TagsController{
@ -44,7 +41,6 @@ func NewTagsController(
refHelper: refHelper,
suggestionsHelper: suggestionsHelper,
getSelectedTag: getSelectedTag,
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,
Prompt: prompt,
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,
InitialContent: "origin",
FindSuggestionsFunc: self.suggestionsHelper.GetRemoteSuggestionsFunc(),
@ -151,9 +147,9 @@ func (self *TagsController) createResetMenu(tag *models.Tag) 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,
Items: []*popup.MenuItem{
Items: []*types.MenuItem{
{
DisplayString: self.c.Tr.LcLightweightTag,
OnPress: func() error {
@ -178,10 +174,10 @@ func (self *TagsController) afterTagCreate() 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,
HandleConfirm: func(tagName string) error {
return self.c.Prompt(popup.PromptOpts{
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.TagMessageTitle,
HandleConfirm: func(msg string) error {
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 {
return self.c.Prompt(popup.PromptOpts{
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.TagNameTitle,
HandleConfirm: func(tagName string) error {
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 {
return func() error {
tag := self.getSelectedTag()
tag := self.getContext().GetSelectedTag()
if tag == nil {
return nil
}

View File

@ -2,31 +2,9 @@ package controllers
import (
"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"
)
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 {
CheckoutRef(ref string, options types.CheckoutRefOptions) 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/types/enums"
"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/utils"
)
@ -21,7 +20,7 @@ import (
// two user actions, meaning we end up undoing reflog entry C. Redoing works in a similar way.
type UndoController struct {
c *ControllerCommon
c *types.ControllerCommon
git *commands.GitCommand
refHelper IRefHelper
@ -33,7 +32,7 @@ type UndoController struct {
var _ types.IController = &UndoController{}
func NewUndoController(
c *ControllerCommon,
c *types.ControllerCommon,
git *commands.GitCommand,
refHelper IRefHelper,
workingTreeHelper IWorkingTreeHelper,
@ -235,7 +234,7 @@ func (self *UndoController) hardResetWithAutoStash(commitSha string, options har
dirtyWorkingTree := self.workingTreeHelper.IsWorkingTreeDirty()
if dirtyWorkingTree {
// offer to autostash changes
return self.c.Ask(popup.AskOpts{
return self.c.Ask(types.AskOpts{
Title: self.c.Tr.AutoStashTitle,
Prompt: self.c.Tr.AutoStashPrompt,
HandleConfirm: func() error {

View File

@ -12,7 +12,6 @@ import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"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/types"
"github.com/jesseduffield/lazygit/pkg/utils"
@ -49,7 +48,7 @@ func (gui *Gui) resolveTemplate(templateStr string, promptResponses []string) (s
SelectedLocalBranch: gui.getSelectedBranch(),
SelectedRemoteBranch: gui.getSelectedRemoteBranch(),
SelectedRemote: gui.getSelectedRemote(),
SelectedTag: gui.getSelectedTag(),
SelectedTag: gui.State.Contexts.Tags.GetSelectedTag(),
SelectedStashEntry: gui.getSelectedStashEntry(),
SelectedCommitFile: gui.getSelectedCommitFile(),
SelectedCommitFilePath: gui.getSelectedCommitFilePath(),
@ -72,7 +71,7 @@ func (gui *Gui) inputPrompt(prompt config.CustomCommandPrompt, promptResponses [
return gui.c.Error(err)
}
return gui.c.Prompt(popup.PromptOpts{
return gui.c.Prompt(types.PromptOpts{
Title: title,
InitialContent: initialValue,
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 {
// 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 {
option := option
@ -108,7 +107,7 @@ func (gui *Gui) menuPrompt(prompt config.CustomCommandPrompt, promptResponses []
return gui.c.Error(err)
}
menuItems[i] = &popup.MenuItem{
menuItems[i] = &types.MenuItem{
DisplayStrings: []string{name, style.FgYellow.Sprint(description)},
OnPress: func() error {
promptResponses[responseIdx] = value
@ -122,7 +121,7 @@ func (gui *Gui) menuPrompt(prompt config.CustomCommandPrompt, promptResponses []
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) {
@ -216,10 +215,10 @@ func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptR
return gui.c.Error(err)
}
menuItems := make([]*popup.MenuItem, len(candidates))
menuItems := make([]*types.MenuItem, len(candidates))
for i := range candidates {
i := i
menuItems[i] = &popup.MenuItem{
menuItems[i] = &types.MenuItem{
DisplayStrings: []string{candidates[i].label},
OnPress: func() error {
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.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 {

View File

@ -5,7 +5,6 @@ import (
"strings"
"github.com/jesseduffield/lazygit/pkg/gui/modes/diffing"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
@ -107,10 +106,10 @@ func (gui *Gui) diffStr() string {
func (gui *Gui) handleCreateDiffingMenuPanel() error {
names := gui.currentDiffTerminals()
menuItems := []*popup.MenuItem{}
menuItems := []*types.MenuItem{}
for _, name := range names {
name := name
menuItems = append(menuItems, []*popup.MenuItem{
menuItems = append(menuItems, []*types.MenuItem{
{
DisplayString: fmt.Sprintf("%s %s", gui.c.Tr.LcDiff, name),
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,
OnPress: func() error {
return gui.c.Prompt(popup.PromptOpts{
return gui.c.Prompt(types.PromptOpts{
Title: gui.c.Tr.LcEnteRefName,
FindSuggestionsFunc: gui.suggestionsHelper.GetRefsSuggestionsFunc(),
HandleConfirm: func(response string) error {
@ -139,7 +138,7 @@ func (gui *Gui) handleCreateDiffingMenuPanel() error {
}...)
if gui.State.Modes.Diffing.Active() {
menuItems = append(menuItems, []*popup.MenuItem{
menuItems = append(menuItems, []*types.MenuItem{
{
DisplayString: gui.c.Tr.LcSwapDiff,
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
import (
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
@ -11,9 +10,9 @@ func (gui *Gui) handleCreateDiscardMenu() error {
return nil
}
var menuItems []*popup.MenuItem
var menuItems []*types.MenuItem
if node.File == nil {
menuItems = []*popup.MenuItem{
menuItems = []*types.MenuItem{
{
DisplayString: gui.c.Tr.LcDiscardAllChanges,
OnPress: func() error {
@ -27,7 +26,7 @@ func (gui *Gui) handleCreateDiscardMenu() error {
}
if node.GetHasStagedChanges() && node.GetHasUnstagedChanges() {
menuItems = append(menuItems, &popup.MenuItem{
menuItems = append(menuItems, &types.MenuItem{
DisplayString: gui.c.Tr.LcDiscardUnstagedChanges,
OnPress: func() error {
gui.c.LogAction(gui.c.Tr.Actions.DiscardUnstagedChangesInDirectory)
@ -46,7 +45,7 @@ func (gui *Gui) handleCreateDiscardMenu() error {
if file.IsSubmodule(submodules) {
submodule := file.SubmoduleConfig(submodules)
menuItems = []*popup.MenuItem{
menuItems = []*types.MenuItem{
{
DisplayString: gui.c.Tr.LcSubmoduleStashAndReset,
OnPress: func() error {
@ -55,7 +54,7 @@ func (gui *Gui) handleCreateDiscardMenu() error {
},
}
} else {
menuItems = []*popup.MenuItem{
menuItems = []*types.MenuItem{
{
DisplayString: gui.c.Tr.LcDiscardAllChanges,
OnPress: func() error {
@ -69,7 +68,7 @@ func (gui *Gui) handleCreateDiscardMenu() error {
}
if file.HasStagedChanges && file.HasUnstagedChanges {
menuItems = append(menuItems, &popup.MenuItem{
menuItems = append(menuItems, &types.MenuItem{
DisplayString: gui.c.Tr.LcDiscardUnstagedChanges,
OnPress: func() error {
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 (
"io"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
func (gui *Gui) handleCreateExtrasMenuPanel() error {
return gui.c.Menu(popup.CreateMenuOptions{
return gui.c.Menu(types.CreateMenuOptions{
Title: gui.c.Tr.CommandLog,
Items: []*popup.MenuItem{
Items: []*types.MenuItem{
{
DisplayString: gui.c.Tr.ToggleShowCommandLog,
OnPress: func() error {

View File

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

View File

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

View File

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

View File

@ -4,7 +4,7 @@ import (
"fmt"
"strings"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
func (gui *Gui) handleCreateFilteringMenuPanel() error {
@ -22,10 +22,10 @@ func (gui *Gui) handleCreateFilteringMenuPanel() error {
}
}
menuItems := []*popup.MenuItem{}
menuItems := []*types.MenuItem{}
if fileName != "" {
menuItems = append(menuItems, &popup.MenuItem{
menuItems = append(menuItems, &types.MenuItem{
DisplayString: fmt.Sprintf("%s '%s'", gui.c.Tr.LcFilterBy, fileName),
OnPress: func() error {
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,
OnPress: func() error {
return gui.c.Prompt(popup.PromptOpts{
return gui.c.Prompt(types.PromptOpts{
FindSuggestionsFunc: gui.suggestionsHelper.GetFilePathSuggestionsFunc(),
Title: gui.c.Tr.EnterFileName,
HandleConfirm: func(response string) error {
@ -47,11 +47,11 @@ func (gui *Gui) handleCreateFilteringMenuPanel() error {
})
if gui.State.Modes.Filtering.Active() {
menuItems = append(menuItems, &popup.MenuItem{
menuItems = append(menuItems, &types.MenuItem{
DisplayString: gui.c.Tr.LcExitFilterMode,
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 (
"fmt"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
)
@ -21,7 +21,7 @@ func (gui *Gui) handleCreateGitFlowMenu() error {
return func() error {
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,
HandleConfirm: func(name string) error {
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",
Items: []*popup.MenuItem{
Items: []*types.MenuItem{
{
// not localising here because it's one to one with the actual git flow commands
DisplayString: fmt.Sprintf("finish branch '%s'", branch.Name),

View File

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

View File

@ -3,18 +3,16 @@ package gui
import (
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"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"
)
// hacking this by including the gui struct for now until we split more things out
type guiCommon struct {
gui *Gui
popup.IPopupHandler
types.IPopupHandler
}
var _ controllers.IGuiCommon = &guiCommon{}
var _ types.IGuiCommon = &guiCommon{}
func (self *guiCommon) LogAction(msg string) {
self.gui.LogAction(msg)
@ -44,6 +42,10 @@ func (self *guiCommon) PopContext() error {
return self.gui.returnFromContext()
}
func (self *guiCommon) CurrentContext() types.Context {
return self.gui.currentContext()
}
func (self *guiCommon) GetAppState() *config.AppState {
return self.gui.Config.GetAppState()
}
@ -51,3 +53,11 @@ func (self *guiCommon) GetAppState() *config.AppState {
func (self *guiCommon) SaveAppState() error {
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()...)
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
}
}
@ -1508,3 +1508,29 @@ func (gui *Gui) keybindings() error {
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/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
@ -25,7 +26,7 @@ type ListContext struct {
Gui *Gui
*BasicContext
*context.BaseContext
}
var _ types.IListContext = &ListContext{}
@ -46,7 +47,7 @@ func (self *ListContext) FocusLine() {
if self.RenderSelection {
_, originY := view.Origin()
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())
}
@ -101,16 +102,8 @@ func (self *ListContext) HandleFocusLost() error {
}
func (self *ListContext) HandleFocus(opts ...types.OnFocusOpts) error {
if self.Gui.popupPanelFocused() {
return nil
}
self.FocusLine()
if self.Gui.State.Modes.Diffing.Active() {
return self.Gui.renderDiff()
}
if self.OnFocus != nil {
if err := self.OnFocus(opts...); err != nil {
return err

View File

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

View File

@ -4,7 +4,7 @@ import (
"errors"
"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/utils"
)
@ -24,10 +24,10 @@ func (gui *Gui) handleMenuClose() error {
}
// 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 {
// 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},
OnPress: func() error {
return nil
@ -69,7 +69,7 @@ func (gui *Gui) createMenu(opts popup.CreateMenuOptions) error {
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 {
return nil
}

View File

@ -4,7 +4,6 @@ import (
"strings"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
@ -56,11 +55,11 @@ func (gui *Gui) handleCreateOptionsMenu() error {
bindings := gui.getBindings(view)
menuItems := make([]*popup.MenuItem, len(bindings))
menuItems := make([]*types.MenuItem, len(bindings))
for i, binding := range bindings {
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)},
OnPress: func() error {
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),
Items: menuItems,
HideCancel: true,

View File

@ -4,7 +4,6 @@ import (
"fmt"
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
@ -13,7 +12,7 @@ func (gui *Gui) handleCreatePatchOptionsMenu() error {
return gui.c.ErrorMsg(gui.c.Tr.NoPatchError)
}
menuItems := []*popup.MenuItem{
menuItems := []*types.MenuItem{
{
DisplayString: "reset patch",
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 {
menuItems = append(menuItems, []*popup.MenuItem{
menuItems = append(menuItems, []*types.MenuItem{
{
DisplayString: fmt.Sprintf("remove patch from original commit (%s)", gui.git.Patch.PatchManager.To),
OnPress: gui.handleDeletePatchFromCommit,
@ -51,7 +50,7 @@ func (gui *Gui) handleCreatePatchOptionsMenu() error {
menuItems = append(
menuItems[:1],
append(
[]*popup.MenuItem{
[]*types.MenuItem{
{
DisplayString: fmt.Sprintf("move patch to selected commit (%s)", selectedCommit.Sha),
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 {
@ -142,7 +141,7 @@ func (gui *Gui) handleMovePatchIntoWorkingTree() error {
}
if gui.workingTreeHelper.IsWorkingTreeDirty() {
return gui.c.Ask(popup.AskOpts{
return gui.c.Ask(types.AskOpts{
Title: gui.c.Tr.MustStashTitle,
Prompt: gui.c.Tr.MustStashWarning,
HandleConfirm: func() error {

View File

@ -11,83 +11,27 @@ import (
"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 {
*common.Common
index int
sync.Mutex
createPopupPanelFn func(CreatePopupPanelOpts) error
createPopupPanelFn func(types.CreatePopupPanelOpts) error
onErrorFn func() error
closePopupFn func() error
createMenuFn func(CreateMenuOptions) error
createMenuFn func(types.CreateMenuOptions) error
withWaitingStatusFn func(message string, f func() error) error
toastFn func(message string)
getPromptInputFn func() string
}
var _ IPopupHandler = &RealPopupHandler{}
var _ types.IPopupHandler = &RealPopupHandler{}
func NewPopupHandler(
common *common.Common,
createPopupPanelFn func(CreatePopupPanelOpts) error,
createPopupPanelFn func(types.CreatePopupPanelOpts) error,
onErrorFn func() error,
closePopupFn func() error,
createMenuFn func(CreateMenuOptions) error,
createMenuFn func(types.CreateMenuOptions) error,
withWaitingStatusFn func(message string, f func() error) error,
toastFn func(message 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)
}
@ -135,18 +79,18 @@ func (self *RealPopupHandler) ErrorMsg(message string) error {
return err
}
return self.Ask(AskOpts{
return self.Ask(types.AskOpts{
Title: self.Tr.Error,
Prompt: coloredMessage,
})
}
func (self *RealPopupHandler) Ask(opts AskOpts) error {
func (self *RealPopupHandler) Ask(opts types.AskOpts) error {
self.Lock()
self.index++
self.Unlock()
return self.createPopupPanelFn(CreatePopupPanelOpts{
return self.createPopupPanelFn(types.CreatePopupPanelOpts{
Title: opts.Title,
Prompt: opts.Prompt,
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.index++
self.Unlock()
return self.createPopupPanelFn(CreatePopupPanelOpts{
return self.createPopupPanelFn(types.CreatePopupPanelOpts{
Title: opts.Title,
Prompt: opts.InitialContent,
Editable: true,
@ -176,7 +120,7 @@ func (self *RealPopupHandler) WithLoaderPanel(message string, f func() error) er
index = self.index
self.Unlock()
err := self.createPopupPanelFn(CreatePopupPanelOpts{
err := self.createPopupPanelFn(types.CreatePopupPanelOpts{
Prompt: message,
HasLoader: true,
})
@ -208,11 +152,11 @@ func (self *RealPopupHandler) GetPromptInput() string {
type TestPopupHandler struct {
OnErrorMsg func(message string) error
OnAsk func(opts AskOpts) error
OnPrompt func(opts PromptOpts) error
OnAsk func(opts types.AskOpts) error
OnPrompt func(opts types.PromptOpts) error
}
var _ IPopupHandler = &TestPopupHandler{}
var _ types.IPopupHandler = &TestPopupHandler{}
func (self *TestPopupHandler) Error(err error) error {
return self.ErrorMsg(err.Error())
@ -222,11 +166,11 @@ func (self *TestPopupHandler) ErrorMsg(message string) error {
return self.OnErrorMsg(message)
}
func (self *TestPopupHandler) Ask(opts AskOpts) error {
func (self *TestPopupHandler) Ask(opts types.AskOpts) error {
return self.OnAsk(opts)
}
func (self *TestPopupHandler) Prompt(opts PromptOpts) error {
func (self *TestPopupHandler) Prompt(opts types.PromptOpts) error {
return self.OnPrompt(opts)
}
@ -238,7 +182,7 @@ func (self *TestPopupHandler) WithWaitingStatus(message string, f func() error)
return f()
}
func (self *TestPopupHandler) Menu(opts CreateMenuOptions) error {
func (self *TestPopupHandler) Menu(opts types.CreateMenuOptions) error {
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/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 {
menuItems := make([]*popup.MenuItem, 0, 4)
menuItems := make([]*types.MenuItem, 0, 4)
fromToDisplayStrings := func(from string, to string) []string {
return []string{fmt.Sprintf("%s → %s", from, to)}
}
menuItemsForBranch := func(branch *models.Branch) []*popup.MenuItem {
return []*popup.MenuItem{
menuItemsForBranch := func(branch *models.Branch) []*types.MenuItem {
return []*types.MenuItem{
{
DisplayStrings: fromToDisplayStrings(branch.Name, gui.c.Tr.LcDefaultBranch),
OnPress: func() error {
@ -26,7 +26,7 @@ func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutB
{
DisplayStrings: fromToDisplayStrings(branch.Name, gui.c.Tr.LcSelectBranch),
OnPress: func() error {
return gui.c.Prompt(popup.PromptOpts{
return gui.c.Prompt(types.PromptOpts{
Title: branch.Name + " →",
FindSuggestionsFunc: gui.suggestionsHelper.GetBranchNameSuggestionsFunc(),
HandleConfirm: func(targetBranchName string) error {
@ -40,7 +40,7 @@ func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutB
if selectedBranch != checkedOutBranch {
menuItems = append(menuItems,
&popup.MenuItem{
&types.MenuItem{
DisplayStrings: fromToDisplayStrings(checkedOutBranch.Name, selectedBranch.Name),
OnPress: func() error {
return gui.createPullRequest(checkedOutBranch.Name, selectedBranch.Name)
@ -52,7 +52,7 @@ func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutB
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 {

View File

@ -4,7 +4,7 @@ import (
"os"
"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
@ -73,7 +73,7 @@ func (gui *Gui) quit() error {
}
if gui.c.UserConfig.ConfirmOnQuit {
return gui.c.Ask(popup.AskOpts{
return gui.c.Ask(types.AskOpts{
Title: "",
Prompt: gui.c.Tr.ConfirmQuit,
HandleConfirm: func() error {

View File

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

View File

@ -7,8 +7,8 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/git_config"
"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/types"
"github.com/jesseduffield/lazygit/pkg/utils"
)
@ -17,10 +17,10 @@ func (gui *Gui) handleCreateRecentReposMenu() error {
reposCount := utils.Min(len(recentRepoPaths), 20)
// 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] {
path := path // cos we're closing over the loop variable
menuItems[i] = &popup.MenuItem{
menuItems[i] = &types.MenuItem{
DisplayStrings: []string{
filepath.Base(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 {

View File

@ -7,20 +7,19 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"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/types"
)
type RefHelper struct {
c *controllers.ControllerCommon
c *types.ControllerCommon
git *commands.GitCommand
getState func() *GuiRepoState
}
func NewRefHelper(
c *controllers.ControllerCommon,
c *types.ControllerCommon,
git *commands.GitCommand,
getState func() *GuiRepoState,
) *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") {
// offer to autostash changes
return self.c.Ask(popup.AskOpts{
return self.c.Ask(types.AskOpts{
Title: self.c.Tr.AutoStashTitle,
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 {
strengths := []string{"soft", "mixed", "hard"}
menuItems := make([]*popup.MenuItem, len(strengths))
menuItems := make([]*types.MenuItem, len(strengths))
for i, strength := range strengths {
strength := strength
menuItems[i] = &popup.MenuItem{
menuItems[i] = &types.MenuItem{
DisplayStrings: []string{
fmt.Sprintf("%s reset", strength),
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),
Items: menuItems,
})

View File

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

View File

@ -4,7 +4,6 @@ import (
"fmt"
"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/utils"
)
@ -54,7 +53,7 @@ func (gui *Gui) handleDeleteRemoteBranch() error {
}
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,
Prompt: message,
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,
Prompt: message,
HandleConfirm: func() error {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,21 +1,8 @@
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 {
var task updateTask
tag := self.getSelectedTag()
tag := self.State.Contexts.Tags.GetSelectedTag()
if tag == nil {
task = NewRenderStringTask("No tags")
} 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 {
tags, err := self.git.Loaders.Tags.GetTags()
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
)
type Context interface {
HandleFocus(opts ...OnFocusOpts) error
HandleFocusLost() error
HandleRender() error
HandleRenderToMain() error
type ParentContexter interface {
SetParentContext(Context)
// we return a bool here to tell us whether or not the returned value just wraps a nil
GetParentContext() (Context, bool)
}
type IBaseContext interface {
ParentContexter
GetKind() ContextKind
GetViewName() string
GetWindowName() string
SetWindowName(string)
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
}
type Context interface {
IBaseContext
HandleFocus(opts ...OnFocusOpts) error
HandleFocusLost() error
HandleRender() error
HandleRenderToMain() error
}
type OnFocusOpts struct {
ClickedViewName string
ClickedViewLineIdx int

View File

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

View File

@ -254,8 +254,9 @@ func (gui *Gui) renderDisplayStrings(v *gocui.View, displayStrings [][]string) {
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)
_, y := v.Origin()
v.OverwriteLines(y, list)
}

View File

@ -3,7 +3,6 @@ package gui
import (
"fmt"
"github.com/jesseduffield/lazygit/pkg/gui/popup"
"github.com/jesseduffield/lazygit/pkg/gui/style"
"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)
}
menuItems := []*popup.MenuItem{
menuItems := []*types.MenuItem{
{
DisplayStrings: []string{
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})
}