Skip to content

Commit

Permalink
feat(copy): allow osc52 copy destination configuration (#1022)
Browse files Browse the repository at this point in the history
add copy_cliboard  option to allow configuring copy destination to primary selection instead of default clipboard
  • Loading branch information
tlinford authored Feb 2, 2022
1 parent 2799eb9 commit 18709ac
Show file tree
Hide file tree
Showing 12 changed files with 189 additions and 110 deletions.
96 changes: 34 additions & 62 deletions default-plugins/status-bar/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ struct State {
tabs: Vec<TabInfo>,
tip_name: String,
mode_info: ModeInfo,
diplay_text_copied_hint: bool,
text_copy_destination: Option<CopyDestination>,
display_system_clipboard_failure: bool,
}

Expand Down Expand Up @@ -156,14 +156,14 @@ impl ZellijPlugin for State {
Event::TabUpdate(tabs) => {
self.tabs = tabs;
}
Event::CopyToClipboard => {
self.diplay_text_copied_hint = true;
Event::CopyToClipboard(copy_destination) => {
self.text_copy_destination = Some(copy_destination);
}
Event::SystemClipboardFailure => {
self.display_system_clipboard_failure = true;
}
Event::InputReceived => {
self.diplay_text_copied_hint = false;
self.text_copy_destination = None;
self.display_system_clipboard_failure = false;
}
_ => {}
Expand All @@ -186,64 +186,7 @@ impl ZellijPlugin for State {
);

let first_line = format!("{}{}", superkey, ctrl_keys);

let mut second_line = LinePart::default();
for t in &mut self.tabs {
if t.active {
match self.mode_info.mode {
InputMode::Normal => {
if t.is_fullscreen_active {
second_line = if self.diplay_text_copied_hint {
text_copied_hint(&self.mode_info.palette)
} else if self.display_system_clipboard_failure {
system_clipboard_error(&self.mode_info.palette)
} else {
fullscreen_panes_to_hide(&self.mode_info.palette, t.panes_to_hide)
}
} else {
second_line = if self.diplay_text_copied_hint {
text_copied_hint(&self.mode_info.palette)
} else if self.display_system_clipboard_failure {
system_clipboard_error(&self.mode_info.palette)
} else {
keybinds(&self.mode_info, &self.tip_name, cols)
}
}
}
InputMode::Locked => {
if t.is_fullscreen_active {
second_line = if self.diplay_text_copied_hint {
text_copied_hint(&self.mode_info.palette)
} else if self.display_system_clipboard_failure {
system_clipboard_error(&self.mode_info.palette)
} else {
locked_fullscreen_panes_to_hide(
&self.mode_info.palette,
t.panes_to_hide,
)
}
} else {
second_line = if self.diplay_text_copied_hint {
text_copied_hint(&self.mode_info.palette)
} else if self.display_system_clipboard_failure {
system_clipboard_error(&self.mode_info.palette)
} else {
keybinds(&self.mode_info, &self.tip_name, cols)
}
}
}
_ => {
second_line = if self.diplay_text_copied_hint {
text_copied_hint(&self.mode_info.palette)
} else if self.display_system_clipboard_failure {
system_clipboard_error(&self.mode_info.palette)
} else {
keybinds(&self.mode_info, &self.tip_name, cols)
}
}
}
}
}
let second_line = self.second_line(cols);

// [48;5;238m is gray background, [0K is so that it fills the rest of the line
// [m is background reset, [0K is so that it clears the rest of the line
Expand All @@ -258,3 +201,32 @@ impl ZellijPlugin for State {
println!("\u{1b}[m{}\u{1b}[0K", second_line);
}
}

impl State {
fn second_line(&self, cols: usize) -> LinePart {
let active_tab = self.tabs.iter().find(|t| t.active);

if let Some(copy_destination) = self.text_copy_destination {
text_copied_hint(&self.mode_info.palette, copy_destination)
} else if self.display_system_clipboard_failure {
system_clipboard_error(&self.mode_info.palette)
} else if let Some(active_tab) = active_tab {
if active_tab.is_fullscreen_active {
match self.mode_info.mode {
InputMode::Normal => {
fullscreen_panes_to_hide(&self.mode_info.palette, active_tab.panes_to_hide)
}
InputMode::Locked => locked_fullscreen_panes_to_hide(
&self.mode_info.palette,
active_tab.panes_to_hide,
),
_ => keybinds(&self.mode_info, &self.tip_name, cols),
}
} else {
keybinds(&self.mode_info, &self.tip_name, cols)
}
} else {
LinePart::default()
}
}
}
11 changes: 9 additions & 2 deletions default-plugins/status-bar/src/second_line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,12 +229,19 @@ pub fn keybinds(help: &ModeInfo, tip_name: &str, max_width: usize) -> LinePart {
best_effort_shortcut_list(help, tip_body.short, max_width)
}

pub fn text_copied_hint(palette: &Palette) -> LinePart {
let hint = " Text copied to clipboard";
pub fn text_copied_hint(palette: &Palette, copy_destination: CopyDestination) -> LinePart {
let green_color = match palette.green {
PaletteColor::Rgb((r, g, b)) => RGB(r, g, b),
PaletteColor::EightBit(color) => Fixed(color),
};
let hint = match copy_destination {
CopyDestination::Command => "Text piped to external command",
#[cfg(not(target_os = "macos"))]
CopyDestination::Primary => "Text copied to primary selection",
#[cfg(target_os = "macos")] // primary selection does not exist on macos
CopyDestination::Primary => "Text copied to clipboard",
CopyDestination::System => "Text copied to clipboard",
};
LinePart {
part: Style::new().fg(green_color).bold().paint(hint).to_string(),
len: hint.len(),
Expand Down
7 changes: 7 additions & 0 deletions zellij-server/src/screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::os::unix::io::RawFd;
use std::rc::Rc;
use std::str;

use zellij_utils::input::options::Clipboard;
use zellij_utils::pane_size::Size;
use zellij_utils::{input::layout::Layout, position::Position, zellij_tile};

Expand Down Expand Up @@ -194,10 +195,12 @@ pub(crate) struct Screen {
draw_pane_frames: bool,
session_is_mirrored: bool,
copy_command: Option<String>,
copy_clipboard: Clipboard,
}

impl Screen {
/// Creates and returns a new [`Screen`].
#[allow(clippy::too_many_arguments)]
pub fn new(
bus: Bus<ScreenInstruction>,
client_attributes: &ClientAttributes,
Expand All @@ -206,6 +209,7 @@ impl Screen {
draw_pane_frames: bool,
session_is_mirrored: bool,
copy_command: Option<String>,
copy_clipboard: Clipboard,
) -> Self {
Screen {
bus,
Expand All @@ -222,6 +226,7 @@ impl Screen {
draw_pane_frames,
session_is_mirrored,
copy_command,
copy_clipboard,
}
}

Expand Down Expand Up @@ -495,6 +500,7 @@ impl Screen {
self.session_is_mirrored,
client_id,
self.copy_command.clone(),
self.copy_clipboard.clone(),
);
tab.apply_layout(layout, new_pids, tab_index, client_id);
if self.session_is_mirrored {
Expand Down Expand Up @@ -700,6 +706,7 @@ pub(crate) fn screen_thread_main(
draw_pane_frames,
session_is_mirrored,
config_options.copy_command,
config_options.copy_clipboard.unwrap_or_default(),
);
loop {
let (event, mut err_ctx) = screen
Expand Down
50 changes: 50 additions & 0 deletions zellij-server/src/tab/clipboard.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use zellij_tile::prelude::CopyDestination;
use zellij_utils::{anyhow::Result, input::options::Clipboard};

use crate::ClientId;

use super::{copy_command::CopyCommand, Output};

pub(crate) enum ClipboardProvider {
Command(CopyCommand),
Osc52(Clipboard),
}

impl ClipboardProvider {
pub(crate) fn set_content(
&self,
content: &str,
output: &mut Output,
client_ids: impl Iterator<Item = ClientId>,
) -> Result<()> {
match &self {
ClipboardProvider::Command(command) => {
command.set(content.to_string())?;
}
ClipboardProvider::Osc52(clipboard) => {
let dest = match clipboard {
#[cfg(not(target_os = "macos"))]
Clipboard::Primary => 'p',
#[cfg(target_os = "macos")] // primary selection does not exist on macos
Clipboard::Primary => 'c',
Clipboard::System => 'c',
};
output.push_str_to_multiple_clients(
&format!("\u{1b}]52;{};{}\u{1b}\\", dest, base64::encode(content)),
client_ids,
);
}
};
Ok(())
}

pub(crate) fn as_copy_destination(&self) -> CopyDestination {
match self {
ClipboardProvider::Command(_) => CopyDestination::Command,
ClipboardProvider::Osc52(clipboard) => match clipboard {
Clipboard::Primary => CopyDestination::Primary,
Clipboard::System => CopyDestination::System,
},
}
}
}
27 changes: 11 additions & 16 deletions zellij-server/src/tab/copy_command.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::io::prelude::*;
use std::process::{Command, Stdio};

use zellij_utils::anyhow::{Context, Result};

pub struct CopyCommand {
command: String,
args: Vec<String>,
Expand All @@ -15,25 +17,18 @@ impl CopyCommand {
args: command_with_args.collect(),
}
}
pub fn set(&self, value: String) -> bool {
let process = match Command::new(self.command.clone())
pub fn set(&self, value: String) -> Result<()> {
let process = Command::new(self.command.clone())
.args(self.args.clone())
.stdin(Stdio::piped())
.spawn()
{
Err(why) => {
eprintln!("couldn't spawn {}: {}", self.command, why);
return false;
}
Ok(process) => process,
};
.with_context(|| format!("couldn't spawn {}", self.command))?;
process
.stdin
.context("could not get stdin")?
.write_all(value.as_bytes())
.with_context(|| format!("couldn't write to {} stdin", self.command))?;

match process.stdin.unwrap().write_all(value.as_bytes()) {
Err(why) => {
eprintln!("couldn't write to {} stdin: {}", self.command, why);
false
}
Ok(_) => true,
}
Ok(())
}
}
Loading

0 comments on commit 18709ac

Please sign in to comment.