feat(cmdline): Enter runs closest command match

Typing a partial command (e.g. `bac`) and pressing Enter with no active
command ran into an "Unknown command" error. Now the top autocomplete
match is highlighted and Enter runs it (`BACKGROUND`), matching standard
DWG command-line behavior.

The fallback only fires when no command family matches the typed verb, so
complete aliases that resolve through a dispatch arm but are absent from
the autocomplete registry (`LT`, `ZO`, …) still run as typed. Programmatic
dispatch (ribbon, plugins, headless automation) is unaffected.

Closes #198

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-06-27 14:45:51 +03:00
commit 63de137106
3 changed files with 71 additions and 38 deletions

View file

@ -36,6 +36,22 @@ impl OpenCADStudio {
}
pub(super) fn dispatch_command(&mut self, cmd: &str) -> Task<Message> {
self.dispatch_command_inner(cmd, false)
}
/// Dispatch a verb typed at the interactive command line, falling back to
/// the closest autocomplete suggestion when the verb matches no command
/// family. Lets a partial command run on Enter (`BAC` → `BACKGROUND`),
/// the standard DWG command-line behavior. The fallback only fires for
/// genuinely unknown verbs, so complete aliases that resolve through a
/// dispatch family (`LT`, `ZO`, …) still run as typed. Programmatic
/// callers (ribbon, plugins, headless automation) use `dispatch_command`
/// and never get silent substitution.
pub(super) fn dispatch_command_or_suggest(&mut self, cmd: &str) -> Task<Message> {
self.dispatch_command_inner(cmd, true)
}
fn dispatch_command_inner(&mut self, cmd: &str, allow_suggest: bool) -> Task<Message> {
let i = self.active_tab;
// Starting a command closes any open ribbon dropdown (e.g. a style
// combo left open) so it does not stay stuck behind the new tool.
@ -126,7 +142,17 @@ impl OpenCADStudio {
return t;
}
// No family matched.
// 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
// input was already cleared, so rank against `cmd` directly.
if allow_suggest {
if let Some(top) = crate::ui::command_line::ranked_matches(cmd).first().copied() {
if !top.eq_ignore_ascii_case(cmd) {
return self.dispatch_command_inner(top, false);
}
}
}
self.command_line
.push_error(&format!("Unknown command: {cmd}"));
self.finish_dispatch(cmd)

View file

@ -338,7 +338,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
return self.focus_cmd_input();
}
if let Some(cmd) = self.command_line.submit() {
return self.dispatch_command(&cmd);
return self.dispatch_command_or_suggest(&cmd);
}
// Empty Enter / Space with no active command repeats the
// last dispatched command — same shortcut `CommandFinalize`