@code-yeongyu/senpi-tui 2026.9.16 → 2026.9.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/autocomplete.d.ts +11 -0
- package/dist/autocomplete.d.ts.map +1 -1
- package/dist/autocomplete.js +4 -1
- package/dist/autocomplete.js.map +1 -1
- package/dist/components/editor-line-render.d.ts +25 -0
- package/dist/components/editor-line-render.d.ts.map +1 -0
- package/dist/components/editor-line-render.js +56 -0
- package/dist/components/editor-line-render.js.map +1 -0
- package/dist/components/editor.d.ts +2 -0
- package/dist/components/editor.d.ts.map +1 -1
- package/dist/components/editor.js +43 -29
- package/dist/components/editor.js.map +1 -1
- package/dist/dollar-invocation-autocomplete.d.ts +21 -0
- package/dist/dollar-invocation-autocomplete.d.ts.map +1 -1
- package/dist/dollar-invocation-autocomplete.js +39 -25
- package/dist/dollar-invocation-autocomplete.js.map +1 -1
- package/package.json +1 -1
|
@@ -4,6 +4,27 @@ export interface DollarInvocationContext {
|
|
|
4
4
|
readonly query: string;
|
|
5
5
|
readonly skillsOnly: boolean;
|
|
6
6
|
}
|
|
7
|
+
export interface DollarSkillMention {
|
|
8
|
+
readonly start: number;
|
|
9
|
+
readonly end: number;
|
|
10
|
+
readonly name: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Locate every `$name` / `$skill:name` token on one line that names a known
|
|
14
|
+
* skill. Tokens must sit at a whitespace boundary, so `$HOME`, `$1`, `a$x`,
|
|
15
|
+
* and unknown names stay plain. Offsets are line-local and `end` is exclusive.
|
|
16
|
+
*/
|
|
17
|
+
export declare function findDollarSkillMentions(line: string, knownSkills: ReadonlySet<string>): DollarSkillMention[];
|
|
18
|
+
/** Names of the skills the command list exposes as `skill:<name>` entries. */
|
|
19
|
+
export declare function knownSkillNames(commands: readonly (SlashCommand | AutocompleteItem)[]): ReadonlySet<string>;
|
|
20
|
+
/**
|
|
21
|
+
* Describe the `$` token under the cursor when it should open the popup.
|
|
22
|
+
*
|
|
23
|
+
* Any `$query` at a whitespace boundary completes, however many `$` tokens
|
|
24
|
+
* precede it, so one prompt can carry several skill mentions. Slash commands
|
|
25
|
+
* are only offered while the token is the first thing in the prompt; a token
|
|
26
|
+
* that already names a known skill closes the popup so `enter` submits.
|
|
27
|
+
*/
|
|
7
28
|
export declare function getDollarInvocationContext(textBeforeCursor: string, _cursorLine: number, commands: readonly (SlashCommand | AutocompleteItem)[]): DollarInvocationContext | null;
|
|
8
29
|
export declare function getDollarInvocationSuggestions(commands: readonly (SlashCommand | AutocompleteItem)[], query: string, skillsOnly: boolean): AutocompleteItem[];
|
|
9
30
|
//# sourceMappingURL=dollar-invocation-autocomplete.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dollar-invocation-autocomplete.d.ts","sourceRoot":"","sources":["../src/dollar-invocation-autocomplete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"dollar-invocation-autocomplete.d.ts","sourceRoot":"","sources":["../src/dollar-invocation-autocomplete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAgCxE,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAyBD;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,kBAAkB,EAAE,CAW5G;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,QAAQ,EAAE,SAAS,CAAC,YAAY,GAAG,gBAAgB,CAAC,EAAE,GAAG,WAAW,CAAC,MAAM,CAAC,CAO3G;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACzC,gBAAgB,EAAE,MAAM,EACxB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,SAAS,CAAC,YAAY,GAAG,gBAAgB,CAAC,EAAE,GACpD,uBAAuB,GAAG,IAAI,CAiBhC;AAED,wBAAgB,8BAA8B,CAC7C,QAAQ,EAAE,SAAS,CAAC,YAAY,GAAG,gBAAgB,CAAC,EAAE,EACtD,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,OAAO,GACjB,gBAAgB,EAAE,CAkCpB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { fuzzyFilter } from "./fuzzy.js";
|
|
2
2
|
const SKILL_COMMAND_PREFIX = "skill:";
|
|
3
3
|
const DOLLAR_QUERY_PATTERN = /^\$([a-zA-Z0-9:_-]*)$/;
|
|
4
|
+
const DOLLAR_MENTION_PATTERN = /(^|\s)\$([a-zA-Z][a-zA-Z0-9:_-]*)(?=\s|$)/g;
|
|
4
5
|
const COMMON_SHELL_VARIABLES = new Set([
|
|
5
6
|
"CI",
|
|
6
7
|
"EDITOR",
|
|
@@ -25,19 +26,6 @@ function isDollarQueryCompletable(query) {
|
|
|
25
26
|
return false;
|
|
26
27
|
return !COMMON_SHELL_VARIABLES.has(query);
|
|
27
28
|
}
|
|
28
|
-
function leadingKnownSkillRun(text, knownSkills) {
|
|
29
|
-
const tokens = text.trim().split(/\s+/).filter(Boolean);
|
|
30
|
-
return (tokens.length > 0 &&
|
|
31
|
-
tokens.every((token) => {
|
|
32
|
-
const match = DOLLAR_QUERY_PATTERN.exec(token);
|
|
33
|
-
if (match === null || match[1] === "")
|
|
34
|
-
return false;
|
|
35
|
-
const name = match[1].startsWith(SKILL_COMMAND_PREFIX)
|
|
36
|
-
? match[1].slice(SKILL_COMMAND_PREFIX.length)
|
|
37
|
-
: match[1];
|
|
38
|
-
return name !== "" && knownSkills.has(name);
|
|
39
|
-
}));
|
|
40
|
-
}
|
|
41
29
|
function commandName(command) {
|
|
42
30
|
return "name" in command ? command.name : command.value;
|
|
43
31
|
}
|
|
@@ -54,32 +42,58 @@ function commandDescription(command) {
|
|
|
54
42
|
return description ? `${hint} — ${description}` : hint;
|
|
55
43
|
return description || undefined;
|
|
56
44
|
}
|
|
57
|
-
|
|
58
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Locate every `$name` / `$skill:name` token on one line that names a known
|
|
47
|
+
* skill. Tokens must sit at a whitespace boundary, so `$HOME`, `$1`, `a$x`,
|
|
48
|
+
* and unknown names stay plain. Offsets are line-local and `end` is exclusive.
|
|
49
|
+
*/
|
|
50
|
+
export function findDollarSkillMentions(line, knownSkills) {
|
|
51
|
+
if (knownSkills.size === 0)
|
|
52
|
+
return [];
|
|
53
|
+
const mentions = [];
|
|
54
|
+
for (const match of line.matchAll(DOLLAR_MENTION_PATTERN)) {
|
|
55
|
+
const token = match[2] ?? "";
|
|
56
|
+
const name = token.startsWith(SKILL_COMMAND_PREFIX) ? token.slice(SKILL_COMMAND_PREFIX.length) : token;
|
|
57
|
+
if (!knownSkills.has(name))
|
|
58
|
+
continue;
|
|
59
|
+
const start = match.index + (match[1] ?? "").length;
|
|
60
|
+
mentions.push({ start, end: start + token.length + 1, name });
|
|
61
|
+
}
|
|
62
|
+
return mentions;
|
|
63
|
+
}
|
|
64
|
+
/** Names of the skills the command list exposes as `skill:<name>` entries. */
|
|
65
|
+
export function knownSkillNames(commands) {
|
|
66
|
+
return new Set(commands.flatMap((command) => {
|
|
59
67
|
const name = skillName(commandName(command));
|
|
60
68
|
return name ? [name] : [];
|
|
61
69
|
}));
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Describe the `$` token under the cursor when it should open the popup.
|
|
73
|
+
*
|
|
74
|
+
* Any `$query` at a whitespace boundary completes, however many `$` tokens
|
|
75
|
+
* precede it, so one prompt can carry several skill mentions. Slash commands
|
|
76
|
+
* are only offered while the token is the first thing in the prompt; a token
|
|
77
|
+
* that already names a known skill closes the popup so `enter` submits.
|
|
78
|
+
*/
|
|
79
|
+
export function getDollarInvocationContext(textBeforeCursor, _cursorLine, commands) {
|
|
62
80
|
const tokenStart = textBeforeCursor.search(/\S+$/);
|
|
63
81
|
const token = tokenStart === -1 ? "" : textBeforeCursor.slice(tokenStart);
|
|
64
82
|
const match = DOLLAR_QUERY_PATTERN.exec(token);
|
|
65
83
|
if (!match)
|
|
66
84
|
return null;
|
|
67
|
-
const rawQuery = match[1];
|
|
85
|
+
const rawQuery = match[1] ?? "";
|
|
68
86
|
if (!isDollarQueryCompletable(rawQuery))
|
|
69
87
|
return null;
|
|
70
88
|
const explicitSkillNamespace = rawQuery.startsWith(SKILL_COMMAND_PREFIX);
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
const hasKnownLeadingSkillRun = leadingKnownSkillRun(precedingText, knownSkills);
|
|
74
|
-
if (hasEarlierDollarToken && !hasKnownLeadingSkillRun)
|
|
75
|
-
return null;
|
|
76
|
-
const isKnownSkillInOrdinaryText = !hasKnownLeadingSkillRun && knownSkills.has(rawQuery);
|
|
77
|
-
if (isKnownSkillInOrdinaryText)
|
|
89
|
+
const query = explicitSkillNamespace ? rawQuery.slice(SKILL_COMMAND_PREFIX.length) : rawQuery;
|
|
90
|
+
if (knownSkillNames(commands).has(query))
|
|
78
91
|
return null;
|
|
92
|
+
const isFirstToken = textBeforeCursor.slice(0, tokenStart).trim() === "";
|
|
79
93
|
return {
|
|
80
94
|
prefix: `$${rawQuery}`,
|
|
81
|
-
query
|
|
82
|
-
skillsOnly:
|
|
95
|
+
query,
|
|
96
|
+
skillsOnly: explicitSkillNamespace || !isFirstToken,
|
|
83
97
|
};
|
|
84
98
|
}
|
|
85
99
|
export function getDollarInvocationSuggestions(commands, query, skillsOnly) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dollar-invocation-autocomplete.js","sourceRoot":"","sources":["../src/dollar-invocation-autocomplete.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AutocompleteItem, SlashCommand } from \"./autocomplete.ts\";\nimport { fuzzyFilter } from \"./fuzzy.ts\";\n\nconst SKILL_COMMAND_PREFIX = \"skill:\";\nconst DOLLAR_QUERY_PATTERN = /^\\$([a-zA-Z0-9:_-]*)$/;\nconst COMMON_SHELL_VARIABLES = new Set([\n\t\"CI\",\n\t\"EDITOR\",\n\t\"HOME\",\n\t\"LANG\",\n\t\"LC_ALL\",\n\t\"NODE_ENV\",\n\t\"OLDPWD\",\n\t\"PATH\",\n\t\"PWD\",\n\t\"SHELL\",\n\t\"SHLVL\",\n\t\"TERM\",\n\t\"TMPDIR\",\n\t\"USER\",\n\t\"VISUAL\",\n]);\n\ntype DollarInvocationItem = {\n\treadonly description?: string;\n\treadonly kind: \"command\" | \"skill\";\n\treadonly label: string;\n\treadonly searchText: string;\n\treadonly value: string;\n};\n\nexport interface DollarInvocationContext {\n\treadonly prefix: string;\n\treadonly query: string;\n\treadonly skillsOnly: boolean;\n}\n\nfunction isDollarQueryCompletable(query: string): boolean {\n\tif (query === \"\") return true;\n\tif (query.startsWith(\"-\") || query.startsWith(\"_\") || /^\\d/.test(query)) return false;\n\treturn !COMMON_SHELL_VARIABLES.has(query);\n}\n\nfunction leadingKnownSkillRun(text: string, knownSkills: ReadonlySet<string>): boolean {\n\tconst tokens = text.trim().split(/\\s+/).filter(Boolean);\n\treturn (\n\t\ttokens.length > 0 &&\n\t\ttokens.every((token) => {\n\t\t\tconst match = DOLLAR_QUERY_PATTERN.exec(token);\n\t\t\tif (match === null || match[1] === \"\") return false;\n\t\t\tconst name = match[1].startsWith(SKILL_COMMAND_PREFIX)\n\t\t\t\t? match[1].slice(SKILL_COMMAND_PREFIX.length)\n\t\t\t\t: match[1];\n\t\t\treturn name !== \"\" && knownSkills.has(name);\n\t\t})\n\t);\n}\n\nfunction commandName(command: SlashCommand | AutocompleteItem): string {\n\treturn \"name\" in command ? command.name : command.value;\n}\n\nfunction skillName(name: string): string | null {\n\tif (!name.startsWith(SKILL_COMMAND_PREFIX)) return null;\n\tconst value = name.slice(SKILL_COMMAND_PREFIX.length);\n\treturn value || null;\n}\n\nfunction commandDescription(command: SlashCommand | AutocompleteItem): string | undefined {\n\tconst hint = \"argumentHint\" in command && command.argumentHint ? command.argumentHint : undefined;\n\tconst description = command.description ?? \"\";\n\tif (hint) return description ? `${hint} — ${description}` : hint;\n\treturn description || undefined;\n}\n\nexport function getDollarInvocationContext(\n\ttextBeforeCursor: string,\n\t_cursorLine: number,\n\tcommands: readonly (SlashCommand | AutocompleteItem)[],\n): DollarInvocationContext | null {\n\tconst knownSkills = new Set(\n\t\tcommands.flatMap((command) => {\n\t\t\tconst name = skillName(commandName(command));\n\t\t\treturn name ? [name] : [];\n\t\t}),\n\t);\n\tconst tokenStart = textBeforeCursor.search(/\\S+$/);\n\tconst token = tokenStart === -1 ? \"\" : textBeforeCursor.slice(tokenStart);\n\tconst match = DOLLAR_QUERY_PATTERN.exec(token);\n\tif (!match) return null;\n\n\tconst rawQuery = match[1];\n\tif (!isDollarQueryCompletable(rawQuery)) return null;\n\tconst explicitSkillNamespace = rawQuery.startsWith(SKILL_COMMAND_PREFIX);\n\tconst precedingText = tokenStart === -1 ? \"\" : textBeforeCursor.slice(0, tokenStart);\n\tconst hasEarlierDollarToken = precedingText.includes(\"$\");\n\tconst hasKnownLeadingSkillRun = leadingKnownSkillRun(precedingText, knownSkills);\n\tif (hasEarlierDollarToken && !hasKnownLeadingSkillRun) return null;\n\tconst isKnownSkillInOrdinaryText = !hasKnownLeadingSkillRun && knownSkills.has(rawQuery);\n\tif (isKnownSkillInOrdinaryText) return null;\n\treturn {\n\t\tprefix: `$${rawQuery}`,\n\t\tquery: explicitSkillNamespace ? rawQuery.slice(SKILL_COMMAND_PREFIX.length) : rawQuery,\n\t\tskillsOnly: hasKnownLeadingSkillRun || explicitSkillNamespace,\n\t};\n}\n\nexport function getDollarInvocationSuggestions(\n\tcommands: readonly (SlashCommand | AutocompleteItem)[],\n\tquery: string,\n\tskillsOnly: boolean,\n): AutocompleteItem[] {\n\tconst items: DollarInvocationItem[] = commands.flatMap((command): DollarInvocationItem[] => {\n\t\tconst name = commandName(command);\n\t\tconst skill = skillName(name);\n\t\tif (skill) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tkind: \"skill\" as const,\n\t\t\t\t\tvalue: `$${skill}`,\n\t\t\t\t\tlabel: `$${skill}`,\n\t\t\t\t\tsearchText: skill,\n\t\t\t\t\tdescription: commandDescription(command),\n\t\t\t\t},\n\t\t\t];\n\t\t}\n\t\tif (skillsOnly) return [];\n\t\treturn [\n\t\t\t{\n\t\t\t\tkind: \"command\" as const,\n\t\t\t\tvalue: `/${name}`,\n\t\t\t\tlabel: `/${name}`,\n\t\t\t\tsearchText: name,\n\t\t\t\tdescription: commandDescription(command),\n\t\t\t},\n\t\t];\n\t});\n\n\treturn fuzzyFilter(items, query, (item) => item.searchText)\n\t\t.map((item, index) => ({ ...item, index }))\n\t\t.sort((left, right) => {\n\t\t\tif (left.kind !== right.kind) return left.kind === \"command\" ? -1 : 1;\n\t\t\treturn left.index - right.index;\n\t\t})\n\t\t.map(({ index: _index, kind: _kind, searchText: _searchText, ...item }) => item);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"dollar-invocation-autocomplete.js","sourceRoot":"","sources":["../src/dollar-invocation-autocomplete.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AutocompleteItem, SlashCommand } from \"./autocomplete.ts\";\nimport { fuzzyFilter } from \"./fuzzy.ts\";\n\nconst SKILL_COMMAND_PREFIX = \"skill:\";\nconst DOLLAR_QUERY_PATTERN = /^\\$([a-zA-Z0-9:_-]*)$/;\nconst DOLLAR_MENTION_PATTERN = /(^|\\s)\\$([a-zA-Z][a-zA-Z0-9:_-]*)(?=\\s|$)/g;\nconst COMMON_SHELL_VARIABLES = new Set([\n\t\"CI\",\n\t\"EDITOR\",\n\t\"HOME\",\n\t\"LANG\",\n\t\"LC_ALL\",\n\t\"NODE_ENV\",\n\t\"OLDPWD\",\n\t\"PATH\",\n\t\"PWD\",\n\t\"SHELL\",\n\t\"SHLVL\",\n\t\"TERM\",\n\t\"TMPDIR\",\n\t\"USER\",\n\t\"VISUAL\",\n]);\n\ntype DollarInvocationItem = {\n\treadonly description?: string;\n\treadonly kind: \"command\" | \"skill\";\n\treadonly label: string;\n\treadonly searchText: string;\n\treadonly value: string;\n};\n\nexport interface DollarInvocationContext {\n\treadonly prefix: string;\n\treadonly query: string;\n\treadonly skillsOnly: boolean;\n}\n\nexport interface DollarSkillMention {\n\treadonly start: number;\n\treadonly end: number;\n\treadonly name: string;\n}\n\nfunction isDollarQueryCompletable(query: string): boolean {\n\tif (query === \"\") return true;\n\tif (query.startsWith(\"-\") || query.startsWith(\"_\") || /^\\d/.test(query)) return false;\n\treturn !COMMON_SHELL_VARIABLES.has(query);\n}\n\nfunction commandName(command: SlashCommand | AutocompleteItem): string {\n\treturn \"name\" in command ? command.name : command.value;\n}\n\nfunction skillName(name: string): string | null {\n\tif (!name.startsWith(SKILL_COMMAND_PREFIX)) return null;\n\tconst value = name.slice(SKILL_COMMAND_PREFIX.length);\n\treturn value || null;\n}\n\nfunction commandDescription(command: SlashCommand | AutocompleteItem): string | undefined {\n\tconst hint = \"argumentHint\" in command && command.argumentHint ? command.argumentHint : undefined;\n\tconst description = command.description ?? \"\";\n\tif (hint) return description ? `${hint} — ${description}` : hint;\n\treturn description || undefined;\n}\n\n/**\n * Locate every `$name` / `$skill:name` token on one line that names a known\n * skill. Tokens must sit at a whitespace boundary, so `$HOME`, `$1`, `a$x`,\n * and unknown names stay plain. Offsets are line-local and `end` is exclusive.\n */\nexport function findDollarSkillMentions(line: string, knownSkills: ReadonlySet<string>): DollarSkillMention[] {\n\tif (knownSkills.size === 0) return [];\n\tconst mentions: DollarSkillMention[] = [];\n\tfor (const match of line.matchAll(DOLLAR_MENTION_PATTERN)) {\n\t\tconst token = match[2] ?? \"\";\n\t\tconst name = token.startsWith(SKILL_COMMAND_PREFIX) ? token.slice(SKILL_COMMAND_PREFIX.length) : token;\n\t\tif (!knownSkills.has(name)) continue;\n\t\tconst start = match.index + (match[1] ?? \"\").length;\n\t\tmentions.push({ start, end: start + token.length + 1, name });\n\t}\n\treturn mentions;\n}\n\n/** Names of the skills the command list exposes as `skill:<name>` entries. */\nexport function knownSkillNames(commands: readonly (SlashCommand | AutocompleteItem)[]): ReadonlySet<string> {\n\treturn new Set(\n\t\tcommands.flatMap((command) => {\n\t\t\tconst name = skillName(commandName(command));\n\t\t\treturn name ? [name] : [];\n\t\t}),\n\t);\n}\n\n/**\n * Describe the `$` token under the cursor when it should open the popup.\n *\n * Any `$query` at a whitespace boundary completes, however many `$` tokens\n * precede it, so one prompt can carry several skill mentions. Slash commands\n * are only offered while the token is the first thing in the prompt; a token\n * that already names a known skill closes the popup so `enter` submits.\n */\nexport function getDollarInvocationContext(\n\ttextBeforeCursor: string,\n\t_cursorLine: number,\n\tcommands: readonly (SlashCommand | AutocompleteItem)[],\n): DollarInvocationContext | null {\n\tconst tokenStart = textBeforeCursor.search(/\\S+$/);\n\tconst token = tokenStart === -1 ? \"\" : textBeforeCursor.slice(tokenStart);\n\tconst match = DOLLAR_QUERY_PATTERN.exec(token);\n\tif (!match) return null;\n\n\tconst rawQuery = match[1] ?? \"\";\n\tif (!isDollarQueryCompletable(rawQuery)) return null;\n\tconst explicitSkillNamespace = rawQuery.startsWith(SKILL_COMMAND_PREFIX);\n\tconst query = explicitSkillNamespace ? rawQuery.slice(SKILL_COMMAND_PREFIX.length) : rawQuery;\n\tif (knownSkillNames(commands).has(query)) return null;\n\tconst isFirstToken = textBeforeCursor.slice(0, tokenStart).trim() === \"\";\n\treturn {\n\t\tprefix: `$${rawQuery}`,\n\t\tquery,\n\t\tskillsOnly: explicitSkillNamespace || !isFirstToken,\n\t};\n}\n\nexport function getDollarInvocationSuggestions(\n\tcommands: readonly (SlashCommand | AutocompleteItem)[],\n\tquery: string,\n\tskillsOnly: boolean,\n): AutocompleteItem[] {\n\tconst items: DollarInvocationItem[] = commands.flatMap((command): DollarInvocationItem[] => {\n\t\tconst name = commandName(command);\n\t\tconst skill = skillName(name);\n\t\tif (skill) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tkind: \"skill\" as const,\n\t\t\t\t\tvalue: `$${skill}`,\n\t\t\t\t\tlabel: `$${skill}`,\n\t\t\t\t\tsearchText: skill,\n\t\t\t\t\tdescription: commandDescription(command),\n\t\t\t\t},\n\t\t\t];\n\t\t}\n\t\tif (skillsOnly) return [];\n\t\treturn [\n\t\t\t{\n\t\t\t\tkind: \"command\" as const,\n\t\t\t\tvalue: `/${name}`,\n\t\t\t\tlabel: `/${name}`,\n\t\t\t\tsearchText: name,\n\t\t\t\tdescription: commandDescription(command),\n\t\t\t},\n\t\t];\n\t});\n\n\treturn fuzzyFilter(items, query, (item) => item.searchText)\n\t\t.map((item, index) => ({ ...item, index }))\n\t\t.sort((left, right) => {\n\t\t\tif (left.kind !== right.kind) return left.kind === \"command\" ? -1 : 1;\n\t\t\treturn left.index - right.index;\n\t\t})\n\t\t.map(({ index: _index, kind: _kind, searchText: _searchText, ...item }) => item);\n}\n"]}
|
package/package.json
CHANGED