diff --git a/crates/ocs_plugin_api/src/host.rs b/crates/ocs_plugin_api/src/host.rs index f146c23ab..8a78042a0 100644 --- a/crates/ocs_plugin_api/src/host.rs +++ b/crates/ocs_plugin_api/src/host.rs @@ -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) -> Vec { 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 { + let _ = tab_id; + None + } } /// Simplified, read-only entity kind exposed by [`DocumentReader`]. diff --git a/crates/ocs_plugin_api/src/ipc/client.rs b/crates/ocs_plugin_api/src/ipc/client.rs index 4fb050e1a..3a617fc02 100644 --- a/crates/ocs_plugin_api/src/ipc/client.rs +++ b/crates/ocs_plugin_api/src/ipc/client.rs @@ -401,6 +401,21 @@ impl HostApi for PluginHostApi { None => Box::new(EmptyDocumentReader), } } + + fn document_path(&self, tab_id: u64) -> Option { + 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. diff --git a/crates/ocs_plugin_api/src/ipc/protocol.rs b/crates/ocs_plugin_api/src/ipc/protocol.rs index 5b494026a..d599fdd13 100644 --- a/crates/ocs_plugin_api/src/ipc/protocol.rs +++ b/crates/ocs_plugin_api/src/ipc/protocol.rs @@ -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), } /// Messages sent from the host to the plugin runner. diff --git a/crates/ocs_plugin_api/src/ipc/server.rs b/crates/ocs_plugin_api/src/ipc/server.rs index 51ad9ac8a..2285b0968 100644 --- a/crates/ocs_plugin_api/src/ipc/server.rs +++ b/crates/ocs_plugin_api/src/ipc/server.rs @@ -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())) + } } } diff --git a/crates/ocs_plugin_api/src/ipc/v4/client.rs b/crates/ocs_plugin_api/src/ipc/v4/client.rs index a491a6ebc..03cbf20ae 100644 --- a/crates/ocs_plugin_api/src/ipc/v4/client.rs +++ b/crates/ocs_plugin_api/src/ipc/v4/client.rs @@ -715,6 +715,21 @@ impl HostApi for V4PluginHostApi { view.take(); } } + + fn document_path(&self, tab_id: u64) -> Option { + 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)] diff --git a/src/app/plugin_host.rs b/src/app/plugin_host.rs index 272e89039..d60992822 100644 --- a/src/app/plugin_host.rs +++ b/src/app/plugin_host.rs @@ -35,6 +35,14 @@ impl<'a> HostSession<'a> { self.app.tabs[self.tab].id } + pub fn document_path(&self, tab_id: u64) -> Option { + 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 { 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 { + self.document_path(tab_id) + } #[cfg(not(target_arch = "wasm32"))] fn document_view_v4(&mut self, tab_id: u64) -> Option { self.document_view_v4(tab_id)