feat(copy): add copy_on_select option (#1298)
* feat(copy): add copy_on_select option with default value of true, keep current behavior of automatically copying selection to clipboard when done selecting. with copy_on_select = false, on mouse release the selection remains, and can be copied with the `Copy` action. * add example to default.yaml * add copy action example to default.yaml, cleanup * fix updated tab tests * fix selection changing while scrolling after release * fix clippy warnings
This commit is contained in:
parent
53afaa01a9
commit
198625b055
7 changed files with 91 additions and 44 deletions
|
|
@ -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 {
|
||||
|
|
@ -210,13 +240,11 @@ 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,
|
||||
|
|
@ -224,8 +252,7 @@ impl Screen {
|
|||
mode_info: ModeInfo,
|
||||
draw_pane_frames: bool,
|
||||
session_is_mirrored: bool,
|
||||
copy_command: Option<String>,
|
||||
copy_clipboard: Clipboard,
|
||||
copy_options: CopyOptions,
|
||||
) -> Self {
|
||||
Screen {
|
||||
bus,
|
||||
|
|
@ -243,8 +270,7 @@ impl Screen {
|
|||
default_mode_info: mode_info,
|
||||
draw_pane_frames,
|
||||
session_is_mirrored,
|
||||
copy_command,
|
||||
copy_clipboard,
|
||||
copy_options,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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,
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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)]
|
||||
|
|
@ -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)
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
@ -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;
|
||||
|
|
@ -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,
|
||||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
@ -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};
|
||||
|
||||
|
|
@ -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,
|
||||
|
|
@ -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(),
|
||||
|
|
@ -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,
|
||||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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::{
|
||||
|
|
@ -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};
|
||||
|
||||
|
|
@ -92,8 +91,8 @@ 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,
|
||||
|
|
@ -101,8 +100,7 @@ fn create_new_screen(size: Size) -> Screen {
|
|||
mode_info,
|
||||
draw_pane_frames,
|
||||
session_is_mirrored,
|
||||
copy_command,
|
||||
copy_clipboard,
|
||||
copy_options,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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',]
|
||||
|
|
@ -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]
|
||||
|
|
@ -537,3 +543,6 @@ plugins:
|
|||
# - system (default)
|
||||
# - primary
|
||||
#copy_clipboard: primary
|
||||
|
||||
# Enable or disable automatic copy (and clear) of selection when releasing mouse
|
||||
#copy_on_select: true
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
|
|
@ -139,6 +145,7 @@ impl Options {
|
|||
scroll_buffer_size,
|
||||
copy_command,
|
||||
copy_clipboard,
|
||||
copy_on_select,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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,
|
||||
|
|
@ -184,6 +192,7 @@ impl Options {
|
|||
scroll_buffer_size,
|
||||
copy_command,
|
||||
copy_clipboard,
|
||||
copy_on_select,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue