summaryrefslogtreecommitdiffstats
path: root/pkg/gui
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2020-11-28 13:14:48 +1100
committerJesse Duffield <jessedduffield@gmail.com>2020-11-28 20:48:17 +1100
commitda3b0bf7c8aa6202d5eb9c8178f6648bc695336a (patch)
treecd0666ae4253469f8f2f1e349357be37bfb3d571 /pkg/gui
parent90ade3225f55652d40c6f0266e50f5328390f02b (diff)
Start on supporting auto-suggestions when checking out a branch
switch to other fuzzy package with no dependencies
Diffstat (limited to 'pkg/gui')
-rw-r--r--pkg/gui/branches_panel.go7
-rw-r--r--pkg/gui/commit_files_panel.go6
-rw-r--r--pkg/gui/commit_message_panel.go40
-rw-r--r--pkg/gui/confirmation_panel.go104
-rw-r--r--pkg/gui/context.go32
-rw-r--r--pkg/gui/credentials_panel.go2
-rw-r--r--pkg/gui/editors.go93
-rw-r--r--pkg/gui/files_panel.go6
-rw-r--r--pkg/gui/gui.go8
-rw-r--r--pkg/gui/layout.go4
-rw-r--r--pkg/gui/list_context.go20
-rw-r--r--pkg/gui/menu_panel.go2
-rw-r--r--pkg/gui/merge_panel.go6
-rw-r--r--pkg/gui/patch_building_panel.go2
-rw-r--r--pkg/gui/patch_options_panel.go2
-rw-r--r--pkg/gui/presentation/suggestions.go15
-rw-r--r--pkg/gui/quitting.go2
-rw-r--r--pkg/gui/rebase_options_panel.go2
-rw-r--r--pkg/gui/remote_branches_panel.go2
-rw-r--r--pkg/gui/remotes_panel.go2
-rw-r--r--pkg/gui/reset_menu_panel.go2
-rw-r--r--pkg/gui/searching.go2
-rw-r--r--pkg/gui/side_window.go6
-rw-r--r--pkg/gui/staging_panel.go6
-rw-r--r--pkg/gui/status_panel.go2
-rw-r--r--pkg/gui/sub_commits_panel.go2
-rw-r--r--pkg/gui/suggestions_panel.go22
-rw-r--r--pkg/gui/tags_panel.go2
-rw-r--r--pkg/gui/view_helpers.go7
29 files changed, 303 insertions, 105 deletions
diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go
index 48e322025..523ecd0c2 100644
--- a/pkg/gui/branches_panel.go
+++ b/pkg/gui/branches_panel.go
@@ -212,7 +212,6 @@ func (gui *Gui) handleCheckoutByName(g *gocui.Gui, v *gocui.View) error {
onRefNotFound: func(ref string) error {
return gui.ask(askOpts{
-
title: gui.Tr.BranchNotFoundTitle,
prompt: fmt.Sprintf("%s %s%s", gui.Tr.BranchNotFoundPrompt, ref, "?"),
handleConfirm: func() error {
@@ -278,7 +277,6 @@ func (gui *Gui) deleteNamedBranch(selectedBranch *models.Branch, force bool) err
)
return gui.ask(askOpts{
-
title: title,
prompt: message,
handleConfirm: func() error {
@@ -315,7 +313,6 @@ func (gui *Gui) mergeBranchIntoCheckedOutBranch(branchName string) error {
)
return gui.ask(askOpts{
-
title: gui.Tr.MergingTitle,
prompt: prompt,
handleConfirm: func() error {
@@ -357,7 +354,6 @@ func (gui *Gui) handleRebaseOntoBranch(selectedBranchName string) error {
)
return gui.ask(askOpts{
-
title: gui.Tr.RebasingTitle,
prompt: prompt,
handleConfirm: func() error {
@@ -454,7 +450,6 @@ func (gui *Gui) handleRenameBranch(g *gocui.Gui, v *gocui.View) error {
}
return gui.ask(askOpts{
-
title: gui.Tr.LcRenameBranch,
prompt: gui.Tr.RenameBranchWarning,
handleConfirm: promptForNewName,
@@ -500,7 +495,7 @@ func (gui *Gui) handleNewBranchOffCurrentItem() error {
}
if context.GetKey() != gui.Contexts.Branches.Context.GetKey() {
- if err := gui.switchContext(gui.Contexts.Branches.Context); err != nil {
+ if err := gui.pushContext(gui.Contexts.Branches.Context); err != nil {
return err
}
}
diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go
index c560e667b..98a8d98a9 100644
--- a/pkg/gui/commit_files_panel.go
+++ b/pkg/gui/commit_files_panel.go
@@ -176,7 +176,7 @@ func (gui *Gui) enterCommitFile(selectedLineIdx int) error {
}
}
- if err := gui.switchContext(gui.Contexts.PatchBuilding.Context); err != nil {
+ if err := gui.pushContext(gui.Contexts.PatchBuilding.Context); err != nil {
return err
}
return gui.handleRefreshPatchBuildingPanel(selectedLineIdx)
@@ -192,7 +192,7 @@ func (gui *Gui) enterCommitFile(selectedLineIdx int) error {
return enterTheFile(selectedLineIdx)
},
handleClose: func() error {
- return gui.switchContext(gui.Contexts.CommitFiles.Context)
+ return gui.pushContext(gui.Contexts.CommitFiles.Context)
},
})
}
@@ -215,5 +215,5 @@ func (gui *Gui) switchToCommitFilesContext(refName string, canRebase bool, conte
return err
}
- return gui.switchContext(gui.Contexts.CommitFiles.Context)
+ return gui.pushContext(gui.Contexts.CommitFiles.Context)
}
diff --git a/pkg/gui/commit_message_panel.go b/pkg/gui/commit_message_panel.go
index 333882467..1cdd51770 100644
--- a/pkg/gui/commit_message_panel.go
+++ b/pkg/gui/commit_message_panel.go
@@ -79,43 +79,3 @@ func (gui *Gui) RenderCommitLength() {
v := gui.getCommitMessageView()
v.Subtitle = gui.getBufferLength(v)
}
-
-// we've just copy+pasted the editor from gocui to here so that we can also re-
-// render the commit message length on each keypress
-func (gui *Gui) commitMessageEditor(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
- newlineKey, ok := gui.getKey(gui.Config.GetUserConfig().Keybinding.Universal.AppendNewline).(gocui.Key)
- if !ok {
- newlineKey = gocui.KeyTab
- }
-
- switch {
- case key == gocui.KeyBackspace || key == gocui.KeyBackspace2:
- v.EditDelete(true)
- case key == gocui.KeyDelete:
- v.EditDelete(false)
- case key == gocui.KeyArrowDown:
- v.MoveCursor(0, 1, false)
- case key == gocui.KeyArrowUp:
- v.MoveCursor(0, -1, false)
- case key == gocui.KeyArrowLeft:
- v.MoveCursor(-1, 0, false)
- case key == gocui.KeyArrowRight:
- v.MoveCursor(1, 0, false)
- case key == newlineKey:
- v.EditNewLine()
- case key == gocui.KeySpace:
- v.EditWrite(' ')
- case key == gocui.KeyInsert:
- v.Overwrite = !v.Overwrite
- case key == gocui.KeyCtrlU:
- v.EditDeleteToStartOfLine()
- case key == gocui.KeyCtrlA:
- v.EditGotoToStartOfLine()
- case key == gocui.KeyCtrlE:
- v.EditGotoToEndOfLine()
- default:
- v.EditWrite(ch)
- }
-
- gui.RenderCommitLength()
-}
diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go
index fbea691ad..dfea11c05 100644
--- a/pkg/gui/confirmation_panel.go
+++ b/pkg/gui/confirmation_panel.go
@@ -27,14 +27,17 @@ type createPopupPanelOpts struct {
// 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
+
+ showSuggestionsPanel bool
}
type askOpts struct {
- title string
- prompt string
- handleConfirm func() error
- handleClose func() error
- handlersManageFocus bool
+ title string
+ prompt string
+ handleConfirm func() error
+ handleClose func() error
+ handlersManageFocus bool
+ showSuggestionsPanel bool
}
func (gui *Gui) createLoaderPanel(prompt string) error {
@@ -46,20 +49,22 @@ func (gui *Gui) createLoaderPanel(prompt string) error {
func (gui *Gui) ask(opts askOpts) error {
return gui.createPopupPanel(createPopupPanelOpts{
- title: opts.title,
- prompt: opts.prompt,
- handleConfirm: opts.handleConfirm,
- handleClose: opts.handleClose,
- handlersManageFocus: opts.handlersManageFocus,
+ title: opts.title,
+ prompt: opts.prompt,
+ handleConfirm: opts.handleConfirm,
+ handleClose: opts.handleClose,
+ handlersManageFocus: opts.handlersManageFocus,
+ showSuggestionsPanel: opts.showSuggestionsPanel,
})
}
func (gui *Gui) prompt(title string, initialContent string, handleConfirm func(string) error) error {
return gui.createPopupPanel(createPopupPanelOpts{
- title: title,
- prompt: initialContent,
- editable: true,
- handleConfirmPrompt: handleConfirm,
+ title: title,
+ prompt: initialContent,
+ editable: true,
+ handleConfirmPrompt: handleConfirm,
+ showSuggestionsPanel: true,
})
}
@@ -79,10 +84,10 @@ func (gui *Gui) wrappedConfirmationFunction(handlersManageFocus bool, function f
}
}
-func (gui *Gui) wrappedPromptConfirmationFunction(handlersManageFocus bool, function func(string) error) func(*gocui.Gui, *gocui.View) error {
- return func(g *gocui.Gui, v *gocui.View) error {
+func (gui *Gui) wrappedPromptConfirmationFunction(handlersManageFocus bool, function func(string) error, getResponse func() string) func(*gocui.Gui, *gocui.View) error {
+ return gui.wrappedHandler(func() error {
if function != nil {
- if err := function(v.Buffer()); err != nil {
+ if err := function(getResponse()); err != nil {
return gui.surfaceError(err)
}
}
@@ -92,7 +97,7 @@ func (gui *Gui) wrappedPromptConfirmationFunction(handlersManageFocus bool, func
}
return nil
- }
+ })
}
func (gui *Gui) deleteConfirmationView() {
@@ -104,6 +109,15 @@ func (gui *Gui) deleteConfirmationView() {
_ = gui.g.DeleteView("confirmation")
}
+func (gui *Gui) deleteSuggestionsView() {
+ keybindingConfig := gui.Config.GetUserConfig().Keybinding
+ _ = gui.g.DeleteKeybinding("suggestions", gui.getKey(keybindingConfig.Universal.Confirm), gocui.ModNone)
+ _ = gui.g.DeleteKeybinding("suggestions", gui.getKey(keybindingConfig.Universal.ConfirmAlt1), gocui.ModNone)
+ _ = gui.g.DeleteKeybinding("suggestions", gui.getKey(keybindingConfig.Universal.Return), gocui.ModNone)
+
+ _ = gui.g.DeleteView("suggestions")
+}
+
func (gui *Gui) closeConfirmationPrompt(handlersManageFocus bool) error {
view := gui.getConfirmationView()
if view == nil {
@@ -117,6 +131,9 @@ func (gui *Gui) closeConfirmationPrompt(handlersManageFocus bool) error {
}
gui.deleteConfirmationView()
+
+ _, _ = gui.g.SetViewOnBottom("suggestions")
+
return nil
}
@@ -156,7 +173,7 @@ func (gui *Gui) getConfirmationPanelDimensions(wrap bool, prompt string) (int, i
height/2 + panelHeight/2
}
-func (gui *Gui) prepareConfirmationPanel(title, prompt string, hasLoader bool) (*gocui.View, error) {
+func (gui *Gui) prepareConfirmationPanel(title, prompt string, hasLoader bool, showSuggestionsPanel bool) (*gocui.View, error) {
x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(true, prompt)
confirmationView, err := gui.g.SetView("confirmation", x0, y0, x1, y1, 0)
if err != nil {
@@ -171,8 +188,23 @@ func (gui *Gui) prepareConfirmationPanel(title, prompt string, hasLoader bool) (
confirmationView.Wrap = true
confirmationView.FgColor = theme.GocuiDefaultTextColor
}
+
+ if showSuggestionsPanel {
+ suggestionsViewHeight := 11
+ suggestionsView, err := gui.g.SetView("suggestions", x0, y1, x1, y1+suggestionsViewHeight, 0)
+ if err != nil {
+ if err.Error() != UNKNOWN_VIEW_ERROR_MSG {
+ return nil, err
+ }
+ suggestionsView.Wrap = true
+ suggestionsView.FgColor = theme.GocuiDefaultTextColor
+ }
+ gui.setSuggestions([]string{})
+ _, _ = gui.g.SetViewOnTop("suggestions")
+ }
+
gui.g.Update(func(g *gocui.Gui) error {
- return gui.switchContext(gui.Contexts.Confirmation.Context)
+ return gui.pushContext(gui.Contexts.Confirmation.Context)
})
return confirmationView, nil
}
@@ -183,11 +215,12 @@ func (gui *Gui) createPopupPanel(opts createPopupPanelOpts) error {
if view, _ := g.View("confirmation"); view != nil {
gui.deleteConfirmationView()
}
- confirmationView, err := gui.prepareConfirmationPanel(opts.title, opts.prompt, opts.hasLoader)
+ confirmationView, err := gui.prepareConfirmationPanel(opts.title, opts.prompt, opts.hasLoader, opts.showSuggestionsPanel)
if err != nil {
return err
}
confirmationView.Editable = opts.editable
+ confirmationView.Editor = gocui.EditorFunc(gui.editorWithCallback)
if opts.editable {
go utils.Safe(func() {
// TODO: remove this wait (right now if you remove it the EditGotoToEndOfLine method doesn't seem to work)
@@ -200,6 +233,7 @@ func (gui *Gui) createPopupPanel(opts createPopupPanelOpts) error {
}
gui.renderString("confirmation", opts.prompt)
+
return gui.setKeyBindings(opts)
})
return nil
@@ -217,7 +251,7 @@ func (gui *Gui) setKeyBindings(opts createPopupPanelOpts) error {
gui.renderString("options", actions)
var onConfirm func(*gocui.Gui, *gocui.View) error
if opts.handleConfirmPrompt != nil {
- onConfirm = gui.wrappedPromptConfirmationFunction(opts.handlersManageFocus, opts.handleConfirmPrompt)
+ onConfirm = gui.wrappedPromptConfirmationFunction(opts.handlersManageFocus, opts.handleConfirmPrompt, func() string { return gui.getConfirmationView().Buffer() })
} else {
onConfirm = gui.wrappedConfirmationFunction(opts.handlersManageFocus, opts.handleConfirm)
}
@@ -230,7 +264,31 @@ func (gui *Gui) setKeyBindings(opts createPopupPanelOpts) error {
return err
}
- return gui.g.SetKeybinding("confirmation", nil, gui.getKey(keybindingConfig.Universal.Return), gocui.ModNone, gui.wrappedConfirmationFunction(opts.handlersManageFocus, opts.handleClose))
+ if err := gui.g.SetKeybinding("confirmation", nil, gui.getKey(keybindingConfig.Universal.Return), gocui.ModNone, gui.wrappedConfirmationFunction(opts.handlersManageFocus, opts.handleClose)); err != nil {
+ return err
+ }
+
+ if err := gui.g.SetKeybinding("confirmation", nil, gui.getKey(keybindingConfig.Universal.TogglePanel), gocui.ModNone, gui.wrappedHandler(func() error { return gui.replaceContext(gui.Contexts.Suggestions.Context) })); err != nil {
+ return err
+ }
+
+ onSuggestionConfirm := gui.wrappedPromptConfirmationFunction(opts.handlersManageFocus, opts.handleConfirmPrompt, func() string { return gui.getSelectedSuggestion() })
+ if err := gui.g.SetKeybinding("suggestions", nil, gui.getKey(keybindingConfig.Universal.Confirm), gocui.ModNone, onSuggestionConfirm); err != nil {
+ return err
+ }
+ if err := gui.g.SetKeybinding("suggestions", nil, gui.getKey(keybindingConfig.Universal.ConfirmAlt1), gocui.ModNone, onSuggestionConfirm); err != nil {
+ return err
+ }
+
+ if err := gui.g.SetKeybinding("suggestions", nil, gui.getKey(keybindingConfig.Universal.Return), gocui.ModNone, gui.wrappedConfirmationFunction(opts.handlersManageFocus, opts.handleClose)); err != nil {
+ return err
+ }
+
+ if err := gui.g.SetKeybinding("suggestions", nil, gui.getKey(keybindingConfig.Universal.TogglePanel), gocui.ModNone, gui.wrappedHandler(func() error { return gui.replaceContext(gui.Contexts.Confirmation.Context) })); err != nil {
+ return err
+ }
+
+ return nil
}
func (gui *Gui) createErrorPanel(message string) error {
diff --git a/pkg/gui/context.go b/pkg/gui/context.go
index 3784bb1d5..c28fc9efc 100644
--- a/pkg/gui/context.go
+++ b/pkg/gui/context.go
@@ -35,6 +35,7 @@ const (
SEARCH_CONTEXT_KEY = "search"
COMMIT_MESSAGE_CONTEXT_KEY = "commitMessage"
SUBMODULES_CONTEXT_KEY = "submodules"
+ SUGGESTIONS_CONTEXT_KEY = "suggestions"
)
var allContextKeys = []string{
@@ -59,6 +60,7 @@ var allContextKeys = []string{
SEARCH_CONTEXT_KEY,
COMMIT_MESSAGE_CONTEXT_KEY,
SUBMODULES_CONTEXT_KEY,
+ SUGGESTIONS_CONTEXT_KEY,
}
type SimpleContextNode struct {
@@ -91,6 +93,7 @@ type ContextTree struct {
Confirmation SimpleContextNode
CommitMessage SimpleContextNode
Search SimpleContextNode
+ Suggestions SimpleContextNode
}
func (gui *Gui) allContexts() []Context {
@@ -115,6 +118,7 @@ func (gui *Gui) allContexts() []Context {
gui.Contexts.Merging.Context,
gui.Contexts.PatchBuilding.Context,
gui.Contexts.SubCommits.Context,
+ gui.Contexts.Suggestions.Context,
}
}
@@ -303,6 +307,9 @@ func (gui *Gui) contextTree() ContextTree {
Key: CONFIRMATION_CONTEXT_KEY,
},
},
+ Suggestions: SimpleContextNode{
+ Context: gui.suggestionsListContext(),
+ },
CommitMessage: SimpleContextNode{
Context: BasicContext{
OnFocus: gui.handleCommitMessageFocused,
@@ -400,7 +407,24 @@ func (gui *Gui) currentContextKeyIgnoringPopups() string {
return ""
}
-func (gui *Gui) switchContext(c Context) error {
+// use replaceContext when you don't want to return to the original context upon
+// hitting escape: you want to go that context's parent instead.
+func (gui *Gui) replaceContext(c Context) error {
+ gui.g.Update(func(*gocui.Gui) error {
+ if len(gui.State.ContextStack) == 0 {
+ gui.State.ContextStack = []Context{c}
+ } else {
+ // replace the last item with the given item
+ gui.State.ContextStack = append(gui.State.ContextStack[0:len(gui.State.ContextStack)-1], c)
+ }
+
+ return gui.activateContext(c)
+ })
+
+ return nil
+}
+
+func (gui *Gui) pushContext(c Context) error {
gui.g.Update(func(*gocui.Gui) error {
// push onto stack
// if we are switching to a side context, remove all other contexts in the stack
@@ -424,11 +448,11 @@ func (gui *Gui) switchContext(c Context) error {
return nil
}
-// switchContextToView is to be used when you don't know which context you
+// pushContextWithView is to be used when you don't know which context you
// want to switch to: you only know the view that you want to switch to. It will
// look up the context currently active for that view and switch to that context
-func (gui *Gui) switchContextToView(viewName string) error {
- return gui.switchContext(gui.State.ViewContextMap[viewName])
+func (gui *Gui) pushContextWithView(viewName string) error {
+ return gui.pushContext(gui.State.ViewContextMap[viewName])
}
func (gui *Gui) returnFromContext() error {
diff --git a/pkg/gui/credentials_panel.go b/pkg/gui/credentials_panel.go
index 53166aa76..fe97dc9aa 100644
--- a/pkg/gui/credentials_panel.go
+++ b/pkg/gui/credentials_panel.go
@@ -26,7 +26,7 @@ func (gui *Gui) promptUserForCredential(passOrUname string) string {
credentialsView.Mask = '*'
}
- if err := gui.switchContext(gui.Contexts.Credentials.Context); err != nil {
+ if err := gui.pushContext(gui.Contexts.Credentials.Context); err != nil {
return err
}
diff --git a/pkg/gui/editors.go b/pkg/gui/editors.go
new file mode 100644
index 000000000..baffd19a3
--- /dev/null
+++ b/pkg/gui/editors.go
@@ -0,0 +1,93 @@
+package gui
+
+import (
+ "github.com/jesseduffield/gocui"
+ "github.com/jesseduffield/lazygit/pkg/utils"
+)
+
+// we've just copy+pasted the editor from gocui to here so that we can also re-
+// render the commit message length on each keypress
+func (gui *Gui) commitMessageEditor(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
+ newlineKey, ok := gui.getKey(gui.Config.GetUserConfig().Keybinding.Universal.AppendNewline).(gocui.Key)
+ if !ok {
+ newlineKey = gocui.KeyTab
+ }
+
+ switch {
+ case key == gocui.KeyBackspace || key == gocui.KeyBackspace2:
+ v.EditDelete(true)
+ case key == gocui.KeyDelete:
+ v.EditDelete(false)
+ case key == gocui.KeyArrowDown:
+ v.MoveCursor(0, 1, false)
+ case key == gocui.KeyArrowUp:
+ v.MoveCursor(0, -1, false)
+ case key == gocui.KeyArrowLeft:
+ v.MoveCursor(-1, 0, false)
+ case key == gocui.KeyArrowRight:
+ v.MoveCursor(1, 0, false)
+ case key == newlineKey:
+ v.EditNewLine()
+ case key == gocui.KeySpace:
+ v.EditWrite(' ')
+ case key == gocui.KeyInsert:
+ v.Overwrite = !v.Overwrite
+ case key == gocui.KeyCtrlU:
+ v.EditDeleteToStartOfLine()
+ case key == gocui.KeyCtrlA:
+ v.EditGotoToStartOfLine()
+ case key == gocui.KeyCtrlE:
+ v.EditGotoToEndOfLine()
+ default:
+ v.EditWrite(ch)
+ }
+
+ gui.RenderCommitLength()
+}
+
+// we've just copy+pasted the editor from gocui to here so that we can also re-
+// render the commit message length on each keypress
+func (gui *Gui) editorWithCallback(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
+ switch {
+ case key == gocui.KeyBackspace || key == gocui.KeyBackspace2:
+ v.EditDelete(true)
+ case key == gocui.KeyDelete:
+ v.EditDelete(false)
+ case key == gocui.KeyArrowDown:
+ v.MoveCursor(0, 1, false)
+ case key == gocui.KeyArrowUp:
+ v.MoveCursor(0, -1, false)
+ case key == gocui.KeyArrowLeft:
+ v.MoveCursor(-1, 0, false)
+ case key == gocui.KeyArrowRight:
+ v.MoveCursor(1, 0, false)
+ case key == gocui.KeySpace:
+ v.EditWrite(' ')
+ case key == gocui.KeyInsert:
+ v.Overwrite = !v.Overwrite
+ case key == gocui.KeyCtrlU:
+ v.EditDeleteToStartOfLine()
+ case key == gocui.KeyCtrlA:
+ v.EditGotoToStartOfLine()
+ case key == gocui.KeyCtrlE:
+ v.EditGotoToEndOfLine()
+ default:
+ v.EditWrite(ch)
+ }
+
+ input := v.Buffer()
+ branchNames := gui.getBranchNames()
+
+ suggestions := utils.FuzzySearch(input, branchNames)
+ gui.setSuggestions(suggestions)
+}
+
+func (gui *Gui) getBranchNames() []string {
+ result := make([]string, len(gui.State.Branches))
+
+ for i, branch := range gui.State.Branches {
+ result[i] = branch.Name
+ }
+
+ return result
+}
diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go
index 1d17b7771..665a403cf 100644
--- a/pkg/gui/files_panel.go
+++ b/pkg/gui/files_panel.go
@@ -183,7 +183,7 @@ func (gui *Gui) enterFile(forceSecondaryFocused bool, selectedLineIdx int) error
if file.HasMergeConflicts {
return gui.createErrorPanel(gui.Tr.FileStagingRequirements)
}
- _ = gui.switchContext(gui.Contexts.Staging.Context)
+ _ = gui.pushContext(gui.Contexts.Staging.Context)
return gui.handleRefreshStagingPanel(forceSecondaryFocused, selectedLineIdx) // TODO: check if this is broken, try moving into context code
}
@@ -341,7 +341,7 @@ func (gui *Gui) handleCommitPress() error {
}
gui.g.Update(func(g *gocui.Gui) error {
- if err := gui.switchContext(gui.Contexts.CommitMessage.Context); err != nil {
+ if err := gui.pushContext(gui.Contexts.CommitMessage.Context); err != nil {
return err
}
@@ -642,7 +642,7 @@ func (gui *Gui) handleSwitchToMerge() error {
return gui.createErrorPanel(gui.Tr.FileNoMergeCons)
}
- return gui.switchContext(gui.Contexts.Merging.Context)
+ return gui.pushContext(gui.Contexts.Merging.Context)
}
func (gui *Gui) openFile(filename string) error {
diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go
index a1dbd909c..a90770ca9 100644
--- a/pkg/gui/gui.go
+++ b/pkg/gui/gui.go
@@ -220,6 +220,10 @@ type submodulePanelState struct {
listPanelState
}
+type suggestionsPanelState struct {
+ listPanelState
+}
+
type panelStates struct {
Files *filePanelState
Branches *branchPanelState
@@ -235,6 +239,7 @@ type panelStates struct {
Merging *mergingPanelState
CommitFiles *commitFilesPanelState
Submodules *submodulePanelState
+ Suggestions *suggestionsPanelState
}
type searchingState struct {
@@ -299,6 +304,8 @@ type guiState struct {
Commits []*models.Commit
StashEntries []*models.StashEntry
CommitFiles []*models.CommitFile
+ // Suggestions will sometimes appear when typing into a prompt
+ Suggestions []string
// FilteredReflogCommits are the ones that appear in the reflog panel.
// when in filtering mode we only include the ones that match the given path
FilteredReflogCommits []*models.Commit
@@ -385,6 +392,7 @@ func (gui *Gui) resetState() {
CommitFiles: &commitFilesPanelState{listPanelState: listPanelState{SelectedLineIdx: -1}, refName: ""},
Stash: &stashPanelState{listPanelState{SelectedLineIdx: -1}},
Menu: &menuPanelState{listPanelState: listPanelState{SelectedLineIdx: 0}, OnPress: nil},
+ Suggestions: &suggestionsPanelState{listPanelState: listPanelState{SelectedLineIdx: 0}},
Merging: &mergingPanelState{
ConflictIndex: 0,
ConflictTop: true,
diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go
index 7f2a04315..2594cb9ad 100644
--- a/pkg/gui/layout.go
+++ b/pkg/gui/layout.go
@@ -277,7 +277,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
initialContext = gui.Contexts.BranchCommits.Context
}
- if err := gui.switchContext(initialContext); err != nil {
+ if err := gui.pushContext(initialContext); err != nil {
return err
}
}
@@ -351,7 +351,7 @@ func (gui *Gui) onInitialViewsCreation() error {
}
gui.g.Mutexes.ViewsMutex.Unlock()
- if err := gui.switchContext(gui.defaultSideContext()); err != nil {
+ if err := gui.pushContext(gui.defaultSideContext()); err != nil {
return err
}
diff --git a/pkg/gui/list_context.go b/pkg/gui/list_context.go
index 86271b065..908f35f7b 100644
--- a/pkg/gui/list_context.go
+++ b/pkg/gui/list_context.go
@@ -219,7 +219,7 @@ func (lc *ListContext) handleClick(g *gocui.Gui, v *gocui.View) error {
newSelectedLineIdx := v.SelectedLineIdx()
// we need to focus the view
- if err := lc.Gui.switchContext(lc); err != nil {
+ if err := lc.Gui.pushContext(lc); err != nil {
return err
}
@@ -483,6 +483,23 @@ func (gui *Gui) submodulesListContext() *ListContext {
}
}
+func (gui *Gui) suggestionsListContext() *ListContext {
+ return &ListContext{
+ ViewName: "suggestions",
+ WindowName: "suggestions",
+ ContextKey: SUGGESTIONS_CONTEXT_KEY,
+ GetItemsLength: func() int { return len(gui.State.Suggestions) },
+ GetPanelState: func() IListPanelState { return gui.State.Panels.Suggestions },
+ OnFocus: func() error { return nil },
+ Gui: gui,
+ ResetMainViewOriginOnFocus: false,
+ Kind: PERSISTENT_POPUP,
+ GetDisplayStrings: func() [][]string {
+ return presentation.GetSuggestionListDisplayStrings(gui.State.Suggestions)
+ },
+ }
+}
+
func (gui *Gui) getListContexts() []*ListContext {
return []*ListContext{
gui.menuListContext(),
@@ -497,6 +514,7 @@ func (gui *Gui) getListContexts() []*ListContext {
gui.stashListContext(),
gui.commitFilesListContext(),
gui.submodulesListContext(),
+ gui.suggestionsListContext(),
}
}
diff --git a/pkg/gui/menu_panel.go b/pkg/gui/menu_panel.go
index 791529ba3..e7839b0a0 100644
--- a/pkg/gui/menu_panel.go
+++ b/pkg/gui/menu_panel.go
@@ -88,7 +88,7 @@ func (gui *Gui) createMenu(title string, items []*menuItem, createMenuOptions cr
gui.State.Panels.Menu.SelectedLineIdx = 0
gui.g.Update(func(g *gocui.Gui) error {
- return gui.switchContext(gui.Contexts.Menu.Context)
+ return gui.pushContext(gui.Contexts.Menu.Context)
})
return nil
}
diff --git a/pkg/gui/merge_panel.go b/pkg/gui/merge_panel.go
index 85e7198e5..60ce4d560 100644
--- a/pkg/gui/merge_panel.go
+++ b/pkg/gui/merge_panel.go
@@ -309,7 +309,7 @@ func (gui *Gui) handleEscapeMerge() error {
// it's possible this method won't be called from the merging view so we need to
// ensure we only 'return' focus if we already have it
if gui.g.CurrentView() == gui.getMainView() {