From b464a947ec354f8cf3c87f9ecbb1cb2423b38014 Mon Sep 17 00:00:00 2001 From: Marco Arnulfo <103679419+marcoarnulfo@users.noreply.github.com> Date: Mon, 19 Oct 2026 08:29:31 +0200 Subject: [PATCH] MEASUREGEOM typed at the command line asks for the option, then the points (fixes #1103) (#1104) --- crates/engine/src/cmd/inquiry.rs | 4 +- crates/engine/src/cmd/utility.rs | 60 ++++++++++++++++++++++++- crates/engine/tests/inquiry_keywords.rs | 14 ++++++ 3 files changed, 75 insertions(+), 3 deletions(-) diff --git a/crates/engine/src/cmd/inquiry.rs b/crates/engine/src/cmd/inquiry.rs index f16ad6447..f27383421 100644 --- a/crates/engine/src/cmd/inquiry.rs +++ b/crates/engine/src/cmd/inquiry.rs @@ -427,7 +427,7 @@ fn run_texts(s: &mut Session, p: &Value) -> Result { mod count; #[derive(Default)] -struct DistM { +pub(super) struct DistM { first: Option, first_source: Option, /// Multiple points: the points so far, the first included. @@ -662,7 +662,7 @@ enum AreaMode { } #[derive(Default)] -struct AreaM { +pub(super) struct AreaM { pts: Vec, mode: AreaMode, total: f64, diff --git a/crates/engine/src/cmd/utility.rs b/crates/engine/src/cmd/utility.rs index 3fa676c30..89c00f7a6 100644 --- a/crates/engine/src/cmd/utility.rs +++ b/crates/engine/src/cmd/utility.rs @@ -26,7 +26,10 @@ pub fn specs() -> Vec { .noundo() .interactive(|_| Ok(Box::::default())), CommandSpec::new("find", "Find...", run_find).menu(&["Edit", "Find..."]).params("{find, replace?, matchCase?: bool, wholeWord?: bool}"), - CommandSpec::new("measuregeom", "Measure Geometry", run_measuregeom).params("{mode: distance|radius|angle|area, ...}").noundo(), + CommandSpec::new("measuregeom", "Measure Geometry", run_measuregeom) + .params("{mode: distance|radius|angle|area, ...}") + .noundo() + .interactive(|_| Ok(Box::::default())), CommandSpec::new("radius.measure", "Radius", run_radius).menu(&["Tools", "Inquiry", "Radius"]).params("{handle}").noundo(), CommandSpec::new("angle.measure", "Angle", run_angle).menu(&["Tools", "Inquiry", "Angle"]).params("{vertex, p1, p2} | {h1, h2}").noundo(), ] @@ -319,6 +322,61 @@ fn run_measuregeom(s: &mut Session, p: &Value) -> Result { } } +/// MEASUREGEOM typed or picked: choose what to measure, then continue as DIST, AREA or a radius pick. +#[derive(Default)] +struct MeasureM { + inner: Option>, + /// Waiting for the arc or circle of the Radius option. + radius: bool, +} + +impl Interactive for MeasureM { + fn name(&self) -> &'static str { + "MEASUREGEOM" + } + fn prompt(&self, s: &Session) -> Prompt { + match &self.inner { + Some(m) => m.prompt(s), + None if self.radius => Prompt::new("Select arc or circle", Accept::POINT), + None => Prompt::new("Enter an option", Accept { point: false, number: false, text: false, select: false, enter: true }) + .kw(&["Distance", "Radius", "ARea"]) + .default("Distance"), + } + } + fn input(&mut self, s: &mut Session, i: Input) -> Result { + if let Some(m) = &mut self.inner { + return m.input(s, i); + } + if self.radius { + let Input::Point(p) = i else { return Ok(Step::Done) }; + let Some(h) = super::curves::pick_at(s, p) else { return Ok(Step::Continue) }; + match run_radius(s, &json!({ "handle": h.0 })) { + Ok(r) => { + for l in r["message"].as_str().unwrap_or_default().lines() { + s.echo(l.to_string()); + } + return Ok(Step::Done); + } + Err(_) => s.echo("Select an arc or circle."), + } + return Ok(Step::Continue); + } + match i { + Input::Enter => self.inner = Some(Box::new(super::inquiry::DistM::default())), + Input::Keyword(k) => match k.as_str() { + "Radius" => self.radius = true, + "ARea" => self.inner = Some(Box::new(super::inquiry::AreaM::default())), + _ => self.inner = Some(Box::new(super::inquiry::DistM::default())), + }, + _ => {} + } + Ok(Step::Continue) + } + fn preview(&self, s: &Session, cursor: Vec2) -> Vec { + self.inner.as_ref().map(|m| m.preview(s, cursor)).unwrap_or_default() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/engine/tests/inquiry_keywords.rs b/crates/engine/tests/inquiry_keywords.rs index 49e0560a5..db9330c3b 100644 --- a/crates/engine/tests/inquiry_keywords.rs +++ b/crates/engine/tests/inquiry_keywords.rs @@ -66,3 +66,17 @@ fn area_of_an_open_elliptical_arc_is_refused_and_a_full_ellipse_is_measured() { assert!(has(&log, "no area"), "{log:?}"); assert!(!has(&log, "Area = "), "{log:?}"); } + +#[test] +fn measuregeom_typed_asks_for_the_option_then_the_points() { + // Distance is the default option (#1103: typed, it used to fail asking for `p1`). + let (s, log) = run(&["measuregeom", "", "0,0", "3,4"]); + assert!(has(&log, "Distance = 5.0000"), "{log:?}"); + assert!(s.running.is_none(), "{}", s.prompt_text()); + + let (_, log) = run(&["circle 0,0 2", "measuregeom", "r", "2,0"]); + assert!(has(&log, "Radius = 2.0000"), "{log:?}"); + + let (_, log) = run(&["measuregeom", "ar", "0,0", "4,0", "4,3", ""]); + assert!(has(&log, "Area = 6.0000"), "{log:?}"); +}