mirror of
https://github.com/zellij-org/zellij.git
synced 2024-12-27 03:04:16 +03:00
Merge branch 'main' into mac-config
This commit is contained in:
commit
4b39699964
@ -10,7 +10,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
* Move the sync command to tab mode (https://github.com/zellij-org/zellij/pull/412)
|
||||
* Fix exit code of `dump-default-config` (https://github.com/zellij-org/zellij/pull/480)
|
||||
* Feature: Switch tabs using `Alt + h/l` in normal mode if there are no panes in the direction (https://github.com/zellij-org/zellij/pull/471)
|
||||
* Fix handling of $HOME `config` direcotry, especially relevant for darwin systems (https://github.com/zellij-org/zellij/pull/487)
|
||||
* Terminal Compatibility: various behaviour fixes (https://github.com/zellij-org/zellij/pull/486)
|
||||
* Fix handling of `$HOME` `config` directory, especially relevant for darwin systems (https://github.com/zellij-org/zellij/pull/487)
|
||||
|
||||
|
||||
## [0.8.0] - 2021-05-07
|
||||
* Terminal compatibility: pass vttest 8 (https://github.com/zellij-org/zellij/pull/461)
|
||||
|
@ -12,7 +12,7 @@ const SCROLL_BACK: usize = 10_000;
|
||||
use crate::utils::logging::debug_log_to_file;
|
||||
|
||||
use crate::panes::terminal_character::{
|
||||
CharacterStyles, CharsetIndex, Cursor, StandardCharset, TerminalCharacter,
|
||||
CharacterStyles, CharsetIndex, Cursor, CursorShape, StandardCharset, TerminalCharacter,
|
||||
EMPTY_TERMINAL_CHARACTER,
|
||||
};
|
||||
|
||||
@ -177,6 +177,7 @@ pub struct Grid {
|
||||
saved_cursor_position: Option<Cursor>,
|
||||
scroll_region: Option<(usize, usize)>,
|
||||
active_charset: CharsetIndex,
|
||||
preceding_char: Option<TerminalCharacter>,
|
||||
pub should_render: bool,
|
||||
pub cursor_key_mode: bool, // DECCKM - when set, cursor keys should send ANSI direction codes (eg. "OD") instead of the arrow keys (eg. "[D")
|
||||
pub erasure_mode: bool, // ERM
|
||||
@ -210,6 +211,7 @@ impl Grid {
|
||||
cursor: Cursor::new(0, 0),
|
||||
saved_cursor_position: None,
|
||||
scroll_region: None,
|
||||
preceding_char: None,
|
||||
width: columns,
|
||||
height: rows,
|
||||
should_render: true,
|
||||
@ -245,6 +247,26 @@ impl Grid {
|
||||
empty_character.styles = styles;
|
||||
self.pad_current_line_until(self.cursor.x);
|
||||
}
|
||||
pub fn move_to_previous_tabstop(&mut self) {
|
||||
let mut previous_tabstop = None;
|
||||
for tabstop in self.horizontal_tabstops.iter() {
|
||||
if *tabstop >= self.cursor.x {
|
||||
break;
|
||||
}
|
||||
previous_tabstop = Some(tabstop);
|
||||
}
|
||||
match previous_tabstop {
|
||||
Some(tabstop) => {
|
||||
self.cursor.x = *tabstop;
|
||||
}
|
||||
None => {
|
||||
self.cursor.x = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn cursor_shape(&self) -> CursorShape {
|
||||
self.cursor.get_shape()
|
||||
}
|
||||
fn set_horizontal_tabstop(&mut self) {
|
||||
self.horizontal_tabstops.insert(self.cursor.x);
|
||||
}
|
||||
@ -925,6 +947,10 @@ impl Grid {
|
||||
self.active_charset = Default::default();
|
||||
self.erasure_mode = false;
|
||||
self.disable_linewrap = false;
|
||||
self.cursor.change_shape(CursorShape::Block);
|
||||
}
|
||||
fn set_preceding_character(&mut self, terminal_character: TerminalCharacter) {
|
||||
self.preceding_char = Some(terminal_character);
|
||||
}
|
||||
}
|
||||
|
||||
@ -937,6 +963,7 @@ impl Perform for Grid {
|
||||
character: c,
|
||||
styles: self.cursor.pending_styles,
|
||||
};
|
||||
self.set_preceding_character(terminal_character);
|
||||
self.add_character(terminal_character);
|
||||
}
|
||||
|
||||
@ -950,9 +977,10 @@ impl Perform for Grid {
|
||||
// tab
|
||||
self.advance_to_next_tabstop(self.cursor.pending_styles);
|
||||
}
|
||||
10 | 11 => {
|
||||
10 | 11 | 12 => {
|
||||
// 0a, newline
|
||||
// 0b, vertical tabulation
|
||||
// 0c, form feed
|
||||
self.add_newline();
|
||||
}
|
||||
13 => {
|
||||
@ -985,7 +1013,7 @@ impl Perform for Grid {
|
||||
// TBD
|
||||
}
|
||||
|
||||
fn csi_dispatch(&mut self, params: &Params, _intermediates: &[u8], _ignore: bool, c: char) {
|
||||
fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], _ignore: bool, c: char) {
|
||||
let mut params_iter = params.iter();
|
||||
let mut next_param_or = |default: u16| {
|
||||
params_iter
|
||||
@ -998,7 +1026,7 @@ impl Perform for Grid {
|
||||
self.cursor
|
||||
.pending_styles
|
||||
.add_style_from_ansi_params(&mut params_iter);
|
||||
} else if c == 'C' {
|
||||
} else if c == 'C' || c == 'a' {
|
||||
// move cursor forward
|
||||
let move_by = next_param_or(1);
|
||||
self.move_cursor_forward_until_edge(move_by);
|
||||
@ -1031,7 +1059,6 @@ impl Perform for Grid {
|
||||
self.clear_all(char_to_replace);
|
||||
}
|
||||
};
|
||||
// TODO: implement 1
|
||||
} else if c == 'H' || c == 'f' {
|
||||
// goto row/col
|
||||
// we subtract 1 from the row/column because these are 1 indexed
|
||||
@ -1043,7 +1070,7 @@ impl Perform for Grid {
|
||||
// move cursor up until edge of screen
|
||||
let move_up_count = next_param_or(1);
|
||||
self.move_cursor_up(move_up_count as usize);
|
||||
} else if c == 'B' {
|
||||
} else if c == 'B' || c == 'e' {
|
||||
// move cursor down until edge of screen
|
||||
let move_down_count = next_param_or(1);
|
||||
let pad_character = EMPTY_TERMINAL_CHARACTER;
|
||||
@ -1052,7 +1079,7 @@ impl Perform for Grid {
|
||||
let move_back_count = next_param_or(1);
|
||||
self.move_cursor_back(move_back_count);
|
||||
} else if c == 'l' {
|
||||
let first_intermediate_is_questionmark = match _intermediates.get(0) {
|
||||
let first_intermediate_is_questionmark = match intermediates.get(0) {
|
||||
Some(b'?') => true,
|
||||
None => false,
|
||||
_ => false,
|
||||
@ -1101,7 +1128,7 @@ impl Perform for Grid {
|
||||
self.insert_mode = false;
|
||||
}
|
||||
} else if c == 'h' {
|
||||
let first_intermediate_is_questionmark = match _intermediates.get(0) {
|
||||
let first_intermediate_is_questionmark = match intermediates.get(0) {
|
||||
Some(b'?') => true,
|
||||
None => false,
|
||||
_ => false,
|
||||
@ -1171,7 +1198,7 @@ impl Perform for Grid {
|
||||
let line_count_to_add = next_param_or(1);
|
||||
let pad_character = EMPTY_TERMINAL_CHARACTER;
|
||||
self.add_empty_lines_in_scroll_region(line_count_to_add, pad_character);
|
||||
} else if c == 'G' {
|
||||
} else if c == 'G' || c == '`' {
|
||||
let column = next_param_or(1).saturating_sub(1);
|
||||
self.move_cursor_to_column(column);
|
||||
} else if c == 'g' {
|
||||
@ -1216,6 +1243,46 @@ impl Perform for Grid {
|
||||
// TODO: should this be styled?
|
||||
self.insert_character_at_cursor_position(EMPTY_TERMINAL_CHARACTER);
|
||||
}
|
||||
} else if c == 'b' {
|
||||
if let Some(c) = self.preceding_char {
|
||||
for _ in 0..next_param_or(1) {
|
||||
self.add_character(c);
|
||||
}
|
||||
}
|
||||
} else if c == 'E' {
|
||||
let count = next_param_or(1);
|
||||
let pad_character = EMPTY_TERMINAL_CHARACTER;
|
||||
self.move_cursor_down(count, pad_character);
|
||||
} else if c == 'F' {
|
||||
let count = next_param_or(1);
|
||||
self.move_cursor_up(count);
|
||||
self.move_cursor_to_beginning_of_line();
|
||||
} else if c == 'I' {
|
||||
for _ in 0..next_param_or(1) {
|
||||
self.advance_to_next_tabstop(self.cursor.pending_styles);
|
||||
}
|
||||
} else if c == 'q' {
|
||||
let first_intermediate_is_space = matches!(intermediates.get(0), Some(b' '));
|
||||
if first_intermediate_is_space {
|
||||
// DECSCUSR (CSI Ps SP q) -- Set Cursor Style.
|
||||
let cursor_style_id = next_param_or(0);
|
||||
let shape = match cursor_style_id {
|
||||
0 | 2 => Some(CursorShape::Block),
|
||||
1 => Some(CursorShape::BlinkingBlock),
|
||||
3 => Some(CursorShape::BlinkingUnderline),
|
||||
4 => Some(CursorShape::Underline),
|
||||
5 => Some(CursorShape::BlinkingBeam),
|
||||
6 => Some(CursorShape::Beam),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(cursor_shape) = shape {
|
||||
self.cursor.change_shape(cursor_shape);
|
||||
}
|
||||
}
|
||||
} else if c == 'Z' {
|
||||
for _ in 0..next_param_or(1) {
|
||||
self.move_to_previous_tabstop();
|
||||
}
|
||||
} else {
|
||||
let result = debug_log_to_file(format!("Unhandled csi: {}->{:?}", c, params));
|
||||
#[cfg(not(test))]
|
||||
@ -1262,6 +1329,7 @@ impl Perform for Grid {
|
||||
self.move_cursor_to_beginning_of_line();
|
||||
}
|
||||
(b'M', None) => {
|
||||
// TODO: if cursor is at the top, it should go down one
|
||||
self.move_cursor_up_with_scrolling(1);
|
||||
}
|
||||
(b'c', None) => {
|
||||
|
@ -701,6 +701,16 @@ impl IndexMut<CharsetIndex> for Charsets {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum CursorShape {
|
||||
Block,
|
||||
BlinkingBlock,
|
||||
Underline,
|
||||
BlinkingUnderline,
|
||||
Beam,
|
||||
BlinkingBeam,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Cursor {
|
||||
pub x: usize,
|
||||
@ -708,6 +718,7 @@ pub struct Cursor {
|
||||
pub is_hidden: bool,
|
||||
pub pending_styles: CharacterStyles,
|
||||
pub charsets: Charsets,
|
||||
shape: CursorShape,
|
||||
}
|
||||
|
||||
impl Cursor {
|
||||
@ -718,8 +729,15 @@ impl Cursor {
|
||||
is_hidden: false,
|
||||
pending_styles: CharacterStyles::new(),
|
||||
charsets: Default::default(),
|
||||
shape: CursorShape::Block,
|
||||
}
|
||||
}
|
||||
pub fn change_shape(&mut self, shape: CursorShape) {
|
||||
self.shape = shape;
|
||||
}
|
||||
pub fn get_shape(&self) -> CursorShape {
|
||||
self.shape
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::panes::grid::Grid;
|
||||
use crate::panes::terminal_character::{
|
||||
CharacterStyles, TerminalCharacter, EMPTY_TERMINAL_CHARACTER,
|
||||
CharacterStyles, CursorShape, TerminalCharacter, EMPTY_TERMINAL_CHARACTER,
|
||||
};
|
||||
use crate::pty::VteBytes;
|
||||
use crate::tab::Pane;
|
||||
@ -291,6 +291,16 @@ impl Pane for TerminalPane {
|
||||
fn set_active_at(&mut self, time: Instant) {
|
||||
self.active_at = time;
|
||||
}
|
||||
fn cursor_shape_csi(&self) -> String {
|
||||
match self.grid.cursor_shape() {
|
||||
CursorShape::Block => "\u{1b}[0 q".to_string(),
|
||||
CursorShape::BlinkingBlock => "\u{1b}[1 q".to_string(),
|
||||
CursorShape::Underline => "\u{1b}[4 q".to_string(),
|
||||
CursorShape::BlinkingUnderline => "\u{1b}[3 q".to_string(),
|
||||
CursorShape::Beam => "\u{1b}[6 q".to_string(),
|
||||
CursorShape::BlinkingBeam => "\u{1b}[5 q".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TerminalPane {
|
||||
|
@ -347,3 +347,39 @@ fn vttest8_5() {
|
||||
}
|
||||
assert_snapshot!(format!("{:?}", grid));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn csi_b() {
|
||||
let mut vte_parser = vte::Parser::new();
|
||||
let mut grid = Grid::new(51, 97);
|
||||
let fixture_name = "csi-b";
|
||||
let content = read_fixture(fixture_name);
|
||||
for byte in content {
|
||||
vte_parser.advance(&mut grid, byte);
|
||||
}
|
||||
assert_snapshot!(format!("{:?}", grid));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn csi_capital_i() {
|
||||
let mut vte_parser = vte::Parser::new();
|
||||
let mut grid = Grid::new(51, 97);
|
||||
let fixture_name = "csi-capital-i";
|
||||
let content = read_fixture(fixture_name);
|
||||
for byte in content {
|
||||
vte_parser.advance(&mut grid, byte);
|
||||
}
|
||||
assert_snapshot!(format!("{:?}", grid));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn csi_capital_z() {
|
||||
let mut vte_parser = vte::Parser::new();
|
||||
let mut grid = Grid::new(51, 97);
|
||||
let fixture_name = "csi-capital-z";
|
||||
let content = read_fixture(fixture_name);
|
||||
for byte in content {
|
||||
vte_parser.advance(&mut grid, byte);
|
||||
}
|
||||
assert_snapshot!(format!("{:?}", grid));
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
source: src/client/panes/./unit/grid_tests.rs
|
||||
expression: "format!(\"{:?}\", grid)"
|
||||
|
||||
---
|
||||
00 (C): ffffff
|
||||
01 (C):
|
||||
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
source: src/client/panes/./unit/grid_tests.rs
|
||||
expression: "format!(\"{:?}\", grid)"
|
||||
|
||||
---
|
||||
00 (C): foo
|
||||
01 (C):
|
||||
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
source: src/client/panes/./unit/grid_tests.rs
|
||||
expression: "format!(\"{:?}\", grid)"
|
||||
|
||||
---
|
||||
00 (C): 12345678foo234567890
|
||||
01 (C):
|
||||
|
@ -132,6 +132,9 @@ pub trait Pane {
|
||||
fn clear_scroll(&mut self);
|
||||
fn active_at(&self) -> Instant;
|
||||
fn set_active_at(&mut self, instant: Instant);
|
||||
fn cursor_shape_csi(&self) -> String {
|
||||
"\u{1b}[0 q".to_string() // default to non blinking block
|
||||
}
|
||||
|
||||
fn right_boundary_x_coords(&self) -> usize {
|
||||
self.x() + self.columns()
|
||||
@ -762,10 +765,12 @@ impl Tab {
|
||||
match self.get_active_terminal_cursor_position() {
|
||||
Some((cursor_position_x, cursor_position_y)) => {
|
||||
let show_cursor = "\u{1b}[?25h";
|
||||
let change_cursor_shape = self.get_active_pane().unwrap().cursor_shape_csi();
|
||||
let goto_cursor_position = &format!(
|
||||
"\u{1b}[{};{}H\u{1b}[m",
|
||||
"\u{1b}[{};{}H\u{1b}[m{}",
|
||||
cursor_position_y + 1,
|
||||
cursor_position_x + 1
|
||||
cursor_position_x + 1,
|
||||
change_cursor_shape
|
||||
); // goto row/col
|
||||
output.push_str(show_cursor);
|
||||
output.push_str(goto_cursor_position);
|
||||
|
1
src/tests/fixtures/csi-b
vendored
Normal file
1
src/tests/fixtures/csi-b
vendored
Normal file
@ -0,0 +1 @@
|
||||
f[5b
|
1
src/tests/fixtures/csi-capital-i
vendored
Normal file
1
src/tests/fixtures/csi-capital-i
vendored
Normal file
@ -0,0 +1 @@
|
||||
[5Ifoo
|
1
src/tests/fixtures/csi-capital-z
vendored
Normal file
1
src/tests/fixtures/csi-capital-z
vendored
Normal file
@ -0,0 +1 @@
|
||||
12345678901234567890[2Zfoo
|
Loading…
Reference in New Issue
Block a user