Skip to content

Commit e3db586

Browse files
committed
feat(tui): add /skills: sub-completion in autocomplete
Typing /skills: in the prompt now triggers inline autocomplete for skill names instead of opening the full dialog. Skills are listed alphabetically and filtered via fuzzysort as the user types after the colon. Selecting a skill inserts /<skill-name> into the prompt.
1 parent f68c3e1 commit e3db586

1 file changed

Lines changed: 40 additions & 0 deletions

File tree

packages/tui/src/component/prompt/autocomplete.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,32 @@ export function Autocomplete(props: {
532532
}))
533533
})
534534

535+
const skillOptions = createMemo((): AutocompleteOption[] => {
536+
const results: AutocompleteOption[] = []
537+
for (const serverCommand of sync.data.command) {
538+
if (serverCommand.source !== "skill") continue
539+
results.push({
540+
display: "/" + serverCommand.name,
541+
description: serverCommand.description,
542+
value: serverCommand.name,
543+
onSelect: () => {
544+
const newText = "/" + serverCommand.name + " "
545+
const cursor = props.input().logicalCursor
546+
props.input().deleteRange(0, 0, cursor.row, cursor.col)
547+
props.input().insertText(newText)
548+
props.input().cursorOffset = Bun.stringWidth(newText)
549+
},
550+
})
551+
}
552+
results.sort((a, b) => a.display.localeCompare(b.display))
553+
const max = firstBy(results, [(x) => x.display.length, "desc"])?.display.length
554+
if (!max) return results
555+
return results.map((item) => ({
556+
...item,
557+
display: item.display.padEnd(max + 2),
558+
}))
559+
})
560+
535561
const options = createMemo((prev: AutocompleteOption[] | undefined) => {
536562
const filesValue = files()
537563
const referenceMatchValue = referenceMatch()
@@ -544,6 +570,20 @@ export function Autocomplete(props: {
544570
return referenceAliasesValue.filter((item) => item.display === `@${referenceMatchValue.name}`)
545571
}
546572

573+
// Sub-completion: /skills: triggers skill-name autocomplete
574+
if (store.visible === "/" && searchValue.startsWith("skills:")) {
575+
const skillFilter = searchValue.slice("skills:".length)
576+
const skills = skillOptions()
577+
if (!skillFilter) return skills
578+
return fuzzysort
579+
.go(skillFilter, skills, {
580+
keys: [(obj) => obj.value ?? obj.display.trimEnd(), "description" as const],
581+
threshold: 0,
582+
limit: 10,
583+
})
584+
.map((arr) => arr.obj)
585+
}
586+
547587
// Files come from fff already fuzzy ranked and filtered
548588
// it shouldn't be additionally sorted by fuzzysort as it will loose the results
549589
const fileOptions: AutocompleteOption[] = store.visible === "@" ? filesValue || [] : []

0 commit comments

Comments
 (0)