From a316577d1e5f4e21348ee19034077f766e73b753 Mon Sep 17 00:00:00 2001 From: Autumn <99296476+AutumnMeowMeow@users.noreply.github.com> Date: Fri, 19 Aug 2022 07:00:26 -0500 Subject: [PATCH] fix(compatibility): improve vttest (#1671) * Improve 'vttest' scenarios: 1. Report terminal as VT220 with sixel rather than VT400 family with sixel. This fixes a hang when launching vttest as it is waiting for a response to DECRQSS. 2. Test 6.2: Support NewLine mode (CR --> CRLF). 3. Test 6.3: Fix DSR cursor position report to honor scrolling region. 4. Test 6.7: Parse and respond to DECREQTPARM (Request Terminal Parameters - CSI x). This is a VT100 sequence that xterm used to respond to always, but more recently only responds to when explicitly set to VT100 level. * cargo fmt * Fix failing unit test snapshot * fix clippy error * VT100 UK character set --- zellij-server/src/panes/grid.rs | 80 +++++++++++++++++-- zellij-server/src/panes/terminal_character.rs | 5 ++ zellij-server/src/panes/terminal_pane.rs | 6 ++ ...s__grid__grid_tests__terminal_reports.snap | 3 +- ...r__panes__grid__grid_tests__vttest3_0.snap | 3 +- 5 files changed, 85 insertions(+), 12 deletions(-) diff --git a/zellij-server/src/panes/grid.rs b/zellij-server/src/panes/grid.rs index 7150fd7a..98ea652b 100644 --- a/zellij-server/src/panes/grid.rs +++ b/zellij-server/src/panes/grid.rs @@ -352,6 +352,7 @@ pub struct Grid { pub sixel_scrolling: bool, // DECSDM pub insert_mode: bool, pub disable_linewrap: bool, + pub new_line_mode: bool, // Automatic newline LNM pub clear_viewport_before_rendering: bool, pub width: usize, pub height: usize, @@ -478,6 +479,7 @@ impl Grid { sixel_scrolling: false, insert_mode: false, disable_linewrap: false, + new_line_mode: false, alternate_screen_state: None, clear_viewport_before_rendering: false, active_charset: Default::default(), @@ -1515,6 +1517,7 @@ impl Grid { self.active_charset = Default::default(); self.erasure_mode = false; self.disable_linewrap = false; + self.new_line_mode = false; self.cursor.change_shape(CursorShape::Initial); self.output_buffer.update_all_lines(); self.changed_colors = None; @@ -2350,8 +2353,18 @@ impl Perform for Grid { _ => {}, }; } - } else if let Some(4) = params_iter.next().map(|param| param[0]) { - self.insert_mode = false; + } else { + for param in params_iter.map(|param| param[0]) { + match param { + 4 => { + self.insert_mode = false; + }, + 20 => { + self.new_line_mode = false; + }, + _ => {}, + } + } } } else if c == 'h' { let first_intermediate_is_questionmark = match intermediates.get(0) { @@ -2434,8 +2447,18 @@ impl Perform for Grid { _ => {}, } } - } else if let Some(4) = params_iter.next().map(|param| param[0]) { - self.insert_mode = true; + } else { + for param in params_iter.map(|param| param[0]) { + match param { + 4 => { + self.insert_mode = true; + }, + 20 => { + self.new_line_mode = true; + }, + _ => {}, + } + } } } else if c == 'r' { if params.len() > 1 { @@ -2602,8 +2625,8 @@ impl Perform for Grid { // https://vt100.net/docs/vt510-rm/DA1.html match intermediates.get(0) { None | Some(0) => { - // primary device attributes - let terminal_capabilities = "\u{1b}[?64;4c"; + // primary device attributes - VT220 with sixel + let terminal_capabilities = "\u{1b}[?62;4c"; self.pending_messages_to_pty .push(terminal_capabilities.as_bytes().to_vec()); }, @@ -2627,13 +2650,41 @@ impl Perform for Grid { }, 6 => { // CPR - cursor position report - let position_report = - format!("\x1b[{};{}R", self.cursor.y + 1, self.cursor.x + 1); + + // Note that this is relative to scrolling region. + let offset = match self.scroll_region { + Some((scroll_region_top, _scroll_region_bottom)) => scroll_region_top, + _ => 0, + }; + let position_report = format!( + "\u{1b}[{};{}R", + self.cursor.y + 1 - offset, + self.cursor.x + 1 + ); self.pending_messages_to_pty .push(position_report.as_bytes().to_vec()); }, _ => {}, } + } else if c == 'x' { + // DECREQTPARM - Request Terminal Parameters + // https://vt100.net/docs/vt100-ug/chapter3.html#DECREQTPARM + // + // Respond with (same as xterm): Parity NONE, 8 bits, + // xmitspeed 38400, recvspeed 38400. (CLoCk MULtiplier = + // 1, STP option flags = 0) + // + // (xterm used to respond to DECREQTPARM in all modes. + // Now it seems to only do so when explicitly in VT100 mode.) + let query = next_param_or(0); + match query { + 0 | 1 => { + let response = format!("\u{1b}[{};1;1;128;128;1;0x", query + 2); + self.pending_messages_to_pty + .push(response.as_bytes().to_vec()); + }, + _ => {}, + } } else if c == 't' { match next_param_or(1) as usize { 14 => { @@ -2678,6 +2729,19 @@ impl Perform for Grid { fn esc_dispatch(&mut self, intermediates: &[u8], _ignore: bool, byte: u8) { match (byte, intermediates.get(0)) { + (b'A', charset_index_symbol) => { + let charset_index: CharsetIndex = match charset_index_symbol { + Some(b'(') => CharsetIndex::G0, + Some(b')') => CharsetIndex::G1, + Some(b'*') => CharsetIndex::G2, + Some(b'+') => CharsetIndex::G3, + _ => { + // invalid, silently do nothing + return; + }, + }; + self.configure_charset(StandardCharset::UK, charset_index); + }, (b'B', charset_index_symbol) => { let charset_index: CharsetIndex = match charset_index_symbol { Some(b'(') => CharsetIndex::G0, diff --git a/zellij-server/src/panes/terminal_character.rs b/zellij-server/src/panes/terminal_character.rs index e933866e..c6fa0adf 100644 --- a/zellij-server/src/panes/terminal_character.rs +++ b/zellij-server/src/panes/terminal_character.rs @@ -586,6 +586,7 @@ impl Default for CharsetIndex { #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum StandardCharset { Ascii, + UK, SpecialCharacterAndLineDrawing, } @@ -602,6 +603,10 @@ impl StandardCharset { pub fn map(self, c: char) -> char { match self { StandardCharset::Ascii => c, + StandardCharset::UK => match c { + '#' => '£', + _ => c, + }, StandardCharset::SpecialCharacterAndLineDrawing => match c { '`' => '◆', 'a' => '▒', diff --git a/zellij-server/src/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs index b305a03a..156b1249 100644 --- a/zellij-server/src/panes/terminal_pane.rs +++ b/zellij-server/src/panes/terminal_pane.rs @@ -162,6 +162,12 @@ impl Pane for TerminalPane { // needs to be adjusted. // here we match against those cases - if need be, we adjust the input and if not // we send back the original input + if self.grid.new_line_mode { + if let &[13] = input_bytes.as_slice() { + // LNM - carriage return is followed by linefeed + return "\u{0d}\u{0a}".as_bytes().to_vec(); + }; + } if self.grid.cursor_key_mode { match input_bytes.as_slice() { LEFT_ARROW => { diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__terminal_reports.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__terminal_reports.snap index aef38672..7b555da7 100644 --- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__terminal_reports.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__terminal_reports.snap @@ -1,6 +1,5 @@ --- source: zellij-server/src/panes/./unit/grid_tests.rs -assertion_line: 721 expression: "format!(\"{:?}\", grid.pending_messages_to_pty)" --- -[[27, 91, 63, 54, 52, 59, 52, 99], [27, 91, 56, 59, 53, 49, 59, 57, 55, 116], [27, 91, 63, 54, 99], [27, 91, 48, 110], [27, 91, 49, 59, 49, 82]] +[[27, 91, 63, 54, 50, 59, 52, 99], [27, 91, 56, 59, 53, 49, 59, 57, 55, 116], [27, 91, 63, 54, 99], [27, 91, 48, 110], [27, 91, 49, 59, 49, 82]] diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest3_0.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest3_0.snap index 5b11dd9b..3a374540 100644 --- a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest3_0.snap +++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vttest3_0.snap @@ -1,7 +1,6 @@ --- source: zellij-server/src/panes/./unit/grid_tests.rs expression: "format!(\"{:?}\", grid)" - --- 00 (C): Selected as G0 (with SI) Selected as G1 (with SO) 01 (C): @@ -10,7 +9,7 @@ expression: "format!(\"{:?}\", grid)" 04 (C): @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ 05 (C): `abcdefghijklmnopqrstuvwxyz{|}~ `abcdefghijklmnopqrstuvwxyz{|}~ 06 (C): Character set A (British) -07 (C): !"#$%&'()*+,-./0123456789:;<=>? !"#$%&'()*+,-./0123456789:;<=>? +07 (C): !"£$%&'()*+,-./0123456789:;<=>? !"£$%&'()*+,-./0123456789:;<=>? 08 (C): @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ 09 (C): `abcdefghijklmnopqrstuvwxyz{|}~ `abcdefghijklmnopqrstuvwxyz{|}~ 10 (C): Character set 0 (DEC Special graphics and line drawing)