diff --git a/src/app/command_driver/utilities.rs b/src/app/command_driver/utilities.rs index a79c3839d..2f995013f 100644 --- a/src/app/command_driver/utilities.rs +++ b/src/app/command_driver/utilities.rs @@ -1121,46 +1121,14 @@ impl OpenCADStudio { let is_mtp = token.trim_start_matches('_').eq_ignore_ascii_case("MTP") || token.trim_start_matches('_').eq_ignore_ascii_case("M2P"); if is_mtp { - let is_point_step = !self.tabs[i] - .active_cmd - .as_ref() - .map(|c| c.input_kind().wants_text()) - .unwrap_or(true) - || self.tabs[i] - .active_cmd - .as_ref() - .map(|c| c.point_step_accepts_keywords()) - .unwrap_or(false); - let not_entity_pick = !self.tabs[i] - .active_cmd - .as_ref() - .map(|c| c.needs_entity_pick()) - .unwrap_or(false); - if is_point_step && not_entity_pick { + if self.point_modifier_step(i) { self.start_mtp_modifier(i); return Task::none(); } } - if let Some(override_kind) = crate::snap::parse_snap_override(token) { - let is_point_step = !self.tabs[i] - .active_cmd - .as_ref() - .map(|c| c.input_kind().wants_text()) - .unwrap_or(true) - || self.tabs[i] - .active_cmd - .as_ref() - .map(|c| c.point_step_accepts_keywords()) - .unwrap_or(false); - let not_entity_pick = !self.tabs[i] - .active_cmd - .as_ref() - .map(|c| c.needs_entity_pick()) - .unwrap_or(false); - if is_point_step && not_entity_pick { - self.apply_snap_override(override_kind); - return Task::none(); - } + if let Some(kind) = self.typed_snap_override(i, token) { + self.apply_snap_override(kind); + return Task::none(); } if let Some((coord, kind)) = crate::app::helpers::parse_coord(token) { // Match the GUI command line: typed coordinates are in the active diff --git a/src/app/update/command.rs b/src/app/update/command.rs index 51a8f4fab..dd34454fe 100644 --- a/src/app/update/command.rs +++ b/src/app/update/command.rs @@ -814,48 +814,16 @@ impl OpenCADStudio { let is_mtp = raw.trim_start_matches('_').eq_ignore_ascii_case("MTP") || raw.trim_start_matches('_').eq_ignore_ascii_case("M2P"); if is_mtp { - let is_point_step = !self.tabs[i] - .active_cmd - .as_ref() - .map(|c| c.input_kind().wants_text()) - .unwrap_or(true) - || self.tabs[i] - .active_cmd - .as_ref() - .map(|c| c.point_step_accepts_keywords()) - .unwrap_or(false); - let not_entity_pick = !self.tabs[i] - .active_cmd - .as_ref() - .map(|c| c.needs_entity_pick()) - .unwrap_or(false); - if is_point_step && not_entity_pick { + if self.point_modifier_step(i) { self.command_line.input.clear(); self.start_mtp_modifier(i); return self.focus_cmd_input(); } } - if let Some(override_kind) = crate::snap::parse_snap_override(&raw) { - let is_point_step = !self.tabs[i] - .active_cmd - .as_ref() - .map(|c| c.input_kind().wants_text()) - .unwrap_or(true) - || self.tabs[i] - .active_cmd - .as_ref() - .map(|c| c.point_step_accepts_keywords()) - .unwrap_or(false); - let not_entity_pick = !self.tabs[i] - .active_cmd - .as_ref() - .map(|c| c.needs_entity_pick()) - .unwrap_or(false); - if is_point_step && not_entity_pick { - self.command_line.input.clear(); - self.apply_snap_override(override_kind); - return self.focus_cmd_input(); - } + if let Some(kind) = self.typed_snap_override(i, &raw) { + self.command_line.input.clear(); + self.apply_snap_override(kind); + return self.focus_cmd_input(); } let text = if free_text { raw diff --git a/src/app/update/viewport_snap.rs b/src/app/update/viewport_snap.rs index 0cd30efa6..811816568 100644 --- a/src/app/update/viewport_snap.rs +++ b/src/app/update/viewport_snap.rs @@ -50,6 +50,35 @@ impl OpenCADStudio { self.accepted_snaps.clear(); } + /// The active command is at a point prompt (keywords allowed) and not + /// picking an object: where MTP and typed snap overrides apply. + pub(crate) fn point_modifier_step(&self, i: usize) -> bool { + self.tabs[i].active_cmd.as_ref().is_some_and(|c| { + (!c.input_kind().wants_text() || c.point_step_accepts_keywords()) + && !c.needs_entity_pick() + }) + } + + /// A snap override typed at a point prompt (`MID`, `END`, `NON`, ...). An + /// option the prompt offers wins, so `CEN` where Center is offered picks + /// Center. + pub(crate) fn typed_snap_override( + &self, + i: usize, + token: &str, + ) -> Option { + let kind = crate::snap::parse_snap_override(token)?; + if !self.point_modifier_step(i) { + return None; + } + let typed = token.trim().trim_start_matches('_').to_uppercase(); + let offered = self.tabs[i].active_cmd.as_ref()?.options().iter().any(|option| { + option.keyword.eq_ignore_ascii_case(&typed) + || option.label.to_uppercase().replace(' ', "").starts_with(&typed) + }); + (!offered).then_some(kind) + } + /// Apply a transparent one-shot snap override (from typed input or the context menu). pub(crate) fn apply_snap_override(&mut self, kind: crate::snap::SnapOverrideKind) { match kind {