use crate::bridge::fnc_session_store::{BridgeSessionId, SessionPayload, SessionStore};
use crate::clipboard;
use anyhow::Result;
#[derive(Debug, Clone)]
pub struct BridgeClipboardOptions {
pub strip_ansi: bool,
pub use_crlf: bool,
}
impl Default for BridgeClipboardOptions {
fn default() -> Self {
Self {
strip_ansi: true,
use_crlf: true,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BridgeClipboardMode {
Text,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BridgeClipboardResult {
pub mode: BridgeClipboardMode,
pub bytes_copied: u64,
}
pub fn apply_session_to_clipboard_with<F>(
store: &mut SessionStore,
id: BridgeSessionId,
_opts: &BridgeClipboardOptions,
set_text: F,
) -> Result<BridgeClipboardResult>
where
F: Fn(&str) -> Result<()>,
{
let payload = store.get_payload(id)?;
match payload {
SessionPayload::InMemory(bytes) => {
let text = std::str::from_utf8(&bytes)
.map_err(|e| anyhow::anyhow!("invalid UTF-8 in session payload: {e}"))?;
set_text(text)?;
Ok(BridgeClipboardResult {
mode: BridgeClipboardMode::Text,
bytes_copied: bytes.len() as u64,
})
}
SessionPayload::TempFile(path) => {
let bytes = std::fs::read(&path)
.map_err(|e| anyhow::anyhow!("failed to read session temp file: {e}"))?;
let _ = std::fs::remove_file(&path);
let text = std::str::from_utf8(&bytes)
.map_err(|e| anyhow::anyhow!("invalid UTF-8 in session payload: {e}"))?;
set_text(text)?;
Ok(BridgeClipboardResult {
mode: BridgeClipboardMode::Text,
bytes_copied: bytes.len() as u64,
})
}
}
}
pub fn apply_session_to_clipboard(
store: &mut SessionStore,
id: BridgeSessionId,
_opts: &BridgeClipboardOptions,
) -> Result<BridgeClipboardResult> {
apply_session_to_clipboard_with(store, id, _opts, clipboard::set_text_content)
}
pub fn apply_warning_to_clipboard<F>(message: &str, set_text: F) -> Result<BridgeClipboardResult>
where
F: Fn(&str) -> Result<()>,
{
set_text(message)?;
Ok(BridgeClipboardResult {
mode: BridgeClipboardMode::Text,
bytes_copied: message.len() as u64,
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::bridge::fnc_session_store::{SessionStore, SessionStoreConfig};
use std::sync::{Arc, Mutex};
use std::time::Duration;
#[test]
fn apply_uses_injected_clipboard() {
let cfg = SessionStoreConfig {
default_max_bytes: 1024,
default_ttl: Duration::from_secs(60),
default_idle_exit: Duration::from_secs(60),
spill_threshold: 8,
};
let store = SessionStore::new(cfg);
let mut store = store.lock().unwrap();
let id = store.open_session(None);
store.put_chunk(id, b"hello").unwrap();
store.finalize(id).unwrap();
let seen = Arc::new(Mutex::new(None::<String>));
let seen_clone = seen.clone();
let res = apply_session_to_clipboard_with(
&mut store,
id,
&BridgeClipboardOptions::default(),
|text| {
*seen_clone.lock().unwrap() = Some(text.to_string());
Ok(())
},
)
.unwrap();
assert_eq!(res.bytes_copied, 5);
assert_eq!(seen.lock().unwrap().as_deref(), Some("hello"));
}
#[test]
fn apply_warning_writes_message() {
let seen = Arc::new(Mutex::new(None::<String>));
let seen_clone = seen.clone();
let res = apply_warning_to_clipboard("warn-msg", |text| {
*seen_clone.lock().unwrap() = Some(text.to_string());
Ok(())
})
.unwrap();
assert_eq!(res.bytes_copied, 8);
assert_eq!(seen.lock().unwrap().as_deref(), Some("warn-msg"));
}
}