MEASUREGEOM typed at the command line asks for the option, then the points (fixes #1103) (#1104)

This commit is contained in:
Marco Arnulfo
2026-10-19 02:29:31 -04:00
committed by GitHub
parent f76ca751cc
commit b464a947ec
3 changed files with 75 additions and 3 deletions
+2 -2
View File
@@ -427,7 +427,7 @@ fn run_texts(s: &mut Session, p: &Value) -> Result<Value> {
mod count;
#[derive(Default)]
struct DistM {
pub(super) struct DistM {
first: Option<Vec2>,
first_source: Option<crate::snap::ViewportPoint>,
/// 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<Vec2>,
mode: AreaMode,
total: f64,
+59 -1
View File
@@ -26,7 +26,10 @@ pub fn specs() -> Vec<CommandSpec> {
.noundo()
.interactive(|_| Ok(Box::<PickM>::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::<MeasureM>::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<Value> {
}
}
/// MEASUREGEOM typed or picked: choose what to measure, then continue as DIST, AREA or a radius pick.
#[derive(Default)]
struct MeasureM {
inner: Option<Box<dyn Interactive>>,
/// 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<Step> {
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<EntityKind> {
self.inner.as_ref().map(|m| m.preview(s, cursor)).unwrap_or_default()
}
}
#[cfg(test)]
mod tests {
use super::*;
+14
View File
@@ -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:?}");
}