fix(ui): handle pasted text properly (#494)
* fix(ui): handle pasted text properly * style(fmt): rustfmt
This commit is contained in:
parent
ce50d6e406
commit
3f1ec7c295
5 changed files with 100 additions and 9 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 $ █
|
||||
|
|
@ -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] = [];
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue