aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2021-05-12 14:22:15 +0200
committerGitHub <noreply@github.com>2021-05-12 14:22:15 +0200
commit3f1ec7c29590fea0805e7effb605548606b58306 (patch)
tree7f4d622d9c945225f21b4d8f15090ca6e0223a27 /src
parentdocs(changelog): compatibility update (diff)
downloadsl0ppij-3f1ec7c29590fea0805e7effb605548606b58306.tar.gz
sl0ppij-3f1ec7c29590fea0805e7effb605548606b58306.tar.xz
sl0ppij-3f1ec7c29590fea0805e7effb605548606b58306.zip
fix(ui): handle pasted text properly (#494)
* fix(ui): handle pasted text properly * style(fmt): rustfmt
Diffstat (limited to 'src')
-rw-r--r--src/client/mod.rs7
-rw-r--r--src/common/input/handler.rs26
-rw-r--r--src/tests/integration/basic.rs48
-rw-r--r--src/tests/integration/snapshots/zellij__tests__integration__basic__bracketed_paste.snap25
-rw-r--r--src/tests/utils.rs3
5 files changed, 100 insertions, 9 deletions
diff --git a/src/client/mod.rs b/src/client/mod.rs
index 5fb40096..ae60fc87 100644
--- a/src/client/mod.rs
+++ b/src/client/mod.rs
@@ -31,8 +31,9 @@ pub enum ClientInstruction {
}
pub fn start_client(mut os_input: Box<dyn ClientOsApi>, opts: CliArgs, config: Config) {
- let clear_client_terminal_attributes = "\u{1b}[?1l\u{1b}=\u{1b}[r\u{1b}12l\u{1b}[?1000l\u{1b}[?1002l\u{1b}[?1003l\u{1b}[?1005l\u{1b}[?1006l";
+ let clear_client_terminal_attributes = "\u{1b}[?1l\u{1b}=\u{1b}[r\u{1b}12l\u{1b}[?1000l\u{1b}[?1002l\u{1b}[?1003l\u{1b}[?1005l\u{1b}[?1006l\u{1b}[?12l";
let take_snapshot = "\u{1b}[?1049h";
+ let bracketed_paste = "\u{1b}[?2004h";
os_input.unset_raw_mode(0);
let _ = os_input
.get_stdout_writer()
@@ -57,6 +58,10 @@ pub fn start_client(mut os_input: Box<dyn ClientOsApi>, opts: CliArgs, config: C
config_options,
));
os_input.set_raw_mode(0);
+ let _ = os_input
+ .get_stdout_writer()
+ .write(bracketed_paste.as_bytes())
+ .unwrap();
let (send_client_instructions, receive_client_instructions): SyncChannelWithContext<
ClientInstruction,
diff --git a/src/common/input/handler.rs b/src/common/input/handler.rs
index 68a75448..62e2e909 100644
--- a/src/common/input/handler.rs
+++ b/src/common/input/handler.rs
@@ -23,6 +23,7 @@ struct InputHandler {
command_is_executing: CommandIsExecuting,
send_client_instructions: SenderWithContext<ClientInstruction>,
should_exit: bool,
+ pasting: bool,
}
impl InputHandler {
@@ -40,6 +41,7 @@ impl InputHandler {
command_is_executing,
send_client_instructions,
should_exit: false,
+ pasting: false,
}
}
@@ -49,6 +51,8 @@ impl InputHandler {
let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow());
err_ctx.add_call(ContextType::StdinHandler);
let alt_left_bracket = vec![27, 91];
+ let bracketed_paste_start = vec![27, 91, 50, 48, 48, 126]; // \u{1b}[200~
+ let bracketed_paste_end = vec![27, 91, 50, 48, 49, 126]; // \u{1b}[201
loop {
if self.should_exit {
break;
@@ -67,6 +71,10 @@ impl InputHandler {
if unsupported_key == alt_left_bracket {
let key = Key::Alt('[');
self.handle_key(&key, raw_bytes);
+ } else if unsupported_key == bracketed_paste_start {
+ self.pasting = true;
+ } else if unsupported_key == bracketed_paste_end {
+ self.pasting = false;
}
}
termion::event::Event::Mouse(_) => {
@@ -81,10 +89,20 @@ impl InputHandler {
}
fn handle_key(&mut self, key: &Key, raw_bytes: Vec<u8>) {
let keybinds = &self.config.keybinds;
- for action in Keybinds::key_to_actions(&key, raw_bytes, &self.mode, keybinds) {
- let should_exit = self.dispatch_action(action);
- if should_exit {
- self.should_exit = true;
+ if self.pasting {
+ // we're inside a paste block, if we're in a mode that allows sending text to the
+ // terminal, send all text directly without interpreting it
+ // otherwise, just discard the input
+ if self.mode == InputMode::Normal || self.mode == InputMode::Locked {
+ let action = Action::Write(raw_bytes);
+ self.dispatch_action(action);
+ }
+ } else {
+ for action in Keybinds::key_to_actions(&key, raw_bytes, &self.mode, keybinds) {
+ let should_exit = self.dispatch_action(action);
+ if should_exit {
+ self.should_exit = true;
+ }
}
}
}
diff --git a/src/tests/integration/basic.rs b/src/tests/integration/basic.rs
index c8305cab..5b72dbfe 100644
--- a/src/tests/integration/basic.rs
+++ b/src/tests/integration/basic.rs
@@ -4,10 +4,10 @@ use ::insta::assert_snapshot;
use crate::common::input::config::Config;
use crate::tests::fakes::FakeInputOutput;
use crate::tests::utils::commands::{
- PANE_MODE, QUIT, SCROLL_DOWN_IN_SCROLL_MODE, SCROLL_MODE, SCROLL_PAGE_DOWN_IN_SCROLL_MODE,
- SCROLL_PAGE_UP_IN_SCROLL_MODE, SCROLL_UP_IN_SCROLL_MODE, SPAWN_TERMINAL_IN_PANE_MODE,
- SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE,
- TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE,
+ BRACKETED_PASTE_END, BRACKETED_PASTE_START, PANE_MODE, QUIT, SCROLL_DOWN_IN_SCROLL_MODE,
+ SCROLL_MODE, SCROLL_PAGE_DOWN_IN_SCROLL_MODE, SCROLL_PAGE_UP_IN_SCROLL_MODE,
+ SCROLL_UP_IN_SCROLL_MODE, SPAWN_TERMINAL_IN_PANE_MODE, SPLIT_DOWN_IN_PANE_MODE,
+ SPLIT_RIGHT_IN_PANE_MODE, TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE,
};
use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots};
use crate::{start, CliArgs};
@@ -441,3 +441,43 @@ pub fn toggle_focused_pane_fullscreen() {
get_next_to_last_snapshot(snapshots).expect("could not find snapshot");
assert_snapshot!(snapshot_before_quit);
}
+
+#[test]
+pub fn bracketed_paste() {
+ // bracketed paste (https://xfree86.org/current/ctlseqs.html#Bracketed%20Paste%20Mode)
+ // makes sure that text the user pastes is not interpreted as commands by the running program
+ // (zellij in this case)
+ // this tests makes sure the "SPLIT_RIGHT_IN_PANE_MODE" command is not interpreted as Zellij,
+ // since it's inside a bracketed paste block, while the "QUIT" command is, since it is already
+ // past the block
+ let fake_win_size = PositionAndSize {
+ columns: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut fake_input_output = get_fake_os_input(&fake_win_size);
+ fake_input_output.add_terminal_input(&[
+ &PANE_MODE,
+ &BRACKETED_PASTE_START,
+ &SPLIT_RIGHT_IN_PANE_MODE,
+ &BRACKETED_PASTE_END,
+ &QUIT,
+ ]);
+ start(
+ Box::new(fake_input_output.clone()),
+ CliArgs::default(),
+ Box::new(fake_input_output.clone()),
+ Config::default(),
+ );
+ let output_frames = fake_input_output
+ .stdout_writer
+ .output_frames
+ .lock()
+ .unwrap();
+ let snapshots = get_output_frame_snapshots(&output_frames, &fake_win_size);
+ let snapshot_before_quit =
+ get_next_to_last_snapshot(snapshots).expect("could not find snapshot");
+ assert_snapshot!(snapshot_before_quit);
+}
diff --git a/src/tests/integration/snapshots/zellij__tests__integration__basic__bracketed_paste.snap b/src/tests/integration/snapshots/zellij__tests__integration__basic__bracketed_paste.snap
new file mode 100644
index 00000000..1eec02f4
--- /dev/null
+++ b/src/tests/integration/snapshots/zellij__tests__integration__basic__bracketed_paste.snap
@@ -0,0 +1,25 @@
+---
+source: src/tests/integration/basic.rs
+expression: snapshot_before_quit
+
+---
+line1-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+line2-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+line3-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+line4-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+line5-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+line6-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+line7-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+line8-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+line9-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+line10-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+line11-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+line12-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+line13-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+line14-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+line15-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+line16-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+line17-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+line18-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+line19-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+prompt $ █
diff --git a/src/tests/utils.rs b/src/tests/utils.rs
index 10b243a7..f01c1ac5 100644
--- a/src/tests/utils.rs
+++ b/src/tests/utils.rs
@@ -81,5 +81,8 @@ pub mod commands {
pub const SWITCH_NEXT_TAB_IN_TAB_MODE: [u8; 1] = [108]; // l
pub const SWITCH_PREV_TAB_IN_TAB_MODE: [u8; 1] = [104]; // h
pub const CLOSE_TAB_IN_TAB_MODE: [u8; 1] = [120]; // x
+
+ pub const BRACKETED_PASTE_START: [u8; 6] = [27, 91, 50, 48, 48, 126]; // \u{1b}[200~
+ pub const BRACKETED_PASTE_END: [u8; 6] = [27, 91, 50, 48, 49, 126]; // \u{1b}[201
pub const SLEEP: [u8; 0] = [];
}