import type { MdCommanderCommandMap, CompletionItem } from "../types"; export interface ParsedCommand { command?: string; params: Record; options: Record; incompleteParam?: { index: number; value: string }; } /** * 解析命令行输入 */ export function parseInput(input: string, commands?: MdCommanderCommandMap): ParsedCommand { const result: ParsedCommand = { params: {}, options: {} }; const trimmed = input.trim(); if (!trimmed) return result; const parts = trimmed.split(/\s+/); let i = 0; // 获取命令 if (parts[0] && !parts[0].startsWith("-")) { result.command = parts[0]; i = 1; } // 获取命令的参数定义 const cmd = result.command ? commands?.[result.command] : undefined; const paramDefs = cmd?.parameters || []; let paramIndex = 0; // 解析参数和选项 while (i < parts.length) { const part = parts[i]; if (part.startsWith("--")) { const eqIndex = part.indexOf("="); if (eqIndex !== -1) { result.options[part.slice(2, eqIndex)] = part.slice(eqIndex + 1); } else { const key = part.slice(2); if (i + 1 < parts.length && !parts[i + 1].startsWith("-")) { result.options[key] = parts[i + 1]; i++; } } } else if (part.startsWith("-") && part.length === 2) { const key = part.slice(1); if (i + 1 < parts.length && !parts[i + 1].startsWith("-")) { result.options[key] = parts[i + 1]; i++; } } else if (paramIndex < paramDefs.length) { result.params[paramDefs[paramIndex].name] = part; paramIndex++; } i++; } // 检查是否有未完成的位置参数 if (paramIndex < paramDefs.length) { const lastPart = parts[parts.length - 1]; if (lastPart && !lastPart.startsWith("-") && parts.length > 1) { result.incompleteParam = { index: paramIndex, value: lastPart }; } } return result; } /** * 获取自动补全建议 */ export function getCompletions(input: string, commands: MdCommanderCommandMap): CompletionItem[] { const trimmed = input.trim(); // 空输入时返回所有命令 if (!trimmed || /^\s*$/.test(trimmed)) { return Object.values(commands).map((cmd) => ({ label: cmd.command, type: "command", description: cmd.description, insertText: cmd.command, })); } const parsed = parseInput(trimmed, commands); // 命令补全 if (!parsed.command || !commands[parsed.command]) { return Object.values(commands) .filter((cmd) => cmd.command.startsWith(parsed.command || "")) .map((cmd) => ({ label: cmd.command, type: "command", description: cmd.description, insertText: cmd.command, })); } const cmd = commands[parsed.command]; if (!cmd) return []; const paramDefs = cmd.parameters || []; const usedParams = Object.keys(parsed.params); // 判断是否正在输入最后一个参数 const isTypingLastParam = paramDefs.length === 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 = parsed.incompleteParam?.index ?? (isTypingLastParam ? paramDefs.length - 1 : 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", description: t.description, insertText: t.insertText, })); } // 枚举补全 if (paramDef.type === "enum" && paramDef.values) { return paramDef.values .filter((v) => v.startsWith(currentValue)) .map((v) => ({ label: v, type: "value", description: paramDef.description, insertText: v, })); } // 其他类型显示提示 return [{ label: `<${paramDef.name}>`, type: "value", description: `${paramDef.type}${paramDef.required !== false ? " (必填)" : ""}: ${paramDef.description || ""}`, insertText: "", }]; } // 选项补全 if (!cmd.options) return []; const usedOptions = Object.keys(parsed.options); return Object.values(cmd.options) .filter((opt) => !usedOptions.includes(opt.option)) .map((opt) => ({ label: `--${opt.option}`, type: "option", description: opt.description, insertText: `--${opt.option}=${opt.type === "boolean" ? "" : ""}`, })); } /** * 根据结果类型获取 CSS 类名 */ export function getResultClass(type?: "success" | "error" | "warning" | "info"): string { switch (type) { case "success": return "text-green-600"; case "error": return "text-red-600"; case "warning": return "text-yellow-600"; default: return "text-blue-600"; } }