Files
Aislo/B07_DesignDetail/openwebcad/src/inputController/input-history.ts
T
eomsangdonandClaude Opus 5.5 8661501dae feat(CAD): 337-1 가-2 점 물음 보조 · ↑↓ 기록 · Tab 후보 — FROM · M2P · @ · # · * · 스냅 이름 늘림 · H11
- 새 inputController/input-history.ts — 쉴 때 = 친 명령 기록 · 명령 중 = 그 물음 최근 값 20 · 알림 줄 안 섞음(H11) · 후보 돌림
- 새 inputController/point-modifiers.ts — FROM(기준점 → <간격띄우기>) · M2P/MTP · @ = 마지막 점 · #·* 절대 좌표 · 스냅 이름
- 스냅 이름 — 세 글자 ~ 영문 전체(END · ENDP · ENDPOINT) · QUA · NOD 더함 · TAN · EXT · INS · APP · PAR · GCE 는 「이 CAD 에 없음」 안내(N14)
- 사다리 — 기준점 없는 첫 점 @dx,dy = 마지막 점 기준 · 옵션 영문 전체 딱 맞음은 옵션 먼저(CENTER) · 줄임은 스냅(CEN) · 덧물음 base
- ↑↓ = 기록 · 후보 · Shift+↑↓ = 화면 옮김 · Tab(쉼 + 친 글) = 후보 돌림 · 명령행도 같은 함수
- 시험 — prompt-frame 가-2 8 · keyboard-chain PLINE 첫 점 줄 손질

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QfHKQs7J3hQELKMWQMUJEy
2026-10-16 00:04:30 +09:00

53 lines
2.3 KiB
TypeScript

/**
* ↑↓ 기록(337 설계 2-12 · H11) — 쉴 때 = 친 명령 기록 · 명령 중 = 그 물음(`prompt.history` · 없으면 글)의 최근 값 20.
* 보이는 기록 줄(run-command 의 log · 알림 섞임)과 나눔. 캔버스 · 명령행이 같이 씀. 글 물음(TEXT 등)은 안 남김.
*/
import { matchCommandPrefixes, resolveCommandInput } from '../commands/registry';
import { currentPrompt } from './prompt-input';
const COMMANDS = '\u0000명령';
const LIMIT = { command: 50, value: 20 };
const groups = new Map<string, string[]>();
let browsing: { group: string; index: number } | null = null;
/** 지금 물음의 기록 묶음 · 글 물음 · 모름 = null */
function groupNow(): string | null {
const prompt = currentPrompt();
if (prompt.kind === 'idle') return COMMANDS;
if (prompt.kind === 'text' || prompt.kind === null) return null;
return prompt.spec?.history ?? prompt.spec?.text ?? prompt.line;
}
/** 제출한 글 하나를 지금 물음 기록에 — 쉴 때는 명령이 된 글만 */
export function pushInput(text: string): void {
browsing = null;
const value = text.trim();
const group = groupNow();
if (!value || !group) return;
if (group === COMMANDS && !resolveCommandInput(value)) return;
const list = groups.get(group) ?? [];
if (list[list.length - 1] !== value) list.push(value);
list.splice(0, Math.max(0, list.length - (group === COMMANDS ? LIMIT.command : LIMIT.value)));
groups.set(group, list);
}
/** ↑(-1) · ↓(+1) — 지금 물음 기록에서 한 칸 · 끝을 지나면 빈 글 · 기록 없으면 null(친 글 그대로) */
export function recallInput(dir: -1 | 1, _text: string): string | null {
const group = groupNow();
const list = group ? groups.get(group) : undefined;
if (!group || !list?.length) return null;
const from = browsing?.group === group ? browsing.index : list.length;
const index = Math.min(list.length, Math.max(0, from + dir));
browsing = { group, index };
return index === list.length ? '' : list[index];
}
/** 명령 후보 돌림(Tab · 후보 보일 때 ↑↓) — base 로 시작하는 명령 중 index 번째(돌아감) */
export function commandCandidate(base: string, index: number): string | null {
const candidates = matchCommandPrefixes(base);
if (!candidates.length) return null;
const n = candidates.length;
return candidates[((index % n) + n) % n].id;
}