fix: completion

This commit is contained in:
hypercross 2026-03-01 11:08:58 +08:00
parent 90b0346b65
commit 05c93e0301
1 changed files with 70 additions and 21 deletions

View File

@ -118,7 +118,8 @@ export function parseInput(input: string, commands?: MdCommanderCommandMap): {
// 检查是否有未完成的位置参数 // 检查是否有未完成的位置参数
if (paramIndex < paramDefs.length) { if (paramIndex < paramDefs.length) {
const lastPart = parts[parts.length - 1]; const lastPart = parts[parts.length - 1];
if (lastPart && !lastPart.startsWith("-")) { // 只有当最后一个部分不是命令本身时,才设置为未完成参数
if (lastPart && !lastPart.startsWith("-") && parts.length > 1) {
result.incompleteParam = { result.incompleteParam = {
index: paramIndex, index: paramIndex,
value: lastPart, value: lastPart,
@ -167,30 +168,65 @@ export function getCompletions(
const paramDefs = cmd.parameters || []; const paramDefs = cmd.parameters || [];
const usedParams = Object.keys(parsed.params); const usedParams = Object.keys(parsed.params);
// 如果还有未填的参数,提供参数值补全 // 判断是否正在输入最后一个参数(没有尾随空格)
if (paramDefs.length > usedParams.length) { const isTypingLastParam = paramDefs.length === usedParams.length &&
const paramDef = paramDefs[usedParams.length]; trimmed.length > 0 &&
!trimmed.endsWith(" ") &&
!trimmed.split(/\s+/)[trimmed.split(/\s+/).length - 1].startsWith("-");
// 如果还有未填的参数,或者当前参数可能未完成
if (paramDefs.length > usedParams.length || parsed.incompleteParam || isTypingLastParam) {
// 确定当前参数的索引
let paramIndex: number;
if (parsed.incompleteParam !== undefined) {
paramIndex = parsed.incompleteParam.index;
} else if (isTypingLastParam) {
// 正在编辑最后一个参数
paramIndex = paramDefs.length - 1;
} else {
paramIndex = usedParams.length;
}
const paramDef = paramDefs[paramIndex];
if (!paramDef) return [];
// 获取当前输入值
let currentValue = parsed.incompleteParam?.value || "";
if (isTypingLastParam && !parsed.incompleteParam) {
const parts = trimmed.split(/\s+/);
currentValue = parts[parts.length - 1] || "";
}
// 模板补全
if (paramDef.templates) {
return paramDef.templates
.filter((t) => t.label.toLowerCase().includes(currentValue.toLowerCase()))
.map((t) => ({
label: t.label,
type: "value" as "value",
description: t.description,
insertText: t.insertText,
}));
}
if (paramDef.type === "enum" && paramDef.values) { if (paramDef.type === "enum" && paramDef.values) {
const currentValue = parsed.incompleteParam?.value || "";
return paramDef.values return paramDef.values
.filter((v) => v.startsWith(currentValue)) .filter((v) => v.startsWith(currentValue))
.map((v) => ({ .map((v) => ({
label: v, label: v,
type: "value", type: "value" as "value",
description: paramDef.description, description: paramDef.description,
insertText: v, insertText: v,
})); }));
} }
// 其他类型的参数,显示提示 // 其他类型的参数,显示提示
if (parsed.incompleteParam) {
return [{ return [{
label: `<${paramDef.name}>`, label: `<${paramDef.name}>`,
type: "value", type: "value" as "value",
description: `${paramDef.type}${paramDef.required !== false ? " (必填)" : ""}: ${paramDef.description || ""}`, description: `${paramDef.type}${paramDef.required !== false ? " (必填)" : ""}: ${paramDef.description || ""}`,
insertText: "", insertText: "",
}]; }];
} }
}
// 选项补全 // 选项补全
if (!cmd.options) return []; if (!cmd.options) return [];
@ -369,6 +405,7 @@ export function useCommander(
if (!comp) return; if (!comp) return;
const input = inputValue(); const input = inputValue();
const trimmed = input.trim();
const parsed = parseInput(input, commands); const parsed = parseInput(input, commands);
let newValue: string; let newValue: string;
@ -386,13 +423,25 @@ export function useCommander(
const paramDefs = cmd?.parameters || []; const paramDefs = cmd?.parameters || [];
const usedParams = Object.keys(parsed.params); const usedParams = Object.keys(parsed.params);
if (paramDefs.length > usedParams.length) {
// 当前参数的补全
const base = parsed.command || ""; const base = parsed.command || "";
const existingParams = Object.values(parsed.params).join(" ");
const existingOptions = Object.entries(parsed.options) const existingOptions = Object.entries(parsed.options)
.map(([k, v]) => `--${k}=${v}`) .map(([k, v]) => `--${k}=${v}`)
.join(" "); .join(" ");
// 判断是否正在编辑最后一个参数(使用原始 input 检查尾随空格)
const isTypingLastParam = paramDefs.length === usedParams.length &&
input.length > 0 &&
!input.endsWith(" ");
if (isTypingLastParam) {
// 替换最后一个参数
const parts = trimmed.split(/\s+/);
parts.pop(); // 移除正在输入的参数
const existingParams = parts.slice(1).join(" "); // 跳过命令
newValue = `${base}${existingParams ? " " + existingParams : ""} ${comp.insertText}${existingOptions ? " " + existingOptions : ""}`;
} else if (paramDefs.length > usedParams.length) {
// 当前参数的补全
const existingParams = Object.values(parsed.params).join(" ");
newValue = `${base} ${existingParams}${existingParams ? " " : ""}${comp.insertText}${existingOptions ? " " + existingOptions : ""}`; newValue = `${base} ${existingParams}${existingParams ? " " : ""}${comp.insertText}${existingOptions ? " " + existingOptions : ""}`;
} else { } else {
newValue = input; newValue = input;