on main help sign in
perf(list): optimize filter performance and limit results (#1193)
a292b29James Trew
internal/tui/components/chat/editor/editor.go+2
@@ -86,6 +86,7 @@ var DeleteKeyMaps = DeleteAttachmentKeyMaps{
86
86
87const (
87const (
88 maxAttachments = 5
88 maxAttachments = 5
89+ maxFileResults = 25
89)
90)
90
91
91type OpenEditorMsg struct {
92type OpenEditorMsg struct {
@@ -500,6 +501,7 @@ func (m *editorCmp) startCompletions() tea.Msg {
500 Completions: completionItems,
501 Completions: completionItems,
501 X: x,
502 X: x,
502 Y: y,
503 Y: y,
504+ MaxResults: maxFileResults,
503 }
505 }
504}
506}
505
507
internal/tui/components/completions/completions.go+2
@@ -22,6 +22,7 @@ type OpenCompletionsMsg struct {
22 Completions []Completion
22 Completions []Completion
23 X int // X position for the completions popup
23 X int // X position for the completions popup
24 Y int // Y position for the completions popup
24 Y int // Y position for the completions popup
25+ MaxResults int // Maximum number of results to render, 0 for no limit
25}
26}
26
27
27type FilterCompletionsMsg struct {
28type FilterCompletionsMsg struct {
@@ -192,6 +193,7 @@ func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
192 }
193 }
193 c.width = width
194 c.width = width
194 c.height = max(min(maxCompletionsHeight, len(items)), 1) // Ensure at least 1 item height
195 c.height = max(min(maxCompletionsHeight, len(items)), 1) // Ensure at least 1 item height
196+ c.list.SetResultsSize(msg.MaxResults)
195 return c, tea.Batch(
197 return c, tea.Batch(
196 c.list.SetItems(items),
198 c.list.SetItems(items),
197 c.list.SetSize(c.width, c.height),
199 c.list.SetSize(c.width, c.height),
internal/tui/exp/list/filterable.go+28−19
@@ -3,8 +3,6 @@ package list
3import (
3import (
4 "regexp"
4 "regexp"
5 "slices"
5 "slices"
6− "sort"
7− "strings"
8
6
9 "github.com/charmbracelet/bubbles/v2/key"
7 "github.com/charmbracelet/bubbles/v2/key"
10 "github.com/charmbracelet/bubbles/v2/textinput"
8 "github.com/charmbracelet/bubbles/v2/textinput"
@@ -28,7 +26,9 @@ type FilterableList[T FilterableItem] interface {
28 Cursor() *tea.Cursor
26 Cursor() *tea.Cursor
29 SetInputWidth(int)
27 SetInputWidth(int)
30 SetInputPlaceholder(string)
28 SetInputPlaceholder(string)
29+ SetResultsSize(int)
31 Filter(q string) tea.Cmd
30 Filter(q string) tea.Cmd
31+ fuzzy.Source
32}
32}
33
33
34type HasMatchIndexes interface {
34type HasMatchIndexes interface {
@@ -47,10 +47,11 @@ type filterableList[T FilterableItem] struct {
47 *filterableOptions
47 *filterableOptions
48 width, height int
48 width, height int
49 // stores all available items
49 // stores all available items
50− items []T
50+ items []T
51+ resultsSize int
51− input textinput.Model
52+ input textinput.Model
52− inputWidth int
53+ inputWidth int
53− query string
54+ query string
54}
55}
55
56
56type filterableListOption func(*filterableOptions)
57type filterableListOption func(*filterableOptions)
@@ -246,22 +247,18 @@ func (f *filterableList[T]) Filter(query string) tea.Cmd {
246 return f.list.SetItems(f.items)
247 return f.list.SetItems(f.items)
247 }
248 }
248
249
249− words := make([]string, len(f.items))
250− for i, item := range f.items {
251− words[i] = strings.ToLower(item.FilterValue())
252− }
253−
254− matches := fuzzy.Find(query, words)
250+ matches := fuzzy.FindFrom(query, f)
255−
256− sort.SliceStable(matches, func(i, j int) bool {
257− return matches[i].Score > matches[j].Score
258− })
259
251
260 var matchedItems []T
252 var matchedItems []T
253+ resultSize := len(matches)
254+ if f.resultsSize > 0 && resultSize > f.resultsSize {
255+ resultSize = f.resultsSize
256+ }
261− for _, match := range matches {
257+ for i := range resultSize {
258+ match := matches[i]
262 item := f.items[match.Index]
259 item := f.items[match.Index]
263− if i, ok := any(item).(HasMatchIndexes); ok {
260+ if it, ok := any(item).(HasMatchIndexes); ok {
264− i.MatchIndexes(match.MatchedIndexes)
261+ it.MatchIndexes(match.MatchedIndexes)
265 }
262 }
266 matchedItems = append(matchedItems, item)
263 matchedItems = append(matchedItems, item)
267 }
264 }
@@ -307,3 +304,15 @@ func (f *filterableList[T]) SetInputWidth(w int) {
307func (f *filterableList[T]) SetInputPlaceholder(ph string) {
304func (f *filterableList[T]) SetInputPlaceholder(ph string) {
308 f.placeholder = ph
305 f.placeholder = ph
309}
306}
307+
308+func (f *filterableList[T]) SetResultsSize(size int) {
309+ f.resultsSize = size
310+}
311+
312+func (f *filterableList[T]) String(i int) string {
313+ return f.items[i].FilterValue()
314+}
315+
316+func (f *filterableList[T]) Len() int {
317+ return len(f.items)
318+}