feat(plugins): expose document path to plugins via HostApi

OpenCADStudio/plugins#901 (comment)

- Add HostApi::document_path(tab_id) returning Option<PathBuf>.
- Add PluginRequest::DocumentPath and PluginResponse::DocumentPath for
  out-of-process plugins.
- Implement the request in the IPC server and in both V3/V4 plugin-side
  HostApi proxies.
- Implement HostSession::document_path by looking up the tab by id and
  returning its current_path.
This commit is contained in:
Sebastian committed 2026-08-29 11:09:31 +02:00
1 parent 3024869de0
commit 09ba67bfd1
6 files changed
+58

No files matched your search

+10
View File
@@ -12,6 +12,7 @@
//! [`ensure_plugin_state`] helpers for the ergonomic typed access.
use std::any::Any;
use std::path::PathBuf;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
@@ -531,6 +532,15 @@ pub trait HostApi {
fn add_entities(&mut self, entities: Vec<EntityType>) -> Vec<Handle> {
entities.into_iter().map(|e| self.add_entity(e)).collect()
}
/// Return the filesystem path of the document in tab `tab_id`, if any.
/// Added after API v4; appended at the very end so older plugins compiled
/// without it keep stable vtable indices. The default returns `None`;
/// in-process hosts should override it to expose the real path.
fn document_path(&self, tab_id: u64) -> Option<PathBuf> {
let _ = tab_id;
None
}
}
/// Simplified, read-only entity kind exposed by [`DocumentReader`].
+15
View File
@@ -401,6 +401,21 @@ impl HostApi for PluginHostApi {
None => Box::new(EmptyDocumentReader),
}
}
fn document_path(&self, tab_id: u64) -> Option<std::path::PathBuf> {
match self.client.request(PluginRequest::DocumentPath { tab_id }) {
Ok(PluginResponse::DocumentPath(Some(path))) => Some(std::path::PathBuf::from(path)),
Ok(PluginResponse::DocumentPath(None)) => None,
Ok(other) => {
eprintln!("[plugin] unexpected DocumentPath response: {other:?}");
None
}
Err(e) => {
eprintln!("[plugin] DocumentPath request failed: {e}");
None
}
}
}
}
/// Sentinel reader used when the shared-memory view could not be initialized.
@@ -136,6 +136,8 @@ pub enum PluginRequest {
CloseDocumentViewV4 { tab_id: u64 },
/// V4: ask the host for the stable tab identifier of the active tab.
GetTabId,
/// V4: ask the host for the filesystem path of the document in `tab_id`.
DocumentPath { tab_id: u64 },
}
/// Responses the host sends back for `PluginRequest`.
@@ -160,6 +162,8 @@ pub enum PluginResponse {
},
/// V4: stable tab identifier of the active tab.
TabId(u64),
/// V4: filesystem path of the document in the requested tab, if any.
DocumentPath(Option<String>),
}
/// Messages sent from the host to the plugin runner.
+3
View File
@@ -74,5 +74,8 @@ pub fn handle_plugin_request(
PluginResponse::Ok
}
GetTabId => PluginResponse::TabId(host.tab_id()),
DocumentPath { tab_id } => {
PluginResponse::DocumentPath(host.document_path(tab_id).map(|p| p.to_string_lossy().to_string()))
}
}
}
@@ -715,6 +715,21 @@ impl HostApi for V4PluginHostApi {
view.take();
}
}
fn document_path(&self, tab_id: u64) -> Option<std::path::PathBuf> {
match self.request(PluginRequest::DocumentPath { tab_id }) {
Ok(PluginResponse::DocumentPath(Some(path))) => Some(std::path::PathBuf::from(path)),
Ok(PluginResponse::DocumentPath(None)) => None,
Ok(other) => {
eprintln!("[plugin] unexpected DocumentPath response: {other:?}");
None
}
Err(e) => {
eprintln!("[plugin] DocumentPath request failed: {e}");
None
}
}
}
}
#[cfg(test)]
+11
View File
@@ -35,6 +35,14 @@ impl<'a> HostSession<'a> {
self.app.tabs[self.tab].id
}
pub fn document_path(&self, tab_id: u64) -> Option<std::path::PathBuf> {
self.app
.tabs
.iter()
.find(|t| t.id == tab_id)
.and_then(|t| t.current_path.clone())
}
#[cfg(not(target_arch = "wasm32"))]
pub fn document_view_v4(&mut self, tab_id: u64) -> Option<ocs_plugin_api::shm::DocumentViewInfo> {
if tab_id != self.tab_id() {
@@ -341,6 +349,9 @@ impl HostApi for HostSession<'_> {
fn tab_id(&self) -> u64 {
self.tab_id()
}
fn document_path(&self, tab_id: u64) -> Option<std::path::PathBuf> {
self.document_path(tab_id)
}
#[cfg(not(target_arch = "wasm32"))]
fn document_view_v4(&mut self, tab_id: u64) -> Option<ocs_plugin_api::shm::DocumentViewInfo> {
self.document_view_v4(tab_id)