use std::cell::RefCell;
pub use rich_ext::clipboard::{ClipboardError, CopyFormat, CLIPBOARD_VAR, MAX_BYTES};
#[derive(Default)]
struct State {
unavailable: Option<String>,
open: bool,
pending: Vec<String>,
}
thread_local! {
static STATE: RefCell<State> = RefCell::new(State::default());
}
pub fn copy(text: impl Into<String>) -> Result<(), ClipboardError> {
let text = text.into();
if text.len() > MAX_BYTES {
return Err(ClipboardError::TooLarge { bytes: text.len() });
}
STATE.with(|state| {
let mut state = state.borrow_mut();
if !state.open {
return Err(ClipboardError::Unsupported(
"no interactive session is running".into(),
));
}
if let Some(reason) = &state.unavailable {
return Err(ClipboardError::Unsupported(reason.clone()));
}
state.pending.push(text);
Ok(())
})
}
pub fn available() -> bool {
STATE.with(|state| {
let state = state.borrow();
state.open && state.unavailable.is_none()
})
}
pub fn report(what: &str, result: &Result<(), ClipboardError>) -> String {
match result {
Ok(()) => format!("copied {what}"),
Err(ClipboardError::Unsupported(_)) => {
format!(
"cannot copy {what}: no terminal clipboard (set {CLIPBOARD_VAR}=1 to force OSC 52)"
)
}
Err(error) => format!("cannot copy {what}: {error}"),
}
}
pub(crate) fn open(unavailable: Option<String>) {
STATE.with(|state| {
let mut state = state.borrow_mut();
state.open = true;
state.unavailable = unavailable;
state.pending.clear();
});
}
pub(crate) fn close() -> Vec<String> {
STATE.with(|state| {
let mut state = state.borrow_mut();
state.open = false;
state.unavailable = None;
std::mem::take(&mut state.pending)
})
}
pub(crate) struct SessionEnvironment;
impl rich_ext::capabilities::Environment for SessionEnvironment {
fn var(&self, name: &str) -> Option<String> {
std::env::var(name).ok()
}
fn is_terminal(&self) -> bool {
true
}
fn size(&self) -> Option<(usize, usize)> {
None
}
}