forked from 1b-agent/opencadstudio-upstream
Snapshot: V4 plugin API and host integration
This commit is contained in:
1 parent
448869ac35
commit
29c41a4041
36 files changed
+5463
-253
No files matched your search
+12
-5
@@ -55,7 +55,7 @@ pub struct ExternalPlugin {
|
||||
impl ExternalPlugin {
|
||||
/// True when the package's API version is supported by this host.
|
||||
pub fn api_compatible(&self) -> bool {
|
||||
self.api_version == ocs_plugin_api::API_VERSION
|
||||
ocs_plugin_api::manifest::host_accepts_plugin_version(self.api_version)
|
||||
}
|
||||
|
||||
/// True when the package can be loaded today: compatible API *and* a native
|
||||
@@ -273,6 +273,7 @@ pub(crate) use loader::{load_at_startup, loaded_ids};
|
||||
#[cfg_attr(test, allow(dead_code))]
|
||||
mod loader {
|
||||
use super::lib_extension;
|
||||
use crate::plugin::v4_support;
|
||||
use ocs_plugin_api::process::PluginManager;
|
||||
use std::cell::RefCell;
|
||||
use std::path::{Path, PathBuf};
|
||||
@@ -291,6 +292,7 @@ mod loader {
|
||||
) -> Vec<(String, Result<(), String>)> {
|
||||
let discovered = super::discover();
|
||||
let mut manager = PluginManager::new();
|
||||
manager.set_notification_handler(v4_support::notification_handler());
|
||||
let mut out = Vec::new();
|
||||
for d in &discovered {
|
||||
if !d.api_compatible() || !d.lib_present {
|
||||
@@ -350,12 +352,13 @@ mod loader {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, not(target_arch = "wasm32")))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::plugin::v4_support;
|
||||
|
||||
#[test]
|
||||
fn api_v2_plugin_from_template_is_incompatible() {
|
||||
fn api_v2_plugin_from_template_is_compatible() {
|
||||
let toml = r#"
|
||||
[plugin]
|
||||
id = "opencad.my_plugin"
|
||||
@@ -374,7 +377,7 @@ xdata_apps = ["MYPLUGIN_RECORD"]
|
||||
assert_eq!(p.api_version, 2);
|
||||
assert_eq!(p.repository.as_deref(), Some("example/opencad-my-plugin"));
|
||||
assert!(p.command_prefixes.contains(&"MP_".to_string()));
|
||||
assert!(!p.api_compatible(), "old API plugins must be rebuilt");
|
||||
assert!(p.api_compatible(), "V2 plugins must be accepted by the V4 host");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -415,7 +418,11 @@ xdata_apps = ["MYPLUGIN_RECORD"]
|
||||
|
||||
let mut app = crate::app::OpenCADStudio::new_for_test();
|
||||
let mut host = crate::app::plugin_host::HostSession::new(&mut app, 0);
|
||||
let process = ocs_plugin_api::process::PluginProcess::spawn(&path, &mut host)
|
||||
let process = ocs_plugin_api::process::PluginProcess::spawn(
|
||||
&path,
|
||||
&mut host,
|
||||
v4_support::notification_handler(),
|
||||
)
|
||||
.expect("spawn test plugin");
|
||||
assert_eq!(process.id(), "opencad.my_plugin");
|
||||
let mut started = false;
|
||||
|
||||
@@ -291,11 +291,12 @@ pub fn install(release: &Release, repository: &str) -> Result<String, String> {
|
||||
|
||||
let toml_text = download_string(&toml.url)?;
|
||||
let manifest = external::parse_plugin_toml(&toml_text).ok_or("plugin.toml is missing an id")?;
|
||||
if manifest.api_version != ocs_plugin_api::API_VERSION {
|
||||
if !ocs_plugin_api::manifest::host_accepts_plugin_version(manifest.api_version) {
|
||||
return Err(format!(
|
||||
"API version {} is incompatible (host requires {})",
|
||||
"API version {} is incompatible (host supports {}-{})",
|
||||
manifest.api_version,
|
||||
ocs_plugin_api::API_VERSION
|
||||
ocs_plugin_api::manifest::API_VERSION_MIN_SUPPORTED,
|
||||
ocs_plugin_api::manifest::effective_max_api_version()
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ pub mod external;
|
||||
pub mod host;
|
||||
pub mod marketplace;
|
||||
pub mod registry;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod v4_support;
|
||||
|
||||
pub use registry::{all_ribbon_modules, plugin_command_names, ribbon_modules_enabled};
|
||||
pub(crate) use registry::try_dispatch;
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
//! Host-side V4 snapshot and notification support for the Python REPL plugin.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use ocs_plugin_api::host::{HostNotification, PluginNotification};
|
||||
use ocs_plugin_api::host_v4::{manager, HostV4SnapshotManager};
|
||||
use ocs_plugin_api::process::NotificationHandler;
|
||||
use ocs_plugin_api::shm::DocumentViewInfo;
|
||||
|
||||
fn mgr() -> std::sync::MutexGuard<'static, HostV4SnapshotManager> {
|
||||
manager().lock().unwrap()
|
||||
}
|
||||
|
||||
/// Open (or refresh) the V4 shared document view for `tab_id`.
|
||||
pub fn open_document_view_v4(
|
||||
tab_id: u64,
|
||||
doc: &acadrust::CadDocument,
|
||||
) -> Option<DocumentViewInfo> {
|
||||
mgr().open(tab_id, doc)
|
||||
}
|
||||
|
||||
/// Close the V4 shared document view for `tab_id`.
|
||||
pub fn close_document_view_v4(tab_id: u64) {
|
||||
mgr().close(tab_id);
|
||||
}
|
||||
|
||||
/// Publish the latest document to the V4 shared view for `tab_id` and broadcast
|
||||
/// a change notification when successful.
|
||||
pub fn publish_document_view_v4(tab_id: u64, doc: &acadrust::CadDocument) {
|
||||
let info = mgr().publish(tab_id, doc);
|
||||
if let Some(info) = info {
|
||||
broadcast(HostNotification::DocumentChangedV4 {
|
||||
tab_id,
|
||||
version: info.version,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Notify V4 plugins that a tab has been closed and clean up its snapshot.
|
||||
pub fn on_tab_closed(tab_id: u64) {
|
||||
close_document_view_v4(tab_id);
|
||||
broadcast(HostNotification::DocumentTabClosed { tab_id });
|
||||
}
|
||||
|
||||
/// V4 notification handler installed on the plugin manager.
|
||||
///
|
||||
/// Forwards REPL status messages to the log; other notifications are handled
|
||||
/// by the manager's per-plugin routing.
|
||||
pub fn notification_handler() -> NotificationHandler {
|
||||
Arc::new(|plugin_id, _command_id, notification| {
|
||||
if let PluginNotification::ReplStatus { status, message } = notification {
|
||||
eprintln!("[{plugin_id}] REPL status {status}: {message}");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn broadcast(notification: HostNotification) {
|
||||
crate::plugin::external::with_manager(|mgr| {
|
||||
mgr.broadcast_notification(None, notification);
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user