diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2020-11-28 13:14:48 +1100 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2020-11-28 20:48:17 +1100 |
commit | da3b0bf7c8aa6202d5eb9c8178f6648bc695336a (patch) | |
tree | cd0666ae4253469f8f2f1e349357be37bfb3d571 | |
parent | 90ade3225f55652d40c6f0266e50f5328390f02b (diff) |
Start on supporting auto-suggestions when checking out a branch
switch to other fuzzy package with no dependencies
42 files changed, 919 insertions, 105 deletions
@@ -23,11 +23,13 @@ require ( github.com/jesseduffield/yaml v2.1.0+incompatible github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect github.com/mattn/go-colorable v0.1.7 // indirect github.com/mattn/go-runewidth v0.0.9 github.com/mgutz/str v1.2.0 github.com/onsi/ginkgo v1.10.3 // indirect github.com/onsi/gomega v1.7.1 // indirect + github.com/sahilm/fuzzy v0.1.0 github.com/sirupsen/logrus v1.4.2 github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad github.com/stretchr/testify v1.4.0 @@ -86,6 +86,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -114,6 +116,8 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= +github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= 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/ |