mirror of
https://github.com/zellij-org/zellij.git
synced 2024-11-26 10:55:12 +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)
|
* 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)
|
* 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)
|
* 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
|
## [0.8.0] - 2021-05-07
|
||||||
* Terminal compatibility: pass vttest 8 (https://github.com/zellij-org/zellij/pull/461)
|
* 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::utils::logging::debug_log_to_file;
|
||||||
|
|
||||||
use crate::panes::terminal_character::{
|
use crate::panes::terminal_character::{
|
||||||
CharacterStyles, CharsetIndex, Cursor, StandardCharset, TerminalCharacter,
|
CharacterStyles, CharsetIndex, Cursor, CursorShape, StandardCharset, TerminalCharacter,
|
||||||
EMPTY_TERMINAL_CHARACTER,
|
EMPTY_TERMINAL_CHARACTER,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -177,6 +177,7 @@ pub struct Grid {
|
|||||||
saved_cursor_position: Option<Cursor>,
|
saved_cursor_position: Option<Cursor>,
|
||||||
scroll_region: Option<(usize, usize)>,
|
scroll_region: Option<(usize, usize)>,
|
||||||
active_charset: CharsetIndex,
|
active_charset: CharsetIndex,
|
||||||
|
preceding_char: Option<TerminalCharacter>,
|
||||||
pub should_render: bool,
|
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 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
|
pub erasure_mode: bool, // ERM
|
||||||
@ -210,6 +211,7 @@ impl Grid {
|
|||||||
cursor: Cursor::new(0, 0),
|
cursor: Cursor::new(0, 0),
|
||||||
saved_cursor_position: None,
|
saved_cursor_position: None,
|
||||||
scroll_region: None,
|
scroll_region: None,
|
||||||
|
preceding_char: None,
|
||||||
width: columns,
|
width: columns,
|
||||||
height: rows,
|
height: rows,
|
||||||
should_render: true,
|
should_render: true,
|
||||||
@ -245,6 +247,26 @@ impl Grid {
|
|||||||
empty_character.styles = styles;
|
empty_character.styles = styles;
|
||||||
self.pad_current_line_until(self.cursor.x);
|
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) {
|
fn set_horizontal_tabstop(&mut self) {
|
||||||
self.horizontal_tabstops.insert(self.cursor.x);
|
self.horizontal_tabstops.insert(self.cursor.x);
|
||||||
}
|
}
|
||||||
@ -925,6 +947,10 @@ impl Grid {
|
|||||||
self.active_charset = Default::default();
|
self.active_charset = Default::default();
|
||||||
self.erasure_mode = false;
|
self.erasure_mode = false;
|
||||||
self.disable_linewrap = 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,
|
character: c,
|
||||||
styles: self.cursor.pending_styles,
|
styles: self.cursor.pending_styles,
|
||||||
};
|
};
|
||||||
|
self.set_preceding_character(terminal_character);
|
||||||
self.add_character(terminal_character);
|
self.add_character(terminal_character);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -950,9 +977,10 @@ impl Perform for Grid {
|
|||||||
// tab
|
// tab
|
||||||
self.advance_to_next_tabstop(self.cursor.pending_styles);
|
self.advance_to_next_tabstop(self.cursor.pending_styles);
|
||||||
}
|
}
|
||||||
10 | 11 => {
|
10 | 11 | 12 => {
|
||||||
// 0a, newline
|
// 0a, newline
|
||||||
// 0b, vertical tabulation
|
// 0b, vertical tabulation
|
||||||
|
// 0c, form feed
|
||||||
self.add_newline();
|
self.add_newline();
|
||||||
}
|
}
|
||||||
13 => {
|
13 => {
|
||||||
@ -985,7 +1013,7 @@ impl Perform for Grid {
|
|||||||
// TBD
|
// 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 params_iter = params.iter();
|
||||||
let mut next_param_or = |default: u16| {
|
let mut next_param_or = |default: u16| {
|
||||||
params_iter
|
params_iter
|
||||||
@ -998,7 +1026,7 @@ impl Perform for Grid {
|
|||||||
self.cursor
|
self.cursor
|
||||||
.pending_styles
|
.pending_styles
|
||||||
.add_style_from_ansi_params(&mut params_iter);
|
.add_style_from_ansi_params(&mut params_iter);
|
||||||
} else if c == 'C' {
|
} else if c == 'C' || c == 'a' {
|
||||||
// move cursor forward
|
// move cursor forward
|
||||||
let move_by = next_param_or(1);
|
let move_by = next_param_or(1);
|
||||||
self.move_cursor_forward_until_edge(move_by);
|
self.move_cursor_forward_until_edge(move_by);
|
||||||
@ -1031,7 +1059,6 @@ impl Perform for Grid {
|
|||||||
self.clear_all(char_to_replace);
|
self.clear_all(char_to_replace);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// TODO: implement 1
|
|
||||||
} else if c == 'H' || c == 'f' {
|
} else if c == 'H' || c == 'f' {
|
||||||
// goto row/col
|
// goto row/col
|
||||||
// we subtract 1 from the row/column because these are 1 indexed
|
// 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
|
// move cursor up until edge of screen
|
||||||
let move_up_count = next_param_or(1);
|
let move_up_count = next_param_or(1);
|
||||||
self.move_cursor_up(move_up_count as usize);
|
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
|
// move cursor down until edge of screen
|
||||||
let move_down_count = next_param_or(1);
|
let move_down_count = next_param_or(1);
|
||||||
let pad_character = EMPTY_TERMINAL_CHARACTER;
|
let pad_character = EMPTY_TERMINAL_CHARACTER;
|
||||||
@ -1052,7 +1079,7 @@ impl Perform for Grid {
|
|||||||
let move_back_count = next_param_or(1);
|
let move_back_count = next_param_or(1);
|
||||||
self.move_cursor_back(move_back_count);
|
self.move_cursor_back(move_back_count);
|
||||||
} else if c == 'l' {
|
} 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,
|
Some(b'?') => true,
|
||||||
None => false,
|
None => false,
|
||||||
_ => false,
|
_ => false,
|
||||||
@ -1101,7 +1128,7 @@ impl Perform for Grid {
|
|||||||
self.insert_mode = false;
|
self.insert_mode = false;
|
||||||
}
|
}
|
||||||
} else if c == 'h' {
|
} 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,
|
Some(b'?') => true,
|
||||||
None => false,
|
None => false,
|
||||||
_ => false,
|
_ => false,
|
||||||
@ -1171,7 +1198,7 @@ impl Perform for Grid {
|
|||||||
let line_count_to_add = next_param_or(1);
|
let line_count_to_add = next_param_or(1);
|
||||||
let pad_character = EMPTY_TERMINAL_CHARACTER;
|
let pad_character = EMPTY_TERMINAL_CHARACTER;
|
||||||
self.add_empty_lines_in_scroll_region(line_count_to_add, pad_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);
|
let column = next_param_or(1).saturating_sub(1);
|
||||||
self.move_cursor_to_column(column);
|
self.move_cursor_to_column(column);
|
||||||
} else if c == 'g' {
|
} else if c == 'g' {
|
||||||
@ -1216,6 +1243,46 @@ impl Perform for Grid {
|
|||||||
// TODO: should this be styled?
|
// TODO: should this be styled?
|
||||||
self.insert_character_at_cursor_position(EMPTY_TERMINAL_CHARACTER);
|
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 {
|
} else {
|
||||||
let result = debug_log_to_file(format!("Unhandled csi: {}->{:?}", c, params));
|
let result = debug_log_to_file(format!("Unhandled csi: {}->{:?}", c, params));
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
@ -1262,6 +1329,7 @@ impl Perform for Grid {
|
|||||||
self.move_cursor_to_beginning_of_line();
|
self.move_cursor_to_beginning_of_line();
|
||||||
}
|
}
|
||||||
(b'M', None) => {
|
(b'M', None) => {
|
||||||
|
// TODO: if cursor is at the top, it should go down one
|
||||||
self.move_cursor_up_with_scrolling(1);
|
self.move_cursor_up_with_scrolling(1);
|
||||||
}
|
}
|
||||||
(b'c', None) => {
|
(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)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Cursor {
|
pub struct Cursor {
|
||||||
pub x: usize,
|
pub x: usize,
|
||||||
@ -708,6 +718,7 @@ pub struct Cursor {
|
|||||||
pub is_hidden: bool,
|
pub is_hidden: bool,
|
||||||
pub pending_styles: CharacterStyles,
|
pub pending_styles: CharacterStyles,
|
||||||
pub charsets: Charsets,
|
pub charsets: Charsets,
|
||||||
|
shape: CursorShape,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cursor {
|
impl Cursor {
|
||||||
@ -718,8 +729,15 @@ impl Cursor {
|
|||||||
is_hidden: false,
|
is_hidden: false,
|
||||||
pending_styles: CharacterStyles::new(),
|
pending_styles: CharacterStyles::new(),
|
||||||
charsets: Default::default(),
|
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)]
|
#[derive(Clone, Copy)]
|
||||||
|
@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::panes::grid::Grid;
|
use crate::panes::grid::Grid;
|
||||||
use crate::panes::terminal_character::{
|
use crate::panes::terminal_character::{
|
||||||
CharacterStyles, TerminalCharacter, EMPTY_TERMINAL_CHARACTER,
|
CharacterStyles, CursorShape, TerminalCharacter, EMPTY_TERMINAL_CHARACTER,
|
||||||
};
|
};
|
||||||
use crate::pty::VteBytes;
|
use crate::pty::VteBytes;
|
||||||
use crate::tab::Pane;
|
use crate::tab::Pane;
|
||||||
@ -291,6 +291,16 @@ impl Pane for TerminalPane {
|
|||||||
fn set_active_at(&mut self, time: Instant) {
|
fn set_active_at(&mut self, time: Instant) {
|
||||||
self.active_at = time;
|
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 {
|
impl TerminalPane {
|
||||||
|
@ -347,3 +347,39 @@ fn vttest8_5() {
|
|||||||
}
|
}
|
||||||
assert_snapshot!(format!("{:?}", grid));
|
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 clear_scroll(&mut self);
|
||||||
fn active_at(&self) -> Instant;
|
fn active_at(&self) -> Instant;
|
||||||
fn set_active_at(&mut self, instant: 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 {
|
fn right_boundary_x_coords(&self) -> usize {
|
||||||
self.x() + self.columns()
|
self.x() + self.columns()
|
||||||
@ -762,10 +765,12 @@ impl Tab {
|
|||||||
match self.get_active_terminal_cursor_position() {
|
match self.get_active_terminal_cursor_position() {
|
||||||
Some((cursor_position_x, cursor_position_y)) => {
|
Some((cursor_position_x, cursor_position_y)) => {
|
||||||
let show_cursor = "\u{1b}[?25h";
|
let show_cursor = "\u{1b}[?25h";
|
||||||
|
let change_cursor_shape = self.get_active_pane().unwrap().cursor_shape_csi();
|
||||||
let goto_cursor_position = &format!(
|
let goto_cursor_position = &format!(
|
||||||
"\u{1b}[{};{}H\u{1b}[m",
|
"\u{1b}[{};{}H\u{1b}[m{}",
|
||||||
cursor_position_y + 1,
|
cursor_position_y + 1,
|
||||||
cursor_position_x + 1
|
cursor_position_x + 1,
|
||||||
|
change_cursor_shape
|
||||||
); // goto row/col
|
); // goto row/col
|
||||||
output.push_str(show_cursor);
|
output.push_str(show_cursor);
|
||||||
output.push_str(goto_cursor_position);
|
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