From 23b7b3784ba432ca7459fb6782c6bbe9dd0b6cba Mon Sep 17 00:00:00 2001 From: jess Date: Wed, 27 May 2026 16:05:55 -0700 Subject: [PATCH] Fixed bug where external implementations of EditorState with no native front end caused objc2 version mismatch between arboard and trash crates to cause the editor to crash. For external use cases with pure ICED winit, set default-features=false --- viewport/Cargo.toml | 8 ++++++-- viewport/src/browser/model.rs | 6 +++--- viewport/src/editor/mod.rs | 2 +- viewport/src/editor/sidecar_io.rs | 2 +- viewport/src/handle.rs | 18 +++++++++--------- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/viewport/Cargo.toml b/viewport/Cargo.toml index d23effc..199c58b 100644 --- a/viewport/Cargo.toml +++ b/viewport/Cargo.toml @@ -29,9 +29,13 @@ filetime = "0.2" regex = "1" printpdf = { version = "0.9", default-features = false } +[features] +default = ["native-shell"] +native-shell = ["arboard", "trash"] + [target.'cfg(not(target_os = "ios"))'.dependencies] -arboard = "3" -trash = "5" +arboard = { version = "3", optional = true } +trash = { version = "5", optional = true } [build-dependencies] cbindgen = "0.29" diff --git a/viewport/src/browser/model.rs b/viewport/src/browser/model.rs index 3bb50b4..47ae089 100644 --- a/viewport/src/browser/model.rs +++ b/viewport/src/browser/model.rs @@ -281,14 +281,14 @@ pub fn trash(item_path: &Path) -> std::io::Result<()> { } } -#[cfg(not(target_os = "ios"))] +#[cfg(all(not(target_os = "ios"), feature = "native-shell"))] fn trash_crate_remove(path: &Path) -> Result<(), Box> { trash::delete(path).map_err(|e| Box::new(e) as Box) } -#[cfg(target_os = "ios")] +#[cfg(any(target_os = "ios", not(feature = "native-shell")))] fn trash_crate_remove(_path: &Path) -> Result<(), Box> { - Err("trash crate not available on iOS; falling back to permanent delete".into()) + Err("trash not available in embedded mode; falling back to permanent delete".into()) } pub fn path_segments(current: &Path, root: &Path) -> Vec<(String, PathBuf)> { diff --git a/viewport/src/editor/mod.rs b/viewport/src/editor/mod.rs index 44fa6bd..33ec4b6 100644 --- a/viewport/src/editor/mod.rs +++ b/viewport/src/editor/mod.rs @@ -14,7 +14,7 @@ mod types; mod undo; mod update; pub use state::EditorState; -#[cfg(not(target_os = "ios"))] +#[cfg(all(not(target_os = "ios"), feature = "native-shell"))] pub use sidecar_io::write_clipboard_image_to_cache; pub use types::{ Anchor, ComputedImage, ComputedTable, ComputedTree, ContextMenuState, FindState, diff --git a/viewport/src/editor/sidecar_io.rs b/viewport/src/editor/sidecar_io.rs index caed015..a3dae91 100644 --- a/viewport/src/editor/sidecar_io.rs +++ b/viewport/src/editor/sidecar_io.rs @@ -303,7 +303,7 @@ pub(super) fn load_image_from_path(src: &str) -> Option { } /// encodes a clipboard image to PNG and writes it into the on-disk cache -#[cfg(not(target_os = "ios"))] +#[cfg(all(not(target_os = "ios"), feature = "native-shell"))] pub fn write_clipboard_image_to_cache(img: &arboard::ImageData) -> Option { let dir = dirs::home_dir()?.join(".acord").join("cache").join("images"); std::fs::create_dir_all(&dir).ok()?; diff --git a/viewport/src/handle.rs b/viewport/src/handle.rs index 0735248..7b268ed 100644 --- a/viewport/src/handle.rs +++ b/viewport/src/handle.rs @@ -20,12 +20,12 @@ use crate::palette; use crate::table_block::TableMessage; use crate::ViewportHandle; -#[cfg(not(target_os = "ios"))] +#[cfg(all(not(target_os = "ios"), feature = "native-shell"))] struct AcordClipboard { board: std::cell::RefCell, } -#[cfg(not(target_os = "ios"))] +#[cfg(all(not(target_os = "ios"), feature = "native-shell"))] impl clipboard::Clipboard for AcordClipboard { fn read(&self, _kind: clipboard::Kind) -> Option { let mut board = self.board.borrow_mut(); @@ -46,11 +46,11 @@ impl clipboard::Clipboard for AcordClipboard { } } -/// iOS stub; UIPasteboard access handled on the Swift side via shell-action bus. -#[cfg(target_os = "ios")] +/// stub clipboard for iOS and embedded consumers without native-shell. +#[cfg(any(target_os = "ios", not(feature = "native-shell")))] struct AcordClipboard; -#[cfg(target_os = "ios")] +#[cfg(any(target_os = "ios", not(feature = "native-shell")))] impl clipboard::Clipboard for AcordClipboard { fn read(&self, _kind: clipboard::Kind) -> Option { None } fn write(&mut self, _kind: clipboard::Kind, _contents: String) {} @@ -224,11 +224,11 @@ pub fn render(handle: &mut ViewportHandle) { &mut handle.renderer, ); - #[cfg(not(target_os = "ios"))] + #[cfg(all(not(target_os = "ios"), feature = "native-shell"))] let mut clipboard = AcordClipboard { board: std::cell::RefCell::new(arboard::Clipboard::new().unwrap()), }; - #[cfg(target_os = "ios")] + #[cfg(any(target_os = "ios", not(feature = "native-shell")))] let mut clipboard = AcordClipboard; let mut messages: Vec = Vec::new(); let mut consumed: Vec = Vec::new(); @@ -673,13 +673,13 @@ pub fn render(handle: &mut ViewportHandle) { handle.state.update(msg); } - #[cfg(not(target_os = "ios"))] + #[cfg(all(not(target_os = "ios"), feature = "native-shell"))] if let Some(text) = handle.state.pending_clipboard.take() { if let Ok(mut board) = arboard::Clipboard::new() { let _ = board.set_text(text); } } - #[cfg(target_os = "ios")] + #[cfg(any(target_os = "ios", not(feature = "native-shell")))] let _ = handle.state.pending_clipboard.take(); handle.state.tick();