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 Oct 9, 2024
1 parent 53c938c commit b9a8a29
Showing 1 changed file with 43 additions and 4 deletions.
47 changes: 43 additions & 4 deletions helix-view/src/clipboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,39 @@ pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
Box::new(provider::FallbackProvider::new())
}

#[cfg(not(any(windows, target_arch = "wasm32", target_os = "macos")))]
#[cfg(not(any(windows, target_arch = "wasm32")))]
// 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};
use provider::command::is_exit_success;
Expand Down Expand Up @@ -138,7 +170,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 @@ -148,14 +180,15 @@ pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
}
}

#[cfg(not(target_os = "windows"))]
#[cfg(not(windows))]
pub mod provider {
use super::{ClipboardProvider, ClipboardType};
use anyhow::Result;
use std::borrow::Cow;

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

#[derive(Debug)]
Expand All @@ -179,8 +212,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 b9a8a29

Please sign in to comment.