diff options
author | Joe Wilm <joe@jwilm.com> | 2016-10-08 18:42:33 -0700 |
---|---|---|
committer | Joe Wilm <joe@jwilm.com> | 2016-10-08 18:42:33 -0700 |
commit | 9d491f9f676536634040fea8294dc672f3466e26 (patch) | |
tree | 81d4ddc867c570a9004c3d878647feb69e0e2d91 /copypasta/src | |
parent | 7e69a070aaf92eff3bea1878bd77821b5ae60ede (diff) | |
download | alacritty-9d491f9f676536634040fea8294dc672f3466e26.tar.gz alacritty-9d491f9f676536634040fea8294dc672f3466e26.zip |
Start implementing copypasta, a clipboard library
Currently it only supports x11 via the xclip program, and that only
supports reading the clipboard contents.
Diffstat (limited to 'copypasta/src')
-rw-r--r-- | copypasta/src/lib.rs | 46 | ||||
-rw-r--r-- | copypasta/src/macos.rs | 19 | ||||
-rw-r--r-- | copypasta/src/x11.rs | 98 |
3 files changed, 163 insertions, 0 deletions
diff --git a/copypasta/src/lib.rs b/copypasta/src/lib.rs new file mode 100644 index 00000000..722142aa --- /dev/null +++ b/copypasta/src/lib.rs @@ -0,0 +1,46 @@ +//! A cross-platform clipboard library + +/// Types that can get the system clipboard contents +pub trait Load : Sized { + /// Errors encountered when working with a clipboard. Each implementation is + /// allowed to define its own error type, but it must conform to std error. + type Err: ::std::error::Error + Send + Sync + 'static; + + /// Create a clipboard + fn new() -> Result<Self, Self::Err>; + + /// Get the primary clipboard contents. + fn load_primary(&self) -> Result<String, Self::Err>; + + /// Get the clipboard selection contents. + /// + /// On most platforms, this doesn't mean anything. A default implementation + /// is provided which uses the primary clipboard. + #[inline] + fn load_selection(&self) -> Result<String, Self::Err> { + self.load_primary() + } +} + +/// Types that can set the system clipboard contents +/// +/// Note that some platforms require the clipboard context to stay active in +/// order to load the contents from other applications. +pub trait Store : Load { + /// Sets the primary clipboard contents + fn store_primary(&mut self, contents: String) -> Result<(), Self::Err>; + + /// Sets the secondary clipboard contents + fn store_selection(&mut self, contents: String) -> Result<(), Self::Err>; +} + +#[cfg(target_os = "linux")] +mod x11; +#[cfg(target_os = "linux")] +pub use x11::{Clipboard, Error}; + +#[cfg(target_os = "macos")] +mod macos; +#[cfg(target_os = "macos")] +pub use macos::{Clipboard, Error}; + diff --git a/copypasta/src/macos.rs b/copypasta/src/macos.rs new file mode 100644 index 00000000..5ef7630e --- /dev/null +++ b/copypasta/src/macos.rs @@ -0,0 +1,19 @@ +//! Clipboard access on macOS +//! +//! Implemented according to https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/PasteboardGuide106/Articles/pbReading.html#//apple_ref/doc/uid/TP40008123-SW1 +//! +//! FIXME implement this :) + +struct Clipboard; + +impl Load for Clipboard { + type Err = (); + + fn new() -> Result<Self, Error> { + Ok(Clipboard) + } + + fn load_primary(&self) -> Result<String, Self::Err> { + Ok(String::new()) + } +} diff --git a/copypasta/src/x11.rs b/copypasta/src/x11.rs new file mode 100644 index 00000000..45fa4825 --- /dev/null +++ b/copypasta/src/x11.rs @@ -0,0 +1,98 @@ +//! X11 Clipboard implementation +//! +//! Note that the x11 implementation is really crap right now - we just depend +//! on xclip being on the user's path. If x11 pasting doesn't work, it's +//! probably because xclip is unavailable. There's currently no non-GPL x11 +//! clipboard library for Rust. Until then, we have this hack. +//! +//! FIXME: Implement actual X11 clipboard API using the ICCCM reference +//! https://tronche.com/gui/x/icccm/ +use std::io; +use std::process::{Output, Command}; +use std::string::FromUtf8Error; + +use super::Load; + +/// The x11 clipboard +pub struct Clipboard; + +#[derive(Debug)] +pub enum Error { + Io(io::Error), + Xclip(String), + Utf8(FromUtf8Error), +} + +impl ::std::error::Error for Error { + fn cause(&self) -> Option<&::std::error::Error> { + match *self { + Error::Io(ref err) => Some(err), + Error::Utf8(ref err) => Some(err), + _ => None, + } + } + + fn description(&self) -> &str { + match *self { + Error::Io(..) => "error calling xclip", + Error::Xclip(..) => "error reported by xclip", + Error::Utf8(..) => "clipboard contents not utf8", + } + } +} + +impl ::std::fmt::Display for Error { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match *self { + Error::Io(ref err) => write!(f, "error calling xclip: {}", err), + Error::Xclip(ref s) => write!(f, "error from xclip: {}", s), + Error::Utf8(ref err) => write!(f, "error parsing xclip output: {}", err), + } + } +} + +impl From<io::Error> for Error { + fn from(val: io::Error) -> Error { + Error::Io(val) + } +} + +impl From<FromUtf8Error> for Error { + fn from(val: FromUtf8Error) -> Error { + Error::Utf8(val) + } +} + +impl Load for Clipboard { + type Err = Error; + + fn new() -> Result<Self, Error> { + Ok(Clipboard) + } + + fn load_primary(&self) -> Result<String, Self::Err> { + let output = try!(Command::new("xclip") + .args(&["-o", "-selection", "clipboard"]) + .output()); + + Clipboard::process_xclip_output(output) + } + + fn load_selection(&self) -> Result<String, Self::Err> { + let output = try!(Command::new("xclip") + .args(&["-o"]) + .output()); + + Clipboard::process_xclip_output(output) + } +} + +impl Clipboard { + fn process_xclip_output(output: Output) -> Result<String, Error> { + if output.status.success() { + Ok(try!(String::from_utf8(output.stdout))) + } else { + Ok(try!(String::from_utf8(output.stderr))) + } + } +} |