forked from 1b-agent/opencadstudio-upstream
Add versioned host settings API for plugins
This commit is contained in:
1 parent
93afe91afc
commit
ec2271fc9c
13 files changed
+218
-17
No files matched your search
@@ -60,6 +60,13 @@ pub enum LogLevel {
|
||||
Error,
|
||||
}
|
||||
|
||||
/// Value of a host-managed drafting or document setting exposed to plugins.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum HostSettingValue {
|
||||
Text(String),
|
||||
Number(f64),
|
||||
}
|
||||
|
||||
/// A notification the host sends to a plugin. These are best-effort,
|
||||
/// full-duplex messages correlated with an optional `command_id`.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
@@ -552,6 +559,22 @@ pub trait HostApi {
|
||||
let _ = tab_id;
|
||||
None
|
||||
}
|
||||
|
||||
/// Read a named host setting without invoking the command dispatcher.
|
||||
/// Names are case-insensitive. Hosts may support only a subset.
|
||||
fn system_variable(&self, _name: &str) -> Option<HostSettingValue> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Set a named host setting without re-entering command dispatch.
|
||||
/// Returns the effective value after validation and normalization.
|
||||
fn set_system_variable(
|
||||
&mut self,
|
||||
_name: &str,
|
||||
_value: HostSettingValue,
|
||||
) -> Result<HostSettingValue, String> {
|
||||
Err("system variable is not supported by this host".to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
/// Simplified, read-only entity kind exposed by [`DocumentReader`].
|
||||
|
||||
@@ -11,7 +11,7 @@ use acadrust::{CadDocument, EntityType, Handle};
|
||||
use interprocess::local_socket::traits::Stream as StreamTrait;
|
||||
use interprocess::local_socket::{GenericNamespaced, Stream, ToNsName};
|
||||
|
||||
use crate::host::{DocumentReader, HostApi, InteractiveCommand, ReaderEntity};
|
||||
use crate::host::{DocumentReader, HostApi, HostSettingValue, InteractiveCommand, ReaderEntity};
|
||||
use crate::ipc::protocol::{
|
||||
HostResponse, HostToPlugin, PluginRequest, PluginResponse, PluginToHost, RunnerHandshake,
|
||||
};
|
||||
@@ -416,6 +416,34 @@ impl HostApi for PluginHostApi {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn system_variable(&self, name: &str) -> Option<HostSettingValue> {
|
||||
match self.client.request(PluginRequest::GetSystemVariable { name: name.to_owned() }) {
|
||||
Ok(PluginResponse::SystemVariable(value)) => value,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_system_variable(
|
||||
&mut self,
|
||||
name: &str,
|
||||
value: HostSettingValue,
|
||||
) -> Result<HostSettingValue, String> {
|
||||
match self.client.request(PluginRequest::SetSystemVariable {
|
||||
name: name.to_owned(),
|
||||
value,
|
||||
}) {
|
||||
Ok(PluginResponse::SystemVariableResult(result)) => {
|
||||
if result.is_ok() {
|
||||
self.document_cache = OnceCell::new();
|
||||
}
|
||||
result
|
||||
}
|
||||
Ok(PluginResponse::Error(error)) => Err(error),
|
||||
Ok(other) => Err(format!("unexpected system variable response: {other:?}")),
|
||||
Err(error) => Err(error.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sentinel reader used when the shared-memory view could not be initialized.
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::host::{CommandSource, CommandStep};
|
||||
use crate::host::{CommandSource, CommandStep, HostSettingValue};
|
||||
use crate::manifest::ApiVersion;
|
||||
use crate::ribbon::owned::{OwnedPluginManifest, OwnedRibbonGroup};
|
||||
|
||||
@@ -138,6 +138,10 @@ pub enum PluginRequest {
|
||||
GetTabId,
|
||||
/// V5: ask the host for the filesystem path of the document in `tab_id`.
|
||||
DocumentPath { tab_id: u64 },
|
||||
/// Read a host-managed setting without nested command dispatch.
|
||||
GetSystemVariable { name: String },
|
||||
/// Change a host-managed setting without nested command dispatch.
|
||||
SetSystemVariable { name: String, value: HostSettingValue },
|
||||
}
|
||||
|
||||
/// Responses the host sends back for `PluginRequest`.
|
||||
@@ -164,6 +168,8 @@ pub enum PluginResponse {
|
||||
TabId(u64),
|
||||
/// V5: filesystem path of the document in the requested tab, if any.
|
||||
DocumentPath(Option<std::ffi::OsString>),
|
||||
SystemVariable(Option<HostSettingValue>),
|
||||
SystemVariableResult(Result<HostSettingValue, String>),
|
||||
}
|
||||
|
||||
/// Messages sent from the host to the plugin runner.
|
||||
|
||||
@@ -77,5 +77,11 @@ pub fn handle_plugin_request(
|
||||
DocumentPath { tab_id } => PluginResponse::DocumentPath(
|
||||
host.document_path(tab_id).map(|path| path.into_os_string()),
|
||||
),
|
||||
GetSystemVariable { name } => {
|
||||
PluginResponse::SystemVariable(host.system_variable(&name))
|
||||
}
|
||||
SetSystemVariable { name, value } => {
|
||||
PluginResponse::SystemVariableResult(host.set_system_variable(&name, value))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ use interprocess::TryClone;
|
||||
|
||||
use crate::host::{
|
||||
DocumentReader, ExecutionResult, HostApi, HostNotification, InteractiveCommand,
|
||||
PluginNotification, PluginRequestSender, PluginRequestError, ReaderEntity,
|
||||
PluginNotification, PluginRequestSender, PluginRequestError, ReaderEntity, HostSettingValue,
|
||||
};
|
||||
use crate::ipc::protocol::{
|
||||
HostRequest, HostResponse, PluginRequest, PluginResponse, RunnerHandshake,
|
||||
@@ -730,6 +730,34 @@ impl HostApi for V4PluginHostApi {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn system_variable(&self, name: &str) -> Option<HostSettingValue> {
|
||||
match self.request(PluginRequest::GetSystemVariable { name: name.to_owned() }) {
|
||||
Ok(PluginResponse::SystemVariable(value)) => value,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_system_variable(
|
||||
&mut self,
|
||||
name: &str,
|
||||
value: HostSettingValue,
|
||||
) -> Result<HostSettingValue, String> {
|
||||
match self.request(PluginRequest::SetSystemVariable {
|
||||
name: name.to_owned(),
|
||||
value,
|
||||
}) {
|
||||
Ok(PluginResponse::SystemVariableResult(result)) => {
|
||||
if result.is_ok() {
|
||||
self.document_cache = OnceCell::new();
|
||||
}
|
||||
result
|
||||
}
|
||||
Ok(PluginResponse::Error(error)) => Err(error),
|
||||
Ok(other) => Err(format!("unexpected system variable response: {other:?}")),
|
||||
Err(error) => Err(error.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -19,8 +19,9 @@
|
||||
/// vtable so API v2 plugins keep working. v4 adds full-duplex notifications on
|
||||
/// a multiplexed socket while leaving the V2/V3 ABI and protocol untouched. v5
|
||||
/// adds the `BuiltinPlugin::on_load` lifecycle callback and
|
||||
/// `HostApi::document_path`.
|
||||
pub const API_VERSION: u32 = 5;
|
||||
/// `HostApi::document_path`. v6 appends generic host system-variable access
|
||||
/// (`HostApi::system_variable` / `set_system_variable`).
|
||||
pub const API_VERSION: u32 = 6;
|
||||
|
||||
/// Oldest plugin API major the current host still loads. This keeps previously
|
||||
/// compiled cdylibs usable as long as their vtable layout is a prefix of the
|
||||
@@ -28,7 +29,7 @@ pub const API_VERSION: u32 = 5;
|
||||
pub const API_VERSION_MIN_SUPPORTED: u32 = 2;
|
||||
|
||||
/// Environment variable that caps the API major accepted by the host at
|
||||
/// runtime. Set to `4` to disable V5 plugins, `3` to disable V4, or `2` for
|
||||
/// runtime. Set to `5` to disable V6 plugins, `4` to disable V5, or `2` for
|
||||
/// V2-only mode.
|
||||
pub const MAX_API_VERSION_ENV: &str = "OCS_PLUGIN_MAX_API_VERSION";
|
||||
|
||||
|
||||
Reference in new issue
Block a user