Skip to content

Commit e3450ca

Browse files
committed
Sync tmux clipboard and system clipboard
When copying, also write the content into the system clipboard. When pasting, request tmux to refresh its paste buffer from the system clipboard, wait for the update to propagate and the request the clipboard content from tmux. With `set -g set-clipboard on` in tmux, this enables sharing the system clipboard with a helix running in tmux, running in an ssh session, running in alacritty. The need for a wait is unfortunate, but I didn't find a better way. Tmux asks the terminal for the clipboard content and updates its buffer after it got an answer. The answer may come or may not. It may take long, e.g. when running through a slow ssh connection. The feature works well on alacritty. On konsole, it doesn't do anything, but doesn't harm either. On xterm, `tmux refresh-client -l` prints gibberish for me, also without using helix, so I added an option to disable this feature.
1 parent 5c2b77b commit e3450ca

File tree

4 files changed

+25
-10
lines changed

4 files changed

+25
-10
lines changed

book/src/configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ You may also specify a file to use for configuration with the `-c` or
4747
| `idle-timeout` | Time in milliseconds since last keypress before idle timers trigger. Used for autocompletion, set to 0 for instant. | `400` |
4848
| `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` |
4949
| `auto-info` | Whether to display infoboxes | `true` |
50+
| `tmux-system-clipboard` | Sync with the system clipboard when running in tmux. | `true` |
5051
| `true-color` | Set to `true` to override automatic detection of terminal truecolor support in the event of a false negative. | `false` |
5152
| `rulers` | List of column positions at which to display the rulers. Can be overridden by language specific `rulers` in `languages.toml` file. | `[]` |
5253
| `color-modes` | Whether to color the mode indicator with different colors depending on the mode itself | `false` |

helix-term/src/health.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crossterm::{
55
use helix_core::config::{default_syntax_loader, user_syntax_loader};
66
use helix_loader::grammar::load_runtime_file;
77
use helix_view::clipboard::get_clipboard_provider;
8+
use helix_view::editor::Config;
89
use std::io::Write;
910

1011
#[derive(Copy, Clone)]
@@ -53,7 +54,7 @@ pub fn general() -> std::io::Result<()> {
5354
let lang_file = helix_loader::lang_config_file();
5455
let log_file = helix_loader::log_file();
5556
let rt_dir = helix_loader::runtime_dir();
56-
let clipboard_provider = get_clipboard_provider();
57+
let clipboard_provider = get_clipboard_provider(&Config::default());
5758

5859
if config_file.exists() {
5960
writeln!(stdout, "Config file: {}", config_file.display())?;
@@ -87,7 +88,7 @@ pub fn clipboard() -> std::io::Result<()> {
8788
let stdout = std::io::stdout();
8889
let mut stdout = stdout.lock();
8990

90-
let board = get_clipboard_provider();
91+
let board = get_clipboard_provider(&Config::default());
9192
match board.name().as_ref() {
9293
"none" => {
9394
writeln!(

helix-view/src/clipboard.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
use anyhow::Result;
44
use std::borrow::Cow;
55

6+
use crate::editor::Config;
7+
68
pub enum ClipboardType {
79
Clipboard,
810
Selection,
@@ -66,12 +68,12 @@ macro_rules! command_provider {
6668
}
6769

6870
#[cfg(windows)]
69-
pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
71+
pub fn get_clipboard_provider(_: &Config) -> Box<dyn ClipboardProvider> {
7072
Box::new(provider::WindowsProvider::default())
7173
}
7274

7375
#[cfg(target_os = "macos")]
74-
pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
76+
pub fn get_clipboard_provider(_: &Config) -> Box<dyn ClipboardProvider> {
7577
use provider::command::exists;
7678

7779
if exists("pbcopy") && exists("pbpaste") {
@@ -85,13 +87,13 @@ pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
8587
}
8688

8789
#[cfg(target_os = "wasm32")]
88-
pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
90+
pub fn get_clipboard_provider(_: &Config) -> Box<dyn ClipboardProvider> {
8991
// TODO:
9092
Box::new(provider::NopProvider::new())
9193
}
9294

9395
#[cfg(not(any(windows, target_os = "wasm32", target_os = "macos")))]
94-
pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
96+
pub fn get_clipboard_provider(config: &Config) -> Box<dyn ClipboardProvider> {
9597
use provider::command::{env_var_is_set, exists, is_exit_success};
9698
// TODO: support for user-defined provider, probably when we have plugin support by setting a
9799
// variable?
@@ -130,9 +132,17 @@ pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
130132
copy => "termux-clipboard-set";
131133
}
132134
} else if env_var_is_set("TMUX") && exists("tmux") {
133-
command_provider! {
134-
paste => "tmux", "save-buffer", "-";
135-
copy => "tmux", "load-buffer", "-";
135+
if config.tmux_system_clipboard {
136+
command_provider! {
137+
// Refresh tmux clipboard, wait a bit for it to be updated and paste it
138+
paste => "sh", "-c", "tmux refresh-client -l; sleep 0.1; tmux save-buffer -";
139+
copy => "tmux", "load-buffer", "-w", "-";
140+
}
141+
} else {
142+
command_provider! {
143+
paste => "tmux", "save-buffer", "-";
144+
copy => "tmux", "load-buffer", "-";
145+
}
136146
}
137147
} else {
138148
Box::new(provider::NopProvider::new())

helix-view/src/editor.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ pub struct Config {
151151
pub statusline: StatusLineConfig,
152152
/// Shape for cursor in each mode
153153
pub cursor_shape: CursorShapeConfig,
154+
/// Sync with the system clipboard when running in tmux. Defaults to `true`.
155+
pub tmux_system_clipboard: bool,
154156
/// Set to `true` to override automatic detection of terminal truecolor support in the event of a false negative. Defaults to `false`.
155157
pub true_color: bool,
156158
/// Search configuration.
@@ -548,6 +550,7 @@ impl Default for Config {
548550
file_picker: FilePickerConfig::default(),
549551
statusline: StatusLineConfig::default(),
550552
cursor_shape: CursorShapeConfig::default(),
553+
tmux_system_clipboard: true,
551554
true_color: false,
552555
search: SearchConfig::default(),
553556
lsp: LspConfig::default(),
@@ -697,7 +700,7 @@ impl Editor {
697700
theme_loader,
698701
last_theme: None,
699702
registers: Registers::default(),
700-
clipboard_provider: get_clipboard_provider(),
703+
clipboard_provider: get_clipboard_provider(&*conf),
701704
status_msg: None,
702705
autoinfo: None,
703706
idle_timer: Box::pin(sleep(conf.idle_timeout)),

0 commit comments

Comments
 (0)