forked from 1b-agent/opencadstudio-upstream
fix(plugin): drive headless tasks, invalidate layer cache, and handle cancel event
This commit is contained in:
1 parent
bc6ad1a5fe
commit
270b6102de
10 files changed
+208
-20
No files matched your search
@@ -556,6 +556,8 @@ pub trait HostApi {
|
||||
/// Add a layer to the active document with full initial properties.
|
||||
/// If an optional property in `config` is `None`, standard CAD defaults are applied.
|
||||
/// Returns `None` if the layer already exists or `config.name` is invalid.
|
||||
///
|
||||
/// To modify properties of an already existing layer, use [`modify_layer`](Self::modify_layer).
|
||||
fn add_layer(&mut self, config: LayerConfig) -> Option<Handle> {
|
||||
let _ = config;
|
||||
None
|
||||
@@ -564,12 +566,24 @@ pub trait HostApi {
|
||||
/// Modify specified properties of an existing layer in the active document.
|
||||
/// Properties that are `None` in `config` are left untouched as-is.
|
||||
/// Returns `false` if the layer does not exist or `config.name` is invalid.
|
||||
///
|
||||
/// To create a new layer, use [`add_layer`](Self::add_layer).
|
||||
fn modify_layer(&mut self, config: LayerConfig) -> bool {
|
||||
let _ = config;
|
||||
false
|
||||
}
|
||||
|
||||
/// Run a command on the active document tab's command line (AutoLISP style).
|
||||
/// Run a command on the active document tab's command line (AutoLISP / script style).
|
||||
///
|
||||
/// The string is passed to the host command driver as if entered into the command line,
|
||||
/// supporting command names, space/newline-delimited arguments, AutoCAD-compatible
|
||||
/// aliases, system variable setters (e.g. `SETVAR PDMODE 3`), and display commands
|
||||
/// (e.g. `VSCURRENT`, `GRID`, `SNAP`).
|
||||
///
|
||||
/// Headless async tasks spawned by commands are automatically pumped through the host
|
||||
/// application lifecycle.
|
||||
///
|
||||
/// Returns `true` if the command was recognized and initiated successfully, `false` otherwise.
|
||||
fn execute_command(&mut self, cmd: &str) -> bool {
|
||||
let _ = cmd;
|
||||
false
|
||||
|
||||
@@ -419,7 +419,12 @@ impl HostApi for PluginHostApi {
|
||||
|
||||
fn add_layer(&mut self, config: crate::host::LayerConfig) -> Option<Handle> {
|
||||
match self.client.request(PluginRequest::AddLayer(config)) {
|
||||
Ok(PluginResponse::OptHandle(h)) => h,
|
||||
Ok(PluginResponse::OptHandle(h)) => {
|
||||
if h.is_some() {
|
||||
self.document_cache = OnceCell::new();
|
||||
}
|
||||
h
|
||||
}
|
||||
Ok(other) => {
|
||||
eprintln!("[plugin] unexpected AddLayer response: {other:?}");
|
||||
None
|
||||
@@ -433,7 +438,12 @@ impl HostApi for PluginHostApi {
|
||||
|
||||
fn modify_layer(&mut self, config: crate::host::LayerConfig) -> bool {
|
||||
match self.client.request(PluginRequest::ModifyLayer(config)) {
|
||||
Ok(PluginResponse::Bool(b)) => b,
|
||||
Ok(PluginResponse::Bool(b)) => {
|
||||
if b {
|
||||
self.document_cache = OnceCell::new();
|
||||
}
|
||||
b
|
||||
}
|
||||
Ok(other) => {
|
||||
eprintln!("[plugin] unexpected ModifyLayer response: {other:?}");
|
||||
false
|
||||
|
||||
@@ -27,9 +27,14 @@ pub use acadrust::{CadDocument, EntityType, Handle};
|
||||
/// Events the host forwards to an active plugin `InteractiveCommand`.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum InteractiveEvent {
|
||||
/// User clicked or specified a point coordinate.
|
||||
Point([f64; 3]),
|
||||
/// User pressed Enter or Return to complete input.
|
||||
Enter,
|
||||
/// User selected an existing entity in the drawing.
|
||||
ObjectPick { handle: Handle, pt: [f64; 3] },
|
||||
/// User cancelled the prompt (e.g. pressed ESC), resetting interactive collection.
|
||||
Cancel,
|
||||
}
|
||||
|
||||
/// Initial handshake sent by the plugin runner immediately after connecting.
|
||||
|
||||
@@ -733,7 +733,12 @@ impl HostApi for V4PluginHostApi {
|
||||
|
||||
fn add_layer(&mut self, config: crate::host::LayerConfig) -> Option<Handle> {
|
||||
match self.request(PluginRequest::AddLayer(config)) {
|
||||
Ok(PluginResponse::OptHandle(h)) => h,
|
||||
Ok(PluginResponse::OptHandle(h)) => {
|
||||
if h.is_some() {
|
||||
self.document_cache = OnceCell::new();
|
||||
}
|
||||
h
|
||||
}
|
||||
Ok(other) => {
|
||||
eprintln!("[plugin] unexpected AddLayer response: {other:?}");
|
||||
None
|
||||
@@ -747,7 +752,12 @@ impl HostApi for V4PluginHostApi {
|
||||
|
||||
fn modify_layer(&mut self, config: crate::host::LayerConfig) -> bool {
|
||||
match self.request(PluginRequest::ModifyLayer(config)) {
|
||||
Ok(PluginResponse::Bool(b)) => b,
|
||||
Ok(PluginResponse::Bool(b)) => {
|
||||
if b {
|
||||
self.document_cache = OnceCell::new();
|
||||
}
|
||||
b
|
||||
}
|
||||
Ok(other) => {
|
||||
eprintln!("[plugin] unexpected ModifyLayer response: {other:?}");
|
||||
false
|
||||
|
||||
@@ -22,7 +22,7 @@ use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::host::{BuiltinPlugin, InteractiveCommand};
|
||||
use crate::host::{BuiltinPlugin, CommandStep, InteractiveCommand};
|
||||
use crate::ipc::client::{InteractiveRegistry, IpcClient, PluginHostApi};
|
||||
use crate::ipc::protocol::{
|
||||
HostRequest, HostResponse, HostToPlugin, InteractiveEvent, PluginToHost, PLUGIN_TOKEN_ENV,
|
||||
@@ -170,7 +170,11 @@ fn handle_host_request(
|
||||
}
|
||||
}
|
||||
HostRequest::InteractiveEvent { command_id, event } => {
|
||||
let step = {
|
||||
if matches!(event, InteractiveEvent::Cancel) {
|
||||
interactive.borrow_mut().remove(&command_id);
|
||||
return HostResponse::CommandStep(Box::new(CommandStep::Cancel));
|
||||
}
|
||||
let (step, done) = {
|
||||
let mut registry = interactive.borrow_mut();
|
||||
let Some(cmd) = registry.get_mut(&command_id) else {
|
||||
return HostResponse::Error(format!(
|
||||
@@ -178,14 +182,30 @@ fn handle_host_request(
|
||||
));
|
||||
};
|
||||
let cmd_ref: &mut dyn InteractiveCommand = cmd.as_mut();
|
||||
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| match event {
|
||||
let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| match event {
|
||||
InteractiveEvent::Point(pt) => cmd_ref.on_point(pt),
|
||||
InteractiveEvent::Enter => cmd_ref.on_enter(),
|
||||
InteractiveEvent::ObjectPick { handle, pt } => {
|
||||
cmd_ref.on_object_pick(handle, pt)
|
||||
}
|
||||
}))
|
||||
InteractiveEvent::Cancel => CommandStep::Cancel,
|
||||
}));
|
||||
match res {
|
||||
Ok(s) => {
|
||||
let is_done = matches!(
|
||||
s,
|
||||
CommandStep::Done
|
||||
| CommandStep::Cancel
|
||||
| CommandStep::CommitAndEnd(_)
|
||||
);
|
||||
(Ok(s), is_done)
|
||||
}
|
||||
Err(_) => (Err(()), true),
|
||||
}
|
||||
};
|
||||
if done {
|
||||
interactive.borrow_mut().remove(&command_id);
|
||||
}
|
||||
match step {
|
||||
Ok(s) => HostResponse::CommandStep(Box::new(s)),
|
||||
Err(_) => HostResponse::Error("interactive command panicked".to_string()),
|
||||
@@ -269,7 +289,11 @@ fn handle_host_request_v4(
|
||||
}
|
||||
}
|
||||
HostRequest::InteractiveEvent { command_id, event } => {
|
||||
let step = {
|
||||
if matches!(event, InteractiveEvent::Cancel) {
|
||||
interactive.borrow_mut().remove(&command_id);
|
||||
return Some(HostResponse::CommandStep(Box::new(CommandStep::Cancel)));
|
||||
}
|
||||
let (step, done) = {
|
||||
let mut registry = interactive.borrow_mut();
|
||||
let Some(cmd) = registry.get_mut(&command_id) else {
|
||||
return Some(HostResponse::Error(format!(
|
||||
@@ -277,14 +301,30 @@ fn handle_host_request_v4(
|
||||
)));
|
||||
};
|
||||
let cmd_ref: &mut dyn InteractiveCommand = cmd.as_mut();
|
||||
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| match event {
|
||||
let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| match event {
|
||||
InteractiveEvent::Point(pt) => cmd_ref.on_point(pt),
|
||||
InteractiveEvent::Enter => cmd_ref.on_enter(),
|
||||
InteractiveEvent::ObjectPick { handle, pt } => {
|
||||
cmd_ref.on_object_pick(handle, pt)
|
||||
}
|
||||
}))
|
||||
InteractiveEvent::Cancel => CommandStep::Cancel,
|
||||
}));
|
||||
match res {
|
||||
Ok(s) => {
|
||||
let is_done = matches!(
|
||||
s,
|
||||
CommandStep::Done
|
||||
| CommandStep::Cancel
|
||||
| CommandStep::CommitAndEnd(_)
|
||||
);
|
||||
(Ok(s), is_done)
|
||||
}
|
||||
Err(_) => (Err(()), true),
|
||||
}
|
||||
};
|
||||
if done {
|
||||
interactive.borrow_mut().remove(&command_id);
|
||||
}
|
||||
match step {
|
||||
Ok(s) => Some(HostResponse::CommandStep(Box::new(s))),
|
||||
Err(_) => Some(HostResponse::Error("interactive command panicked".to_string())),
|
||||
|
||||
Reference in new issue
Block a user