#[derive(Debug, thiserror::Error)]
pub enum ClipboardError {
#[error(
"Content too large for clipboard: {content_len} bytes exceeds {limit} byte limit. \
Consider using streaming mode (without --clip) or processing fewer files."
)]
SizeExceeded {
content_len: usize,
limit: usize,
},
#[error("Failed to access clipboard: {0}")]
Access(String),
#[error("Failed to copy to clipboard: {0}")]
Write(String),
#[error("Failed to spawn clipboard thread: {0}")]
ThreadSpawn(#[from] std::io::Error),
#[error("Clipboard operation timed out (system clipboard might be locked)")]
Timeout,
#[error("Clipboard thread exited without sending a result")]
ThreadLost,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_size_exceeded_display_includes_both_values() {
let err = ClipboardError::SizeExceeded {
content_len: 2_000_000,
limit: 1_000_000,
};
let msg = err.to_string();
assert!(
msg.contains("2000000") && msg.contains("1000000"),
"Display should include both content_len and limit: {msg}"
);
}
#[test]
fn test_access_error_display() {
let err = ClipboardError::Access("no display server".to_string());
assert!(err.to_string().contains("no display server"));
}
#[test]
fn test_write_error_display() {
let err = ClipboardError::Write("permission denied".to_string());
assert!(err.to_string().contains("permission denied"));
}
#[test]
fn test_timeout_error_display() {
let err = ClipboardError::Timeout;
assert!(err.to_string().contains("timed out"));
}
#[test]
fn test_thread_lost_error_display() {
let err = ClipboardError::ThreadLost;
assert!(err.to_string().contains("without sending a result"));
}
#[test]
fn test_thread_spawn_from_io_error() {
let io_err = std::io::Error::other("no threads");
let err = ClipboardError::from(io_err);
assert!(matches!(err, ClipboardError::ThreadSpawn(_)));
}
}