diff options
author | Dmitry Sharshakov | 2021-08-12 02:53:48 +0000 |
---|---|---|
committer | GitHub | 2021-08-12 02:53:48 +0000 |
commit | 7d51805e94a461834ce34e0829da5859d1f9db32 (patch) | |
tree | 08ce918cab9d5d0cc09e43910c79a6f73673664a /helix-view | |
parent | d03982ee432bb418e1e74d490ae66371e201cee2 (diff) |
Support primary clipboard (#548)
* clipboard-none: add in-memory fallback buffer
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* view: add Wayland primary clipboard
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* Format
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* helix-term: copy to primary selection after mouse move stops
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* helix-term: don't update primary selection if it is a single character
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* helix-term: discard result of setting primary selection
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* helix-term: add commands for interaction with primary clipboard
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* editor: implement primary selection copy/paste using commands
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* clipboard: support xsel for primary selection
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* clipboard: support xclip for primary selection
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* helix-term: multiple cursor support for middle click paste
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* rename primary selection to primary clipboard in scope of PR
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* helix-term: make middle click paste optional
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* Format
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* Update helix-term/src/ui/editor.rs
* fix formatting
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* config: correct defaults if terminal prop is not set
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* refactor: merge clipboard and primary selection implementations
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* Tidy up code
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* view: remove names for different clipboard/selection providers
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* Update helix-view/src/clipboard.rs
Co-authored-by: Gokul Soumya <gokulps15@gmail.com>
* helix-view: tidy macros
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* helix-term: refactor paste-replace commands
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* helix-term: use new config for middle-click-paste
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* clipboard: remove memory fallback for command and windows providers
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* clipboard-win: fix build
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* clipboard: return empty string when primary clipboard is missing
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
* clipboard: fix errors in Windows build
Signed-off-by: Dmitry Sharshakov <d3dx12.xx@gmail.com>
Co-authored-by: Gokul Soumya <gokulps15@gmail.com>
Diffstat (limited to 'helix-view')
-rw-r--r-- | helix-view/src/clipboard.rs | 146 | ||||
-rw-r--r-- | helix-view/src/editor.rs | 3 |
2 files changed, 126 insertions, 23 deletions
diff --git a/helix-view/src/clipboard.rs b/helix-view/src/clipboard.rs index 401c0459..3778c8d4 100644 --- a/helix-view/src/clipboard.rs +++ b/helix-view/src/clipboard.rs @@ -3,10 +3,15 @@ use anyhow::Result; use std::borrow::Cow; +pub enum ClipboardType { + Clipboard, + Selection, +} + pub trait ClipboardProvider: std::fmt::Debug { fn name(&self) -> Cow<str>; - fn get_contents(&self) -> Result<String>; - fn set_contents(&self, contents: String) -> Result<()>; + fn get_contents(&self, clipboard_type: ClipboardType) -> Result<String>; + fn set_contents(&mut self, contents: String, clipboard_type: ClipboardType) -> Result<()>; } macro_rules! command_provider { @@ -20,6 +25,33 @@ macro_rules! command_provider { prg: $set_prg, args: &[ $( $set_arg ),* ], }, + get_primary_cmd: None, + set_primary_cmd: None, + }) + }}; + + (paste => $get_prg:literal $( , $get_arg:literal )* ; + copy => $set_prg:literal $( , $set_arg:literal )* ; + primary_paste => $pr_get_prg:literal $( , $pr_get_arg:literal )* ; + primary_copy => $pr_set_prg:literal $( , $pr_set_arg:literal )* ; + ) => {{ + Box::new(provider::CommandProvider { + get_cmd: provider::CommandConfig { + prg: $get_prg, + args: &[ $( $get_arg ),* ], + }, + set_cmd: provider::CommandConfig { + prg: $set_prg, + args: &[ $( $set_arg ),* ], + }, + get_primary_cmd: Some(provider::CommandConfig { + prg: $pr_get_prg, + args: &[ $( $pr_get_arg ),* ], + }), + set_primary_cmd: Some(provider::CommandConfig { + prg: $pr_set_prg, + args: &[ $( $pr_set_arg ),* ], + }), }) }}; } @@ -37,11 +69,15 @@ pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> { command_provider! { paste => "wl-paste", "--no-newline"; copy => "wl-copy", "--type", "text/plain"; + primary_paste => "wl-paste", "-p", "--no-newline"; + primary_copy => "wl-copy", "-p", "--type", "text/plain"; } } else if env_var_is_set("DISPLAY") && exists("xclip") { command_provider! { paste => "xclip", "-o", "-selection", "clipboard"; copy => "xclip", "-i", "-selection", "clipboard"; + primary_paste => "xclip", "-o"; + primary_copy => "xclip", "-i"; } } else if env_var_is_set("DISPLAY") && exists("xsel") && is_exit_success("xsel", &["-o", "-b"]) { @@ -49,6 +85,8 @@ pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> { command_provider! { paste => "xsel", "-o", "-b"; copy => "xsel", "--nodetach", "-i", "-b"; + primary_paste => "xsel", "-o"; + primary_copy => "xsel", "-i"; } } else if exists("lemonade") { command_provider! { @@ -78,10 +116,10 @@ pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> { } } else { #[cfg(target_os = "windows")] - return Box::new(provider::WindowsProvider); + return Box::new(provider::WindowsProvider::new()); #[cfg(not(target_os = "windows"))] - return Box::new(provider::NopProvider); + return Box::new(provider::NopProvider::new()); } } @@ -103,30 +141,62 @@ fn is_exit_success(program: &str, args: &[&str]) -> bool { } mod provider { - use super::ClipboardProvider; + use super::{ClipboardProvider, ClipboardType}; use anyhow::{bail, Context as _, Result}; use std::borrow::Cow; #[derive(Debug)] - pub struct NopProvider; + pub struct NopProvider { + buf: String, + primary_buf: String, + } + + impl NopProvider { + pub fn new() -> Self { + Self { + buf: String::new(), + primary_buf: String::new(), + } + } + } impl ClipboardProvider for NopProvider { fn name(&self) -> Cow<str> { Cow::Borrowed("none") } - fn get_contents(&self) -> Result<String> { - Ok(String::new()) + fn get_contents(&self, clipboard_type: ClipboardType) -> Result<String> { + let value = match clipboard_type { + ClipboardType::Clipboard => self.buf.clone(), + ClipboardType::Selection => self.primary_buf.clone(), + }; + + Ok(value) } - fn set_contents(&self, _: String) -> Result<()> { + fn set_contents(&mut self, content: String, clipboard_type: ClipboardType) -> Result<()> { + match clipboard_type { + ClipboardType::Clipboard => self.buf = content, + ClipboardType::Selection => self.primary_buf = content, + } Ok(()) } } #[cfg(target_os = "windows")] #[derive(Debug)] - pub struct WindowsProvider; + pub struct WindowsProvider { + selection_buf: String, + } + + #[cfg(target_os = "windows")] + impl WindowsProvider { + pub fn new() -> Self { + Self { + selection_buf: String::new(), + } + } + } #[cfg(target_os = "windows")] impl ClipboardProvider for WindowsProvider { @@ -134,13 +204,23 @@ mod provider { Cow::Borrowed("clipboard-win") } - fn get_contents(&self) -> Result<String> { - let contents = clipboard_win::get_clipboard(clipboard_win::formats::Unicode)?; - Ok(contents) + fn get_contents(&self, clipboard_type: ClipboardType) -> Result<String> { + match clipboard_type { + ClipboardType::Clipboard => { + let contents = clipboard_win::get_clipboard(clipboard_win::formats::Unicode)?; + Ok(contents) + } + ClipboardType::Selection => Ok(String::new()), + } } - fn set_contents(&self, contents: String) -> Result<()> { - clipboard_win::set_clipboard(clipboard_win::formats::Unicode, contents)?; + fn set_contents(&mut self, contents: String, clipboard_type: ClipboardType) -> Result<()> { + match clipboard_type { + ClipboardType::Clipboard => { + clipboard_win::set_clipboard(clipboard_win::formats::Unicode, contents); + } + ClipboardType::Selection => {} + }; Ok(()) } } @@ -192,6 +272,8 @@ mod provider { pub struct CommandProvider { pub get_cmd: CommandConfig, pub set_cmd: CommandConfig, + pub get_primary_cmd: Option<CommandConfig>, + pub set_primary_cmd: Option<CommandConfig>, } impl ClipboardProvider for CommandProvider { @@ -203,16 +285,34 @@ mod provider { } } - fn get_contents(&self) -> Result<String> { - let output = self - .get_cmd - .execute(None, true)? - .context("output is missing")?; - Ok(output) + fn get_contents(&self, clipboard_type: ClipboardType) -> Result<String> { + match clipboard_type { + ClipboardType::Clipboard => Ok(self + .get_cmd + .execute(None, true)? + .context("output is missing")?), + ClipboardType::Selection => { + if let Some(cmd) = &self.get_primary_cmd { + return cmd.execute(None, true)?.context("output is missing"); + } + + Ok(String::new()) + } + } } - fn set_contents(&self, value: String) -> Result<()> { - self.set_cmd.execute(Some(&value), false).map(|_| ()) + fn set_contents(&mut self, value: String, clipboard_type: ClipboardType) -> Result<()> { + let cmd = match clipboard_type { + ClipboardType::Clipboard => &self.set_cmd, + ClipboardType::Selection => { + if let Some(cmd) = &self.set_primary_cmd { + cmd + } else { + return Ok(()); + } + } + }; + cmd.execute(Some(&value), false).map(|_| ()) } } } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index ec3cedd6..9b7f8429 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -29,6 +29,8 @@ pub struct Config { pub scroll_lines: isize, /// Mouse support. Defaults to true. pub mouse: bool, + /// Middle click paste support. Defaults to true + pub middle_click_paste: bool, } impl Default for Config { @@ -37,6 +39,7 @@ impl Default for Config { scrolloff: 5, scroll_lines: 3, mouse: true, + middle_click_paste: true, } } } |