diff --git a/Cargo.toml b/Cargo.toml index 511c1fbf..8b7a0aff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ documentation = "https://amp.rs/docs" readme = "README.md" license-file = "LICENSE" keywords = ["text", "editor", "terminal", "modal"] -edition="2021" +edition = "2021" [build-dependencies] regex = "1.10" @@ -27,7 +27,7 @@ syntect = "5.1" termion = "2.0" error-chain = "0.12" unicode-segmentation = "1.10" -cli-clipboard = "0.4" +cli-clipboard = { version = "0.4.0", optional = true } yaml-rust = "0.4" smallvec = "1.11" lazy_static = "1.4" @@ -50,3 +50,7 @@ criterion = "0.5" name = "draw_buffer" path = "benches/view/draw_buffer.rs" harness = false + +[features] +default = ["clipboard"] +clipboard = ["dep:cli-clipboard"] diff --git a/src/models/application/clipboard.rs b/src/models/application/clipboard.rs index 01a4d8cc..afdebad7 100644 --- a/src/models/application/clipboard.rs +++ b/src/models/application/clipboard.rs @@ -1,11 +1,11 @@ use crate::errors::*; -use cli_clipboard::{ClipboardContext, ClipboardProvider}; /// In-app content can be captured in both regular and full-line selection /// modes. This type describes the structure of said content, based on the /// context in which it was captured. When OS-level clipboard contents are /// used, they are always represented as inline, as we cannot infer block /// style without the copy context. + #[derive(Debug, PartialEq)] pub enum ClipboardContent { Inline(String), @@ -13,95 +13,137 @@ pub enum ClipboardContent { None, } -/// Qualifies in-app copy/paste content with structural information, and -/// synchronizes said content with the OS-level clipboard (preferring it -/// in scenarios where it differs from the in-app equivalent). -pub struct Clipboard { - content: ClipboardContent, - system_clipboard: Option, -} +#[cfg(feature = "clipboard")] +mod clipboard_impl { + use super::*; + use cli_clipboard::{ClipboardContext, ClipboardProvider}; -impl Default for Clipboard { - fn default() -> Self { - Self::new() + /// Qualifies in-app copy/paste content with structural information, and + /// synchronizes said content with the OS-level clipboard (preferring it + /// in scenarios where it differs from the in-app equivalent). + pub struct Clipboard { + content: ClipboardContent, + system_clipboard: Option, } -} -impl Clipboard { - pub fn new() -> Clipboard { - // Initialize and keep a reference to the system clipboard. - let system_clipboard = match ClipboardProvider::new() { - Ok(clipboard) => Some(clipboard), - Err(_) => None, - }; - - Clipboard { - content: ClipboardContent::None, - system_clipboard, + impl Default for Clipboard { + fn default() -> Self { + Self::new() } } - /// Returns the in-app clipboard content. However, if in-app content - /// differs from the system clipboard, the system clipboard content will - /// be saved to the in-app clipboard as inline data and returned instead. - pub fn get_content(&mut self) -> &ClipboardContent { - // Check the system clipboard for newer content. - let new_content = match self.system_clipboard { - Some(ref mut clipboard) => { - match clipboard.get_contents() { - Ok(content) => { - if content.is_empty() { - None - } else { - // There is system clipboard content we can use. - match self.content { - ClipboardContent::Inline(ref app_content) | - ClipboardContent::Block(ref app_content) => { - // We have in-app clipboard content, too. Prefer - // the system clipboard content if they differ. - if content != *app_content { - Some(ClipboardContent::Inline(content)) - } else { - None + impl Clipboard { + pub fn new() -> Clipboard { + // Initialize and keep a reference to the system clipboard. + let system_clipboard = match ClipboardProvider::new() { + Ok(clipboard) => Some(clipboard), + Err(_) => None, + }; + + Clipboard { + content: ClipboardContent::None, + system_clipboard, + } + } + + /// Returns the in-app clipboard content. However, if in-app content + /// differs from the system clipboard, the system clipboard content will + /// be saved to the in-app clipboard as inline data and returned instead. + pub fn get_content(&mut self) -> &ClipboardContent { + // Check the system clipboard for newer content. + let new_content = match self.system_clipboard { + Some(ref mut clipboard) => { + match clipboard.get_contents() { + Ok(content) => { + if content.is_empty() { + None + } else { + // There is system clipboard content we can use. + match self.content { + ClipboardContent::Inline(ref app_content) + | ClipboardContent::Block(ref app_content) => { + // We have in-app clipboard content, too. Prefer + // the system clipboard content if they differ. + if content != *app_content { + Some(ClipboardContent::Inline(content)) + } else { + None + } } + // We have no in-app clipboard content. Use the system's. + _ => Some(ClipboardContent::Inline(content)), } - // We have no in-app clipboard content. Use the system's. - _ => Some(ClipboardContent::Inline(content)), } } + _ => None, } - _ => None, } + None => None, + }; + + // Update the in-app clipboard if we've found newer content. + if new_content.is_some() { + self.content = new_content.unwrap(); } - None => None, - }; - // Update the in-app clipboard if we've found newer content. - if new_content.is_some() { - self.content = new_content.unwrap(); + &self.content } - &self.content - } + // Updates the in-app and system clipboards with the specified content. + pub fn set_content(&mut self, content: ClipboardContent) -> Result<()> { + // Update the in-app clipboard. + self.content = content; - // Updates the in-app and system clipboards with the specified content. - pub fn set_content(&mut self, content: ClipboardContent) -> Result<()> { - // Update the in-app clipboard. - self.content = content; - - // Update the system clipboard. - match self.content { - ClipboardContent::Inline(ref app_content) | - ClipboardContent::Block(ref app_content) => { - if let Some(ref mut clipboard) = self.system_clipboard { - return clipboard - .set_contents(app_content.clone()) - .map_err(|_| Error::from("Failed to update system clipboard")); + // Update the system clipboard. + match self.content { + ClipboardContent::Inline(ref app_content) + | ClipboardContent::Block(ref app_content) => { + if let Some(ref mut clipboard) = self.system_clipboard { + return clipboard + .set_contents(app_content.clone()) + .map_err(|_| Error::from("Failed to update system clipboard")); + } } + _ => (), } - _ => (), + + Ok(()) } + } +} +#[cfg(feature = "clipboard")] +pub use clipboard_impl::*; + +#[cfg(not(feature = "clipboard"))] +mod non_clipboard_impl { + use super::*; + /// a fake clipboard implementation for non-clipboard feature + /// it just save the content in memory, do not interact with system clipboard + pub struct Clipboard { + content: ClipboardContent, + } + impl Default for Clipboard { + fn default() -> Self { + Self::new() + } + } - Ok(()) + impl Clipboard { + pub fn new() -> Clipboard { + Clipboard { + content: ClipboardContent::None, + } + } + + pub fn get_content(&mut self) -> &ClipboardContent { + &self.content + } + + pub fn set_content(&mut self, content: ClipboardContent) -> Result<()> { + self.content = content; + Ok(()) + } } } +#[cfg(not(feature = "clipboard"))] +pub use non_clipboard_impl::*;