refactor: impl
This commit is contained in:
parent
c2c3956a82
commit
5d026dfd80
|
|
@ -39,4 +39,5 @@ export { TabBar } from './md-commander/TabBar';
|
||||||
export { TrackerView } from './md-commander/TrackerView';
|
export { TrackerView } from './md-commander/TrackerView';
|
||||||
export { CommanderEntries } from './md-commander/CommanderEntries';
|
export { CommanderEntries } from './md-commander/CommanderEntries';
|
||||||
export { CommanderInput } from './md-commander/CommanderInput';
|
export { CommanderInput } from './md-commander/CommanderInput';
|
||||||
export { useCommander, defaultCommands } from './md-commander/hooks';
|
export { useCommander } from './md-commander/hooks';
|
||||||
|
export { initializeCommands, getCommands } from './md-commander/stores/commandsStore';
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
export { useCommander, initializeCommands, defaultCommands } from "./useCommander";
|
export { useCommander } from "./useCommander";
|
||||||
export type { UseCommanderReturn } from "./useCommander";
|
export type { UseCommanderReturn } from "./useCommander";
|
||||||
export { rollSimple, rollFormula } from "./useDiceRoller";
|
export { rollSimple, rollFormula } from "./useDiceRoller";
|
||||||
export type { DiceRollerResult } from "./useDiceRoller";
|
export type { DiceRollerResult } from "./useDiceRoller";
|
||||||
|
|
|
||||||
|
|
@ -1,45 +1,14 @@
|
||||||
import { createSignal } from "solid-js";
|
import { createSignal } from "solid-js";
|
||||||
import type {
|
import type {
|
||||||
MdCommanderCommand,
|
|
||||||
MdCommanderCommandMap,
|
|
||||||
CommanderEntry,
|
CommanderEntry,
|
||||||
CompletionItem,
|
CompletionItem,
|
||||||
TrackerItem,
|
TrackerItem,
|
||||||
TrackerAttribute,
|
TrackerAttribute,
|
||||||
TrackerCommand,
|
TrackerCommand,
|
||||||
TrackerViewMode,
|
TrackerViewMode,
|
||||||
|
MdCommanderCommandMap,
|
||||||
} from "../types";
|
} from "../types";
|
||||||
import { parseInput, getCompletions } from "./completions";
|
import { parseInput, getCompletions } from "./completions";
|
||||||
import { setupHelpCommand, clearCommand, rollCommand, trackCommand, untrackCommand, listTrackCommand } from "../commands";
|
|
||||||
import {
|
|
||||||
addTrackerItem as addTracker,
|
|
||||||
removeTrackerItem as removeTracker,
|
|
||||||
updateTrackerAttribute as updateTrackerAttr,
|
|
||||||
updateTrackerClasses as updateTrackerClassesStore,
|
|
||||||
moveTrackerItem as moveTracker,
|
|
||||||
removeTrackerClass as removeClassFromTracker,
|
|
||||||
getTrackerItems,
|
|
||||||
getTrackerHistory,
|
|
||||||
findTrackerIndex,
|
|
||||||
} from "../stores";
|
|
||||||
|
|
||||||
// ==================== 默认命令 ====================
|
|
||||||
|
|
||||||
export const defaultCommands: MdCommanderCommandMap = {
|
|
||||||
help: { command: "help" }, // 占位,稍后初始化
|
|
||||||
clear: clearCommand,
|
|
||||||
roll: rollCommand,
|
|
||||||
track: trackCommand,
|
|
||||||
untrack: untrackCommand,
|
|
||||||
list: listTrackCommand,
|
|
||||||
};
|
|
||||||
|
|
||||||
// 初始化默认命令(包括 help)
|
|
||||||
export function initializeCommands(customCommands?: MdCommanderCommandMap): MdCommanderCommandMap {
|
|
||||||
const commands = { ...defaultCommands, ...customCommands };
|
|
||||||
commands.help = setupHelpCommand(commands);
|
|
||||||
return commands;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================== Commander Hook ====================
|
// ==================== Commander Hook ====================
|
||||||
|
|
||||||
|
|
@ -58,30 +27,31 @@ export interface UseCommanderReturn {
|
||||||
handleCommand: () => void;
|
handleCommand: () => void;
|
||||||
updateCompletions: () => void;
|
updateCompletions: () => void;
|
||||||
acceptCompletion: () => void;
|
acceptCompletion: () => void;
|
||||||
commands: MdCommanderCommandMap;
|
commands: () => MdCommanderCommandMap;
|
||||||
|
setCommands: (cmds: MdCommanderCommandMap) => void;
|
||||||
historyIndex: () => number;
|
historyIndex: () => number;
|
||||||
setHistoryIndex: (v: number) => void;
|
setHistoryIndex: (v: number) => void;
|
||||||
commandHistory: () => string[];
|
commandHistory: () => string[];
|
||||||
navigateHistory: (direction: 'up' | 'down') => void;
|
navigateHistory: (direction: "up" | "down") => void;
|
||||||
|
|
||||||
// Tracker 相关 - 直接暴露 store API
|
// Tracker 相关
|
||||||
viewMode: () => TrackerViewMode;
|
viewMode: () => TrackerViewMode;
|
||||||
setViewMode: (mode: TrackerViewMode) => void;
|
setViewMode: (mode: TrackerViewMode) => void;
|
||||||
trackerItems: () => TrackerItem[];
|
trackerItems: () => TrackerItem[];
|
||||||
trackerHistory: () => TrackerCommand[];
|
trackerHistory: () => TrackerCommand[];
|
||||||
addTrackerItem: typeof addTracker;
|
addTrackerItem: (item: Omit<TrackerItem, "id">) => TrackerItem;
|
||||||
removeTrackerItem: typeof removeTracker;
|
removeTrackerItem: (emmet: string) => boolean;
|
||||||
removeTrackerItemByIndex: (index: number) => void;
|
removeTrackerItemByIndex: (index: number) => void;
|
||||||
updateTrackerAttribute: typeof updateTrackerAttr;
|
updateTrackerAttribute: (emmet: string, attrName: string, attr: TrackerAttribute) => boolean;
|
||||||
updateTrackerAttributeByIndex: (index: number, attrName: string, attr: TrackerAttribute) => void;
|
updateTrackerAttributeByIndex: (index: number, attrName: string, attr: TrackerAttribute) => void;
|
||||||
updateTrackerClassesByIndex: (index: number, classes: string[]) => void;
|
updateTrackerClassesByIndex: (index: number, classes: string[]) => void;
|
||||||
moveTrackerItem: typeof moveTracker;
|
moveTrackerItem: (emmet: string, direction: "up" | "down") => boolean;
|
||||||
moveTrackerItemByIndex: (index: number, direction: 'up' | 'down') => void;
|
moveTrackerItemByIndex: (index: number, direction: "up" | "down") => void;
|
||||||
removeTrackerItemClass: typeof removeClassFromTracker;
|
removeTrackerItemClass: (emmet: string, className: string) => boolean;
|
||||||
removeTrackerItemClassByIndex: (index: number, className: string) => void;
|
removeTrackerItemClassByIndex: (index: number, className: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useCommander(customCommands?: MdCommanderCommandMap): UseCommanderReturn {
|
export function useCommander(initialCommands?: MdCommanderCommandMap): UseCommanderReturn {
|
||||||
const [inputValue, setInputValue] = createSignal("");
|
const [inputValue, setInputValue] = createSignal("");
|
||||||
const [entries, setEntries] = createSignal<CommanderEntry[]>([]);
|
const [entries, setEntries] = createSignal<CommanderEntry[]>([]);
|
||||||
const [showCompletions, setShowCompletions] = createSignal(false);
|
const [showCompletions, setShowCompletions] = createSignal(false);
|
||||||
|
|
@ -91,8 +61,7 @@ export function useCommander(customCommands?: MdCommanderCommandMap): UseCommand
|
||||||
const [commandHistory, setCommandHistory] = createSignal<string[]>([]);
|
const [commandHistory, setCommandHistory] = createSignal<string[]>([]);
|
||||||
const [historyIndex, setHistoryIndex] = createSignal(-1);
|
const [historyIndex, setHistoryIndex] = createSignal(-1);
|
||||||
const [viewMode, setViewMode] = createSignal<TrackerViewMode>("history");
|
const [viewMode, setViewMode] = createSignal<TrackerViewMode>("history");
|
||||||
|
const [commands, setCommands] = createSignal<MdCommanderCommandMap>(initialCommands || {});
|
||||||
const commands = initializeCommands(customCommands);
|
|
||||||
|
|
||||||
// ==================== 命令执行 ====================
|
// ==================== 命令执行 ====================
|
||||||
|
|
||||||
|
|
@ -100,9 +69,10 @@ export function useCommander(customCommands?: MdCommanderCommandMap): UseCommand
|
||||||
const input = inputValue().trim();
|
const input = inputValue().trim();
|
||||||
if (!input) return;
|
if (!input) return;
|
||||||
|
|
||||||
const parsed = parseInput(input, commands);
|
const cmds = commands();
|
||||||
|
const parsed = parseInput(input, cmds);
|
||||||
const commandName = parsed.command;
|
const commandName = parsed.command;
|
||||||
const cmd = commands[commandName!];
|
const cmd = cmds[commandName!];
|
||||||
|
|
||||||
let result: { message: string; type?: "success" | "error" | "warning" | "info"; isHtml?: boolean };
|
let result: { message: string; type?: "success" | "error" | "warning" | "info"; isHtml?: boolean };
|
||||||
|
|
||||||
|
|
@ -110,7 +80,7 @@ export function useCommander(customCommands?: MdCommanderCommandMap): UseCommand
|
||||||
result = { message: `未知命令:${commandName}`, type: "error" };
|
result = { message: `未知命令:${commandName}`, type: "error" };
|
||||||
} else if (cmd.handler) {
|
} else if (cmd.handler) {
|
||||||
try {
|
try {
|
||||||
result = cmd.handler({ params: parsed.params, options: parsed.options }, commands);
|
result = cmd.handler({ params: parsed.params, options: parsed.options }, cmds);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
result = {
|
result = {
|
||||||
message: `执行错误:${e instanceof Error ? e.message : String(e)}`,
|
message: `执行错误:${e instanceof Error ? e.message : String(e)}`,
|
||||||
|
|
@ -143,7 +113,7 @@ export function useCommander(customCommands?: MdCommanderCommandMap): UseCommand
|
||||||
// ==================== 自动补全 ====================
|
// ==================== 自动补全 ====================
|
||||||
|
|
||||||
const updateCompletions = () => {
|
const updateCompletions = () => {
|
||||||
const comps = getCompletions(inputValue(), commands);
|
const comps = getCompletions(inputValue(), commands());
|
||||||
setCompletions(comps);
|
setCompletions(comps);
|
||||||
setShowCompletions(comps.length > 0 && isFocused());
|
setShowCompletions(comps.length > 0 && isFocused());
|
||||||
setSelectedCompletionState(0);
|
setSelectedCompletionState(0);
|
||||||
|
|
@ -151,8 +121,8 @@ export function useCommander(customCommands?: MdCommanderCommandMap): UseCommand
|
||||||
|
|
||||||
const setSelectedCompletion = (v: number | ((prev: number) => number)) => {
|
const setSelectedCompletion = (v: number | ((prev: number) => number)) => {
|
||||||
const maxIdx = completions().length - 1;
|
const maxIdx = completions().length - 1;
|
||||||
if (typeof v === 'function') {
|
if (typeof v === "function") {
|
||||||
setSelectedCompletionState(prev => {
|
setSelectedCompletionState((prev) => {
|
||||||
const next = v(prev);
|
const next = v(prev);
|
||||||
return Math.max(0, Math.min(next, maxIdx));
|
return Math.max(0, Math.min(next, maxIdx));
|
||||||
});
|
});
|
||||||
|
|
@ -168,7 +138,7 @@ export function useCommander(customCommands?: MdCommanderCommandMap): UseCommand
|
||||||
if (!comp) return;
|
if (!comp) return;
|
||||||
|
|
||||||
const input = inputValue();
|
const input = inputValue();
|
||||||
const parsed = parseInput(input, commands);
|
const parsed = parseInput(input, commands());
|
||||||
let newValue: string;
|
let newValue: string;
|
||||||
|
|
||||||
if (comp.type === "command") {
|
if (comp.type === "command") {
|
||||||
|
|
@ -179,7 +149,7 @@ export function useCommander(customCommands?: MdCommanderCommandMap): UseCommand
|
||||||
.join(" ");
|
.join(" ");
|
||||||
newValue = `${parsed.command || ""} ${existingOptions}${existingOptions ? " " : ""}${comp.insertText}`;
|
newValue = `${parsed.command || ""} ${existingOptions}${existingOptions ? " " : ""}${comp.insertText}`;
|
||||||
} else if (comp.type === "value") {
|
} else if (comp.type === "value") {
|
||||||
const cmd = parsed.command ? commands[parsed.command] : null;
|
const cmd = parsed.command ? commands()[parsed.command] : null;
|
||||||
const paramDefs = cmd?.parameters || [];
|
const paramDefs = cmd?.parameters || [];
|
||||||
const usedParams = Object.keys(parsed.params);
|
const usedParams = Object.keys(parsed.params);
|
||||||
const isTypingLastParam = paramDefs.length === usedParams.length && !input.endsWith(" ");
|
const isTypingLastParam = paramDefs.length === usedParams.length && !input.endsWith(" ");
|
||||||
|
|
@ -204,12 +174,12 @@ export function useCommander(customCommands?: MdCommanderCommandMap): UseCommand
|
||||||
|
|
||||||
// ==================== 命令历史 ====================
|
// ==================== 命令历史 ====================
|
||||||
|
|
||||||
const navigateHistory = (direction: 'up' | 'down') => {
|
const navigateHistory = (direction: "up" | "down") => {
|
||||||
const history = commandHistory();
|
const history = commandHistory();
|
||||||
if (history.length === 0) return;
|
if (history.length === 0) return;
|
||||||
|
|
||||||
let newIndex = historyIndex();
|
let newIndex = historyIndex();
|
||||||
if (direction === 'up') {
|
if (direction === "up") {
|
||||||
if (newIndex < history.length - 1) newIndex++;
|
if (newIndex < history.length - 1) newIndex++;
|
||||||
} else {
|
} else {
|
||||||
if (newIndex > 0) {
|
if (newIndex > 0) {
|
||||||
|
|
@ -226,37 +196,47 @@ export function useCommander(customCommands?: MdCommanderCommandMap): UseCommand
|
||||||
};
|
};
|
||||||
|
|
||||||
// ==================== Tracker 操作 ====================
|
// ==================== Tracker 操作 ====================
|
||||||
|
const {
|
||||||
|
getTrackerItems,
|
||||||
|
getTrackerHistory,
|
||||||
|
addTrackerItem,
|
||||||
|
removeTrackerItem,
|
||||||
|
updateTrackerAttribute,
|
||||||
|
updateTrackerClasses,
|
||||||
|
moveTrackerItem,
|
||||||
|
removeTrackerClass,
|
||||||
|
} = require("../stores") as typeof import("../stores");
|
||||||
|
|
||||||
const getEmmetFromIndex = (index: number): string | null => {
|
const getEmmetFromIndex = (index: number): string | null => {
|
||||||
const items = getTrackerItems();
|
const items = getTrackerItems();
|
||||||
if (index < 0 || index >= items.length) return null;
|
if (index < 0 || index >= items.length) return null;
|
||||||
const item = items[index];
|
const item = items[index];
|
||||||
return `${item.tag}${item.id ? '#' + item.id : ''}${item.classes.length > 0 ? '.' + item.classes.join('.') : ''}`;
|
return `${item.tag}${item.id ? "#" + item.id : ""}${item.classes.length > 0 ? "." + item.classes.join(".") : ""}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeTrackerItemByIndex = (index: number) => {
|
const removeTrackerItemByIndex = (index: number) => {
|
||||||
const emmet = getEmmetFromIndex(index);
|
const emmet = getEmmetFromIndex(index);
|
||||||
if (emmet) removeTracker(emmet);
|
if (emmet) removeTrackerItem(emmet);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateTrackerAttributeByIndex = (index: number, attrName: string, attr: TrackerAttribute) => {
|
const updateTrackerAttributeByIndex = (index: number, attrName: string, attr: TrackerAttribute) => {
|
||||||
const emmet = getEmmetFromIndex(index);
|
const emmet = getEmmetFromIndex(index);
|
||||||
if (emmet) updateTrackerAttr(emmet, attrName, attr);
|
if (emmet) updateTrackerAttribute(emmet, attrName, attr);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateTrackerClassesByIndex = (index: number, classes: string[]) => {
|
const updateTrackerClassesByIndex = (index: number, classes: string[]) => {
|
||||||
const emmet = getEmmetFromIndex(index);
|
const emmet = getEmmetFromIndex(index);
|
||||||
if (emmet) updateTrackerClassesStore(emmet, classes);
|
if (emmet) updateTrackerClasses(emmet, classes);
|
||||||
};
|
};
|
||||||
|
|
||||||
const moveTrackerItemByIndex = (index: number, direction: 'up' | 'down') => {
|
const moveTrackerItemByIndex = (index: number, direction: "up" | "down") => {
|
||||||
const emmet = getEmmetFromIndex(index);
|
const emmet = getEmmetFromIndex(index);
|
||||||
if (emmet) moveTracker(emmet, direction);
|
if (emmet) moveTrackerItem(emmet, direction);
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeTrackerItemClassByIndex = (index: number, className: string) => {
|
const removeTrackerItemClassByIndex = (index: number, className: string) => {
|
||||||
const emmet = getEmmetFromIndex(index);
|
const emmet = getEmmetFromIndex(index);
|
||||||
if (emmet) removeClassFromTracker(emmet, className);
|
if (emmet) removeTrackerClass(emmet, className);
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -275,6 +255,7 @@ export function useCommander(customCommands?: MdCommanderCommandMap): UseCommand
|
||||||
updateCompletions,
|
updateCompletions,
|
||||||
acceptCompletion,
|
acceptCompletion,
|
||||||
commands,
|
commands,
|
||||||
|
setCommands,
|
||||||
historyIndex,
|
historyIndex,
|
||||||
setHistoryIndex,
|
setHistoryIndex,
|
||||||
commandHistory,
|
commandHistory,
|
||||||
|
|
@ -283,15 +264,15 @@ export function useCommander(customCommands?: MdCommanderCommandMap): UseCommand
|
||||||
setViewMode,
|
setViewMode,
|
||||||
trackerItems: getTrackerItems,
|
trackerItems: getTrackerItems,
|
||||||
trackerHistory: getTrackerHistory,
|
trackerHistory: getTrackerHistory,
|
||||||
addTrackerItem: addTracker,
|
addTrackerItem,
|
||||||
removeTrackerItem: removeTracker,
|
removeTrackerItem,
|
||||||
removeTrackerItemByIndex,
|
removeTrackerItemByIndex,
|
||||||
updateTrackerAttribute: updateTrackerAttr,
|
updateTrackerAttribute,
|
||||||
updateTrackerAttributeByIndex,
|
updateTrackerAttributeByIndex,
|
||||||
updateTrackerClassesByIndex,
|
updateTrackerClassesByIndex,
|
||||||
moveTrackerItem: moveTracker,
|
moveTrackerItem,
|
||||||
moveTrackerItemByIndex,
|
moveTrackerItemByIndex,
|
||||||
removeTrackerItemClass: removeClassFromTracker,
|
removeTrackerItemClass,
|
||||||
removeTrackerItemClassByIndex,
|
removeTrackerItemClassByIndex,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import { customElement, noShadowDOM } from "solid-element";
|
import { customElement, noShadowDOM } from "solid-element";
|
||||||
import { onMount, onCleanup, Show, createEffect } from "solid-js";
|
import { onMount, onCleanup, Show, createEffect, on } from "solid-js";
|
||||||
import { useCommander, initializeCommands } from "./hooks";
|
import { useCommander } from "./hooks";
|
||||||
import { CommanderInput } from "./CommanderInput";
|
import { CommanderInput } from "./CommanderInput";
|
||||||
import { CommanderEntries } from "./CommanderEntries";
|
import { CommanderEntries } from "./CommanderEntries";
|
||||||
import { TrackerView } from "./TrackerView";
|
import { TrackerView } from "./TrackerView";
|
||||||
import { TabBar } from "./TabBar";
|
import { TabBar } from "./TabBar";
|
||||||
import type { MdCommanderProps } from "./types";
|
import type { MdCommanderProps } from "./types";
|
||||||
import { loadElementSrc, resolvePath } from "../utils/path";
|
import { loadElementSrc, resolvePath } from "../utils/path";
|
||||||
import { loadCommandTemplates } from "./utils/commandTemplates";
|
import { initializeCommands, loadCommandTemplatesFromCSV } from "./stores/commandsStore";
|
||||||
|
|
||||||
customElement<MdCommanderProps>(
|
customElement<MdCommanderProps>(
|
||||||
"md-commander",
|
"md-commander",
|
||||||
|
|
@ -15,13 +15,21 @@ customElement<MdCommanderProps>(
|
||||||
(props, { element }) => {
|
(props, { element }) => {
|
||||||
noShadowDOM();
|
noShadowDOM();
|
||||||
const { articlePath, rawSrc } = loadElementSrc(element as any);
|
const { articlePath, rawSrc } = loadElementSrc(element as any);
|
||||||
const commander = useCommander(props.commands);
|
|
||||||
|
|
||||||
createEffect(async () => {
|
// 初始化命令并注册到 store
|
||||||
if (!rawSrc) return;
|
const commands = initializeCommands(props.commands);
|
||||||
const commands = initializeCommands(props.commands);
|
const commander = useCommander(commands);
|
||||||
await loadCommandTemplates(commands, resolvePath(articlePath, rawSrc));
|
|
||||||
});
|
// 加载 CSV 模板
|
||||||
|
createEffect(
|
||||||
|
on(() => props.commandTemplates, async (csvPaths) => {
|
||||||
|
if (!csvPaths || !rawSrc) return;
|
||||||
|
await loadCommandTemplatesFromCSV(csvPaths, resolvePath, articlePath);
|
||||||
|
// 更新 commander 中的命令(从 store 获取)
|
||||||
|
const { getCommands } = await import("./stores/commandsStore");
|
||||||
|
commander.setCommands(getCommands());
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
if (commander.showCompletions() && commander.completions().length > 0) {
|
if (commander.showCompletions() && commander.completions().length > 0) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
import { createStore } from "solid-js/store";
|
||||||
|
import type { MdCommanderCommand, MdCommanderCommandMap } from "../types";
|
||||||
|
import { setupHelpCommand, clearCommand, rollCommand, trackCommand, untrackCommand, listTrackCommand } from "../commands";
|
||||||
|
|
||||||
|
const defaultCommands: MdCommanderCommandMap = {
|
||||||
|
help: setupHelpCommand({}),
|
||||||
|
clear: clearCommand,
|
||||||
|
roll: rollCommand,
|
||||||
|
track: trackCommand,
|
||||||
|
untrack: untrackCommand,
|
||||||
|
list: listTrackCommand,
|
||||||
|
};
|
||||||
|
|
||||||
|
const [commandsStore, setCommandsStore] = createStore<{
|
||||||
|
commands: MdCommanderCommandMap;
|
||||||
|
initialized: boolean;
|
||||||
|
}>({
|
||||||
|
commands: { ...defaultCommands },
|
||||||
|
initialized: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化命令(包括 help 命令的动态更新)
|
||||||
|
*/
|
||||||
|
export function initializeCommands(customCommands?: MdCommanderCommandMap): MdCommanderCommandMap {
|
||||||
|
const commands = { ...defaultCommands, ...customCommands };
|
||||||
|
// 更新 help 命令的命令列表
|
||||||
|
commands.help = setupHelpCommand(commands);
|
||||||
|
return commands;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册命令到 store
|
||||||
|
*/
|
||||||
|
export function registerCommands(customCommands?: MdCommanderCommandMap): void {
|
||||||
|
const commands = initializeCommands(customCommands);
|
||||||
|
setCommandsStore({ commands, initialized: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 store 获取命令
|
||||||
|
*/
|
||||||
|
export function getCommands(): MdCommanderCommandMap {
|
||||||
|
return commandsStore.commands;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查命令是否已初始化
|
||||||
|
*/
|
||||||
|
export function isCommandsInitialized(): boolean {
|
||||||
|
return commandsStore.initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取单个命令
|
||||||
|
*/
|
||||||
|
export function getCommand(name: string): MdCommanderCommand | undefined {
|
||||||
|
return commandsStore.commands[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 CSV 文件加载命令模板并更新命令定义
|
||||||
|
*/
|
||||||
|
export async function loadCommandTemplatesFromCSV(
|
||||||
|
csvPaths: string | string[],
|
||||||
|
resolvePath: (base: string, path: string) => string,
|
||||||
|
articlePath: string
|
||||||
|
): Promise<void> {
|
||||||
|
const paths = Array.isArray(csvPaths) ? csvPaths : [csvPaths];
|
||||||
|
|
||||||
|
for (const path of paths) {
|
||||||
|
try {
|
||||||
|
const { loadCSV } = await import("../../utils/csv-loader");
|
||||||
|
const csv = await loadCSV<CommandTemplateRow>(resolvePath(articlePath, path));
|
||||||
|
|
||||||
|
// 按命令分组模板
|
||||||
|
const templatesByCommand = new Map<string, CommandTemplateRow[]>();
|
||||||
|
for (const row of csv) {
|
||||||
|
if (!row.command || !row.label || !row.insertedText) continue;
|
||||||
|
|
||||||
|
if (!templatesByCommand.has(row.command)) {
|
||||||
|
templatesByCommand.set(row.command, []);
|
||||||
|
}
|
||||||
|
templatesByCommand.get(row.command)!.push(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为每个命令添加模板
|
||||||
|
setCommandsStore("commands", (prev) => {
|
||||||
|
const updated = { ...prev };
|
||||||
|
for (const [commandName, rows] of templatesByCommand.entries()) {
|
||||||
|
const cmd = updated[commandName];
|
||||||
|
if (!cmd || !cmd.parameters) continue;
|
||||||
|
|
||||||
|
const templates = rows.map((row) => ({
|
||||||
|
label: row.label,
|
||||||
|
description: row.description || "",
|
||||||
|
insertText: row.insertedText,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 为每个参数添加模板
|
||||||
|
updated[commandName] = {
|
||||||
|
...cmd,
|
||||||
|
parameters: cmd.parameters.map((param) => ({
|
||||||
|
...param,
|
||||||
|
templates: param.templates ? [...param.templates, ...templates] : templates,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return updated;
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`Error loading command templates from ${path}:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CommandTemplateRow {
|
||||||
|
command: string;
|
||||||
|
parameter: string;
|
||||||
|
label: string;
|
||||||
|
description: string;
|
||||||
|
insertedText: string;
|
||||||
|
}
|
||||||
|
|
@ -12,3 +12,12 @@ export {
|
||||||
findTrackerItem,
|
findTrackerItem,
|
||||||
} from "./trackerStore";
|
} from "./trackerStore";
|
||||||
export type { TrackerStore } from "./trackerStore";
|
export type { TrackerStore } from "./trackerStore";
|
||||||
|
|
||||||
|
export {
|
||||||
|
initializeCommands,
|
||||||
|
registerCommands,
|
||||||
|
getCommands,
|
||||||
|
isCommandsInitialized,
|
||||||
|
getCommand,
|
||||||
|
loadCommandTemplatesFromCSV,
|
||||||
|
} from "./commandsStore";
|
||||||
|
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
import type { MdCommanderCommandMap, MdCommanderTemplate } from "../types";
|
|
||||||
import { loadCSV } from "../../utils/csv-loader";
|
|
||||||
|
|
||||||
export interface CommandTemplateRow {
|
|
||||||
command: string;
|
|
||||||
parameter: string;
|
|
||||||
label: string;
|
|
||||||
description: string;
|
|
||||||
insertedText: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从 CSV 内容构建命令模板
|
|
||||||
*/
|
|
||||||
function buildTemplatesFromRows(rows: CommandTemplateRow[]): MdCommanderTemplate[] {
|
|
||||||
return rows.map(row => ({
|
|
||||||
label: row.label,
|
|
||||||
description: row.description || "",
|
|
||||||
insertText: row.insertedText,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从 CSV 文件加载命令模板并更新命令定义
|
|
||||||
*/
|
|
||||||
export async function loadCommandTemplates(
|
|
||||||
commands: MdCommanderCommandMap,
|
|
||||||
csvPaths: string | string[]
|
|
||||||
): Promise<MdCommanderCommandMap> {
|
|
||||||
const paths = Array.isArray(csvPaths) ? csvPaths : [csvPaths];
|
|
||||||
|
|
||||||
for (const path of paths) {
|
|
||||||
try {
|
|
||||||
const csv = await loadCSV<CommandTemplateRow>(path);
|
|
||||||
|
|
||||||
// 按命令分组模板
|
|
||||||
const templatesByCommand = new Map<string, CommandTemplateRow[]>();
|
|
||||||
for (const row of csv) {
|
|
||||||
if (!row.command || !row.label || !row.insertedText) continue;
|
|
||||||
|
|
||||||
if (!templatesByCommand.has(row.command)) {
|
|
||||||
templatesByCommand.set(row.command, []);
|
|
||||||
}
|
|
||||||
templatesByCommand.get(row.command)!.push(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 为每个命令添加模板
|
|
||||||
for (const [commandName, rows] of templatesByCommand.entries()) {
|
|
||||||
const cmd = commands[commandName];
|
|
||||||
if (!cmd || !cmd.parameters) continue;
|
|
||||||
|
|
||||||
const templates = buildTemplatesFromRows(rows);
|
|
||||||
|
|
||||||
// 为每个参数添加模板
|
|
||||||
for (const param of cmd.parameters) {
|
|
||||||
if (!param.templates) {
|
|
||||||
param.templates = [];
|
|
||||||
}
|
|
||||||
// 添加新模板
|
|
||||||
param.templates.push(...templates);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.warn(`Error loading command templates from ${path}:`, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return commands;
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue