refactor: split four oversized files into submodule trees
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.
- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
with thin delegating arms; the 66 fattest arm bodies move to topic
methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
mspace,project,selection,modify,group_layer,preview}. The impl Scene
body is split across files via inherent-impl-per-file; struct, ctor,
fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
The 233-arm dispatch match becomes source-ordered per-family
dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.
Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:51:29 +03:00
|
|
|
use super::{Message, OpenCADStudio};
|
|
|
|
|
use crate::command::CadCommand;
|
|
|
|
|
use crate::scene::Scene;
|
|
|
|
|
use iced::Task;
|
|
|
|
|
use std::path::PathBuf;
|
|
|
|
|
|
|
|
|
|
mod blocks;
|
|
|
|
|
mod dim;
|
|
|
|
|
mod display;
|
|
|
|
|
mod draw;
|
|
|
|
|
mod fileops;
|
|
|
|
|
mod inquiry;
|
|
|
|
|
mod layerprops;
|
|
|
|
|
mod layers;
|
|
|
|
|
mod styleprops;
|
|
|
|
|
mod view;
|
|
|
|
|
|
|
|
|
|
// `DrawOrderRefCommand` lives in the `view` family file but is referenced by
|
|
|
|
|
// path (`commands::DrawOrderRefCommand`) from `update.rs`, so re-export it at
|
|
|
|
|
// the module root to keep that path valid.
|
|
|
|
|
pub(crate) use view::DrawOrderRefCommand;
|
|
|
|
|
|
|
|
|
|
impl OpenCADStudio {
|
|
|
|
|
/// First `"{prefix}{n}"` (n ≥ 1) not already used by a block record in the
|
|
|
|
|
/// active drawing. Used to auto-name a paste-as-block definition.
|
|
|
|
|
fn unique_block_name(&self, prefix: &str) -> String {
|
|
|
|
|
let i = self.active_tab;
|
|
|
|
|
let mut n = 1;
|
|
|
|
|
loop {
|
|
|
|
|
let name = format!("{prefix}{n}");
|
|
|
|
|
if self.tabs[i].scene.document.block_records.get(&name).is_none() {
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
n += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn dispatch_command(&mut self, cmd: &str) -> Task<Message> {
|
2026-06-27 14:45:51 +03:00
|
|
|
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> {
|
refactor: split four oversized files into submodule trees
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.
- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
with thin delegating arms; the 66 fattest arm bodies move to topic
methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
mspace,project,selection,modify,group_layer,preview}. The impl Scene
body is split across files via inherent-impl-per-file; struct, ctor,
fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
The 233-arm dispatch match becomes source-ordered per-family
dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.
Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:51:29 +03:00
|
|
|
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.
|
|
|
|
|
self.ribbon.close_dropdown();
|
|
|
|
|
// Cancel any running command before starting a new one.
|
|
|
|
|
if self.tabs[i].active_cmd.is_some() {
|
|
|
|
|
self.tabs[i].scene.clear_preview_wire();
|
|
|
|
|
self.tabs[i].active_cmd = None;
|
|
|
|
|
}
|
|
|
|
|
// Starting any command leaves interactive PAN mode (the PAN arm below
|
|
|
|
|
// re-enables it).
|
|
|
|
|
self.tabs[i].pan_mode = false;
|
|
|
|
|
// Reset the last committed point so the first click of the new command
|
|
|
|
|
// is not constrained by ortho/polar relative to a previous command's endpoint.
|
|
|
|
|
self.last_point = None;
|
2026-06-27 16:32:40 +03:00
|
|
|
// Starting a command restarts the right-click cycle, so its first
|
|
|
|
|
// right-click acts as Enter rather than opening the context menu.
|
|
|
|
|
self.tabs[i].scene.selection.borrow_mut().right_click_entered = false;
|
refactor: split four oversized files into submodule trees
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.
- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
with thin delegating arms; the 66 fattest arm bodies move to topic
methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
mspace,project,selection,modify,group_layer,preview}. The impl Scene
body is split across files via inherent-impl-per-file; struct, ctor,
fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
The 233-arm dispatch match becomes source-ordered per-family
dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.
Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:51:29 +03:00
|
|
|
// A fresh command starts at the polar/cartesian default — clear
|
|
|
|
|
// any `,`-driven reshape from a previous command (#35).
|
|
|
|
|
self.dyn_user_reshaped = false;
|
|
|
|
|
|
|
|
|
|
if let Some(path_str) = cmd.strip_prefix("OPEN_RECENT:") {
|
|
|
|
|
let path = PathBuf::from(path_str);
|
|
|
|
|
let size = std::fs::metadata(&path).map(|m| m.len()).unwrap_or(0);
|
|
|
|
|
return Task::done(Message::OpenPathPicked(Some((path, size))));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The Start (welcome) tab has no drawing to act on, so a drawing
|
|
|
|
|
// command would silently do nothing. Allow only the commands that
|
|
|
|
|
// make sense there (create / open a document, or quit) and tell the
|
|
|
|
|
// user otherwise instead of running a no-op. See #96.
|
|
|
|
|
if self.tabs[i].is_start
|
|
|
|
|
&& !matches!(
|
|
|
|
|
cmd,
|
|
|
|
|
"NEW" | "OPEN" | "EXIT" | "QUIT" | "REPORT" | "CHANGELOG" | "ABOUT"
|
|
|
|
|
| "PLUGINS" | "PLUGINMANAGER" | "DONATE" | "WEBVERSION"
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
self.command_line
|
|
|
|
|
.push_info("No drawing open. Use NEW or OPEN to start a drawing.");
|
|
|
|
|
return Task::none();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if crate::plugin::try_dispatch(self, i, cmd) {
|
|
|
|
|
// try_dispatch returns true for both finished commands and interactive
|
|
|
|
|
// commands that it just installed. If no command is now active, the
|
|
|
|
|
// tool was a one-shot and we must turn the ribbon highlight off here —
|
|
|
|
|
// normally apply_cmd_result does that, but plugin dispatch can return
|
|
|
|
|
// without producing a CmdResult.
|
2026-06-27 16:16:08 +03:00
|
|
|
self.command_line.record_recent(cmd);
|
refactor: split four oversized files into submodule trees
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.
- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
with thin delegating arms; the 66 fattest arm bodies move to topic
methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
mspace,project,selection,modify,group_layer,preview}. The impl Scene
body is split across files via inherent-impl-per-file; struct, ctor,
fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
The 233-arm dispatch match becomes source-ordered per-family
dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.
Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:51:29 +03:00
|
|
|
if self.tabs[i].active_cmd.is_none() {
|
|
|
|
|
self.ribbon.deactivate_tool();
|
|
|
|
|
}
|
|
|
|
|
return Task::none();
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-27 16:16:08 +03:00
|
|
|
// Command families are dispatched in source order (see
|
|
|
|
|
// `dispatch_families`); the first whose `match` arm matches handles it.
|
|
|
|
|
if let Some(t) = self.dispatch_families(cmd, i) {
|
|
|
|
|
// A command resolved — record it for the right-click Repeat menu so
|
|
|
|
|
// commands from every source (command line, ribbon, context menu,
|
|
|
|
|
// shortcuts) appear there, not only typed ones. Recorded after
|
|
|
|
|
// resolution so a partial verb completed via the suggestion
|
|
|
|
|
// fallback (`BAC`) stores the real command (`BACKGROUND`).
|
|
|
|
|
self.command_line.record_recent(cmd);
|
refactor: split four oversized files into submodule trees
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.
- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
with thin delegating arms; the 66 fattest arm bodies move to topic
methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
mspace,project,selection,modify,group_layer,preview}. The impl Scene
body is split across files via inherent-impl-per-file; struct, ctor,
fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
The 233-arm dispatch match becomes source-ordered per-family
dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.
Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:51:29 +03:00
|
|
|
return t;
|
|
|
|
|
}
|
2026-06-27 16:16:08 +03:00
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Try each command family in source order, returning the first that
|
|
|
|
|
/// handles `cmd`, or `None` when none match. Each family returns
|
|
|
|
|
/// `Some(task)` for an arm it owns (early-returning or falling through to
|
|
|
|
|
/// `finish_dispatch`), or `None` to defer to the next — equivalent to one
|
|
|
|
|
/// sequential `match` over all arms.
|
|
|
|
|
fn dispatch_families(&mut self, cmd: &str, i: usize) -> Option<Task<Message>> {
|
|
|
|
|
if let Some(t) = self.dispatch_fileops(cmd, i) {
|
|
|
|
|
return Some(t);
|
|
|
|
|
}
|
refactor: split four oversized files into submodule trees
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.
- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
with thin delegating arms; the 66 fattest arm bodies move to topic
methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
mspace,project,selection,modify,group_layer,preview}. The impl Scene
body is split across files via inherent-impl-per-file; struct, ctor,
fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
The 233-arm dispatch match becomes source-ordered per-family
dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.
Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:51:29 +03:00
|
|
|
if let Some(t) = self.dispatch_layers(cmd, i) {
|
2026-06-27 16:16:08 +03:00
|
|
|
return Some(t);
|
refactor: split four oversized files into submodule trees
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.
- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
with thin delegating arms; the 66 fattest arm bodies move to topic
methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
mspace,project,selection,modify,group_layer,preview}. The impl Scene
body is split across files via inherent-impl-per-file; struct, ctor,
fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
The 233-arm dispatch match becomes source-ordered per-family
dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.
Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:51:29 +03:00
|
|
|
}
|
|
|
|
|
if let Some(t) = self.dispatch_blocks(cmd, i) {
|
2026-06-27 16:16:08 +03:00
|
|
|
return Some(t);
|
refactor: split four oversized files into submodule trees
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.
- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
with thin delegating arms; the 66 fattest arm bodies move to topic
methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
mspace,project,selection,modify,group_layer,preview}. The impl Scene
body is split across files via inherent-impl-per-file; struct, ctor,
fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
The 233-arm dispatch match becomes source-ordered per-family
dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.
Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:51:29 +03:00
|
|
|
}
|
|
|
|
|
if let Some(t) = self.dispatch_draw(cmd, i) {
|
2026-06-27 16:16:08 +03:00
|
|
|
return Some(t);
|
refactor: split four oversized files into submodule trees
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.
- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
with thin delegating arms; the 66 fattest arm bodies move to topic
methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
mspace,project,selection,modify,group_layer,preview}. The impl Scene
body is split across files via inherent-impl-per-file; struct, ctor,
fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
The 233-arm dispatch match becomes source-ordered per-family
dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.
Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:51:29 +03:00
|
|
|
}
|
|
|
|
|
if let Some(t) = self.dispatch_dim(cmd, i) {
|
2026-06-27 16:16:08 +03:00
|
|
|
return Some(t);
|
refactor: split four oversized files into submodule trees
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.
- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
with thin delegating arms; the 66 fattest arm bodies move to topic
methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
mspace,project,selection,modify,group_layer,preview}. The impl Scene
body is split across files via inherent-impl-per-file; struct, ctor,
fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
The 233-arm dispatch match becomes source-ordered per-family
dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.
Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:51:29 +03:00
|
|
|
}
|
|
|
|
|
if let Some(t) = self.dispatch_inquiry(cmd, i) {
|
2026-06-27 16:16:08 +03:00
|
|
|
return Some(t);
|
refactor: split four oversized files into submodule trees
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.
- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
with thin delegating arms; the 66 fattest arm bodies move to topic
methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
mspace,project,selection,modify,group_layer,preview}. The impl Scene
body is split across files via inherent-impl-per-file; struct, ctor,
fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
The 233-arm dispatch match becomes source-ordered per-family
dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.
Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:51:29 +03:00
|
|
|
}
|
|
|
|
|
if let Some(t) = self.dispatch_view(cmd, i) {
|
2026-06-27 16:16:08 +03:00
|
|
|
return Some(t);
|
refactor: split four oversized files into submodule trees
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.
- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
with thin delegating arms; the 66 fattest arm bodies move to topic
methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
mspace,project,selection,modify,group_layer,preview}. The impl Scene
body is split across files via inherent-impl-per-file; struct, ctor,
fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
The 233-arm dispatch match becomes source-ordered per-family
dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.
Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:51:29 +03:00
|
|
|
}
|
|
|
|
|
if let Some(t) = self.dispatch_layerprops(cmd, i) {
|
2026-06-27 16:16:08 +03:00
|
|
|
return Some(t);
|
refactor: split four oversized files into submodule trees
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.
- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
with thin delegating arms; the 66 fattest arm bodies move to topic
methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
mspace,project,selection,modify,group_layer,preview}. The impl Scene
body is split across files via inherent-impl-per-file; struct, ctor,
fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
The 233-arm dispatch match becomes source-ordered per-family
dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.
Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:51:29 +03:00
|
|
|
}
|
|
|
|
|
if let Some(t) = self.dispatch_styleprops(cmd, i) {
|
2026-06-27 16:16:08 +03:00
|
|
|
return Some(t);
|
refactor: split four oversized files into submodule trees
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.
- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
with thin delegating arms; the 66 fattest arm bodies move to topic
methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
mspace,project,selection,modify,group_layer,preview}. The impl Scene
body is split across files via inherent-impl-per-file; struct, ctor,
fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
The 233-arm dispatch match becomes source-ordered per-family
dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.
Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:51:29 +03:00
|
|
|
}
|
|
|
|
|
if let Some(t) = self.dispatch_display(cmd, i) {
|
2026-06-27 16:16:08 +03:00
|
|
|
return Some(t);
|
2026-06-27 14:45:51 +03:00
|
|
|
}
|
2026-06-27 16:16:08 +03:00
|
|
|
None
|
refactor: split four oversized files into submodule trees
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.
- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
with thin delegating arms; the 66 fattest arm bodies move to topic
methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
mspace,project,selection,modify,group_layer,preview}. The impl Scene
body is split across files via inherent-impl-per-file; struct, ctor,
fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
The 233-arm dispatch match becomes source-ordered per-family
dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.
Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:51:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Shared tail run after a `dispatch_*` family handler whose matched arm
|
|
|
|
|
/// did not early-return. Focuses the command line whenever a command just
|
|
|
|
|
/// became active.
|
|
|
|
|
fn finish_dispatch(&mut self, cmd: &str) -> Task<Message> {
|
|
|
|
|
let i = self.active_tab;
|
|
|
|
|
if self.tabs[i].active_cmd.is_some() {
|
|
|
|
|
self.tabs[i].last_cmd = Some(cmd.to_string());
|
|
|
|
|
self.focus_cmd_input()
|
|
|
|
|
} else {
|
|
|
|
|
Task::none()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ── Autocomplete registry — one-shot commands ──────────────────────────────
|
|
|
|
|
// These commands dispatch a single action (file ops, view, layer/style
|
|
|
|
|
// managers, undo/redo, …) rather than installing an interactive `CadCommand`,
|
|
|
|
|
// so they have no module of their own to register from. They are surfaced for
|
|
|
|
|
// command-line autocomplete here. Internal dispatch tokens that the user never
|
|
|
|
|
// types (REFEDIT_BEGIN, REFCLOSE_SAVE, REFCLOSE_DISCARD) are intentionally
|
|
|
|
|
// excluded.
|
|
|
|
|
inventory::submit!(crate::command::CommandRegistration {
|
|
|
|
|
names: &[
|
feat(commands): integrate standard CAD commands and fix behavior gaps
Broad pass over the command set: integrate missing commands, wire
previously-unreachable ribbon/menu buttons, and correct name/behaviour
mismatches. Every UI command token now resolves (real handler where the
infrastructure exists, an honest "not yet implemented" status otherwise).
New commands:
- Draw: 3DPOLY, 2D solid (SO/SOLID2D), HELIX, TRACE, SKETCH, DIMCENTER
(DCE/CENTERMARK)
- Modify/inquiry: REVERSE, MEASUREGEOM (MEA), DBLIST
- Data/manage: BASE, OVERKILL (exact-duplicate removal), AUDIT (read-only
integrity report), SETVAR (system-variable get/set), SCRIPT (.scr runner),
FINDNONPURGEABLE
Behaviour fixes:
- LINE and SPLINE gain Close/Undo; AREA computes area/perimeter in f64
(correct at large coordinates)
- ATTEDIT/ATE unified so the alias and the ribbon button open the
interactive editor; -ATTEDIT is the command-line form
- Linear/aligned/radius/diameter dimensions gain a text override (Text) and
text angle (Angle) option
- INSERT gains Scale/Rotate options; COPY gains an Array option
- LINETYPE SET sets the current entity linetype; SETBYLAYER resets overrides
- UNDO accepts a step count
Integrations: standard dimension/block aliases (DLI/DRA/DAN, BMAKE,
EXPORTPDF, DDIM), drafting-aid and screen toggles (GRID/SNAP/POLAR/OSNAP/
DSETTINGS/CLEANSCREEN/QUICKPROPERTIES), viewport tiling
(CASCADE/HORIZONTAL/VERTICAL/VPJOIN), and customization entry points
(CUI/ALIASEDIT).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:27:35 +03:00
|
|
|
// Drafting-aid / display toggles + customization entry points wired in the
|
|
|
|
|
// dispatch families (no interactive command module of their own).
|
|
|
|
|
"ALIASEDIT", "CLEANSCREEN", "CUI", "DSETTINGS", "GRID", "OSNAP", "POLAR",
|
|
|
|
|
"QUICKPROPERTIES", "SNAP",
|
|
|
|
|
// Viewport-arrangement shortcuts (delegate to VPORTS configurations).
|
|
|
|
|
"CASCADE", "HORIZONTAL", "VERTICAL", "VPJOIN",
|
|
|
|
|
// Standard aliases for existing commands.
|
|
|
|
|
"BMAKE", "EXPORTPDF", "DDIM",
|
|
|
|
|
// Inquiry: list the whole drawing database.
|
|
|
|
|
"DBLIST",
|
|
|
|
|
// Reset selected entities' overrides to follow their layer.
|
|
|
|
|
"SETBYLAYER",
|
|
|
|
|
// Remove duplicate objects; set drawing base point; audit integrity;
|
|
|
|
|
// read/write system variables.
|
|
|
|
|
"OVERKILL", "BASE", "AUDIT", "SETVAR", "SCRIPT", "SCR", "FINDNONPURGEABLE",
|
refactor: split four oversized files into submodule trees
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.
- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
with thin delegating arms; the 66 fattest arm bodies move to topic
methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
mspace,project,selection,modify,group_layer,preview}. The impl Scene
body is split across files via inherent-impl-per-file; struct, ctor,
fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
The 233-arm dispatch match becomes source-ordered per-family
dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.
Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:51:29 +03:00
|
|
|
"3DORBIT", "3O", "ABOUT", "ATTDISP", "ATTEXT", "BACKGROUND", "CDIMSTY", "CELTSCALE",
|
|
|
|
|
"CHANGELOG", "CHPROP", "CLAYER", "CLEAR", "CLR", "COLORSCHEME", "COUNT", "DATAEXTRACTION",
|
|
|
|
|
"DE", "DESELALL", "DESELECT", "DIMSTYLE", "DONATE", "DRAWORDER", "DWGPROP", "DWGPROPS",
|
|
|
|
|
"EATTEXT", "EXIT", "EXPORT", "EXPORTSTEP", "EXPORTSTL", "FILETAB", "FIND", "FLATTEN",
|
|
|
|
|
"HELP", "HIDEOBJECTS", "IM", "IMAGE", "IMAGEATTACH", "IMPORTOBJ", "ISOLATEOBJECTS", "LA",
|
|
|
|
|
"LAYER", "LAYERS", "LAYISO", "LAYON", "LAYOUTMANAGER", "LAYOUTPANEL", "LAYOUTTAB", "LAYTHW",
|
|
|
|
|
"LAYUNISO", "LI", "LINETYPE", "LIST", "LTSCALE", "LWDISPLAY", "MASSPROP", "MLEADERSTYLE",
|
|
|
|
|
"MLSTYLE", "MS", "MSPACE", "NAVVCUBE", "NEW", "OBJIMPORT", "OPEN", "ORTHO",
|
|
|
|
|
"P", "PAN", "PAGESETUP", "PERF", "PERSP", "PLOT", "PLOTSTYLE", "PLOTSTYLEEDITOR",
|
|
|
|
|
"PLOTSTYLEPANEL", "PR",
|
|
|
|
|
"PRINT", "PROPERTIES", "PROPS", "PSPACE", "PURGE", "QS", "QSAVE", "QSELECT",
|
2026-06-27 16:32:40 +03:00
|
|
|
"QUIT", "REDO", "REDRAW", "REDRWALL", "REGEN", "REGENALL", "RENAME", "REPORT",
|
refactor: split four oversized files into submodule trees
Break up the four giant files (~29k lines total) into focused submodule
directories, one concern per file. Pure mechanical moves — behavior is
unchanged.
- app/update.rs (9650) -> app/update/{mod,viewport,command,style,file,
dynamic,dialog,util}. The 384-arm update_inner match stays in mod.rs
with thin delegating arms; the 66 fattest arm bodies move to topic
methods. Arm set preserved exactly (384 -> 384).
- scene/mod.rs (9017) -> scene/{mod,entity,tess,hittest,layout,paper,
mspace,project,selection,modify,group_layer,preview}. The impl Scene
body is split across files via inherent-impl-per-file; struct, ctor,
fields and load-time helpers stay in the root. fn count 123 -> 123.
- app/commands.rs (6082) -> app/commands/* grouped by command family.
The 233-arm dispatch match becomes source-ordered per-family
dispatch_* handlers, preserving first-match precedence (233 -> 233).
- app/view.rs (4686) -> app/view/{mod,overlay,modal,viewcube,controls}.
Largest file drops from 9650 to 3343. Builds clean; app launches and
loads plugins with no panic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:51:29 +03:00
|
|
|
"SA", "SAVE", "SAVEAS", "SCALETEXT", "SELECTALL", "SELECTSIMILAR", "SELSIM", "SHEETSET",
|
|
|
|
|
"SHORTCUTS", "SOLID", "SSM", "STEPOUT", "STLOUT", "STPOUT", "STYLE", "STYLESMANAGER",
|
|
|
|
|
"TABLESTYLE", "TOOLPALETTES", "TP", "TS", "U", "UCS", "UCSICON", "UNDERLAY",
|
|
|
|
|
"UNDO", "UNISOLATEOBJECTS", "USERI", "USERR", "VIEW", "VPORTS", "VS", "VW",
|
|
|
|
|
"WB", "WBLOCK", "WEBVERSION", "WIREFRAME", "XA", "XATTACH", "XDATA", "XR",
|
|
|
|
|
"XREF", "XRELOAD", "ZOOM", "ZS",
|
|
|
|
|
]
|
|
|
|
|
});
|