- 새 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
84 lines
2.5 KiB
TypeScript
84 lines
2.5 KiB
TypeScript
/**
|
|
* 점 물음 보조(337 설계 1-4 · 2-5 ④ · 가-2) — 한 번 스냅 이름 · FROM · M2P(MTP) · `@`(마지막 점) · `#` · `*`(절대 좌표).
|
|
* FROM · M2P 는 덧물음 두 개를 잇고 끝에 고른 점을 원래 물음에 넘김(도구 머신은 모름 → 투명).
|
|
*/
|
|
import { Point } from '@flatten-js/core';
|
|
import { lastPoint, normalizeKeyword } from '../commands/prompt';
|
|
import { ActorEvent } from '../tools/tool.types';
|
|
import { parsePointText } from './input-patterns';
|
|
import { absentSnapName, setSnapOverride, snapName } from './input-snap-override';
|
|
import { distanceCursor, notice, pushSubPrompt, sendPoint } from './prompt-input';
|
|
|
|
const point = (x: number, y: number) => new Point(x, y);
|
|
|
|
/** FROM — 「기준점:」 → 「<간격띄우기>:」(`@dx,dy` · 거리 = 기준점에서 커서 쪽) */
|
|
function startFrom() {
|
|
pushSubPrompt({
|
|
prompt: { text: '기준점' },
|
|
kind: 'point',
|
|
onPoint: (base) => {
|
|
pushSubPrompt({
|
|
prompt: { text: '<간격띄우기>' },
|
|
kind: 'point',
|
|
base,
|
|
onPoint: (target) => ({ point: target }),
|
|
});
|
|
return 'done';
|
|
},
|
|
});
|
|
}
|
|
|
|
/** M2P · MTP — 두 점의 가운데 */
|
|
function startMidBetween() {
|
|
pushSubPrompt({
|
|
prompt: { text: '중간점의 첫 번째 점' },
|
|
kind: 'point',
|
|
onPoint: (first) => {
|
|
pushSubPrompt({
|
|
prompt: { text: '중간점의 두 번째 점' },
|
|
kind: 'point',
|
|
base: first,
|
|
onPoint: (second) => ({ point: point((first.x + second.x) / 2, (first.y + second.y) / 2) }),
|
|
});
|
|
return 'done';
|
|
},
|
|
});
|
|
}
|
|
|
|
/** 점 물음에서 친 글이 보조면 처리하고 true · 아니면 false(옵션 · 좌표 차례로) */
|
|
export function tryPointModifier(text: string): boolean {
|
|
const typed = normalizeKeyword(text);
|
|
const snap = snapName(typed);
|
|
if (snap) {
|
|
setSnapOverride(snap);
|
|
return true;
|
|
}
|
|
const absent = absentSnapName(typed);
|
|
if (absent) {
|
|
notice(`「${absent}」 스냅은 이 CAD 에 없음.`);
|
|
return true;
|
|
}
|
|
if (typed === 'FROM' || typed === 'FRO') {
|
|
startFrom();
|
|
return true;
|
|
}
|
|
if (typed === 'M2P' || typed === 'MTP') {
|
|
startMidBetween();
|
|
return true;
|
|
}
|
|
if (typed === '@') {
|
|
const last = lastPoint();
|
|
if (!last) return false;
|
|
sendPoint({ type: ActorEvent.ABSOLUTE_POINT_INPUT, value: point(last.x, last.y) });
|
|
return true;
|
|
}
|
|
if (typed.startsWith('#') || typed.startsWith('*')) {
|
|
// 절대 좌표 강제 — `#x,y` · `*d<a`
|
|
const event = parsePointText(typed.slice(1), distanceCursor);
|
|
if (event?.type !== ActorEvent.ABSOLUTE_POINT_INPUT) return false;
|
|
sendPoint(event);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|