/** * 명령 레지스트리 — 리본·명령행·단축키가 읽는 단일 소스. * 새 명령은 commands.*.ts에 한 줄 추가하면 세 곳에 동시에 나타난다. */ import type { AnyToolMachine, CadCommand } from './command.types'; import type { Tool } from '../tools'; import { DIMENSION_COMMANDS, LEADER_COMMANDS, MARKUP_COMMANDS, TABLE_COMMANDS, TEXT_COMMANDS, } from './commands.annotate'; import { DRAW_COMMANDS } from './commands.draw'; import { FILE_COMMANDS } from './commands.file'; import { INSERT_COMMANDS } from './commands.insert'; import { LAYER_COMMANDS } from './commands.layer'; import { CLIPBOARD_COMMANDS, GROUP_COMMANDS, INQUIRY_COMMANDS, PROPERTY_COMMANDS, } from './commands.utility'; import { ALIGN_COMMANDS, MODIFY_COMMANDS } from './commands.modify'; import { VIEW_COMMANDS } from './commands.view'; import { inputPrefs } from '../../../../A00_Common/input_prefs'; import '../tools/factories/end-command'; // 명령 끝 → 쉬는 상태 갈고리 const ALL_COMMANDS: CadCommand[] = [ ...DRAW_COMMANDS, ...MODIFY_COMMANDS, ...ALIGN_COMMANDS, ...TEXT_COMMANDS, ...DIMENSION_COMMANDS, ...LEADER_COMMANDS, ...TABLE_COMMANDS, ...MARKUP_COMMANDS, ...LAYER_COMMANDS, ...PROPERTY_COMMANDS, ...GROUP_COMMANDS, ...INQUIRY_COMMANDS, ...CLIPBOARD_COMMANDS, ...INSERT_COMMANDS, ...VIEW_COMMANDS, ...FILE_COMMANDS, ]; const COMMANDS_BY_ID = new Map( ALL_COMMANDS.map((command) => [command.id, command]) ); const COMMANDS_BY_ALIAS = new Map(); for (const command of ALL_COMMANDS) { for (const alias of command.aliases ?? []) { if (!COMMANDS_BY_ALIAS.has(alias)) { COMMANDS_BY_ALIAS.set(alias, command); } } } /** * 확정한 도면에서도 쓸 수 있는 명령 — **보는 일만 하는 것들**이다 * (2026-09-01 사용자 확정: 확정하면 수정이 안 되고, 풀려면 [수정]을 누른다). * * 허용을 명시하는 쪽으로 짠다. 새 편집 명령이 늘어도 자동으로 막히고, 반대로 짜면 * 새 명령마다 여기 적어야 해 언젠가 빠뜨린다. */ const VIEW_ONLY_COMMAND_IDS: ReadonlySet = new Set([ // 보기 — 확대·이동·다시그리기·선택 ...VIEW_COMMANDS.map((command) => command.id), // 조회 — 거리·면적·각도처럼 재기만 하는 것 ...INQUIRY_COMMANDS.map((command) => command.id), // 도면층 보이기·잠금 — 객체를 건드리지 않는 것만 (LAYMCH·LAYCUR·LAYMRG·LAYDEL 제외) 'LAYER', 'LAYCURSET', 'LAYOFF', 'LAYON', 'LAYFRZ', 'LAYTHW', 'LAYLCK', 'LAYULK', 'LAYISO', 'LAYUNISO', 'LAYERP', 'LAYERSTATE', 'LAYERSTATERESTORE', 'LAYWALK', // 파일 — 내보내기와 클립보드 복사는 도면을 바꾸지 않는다 'EXPORT', 'EXPORTSVG', 'EXPORTPNG', 'COPYCLIP', 'COPYBASE', 'TOAREA', // 고른 범위 → 면적산출 표(M02 83장) ]); /** 확정한 도면에서 이 명령을 실행해도 되는가. */ export const isViewOnlyCommand = (command: CadCommand): boolean => VIEW_ONLY_COMMAND_IDS.has(command.id); export const getAllCommands = (): CadCommand[] => ALL_COMMANDS; export const getCommandById = (id: string): CadCommand | undefined => COMMANDS_BY_ID.get(id); /** 활성 도구로 어떤 명령이 실행 중인지 되짚는다 (리본 강조·상태 표시용) */ export const getCommandByTool = (tool: Tool | null): CadCommand | undefined => tool ? ALL_COMMANDS.find((command) => command.tool === tool) : undefined; /** 도구형 명령의 xstate 머신 표 — 도구 활성화 경로가 이 표만 본다 */ export const TOOL_STATE_MACHINES = Object.fromEntries( ALL_COMMANDS.filter((command) => command.tool && command.machine).map((command) => [ command.tool, command.machine, ]) ) as Record; /** 내 별칭(☰ [설정] · `cadAliases`) 이 가리키는 명령들 — 부를 때마다 읽어 저장 즉시 따름 */ function userAliasCommands(match: (alias: string) => boolean): CadCommand[] { return Object.entries(inputPrefs().cadAliases).flatMap(([id, aliases]) => { const command = COMMANDS_BY_ID.get(id); return command && aliases.some(match) ? [command] : []; }); } /** 명령행 입력 해석 — 이름 > 내 별칭 > 기본 별칭(acad.pgp 식) 딱 맞음만(앞글자 실행 없음 · 후보는 목록) */ export function resolveCommandInput(input: string): CadCommand | undefined { const text = input.trim().toUpperCase().replace(/^_/, ''); if (!text) return undefined; return ( COMMANDS_BY_ID.get(text) ?? userAliasCommands((alias) => alias === text)[0] ?? COMMANDS_BY_ALIAS.get(text) ); } /** 접두사가 같은 명령 후보 (커서 옆 자동완성 목록에 쓴다) */ export function matchCommandPrefixes(input: string): CadCommand[] { const text = input.trim().toUpperCase(); if (!text) return []; const byAlias = ALL_COMMANDS.filter((command) => (command.aliases ?? []).some((alias) => alias.startsWith(text)) ); const byId = ALL_COMMANDS.filter((command) => command.id.startsWith(text)); const byUser = userAliasCommands((alias) => alias.startsWith(text)); return [...new Set([...byUser, ...byAlias, ...byId])]; } /** 명령행 자동완성에 보여줄 문자열 (예: "LINE (L) 선") */ export const describeCommand = (command: CadCommand): string => `${command.id}${command.aliases?.length ? ` (${command.aliases[0]})` : ''} ${command.label}`;