mirror of
https://github.com/earendil-works/pi.git
synced 2026-10-02 00:35:27 +08:00
fix(tui): complete slash commands after leading whitespace (#10218)
This commit is contained in:
@@ -335,11 +335,12 @@ export class CombinedAutocompleteProvider implements AutocompleteProvider {
|
||||
};
|
||||
}
|
||||
|
||||
if (!options.force && textBeforeCursor.startsWith("/")) {
|
||||
const spaceIndex = textBeforeCursor.indexOf(" ");
|
||||
const commandText = textBeforeCursor.trimStart();
|
||||
if (!options.force && commandText.startsWith("/")) {
|
||||
const spaceIndex = commandText.indexOf(" ");
|
||||
|
||||
if (spaceIndex === -1) {
|
||||
const prefix = textBeforeCursor.slice(1);
|
||||
const prefix = commandText.slice(1);
|
||||
const commandItems = this.commands.map((cmd) => {
|
||||
const name = "name" in cmd ? cmd.name : cmd.value;
|
||||
const hint = "argumentHint" in cmd && cmd.argumentHint ? cmd.argumentHint : undefined;
|
||||
@@ -371,12 +372,12 @@ export class CombinedAutocompleteProvider implements AutocompleteProvider {
|
||||
|
||||
return {
|
||||
items: filtered,
|
||||
prefix: textBeforeCursor,
|
||||
prefix: commandText,
|
||||
};
|
||||
}
|
||||
|
||||
const commandName = textBeforeCursor.slice(1, spaceIndex);
|
||||
const argumentText = textBeforeCursor.slice(spaceIndex + 1);
|
||||
const commandName = commandText.slice(1, spaceIndex);
|
||||
const argumentText = commandText.slice(spaceIndex + 1);
|
||||
|
||||
const command = this.commands.find((cmd) => {
|
||||
const name = "name" in cmd ? cmd.name : cmd.value;
|
||||
|
||||
@@ -32,6 +32,51 @@ describe("CombinedAutocompleteProvider slash-command filter", () => {
|
||||
assert.ok(items.includes("model"));
|
||||
});
|
||||
|
||||
it("completes commands after leading whitespace and preserves it", async () => {
|
||||
const provider = new CombinedAutocompleteProvider([{ name: "model" }], process.cwd());
|
||||
for (const [line, expected] of [
|
||||
[" /", " /model "],
|
||||
[" /mod", " /model "],
|
||||
["\t/mod", "\t/model "],
|
||||
] as const) {
|
||||
const result = await provider.getSuggestions([line], 0, line.length, {
|
||||
signal: new AbortController().signal,
|
||||
});
|
||||
assert.ok(result);
|
||||
assert.equal(result.prefix, line.trimStart());
|
||||
assert.deepStrictEqual(
|
||||
result.items.map((item) => item.value),
|
||||
["model"],
|
||||
);
|
||||
const applied = provider.applyCompletion([line], 0, line.length, result.items[0]!, result.prefix);
|
||||
assert.equal(applied.lines[0], expected);
|
||||
assert.equal(applied.cursorCol, expected.length);
|
||||
}
|
||||
});
|
||||
|
||||
it("completes command arguments after leading whitespace", async () => {
|
||||
const provider = new CombinedAutocompleteProvider(
|
||||
[
|
||||
{
|
||||
name: "model",
|
||||
getArgumentCompletions: (prefix: string) => {
|
||||
assert.equal(prefix, "son");
|
||||
return [{ value: "sonnet", label: "sonnet" }];
|
||||
},
|
||||
},
|
||||
],
|
||||
process.cwd(),
|
||||
);
|
||||
const line = " /model son";
|
||||
const result = await provider.getSuggestions([line], 0, line.length, {
|
||||
signal: new AbortController().signal,
|
||||
});
|
||||
assert.ok(result);
|
||||
assert.equal(result.prefix, "son");
|
||||
const applied = provider.applyCompletion([line], 0, line.length, result.items[0]!, result.prefix);
|
||||
assert.equal(applied.lines[0], " /model sonnet");
|
||||
});
|
||||
|
||||
it("keeps explicit skill: queries working", async () => {
|
||||
const items = await suggestionsFor("skill:side");
|
||||
assert.ok(items.includes("skill:to-sidecar"));
|
||||
|
||||
Reference in New Issue
Block a user