From 9f2886f96f75f0c127212562e05cc4d53e49b147 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 14 Jul 2026 13:37:38 +0200 Subject: [PATCH] Hold the file-path suggestions trie outside the model The file-path suggestions trie is rebuilt asynchronously and then read by the suggestions search, which runs on an AsyncHandler worker. It lived in Model().FilesTrie, so that worker read the (UI-thread-only) model. Move it to an atomic pointer on the SuggestionsHelper instead: it's the only place that uses it, the helper is recreated per repo (so the cache still resets on a repo switch), and an atomic pointer is safe to store from the build and load from the search worker. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../controllers/helpers/suggestions_helper.go | 22 +++++++++++++------ pkg/gui/gui.go | 2 -- pkg/gui/types/common.go | 4 ---- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/pkg/gui/controllers/helpers/suggestions_helper.go b/pkg/gui/controllers/helpers/suggestions_helper.go index 8a5916816..8784d82fc 100644 --- a/pkg/gui/controllers/helpers/suggestions_helper.go +++ b/pkg/gui/controllers/helpers/suggestions_helper.go @@ -3,6 +3,7 @@ package helpers import ( "fmt" "strings" + "sync/atomic" "github.com/jesseduffield/generics/set" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" @@ -28,14 +29,20 @@ import ( type SuggestionsHelper struct { c *HelperCommon + + // filesTrie holds the repo's file paths for file-path suggestions. It's + // rebuilt asynchronously and read from the suggestions worker goroutine, so + // it lives here as an atomic pointer rather than in the (UI-thread-only) + // model. + filesTrie atomic.Pointer[patricia.Trie] } func NewSuggestionsHelper( c *HelperCommon, ) *SuggestionsHelper { - return &SuggestionsHelper{ - c: c, - } + self := &SuggestionsHelper{c: c} + self.filesTrie.Store(patricia.NewTrie()) + return self } func (self *SuggestionsHelper) getRemoteNames() []string { @@ -137,9 +144,9 @@ func (self *SuggestionsHelper) GetFilePathSuggestionsFunc() func(string) []*type trie.Insert(patricia.Prefix(file), file) } + // cache the trie for future use + self.filesTrie.Store(trie) self.c.OnUIThread(func() error { - // cache the trie for future use - self.c.Model().FilesTrie = trie self.c.Contexts().Suggestions.RefreshSuggestions() return nil }) @@ -148,9 +155,10 @@ func (self *SuggestionsHelper) GetFilePathSuggestionsFunc() func(string) []*type }) return func(input string) []*types.Suggestion { + filesTrie := self.filesTrie.Load() matchingNames := []string{} if self.c.UserConfig().Gui.UseFuzzySearch() { - _ = self.c.Model().FilesTrie.VisitFuzzy(patricia.Prefix(input), true, func(prefix patricia.Prefix, item patricia.Item, skipped int) error { + _ = filesTrie.VisitFuzzy(patricia.Prefix(input), true, func(prefix patricia.Prefix, item patricia.Item, skipped int) error { matchingNames = append(matchingNames, item.(string)) return nil }) @@ -159,7 +167,7 @@ func (self *SuggestionsHelper) GetFilePathSuggestionsFunc() func(string) []*type matchingNames = utils.FilterStrings(input, matchingNames, true) } else { substrings := strings.Fields(input) - _ = self.c.Model().FilesTrie.Visit(func(prefix patricia.Prefix, item patricia.Item) error { + _ = filesTrie.Visit(func(prefix patricia.Prefix, item patricia.Item) error { for _, sub := range substrings { if !utils.CaseAwareContains(item.(string), sub) { return nil diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 9b592ffae..533c01fbd 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -49,7 +49,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/utils" "github.com/samber/lo" "github.com/sasha-s/go-deadlock" - "gopkg.in/ozeidan/fuzzy-patricia.v3/patricia" ) const StartupPopupVersion = 5 @@ -639,7 +638,6 @@ func (gui *Gui) resetState(startArgs appTypes.StartArgs) types.Context { FilteredReflogCommits: make([]*models.Commit, 0), ReflogCommits: make([]*models.Commit, 0), BisectInfo: git_commands.NewNullBisectInfo(), - FilesTrie: patricia.NewTrie(), Authors: map[string]*models.Author{}, MainBranches: git_commands.NewMainBranches(gui.c.Common, gui.os.Cmd), HashPool: &utils.StringPool{}, diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go index 6e7f72541..6d11e29db 100644 --- a/pkg/gui/types/common.go +++ b/pkg/gui/types/common.go @@ -11,7 +11,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/tasks" "github.com/jesseduffield/lazygit/pkg/utils" "github.com/sasha-s/go-deadlock" - "gopkg.in/ozeidan/fuzzy-patricia.v3/patricia" ) type HelperCommon struct { @@ -348,9 +347,6 @@ type Model struct { MainBranches *git_commands.MainBranches - // for displaying suggestions while typing in a file name - FilesTrie *patricia.Trie - Authors map[string]*models.Author HashPool *utils.StringPool