aboutsummaryrefslogtreecommitdiff
path: root/helix-view
diff options
context:
space:
mode:
authorDmitry Sharshakov2021-08-12 02:53:48 +0000
committerGitHub2021-08-12 02:53:48 +0000
commit7d51805e94a461834ce34e0829da5859d1f9db32 (patch)
tree08ce918cab9d5d0cc09e43910c79a6f73673664a /helix-view
parentd03982ee432bb418e1e74d490ae66371e201cee2 (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.rs146
-rw-r--r--helix-view/src/editor.rs3
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,
}
}
}