fix(compatibility): fix vim overwrite message and buffer clearing on exit (#98)
* fix(compatibility): fix vim overwrite message and buffer clearing on exit * style(formatting): make rustfmt happy
This commit is contained in:
parent
8589addde0
commit
ac9c0274f4
9 changed files with 265 additions and 24 deletions
|
|
@ -248,7 +248,7 @@ impl Debug for WrappedFragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct CursorPosition {
|
pub struct CursorPosition {
|
||||||
line_index: (usize, usize), // (canonical line index, fragment index in line)
|
line_index: (usize, usize), // (canonical line index, fragment index in line)
|
||||||
column_index: usize, // 0 is the first character from the pane edge
|
column_index: usize, // 0 is the first character from the pane edge
|
||||||
|
|
@ -312,6 +312,8 @@ pub struct Scroll {
|
||||||
viewport_bottom_offset: Option<usize>,
|
viewport_bottom_offset: Option<usize>,
|
||||||
scroll_region: Option<(usize, usize)>, // start line, end line (if set, this is the area the will scroll)
|
scroll_region: Option<(usize, usize)>, // start line, end line (if set, this is the area the will scroll)
|
||||||
show_cursor: bool,
|
show_cursor: bool,
|
||||||
|
lines_outside_of_scroll_region: Option<Vec<CanonicalLine>>,
|
||||||
|
cursor_position_outside_of_scroll_region: Option<CursorPosition>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scroll {
|
impl Scroll {
|
||||||
|
|
@ -327,6 +329,8 @@ impl Scroll {
|
||||||
viewport_bottom_offset: None,
|
viewport_bottom_offset: None,
|
||||||
scroll_region: None,
|
scroll_region: None,
|
||||||
show_cursor: true,
|
show_cursor: true,
|
||||||
|
lines_outside_of_scroll_region: None,
|
||||||
|
cursor_position_outside_of_scroll_region: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn as_character_lines(&self) -> Vec<Vec<TerminalCharacter>> {
|
pub fn as_character_lines(&self) -> Vec<Vec<TerminalCharacter>> {
|
||||||
|
|
@ -393,7 +397,9 @@ impl Scroll {
|
||||||
}
|
}
|
||||||
pub fn add_canonical_line(&mut self) {
|
pub fn add_canonical_line(&mut self) {
|
||||||
let current_canonical_line_index = self.cursor_position.line_index.0;
|
let current_canonical_line_index = self.cursor_position.line_index.0;
|
||||||
if let Some((scroll_region_top, scroll_region_bottom)) = self.scroll_region {
|
if let Some((scroll_region_top, scroll_region_bottom)) =
|
||||||
|
self.scroll_region_absolute_indices()
|
||||||
|
{
|
||||||
if current_canonical_line_index == scroll_region_bottom {
|
if current_canonical_line_index == scroll_region_bottom {
|
||||||
// end of scroll region
|
// end of scroll region
|
||||||
// when we have a scroll region set and we're at its bottom
|
// when we have a scroll region set and we're at its bottom
|
||||||
|
|
@ -500,17 +506,15 @@ impl Scroll {
|
||||||
self.cursor_position.move_up_by_canonical_lines(count);
|
self.cursor_position.move_up_by_canonical_lines(count);
|
||||||
}
|
}
|
||||||
pub fn change_size(&mut self, columns: usize, lines: usize) {
|
pub fn change_size(&mut self, columns: usize, lines: usize) {
|
||||||
if self.scroll_region.is_none() {
|
for canonical_line in self.canonical_lines.iter_mut() {
|
||||||
for canonical_line in self.canonical_lines.iter_mut() {
|
canonical_line.change_width(columns);
|
||||||
canonical_line.change_width(columns);
|
}
|
||||||
}
|
let cursor_line = self
|
||||||
let cursor_line = self
|
.canonical_lines
|
||||||
.canonical_lines
|
.get(self.cursor_position.line_index.0)
|
||||||
.get(self.cursor_position.line_index.0)
|
.expect("cursor out of bounds");
|
||||||
.expect("cursor out of bounds");
|
if cursor_line.wrapped_fragments.len() <= self.cursor_position.line_index.1 {
|
||||||
if cursor_line.wrapped_fragments.len() <= self.cursor_position.line_index.1 {
|
self.cursor_position.line_index.1 = cursor_line.wrapped_fragments.len() - 1;
|
||||||
self.cursor_position.line_index.1 = cursor_line.wrapped_fragments.len() - 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.lines_in_view = lines;
|
self.lines_in_view = lines;
|
||||||
self.total_columns = columns;
|
self.total_columns = columns;
|
||||||
|
|
@ -597,13 +601,18 @@ impl Scroll {
|
||||||
self.cursor_position.reset();
|
self.cursor_position.reset();
|
||||||
}
|
}
|
||||||
pub fn move_cursor_to(&mut self, line: usize, col: usize) {
|
pub fn move_cursor_to(&mut self, line: usize, col: usize) {
|
||||||
if self.canonical_lines.len() > line {
|
let line_on_screen = if self.canonical_lines.len() > self.lines_in_view {
|
||||||
self.cursor_position.move_to_canonical_line(line);
|
line + (self.canonical_lines.len() - self.lines_in_view)
|
||||||
} else {
|
} else {
|
||||||
for _ in self.canonical_lines.len()..=line {
|
line
|
||||||
|
};
|
||||||
|
if self.canonical_lines.len() > line_on_screen {
|
||||||
|
self.cursor_position.move_to_canonical_line(line_on_screen);
|
||||||
|
} else {
|
||||||
|
for _ in self.canonical_lines.len()..=line_on_screen {
|
||||||
self.canonical_lines.push(CanonicalLine::new());
|
self.canonical_lines.push(CanonicalLine::new());
|
||||||
}
|
}
|
||||||
self.cursor_position.move_to_canonical_line(line);
|
self.cursor_position.move_to_canonical_line(line_on_screen);
|
||||||
}
|
}
|
||||||
let (current_canonical_line_index, current_line_wrap_position) =
|
let (current_canonical_line_index, current_line_wrap_position) =
|
||||||
self.cursor_position.line_index;
|
self.cursor_position.line_index;
|
||||||
|
|
@ -630,14 +639,48 @@ impl Scroll {
|
||||||
self.move_cursor_to(line, current_column);
|
self.move_cursor_to(line, current_column);
|
||||||
}
|
}
|
||||||
pub fn set_scroll_region(&mut self, top_line: usize, bottom_line: usize) {
|
pub fn set_scroll_region(&mut self, top_line: usize, bottom_line: usize) {
|
||||||
|
if self.scroll_region.is_none() {
|
||||||
|
self.lines_outside_of_scroll_region = Some(self.canonical_lines.drain(..).collect());
|
||||||
|
self.cursor_position_outside_of_scroll_region = Some(self.cursor_position);
|
||||||
|
}
|
||||||
self.scroll_region = Some((top_line, bottom_line));
|
self.scroll_region = Some((top_line, bottom_line));
|
||||||
// TODO: clear linewraps in scroll region?
|
|
||||||
}
|
}
|
||||||
pub fn clear_scroll_region(&mut self) {
|
pub fn clear_scroll_region(&mut self) {
|
||||||
self.scroll_region = None;
|
if let Some(scroll_region) = self.scroll_region_absolute_indices() {
|
||||||
|
self.canonical_lines.drain(scroll_region.0..scroll_region.1);
|
||||||
|
self.cursor_position.reset();
|
||||||
|
self.scroll_region = None;
|
||||||
|
}
|
||||||
|
if let Some(lines_outside_of_scroll_region) = self.lines_outside_of_scroll_region.as_mut() {
|
||||||
|
self.canonical_lines = lines_outside_of_scroll_region.drain(..).collect();
|
||||||
|
}
|
||||||
|
if let Some(cursor_position_outside_of_scroll_region) =
|
||||||
|
self.cursor_position_outside_of_scroll_region
|
||||||
|
{
|
||||||
|
self.cursor_position = cursor_position_outside_of_scroll_region;
|
||||||
|
}
|
||||||
|
self.lines_outside_of_scroll_region = None;
|
||||||
|
self.cursor_position_outside_of_scroll_region = None;
|
||||||
|
}
|
||||||
|
pub fn set_scroll_region_to_screen_size(&mut self) {
|
||||||
|
self.scroll_region = Some((0, self.lines_in_view - 1)); // these are indices
|
||||||
|
}
|
||||||
|
fn scroll_region_absolute_indices(&mut self) -> Option<(usize, usize)> {
|
||||||
|
if self.scroll_region.is_none() {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
if self.canonical_lines.len() > self.lines_in_view {
|
||||||
|
let absolute_top = self.canonical_lines.len() - 1 - self.lines_in_view;
|
||||||
|
let absolute_bottom = self.canonical_lines.len() - 1;
|
||||||
|
Some((absolute_top, absolute_bottom))
|
||||||
|
} else {
|
||||||
|
Some((self.scroll_region.unwrap().0, self.scroll_region.unwrap().1))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn delete_lines_in_scroll_region(&mut self, count: usize) {
|
pub fn delete_lines_in_scroll_region(&mut self, count: usize) {
|
||||||
if let Some((scroll_region_top, scroll_region_bottom)) = self.scroll_region {
|
if let Some((scroll_region_top, scroll_region_bottom)) =
|
||||||
|
self.scroll_region_absolute_indices()
|
||||||
|
{
|
||||||
let current_canonical_line_index = self.cursor_position.line_index.0;
|
let current_canonical_line_index = self.cursor_position.line_index.0;
|
||||||
if current_canonical_line_index >= scroll_region_top
|
if current_canonical_line_index >= scroll_region_top
|
||||||
&& current_canonical_line_index <= scroll_region_bottom
|
&& current_canonical_line_index <= scroll_region_bottom
|
||||||
|
|
@ -655,7 +698,9 @@ impl Scroll {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn add_empty_lines_in_scroll_region(&mut self, count: usize) {
|
pub fn add_empty_lines_in_scroll_region(&mut self, count: usize) {
|
||||||
if let Some((scroll_region_top, scroll_region_bottom)) = self.scroll_region {
|
if let Some((scroll_region_top, scroll_region_bottom)) =
|
||||||
|
self.scroll_region_absolute_indices()
|
||||||
|
{
|
||||||
let current_canonical_line_index = self.cursor_position.line_index.0;
|
let current_canonical_line_index = self.cursor_position.line_index.0;
|
||||||
if current_canonical_line_index >= scroll_region_top
|
if current_canonical_line_index >= scroll_region_top
|
||||||
&& current_canonical_line_index <= scroll_region_bottom
|
&& current_canonical_line_index <= scroll_region_bottom
|
||||||
|
|
@ -673,7 +718,9 @@ impl Scroll {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn move_cursor_up_in_scroll_region(&mut self, count: usize) {
|
pub fn move_cursor_up_in_scroll_region(&mut self, count: usize) {
|
||||||
if let Some((scroll_region_top, scroll_region_bottom)) = self.scroll_region {
|
if let Some((scroll_region_top, scroll_region_bottom)) =
|
||||||
|
self.scroll_region_absolute_indices()
|
||||||
|
{
|
||||||
// the scroll region indices start at 1, so we need to adjust them
|
// the scroll region indices start at 1, so we need to adjust them
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
let current_canonical_line_index = self.cursor_position.line_index.0;
|
let current_canonical_line_index = self.cursor_position.line_index.0;
|
||||||
|
|
@ -694,7 +741,7 @@ impl Scroll {
|
||||||
/// [scroll_up](https://github.com/alacritty/alacritty/blob/ec42b42ce601808070462111c0c28edb0e89babb/alacritty_terminal/src/grid/mod.rs#L261)
|
/// [scroll_up](https://github.com/alacritty/alacritty/blob/ec42b42ce601808070462111c0c28edb0e89babb/alacritty_terminal/src/grid/mod.rs#L261)
|
||||||
/// This function takes the first line of the scroll region and moves it to the bottom (count times)
|
/// This function takes the first line of the scroll region and moves it to the bottom (count times)
|
||||||
pub fn rotate_scroll_region_up(&mut self, count: usize) {
|
pub fn rotate_scroll_region_up(&mut self, count: usize) {
|
||||||
if let Some((_, scroll_region_bottom)) = self.scroll_region {
|
if let Some((_, scroll_region_bottom)) = self.scroll_region_absolute_indices() {
|
||||||
if self.show_cursor {
|
if self.show_cursor {
|
||||||
let scroll_region_bottom_index = scroll_region_bottom - 1;
|
let scroll_region_bottom_index = scroll_region_bottom - 1;
|
||||||
self.cursor_position
|
self.cursor_position
|
||||||
|
|
@ -714,7 +761,7 @@ impl Scroll {
|
||||||
/// [scroll_down](https://github.com/alacritty/alacritty/blob/ec42b42ce601808070462111c0c28edb0e89babb/alacritty_terminal/src/grid/mod.rs#L221)
|
/// [scroll_down](https://github.com/alacritty/alacritty/blob/ec42b42ce601808070462111c0c28edb0e89babb/alacritty_terminal/src/grid/mod.rs#L221)
|
||||||
/// This function takes the last line of the scroll region and moves it to the top (count times)
|
/// This function takes the last line of the scroll region and moves it to the top (count times)
|
||||||
pub fn rotate_scroll_region_down(&mut self, count: usize) {
|
pub fn rotate_scroll_region_down(&mut self, count: usize) {
|
||||||
if let Some((scroll_region_top, _)) = self.scroll_region {
|
if let Some((scroll_region_top, _)) = self.scroll_region_absolute_indices() {
|
||||||
if self.show_cursor {
|
if self.show_cursor {
|
||||||
let scroll_region_top_index = scroll_region_top - 1;
|
let scroll_region_top_index = scroll_region_top - 1;
|
||||||
self.cursor_position
|
self.cursor_position
|
||||||
|
|
|
||||||
|
|
@ -443,6 +443,15 @@ impl vte::Perform for TerminalPane {
|
||||||
(params[0] as usize - 1, params[1] as usize - 1)
|
(params[0] as usize - 1, params[1] as usize - 1)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
if params.len() >= 1 && params[0] == 0 {
|
||||||
|
// this is a hack
|
||||||
|
//
|
||||||
|
// the logic should *probably* be:
|
||||||
|
// if we get an instruction to move outside the scroll region
|
||||||
|
// (which is 1 indexed, so if we get 0 it's always(?) outside)
|
||||||
|
// we need to set it to screen size
|
||||||
|
self.scroll.set_scroll_region_to_screen_size();
|
||||||
|
}
|
||||||
self.scroll.move_cursor_to(row, col);
|
self.scroll.move_cursor_to(row, col);
|
||||||
} else if c == 'A' {
|
} else if c == 'A' {
|
||||||
// move cursor up until edge of screen
|
// move cursor up until edge of screen
|
||||||
|
|
|
||||||
BIN
src/tests/fixtures/clear_scroll_region
vendored
Normal file
BIN
src/tests/fixtures/clear_scroll_region
vendored
Normal file
Binary file not shown.
BIN
src/tests/fixtures/vim_overwrite
vendored
Normal file
BIN
src/tests/fixtures/vim_overwrite
vendored
Normal file
Binary file not shown.
|
|
@ -260,3 +260,60 @@ pub fn htop_right_scrolling() {
|
||||||
assert_snapshot!(snapshot);
|
assert_snapshot!(snapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn vim_overwrite() {
|
||||||
|
// this tests the vim overwrite message
|
||||||
|
// to recreate:
|
||||||
|
// * open a file in vim
|
||||||
|
// * open the same file in another window
|
||||||
|
// * change the file in the other window and save
|
||||||
|
// * change the file in the original vim window and save
|
||||||
|
// * confirm you would like to change the file by pressing 'y' and then ENTER
|
||||||
|
// * if everything looks fine, this test passed :)
|
||||||
|
let fake_win_size = PositionAndSize {
|
||||||
|
columns: 116,
|
||||||
|
rows: 28,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
};
|
||||||
|
let fixture_name = "vim_overwrite";
|
||||||
|
let mut fake_input_output = get_fake_os_input(&fake_win_size, fixture_name);
|
||||||
|
fake_input_output.add_terminal_input(&[&COMMAND_TOGGLE, &COMMAND_TOGGLE, &QUIT]);
|
||||||
|
start(Box::new(fake_input_output.clone()), Opt::default());
|
||||||
|
let output_frames = fake_input_output
|
||||||
|
.stdout_writer
|
||||||
|
.output_frames
|
||||||
|
.lock()
|
||||||
|
.unwrap();
|
||||||
|
let snapshots = get_output_frame_snapshots(&output_frames, &fake_win_size);
|
||||||
|
for snapshot in snapshots {
|
||||||
|
assert_snapshot!(snapshot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn clear_scroll_region() {
|
||||||
|
// this tests the scroll region used by eg. vim is cleared properly
|
||||||
|
// this means that when vim exits, we get back the previous scroll
|
||||||
|
// buffer
|
||||||
|
let fake_win_size = PositionAndSize {
|
||||||
|
columns: 116,
|
||||||
|
rows: 28,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
};
|
||||||
|
let fixture_name = "clear_scroll_region";
|
||||||
|
let mut fake_input_output = get_fake_os_input(&fake_win_size, fixture_name);
|
||||||
|
fake_input_output.add_terminal_input(&[&COMMAND_TOGGLE, &COMMAND_TOGGLE, &QUIT]);
|
||||||
|
start(Box::new(fake_input_output.clone()), Opt::default());
|
||||||
|
let output_frames = fake_input_output
|
||||||
|
.stdout_writer
|
||||||
|
.output_frames
|
||||||
|
.lock()
|
||||||
|
.unwrap();
|
||||||
|
let snapshots = get_output_frame_snapshots(&output_frames, &fake_win_size);
|
||||||
|
for snapshot in snapshots {
|
||||||
|
assert_snapshot!(snapshot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
---
|
||||||
|
source: src/tests/integration/compatibility.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
⋊> ~/c/mosaic on main ⨯ vim some-file 15:07:22
|
||||||
|
⋊> ~/c/mosaic on main ⨯ 15:07:29
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Bye from Mosaic!█
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
---
|
||||||
|
source: src/tests/integration/compatibility.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
Welcome to fish, the friendly interactive shell
|
||||||
|
⋊> ~/c/mosaic on main ⨯ vim some-file 15:07:22
|
||||||
|
⋊> ~/c/mosaic on main ⨯ █ 15:07:29
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
---
|
||||||
|
source: src/tests/integration/compatibility.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
1 line 1
|
||||||
|
2 line 2
|
||||||
|
3 line 3
|
||||||
|
4 line 4
|
||||||
|
5 line 5
|
||||||
|
6 line 6
|
||||||
|
7 line 7
|
||||||
|
8 line 8
|
||||||
|
9 line 9
|
||||||
|
10 line 10
|
||||||
|
11 line 11
|
||||||
|
12 line 12
|
||||||
|
13 line 13
|
||||||
|
14 line 14
|
||||||
|
15 line 15
|
||||||
|
16 line 16
|
||||||
|
17 line 17
|
||||||
|
18 line 18
|
||||||
|
19 line 19
|
||||||
|
20 line 20
|
||||||
|
21 line 21
|
||||||
|
22 line 22
|
||||||
|
23 line 23
|
||||||
|
24 line 24
|
||||||
|
25 line 25
|
||||||
|
NORMAL some-file unix | utf-8 | no ft 1% 1:1
|
||||||
|
|
||||||
|
Bye from Mosaic!█
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
---
|
||||||
|
source: src/tests/integration/compatibility.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
1 █
|
||||||
|
1 line 1
|
||||||
|
2 line 2
|
||||||
|
3 line 3
|
||||||
|
4 line 4
|
||||||
|
5 line 5
|
||||||
|
6 line 6
|
||||||
|
7 line 7
|
||||||
|
8 line 8
|
||||||
|
9 line 9
|
||||||
|
10 line 10
|
||||||
|
11 line 11
|
||||||
|
12 line 12
|
||||||
|
13 line 13
|
||||||
|
14 line 14
|
||||||
|
15 line 15
|
||||||
|
16 line 16
|
||||||
|
17 line 17
|
||||||
|
18 line 18
|
||||||
|
19 line 19
|
||||||
|
20 line 20
|
||||||
|
21 line 21
|
||||||
|
22 line 22
|
||||||
|
23 line 23
|
||||||
|
24 line 24
|
||||||
|
25 line 25
|
||||||
|
NORMAL some-file unix | utf-8 | no ft 1% 1:1
|
||||||
|
|
||||||
Loading…
Add table
Reference in a new issue