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
This commit is contained in:
jess 2026-05-27 16:05:55 -07:00
parent e9c2b9ed80
commit 23b7b3784b
5 changed files with 20 additions and 16 deletions

View File

@ -29,9 +29,13 @@ filetime = "0.2"
regex = "1" regex = "1"
printpdf = { version = "0.9", default-features = false } printpdf = { version = "0.9", default-features = false }
[features]
default = ["native-shell"]
native-shell = ["arboard", "trash"]
[target.'cfg(not(target_os = "ios"))'.dependencies] [target.'cfg(not(target_os = "ios"))'.dependencies]
arboard = "3" arboard = { version = "3", optional = true }
trash = "5" trash = { version = "5", optional = true }
[build-dependencies] [build-dependencies]
cbindgen = "0.29" cbindgen = "0.29"

View File

@ -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<dyn std::error::Error>> { fn trash_crate_remove(path: &Path) -> Result<(), Box<dyn std::error::Error>> {
trash::delete(path).map_err(|e| Box::new(e) as Box<dyn std::error::Error>) trash::delete(path).map_err(|e| Box::new(e) as Box<dyn std::error::Error>)
} }
#[cfg(target_os = "ios")] #[cfg(any(target_os = "ios", not(feature = "native-shell")))]
fn trash_crate_remove(_path: &Path) -> Result<(), Box<dyn std::error::Error>> { fn trash_crate_remove(_path: &Path) -> Result<(), Box<dyn std::error::Error>> {
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)> { pub fn path_segments(current: &Path, root: &Path) -> Vec<(String, PathBuf)> {

View File

@ -14,7 +14,7 @@ mod types;
mod undo; mod undo;
mod update; mod update;
pub use state::EditorState; 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 sidecar_io::write_clipboard_image_to_cache;
pub use types::{ pub use types::{
Anchor, ComputedImage, ComputedTable, ComputedTree, ContextMenuState, FindState, Anchor, ComputedImage, ComputedTable, ComputedTree, ContextMenuState, FindState,

View File

@ -303,7 +303,7 @@ pub(super) fn load_image_from_path(src: &str) -> Option<ImageCacheEntry> {
} }
/// encodes a clipboard image to PNG and writes it into the on-disk cache /// 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<String> { pub fn write_clipboard_image_to_cache(img: &arboard::ImageData) -> Option<String> {
let dir = dirs::home_dir()?.join(".acord").join("cache").join("images"); let dir = dirs::home_dir()?.join(".acord").join("cache").join("images");
std::fs::create_dir_all(&dir).ok()?; std::fs::create_dir_all(&dir).ok()?;

View File

@ -20,12 +20,12 @@ use crate::palette;
use crate::table_block::TableMessage; use crate::table_block::TableMessage;
use crate::ViewportHandle; use crate::ViewportHandle;
#[cfg(not(target_os = "ios"))] #[cfg(all(not(target_os = "ios"), feature = "native-shell"))]
struct AcordClipboard { struct AcordClipboard {
board: std::cell::RefCell<arboard::Clipboard>, board: std::cell::RefCell<arboard::Clipboard>,
} }
#[cfg(not(target_os = "ios"))] #[cfg(all(not(target_os = "ios"), feature = "native-shell"))]
impl clipboard::Clipboard for AcordClipboard { impl clipboard::Clipboard for AcordClipboard {
fn read(&self, _kind: clipboard::Kind) -> Option<String> { fn read(&self, _kind: clipboard::Kind) -> Option<String> {
let mut board = self.board.borrow_mut(); 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. /// stub clipboard for iOS and embedded consumers without native-shell.
#[cfg(target_os = "ios")] #[cfg(any(target_os = "ios", not(feature = "native-shell")))]
struct AcordClipboard; struct AcordClipboard;
#[cfg(target_os = "ios")] #[cfg(any(target_os = "ios", not(feature = "native-shell")))]
impl clipboard::Clipboard for AcordClipboard { impl clipboard::Clipboard for AcordClipboard {
fn read(&self, _kind: clipboard::Kind) -> Option<String> { None } fn read(&self, _kind: clipboard::Kind) -> Option<String> { None }
fn write(&mut self, _kind: clipboard::Kind, _contents: String) {} fn write(&mut self, _kind: clipboard::Kind, _contents: String) {}
@ -224,11 +224,11 @@ pub fn render(handle: &mut ViewportHandle) {
&mut handle.renderer, &mut handle.renderer,
); );
#[cfg(not(target_os = "ios"))] #[cfg(all(not(target_os = "ios"), feature = "native-shell"))]
let mut clipboard = AcordClipboard { let mut clipboard = AcordClipboard {
board: std::cell::RefCell::new(arboard::Clipboard::new().unwrap()), 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 clipboard = AcordClipboard;
let mut messages: Vec<Message> = Vec::new(); let mut messages: Vec<Message> = Vec::new();
let mut consumed: Vec<usize> = Vec::new(); let mut consumed: Vec<usize> = Vec::new();
@ -673,13 +673,13 @@ pub fn render(handle: &mut ViewportHandle) {
handle.state.update(msg); 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 Some(text) = handle.state.pending_clipboard.take() {
if let Ok(mut board) = arboard::Clipboard::new() { if let Ok(mut board) = arboard::Clipboard::new() {
let _ = board.set_text(text); let _ = board.set_text(text);
} }
} }
#[cfg(target_os = "ios")] #[cfg(any(target_os = "ios", not(feature = "native-shell")))]
let _ = handle.state.pending_clipboard.take(); let _ = handle.state.pending_clipboard.take();
handle.state.tick(); handle.state.tick();