feat(ui): models dialog: filter by provider and model name

Ayman Bagabas created

Change summary

internal/ui/dialog/models_list.go | 44 ++++++++++++++++++++++----------
1 file changed, 30 insertions(+), 14 deletions(-)

Detailed changes

internal/ui/dialog/models_list.go 🔗

@@ -1,7 +1,10 @@
 package dialog
 
 import (
+	"fmt"
 	"slices"
+	"sort"
+	"strings"
 
 	"github.com/charmbracelet/crush/internal/ui/list"
 	"github.com/charmbracelet/crush/internal/ui/styles"
@@ -186,16 +189,21 @@ func (f *ModelsList) VisibleItems() []list.Item {
 		}
 	}
 
-	matches := fuzzy.FindFrom(f.query, list.FilterableItemsSource(filterableItems))
-	for _, match := range matches {
-		item := filterableItems[match.Index]
-		if ms, ok := item.(list.MatchSettable); ok {
-			ms.SetMatch(match)
-			item = ms.(list.FilterableItem)
-		}
-		filterableItems = append(filterableItems, item)
+	filterValue := func(itm *ModelItem) string {
+		return strings.ToLower(fmt.Sprintf("%s %s", itm.prov.Name, itm.model.Name))
+	}
+
+	names := make([]string, len(filterableItems))
+	for i, item := range filterableItems {
+		ms := item.(*ModelItem)
+		names[i] = filterValue(ms)
 	}
 
+	matches := fuzzy.Find(f.query, names)
+	sort.SliceStable(matches, func(i, j int) bool {
+		return matches[i].Score > matches[j].Score
+	})
+
 	items := []list.Item{}
 	visitedGroups := map[int]bool{}
 
@@ -203,19 +211,27 @@ func (f *ModelsList) VisibleItems() []list.Item {
 	// Find which group this item belongs to
 	for gi, g := range f.groups {
 		addedCount := 0
+		name := g.Title + " "
 		for _, match := range matches {
-			item := filterableItems[match.Index]
-			if slices.Contains(g.Items, item.(*ModelItem)) {
+			item := filterableItems[match.Index].(*ModelItem)
+			idxs := []int{}
+			for _, idx := range match.MatchedIndexes {
+				// Adjusts removing provider name highlights
+				if idx < len(name) {
+					continue
+				}
+				idxs = append(idxs, idx-len(name))
+			}
+
+			match.MatchedIndexes = idxs
+			if slices.Contains(g.Items, item) {
 				if !visitedGroups[gi] {
 					// Add section header
 					items = append(items, &g)
 					visitedGroups[gi] = true
 				}
 				// Add the matched item
-				if ms, ok := item.(list.MatchSettable); ok {
-					ms.SetMatch(match)
-					item = ms.(list.FilterableItem)
-				}
+				item.SetMatch(match)
 				items = append(items, item)
 				addedCount++
 			}