Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(copy): add copy_on_select option #1298

Merged
merged 7 commits into from
Apr 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 40 additions & 11 deletions zellij-server/src/screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,36 @@ impl From<&ScreenInstruction> for ScreenContext {
}
}

#[derive(Debug, Clone)]
pub(crate) struct CopyOptions {
pub command: Option<String>,
pub clipboard: Clipboard,
pub copy_on_select: bool,
}

impl CopyOptions {
pub(crate) fn new(
copy_command: Option<String>,
copy_clipboard: Clipboard,
copy_on_select: bool,
) -> Self {
Self {
command: copy_command,
clipboard: copy_clipboard,
copy_on_select,
}
}

#[cfg(test)]
pub(crate) fn default() -> Self {
Self {
command: None,
clipboard: Clipboard::default(),
copy_on_select: true,
}
}
}

/// A [`Screen`] holds multiple [`Tab`]s, each one holding multiple [`panes`](crate::client::panes).
/// It only directly controls which tab is active, delegating the rest to the individual `Tab`.
pub(crate) struct Screen {
Expand All @@ -210,22 +240,19 @@ pub(crate) struct Screen {
style: Style,
draw_pane_frames: bool,
session_is_mirrored: bool,
copy_command: Option<String>,
copy_clipboard: Clipboard,
copy_options: CopyOptions,
}

impl Screen {
/// Creates and returns a new [`Screen`].
#[allow(clippy::too_many_arguments)]
pub fn new(
bus: Bus<ScreenInstruction>,
client_attributes: &ClientAttributes,
max_panes: Option<usize>,
mode_info: ModeInfo,
draw_pane_frames: bool,
session_is_mirrored: bool,
copy_command: Option<String>,
copy_clipboard: Clipboard,
copy_options: CopyOptions,
) -> Self {
Screen {
bus,
Expand All @@ -243,8 +270,7 @@ impl Screen {
default_mode_info: mode_info,
draw_pane_frames,
session_is_mirrored,
copy_command,
copy_clipboard,
copy_options,
}
}

Expand Down Expand Up @@ -546,8 +572,7 @@ impl Screen {
self.connected_clients.clone(),
self.session_is_mirrored,
client_id,
self.copy_command.clone(),
self.copy_clipboard.clone(),
self.copy_options.clone(),
);
tab.apply_layout(layout, new_pids, tab_index, client_id);
if self.session_is_mirrored {
Expand Down Expand Up @@ -743,6 +768,11 @@ pub(crate) fn screen_thread_main(
let capabilities = config_options.simplified_ui;
let draw_pane_frames = config_options.pane_frames.unwrap_or(true);
let session_is_mirrored = config_options.mirror_session.unwrap_or(false);
let copy_options = CopyOptions::new(
config_options.copy_command,
config_options.copy_clipboard.unwrap_or_default(),
config_options.copy_on_select.unwrap_or(true),
);

let mut screen = Screen::new(
bus,
Expand All @@ -757,8 +787,7 @@ pub(crate) fn screen_thread_main(
),
draw_pane_frames,
session_is_mirrored,
config_options.copy_command,
config_options.copy_clipboard.unwrap_or_default(),
copy_options,
);
loop {
let (event, mut err_ctx) = screen
Expand Down
25 changes: 16 additions & 9 deletions zellij-server/src/tab/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ mod copy_command;

use copy_command::CopyCommand;
use zellij_tile::prelude::Style;
use zellij_utils::input::options::Clipboard;
use zellij_utils::position::{Column, Line};
use zellij_utils::{position::Position, serde, zellij_tile};

use crate::screen::CopyOptions;
use crate::ui::pane_boundaries_frame::FrameParams;

use self::clipboard::ClipboardProvider;
Expand Down Expand Up @@ -89,6 +89,7 @@ pub(crate) struct Tab {
// TODO: used only to focus the pane when the layout is loaded
// it seems that optimization is possible using `active_panes`
focus_pane_id: Option<PaneId>,
copy_on_select: bool,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
Expand Down Expand Up @@ -281,8 +282,7 @@ impl Tab {
connected_clients_in_app: Rc<RefCell<HashSet<ClientId>>>,
session_is_mirrored: bool,
client_id: ClientId,
copy_command: Option<String>,
copy_clipboard: Clipboard,
copy_options: CopyOptions,
) -> Self {
let name = if name.is_empty() {
format!("Tab #{}", index + 1)
Expand Down Expand Up @@ -322,9 +322,9 @@ impl Tab {
style,
);

let clipboard_provider = match copy_command {
let clipboard_provider = match copy_options.command {
Some(command) => ClipboardProvider::Command(CopyCommand::new(command)),
None => ClipboardProvider::Osc52(copy_clipboard),
None => ClipboardProvider::Osc52(copy_options.clipboard),
};

Tab {
Expand All @@ -351,6 +351,7 @@ impl Tab {
link_handler: Rc::new(RefCell::new(LinkHandler::new())),
clipboard_provider,
focus_pane_id: None,
copy_on_select: copy_options.copy_on_select,
}
}

Expand Down Expand Up @@ -1586,7 +1587,9 @@ impl Tab {
return;
}

// read these here to avoid use of borrowed `*self`, since we are holding active_pane
let selecting = self.selecting_with_mouse;
let copy_on_release = self.copy_on_select;
let active_pane = self.get_active_pane_or_floating_pane_mut(client_id);

if let Some(active_pane) = active_pane {
Expand All @@ -1604,11 +1607,15 @@ impl Tab {
self.write_to_active_terminal(mouse_event.into_bytes(), client_id);
} else if selecting {
active_pane.end_selection(&relative_position, client_id);
let selected_text = active_pane.get_selected_text();
active_pane.reset_selection();
if let Some(selected_text) = selected_text {
self.write_selection_to_clipboard(&selected_text);
if copy_on_release {
let selected_text = active_pane.get_selected_text();
active_pane.reset_selection();

if let Some(selected_text) = selected_text {
self.write_selection_to_clipboard(&selected_text);
}
}

self.selecting_with_mouse = false;
}
}
Expand Down
8 changes: 3 additions & 5 deletions zellij-server/src/tab/unit/tab_integration_tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::{Output, Tab};
use crate::screen::CopyOptions;
use crate::zellij_tile::data::{ModeInfo, Palette};
use crate::{
os_input_output::{AsyncReader, Pid, ServerOsApi},
Expand All @@ -11,7 +12,6 @@ use std::path::PathBuf;
use zellij_tile::prelude::Style;
use zellij_utils::envs::set_session_name;
use zellij_utils::input::layout::LayoutTemplate;
use zellij_utils::input::options::Clipboard;
use zellij_utils::ipc::IpcReceiverWithContext;
use zellij_utils::pane_size::Size;
use zellij_utils::position::Position;
Expand Down Expand Up @@ -102,9 +102,8 @@ fn create_new_tab(size: Size) -> Tab {
let mut connected_clients = HashSet::new();
connected_clients.insert(client_id);
let connected_clients = Rc::new(RefCell::new(connected_clients));
let copy_command = None;
let character_cell_info = Rc::new(RefCell::new(None));
let clipboard = Clipboard::default();
let copy_options = CopyOptions::default();
let mut tab = Tab::new(
index,
position,
Expand All @@ -120,8 +119,7 @@ fn create_new_tab(size: Size) -> Tab {
connected_clients,
session_is_mirrored,
client_id,
copy_command,
clipboard,
copy_options,
);
tab.apply_layout(
LayoutTemplate::default().try_into().unwrap(),
Expand Down
14 changes: 5 additions & 9 deletions zellij-server/src/tab/unit/tab_tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::Tab;
use crate::screen::CopyOptions;
use crate::zellij_tile::data::{ModeInfo, Palette};
use crate::{
os_input_output::{AsyncReader, Pid, ServerOsApi},
Expand All @@ -10,7 +11,6 @@ use std::convert::TryInto;
use std::path::PathBuf;
use zellij_tile::prelude::Style;
use zellij_utils::input::layout::LayoutTemplate;
use zellij_utils::input::options::Clipboard;
use zellij_utils::ipc::IpcReceiverWithContext;
use zellij_utils::pane_size::{Size, SizeInPixels};

Expand Down Expand Up @@ -99,8 +99,7 @@ fn create_new_tab(size: Size) -> Tab {
let character_cell_info = Rc::new(RefCell::new(None));
connected_clients.insert(client_id);
let connected_clients = Rc::new(RefCell::new(connected_clients));
let copy_command = None;
let copy_clipboard = Clipboard::default();
let copy_options = CopyOptions::default();
let mut tab = Tab::new(
index,
position,
Expand All @@ -116,8 +115,7 @@ fn create_new_tab(size: Size) -> Tab {
connected_clients,
session_is_mirrored,
client_id,
copy_command,
copy_clipboard,
copy_options,
);
tab.apply_layout(
LayoutTemplate::default().try_into().unwrap(),
Expand Down Expand Up @@ -146,8 +144,7 @@ fn create_new_tab_with_cell_size(
let mut connected_clients = HashSet::new();
connected_clients.insert(client_id);
let connected_clients = Rc::new(RefCell::new(connected_clients));
let copy_command = None;
let copy_clipboard = Clipboard::default();
let copy_options = CopyOptions::default();
let mut tab = Tab::new(
index,
position,
Expand All @@ -163,8 +160,7 @@ fn create_new_tab_with_cell_size(
connected_clients,
session_is_mirrored,
client_id,
copy_command,
copy_clipboard,
copy_options,
);
tab.apply_layout(
LayoutTemplate::default().try_into().unwrap(),
Expand Down
10 changes: 4 additions & 6 deletions zellij-server/src/unit/screen_tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{Screen, ScreenInstruction};
use super::{CopyOptions, Screen, ScreenInstruction};
use crate::panes::PaneId;
use crate::zellij_tile::data::{ModeInfo, Palette};
use crate::{
Expand All @@ -10,7 +10,6 @@ use std::convert::TryInto;
use std::path::PathBuf;
use zellij_utils::input::command::TerminalAction;
use zellij_utils::input::layout::LayoutTemplate;
use zellij_utils::input::options::Clipboard;
use zellij_utils::ipc::IpcReceiverWithContext;
use zellij_utils::pane_size::{Size, SizeInPixels};

Expand Down Expand Up @@ -92,17 +91,16 @@ fn create_new_screen(size: Size) -> Screen {
let mode_info = ModeInfo::default();
let draw_pane_frames = false;
let session_is_mirrored = true;
let copy_command = None;
let copy_clipboard = Clipboard::default();
let copy_options = CopyOptions::default();

Screen::new(
bus,
&client_attributes,
max_panes,
mode_info,
draw_pane_frames,
session_is_mirrored,
copy_command,
copy_clipboard,
copy_options,
)
}

Expand Down
11 changes: 10 additions & 1 deletion zellij-utils/assets/config/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ keybinds:
key: [ Alt: '+']
- action: [Resize: Decrease,]
key: [ Alt: '-']
# uncomment this and adjust key if using copy_on_select=false
# - action: [Copy: ]
# key: [ Alt: 'c']
locked:
- action: [SwitchToMode: Normal,]
key: [Ctrl: 'g',]
Expand Down Expand Up @@ -316,6 +319,9 @@ keybinds:
key: [ Alt: '+']
- action: [Resize: Decrease,]
key: [ Alt: '-']
# uncomment this and adjust key if using copy_on_select=false
# - action: [Copy: ]
# key: [ Alt: 'c']
renametab:
- action: [SwitchToMode: Normal,]
key: [Char: "\n", Ctrl: 'c', Esc]
Expand Down Expand Up @@ -536,4 +542,7 @@ plugins:
# Options:
# - system (default)
# - primary
# copy_clipboard: primary
#copy_clipboard: primary

# Enable or disable automatic copy (and clear) of selection when releasing mouse
#copy_on_select: true
16 changes: 13 additions & 3 deletions zellij-utils/src/input/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,14 @@ pub struct Options {
#[clap(long, arg_enum, ignore_case = true, conflicts_with = "copy-command")]
#[serde(default)]
pub copy_clipboard: Option<Clipboard>,

/// Automatically copy when selecting text (true or false)
#[clap(long)]
#[serde(default)]
pub copy_on_select: Option<bool>,
}

#[derive(ArgEnum, Deserialize, Serialize, Debug, Clone, PartialEq)]
#[derive(ArgEnum, Deserialize, Serialize, Debug, Clone, Copy, PartialEq)]
pub enum Clipboard {
#[serde(alias = "system")]
System,
Expand Down Expand Up @@ -124,7 +129,8 @@ impl Options {
let on_force_close = other.on_force_close.or(self.on_force_close);
let scroll_buffer_size = other.scroll_buffer_size.or(self.scroll_buffer_size);
let copy_command = other.copy_command.or_else(|| self.copy_command.clone());
let copy_clipboard = other.copy_clipboard.or_else(|| self.copy_clipboard.clone());
let copy_clipboard = other.copy_clipboard.or(self.copy_clipboard);
let copy_on_select = other.copy_on_select.or(self.copy_on_select);

Options {
simplified_ui,
Expand All @@ -139,6 +145,7 @@ impl Options {
scroll_buffer_size,
copy_command,
copy_clipboard,
copy_on_select,
}
}

Expand Down Expand Up @@ -169,7 +176,8 @@ impl Options {
let on_force_close = other.on_force_close.or(self.on_force_close);
let scroll_buffer_size = other.scroll_buffer_size.or(self.scroll_buffer_size);
let copy_command = other.copy_command.or_else(|| self.copy_command.clone());
let copy_clipboard = other.copy_clipboard.or_else(|| self.copy_clipboard.clone());
let copy_clipboard = other.copy_clipboard.or(self.copy_clipboard);
let copy_on_select = other.copy_on_select.or(self.copy_on_select);

Options {
simplified_ui,
Expand All @@ -184,6 +192,7 @@ impl Options {
scroll_buffer_size,
copy_command,
copy_clipboard,
copy_on_select,
}
}

Expand Down Expand Up @@ -234,6 +243,7 @@ impl From<CliOptions> for Options {
scroll_buffer_size: opts.scroll_buffer_size,
copy_command: opts.copy_command,
copy_clipboard: opts.copy_clipboard,
copy_on_select: opts.copy_on_select,
}
}
}