Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow reading any format of data from clipboard #95

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
target
.vscode
*.png
examples/tmp/*
46 changes: 46 additions & 0 deletions examples/get_bytes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use std::{fs, path::PathBuf};

use arboard::Clipboard;

const FILE_TYPES: &'static [(&[u8], &str)] = &[
(b"image/png", "png"),
(b"image/jpeg", "jpeg"),
(b"image/bmp", "bmp"),
(b"image/gif", "gif"),
(b"text/html", "html"),
(b"text/plain", "txt"),
(b"text/uri-list", "txt"),
(b"SAVE_TARGETS", "sav.txt"),
];

fn main() {
let mut clipboard = Clipboard::new().unwrap();

println!("Formats available are: {:#?}", clipboard.get_formats());

let tmp_path = PathBuf::from("./examples/tmp/");
if tmp_path.exists() {
fs::remove_dir_all(&tmp_path).unwrap();
}
fs::create_dir_all(&tmp_path).unwrap();

for (mime, ext) in FILE_TYPES.iter() {

let path = tmp_path.join(&format!(
"output-{}.{ext}",
mime.into_iter()
.map(|c| if (*c as char).is_alphanumeric() { *c as char } else { '-' })
.collect::<String>()
));

if let Ok(data) = clipboard.get_bytes(mime) {
println!("Saving {:?} as {}", mime, path.display());
fs::write(path, data).unwrap();
} else {
println!(
r#""{}" mime-type not available"#,
String::from_utf8_lossy(mime) // mime.into_iter().map(|c| *c as char).collect::<String>()
)
}
}
}
13 changes: 12 additions & 1 deletion examples/hello_world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,20 @@ use simple_logger::SimpleLogger;
fn main() {
SimpleLogger::new().init().unwrap();
let mut clipboard = Clipboard::new().unwrap();

for format in [b"text/html" as &[u8], b"text/plain", b"image/png", b"application/json"] {
println!("Format: {:?}", String::from_utf8_lossy(format));
println!(
"Content: {:#?}",
clipboard
.get_bytes(format)
.map(|bytes| bytes.into_iter().map(|c| c as char).collect::<String>())
);
}

println!("Clipboard text was: {:?}", clipboard.get_text());

let the_string = "Hello, world!";
clipboard.set_text(the_string).unwrap();
// clipboard.set_text(the_string).unwrap();
println!("But now the clipboard text should be: \"{}\"", the_string);
}
11 changes: 11 additions & 0 deletions examples/set_bytes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use arboard::Clipboard;
use simple_logger::SimpleLogger;
use std::{fs, thread, time::Duration};

fn main() {
SimpleLogger::new().init().unwrap();
let mut ctx = Clipboard::new().unwrap();
ctx.set_bytes(fs::read("./examples/ferris.png").unwrap(), &b"image/png".to_owned()).unwrap();
println!("Copied rust logo(staying for 5s)");
thread::sleep(Duration::from_secs(2));
}
5 changes: 5 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ pub enum Error {
#[error("The image or the text that was about the be transferred to/from the clipboard could not be converted to the appropriate format.")]
ConversionFailure,

/// This can happen if format is not available.
#[error("Possible format is unsupported")]
FormatUnsupported,

/// Any error that doesn't fit the other error types.
///
/// The `description` field is only meant to help the developer and should not be relied on as a
Expand All @@ -79,6 +83,7 @@ impl std::fmt::Debug for Error {
ClipboardNotSupported,
ClipboardOccupied,
ConversionFailure,
FormatUnsupported,
Unknown { .. }
);
f.write_fmt(format_args!("{} - \"{}\"", name, self))
Expand Down
35 changes: 35 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,21 @@ impl Clipboard {
self.get().text()
}

/// Fetches utf-8 text from the clipboard and returns it.
pub fn get_formats(&mut self) -> Result<Vec<String>, Error> {
self.get().formats()
}

/// Fetches utf-8 text from the clipboard and returns it.
pub fn get_bytes(&mut self, format: &[u8]) -> Result<Vec<u8>, Error> {
self.get().bytes(format)
}

/// Set bytes
pub fn set_bytes<'a, T: Into<Cow<'a, [u8]>>>(&mut self, bytes: T, format: &[u8]) -> Result<(), Error> {
self.set().bytes(bytes, format)
}

/// Places the text onto the clipboard. Any valid utf-8 string is accepted.
pub fn set_text<'a, T: Into<Cow<'a, str>>>(&mut self, text: T) -> Result<(), Error> {
self.set().text(text)
Expand Down Expand Up @@ -155,6 +170,16 @@ impl Get<'_> {
pub fn image(self) -> Result<ImageData<'static>, Error> {
self.platform.image()
}

/// Get formats/mimes available in clipboard
pub fn formats(self) -> Result<Vec<String>, Error> {
self.platform.formats()
}

/// Get formats/mimes available in clipboard
pub fn bytes(self, format: &[u8]) -> Result<Vec<u8>, Error> {
self.platform.bytes(format)
}
}

/// A builder for an operation that sets a value to the clipboard.
Expand All @@ -164,6 +189,16 @@ pub struct Set<'clipboard> {
}

impl Set<'_> {
/// Completes the "set" operation by placing text onto the clipboard. Any valid UTF-8 string
/// is accepted.
pub fn bytes<'a, T: Into<Cow<'a, [u8]>>>(
self,
bytes: T,
format: &[u8],
) -> Result<(), Error> {
let bytes = bytes.into();
self.platform.bytes(bytes, format.into())
}
/// Completes the "set" operation by placing text onto the clipboard. Any valid UTF-8 string
/// is accepted.
pub fn text<'a, T: Into<Cow<'a, str>>>(self, text: T) -> Result<(), Error> {
Expand Down
26 changes: 26 additions & 0 deletions src/platform/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,22 @@ impl<'clipboard> Get<'clipboard> {
Clipboard::WlDataControl(clipboard) => clipboard.get_image(self.selection),
}
}

pub(crate) fn formats(self) -> Result<Vec<String>, Error> {
match self.clipboard {
Clipboard::X11(clipboard) => clipboard.get_formats(self.selection),
#[cfg(feature = "wayland-data-control")]
Clipboard::WlDataControl(clipboard) => clipboard.get_formats(self.selection),
}
}

pub(crate) fn bytes(self, format: &[u8]) -> Result<Vec<u8>, Error> {
match self.clipboard {
Clipboard::X11(clipboard) => clipboard.get_bytes(self.selection, format.into()),
#[cfg(feature = "wayland-data-control")]
Clipboard::WlDataControl(clipboard) => clipboard.get_bytes(self.selection, format.into()),
}
}
}

/// Linux-specific extensions to the [`Get`](super::Get) builder.
Expand Down Expand Up @@ -167,6 +183,16 @@ impl<'clipboard> Set<'clipboard> {
}
}

pub(crate) fn bytes(self, bytes: Cow<'_, [u8]>, format: Cow<'_, [u8]>) -> Result<(), Error> {
match self.clipboard {
Clipboard::X11(clipboard) => {
clipboard.set_bytes(bytes, format, self.selection, self.wait)
}
#[cfg(feature = "wayland-data-control")]
Clipboard::WlDataControl(clipboard) => clipboard.set_bytes(bytes, self.selection, self.wait),
}
}

#[cfg(feature = "image-data")]
pub(crate) fn image(self, image: ImageData<'_>) -> Result<(), Error> {
match self.clipboard {
Expand Down
17 changes: 17 additions & 0 deletions src/platform/linux/wayland.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ impl Clipboard {
Ok(Self {})
}

pub(crate) fn get_formats(&mut self, selection: LinuxClipboardKind) -> Result<Vec<String>, Error> {
todo!()
}

pub(crate) fn get_bytes(&mut self, selection: LinuxClipboardKind, format: &[u8]) -> Result<Vec<String>, Error> {
todo!()
}

pub(crate) fn get_text(&mut self, selection: LinuxClipboardKind) -> Result<String, Error> {
use wl_clipboard_rs::paste::MimeType;

Expand Down Expand Up @@ -92,6 +100,15 @@ impl Clipboard {
Ok(())
}

pub(crate) fn set_bytes(
&self, bytes: Cow<'_, Vec<u8>>,
format: Cow<'_, [u8]>,
selection: LinuxClipboardKind,
wait: bool,
) -> Result<()> {
todo!()
}

pub(crate) fn set_html(
&self,
html: Cow<'_, str>,
Expand Down