refactor(commands): unified StepInput → feed_command step router (F0)
Introduce the single place every input source funnels through to drive the active command's step machine: a `StepInput` vocabulary (one variant per `CadCommand::on_*` method) and `OpenCADStudio::feed_command`, which routes the input to the matching `on_*` and applies the result. Sources keep their own classification (raw input → which StepInput); only the routing is centralized. Migrate the headless automation feeder onto it: feed_active_cmd builds a StepInput, the terminator sends StepInput::Enter. No behavior change — automation_ops_round_trip still passes. Also fixes headless inline-argument loss for plugin commands (#162): run_headless now offers the whole line to plugin dispatch first (plugins parse their own inline args, e.g. `HC_PIPE 2B 2C 1.25 0.013`), falling back to the first-word + fed-tokens path for built-in interactive tools. First phase of routing all input sources (command line, dynamic input, plugin API, viewport clicks) through one driver. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
69ea050124
commit
5fdd212592
3 changed files with 96 additions and 25 deletions
|
|
@ -372,12 +372,35 @@ impl OpenCADStudio {
|
|||
let _ = self.dispatch_command(cmd);
|
||||
return;
|
||||
}
|
||||
// Plugin commands parse their own inline arguments from the whole line
|
||||
// (e.g. `HC_PIPE 2B 2C 1.25 0.013`), so offer the full command to plugin
|
||||
// dispatch first. A built-in interactive tool matches only its bare name
|
||||
// (`LINE`), so the full line is not a plugin command and falls through to
|
||||
// the first-word + fed-tokens path below. (#162)
|
||||
if crate::plugin::try_dispatch(self, i, cmd) {
|
||||
// The plugin either committed immediately (inline args consumed) or
|
||||
// installed an interactive command — feed any remaining tokens and
|
||||
// finish it on Enter, as for a built-in tool.
|
||||
self.finish_headless_interactive(&tokens);
|
||||
return;
|
||||
}
|
||||
let _ = self.dispatch_command(tokens[0]);
|
||||
if self.tabs[i].active_cmd.is_none() {
|
||||
// Not an interactive tool — an inline-argument command.
|
||||
let _ = self.dispatch_command(cmd);
|
||||
return;
|
||||
}
|
||||
self.finish_headless_interactive(&tokens);
|
||||
}
|
||||
|
||||
/// Feed `tokens[1..]` to the active interactive command as points / option
|
||||
/// keywords, then terminate it as if Enter were pressed (LINE / PLINE finish
|
||||
/// on Enter). No-op when no command is active.
|
||||
fn finish_headless_interactive(&mut self, tokens: &[&str]) {
|
||||
let i = self.active_tab;
|
||||
if self.tabs[i].active_cmd.is_none() {
|
||||
return;
|
||||
}
|
||||
self.last_point = None;
|
||||
for tok in &tokens[1..] {
|
||||
if self.tabs[i].active_cmd.is_none() {
|
||||
|
|
@ -386,17 +409,15 @@ impl OpenCADStudio {
|
|||
self.feed_active_cmd(tok);
|
||||
}
|
||||
// Terminate a still-open command (LINE / PLINE finish on Enter).
|
||||
if self.tabs[i].active_cmd.is_some() {
|
||||
if let Some(r) = self.tabs[i].active_cmd.as_mut().map(|c| c.on_enter()) {
|
||||
let _ = self.apply_cmd_result(r);
|
||||
}
|
||||
}
|
||||
let _ = self.feed_command(crate::command::StepInput::Enter);
|
||||
}
|
||||
|
||||
/// Feed one token to the active command. When the command is picking an
|
||||
/// existing entity, the token is a hex handle; otherwise a coordinate point
|
||||
/// or an option keyword.
|
||||
/// Classify one headless token into a [`StepInput`] and route it through the
|
||||
/// shared [`OpenCADStudio::feed_command`]. When the command is picking an
|
||||
/// existing entity the token is a hex handle; otherwise it is a coordinate
|
||||
/// point or an option keyword / value.
|
||||
fn feed_active_cmd(&mut self, token: &str) {
|
||||
use crate::command::StepInput;
|
||||
let i = self.active_tab;
|
||||
// Object-pick step: the token is a handle (as returned by `query`).
|
||||
if self.tabs[i]
|
||||
|
|
@ -419,13 +440,7 @@ impl OpenCADStudio {
|
|||
)
|
||||
})
|
||||
.unwrap_or(glam::Vec3::ZERO);
|
||||
if let Some(r) = self.tabs[i]
|
||||
.active_cmd
|
||||
.as_mut()
|
||||
.map(|c| c.on_entity_pick(handle, pt.as_dvec3()))
|
||||
{
|
||||
let _ = self.apply_cmd_result(r);
|
||||
}
|
||||
let _ = self.feed_command(StepInput::EntityPick(handle, pt.as_dvec3()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -436,15 +451,9 @@ impl OpenCADStudio {
|
|||
}
|
||||
}
|
||||
self.last_point = Some(pt);
|
||||
if let Some(r) = self.tabs[i].active_cmd.as_mut().map(|c| c.on_point(pt.as_dvec3())) {
|
||||
let _ = self.apply_cmd_result(r);
|
||||
}
|
||||
} else if let Some(r) = self.tabs[i]
|
||||
.active_cmd
|
||||
.as_mut()
|
||||
.and_then(|c| c.on_text_input(token))
|
||||
{
|
||||
let _ = self.apply_cmd_result(r);
|
||||
let _ = self.feed_command(StepInput::Point(pt.as_dvec3()));
|
||||
} else {
|
||||
let _ = self.feed_command(StepInput::Text(token.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue