summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2021-10-23 10:46:02 +1100
committerJesse Duffield <jessedduffield@gmail.com>2021-10-23 12:29:52 +1100
commit629494144fcef931a9f484821202bcd4370aa23b (patch)
treeec7adf3bb2fc6c550f0ec52fdd61efd978a391d2
parentb6a5e9d615f0fee7d76f5db33ff48bf32f0ef98b (diff)
show suggestions when typing in an origin
-rw-r--r--pkg/gui/branches_panel.go30
-rw-r--r--pkg/gui/filtering.go66
-rw-r--r--pkg/gui/filtering_menu_panel.go2
-rw-r--r--pkg/gui/find_suggestions.go133
-rw-r--r--pkg/gui/pull_request_menu_panel.go2
-rw-r--r--pkg/gui/tags_panel.go5
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)