feat(ucs): interactive UCS command — UCS Z 90 typable everywhere (F2, #169)

Bare `UCS` now enters an interactive front-end (UcsCommand) that gathers the
option then its value as separate steps, instead of the command line
submitting `UCS` alone on the first Space. The front-end delegates execution
back to the existing inline `UCS <option> …` handler via a new
`CmdResult::Dispatch(String)`, so the coordinate-system math and the
save/persist path are untouched.

Now `UCS Z 90` works the same from the command line (Space-separated),
headless automation, and any source that feeds the active command — closing
the input half of #169. Inline `UCS Z 90` (one-shot / paste) still hits the
inline handler directly.

Second phase of routing input sources through the unified step driver: the
interactive command is driven by feed_command like any tool. Adds headless
test ucs_interactive_inline_args.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-06-25 12:36:49 +03:00
commit 36d2f33301
6 changed files with 159 additions and 2 deletions

View file

@ -565,6 +565,27 @@ mod tests {
assert_eq!(app.automation_op(r#"{"op":"run"}"#)["ok"], false);
}
#[test]
fn ucs_interactive_inline_args() {
// `UCS Z 90` must drive the interactive UCS command step-by-step (option
// "Z" then value "90") and rotate the active UCS 90° about Z. (#169)
let mut app = OpenCADStudio::new_for_test();
app.automation_op(r#"{"op":"new"}"#);
app.automation_op(r#"{"op":"run","cmd":"UCS Z 90"}"#);
let i = app.active_tab;
let ucs = app.tabs[i]
.active_ucs
.as_ref()
.expect("UCS Z 90 should set an active UCS");
// 90° about Z sends the X axis (1,0,0) → (0,1,0).
assert!(
ucs.x_axis.x.abs() < 1e-6 && (ucs.x_axis.y - 1.0).abs() < 1e-6,
"x_axis after UCS Z 90 = ({}, {})",
ucs.x_axis.x,
ucs.x_axis.y
);
}
#[test]
fn save_then_open_round_trips() {
let mut app = OpenCADStudio::new_for_test();