diff --git a/go.mod b/go.mod index e4ecbe338..bc85923d9 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gookit/color v1.4.2 github.com/imdario/mergo v0.3.11 github.com/integrii/flaggy v1.4.0 - github.com/jesseduffield/generics v0.0.0-20220319062156-fa5cb8bde518 + github.com/jesseduffield/generics v0.0.0-20220319080325-a60171f800d5 github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e diff --git a/go.sum b/go.sum index 98c61cb73..eff282697 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/integrii/flaggy v1.4.0 h1:A1x7SYx4jqu5NSrY14z8Z+0UyX2S5ygfJJrfolWR3zM github.com/integrii/flaggy v1.4.0/go.mod h1:tnTxHeTJbah0gQ6/K0RW0J7fMUBk9MCF5blhm43LNpI= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jesseduffield/generics v0.0.0-20220319062156-fa5cb8bde518 h1:scclO0fuRMsIdYr6Gg+9LS1S1ZO93tHKQSbErWQWQ4s= -github.com/jesseduffield/generics v0.0.0-20220319062156-fa5cb8bde518/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= +github.com/jesseduffield/generics v0.0.0-20220319080325-a60171f800d5 h1:mZf9Ezkd4Thuw2tj5naFeoUbHkbNiD38LQFokUGSbtQ= +github.com/jesseduffield/generics v0.0.0-20220319080325-a60171f800d5/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 h1:GOQrmaE8i+KEdB8NzAegKYd4tPn/inM0I1uo0NXFerg= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o= github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 h1:9N08i5kjvOfkzMj6THmIM110wPTQLdVYEOHMHT2DFiI= diff --git a/pkg/gui/context.go b/pkg/gui/context.go index 53e29e246..2c30218bc 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/jesseduffield/generics/maps" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" @@ -413,16 +414,9 @@ func (gui *Gui) changeMainViewsContext(c types.Context) { func (gui *Gui) viewTabNames(viewName string) []string { tabContexts := gui.State.ViewTabContextMap[viewName] - if len(tabContexts) == 0 { - return nil - } - - result := make([]string, len(tabContexts)) - for i, tabContext := range tabContexts { - result[i] = tabContext.Tab - } - - return result + return slices.Map(tabContexts, func(tabContext context.TabContext) string { + return tabContext.Tab + }) } func (gui *Gui) setViewTabForContext(c types.Context) { diff --git a/pkg/gui/context/menu_context.go b/pkg/gui/context/menu_context.go index 67d6b126a..1f5654902 100644 --- a/pkg/gui/context/menu_context.go +++ b/pkg/gui/context/menu_context.go @@ -1,6 +1,7 @@ package context import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/types" @@ -77,19 +78,16 @@ func (self *MenuViewModel) SetMenuItems(items []*types.MenuItem) { } // TODO: move into presentation package -func (self *MenuViewModel) GetDisplayStrings(startIdx int, length int) [][]string { - stringArrays := make([][]string, len(self.menuItems)) - for i, item := range self.menuItems { - if item.DisplayStrings == nil { - styledStr := item.DisplayString - if item.OpensMenu { - styledStr = presentation.OpensMenuStyle(styledStr) - } - stringArrays[i] = []string{styledStr} - } else { - stringArrays[i] = item.DisplayStrings +func (self *MenuViewModel) GetDisplayStrings(_startIdx int, _length int) [][]string { + return slices.Map(self.menuItems, func(item *types.MenuItem) []string { + if item.DisplayStrings != nil { + return item.DisplayStrings } - } - return stringArrays + styledStr := item.DisplayString + if item.OpensMenu { + styledStr = presentation.OpensMenuStyle(styledStr) + } + return []string{styledStr} + }) } diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go index 477c5c64f..636c1c5fe 100644 --- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go +++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/types/enums" @@ -51,17 +52,14 @@ func (self *MergeAndRebaseHelper) CreateRebaseOptionsMenu() error { options = append(options, REBASE_OPTION_SKIP) } - 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] = &types.MenuItem{ + menuItems := slices.Map(options, func(option string) *types.MenuItem { + return &types.MenuItem{ DisplayString: option, OnPress: func() error { return self.genericMergeCommand(option) }, } - } + }) var title string if self.git.Status.WorkingTreeState() == enums.REBASE_MODE_MERGING { diff --git a/pkg/gui/controllers/helpers/refs_helper.go b/pkg/gui/controllers/helpers/refs_helper.go index 65c01d4a7..0838dd6f0 100644 --- a/pkg/gui/controllers/helpers/refs_helper.go +++ b/pkg/gui/controllers/helpers/refs_helper.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" @@ -134,10 +135,8 @@ func (self *RefsHelper) ResetToRef(ref string, strength string, envVars []string func (self *RefsHelper) CreateGitResetMenu(ref string) error { strengths := []string{"soft", "mixed", "hard"} - menuItems := make([]*types.MenuItem, len(strengths)) - for i, strength := range strengths { - strength := strength - menuItems[i] = &types.MenuItem{ + menuItems := slices.Map(strengths, func(strength string) *types.MenuItem { + return &types.MenuItem{ DisplayStrings: []string{ fmt.Sprintf("%s reset", strength), style.FgRed.Sprintf("reset --%s %s", strength, ref), @@ -147,7 +146,7 @@ func (self *RefsHelper) CreateGitResetMenu(ref string) error { return self.ResetToRef(ref, strength, []string{}) }, } - } + }) return self.c.Menu(types.CreateMenuOptions{ Title: fmt.Sprintf("%s %s", self.c.Tr.LcResetTo, ref), diff --git a/pkg/gui/controllers/helpers/suggestions_helper.go b/pkg/gui/controllers/helpers/suggestions_helper.go index a48e325b1..52ccf9d96 100644 --- a/pkg/gui/controllers/helpers/suggestions_helper.go +++ b/pkg/gui/controllers/helpers/suggestions_helper.go @@ -4,6 +4,8 @@ import ( "fmt" "os" + "github.com/jesseduffield/generics/slices" + "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" @@ -51,22 +53,18 @@ func NewSuggestionsHelper( } func (self *SuggestionsHelper) getRemoteNames() []string { - result := make([]string, len(self.model.Remotes)) - for i, remote := range self.model.Remotes { - result[i] = remote.Name - } - return result + return slices.Map(self.model.Remotes, func(remote *models.Remote) string { + return remote.Name + }) } func matchesToSuggestions(matches []string) []*types.Suggestion { - suggestions := make([]*types.Suggestion, len(matches)) - for i, match := range matches { - suggestions[i] = &types.Suggestion{ + return slices.Map(matches, func(match string) *types.Suggestion { + return &types.Suggestion{ Value: match, Label: match, } - } - return suggestions + }) } func (self *SuggestionsHelper) GetRemoteSuggestionsFunc() func(string) []*types.Suggestion { @@ -76,11 +74,9 @@ func (self *SuggestionsHelper) GetRemoteSuggestionsFunc() func(string) []*types. } func (self *SuggestionsHelper) getBranchNames() []string { - result := make([]string, len(self.model.Branches)) - for i, branch := range self.model.Branches { - result[i] = branch.Name - } - return result + return slices.Map(self.model.Branches, func(branch *models.Branch) string { + return branch.Name + }) } func (self *SuggestionsHelper) GetBranchNameSuggestionsFunc() func(string) []*types.Suggestion { @@ -94,15 +90,12 @@ func (self *SuggestionsHelper) GetBranchNameSuggestionsFunc() func(string) []*ty matchingBranchNames = utils.FuzzySearch(input, branchNames) } - suggestions := make([]*types.Suggestion, len(matchingBranchNames)) - for i, branchName := range matchingBranchNames { - suggestions[i] = &types.Suggestion{ + return slices.Map(matchingBranchNames, func(branchName string) *types.Suggestion { + return &types.Suggestion{ Value: branchName, Label: presentation.GetBranchTextStyle(branchName).Sprint(branchName), } - } - - return suggestions + }) } } @@ -148,26 +141,16 @@ func (self *SuggestionsHelper) GetFilePathSuggestionsFunc() func(string) []*type // 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 + return matchesToSuggestions(matchingNames) } } func (self *SuggestionsHelper) getRemoteBranchNames(separator string) []string { - result := []string{} - for _, remote := range self.model.Remotes { - for _, branch := range remote.Branches { - result = append(result, fmt.Sprintf("%s%s%s", remote.Name, separator, branch.Name)) - } - } - return result + return slices.FlatMap(self.model.Remotes, func(remote *models.Remote) []string { + return slices.Map(remote.Branches, func(branch *models.RemoteBranch) string { + return fmt.Sprintf("%s%s%s", remote.Name, separator, branch.Name) + }) + }) } func (self *SuggestionsHelper) GetRemoteBranchesSuggestionsFunc(separator string) func(string) []*types.Suggestion { @@ -175,11 +158,9 @@ func (self *SuggestionsHelper) GetRemoteBranchesSuggestionsFunc(separator string } func (self *SuggestionsHelper) getTagNames() []string { - result := make([]string, len(self.model.Tags)) - for i, tag := range self.model.Tags { - result[i] = tag.Name - } - return result + return slices.Map(self.model.Tags, func(tag *models.Tag) string { + return tag.Name + }) } func (self *SuggestionsHelper) GetRefsSuggestionsFunc() func(string) []*types.Suggestion { diff --git a/pkg/gui/files_panel_test.go b/pkg/gui/files_panel_test.go index 8946898e5..08d5d8838 100644 --- a/pkg/gui/files_panel_test.go +++ b/pkg/gui/files_panel_test.go @@ -3,6 +3,7 @@ package gui import ( "testing" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/stretchr/testify/assert" ) @@ -24,11 +25,7 @@ func TestGetSuggestedRemote(t *testing.T) { } func mkRemoteList(names ...string) []*models.Remote { - result := make([]*models.Remote, 0, len(names)) - - for _, name := range names { - result = append(result, &models.Remote{Name: name}) - } - - return result + return slices.Map(names, func(name string) *models.Remote { + return &models.Remote{Name: name} + }) } diff --git a/pkg/gui/filetree/commit_file_node.go b/pkg/gui/filetree/commit_file_node.go index ac2057da5..ad794c0c2 100644 --- a/pkg/gui/filetree/commit_file_node.go +++ b/pkg/gui/filetree/commit_file_node.go @@ -1,6 +1,7 @@ package filetree import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -40,19 +41,15 @@ func (s *CommitFileNode) GetPath() string { } func (s *CommitFileNode) GetChildren() []INode { - result := make([]INode, len(s.Children)) - for i, child := range s.Children { - result[i] = child - } - - return result + return slices.Map(s.Children, func(child *CommitFileNode) INode { + return child + }) } func (s *CommitFileNode) SetChildren(children []INode) { - castChildren := make([]*CommitFileNode, len(children)) - for i, child := range children { - castChildren[i] = child.(*CommitFileNode) - } + castChildren := slices.Map(children, func(child INode) *CommitFileNode { + return child.(*CommitFileNode) + }) s.Children = castChildren } @@ -102,12 +99,10 @@ func (s *CommitFileNode) EveryFile(test func(file *models.CommitFile) bool) bool func (n *CommitFileNode) Flatten(collapsedPaths *CollapsedPaths) []*CommitFileNode { results := flatten(n, collapsedPaths) - nodes := make([]*CommitFileNode, len(results)) - for i, result := range results { - nodes[i] = result.(*CommitFileNode) - } - return nodes + return slices.Map(results, func(result INode) *CommitFileNode { + return result.(*CommitFileNode) + }) } func (node *CommitFileNode) GetNodeAtIndex(index int, collapsedPaths *CollapsedPaths) *CommitFileNode { @@ -149,12 +144,10 @@ func (s *CommitFileNode) Compress() { func (s *CommitFileNode) GetLeaves() []*CommitFileNode { leaves := getLeaves(s) - castLeaves := make([]*CommitFileNode, len(leaves)) - for i := range leaves { - castLeaves[i] = leaves[i].(*CommitFileNode) - } - return castLeaves + return slices.Map(leaves, func(leaf INode) *CommitFileNode { + return leaf.(*CommitFileNode) + }) } // extra methods diff --git a/pkg/gui/filetree/file_node.go b/pkg/gui/filetree/file_node.go index e73504321..69663b000 100644 --- a/pkg/gui/filetree/file_node.go +++ b/pkg/gui/filetree/file_node.go @@ -1,6 +1,7 @@ package filetree import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -42,19 +43,15 @@ func (s *FileNode) GetPath() string { } func (s *FileNode) GetChildren() []INode { - result := make([]INode, len(s.Children)) - for i, child := range s.Children { - result[i] = child - } - - return result + return slices.Map(s.Children, func(child *FileNode) INode { + return child + }) } func (s *FileNode) SetChildren(children []INode) { - castChildren := make([]*FileNode, len(children)) - for i, child := range children { - castChildren[i] = child.(*FileNode) - } + castChildren := slices.Map(children, func(child INode) *FileNode { + return child.(*FileNode) + }) s.Children = castChildren } @@ -89,12 +86,9 @@ func (s *FileNode) Any(test func(node *FileNode) bool) bool { func (n *FileNode) Flatten(collapsedPaths *CollapsedPaths) []*FileNode { results := flatten(n, collapsedPaths) - nodes := make([]*FileNode, len(results)) - for i, result := range results { - nodes[i] = result.(*FileNode) - } - - return nodes + return slices.Map(results, func(result INode) *FileNode { + return result.(*FileNode) + }) } func (node *FileNode) GetNodeAtIndex(index int, collapsedPaths *CollapsedPaths) *FileNode { @@ -146,12 +140,10 @@ func (node *FileNode) GetFilePathsMatching(test func(*models.File) bool) []strin func (s *FileNode) GetLeaves() []*FileNode { leaves := getLeaves(s) - castLeaves := make([]*FileNode, len(leaves)) - for i := range leaves { - castLeaves[i] = leaves[i].(*FileNode) - } - return castLeaves + return slices.Map(leaves, func(leaf INode) *FileNode { + return leaf.(*FileNode) + }) } // extra methods diff --git a/pkg/gui/filetree/file_tree.go b/pkg/gui/filetree/file_tree.go index 47d7f32f2..d4bb8e596 100644 --- a/pkg/gui/filetree/file_tree.go +++ b/pkg/gui/filetree/file_tree.go @@ -3,6 +3,7 @@ package filetree import ( "fmt" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/sirupsen/logrus" ) @@ -85,13 +86,7 @@ func (self *FileTree) getFilesForDisplay() []*models.File { } func (self *FileTree) FilterFiles(test func(*models.File) bool) []*models.File { - result := make([]*models.File, 0) - for _, file := range self.getFiles() { - if test(file) { - result = append(result, file) - } - } - return result + return slices.Filter(self.getFiles(), test) } func (self *FileTree) SetFilter(filter FileTreeDisplayFilter) { diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go index dcea5a936..5a3f172f0 100644 --- a/pkg/gui/list_context_config.go +++ b/pkg/gui/list_context_config.go @@ -3,6 +3,7 @@ package gui import ( "log" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/context" @@ -28,12 +29,9 @@ func (gui *Gui) filesListContext() *context.WorkingTreeContext { gui.Views.Files, func(startIdx int, length int) [][]string { lines := presentation.RenderFileTree(gui.State.Contexts.Files.FileTreeViewModel, gui.State.Modes.Diffing.Ref, gui.State.Model.Submodules) - mappedLines := make([][]string, len(lines)) - for i, line := range lines { - mappedLines[i] = []string{line} - } - - return mappedLines + return slices.Map(lines, func(line string) []string { + return []string{line} + }) }, OnFocusWrapper(gui.onFocusFile), OnFocusWrapper(gui.withDiffModeCheck(gui.filesRenderToMain)), @@ -235,12 +233,9 @@ func (gui *Gui) commitFilesListContext() *context.CommitFilesContext { } lines := presentation.RenderCommitFileTree(gui.State.Contexts.CommitFiles.CommitFileTreeViewModel, gui.State.Modes.Diffing.Ref, gui.git.Patch.PatchManager) - mappedLines := make([][]string, len(lines)) - for i, line := range lines { - mappedLines[i] = []string{line} - } - - return mappedLines + return slices.Map(lines, func(line string) []string { + return []string{line} + }) }, OnFocusWrapper(gui.onCommitFileFocus), OnFocusWrapper(gui.withDiffModeCheck(gui.commitFilesRenderToMain)), diff --git a/pkg/gui/options_menu_panel.go b/pkg/gui/options_menu_panel.go index 54f08ed50..c21a9dce3 100644 --- a/pkg/gui/options_menu_panel.go +++ b/pkg/gui/options_menu_panel.go @@ -4,6 +4,7 @@ import ( "log" "strings" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" @@ -62,11 +63,8 @@ func (gui *Gui) handleCreateOptionsMenu() error { context := gui.currentContext() bindings := gui.getBindings(context) - menuItems := make([]*types.MenuItem, len(bindings)) - - for i, binding := range bindings { - binding := binding // note to self, never close over loop variables - menuItems[i] = &types.MenuItem{ + menuItems := slices.Map(bindings, func(binding *types.Binding) *types.MenuItem { + return &types.MenuItem{ DisplayStrings: []string{GetKeyDisplay(binding.Key), gui.displayDescription(binding)}, OnPress: func() error { if binding.Key == nil { @@ -78,7 +76,7 @@ func (gui *Gui) handleCreateOptionsMenu() error { return binding.Handler() }, } - } + }) return gui.c.Menu(types.CreateMenuOptions{ Title: strings.Title(gui.c.Tr.LcMenu), diff --git a/pkg/gui/presentation/branches.go b/pkg/gui/presentation/branches.go index 9062eface..b97ef6a5f 100644 --- a/pkg/gui/presentation/branches.go +++ b/pkg/gui/presentation/branches.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/i18n" @@ -14,14 +15,10 @@ import ( var branchPrefixColorCache = make(map[string]style.TextStyle) func GetBranchListDisplayStrings(branches []*models.Branch, fullDescription bool, diffName string, tr *i18n.TranslationSet) [][]string { - lines := make([][]string, len(branches)) - - for i := range branches { - diffed := branches[i].Name == diffName - lines[i] = getBranchDisplayStrings(branches[i], fullDescription, diffed, tr) - } - - return lines + return slices.Map(branches, func(branch *models.Branch) []string { + diffed := branch.Name == diffName + return getBranchDisplayStrings(branch, fullDescription, diffed, tr) + }) } // getBranchDisplayStrings returns the display string of branch diff --git a/pkg/gui/presentation/graph/graph.go b/pkg/gui/presentation/graph/graph.go index 70ab53079..de90d3e7a 100644 --- a/pkg/gui/presentation/graph/graph.go +++ b/pkg/gui/presentation/graph/graph.go @@ -5,10 +5,12 @@ import ( "strings" "sync" + "github.com/jesseduffield/generics/set" "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/samber/lo" ) type PipeKind uint8 @@ -77,7 +79,6 @@ func GetPipeSets(commits []*models.Commit, getStyle func(c *models.Commit) style func RenderAux(pipeSets [][]*Pipe, commits []*models.Commit, selectedCommitSha string) []string { maxProcs := runtime.GOMAXPROCS(0) - lines := make([]string, 0, len(pipeSets)) // splitting up the rendering of the graph into multiple goroutines allows us to render the graph in parallel chunks := make([][]string, maxProcs) perProc := len(pipeSets) / maxProcs @@ -110,24 +111,19 @@ func RenderAux(pipeSets [][]*Pipe, commits []*models.Commit, selectedCommitSha s wg.Wait() - for _, chunk := range chunks { - lines = append(lines, chunk...) - } - - return lines + return slices.Flatten(chunks) } func getNextPipes(prevPipes []*Pipe, commit *models.Commit, getStyle func(c *models.Commit) style.TextStyle) []*Pipe { - currentPipes := make([]*Pipe, 0, len(prevPipes)) - maxPos := 0 - for _, pipe := range prevPipes { - // a pipe that terminated in the previous line has no bearing on the current line - // so we'll filter those out - if pipe.kind != TERMINATES { - currentPipes = append(currentPipes, pipe) - } - maxPos = utils.Max(maxPos, pipe.toPos) - } + maxPos := lo.Max( + slices.Map(prevPipes, func(pipe *Pipe) int { return pipe.toPos }), + ) + + // a pipe that terminated in the previous line has no bearing on the current line + // so we'll filter those out + currentPipes := slices.Filter(prevPipes, func(pipe *Pipe) bool { + return pipe.kind != TERMINATES + }) newPipes := make([]*Pipe, 0, len(currentPipes)+len(commit.Parents)) // start by assuming that we've got a brand new commit not related to any preceding commit. @@ -142,9 +138,9 @@ func getNextPipes(prevPipes []*Pipe, commit *models.Commit, getStyle func(c *mod } // a taken spot is one where a current pipe is ending on - takenSpots := make(map[int]bool) + takenSpots := set.New[int]() // a traversed spot is one where a current pipe is starting on, ending on, or passing through - traversedSpots := make(map[int]bool) + traversedSpots := set.New[int]() if len(commit.Parents) > 0 { newPipes = append(newPipes, &Pipe{ @@ -157,17 +153,17 @@ func getNextPipes(prevPipes []*Pipe, commit *models.Commit, getStyle func(c *mod }) } - traversedSpotsForContinuingPipes := make(map[int]bool) + traversedSpotsForContinuingPipes := set.New[int]() for _, pipe := range currentPipes { if !equalHashes(pipe.toSha, commit.Sha) { - traversedSpotsForContinuingPipes[pipe.toPos] = true + traversedSpotsForContinuingPipes.Add(pipe.toPos) } } getNextAvailablePosForContinuingPipe := func() int { i := 0 for { - if !traversedSpots[i] { + if !traversedSpots.Includes(i) { return i } i++ @@ -179,7 +175,7 @@ func getNextPipes(prevPipes []*Pipe, commit *models.Commit, getStyle func(c *mod for { // a newly created pipe is not allowed to end on a spot that's already taken, // nor on a spot that's been traversed by a continuing pipe. - if !takenSpots[i] && !traversedSpotsForContinuingPipes[i] { + if !takenSpots.Includes(i) && !traversedSpotsForContinuingPipes.Includes(i) { return i } i++ @@ -192,9 +188,9 @@ func getNextPipes(prevPipes []*Pipe, commit *models.Commit, getStyle func(c *mod left, right = right, left } for i := left; i <= right; i++ { - traversedSpots[i] = true + traversedSpots.Add(i) } - takenSpots[to] = true + takenSpots.Add(to) } for _, pipe := range currentPipes { @@ -237,7 +233,7 @@ func getNextPipes(prevPipes []*Pipe, commit *models.Commit, getStyle func(c *mod style: getStyle(commit), }) - takenSpots[availablePos] = true + takenSpots.Add(availablePos) } } @@ -246,7 +242,7 @@ func getNextPipes(prevPipes []*Pipe, commit *models.Commit, getStyle func(c *mod // continuing on, potentially moving left to fill in a blank spot last := pipe.toPos for i := pipe.toPos; i > pos; i-- { - if takenSpots[i] || traversedSpots[i] { + if takenSpots.Includes(i) || traversedSpots.Includes(i) { break } else { last = i @@ -297,10 +293,9 @@ func renderPipeSet( } isMerge := startCount > 1 - cells := make([]*Cell, maxPos+1) - for i := range cells { - cells[i] = &Cell{cellType: CONNECTION, style: style.FgDefault} - } + cells := slices.Map(lo.Range(maxPos+1), func(i int) *Cell { + return &Cell{cellType: CONNECTION, style: style.FgDefault} + }) renderPipe := func(pipe *Pipe, style style.TextStyle, overrideRightStyle bool) { left := pipe.left() @@ -336,17 +331,9 @@ func renderPipeSet( // so we have our commit pos again, now it's time to build the cells. // we'll handle the one that's sourced from our selected commit last so that it can override the other cells. - selectedPipes := []*Pipe{} - // pre-allocating this one because most of the time we'll only have non-selected pipes - nonSelectedPipes := make([]*Pipe, 0, len(pipes)) - - for _, pipe := range pipes { - if highlight && equalHashes(pipe.fromSha, selectedCommitSha) { - selectedPipes = append(selectedPipes, pipe) - } else { - nonSelectedPipes = append(nonSelectedPipes, pipe) - } - } + selectedPipes, nonSelectedPipes := slices.Partition(pipes, func(pipe *Pipe) bool { + return highlight && equalHashes(pipe.fromSha, selectedCommitSha) + }) for _, pipe := range nonSelectedPipes { if pipe.kind == STARTS { diff --git a/pkg/gui/presentation/reflog_commits.go b/pkg/gui/presentation/reflog_commits.go index 72bb80ef6..95124c867 100644 --- a/pkg/gui/presentation/reflog_commits.go +++ b/pkg/gui/presentation/reflog_commits.go @@ -2,6 +2,7 @@ package presentation import ( "github.com/jesseduffield/generics/set" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/theme" @@ -10,8 +11,6 @@ import ( ) func GetReflogCommitListDisplayStrings(commits []*models.Commit, fullDescription bool, cherryPickedCommitShaSet *set.Set[string], diffName string, parseEmoji bool) [][]string { - lines := make([][]string, len(commits)) - var displayFunc func(*models.Commit, bool, bool, bool) []string if fullDescription { displayFunc = getFullDescriptionDisplayStringsForReflogCommit @@ -19,13 +18,11 @@ func GetReflogCommitListDisplayStrings(commits []*models.Commit, fullDescription displayFunc = getDisplayStringsForReflogCommit } - for i := range commits { - diffed := commits[i].Sha == diffName - cherryPicked := cherryPickedCommitShaSet.Includes(commits[i].Sha) - lines[i] = displayFunc(commits[i], cherryPicked, diffed, parseEmoji) - } - - return lines + return slices.Map(commits, func(commit *models.Commit) []string { + diffed := commit.Sha == diffName + cherryPicked := cherryPickedCommitShaSet.Includes(commit.Sha) + return displayFunc(commit, cherryPicked, diffed, parseEmoji) + }) } func reflogShaColor(cherryPicked, diffed bool) style.TextStyle { diff --git a/pkg/gui/presentation/remote_branches.go b/pkg/gui/presentation/remote_branches.go index d8439acfe..c5c54dfcb 100644 --- a/pkg/gui/presentation/remote_branches.go +++ b/pkg/gui/presentation/remote_branches.go @@ -1,19 +1,16 @@ package presentation import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/theme" ) func GetRemoteBranchListDisplayStrings(branches []*models.RemoteBranch, diffName string) [][]string { - lines := make([][]string, len(branches)) - - for i := range branches { - diffed := branches[i].FullName() == diffName - lines[i] = getRemoteBranchDisplayStrings(branches[i], diffed) - } - - return lines + return slices.Map(branches, func(branch *models.RemoteBranch) []string { + diffed := branch.FullName() == diffName + return getRemoteBranchDisplayStrings(branch, diffed) + }) } // getRemoteBranchDisplayStrings returns the display string of branch diff --git a/pkg/gui/presentation/remotes.go b/pkg/gui/presentation/remotes.go index a1e50fe2f..9b26cbfae 100644 --- a/pkg/gui/presentation/remotes.go +++ b/pkg/gui/presentation/remotes.go @@ -1,20 +1,17 @@ package presentation import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/theme" ) func GetRemoteListDisplayStrings(remotes []*models.Remote, diffName string) [][]string { - lines := make([][]string, len(remotes)) - - for i := range remotes { - diffed := remotes[i].Name == diffName - lines[i] = getRemoteDisplayStrings(remotes[i], diffed) - } - - return lines + return slices.Map(remotes, func(remote *models.Remote) []string { + diffed := remote.Name == diffName + return getRemoteDisplayStrings(remote, diffed) + }) } // getRemoteDisplayStrings returns the display string of branch diff --git a/pkg/gui/presentation/stash_entries.go b/pkg/gui/presentation/stash_entries.go index f15b35a9c..54b39c636 100644 --- a/pkg/gui/presentation/stash_entries.go +++ b/pkg/gui/presentation/stash_entries.go @@ -1,19 +1,16 @@ package presentation import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/theme" ) func GetStashEntryListDisplayStrings(stashEntries []*models.StashEntry, diffName string) [][]string { - lines := make([][]string, len(stashEntries)) - - for i := range stashEntries { - diffed := stashEntries[i].RefName() == diffName - lines[i] = getStashEntryDisplayStrings(stashEntries[i], diffed) - } - - return lines + return slices.Map(stashEntries, func(stashEntry *models.StashEntry) []string { + diffed := stashEntry.RefName() == diffName + return getStashEntryDisplayStrings(stashEntry, diffed) + }) } // getStashEntryDisplayStrings returns the display string of branch diff --git a/pkg/gui/presentation/submodules.go b/pkg/gui/presentation/submodules.go index 2d131ed8f..0fb057ef0 100644 --- a/pkg/gui/presentation/submodules.go +++ b/pkg/gui/presentation/submodules.go @@ -1,18 +1,15 @@ package presentation import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/theme" ) func GetSubmoduleListDisplayStrings(submodules []*models.SubmoduleConfig) [][]string { - lines := make([][]string, len(submodules)) - - for i := range submodules { - lines[i] = getSubmoduleDisplayStrings(submodules[i]) - } - - return lines + return slices.Map(submodules, func(submodule *models.SubmoduleConfig) []string { + return getSubmoduleDisplayStrings(submodule) + }) } func getSubmoduleDisplayStrings(s *models.SubmoduleConfig) []string { diff --git a/pkg/gui/presentation/suggestions.go b/pkg/gui/presentation/suggestions.go index 81c6a3a3d..5319b40f7 100644 --- a/pkg/gui/presentation/suggestions.go +++ b/pkg/gui/presentation/suggestions.go @@ -1,17 +1,14 @@ package presentation import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/gui/types" ) func GetSuggestionListDisplayStrings(suggestions []*types.Suggestion) [][]string { - lines := make([][]string, len(suggestions)) - - for i := range suggestions { - lines[i] = getSuggestionDisplayStrings(suggestions[i]) - } - - return lines + return slices.Map(suggestions, func(suggestion *types.Suggestion) []string { + return getSuggestionDisplayStrings(suggestion) + }) } func getSuggestionDisplayStrings(suggestion *types.Suggestion) []string { diff --git a/pkg/gui/presentation/tags.go b/pkg/gui/presentation/tags.go index 4754c4bef..2157e29c9 100644 --- a/pkg/gui/presentation/tags.go +++ b/pkg/gui/presentation/tags.go @@ -1,19 +1,16 @@ package presentation import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/theme" ) func GetTagListDisplayStrings(tags []*models.Tag, diffName string) [][]string { - lines := make([][]string, len(tags)) - - for i := range tags { - diffed := tags[i].Name == diffName - lines[i] = getTagDisplayStrings(tags[i], diffed) - } - - return lines + return slices.Map(tags, func(tag *models.Tag) []string { + diffed := tag.Name == diffName + return getTagDisplayStrings(tag, diffed) + }) } // getTagDisplayStrings returns the display string of branch diff --git a/pkg/gui/recent_repos_panel.go b/pkg/gui/recent_repos_panel.go index 73ee784c3..38684809b 100644 --- a/pkg/gui/recent_repos_panel.go +++ b/pkg/gui/recent_repos_panel.go @@ -4,22 +4,19 @@ import ( "os" "path/filepath" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/env" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" - "github.com/jesseduffield/lazygit/pkg/utils" ) func (gui *Gui) handleCreateRecentReposMenu() error { recentRepoPaths := gui.c.GetAppState().RecentRepos - reposCount := utils.Min(len(recentRepoPaths), 20) // we won't show the current repo hence the -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] = &types.MenuItem{ + menuItems := slices.Map(recentRepoPaths[1:], func(path string) *types.MenuItem { + return &types.MenuItem{ DisplayStrings: []string{ filepath.Base(path), style.FgMagenta.Sprint(path), @@ -31,7 +28,7 @@ func (gui *Gui) handleCreateRecentReposMenu() error { return gui.dispatchSwitchToRepo(path, false) }, } - } + }) return gui.c.Menu(types.CreateMenuOptions{Title: gui.c.Tr.RecentRepos, Items: menuItems}) } diff --git a/pkg/gui/refresh.go b/pkg/gui/refresh.go index 5252d7ec9..602eb37e9 100644 --- a/pkg/gui/refresh.go +++ b/pkg/gui/refresh.go @@ -6,6 +6,7 @@ import ( "sync" "github.com/jesseduffield/generics/set" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/loaders" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/types/enums" @@ -32,12 +33,9 @@ func getScopeNames(scopes []types.RefreshableView) []string { types.BISECT_INFO: "bisect", } - scopeNames := make([]string, len(scopes)) - for i, scope := range scopes { - scopeNames[i] = scopeNameMap[scope] - } - - return scopeNames + return slices.Map(scopes, func(scope types.RefreshableView) string { + return scopeNameMap[scope] + }) } func getModeName(mode types.RefreshMode) string { diff --git a/pkg/gui/services/custom_commands/handler_creator.go b/pkg/gui/services/custom_commands/handler_creator.go index 04e6cb644..dbae84de7 100644 --- a/pkg/gui/services/custom_commands/handler_creator.go +++ b/pkg/gui/services/custom_commands/handler_creator.go @@ -1,6 +1,7 @@ package custom_commands import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/config" @@ -99,16 +100,14 @@ func (self *HandlerCreator) inputPrompt(prompt *config.CustomCommandPrompt, wrap } func (self *HandlerCreator) menuPrompt(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error { - menuItems := make([]*types.MenuItem, len(prompt.Options)) - for i, option := range prompt.Options { - option := option - menuItems[i] = &types.MenuItem{ + menuItems := slices.Map(prompt.Options, func(option config.CustomCommandMenuOption) *types.MenuItem { + return &types.MenuItem{ DisplayStrings: []string{option.Name, style.FgYellow.Sprint(option.Description)}, OnPress: func() error { return wrappedF(option.Value) }, } - } + }) return self.c.Menu(types.CreateMenuOptions{Title: prompt.Title, Items: menuItems}) } @@ -126,16 +125,14 @@ func (self *HandlerCreator) menuPromptFromCommand(prompt *config.CustomCommandPr return self.c.Error(err) } - menuItems := make([]*types.MenuItem, len(candidates)) - for i := range candidates { - i := i - menuItems[i] = &types.MenuItem{ - DisplayStrings: []string{candidates[i].label}, + menuItems := slices.Map(candidates, func(candidate *commandMenuEntry) *types.MenuItem { + return &types.MenuItem{ + DisplayStrings: []string{candidate.label}, OnPress: func() error { - return wrappedF(candidates[i].value) + return wrappedF(candidate.value) }, } - } + }) return self.c.Menu(types.CreateMenuOptions{Title: prompt.Title, Items: menuItems}) } diff --git a/pkg/gui/services/custom_commands/keybinding_creator.go b/pkg/gui/services/custom_commands/keybinding_creator.go index e3c233951..ed2921359 100644 --- a/pkg/gui/services/custom_commands/keybinding_creator.go +++ b/pkg/gui/services/custom_commands/keybinding_creator.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/context" @@ -77,11 +78,9 @@ func (self *KeybindingCreator) contextForContextKey(contextKey types.ContextKey) } func formatUnknownContextError(customCommand config.CustomCommand) error { - // stupid golang making me build an array of strings for this. - allContextKeyStrings := make([]string, len(context.AllContextKeys)) - for i := range context.AllContextKeys { - allContextKeyStrings[i] = string(context.AllContextKeys[i]) - } + allContextKeyStrings := slices.Map(context.AllContextKeys, func(key types.ContextKey) string { + return string(key) + }) return fmt.Errorf("Error when setting custom command keybindings: unknown context: %s. Key: %s, Command: %s.\nPermitted contexts: %s", customCommand.Context, customCommand.Key, customCommand.Command, strings.Join(allContextKeyStrings, ", ")) } diff --git a/pkg/gui/status_panel.go b/pkg/gui/status_panel.go index 6ca6e6996..cde535cd9 100644 --- a/pkg/gui/status_panel.go +++ b/pkg/gui/status_panel.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/types/enums" "github.com/jesseduffield/lazygit/pkg/constants" "github.com/jesseduffield/lazygit/pkg/gui/presentation" @@ -102,16 +103,15 @@ func (gui *Gui) askForConfigFile(action func(file string) error) error { case 1: return action(confPaths[0]) default: - menuItems := make([]*types.MenuItem, len(confPaths)) - for i, file := range confPaths { - i := i - menuItems[i] = &types.MenuItem{ - DisplayString: file, + menuItems := slices.Map(confPaths, func(path string) *types.MenuItem { + return &types.MenuItem{ + DisplayString: path, OnPress: func() error { - return action(confPaths[i]) + return action(path) }, } - } + }) + return gui.c.Menu(types.CreateMenuOptions{ Title: gui.c.Tr.SelectConfigFile, Items: menuItems, diff --git a/pkg/utils/formatting.go b/pkg/utils/formatting.go index d33028063..657d1d2eb 100644 --- a/pkg/utils/formatting.go +++ b/pkg/utils/formatting.go @@ -3,7 +3,9 @@ package utils import ( "strings" + "github.com/jesseduffield/generics/slices" "github.com/mattn/go-runewidth" + "github.com/samber/lo" ) // WithPadding pads a string as much as you want @@ -83,27 +85,20 @@ func getPaddedDisplayStrings(stringArrays [][]string, padWidths []int) string { } func getPadWidths(stringArrays [][]string) []int { - maxWidth := 0 - for _, stringArray := range stringArrays { - if len(stringArray) > maxWidth { - maxWidth = len(stringArray) - } - } + maxWidth := slices.MaxBy(stringArrays, func(stringArray []string) int { + return len(stringArray) + }) + if maxWidth-1 < 0 { return []int{} } - padWidths := make([]int, maxWidth-1) - for i := range padWidths { - for _, strings := range stringArrays { - uncoloredStr := Decolorise(strings[i]) + return slices.Map(lo.Range(maxWidth-1), func(i int) int { + return slices.MaxBy(stringArrays, func(stringArray []string) int { + uncoloredStr := Decolorise(stringArray[i]) - width := runewidth.StringWidth(uncoloredStr) - if width > padWidths[i] { - padWidths[i] = width - } - } - } - return padWidths + return runewidth.StringWidth(uncoloredStr) + }) + }) } // TruncateWithEllipsis returns a string, truncated to a certain length, with an ellipsis diff --git a/pkg/utils/fuzzy_search.go b/pkg/utils/fuzzy_search.go index 4199d6c8b..5fce3dde9 100644 --- a/pkg/utils/fuzzy_search.go +++ b/pkg/utils/fuzzy_search.go @@ -3,6 +3,7 @@ package utils import ( "sort" + "github.com/jesseduffield/generics/slices" "github.com/sahilm/fuzzy" ) @@ -14,10 +15,7 @@ func FuzzySearch(needle string, haystack []string) []string { matches := fuzzy.Find(needle, haystack) sort.Sort(matches) - result := make([]string, len(matches)) - for i, match := range matches { - result[i] = match.Str - } - - return result + return slices.Map(matches, func(match fuzzy.Match) string { + return match.Str + }) } diff --git a/vendor/github.com/jesseduffield/generics/slices/slices.go b/vendor/github.com/jesseduffield/generics/slices/slices.go index b9c783caf..ec5653ddc 100644 --- a/vendor/github.com/jesseduffield/generics/slices/slices.go +++ b/vendor/github.com/jesseduffield/generics/slices/slices.go @@ -1,6 +1,7 @@ package slices import ( + "golang.org/x/exp/constraints" "golang.org/x/exp/slices" ) @@ -28,14 +29,34 @@ func Every[T any](slice []T, test func(T) bool) bool { // Produces a new slice, leaves the input slice untouched. func Map[T any, V any](slice []T, f func(T) V) []V { - result := make([]V, len(slice)) - for i, value := range slice { - result[i] = f(value) + result := make([]V, 0, len(slice)) + for _, value := range slice { + result = append(result, f(value)) } return result } +// Produces a new slice, leaves the input slice untouched. +func FlatMap[T any, V any](slice []T, f func(T) []V) []V { + // impossible to know how long this slice will be in the end but the length + // of the original slice is the lower bound + result := make([]V, 0, len(slice)) + for _, value := range slice { + result = append(result, f(value)...) + } + + return result +} + +func Flatten[T any](slice [][]T) []T { + result := make([]T, 0, len(slice)) + for _, subSlice := range slice { + result = append(result, subSlice...) + } + return result +} + func MapInPlace[T any](slice []T, f func(T) T) { for i, value := range slice { slice[i] = f(value) @@ -152,3 +173,53 @@ func Shift[T any](slice []T) (T, []T) { slice = slice[1:] return value, slice } + +func Partition[T any](slice []T, test func(T) bool) ([]T, []T) { + left := make([]T, 0, len(slice)) + right := make([]T, 0, len(slice)) + + for _, value := range slice { + if test(value) { + left = append(left, value) + } else { + right = append(right, value) + } + } + + return left, right +} + +func MaxBy[T any, V constraints.Ordered](slice []T, f func(T) V) V { + if len(slice) == 0 { + return zero[V]() + } + + max := f(slice[0]) + for _, element := range slice[1:] { + value := f(element) + if value > max { + max = value + } + } + return max +} + +func MinBy[T any, V constraints.Ordered](slice []T, f func(T) V) V { + if len(slice) == 0 { + return zero[V]() + } + + min := f(slice[0]) + for _, element := range slice[1:] { + value := f(element) + if value < min { + min = value + } + } + return min +} + +func zero[T any]() T { + var value T + return value +} diff --git a/vendor/modules.txt b/vendor/modules.txt index b7234a630..332871ffe 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -120,7 +120,7 @@ github.com/integrii/flaggy # github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 ## explicit github.com/jbenet/go-context/io -# github.com/jesseduffield/generics v0.0.0-20220319062156-fa5cb8bde518 +# github.com/jesseduffield/generics v0.0.0-20220319080325-a60171f800d5 ## explicit; go 1.18 github.com/jesseduffield/generics/maps github.com/jesseduffield/generics/set