summaryrefslogtreecommitdiff
path: root/copypasta/src
diff options
context:
space:
mode:
authorJoe Wilm <joe@jwilm.com>2016-10-08 18:42:33 -0700
committerJoe Wilm <joe@jwilm.com>2016-10-08 18:42:33 -0700
commit9d491f9f676536634040fea8294dc672f3466e26 (patch)
tree81d4ddc867c570a9004c3d878647feb69e0e2d91 /copypasta/src
parent7e69a070aaf92eff3bea1878bd77821b5ae60ede (diff)
downloadalacritty-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.rs46
-rw-r--r--copypasta/src/macos.rs19
-rw-r--r--copypasta/src/x11.rs98
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)))
+ }
+ }
+}