From 65347de9040d2343e3c11957466ee5ed82306d1e Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Fri, 2 Oct 2026 10:02:51 +0300 Subject: [PATCH] fix(commands): strip _/. name prefixes only when the name as written is unknown #1584 stripped the prefixes before dispatch, which turned the ribbon's own internal names (_PCCROPPOLY, _XREFEDIT, _PDFULSNAP, ...) into unknown commands. A name is now tried as written and retried without its prefixes only when no family handles it; the Start-tab gate judges the bare name. Co-Authored-By: Claude Opus 5.5 --- src/app/command_driver/utilities.rs | 1 - src/app/commands/fileops.rs | 3 +-- src/app/commands/mod.rs | 23 +++++++++++++++++------ 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/app/command_driver/utilities.rs b/src/app/command_driver/utilities.rs index 39ad731c1..f80076737 100644 --- a/src/app/command_driver/utilities.rs +++ b/src/app/command_driver/utilities.rs @@ -1197,4 +1197,3 @@ impl OpenCADStudio { self.run_command_line(trimmed) } } - diff --git a/src/app/commands/fileops.rs b/src/app/commands/fileops.rs index 57bc226ae..4dd2ed284 100644 --- a/src/app/commands/fileops.rs +++ b/src/app/commands/fileops.rs @@ -489,7 +489,7 @@ mod tests { } #[test] - fn autodesk_command_prefixes_strip_underscore_and_dot() { + fn command_name_prefixes_are_stripped() { let mut app = fresh_app(); let i = app.active_tab; let before_count = app.tabs[i].scene.document.entities().count(); @@ -535,4 +535,3 @@ ZOOM EXTENTS assert_eq!(app.tabs[i].scene.document.entities().count(), 8); } } - diff --git a/src/app/commands/mod.rs b/src/app/commands/mod.rs index efd730b0f..cdd87f134 100644 --- a/src/app/commands/mod.rs +++ b/src/app/commands/mod.rs @@ -116,11 +116,6 @@ impl OpenCADStudio { Some(rest) => (rest.trim(), true), None => (cmd, false), }; - let cmd = cmd.trim(); - // AutoCAD command prefixes: '_' (international name), '.' (built-in name bypass) - let cmd = cmd.strip_prefix('.').unwrap_or(cmd); - let cmd = cmd.strip_prefix('_').unwrap_or(cmd); - let cmd = cmd.strip_prefix('.').unwrap_or(cmd); let resolved = self.resolve_alias(cmd); let cmd = resolved.as_deref().unwrap_or(cmd); if is_spacemouse_command(cmd) { @@ -201,7 +196,7 @@ impl OpenCADStudio { // editors (shortcuts, aliases) — none of them read the scene. This is // the single place that decides; `on_ribbon_tool_click` defers to it // rather than keeping a second, blunter copy (#388, #389). - if self.tabs[i].is_start && !start_allowed(cmd) { + if self.tabs[i].is_start && !start_allowed(strip_command_prefixes(cmd).unwrap_or(cmd)) { self.command_line .push_info(crate::t!("No drawing open. Use NEW or OPEN to start a drawing.").as_ref()); return Task::none(); @@ -233,6 +228,15 @@ impl OpenCADStudio { return t; } + // Scripts and typed input may carry the international (`_`) and + // built-in (`.`) name prefixes (`_LINE`, `._LINE`). Ribbon tools + // dispatch internal names that start with `_` themselves + // (`_PCCROPPOLY`), so a name is tried as written first and loses its + // prefixes only when nothing handles it. + if let Some(bare) = strip_command_prefixes(cmd) { + return self.dispatch_command_inner(bare, allow_suggest); + } + // No family matched. From the interactive command line, run the // closest autocomplete suggestion instead of erroring, so a partial // command completes on Enter (`BAC` → `BACKGROUND`). The verb's own @@ -1036,3 +1040,10 @@ mod marquee_cancel_tests { ); } } + +/// `cmd` without its leading `_` / `.` name prefixes (`_LINE`, `.LINE`, +/// `._LINE`), or `None` when it carries none. +fn strip_command_prefixes(cmd: &str) -> Option<&str> { + let bare = cmd.trim_start_matches(['_', '.']); + (bare.len() != cmd.len() && !bare.is_empty()).then_some(bare) +}