diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2021-10-23 10:46:02 +1100 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2021-10-23 12:29:52 +1100 |
commit | 629494144fcef931a9f484821202bcd4370aa23b (patch) | |
tree | ec7adf3bb2fc6c550f0ec52fdd61efd978a391d2 | |
parent | b6a5e9d615f0fee7d76f5db33ff48bf32f0ef98b (diff) |
show suggestions when typing in an origin
-rw-r--r-- | pkg/gui/branches_panel.go | 30 | ||||
-rw-r--r-- | pkg/gui/filtering.go | 66 | ||||
-rw-r--r-- | pkg/gui/filtering_menu_panel.go | 2 | ||||
-rw-r--r-- | pkg/gui/find_suggestions.go | 133 | ||||
-rw-r--r-- | pkg/gui/pull_request_menu_panel.go | 2 | ||||
-rw-r--r-- | pkg/gui/tags_panel.go | 5 |
6 files changed, 139 insertions, 99 deletions
diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go index d7d972ae7..e85e9fd05 100644 --- a/pkg/gui/branches_panel.go +++ b/pkg/gui/branches_panel.go @@ -7,8 +7,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" - "github.com/jesseduffield/lazygit/pkg/gui/presentation" - "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -220,7 +218,7 @@ func (gui *Gui) handleCheckoutRef(ref string, options handleCheckoutRefOptions) func (gui *Gui) handleCheckoutByName() error { return gui.prompt(promptOpts{ title: gui.Tr.BranchName + ":", - findSuggestionsFunc: gui.findBranchNameSuggestions, + findSuggestionsFunc: gui.getBranchNameSuggestionsFunc(), handleConfirm: func(response string) error { return gui.handleCheckoutRef(response, handleCheckoutRefOptions{ span: "Checkout branch", @@ -535,32 +533,6 @@ func (gui *Gui) handleNewBranchOffCurrentItem() error { }) } -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 -} - -func (gui *Gui) findBranchNameSuggestions(input string) []*types.Suggestion { - branchNames := gui.getBranchNames() - - matchingBranchNames := utils.FuzzySearch(sanitizedBranchName(input), branchNames) - - suggestions := make([]*types.Suggestion, len(matchingBranchNames)) - for i, branchName := range matchingBranchNames { - suggestions[i] = &types.Suggestion{ - Value: branchName, - Label: presentation.GetBranchTextStyle(branchName).Sprint(branchName), - } - } - - return suggestions -} - // sanitizedBranchName will remove all spaces in favor of a dash "-" to meet // git's branch naming requirement. func sanitizedBranchName(input string) string { diff --git a/pkg/gui/filtering.go b/pkg/gui/filtering.go index 17fd44e23..1f5c5032a 100644 --- a/pkg/gui/filtering.go +++ b/pkg/gui/filtering.go @@ -1,14 +1,5 @@ package gui -import ( - "os" - - "github.com/jesseduffield/lazygit/pkg/gui/types" - "github.com/jesseduffield/lazygit/pkg/utils" - "github.com/jesseduffield/minimal/gitignore" - "gopkg.in/ozeidan/fuzzy-patricia.v3/patricia" -) - func (gui *Gui) validateNotInFilterMode() (bool, error) { if gui.State.Modes.Filtering.Active() { err := gui.ask(askOpts{ @@ -49,60 +40,3 @@ func (gui *Gui) setFiltering(path string) error { gui.State.Contexts.BranchCommits.GetPanelState().SetSelectedLineIdx(0) }}) } - -// here we asynchronously fetch the latest set of paths in the repo and store in -// gui.State.FilesTrie. On the main thread we'll be doing a fuzzy search via -// gui.State.FilesTrie. So if we've looked for a file previously, we'll start with -// the old trie and eventually it'll be swapped out for the new one. -func (gui *Gui) getFindSuggestionsForFilterPath() func(string) []*types.Suggestion { - _ = gui.WithWaitingStatus(gui.Tr.LcLoadingFileSuggestions, func() error { - trie := patricia.NewTrie() - // load every non-gitignored file in the repo - ignore, err := gitignore.FromGit() - if err != nil { - return err - } - - err = ignore.Walk(".", - func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - trie.Insert(patricia.Prefix(path), path) - return nil - }) - // cache the trie for future use - gui.State.FilesTrie = trie - - // refresh the selections view - gui.suggestionsAsyncHandler.Do(func() func() { - // assuming here that the confirmation view is what we're typing into. - // This assumption may prove false over time - suggestions := gui.findSuggestions(gui.Views.Confirmation.TextArea.GetContent()) - return func() { gui.setSuggestions(suggestions) } - }) - - return err - }) - - return func(input string) []*types.Suggestion { - matchingNames := []string{} - _ = gui.State.FilesTrie.VisitFuzzy(patricia.Prefix(input), true, func(prefix patricia.Prefix, item patricia.Item, skipped int) error { - matchingNames = append(matchingNames, item.(string)) - return nil - }) - - // doing another fuzzy search for good measure - matchingNames = utils.FuzzySearch(input, matchingNames) - - suggestions := make([]*types.Suggestion, len(matchingNames)) - for i, name := range matchingNames { - suggestions[i] = &types.Suggestion{ - Value: name, - Label: name, - } - } - - return suggestions - } -} diff --git a/pkg/gui/filtering_menu_panel.go b/pkg/gui/filtering_menu_panel.go index bd17291ae..c354f0996 100644 --- a/pkg/gui/filtering_menu_panel.go +++ b/pkg/gui/filtering_menu_panel.go @@ -35,7 +35,7 @@ func (gui *Gui) handleCreateFilteringMenuPanel() error { displayString: gui.Tr.LcFilterPathOption, onPress: func() error { return gui.prompt(promptOpts{ - findSuggestionsFunc: gui.getFindSuggestionsForFilterPath(), + findSuggestionsFunc: gui.getFilePathSuggestionsFunc(), title: gui.Tr.LcEnterFileName, handleConfirm: func(response string) error { return gui.setFiltering(strings.TrimSpace(response)) diff --git a/pkg/gui/find_suggestions.go b/pkg/gui/find_suggestions.go new file mode 100644 index 000000000..b5ee0ecf2 --- /dev/null +++ b/pkg/gui/find_suggestions.go @@ -0,0 +1,133 @@ +package gui + +import ( + "os" + + "github.com/jesseduffield/lazygit/pkg/gui/presentation" + "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/jesseduffield/minimal/gitignore" + "gopkg.in/ozeidan/fuzzy-patricia.v3/patricia" +) + +// Thinking out loud: I'm typically a staunch advocate of organising code by feature rather than type, +// because colocating code that relates to the same feature means far less effort +// to get all the context you need to work on any particular feature. But the one +// major benefit of grouping by type is that it makes it makes it less likely that +// somebody will re-implement the same logic twice, because they can quickly see +// if a certain method has been used for some use case, given that as a starting point +// they know about the type. In that vein, I'm including all our functions for +// finding suggestions in this file, so that it's easy to see if a function already +// exists for fetching a particular model. + +func (gui *Gui) getRemoteNames() []string { + result := make([]string, len(gui.State.Remotes)) + for i, remote := range gui.State.Remotes { + result[i] = remote.Name + } + return result +} + +func matchesToSuggestions(matches []string) []*types.Suggestion { + suggestions := make([]*types.Suggestion, len(matches)) + for i, match := range matches { + suggestions[i] = &types.Suggestion{ + Value: match, + Label: match, + } + } + return suggestions +} + +func (gui *Gui) getRemoteSuggestionsFunc() func(string) []*types.Suggestion { + remoteNames := gui.getRemoteNames() + + return func(input string) []*types.Suggestion { + return matchesToSuggestions( + utils.FuzzySearch(input, remoteNames), + ) + } +} + +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 +} + +func (gui *Gui) getBranchNameSuggestionsFunc() func(string) []*types.Suggestion { + branchNames := gui.getBranchNames() + + return func(input string) []*types.Suggestion { + matchingBranchNames := utils.FuzzySearch(sanitizedBranchName(input), branchNames) + + suggestions := make([]*types.Suggestion, len(matchingBranchNames)) + for i, branchName := range matchingBranchNames { + suggestions[i] = &types.Suggestion{ + Value: branchName, + Label: presentation.GetBranchTextStyle(branchName).Sprint(branchName), + } + } + + return suggestions + } +} + +// here we asynchronously fetch the latest set of paths in the repo and store in +// gui.State.FilesTrie. On the main thread we'll be doing a fuzzy search via +// gui.State.FilesTrie. So if we've looked for a file previously, we'll start with +// the old trie and eventually it'll be swapped out for the new one. +func (gui *Gui) getFilePathSuggestionsFunc() func(string) []*types.Suggestion { + _ = gui.WithWaitingStatus(gui.Tr.LcLoadingFileSuggestions, func() error { + trie := patricia.NewTrie() + // load every non-gitignored file in the repo + ignore, err := gitignore.FromGit() + if err != nil { + return err + } + + err = ignore.Walk(".", + func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + trie.Insert(patricia.Prefix(path), path) + return nil + }) + // cache the trie for future use + gui.State.FilesTrie = trie + + // refresh the selections view + gui.suggestionsAsyncHandler.Do(func() func() { + // assuming here that the confirmation view is what we're typing into. + // This assumption may prove false over time + suggestions := gui.findSuggestions(gui.Views.Confirmation.TextArea.GetContent()) + return func() { gui.setSuggestions(suggestions) } + }) + + return err + }) + + return func(input string) []*types.Suggestion { + matchingNames := []string{} + _ = gui.State.FilesTrie.VisitFuzzy(patricia.Prefix(input), true, func(prefix patricia.Prefix, item patricia.Item, skipped int) error { + matchingNames = append(matchingNames, item.(string)) + return nil + }) + + // doing another fuzzy search for good measure + matchingNames = utils.FuzzySearch(input, matchingNames) + + suggestions := make([]*types.Suggestion, len(matchingNames)) + for i, name := range matchingNames { + suggestions[i] = &types.Suggestion{ + Value: name, + Label: name, + } + } + + return suggestions + } +} diff --git a/pkg/gui/pull_request_menu_panel.go b/pkg/gui/pull_request_menu_panel.go index aa7bc481a..60fdee50c 100644 --- a/pkg/gui/pull_request_menu_panel.go +++ b/pkg/gui/pull_request_menu_panel.go @@ -28,7 +28,7 @@ func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutB onPress: func() error { return gui.prompt(promptOpts{ title: branch.Name + " →", - findSuggestionsFunc: gui.findBranchNameSuggestions, + findSuggestionsFunc: gui.getBranchNameSuggestionsFunc(), handleConfirm: func(targetBranchName string) error { return gui.createPullRequest(branch.Name, targetBranchName) }}, diff --git a/pkg/gui/tags_panel.go b/pkg/gui/tags_panel.go index 500b41af1..2ce52d54a 100644 --- a/pkg/gui/tags_panel.go +++ b/pkg/gui/tags_panel.go @@ -121,8 +121,9 @@ func (gui *Gui) handlePushTag(tag *models.Tag) error { ) return gui.prompt(promptOpts{ - title: title, - initialContent: "origin", + title: title, + initialContent: "origin", + findSuggestionsFunc: gui.getRemoteSuggestionsFunc(), handleConfirm: func(response string) error { return gui.WithWaitingStatus(gui.Tr.PushingTagStatus, func() error { err := gui.GitCommand.WithSpan(gui.Tr.Spans.PushTag).PushTag(response, tag.Name, gui.promptUserForCredential) |