use base64::prelude::{Engine, BASE64_STANDARD};
use std::fmt;
use std::str::FromStr;
use crate::{osc, Command};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ClipboardType {
Clipboard,
Primary,
Other(char),
}
impl From<&ClipboardType> for char {
fn from(val: &ClipboardType) -> Self {
match val {
ClipboardType::Clipboard => 'c',
ClipboardType::Primary => 'p',
ClipboardType::Other(other) => *other,
}
}
}
impl From<char> for ClipboardType {
fn from(value: char) -> Self {
match value {
'c' => ClipboardType::Clipboard,
'p' => ClipboardType::Primary,
other => ClipboardType::Other(other),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ClipboardSelection(
)
pub Vec<ClipboardType>,
);
impl ClipboardSelection {
fn to_osc52_pc(&self) -> String {
self.0.iter().map(Into::<char>::into).collect()
}
}
impl fmt::Display for ClipboardSelection {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.to_osc52_pc())
}
}
impl FromStr for ClipboardSelection {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(ClipboardSelection(
s.chars().map(From::<char>::from).collect(),
))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CopyToClipboard<T> {
pub content: T,
pub destination: ClipboardSelection,
}
impl<T: AsRef<[u8]>> Command for CopyToClipboard<T> {
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
write!(
f,
osc!("52;{destination};{encoded_text}"),
destination = self.destination.to_osc52_pc(),
encoded_text = BASE64_STANDARD.encode(&self.content)
)
}
#[cfg(windows)]
fn execute_winapi(&self) -> std::io::Result<()> {
use std::io;
Err(io::Error::new(
io::ErrorKind::Unsupported,
"Copying is not implemented for the Windows API.",
))
}
}
impl<T: AsRef<[u8]>> CopyToClipboard<T> {
pub fn to_clipboard_from(content: T) -> CopyToClipboard<T> {
CopyToClipboard {
content,
destination: ClipboardSelection(vec![ClipboardType::Clipboard]),
}
}
pub fn to_primary_from(content: T) -> CopyToClipboard<T> {
CopyToClipboard {
content,
destination: ClipboardSelection(vec![ClipboardType::Primary]),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_clipboard_string_to_selection() {
assert_eq!(
ClipboardSelection::from_str("p").unwrap(),
ClipboardSelection(vec![ClipboardType::Primary])
);
assert_eq!(
ClipboardSelection::from_str("").unwrap(),
ClipboardSelection(vec![])
);
assert_eq!(
ClipboardSelection::from_str("cp").unwrap(),
ClipboardSelection(vec![ClipboardType::Clipboard, ClipboardType::Primary])
);
}
#[test]
fn test_clipboard_selection_to_osc52_pc() {
assert_eq!(ClipboardSelection(vec![]).to_osc52_pc(), "");
assert_eq!(
ClipboardSelection(vec![ClipboardType::Clipboard]).to_osc52_pc(),
"c"
);
assert_eq!(
ClipboardSelection(vec![ClipboardType::Primary]).to_osc52_pc(),
"p"
);
assert_eq!(
ClipboardSelection(vec![ClipboardType::Primary, ClipboardType::Clipboard])
.to_osc52_pc(),
"pc"
);
assert_eq!(
ClipboardSelection(vec![ClipboardType::Clipboard, ClipboardType::Primary])
.to_osc52_pc(),
"cp"
);
assert_eq!(
ClipboardSelection(vec![ClipboardType::Other('s')]).to_osc52_pc(),
"s"
);
}
#[test]
fn test_clipboard_copy_string_osc52() {
let mut buffer = String::new();
super::CopyToClipboard {
content: "foo",
destination: ClipboardSelection(vec![ClipboardType::Clipboard]),
}
.write_ansi(&mut buffer)
.unwrap();
assert_eq!(buffer, "\x1b]52;c;Zm9v\x1b\\");
buffer.clear();
super::CopyToClipboard {
content: "foo",
destination: ClipboardSelection(vec![ClipboardType::Primary]),
}
.write_ansi(&mut buffer)
.unwrap();
assert_eq!(buffer, "\x1b]52;p;Zm9v\x1b\\");
buffer.clear();
super::CopyToClipboard {
content: "foo",
destination: ClipboardSelection(vec![ClipboardType::Primary, ClipboardType::Clipboard]),
}
.write_ansi(&mut buffer)
.unwrap();
assert_eq!(buffer, "\x1b]52;pc;Zm9v\x1b\\");
buffer.clear();
super::CopyToClipboard {
content: "foo",
destination: ClipboardSelection(vec![]),
}
.write_ansi(&mut buffer)
.unwrap();
assert_eq!(buffer, "\x1b]52;;Zm9v\x1b\\");
}
#[test]
fn test_clipboard_copy_string_osc52_constructor() {
let mut buffer = String::new();
super::CopyToClipboard::to_clipboard_from("foo")
.write_ansi(&mut buffer)
.unwrap();
assert_eq!(buffer, "\x1b]52;c;Zm9v\x1b\\");
let mut buffer = String::new();
super::CopyToClipboard::to_primary_from("foo")
.write_ansi(&mut buffer)
.unwrap();
assert_eq!(buffer, "\x1b]52;p;Zm9v\x1b\\");
}
}