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
This commit is contained in:
@@ -3,17 +3,20 @@ import { type FC, type FormEvent, useMemo, useRef, useState } from 'react';
|
||||
import { describeCommand, matchCommandPrefixes } from '../commands/registry';
|
||||
import { getCommandHistory, runCommandInput } from '../commands/run-command';
|
||||
import { activeToolWantsFreeText, isPlainSpace } from '../inputController/ime-sink';
|
||||
import { commandCandidate, recallInput } from '../inputController/input-history';
|
||||
import { currentPrompt } from '../inputController/prompt-input';
|
||||
import { getInputController } from '../state';
|
||||
|
||||
export const CommandLine: FC = () => {
|
||||
const [text, setText] = useState('');
|
||||
const [historyIndex, setHistoryIndex] = useState<number | null>(null);
|
||||
/** Tab · ↑↓ 후보 돌림 — 처음 친 글 · 몇째(null = 안 돌림) */
|
||||
const [pick, setPick] = useState<{ base: string; index: number } | null>(null);
|
||||
const [fromHistory, setFromHistory] = useState(false);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const history = getCommandHistory();
|
||||
const instruction = currentPrompt().line || '명령을 입력하거나 도구를 선택하십시오.';
|
||||
|
||||
const suggestions = useMemo(() => matchCommandPrefixes(text).slice(0, 8), [text]);
|
||||
const suggestions = useMemo(() => matchCommandPrefixes(pick?.base ?? text).slice(0, 8), [text, pick]);
|
||||
|
||||
const submit = (event: FormEvent) => {
|
||||
event.preventDefault();
|
||||
@@ -26,17 +29,28 @@ export const CommandLine: FC = () => {
|
||||
// 진행 중인 명령이 문자·숫자를 기다리면 그쪽으로, 아니면 명령으로 해석된다
|
||||
getInputController().submitText(value);
|
||||
setText('');
|
||||
setHistoryIndex(null);
|
||||
setPick(null);
|
||||
setFromHistory(false);
|
||||
};
|
||||
|
||||
const recallHistory = (direction: -1 | 1) => {
|
||||
if (!history.length) return;
|
||||
const nextIndex =
|
||||
historyIndex === null
|
||||
? history.length - 1
|
||||
: Math.min(history.length - 1, Math.max(0, historyIndex + direction));
|
||||
setHistoryIndex(nextIndex);
|
||||
setText(history[nextIndex].split(' ')[0]);
|
||||
/** 후보 보이면 후보 돌림 · 아니면 친 명령 · 최근 값 기록(캔버스와 같은 함수 · 알림 줄 안 섞음) */
|
||||
const recall = (direction: -1 | 1) => {
|
||||
if (pick || (!fromHistory && text.trim() && suggestions.length)) {
|
||||
cycle(direction);
|
||||
return;
|
||||
}
|
||||
const value = recallInput(direction, text);
|
||||
if (value === null) return;
|
||||
setText(value);
|
||||
setFromHistory(true);
|
||||
};
|
||||
const cycle = (direction: -1 | 1) => {
|
||||
const base = pick?.base ?? text;
|
||||
const index = pick ? pick.index + direction : direction > 0 ? 0 : -1;
|
||||
const name = commandCandidate(base, index);
|
||||
if (!name) return;
|
||||
setPick({ base, index });
|
||||
setText(name);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -53,7 +67,11 @@ export const CommandLine: FC = () => {
|
||||
id="cad-command"
|
||||
ref={inputRef}
|
||||
value={text}
|
||||
onChange={(event) => setText(event.target.value)}
|
||||
onChange={(event) => {
|
||||
setText(event.target.value);
|
||||
setPick(null);
|
||||
setFromHistory(false);
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.nativeEvent.isComposing) return; // 한글 조합 중 키는 IME 몫
|
||||
if (event.key === ' ' && !activeToolWantsFreeText()) {
|
||||
@@ -68,17 +86,13 @@ export const CommandLine: FC = () => {
|
||||
event.preventDefault();
|
||||
getInputController().handleEscapeKey();
|
||||
}
|
||||
if (event.key === 'ArrowUp') {
|
||||
if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
|
||||
event.preventDefault();
|
||||
recallHistory(-1);
|
||||
}
|
||||
if (event.key === 'ArrowDown') {
|
||||
event.preventDefault();
|
||||
recallHistory(1);
|
||||
recall(event.key === 'ArrowUp' ? -1 : 1);
|
||||
}
|
||||
if (event.key === 'Tab' && suggestions.length) {
|
||||
event.preventDefault();
|
||||
setText(suggestions[0].id);
|
||||
cycle(1);
|
||||
}
|
||||
}}
|
||||
placeholder="명령 입력 (예: L, LINE, REC, MOVE)"
|
||||
|
||||
Reference in New Issue
Block a user