refactor(CAD): 337-6 가 끝 몫 — 옛 OFFSET · LENGTHEN · 옛 꼴 통과 지움 · ALL · L · P 실제 고름 시험 · 안내 글
- transform-acad: 고르기 물음 ALL · L · P = 「n개를 찾음, 총 m개」 · 다시 「객체 선택:」 · 빈 Enter = 고르기 끝(설계 1-4 · 2-15) - transform-tools: 안 쓰는 옛 OFFSET · LENGTHEN 머신 지움(새 offset-tool · lengthen-tool 이 대신) - prompt-input · prompt · sequence-tool: 옛 꼴 통과(meta.options 글 배열 · TEXT_INPUT 대문자 통과 · chainFromLastPoint) 지움 - prompt-contract: 옛 꼴 안 쓰는지 지키는 시험 더함 - 안내 글(설계 4 장 끝): 오른쪽 단추 · 휠 두 번 · CAD 키 줄 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QfHKQs7J3hQELKMWQMUJEy
This commit is contained in:
@@ -47,8 +47,6 @@ export interface PromptMeta {
|
||||
kind?: StepKind;
|
||||
prompt?: PromptLike;
|
||||
instructions?: string;
|
||||
/** 옛 꼴 — 점 물음이 받는 옵션 글자(대문자) */
|
||||
options?: string[];
|
||||
}
|
||||
|
||||
/** 함수 꼴 물음을 지금 context 로 풂 */
|
||||
|
||||
@@ -147,14 +147,12 @@ export interface CurrentPrompt {
|
||||
spec: PromptSpec | null;
|
||||
/** 그린 한 줄(새 꼴) 또는 옛 instructions */
|
||||
line: string | null;
|
||||
/** 옛 꼴 — 점 물음이 받는 옵션 글자 */
|
||||
legacyOptions: string[];
|
||||
}
|
||||
|
||||
export function currentPrompt(): CurrentPrompt {
|
||||
const sub = subPrompt();
|
||||
if (sub) {
|
||||
return { kind: sub.kind, spec: sub.prompt, line: renderPrompt(sub.prompt, sub.kind), legacyOptions: [] };
|
||||
return { kind: sub.kind, spec: sub.prompt, line: renderPrompt(sub.prompt, sub.kind) };
|
||||
}
|
||||
const meta = activeMeta();
|
||||
const spec = resolvePrompt(meta?.prompt, activeSnapshot()?.context);
|
||||
@@ -163,7 +161,6 @@ export function currentPrompt(): CurrentPrompt {
|
||||
kind,
|
||||
spec,
|
||||
line: spec ? renderPrompt(spec, meta?.kind) : (meta?.instructions ?? null),
|
||||
legacyOptions: meta?.options ?? [],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -276,12 +273,6 @@ function numberProblem(value: number, rule: PromptSpec['number']): string | null
|
||||
|
||||
// ---- 사다리(설계 2-5) ----
|
||||
|
||||
/** 옛 꼴 통과 — 새 물음이 없는 상태가 TEXT_INPUT 을 받고 숫자는 안 받음 */
|
||||
const legacyTakesText = (): boolean => {
|
||||
const on = (flatConfig()?.on ?? {}) as Record<string, unknown>;
|
||||
return !!on.TEXT_INPUT && !on.NUMBER_INPUT;
|
||||
};
|
||||
|
||||
/** ② 빈 Enter · Space · 우클릭 */
|
||||
function routeEmpty(prompt: CurrentPrompt) {
|
||||
const lockedLength = getLockedLength();
|
||||
@@ -400,17 +391,8 @@ export function routeTyped(raw: string): void {
|
||||
notice(`「${hit.absent.label}(${hit.absent.kw})」 옵션은 이 CAD 에 없음.`);
|
||||
return;
|
||||
}
|
||||
const upper = normalizeKeyword(text);
|
||||
if (!prompt.spec && prompt.legacyOptions.includes(upper)) {
|
||||
send({ type: ActorEvent.TEXT_INPUT, value: upper }); // 옛 꼴 통과
|
||||
return;
|
||||
}
|
||||
if (prompt.kind === 'point') return routePointText(text, prompt);
|
||||
if (prompt.kind === 'number') return routeNumber(text, prompt);
|
||||
if (!prompt.spec && legacyTakesText()) {
|
||||
send({ type: ActorEvent.TEXT_INPUT, value: upper }); // 옛 꼴 통과
|
||||
return;
|
||||
}
|
||||
reject(prompt); // ⑦ ⑩
|
||||
}
|
||||
|
||||
|
||||
@@ -118,8 +118,6 @@ export interface SequenceToolConfig {
|
||||
pickfirst?: boolean;
|
||||
/** 옛 꼴 — true = `loopFrom: 0` · false = 끝 */
|
||||
restart?: boolean;
|
||||
/** 옛 꼴 — 확정 뒤 마지막 점을 첫 값으로 이어받아 계속 그린다 */
|
||||
chainFromLastPoint?: boolean;
|
||||
/** 점 입력 중 스냅·각도 가이드 사용 여부 (기본 true) */
|
||||
helpers?: boolean;
|
||||
/** ESC 로 확정 없이 그만둘 때 */
|
||||
@@ -201,9 +199,7 @@ export function createSequenceTool(config: SequenceToolConfig) {
|
||||
? indexOf(config.loopFrom)
|
||||
: config.restart === true
|
||||
? 0
|
||||
: config.chainFromLastPoint && config.restart !== false
|
||||
? 1
|
||||
: null;
|
||||
: null;
|
||||
for (const step of steps) if (step.next !== undefined) indexOf(step.next);
|
||||
const isRepeat = (index: number) => !!config.repeatLastStep && index === lastIndex;
|
||||
|
||||
@@ -375,18 +371,16 @@ export function createSequenceTool(config: SequenceToolConfig) {
|
||||
setGhostHelperEntities([]);
|
||||
};
|
||||
|
||||
/** 확정 뒤 되풀이 — loopFrom 앞 값만 둠(옛 chainFromLastPoint = 마지막 점 이어받음) */
|
||||
/** 확정 뒤 되풀이 — loopFrom 앞 값만 둠 */
|
||||
const loopAgain = assign(({ context }: Ctx): Partial<SequenceContext> => {
|
||||
const from = loopIndex as number;
|
||||
const tail = lastPoint(context.values);
|
||||
const chain = config.chainFromLastPoint && config.loopFrom === undefined && tail;
|
||||
const keep = context.values.map((_, index) => chain || context.stepOf[index] < from);
|
||||
const values = chain ? [tail] : context.values.filter((_, index) => keep[index]);
|
||||
const keep = context.values.map((_, index) => context.stepOf[index] < from);
|
||||
const values = context.values.filter((_, index) => keep[index]);
|
||||
const next = {
|
||||
...context,
|
||||
values,
|
||||
picks: chain ? [tail] : context.picks.filter((_, index) => keep[index]),
|
||||
stepOf: chain ? [0] : context.stepOf.filter((_, index) => keep[index]),
|
||||
picks: context.picks.filter((_, index) => keep[index]),
|
||||
stepOf: context.stepOf.filter((_, index) => keep[index]),
|
||||
closed: false,
|
||||
loops: context.loops + 1,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/** 대칭·정렬·간격띄우기·신축·길이조정 (조사표 2절) */
|
||||
/** 대칭·정렬·신축 (조사표 2절) */
|
||||
import { Box, Point, Polygon } from '@flatten-js/core';
|
||||
import { toast } from 'react-toastify';
|
||||
import { type AnyActorRef, assign } from 'xstate';
|
||||
import { OPT } from '../../commands/prompt';
|
||||
import type { Entity } from '../../entities/Entity';
|
||||
@@ -21,7 +20,7 @@ import { createDisplaceTool } from '../move-tool';
|
||||
import { SelectState } from '../select-tool';
|
||||
import type { MouseClickEvent, StateEvent } from '../tool.types';
|
||||
import { SELECT_CHILD } from '../transform.helpers';
|
||||
import { copyStyle, lengthenLine, offsetEntity } from './modify.helpers';
|
||||
import { copyStyle } from './modify.helpers';
|
||||
|
||||
/** 원본 특성을 유지한 복사본 */
|
||||
const cloneStyled = (entity: Entity): Entity => copyStyle(entity, entity.clone());
|
||||
@@ -110,23 +109,6 @@ export const alignToolStateMachine = createSequenceTool({
|
||||
},
|
||||
});
|
||||
|
||||
export const offsetToolStateMachine = createSequenceTool({
|
||||
tool: Tool.OFFSET,
|
||||
steps: [
|
||||
{ kind: 'number', instructions: '간격띄우기 거리를 입력하십시오 <1>.', defaultValue: 1 },
|
||||
{ kind: 'entity', instructions: '간격띄우기할 객체를 선택하십시오.' },
|
||||
{ kind: 'point', instructions: '간격을 띄울 방향의 점을 지정하십시오.' },
|
||||
],
|
||||
commit: (input) => {
|
||||
const result = offsetEntity(input.entity(1), input.number(0), input.point(2));
|
||||
if (!result) {
|
||||
toast.warn('이 객체는 지정한 거리로 간격을 띄울 수 없습니다.');
|
||||
return;
|
||||
}
|
||||
addEntities([result], true);
|
||||
},
|
||||
});
|
||||
|
||||
/** 바꾼 것을 원본 자리에 — id · 묶음 · 꼴 그대로 */
|
||||
const inPlaceOf = <T extends Entity>(source: Entity, made: T): T => {
|
||||
copyStyle(source, made);
|
||||
@@ -208,25 +190,3 @@ export const stretchToolStateMachine = createDisplaceTool({
|
||||
return context.originals.flatMap((entity) => stretchEntity(entity, box, dx, dy) ?? []);
|
||||
},
|
||||
});
|
||||
|
||||
export const lengthenToolStateMachine = createSequenceTool({
|
||||
tool: Tool.LENGTHEN,
|
||||
steps: [
|
||||
{ kind: 'entity', instructions: '길이를 바꿀 선을 늘릴 쪽 끝 근처에서 선택하십시오.' },
|
||||
{
|
||||
kind: 'number',
|
||||
instructions: '증분 길이를 입력하십시오 (음수는 단축) <10>.',
|
||||
defaultValue: 10,
|
||||
},
|
||||
],
|
||||
commit: (input) => {
|
||||
const entity = input.entity(0);
|
||||
const changed = lengthenLine(entity, input.number(1), input.pick(0));
|
||||
if (!changed) {
|
||||
toast.warn('선만 길이를 조정할 수 있습니다.');
|
||||
return;
|
||||
}
|
||||
deleteEntities([entity], false);
|
||||
addEntities([changed], true);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -62,4 +62,15 @@ describe("물음 약속(2-16)", () => {
|
||||
}
|
||||
expect(problems).toEqual([]);
|
||||
});
|
||||
|
||||
it("옛 꼴 통과 안 씀 — 옵션 글 배열 없음 · 숫자 없이 TEXT_INPUT 만 받는 상태 없음(글 물음 빼고)", () => {
|
||||
const problems: string[] = [];
|
||||
for (const { where, meta, on } of rows) {
|
||||
if ((meta as { options?: unknown } | undefined)?.options)
|
||||
problems.push(`${where}: meta.options`);
|
||||
if (on.TEXT_INPUT && !on.NUMBER_INPUT && meta?.kind !== "text")
|
||||
problems.push(`${where}: TEXT_INPUT 만`);
|
||||
}
|
||||
expect(problems).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -621,14 +621,23 @@ describe("PEDIT 고르기 · 고르기 공용(2-14 ④ · 2-15)", () => {
|
||||
expect(entities()).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("고르기 물음의 ALL · L · P 는 거절 없이 선택 도구로 넘어감", () => {
|
||||
it("고르기 물음의 ALL · L · P = 실제 고름 · 「n개를 찾음」 · 다시 「객체 선택:」 · 빈 Enter = 고르기 끝", () => {
|
||||
line("0,0", "10,0");
|
||||
line("0,20", "10,20");
|
||||
type("m");
|
||||
for (const word of ["all", "l", "p"]) {
|
||||
type(word);
|
||||
expect(noticeLine()).toBeNull();
|
||||
expect(activeTool()).toBe(Tool.MOVE);
|
||||
}
|
||||
type("all");
|
||||
expect(noticeLine()).toBe("2개를 찾음, 총 2개");
|
||||
expect(promptLine()).toBe("객체 선택:");
|
||||
expect(activeTool()).toBe(Tool.MOVE);
|
||||
type("l");
|
||||
expect(noticeLine()).toBe("1개를 찾음, 총 2개");
|
||||
expect(promptLine()).toBe("객체 선택:");
|
||||
type("p");
|
||||
expect(noticeLine()).toMatch(/^\d+개를 찾음, 총 2개$/);
|
||||
expect(promptLine()).toBe("객체 선택:");
|
||||
enter();
|
||||
expect(activeTool()).toBe(Tool.MOVE);
|
||||
expect(promptLine()).toBe("기준점 지정 또는 [변위(D)] <변위>:");
|
||||
});
|
||||
|
||||
const selectTakesKeywords = !!(
|
||||
|
||||
@@ -121,8 +121,8 @@ export const ui_locales_common = {
|
||||
App_Settings_Rule_Pan: ["화면 옮기기 = 가운데 단추 끌기", "Pan = drag with the middle button"],
|
||||
App_Settings_Rule_Pick: ["고르기 = 왼쪽 단추", "Select = left button"],
|
||||
App_Settings_Rule_Right: [
|
||||
"오른쪽 단추 = 메뉴 · CAD 에서는 Enter",
|
||||
"Right button = menu · Enter in CAD",
|
||||
"오른쪽 단추 = 메뉴 · CAD 에서는 명령 중 Enter · 쉴 때 반복 · Shift = 스냅 메뉴 · CAD 휠 두 번 = 범위",
|
||||
"Right button = menu · in CAD Enter during a command · repeat when idle · Shift = snap menu · CAD wheel double-click = extents",
|
||||
],
|
||||
App_Settings_Rule_Pinch: [
|
||||
"트랙패드 · 손가락 벌림 = 늘 확대(휠 방향과 상관없음)",
|
||||
@@ -164,8 +164,8 @@ export const ui_locales_common = {
|
||||
],
|
||||
App_Settings_Keys_Cad: ["CAD", "CAD"],
|
||||
App_Settings_Keys_Cad_Keys: [
|
||||
"F3 스냅 · F7 그리드 · F8 직교 · F10 45° · Ctrl+Z · Ctrl+Y · Ctrl+A · Ctrl+S(M02) · Delete · Esc · Enter · Space = Enter · 방향키 = 화면 옮김 · 글자 = 명령",
|
||||
"F3 snap · F7 grid · F8 ortho · F10 45° · Ctrl+Z · Ctrl+Y · Ctrl+A · Ctrl+S (M02) · Delete · Esc · Enter · Space = Enter · arrows = pan · letters = command",
|
||||
"F3 스냅 · F7 그리드 · F8 직교 · F10 45° · Ctrl+Z · Ctrl+Y · Ctrl+A · Ctrl+S(M02) · Delete · Esc · Enter · Space = Enter · ↑↓ = 기록 · 최근 값 · Ctrl+C · X · 1 · ← → · Shift+↑↓ = 화면 옮김 · 글자 = 명령",
|
||||
"F3 snap · F7 grid · F8 ortho · F10 45° · Ctrl+Z · Ctrl+Y · Ctrl+A · Ctrl+S (M02) · Delete · Esc · Enter · Space = Enter · ↑↓ = history · recent values · Ctrl+C · X · 1 · ← → · Shift+↑↓ = pan · letters = command",
|
||||
],
|
||||
App_Settings_Keys_Table: ["B08 · B09 표", "B08 · B09 tables"],
|
||||
App_Settings_Keys_Table_Keys: [
|
||||
|
||||
Reference in New Issue
Block a user