Skip to content

Commit 405f568

Browse files
authored
Merge pull request #228 from jameslaydigital/tree-filter-rank-results
Tree filter rank results
2 parents eb17564 + 6b157d8 commit 405f568

File tree

1 file changed

+69
-16
lines changed

1 file changed

+69
-16
lines changed

components/tree.go

Lines changed: 69 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,9 @@ func NewTree(dbName string, dbdriver drivers.Driver) *Tree {
194194
if filterText == "" {
195195
tree.ClearSearch()
196196
} else {
197-
tree.FoundNodeCountInput.SetText(fmt.Sprintf("[%d/%d]", len(tree.state.searchFoundNodes), len(tree.state.searchFoundNodes)))
197+
if len(tree.state.searchFoundNodes) > 0 {
198+
tree.FoundNodeCountInput.SetText(fmt.Sprintf("[1/%d]", len(tree.state.searchFoundNodes)))
199+
}
198200
tree.SetBorderPadding(1, 0, 0, 0)
199201
}
200202

@@ -291,6 +293,38 @@ func (tree *Tree) databasesToNodes(children map[string][]string, node *tview.Tre
291293
}
292294
}
293295

296+
func prioritizeResult(pattern, target string, fuzzyRank int) int {
297+
// play match golf - lowest score wins
298+
299+
// Exact match
300+
if pattern == target {
301+
return 0
302+
}
303+
304+
// Prefix is scored on length difference, 1-99
305+
if strings.HasPrefix(target, pattern) {
306+
lengthDiff := len(target) - len(pattern)
307+
if lengthDiff > 98 {
308+
lengthDiff = 98
309+
}
310+
return 1 + lengthDiff
311+
}
312+
313+
// Substr penalized by distance from start and length diff
314+
if strings.Contains(target, pattern) {
315+
index := strings.Index(target, pattern)
316+
lengthPenalty := len(target) - len(pattern)
317+
score := 100 + index + lengthPenalty
318+
if score > 9999 {
319+
score = 9999
320+
}
321+
return score
322+
}
323+
324+
// If no other matches, fall back to fuzzy match with a low score
325+
return 10000 + fuzzyRank
326+
}
327+
294328
func (tree *Tree) search(searchText string) {
295329
rootNode := tree.GetRoot()
296330
lowerSearchText := strings.ToLower(searchText)
@@ -317,32 +351,57 @@ func (tree *Tree) search(searchText string) {
317351
tableNameFilter = parts[1]
318352
}
319353

354+
// Collect nodes with their match ranks
355+
type rankedNode struct {
356+
node *tview.TreeNode
357+
rank int
358+
}
359+
var rankedNodes []rankedNode
360+
320361
rootNode.Walk(func(node, parent *tview.TreeNode) bool {
321362
nodeText := strings.ToLower(node.GetText())
322363

323364
if databaseNameFilter == "" {
324-
if fuzzy.Match(tableNameFilter, nodeText) {
365+
rank := fuzzy.RankMatch(tableNameFilter, nodeText)
366+
if rank >= 0 {
325367
if parent != nil {
326368
parent.SetExpanded(true)
327369
}
328-
tree.state.searchFoundNodes = append(tree.state.searchFoundNodes, node)
329-
tree.SetCurrentNode(node)
330-
tree.state.currentFocusFoundNode = node
370+
adjustedRank := prioritizeResult(tableNameFilter, nodeText, rank)
371+
rankedNodes = append(rankedNodes, rankedNode{node: node, rank: adjustedRank})
331372
}
332373
} else {
333-
if fuzzy.Match(tableNameFilter, nodeText) && parent != nil {
374+
rank := fuzzy.RankMatch(tableNameFilter, nodeText)
375+
if rank >= 0 && parent != nil {
334376
parentText := strings.ToLower(parent.GetText())
335-
if fuzzy.Match(databaseNameFilter, parentText) {
377+
parentRank := fuzzy.RankMatch(databaseNameFilter, parentText)
378+
if parentRank >= 0 {
336379
parent.SetExpanded(true)
337-
tree.state.searchFoundNodes = append(tree.state.searchFoundNodes, node)
338-
tree.SetCurrentNode(node)
339-
tree.state.currentFocusFoundNode = node
380+
adjustedTableRank := prioritizeResult(tableNameFilter, nodeText, rank)
381+
adjustedParentRank := prioritizeResult(databaseNameFilter, parentText, parentRank)
382+
// Combine ranks: prioritize table match but factor in database match
383+
combinedRank := adjustedTableRank + (adjustedParentRank / 2)
384+
rankedNodes = append(rankedNodes, rankedNode{node: node, rank: combinedRank})
340385
}
341386
}
342387
}
343388

344389
return true
345390
})
391+
392+
sort.Slice(rankedNodes, func(i, j int) bool {
393+
return rankedNodes[i].rank < rankedNodes[j].rank
394+
})
395+
396+
for _, rn := range rankedNodes {
397+
tree.state.searchFoundNodes = append(tree.state.searchFoundNodes, rn.node)
398+
}
399+
400+
// Set current node to best match
401+
if len(tree.state.searchFoundNodes) > 0 {
402+
tree.SetCurrentNode(tree.state.searchFoundNodes[0])
403+
tree.state.currentFocusFoundNode = tree.state.searchFoundNodes[0]
404+
}
346405
}
347406

348407
// Subscribe to changes in the tree state
@@ -482,12 +541,6 @@ func (tree *Tree) Highlight() {
482541
}
483542

484543
func (tree *Tree) goToNextFoundNode() {
485-
foundNodesText := make([]string, len(tree.state.searchFoundNodes))
486-
487-
for i, node := range tree.state.searchFoundNodes {
488-
foundNodesText[i] = node.GetText()
489-
}
490-
491544
for i, node := range tree.state.searchFoundNodes {
492545
if node == tree.state.currentFocusFoundNode {
493546
var newFocusNodeIndex int

0 commit comments

Comments
 (0)