|
1 | 1 | import type { BoxRenderable, TextareaRenderable, KeyEvent, ScrollBoxRenderable } from "@opentui/core" |
2 | | -import fuzzysort from "fuzzysort" |
3 | 2 | import { firstBy } from "remeda" |
4 | 3 | import { createMemo, createResource, createEffect, onMount, onCleanup, For, Show, createSignal } from "solid-js" |
5 | 4 | import { createStore } from "solid-js/store" |
@@ -62,6 +61,41 @@ export type AutocompleteOption = { |
62 | 61 | path?: string |
63 | 62 | } |
64 | 63 |
|
| 64 | +function tieredMatch( |
| 65 | + items: AutocompleteOption[], |
| 66 | + needle: string, |
| 67 | + prefix: string, |
| 68 | + limit: number = 100, |
| 69 | +): AutocompleteOption[] { |
| 70 | + const lowerNeedle = needle.toLowerCase() |
| 71 | + const fullNeedle = (prefix + needle).toLowerCase() |
| 72 | + |
| 73 | + const tier1: AutocompleteOption[] = [] |
| 74 | + const tier2: AutocompleteOption[] = [] |
| 75 | + const tier3: AutocompleteOption[] = [] |
| 76 | + |
| 77 | + for (const item of items) { |
| 78 | + const display = item.display.trimEnd().toLowerCase() |
| 79 | + |
| 80 | + if (display.startsWith(fullNeedle)) { |
| 81 | + tier1.push(item) |
| 82 | + } else if (display.includes(lowerNeedle)) { |
| 83 | + tier2.push(item) |
| 84 | + } else { |
| 85 | + const descMatch = item.description?.toLowerCase().includes(lowerNeedle) |
| 86 | + const aliasMatch = item.aliases?.some((a) => a.toLowerCase().includes(lowerNeedle)) |
| 87 | + if (descMatch || aliasMatch) { |
| 88 | + tier3.push(item) |
| 89 | + } |
| 90 | + } |
| 91 | + } |
| 92 | + |
| 93 | + const sortByDisplay = (a: AutocompleteOption, b: AutocompleteOption) => |
| 94 | + a.display.trimEnd().localeCompare(b.display.trimEnd()) |
| 95 | + |
| 96 | + return [...tier1.sort(sortByDisplay), ...tier2.sort(sortByDisplay), ...tier3.sort(sortByDisplay)].slice(0, limit) |
| 97 | +} |
| 98 | + |
65 | 99 | export function Autocomplete(props: { |
66 | 100 | value: string |
67 | 101 | sessionID?: string |
@@ -488,25 +522,7 @@ export function Autocomplete(props: { |
488 | 522 | return prev |
489 | 523 | } |
490 | 524 |
|
491 | | - const result = fuzzysort.go(removeLineRange(currentFilter), mixed, { |
492 | | - keys: [ |
493 | | - (obj) => removeLineRange((obj.value ?? obj.display).trimEnd()), |
494 | | - "description", |
495 | | - (obj) => obj.aliases?.join(" ") ?? "", |
496 | | - ], |
497 | | - limit: 10, |
498 | | - scoreFn: (objResults) => { |
499 | | - const displayResult = objResults[0] |
500 | | - let score = objResults.score |
501 | | - if (displayResult && displayResult.target.startsWith(store.visible + currentFilter)) { |
502 | | - score *= 2 |
503 | | - } |
504 | | - const frecencyScore = objResults.obj.path ? frecency.getFrecency(objResults.obj.path) : 0 |
505 | | - return score * (1 + frecencyScore) |
506 | | - }, |
507 | | - }) |
508 | | - |
509 | | - return result.map((arr) => arr.obj) |
| 525 | + return tieredMatch(mixed, currentFilter, store.visible || "/", 100) |
510 | 526 | }) |
511 | 527 |
|
512 | 528 | createEffect(() => { |
|
0 commit comments