use std::{
io::{Read, Write},
net::SocketAddr,
};
use base64::{prelude::BASE64_STANDARD, Engine};
use clap::Args;
use image::{codecs::bmp::BmpEncoder, ImageEncoder};
use crate::{
clipboard::{Content, Image},
protocol::Connection,
};
#[derive(Args, Debug)]
struct ClientCli {
#[arg(long, default_value = "127.0.0.1:14573")]
target: SocketAddr,
}
#[derive(Args, Debug)]
pub struct PasteCli {
#[command(flatten)]
client: ClientCli,
#[arg(long)]
iterm2: bool,
}
#[derive(Args, Debug)]
pub struct CopyCli {
#[command(flatten)]
client: ClientCli,
}
fn is_tmux() -> bool {
std::env::var("TERM").is_ok_and(|term| term.starts_with("tmux") || term.starts_with("screen"))
}
fn print_image(args: &PasteCli, image: Image) {
let mut bmp = Vec::new();
BmpEncoder::new(&mut bmp)
.write_image(
&image.bytes,
image.width as u32,
image.height as u32,
image::ExtendedColorType::Rgba8,
)
.unwrap();
let mut stdout = std::io::stdout().lock();
let is_tmux = is_tmux();
if args.iterm2 {
if is_tmux {
stdout.write_all("\x1bPtmux;\x1b\x1b]".as_bytes()).unwrap();
} else {
stdout.write_all("\x1b]".as_bytes()).unwrap();
}
writeln!(&mut stdout, "1337;File=size={};inline=1:", bmp.len()).unwrap();
}
stdout
.write_all(BASE64_STANDARD.encode(&bmp).as_bytes())
.unwrap();
if args.iterm2 {
if is_tmux {
stdout.write_all("\x07\x1b\\".as_bytes()).unwrap();
} else {
stdout.write_all("\x07".as_bytes()).unwrap();
}
}
}
pub fn paste(args: PasteCli) -> anyhow::Result<()> {
let stream = std::net::TcpStream::connect(args.client.target).unwrap();
let mut conn = Connection::new(&stream, &stream);
conn.send_command("PASTE")?;
match conn.read_command()?.as_str() {
"COPY TEXT" => {
let text = conn.read_string()?;
print!("{}", text);
}
"COPY IMAGE" => {
let image = conn.read_image()?;
print_image(&args, image);
}
"COPY NONE" => {}
response => {
return Err(anyhow::anyhow!("Unexpected response: {}", response));
}
}
Ok(())
}
pub fn copy(args: CopyCli) -> anyhow::Result<()> {
let stream = std::net::TcpStream::connect(args.client.target).unwrap();
let mut conn = Connection::new(&stream, &stream);
let mut content = String::new();
std::io::stdin().read_to_string(&mut content)?;
conn.send_clipboard(&Some(Content::Text(content)))?;
Ok(())
}