feat(view): -VIEW command-line form with the standard view presets

-VIEW asks "Enter an option [?/Delete/Orthographic/Restore/Save/sEttings/
Window]:" and takes the orthographic and isometric presets (TOP, BOTTOM,
FRONT, BACK, LEFT, RIGHT, SWISO, SEISO, NEISO, NWISO, also with a leading
underscore) directly, Orthographic asking for the face with <Top> as the
default. Keyword prompts accept a leading underscore on their keywords.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
ramox81andClaude Opus 5.5 committed 2026-10-08 15:43:45 +03:00
1 parent ff6e2a6613
commit 62ff1daade
3 files changed
+94

No files matched your search

+78
View File
@@ -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<String> = 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]<Top>:",
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::<Vec<_>>().join(" ");
return self.dispatch_layerprops(format!("VIEW {first} {rest}").trim_end(), i);
}
"VIEW" => {
use crate::command::KeywordCommand;
let c = KeywordCommand::new(
+1
View File
@@ -915,6 +915,7 @@ inventory::submit!(crate::command::CommandRegistration {
"USERI",
"USERR",
"VIEW",
"-VIEW",
"VPORTS",
"VS",
"VW",
+15
View File
@@ -642,6 +642,9 @@ pub struct KeywordCommand {
/// Keyword a bare Enter dispatches at the verb step (`<Default>` prompts,
/// e.g. PLAN's `<Current>`). `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);