Skip to content

Commit

Permalink
Fix system clipboard with mosh + tmux
Browse files Browse the repository at this point in the history
Some times tmux doesn't pass the clipboard information to the terminal
correctly. This is the case of mosh + tmux. The current clipboard
doesn't work properly in this case. However, when the tmux option
`allow-passthrough` is on, we can escape tmux and pass the OSC52 string
directly to the terminal.

In this patch, if helix detects that tmux `allow-passthrough` is on, it
will use the OSC52 clipboard provider and will escape tmux and pass the
OSC52 directly to the terminal.

Tested with mosh + tmux with the `allow-passthrough` option on.
  • Loading branch information
useche committed Apr 21, 2024
1 parent d140072 commit ab32160
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 2 deletions.
16 changes: 16 additions & 0 deletions book/src/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,22 @@ are joined with newlines. Pasting from these registers will paste multiple
selections if the clipboard was last yanked to by the Helix session. Otherwise
the clipboard contents are pasted as one selection.

### Tmux clipboard issues

Tmux clipboard support has bad interactions with some specific remote shell
and terminal combinations (e.g. kitty + mosh + tmux). Tmux allows for escaping
strings directly to the terminal, bypassing the remote shell and allowing work
arounds to this problem. Helix is able to work around this problem by escaping
the OSC52 sequences in tmux. To use this feature, you need to enable the tmux
option with the tmux command:

```
set-window-option -g allow-passthrough on
```

Helix will detect this and use the feature to bypass tmux and the remote
shell. You can find more information [here](https://sunaku.github.io/tmux-yank-osc52.html).

## Surround

Helix includes built-in functionality similar to [vim-surround](https://github.com/tpope/vim-surround).
Expand Down
42 changes: 40 additions & 2 deletions helix-view/src/clipboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,37 @@ pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
Box::new(provider::FallbackProvider::new())
}

// Check if we are in tmux and the allow-passthrough is on.
fn tmux_allow_passthrough() -> bool {
use helix_stdx::env::env_var_is_set;

if !env_var_is_set("TMUX") {
return false;
}

use std::process::Command;
let result = Command::new("tmux")
.arg("show")
.arg("-gw")
.arg("allow-passthrough")
.output();
let output = match result {
Ok(out) => out,
Err(_) => return false,
};

if !output.status.success() {
return false;
}

let output = match String::from_utf8(output.stdout) {
Ok(out) => out,
Err(_) => return false,
};

output.contains("on")
}

#[cfg(not(any(windows, target_os = "wasm32", target_os = "macos")))]
pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
use helix_stdx::env::{binary_exists, env_var_is_set};
Expand Down Expand Up @@ -138,7 +169,7 @@ pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
paste => "termux-clipboard-get";
copy => "termux-clipboard-set";
}
} else if env_var_is_set("TMUX") && binary_exists("tmux") {
} else if env_var_is_set("TMUX") && binary_exists("tmux") && !tmux_allow_passthrough() {
command_provider! {
paste => "tmux", "save-buffer", "-";
copy => "tmux", "load-buffer", "-w", "-";
Expand All @@ -156,6 +187,7 @@ pub mod provider {

#[cfg(feature = "term")]
mod osc52 {
use crate::clipboard::tmux_allow_passthrough;
use {super::ClipboardType, crate::base64};

#[derive(Debug)]
Expand All @@ -179,8 +211,14 @@ pub mod provider {
ClipboardType::Clipboard => "c",
ClipboardType::Selection => "p",
};

// Send an OSC 52 set command: https://terminalguide.namepad.de/seq/osc-52/
write!(f, "\x1b]52;{};{}\x1b\\", kind, &self.encoded_content)
let mut osc52 = format!("\x1b]52;{};{}\x07", kind, &self.encoded_content);
if tmux_allow_passthrough() {
// If we are inside tmux and we are allow to passthrough, escape it too.
osc52 = format!("\x1bPtmux;\x1b{}\x1b\\", osc52);
}
f.write_str(&osc52)
}
}
}
Expand Down

0 comments on commit ab32160

Please sign in to comment.