diff --git a/src/app/commands/layerprops.rs b/src/app/commands/layerprops.rs index 6d49ab04d..7d72f79c5 100644 --- a/src/app/commands/layerprops.rs +++ b/src/app/commands/layerprops.rs @@ -760,6 +760,84 @@ impl OpenCADStudio { } } + // -VIEW: the command-line form. Its presets set the standard + // orthographic and isometric views; the rest are VIEW's verbs. + "-VIEW" => { + use crate::command::KeywordCommand; + let c = KeywordCommand::new( + "-VIEW", + "Enter an option [?/Delete/Orthographic/Restore/Save/sEttings/Window]:", + vec![ + ("?", "?", None), + ("Delete", "DELETE", Some("Enter view name(s) to delete:")), + ("Orthographic", "ORTHOGRAPHIC", None), + ("Restore", "RESTORE", Some("Enter view name to restore:")), + ("Save", "SAVE", Some("Enter view name to save:")), + ], + ) + .with_hidden(&["TOP", "BOTTOM", "FRONT", "BACK", "LEFT", "RIGHT", "SWISO", "SEISO", "NEISO", "NWISO"]); + self.command_line.push_info(&c.prompt()); + self.tabs[i].active_cmd = Some(Box::new(c)); + } + cmd if cmd.starts_with("-VIEW ") => { + let words: Vec = cmd["-VIEW ".len()..] + .split_whitespace() + .map(|word| word.trim_start_matches('_').to_ascii_uppercase()) + .collect(); + let first = words.first().map(String::as_str).unwrap_or(""); + let preset = |word: &str| -> Option<&'static str> { + ["TOP", "BOTTOM", "FRONT", "BACK", "LEFT", "RIGHT", "SWISO", "SEISO", "NEISO", "NWISO"] + .into_iter() + .find(|name| name.eq_ignore_ascii_case(word)) + }; + // The Orthographic face: Top/Bottom/Front/BAck/Left/Right. + let face = |word: &str| -> Option<&'static str> { + match word { + "BA" | "BAC" | "BACK" => Some("BACK"), + _ => ["TOP", "BOTTOM", "FRONT", "LEFT", "RIGHT"] + .into_iter() + .find(|name| !word.is_empty() && name.starts_with(word)), + } + }; + let orthographic = !first.is_empty() && "ORTHOGRAPHIC".starts_with(first); + let view = if orthographic { + match words.get(1) { + Some(word) => face(word), + None => { + use crate::command::KeywordCommand; + let c = KeywordCommand::new( + "-VIEW ORTHOGRAPHIC", + "Enter an option [Top/Bottom/Front/BAck/Left/Right]:", + vec![ + ("Top", "TOP", None), + ("Bottom", "BOTTOM", None), + ("Front", "FRONT", None), + ("BAck", "BACK", None), + ("Left", "LEFT", None), + ("Right", "RIGHT", None), + ], + ) + .with_default("TOP"); + self.command_line.push_info(&c.prompt()); + self.tabs[i].active_cmd = Some(Box::new(c)); + return Some(self.finish_dispatch(cmd)); + } + } + } else { + preset(first) + }; + if let Some(view) = view { + self.command_line.push_output(crate::t!("Regenerating model.").as_ref()); + return self.dispatch_layerprops(&format!("VIEW {view}"), i); + } + if orthographic { + self.command_line.push_error(crate::t!("Invalid option keyword.").as_ref()); + return Some(self.finish_dispatch(cmd)); + } + // View names keep their case. + let rest = cmd["-VIEW ".len()..].split_whitespace().skip(1).collect::>().join(" "); + return self.dispatch_layerprops(format!("VIEW {first} {rest}").trim_end(), i); + } "VIEW" => { use crate::command::KeywordCommand; let c = KeywordCommand::new( diff --git a/src/app/commands/mod.rs b/src/app/commands/mod.rs index 72c664de6..4131211e9 100644 --- a/src/app/commands/mod.rs +++ b/src/app/commands/mod.rs @@ -915,6 +915,7 @@ inventory::submit!(crate::command::CommandRegistration { "USERI", "USERR", "VIEW", + "-VIEW", "VPORTS", "VS", "VW", diff --git a/src/command.rs b/src/command.rs index feb9be7f4..2b250a10b 100644 --- a/src/command.rs +++ b/src/command.rs @@ -642,6 +642,9 @@ pub struct KeywordCommand { /// Keyword a bare Enter dispatches at the verb step (`` prompts, /// e.g. PLAN's ``). `None` = Enter cancels, as before. default: Option<&'static str>, + /// Keywords taken at the verb step without being offered in the prompt + /// (-VIEW's view presets). + hidden: &'static [&'static str], } impl KeywordCommand { @@ -651,6 +654,12 @@ impl KeywordCommand { self } + /// Keywords accepted at the verb step but not listed in the prompt. + pub fn with_hidden(mut self, keywords: &'static [&'static str]) -> Self { + self.hidden = keywords; + self + } + pub fn new( name: &'static str, prompt: &'static str, @@ -662,6 +671,7 @@ impl KeywordCommand { options, pending: None, default: None, + hidden: &[], } } } @@ -734,6 +744,11 @@ impl CadCommand for KeywordCommand { // Consumed inputs that keep prompting return `Some(NeedPoint)` — // `None` would hand the same text to the command a second time. None => { + // A leading underscore marks the English keyword, as in scripts. + let t = t.strip_prefix('_').unwrap_or(t); + if let Some(keyword) = self.hidden.iter().find(|keyword| keyword.eq_ignore_ascii_case(t)) { + return Some(CmdResult::Dispatch(format!("{} {keyword}", self.name))); + } let Some((_, keyword, value_prompt)) = match_cmd_option(&self.options, t) else { // Unknown verb — keep prompting rather than dispatch garbage. return Some(CmdResult::NeedPoint);