mirror of
https://github.com/wez/wezterm.git
synced 2024-12-24 13:52:55 +03:00
term: avoid dirtying lines when the cursor moves
Tag CursorPosition with the seqno of the cursor move instead. This should avoid over-invalidating lines and the selection if it was just the cursor that moved.
This commit is contained in:
parent
23097993e5
commit
80d261977f
@ -20,6 +20,7 @@ use anyhow::Error;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ops::{Deref, DerefMut, Range};
|
||||
use std::str;
|
||||
use termwiz::surface::SequenceNo;
|
||||
|
||||
pub mod config;
|
||||
pub use config::TerminalConfiguration;
|
||||
@ -112,6 +113,7 @@ pub struct CursorPosition {
|
||||
pub y: VisibleRowIndex,
|
||||
pub shape: termwiz::surface::CursorShape,
|
||||
pub visibility: termwiz::surface::CursorVisibility,
|
||||
pub seqno: SequenceNo,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "use_serde", derive(Deserialize, Serialize))]
|
||||
|
@ -254,6 +254,7 @@ impl Screen {
|
||||
y: new_cursor_y,
|
||||
shape: cursor.shape,
|
||||
visibility: cursor.visibility,
|
||||
seqno,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -737,6 +737,7 @@ impl TerminalState {
|
||||
} else {
|
||||
CursorVisibility::Hidden
|
||||
},
|
||||
seqno: self.cursor.seqno,
|
||||
}
|
||||
}
|
||||
|
||||
@ -746,16 +747,10 @@ impl TerminalState {
|
||||
|
||||
/// Sets the cursor position to precisely the x and values provided
|
||||
fn set_cursor_position_absolute(&mut self, x: usize, y: VisibleRowIndex) {
|
||||
let seqno = self.seqno;
|
||||
let old_y = self.cursor.y;
|
||||
|
||||
self.cursor.y = y;
|
||||
self.cursor.x = x;
|
||||
self.cursor.seqno = self.seqno;
|
||||
self.wrap_next = false;
|
||||
|
||||
let screen = self.screen_mut();
|
||||
screen.dirty_line(old_y, seqno);
|
||||
screen.dirty_line(y, seqno);
|
||||
}
|
||||
|
||||
/// Sets the cursor position. x and y are 0-based and relative to the
|
||||
@ -925,8 +920,7 @@ impl TerminalState {
|
||||
None => self.left_and_right_margins.end - 1,
|
||||
};
|
||||
self.cursor.x = x.min(self.left_and_right_margins.end - 1);
|
||||
let y = self.cursor.y;
|
||||
self.screen_mut().dirty_line(y, seqno);
|
||||
self.cursor.seqno = seqno;
|
||||
}
|
||||
|
||||
/// Move the cursor up 1 line. If the position is at the top scroll margin,
|
||||
@ -1935,7 +1929,6 @@ impl TerminalState {
|
||||
Cursor::Left(n) => {
|
||||
// https://vt100.net/docs/vt510-rm/CUB.html
|
||||
|
||||
let y = self.cursor.y;
|
||||
let candidate = self.cursor.x as i64 - n as i64;
|
||||
let new_x = if self.cursor.x < self.left_and_right_margins.start {
|
||||
// outside the margin, so allow movement to the border
|
||||
@ -1957,14 +1950,12 @@ impl TerminalState {
|
||||
let new_x = new_x.max(0) as usize;
|
||||
|
||||
self.cursor.x = new_x;
|
||||
self.cursor.seqno = seqno;
|
||||
self.wrap_next = false;
|
||||
let screen = self.screen_mut();
|
||||
screen.dirty_line(y, seqno);
|
||||
}
|
||||
|
||||
Cursor::Right(n) => {
|
||||
// https://vt100.net/docs/vt510-rm/CUF.html
|
||||
let y = self.cursor.y;
|
||||
let cols = self.screen().physical_cols;
|
||||
let new_x = if self.cursor.x >= self.left_and_right_margins.end {
|
||||
// outside the margin, so allow movement to screen edge
|
||||
@ -1975,15 +1966,13 @@ impl TerminalState {
|
||||
};
|
||||
|
||||
self.cursor.x = new_x;
|
||||
self.cursor.seqno = seqno;
|
||||
self.wrap_next = false;
|
||||
let screen = self.screen_mut();
|
||||
screen.dirty_line(y, seqno);
|
||||
}
|
||||
|
||||
Cursor::Up(n) => {
|
||||
// https://vt100.net/docs/vt510-rm/CUU.html
|
||||
|
||||
let old_y = self.cursor.y;
|
||||
let candidate = self.cursor.y.saturating_sub(i64::from(n));
|
||||
let new_y = if self.cursor.y < self.top_and_bottom_margins.start {
|
||||
// above the top margin, so allow movement to
|
||||
@ -2001,14 +1990,11 @@ impl TerminalState {
|
||||
let new_y = new_y.max(0);
|
||||
|
||||
self.cursor.y = new_y;
|
||||
self.cursor.seqno = seqno;
|
||||
self.wrap_next = false;
|
||||
let screen = self.screen_mut();
|
||||
screen.dirty_line(old_y, seqno);
|
||||
screen.dirty_line(new_y, seqno);
|
||||
}
|
||||
Cursor::Down(n) => {
|
||||
// https://vt100.net/docs/vt510-rm/CUD.html
|
||||
let old_y = self.cursor.y;
|
||||
let rows = self.screen().physical_rows;
|
||||
let new_y = if self.cursor.y >= self.top_and_bottom_margins.end {
|
||||
// below the bottom margin, so allow movement to
|
||||
@ -2020,10 +2006,8 @@ impl TerminalState {
|
||||
};
|
||||
|
||||
self.cursor.y = new_y;
|
||||
self.cursor.seqno = seqno;
|
||||
self.wrap_next = false;
|
||||
let screen = self.screen_mut();
|
||||
screen.dirty_line(old_y, seqno);
|
||||
screen.dirty_line(new_y, seqno);
|
||||
}
|
||||
|
||||
Cursor::CharacterAndLinePosition { line, col } | Cursor::Position { line, col } => self
|
||||
@ -2044,10 +2028,8 @@ impl TerminalState {
|
||||
col
|
||||
};
|
||||
self.cursor.x = col.min(self.screen().physical_cols - 1);
|
||||
self.cursor.seqno = seqno;
|
||||
self.wrap_next = false;
|
||||
let y = self.cursor.y;
|
||||
let screen = self.screen_mut();
|
||||
screen.dirty_line(y, seqno);
|
||||
}
|
||||
|
||||
Cursor::CharacterPositionBackward(col) => self.set_cursor_pos(
|
||||
@ -2070,7 +2052,6 @@ impl TerminalState {
|
||||
}
|
||||
Cursor::NextLine(n) => {
|
||||
// https://vt100.net/docs/vt510-rm/CNL.html
|
||||
let old_y = self.cursor.y;
|
||||
let rows = self.screen().physical_rows;
|
||||
let new_y = if self.cursor.y >= self.top_and_bottom_margins.end {
|
||||
// below the bottom margin, so allow movement to
|
||||
@ -2083,14 +2064,11 @@ impl TerminalState {
|
||||
|
||||
self.cursor.y = new_y;
|
||||
self.cursor.x = self.left_and_right_margins.start;
|
||||
self.cursor.seqno = seqno;
|
||||
self.wrap_next = false;
|
||||
let screen = self.screen_mut();
|
||||
screen.dirty_line(old_y, seqno);
|
||||
screen.dirty_line(new_y, seqno);
|
||||
}
|
||||
Cursor::PrecedingLine(n) => {
|
||||
// https://vt100.net/docs/vt510-rm/CPL.html
|
||||
let old_y = self.cursor.y;
|
||||
let candidate = self.cursor.y.saturating_sub(i64::from(n));
|
||||
let new_y = if self.cursor.y < self.top_and_bottom_margins.start {
|
||||
// above the top margin, so allow movement to
|
||||
@ -2109,10 +2087,8 @@ impl TerminalState {
|
||||
|
||||
self.cursor.y = new_y;
|
||||
self.cursor.x = self.left_and_right_margins.start;
|
||||
self.cursor.seqno = seqno;
|
||||
self.wrap_next = false;
|
||||
let screen = self.screen_mut();
|
||||
screen.dirty_line(old_y, seqno);
|
||||
screen.dirty_line(new_y, seqno);
|
||||
}
|
||||
|
||||
Cursor::ActivePositionReport { .. } => {
|
||||
|
@ -5,11 +5,11 @@ use super::*;
|
||||
#[test]
|
||||
fn test_bs() {
|
||||
let mut term = TestTerm::new(3, 4, 0);
|
||||
term.assert_cursor_pos(0, 0, None);
|
||||
term.assert_cursor_pos(0, 0, None, Some(0));
|
||||
term.print("\x08");
|
||||
term.assert_cursor_pos(0, 0, Some("cannot move left of the margin"));
|
||||
term.assert_cursor_pos(0, 0, Some("cannot move left of the margin"), Some(0));
|
||||
term.print("ab\x08");
|
||||
term.assert_cursor_pos(1, 0, None);
|
||||
term.assert_cursor_pos(1, 0, None, None);
|
||||
// TODO: when we can set the left margin, we should test that here
|
||||
}
|
||||
|
||||
@ -17,14 +17,22 @@ fn test_bs() {
|
||||
fn test_lf() {
|
||||
let mut term = TestTerm::new(3, 10, 0);
|
||||
term.print("hello\n");
|
||||
term.assert_cursor_pos(5, 1, Some("LF moves vertically only"));
|
||||
term.assert_cursor_pos(5, 1, Some("LF moves vertically only"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cr() {
|
||||
let mut term = TestTerm::new(3, 10, 0);
|
||||
term.print("hello\r");
|
||||
term.assert_cursor_pos(0, 0, Some("CR moves to left margin on current line"));
|
||||
term.assert_cursor_pos(
|
||||
0,
|
||||
0,
|
||||
Some(
|
||||
"CR moves to left margin on current line, \
|
||||
but is unchanged relative to the initial state",
|
||||
),
|
||||
Some(0),
|
||||
);
|
||||
// TODO: when we can set the left margin, we should test that here
|
||||
}
|
||||
|
||||
@ -32,11 +40,11 @@ fn test_cr() {
|
||||
fn test_tab() {
|
||||
let mut term = TestTerm::new(3, 25, 0);
|
||||
term.print("\t");
|
||||
term.assert_cursor_pos(8, 0, None);
|
||||
term.assert_cursor_pos(8, 0, None, None);
|
||||
term.print("\t");
|
||||
term.assert_cursor_pos(16, 0, None);
|
||||
term.assert_cursor_pos(16, 0, None, None);
|
||||
term.print("\t");
|
||||
term.assert_cursor_pos(24, 0, None);
|
||||
term.assert_cursor_pos(24, 0, None, None);
|
||||
term.print("\t");
|
||||
term.assert_cursor_pos(24, 0, None);
|
||||
term.assert_cursor_pos(24, 0, None, None);
|
||||
}
|
||||
|
@ -6,12 +6,12 @@ use super::*;
|
||||
fn test_ind() {
|
||||
let mut term = TestTerm::new(4, 4, 0);
|
||||
term.print("a\r\nb\x1bD");
|
||||
term.assert_cursor_pos(1, 2, None);
|
||||
term.assert_cursor_pos(1, 2, None, None);
|
||||
assert_visible_contents(&term, file!(), line!(), &["a", "b", "", ""]);
|
||||
term.print("\x1bD");
|
||||
term.assert_cursor_pos(1, 3, None);
|
||||
term.assert_cursor_pos(1, 3, None, None);
|
||||
term.print("\x1bD");
|
||||
term.assert_cursor_pos(1, 3, None);
|
||||
term.assert_cursor_pos(1, 3, None, Some(term.current_seqno() - 1));
|
||||
assert_visible_contents(&term, file!(), line!(), &["b", "", "", ""]);
|
||||
}
|
||||
|
||||
@ -19,11 +19,11 @@ fn test_ind() {
|
||||
fn test_nel() {
|
||||
let mut term = TestTerm::new(4, 4, 0);
|
||||
term.print("a\r\nb\x1bE");
|
||||
term.assert_cursor_pos(0, 2, None);
|
||||
term.assert_cursor_pos(0, 2, None, None);
|
||||
term.print("\x1bE");
|
||||
term.assert_cursor_pos(0, 3, None);
|
||||
term.assert_cursor_pos(0, 3, None, None);
|
||||
term.print("\x1bE");
|
||||
term.assert_cursor_pos(0, 3, None);
|
||||
term.assert_cursor_pos(0, 3, None, None);
|
||||
assert_visible_contents(&term, file!(), line!(), &["b", "", "", ""]);
|
||||
}
|
||||
|
||||
@ -32,25 +32,25 @@ fn test_hts() {
|
||||
let mut term = TestTerm::new(3, 25, 0);
|
||||
term.print("boo");
|
||||
term.print("\x1bH\r\n");
|
||||
term.assert_cursor_pos(0, 1, None);
|
||||
term.assert_cursor_pos(0, 1, None, None);
|
||||
term.print("\t");
|
||||
term.assert_cursor_pos(3, 1, None);
|
||||
term.assert_cursor_pos(3, 1, None, None);
|
||||
term.print("\t");
|
||||
term.assert_cursor_pos(8, 1, None);
|
||||
term.assert_cursor_pos(8, 1, None, None);
|
||||
|
||||
// Check that tabs are expanded if we resize
|
||||
term.resize(4, 80, 4 * 16, 80 * 8);
|
||||
term.cup(0, 1);
|
||||
term.print("\t");
|
||||
term.assert_cursor_pos(3, 1, None);
|
||||
term.assert_cursor_pos(3, 1, None, None);
|
||||
term.print("\t");
|
||||
term.assert_cursor_pos(8, 1, None);
|
||||
term.assert_cursor_pos(8, 1, None, None);
|
||||
term.print("\t");
|
||||
term.assert_cursor_pos(16, 1, None);
|
||||
term.assert_cursor_pos(16, 1, None, None);
|
||||
term.print("\t");
|
||||
term.assert_cursor_pos(24, 1, None);
|
||||
term.assert_cursor_pos(24, 1, None, None);
|
||||
term.print("\t");
|
||||
term.assert_cursor_pos(32, 1, None);
|
||||
term.assert_cursor_pos(32, 1, None, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -58,14 +58,15 @@ fn test_ri() {
|
||||
let mut term = TestTerm::new(4, 2, 0);
|
||||
term.print("a\r\nb\r\nc\r\nd.");
|
||||
assert_visible_contents(&term, file!(), line!(), &["a", "b", "c", "d."]);
|
||||
term.assert_cursor_pos(1, 3, None);
|
||||
term.assert_cursor_pos(1, 3, None, None);
|
||||
term.print("\x1bM");
|
||||
term.assert_cursor_pos(1, 2, None);
|
||||
term.assert_cursor_pos(1, 2, None, None);
|
||||
term.print("\x1bM");
|
||||
term.assert_cursor_pos(1, 1, None);
|
||||
term.assert_cursor_pos(1, 1, None, None);
|
||||
term.print("\x1bM");
|
||||
term.assert_cursor_pos(1, 0, None);
|
||||
term.assert_cursor_pos(1, 0, None, None);
|
||||
let seqno = term.current_seqno();
|
||||
term.print("\x1bM");
|
||||
term.assert_cursor_pos(1, 0, None);
|
||||
term.assert_cursor_pos(1, 0, None, Some(seqno));
|
||||
assert_visible_contents(&term, file!(), line!(), &["", "a", "b", "c"]);
|
||||
}
|
||||
|
@ -3,20 +3,20 @@ use super::*;
|
||||
#[test]
|
||||
fn test_vpa() {
|
||||
let mut term = TestTerm::new(3, 4, 0);
|
||||
term.assert_cursor_pos(0, 0, None);
|
||||
term.assert_cursor_pos(0, 0, None, Some(0));
|
||||
term.print("a\r\nb\r\nc");
|
||||
term.assert_cursor_pos(1, 2, None);
|
||||
term.assert_cursor_pos(1, 2, None, None);
|
||||
term.print("\x1b[d");
|
||||
term.assert_cursor_pos(1, 0, None);
|
||||
term.assert_cursor_pos(1, 0, None, None);
|
||||
term.print("\r\n\r\n");
|
||||
term.assert_cursor_pos(0, 2, None);
|
||||
term.assert_cursor_pos(0, 2, None, None);
|
||||
|
||||
// escapes are 1-based, so check that we're handling that
|
||||
// when we parse them!
|
||||
term.print("\x1b[2d");
|
||||
term.assert_cursor_pos(0, 1, None);
|
||||
term.assert_cursor_pos(0, 1, None, None);
|
||||
term.print("\x1b[-2d");
|
||||
term.assert_cursor_pos(0, 1, None);
|
||||
term.assert_cursor_pos(0, 1, None, Some(term.current_seqno() - 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -85,30 +85,30 @@ fn test_dch() {
|
||||
fn test_cup() {
|
||||
let mut term = TestTerm::new(3, 4, 0);
|
||||
term.cup(1, 1);
|
||||
term.assert_cursor_pos(1, 1, None);
|
||||
term.assert_cursor_pos(1, 1, None, None);
|
||||
term.cup(-1, -1);
|
||||
term.assert_cursor_pos(0, 0, None);
|
||||
term.assert_cursor_pos(0, 0, None, None);
|
||||
term.cup(2, 2);
|
||||
term.assert_cursor_pos(2, 2, None);
|
||||
term.assert_cursor_pos(2, 2, None, None);
|
||||
term.cup(-1, -1);
|
||||
term.assert_cursor_pos(0, 0, None);
|
||||
term.assert_cursor_pos(0, 0, None, None);
|
||||
term.cup(500, 500);
|
||||
term.assert_cursor_pos(3, 2, None);
|
||||
term.assert_cursor_pos(3, 2, None, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hvp() {
|
||||
let mut term = TestTerm::new(3, 4, 0);
|
||||
term.hvp(1, 1);
|
||||
term.assert_cursor_pos(1, 1, None);
|
||||
term.assert_cursor_pos(1, 1, None, None);
|
||||
term.hvp(-1, -1);
|
||||
term.assert_cursor_pos(0, 0, None);
|
||||
term.assert_cursor_pos(0, 0, None, None);
|
||||
term.hvp(2, 2);
|
||||
term.assert_cursor_pos(2, 2, None);
|
||||
term.assert_cursor_pos(2, 2, None, None);
|
||||
term.hvp(-1, -1);
|
||||
term.assert_cursor_pos(0, 0, None);
|
||||
term.assert_cursor_pos(0, 0, None, None);
|
||||
term.hvp(500, 500);
|
||||
term.assert_cursor_pos(3, 2, None);
|
||||
term.assert_cursor_pos(3, 2, None, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -116,9 +116,10 @@ fn test_dl() {
|
||||
let mut term = TestTerm::new(3, 1, 0);
|
||||
term.print("a\r\nb\r\nc");
|
||||
term.cup(0, 1);
|
||||
let seqno = term.current_seqno();
|
||||
term.delete_lines(1);
|
||||
assert_visible_contents(&term, file!(), line!(), &["a", "c", ""]);
|
||||
term.assert_cursor_pos(0, 1, None);
|
||||
term.assert_cursor_pos(0, 1, None, Some(seqno));
|
||||
term.cup(0, 0);
|
||||
term.delete_lines(2);
|
||||
assert_visible_contents(&term, file!(), line!(), &["", "", ""]);
|
||||
@ -132,22 +133,23 @@ fn test_dl() {
|
||||
fn test_cha() {
|
||||
let mut term = TestTerm::new(3, 4, 0);
|
||||
term.cup(1, 1);
|
||||
term.assert_cursor_pos(1, 1, None);
|
||||
term.assert_cursor_pos(1, 1, None, None);
|
||||
|
||||
term.print("\x1b[G");
|
||||
term.assert_cursor_pos(0, 1, None);
|
||||
term.assert_cursor_pos(0, 1, None, None);
|
||||
|
||||
term.print("\x1b[2G");
|
||||
term.assert_cursor_pos(1, 1, None);
|
||||
term.assert_cursor_pos(1, 1, None, None);
|
||||
|
||||
term.print("\x1b[0G");
|
||||
term.assert_cursor_pos(0, 1, None);
|
||||
term.assert_cursor_pos(0, 1, None, None);
|
||||
|
||||
let seqno = term.current_seqno();
|
||||
term.print("\x1b[-1G");
|
||||
term.assert_cursor_pos(0, 1, None);
|
||||
term.assert_cursor_pos(0, 1, None, Some(seqno));
|
||||
|
||||
term.print("\x1b[100G");
|
||||
term.assert_cursor_pos(3, 1, None);
|
||||
term.assert_cursor_pos(3, 1, None, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -149,13 +149,14 @@ impl TestTerm {
|
||||
self.print("!p");
|
||||
}
|
||||
|
||||
fn assert_cursor_pos(&self, x: usize, y: i64, reason: Option<&str>) {
|
||||
fn assert_cursor_pos(&self, x: usize, y: i64, reason: Option<&str>, seqno: Option<SequenceNo>) {
|
||||
let cursor = self.cursor_pos();
|
||||
let expect = CursorPosition {
|
||||
x,
|
||||
y,
|
||||
shape: CursorShape::Default,
|
||||
visibility: CursorVisibility::Visible,
|
||||
seqno: seqno.unwrap_or_else(|| self.current_seqno()),
|
||||
};
|
||||
assert_eq!(
|
||||
cursor, expect,
|
||||
@ -165,12 +166,14 @@ impl TestTerm {
|
||||
}
|
||||
|
||||
fn assert_dirty_lines(&self, seqno: SequenceNo, expected: &[usize], reason: Option<&str>) {
|
||||
let mut seqs = vec![];
|
||||
let dirty_indices: Vec<usize> = self
|
||||
.screen()
|
||||
.lines
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, line)| {
|
||||
seqs.push(line.current_seqno());
|
||||
if line.changed_since(seqno) {
|
||||
Some(i)
|
||||
} else {
|
||||
@ -180,8 +183,9 @@ impl TestTerm {
|
||||
.collect();
|
||||
assert_eq!(
|
||||
&dirty_indices, &expected,
|
||||
"actual dirty lines (left) didn't match expected dirty lines (right) reason={:?}",
|
||||
reason
|
||||
"actual dirty lines (left) didn't match expected dirty \
|
||||
lines (right) reason={:?}. threshold seq: {} seqs: {:?}",
|
||||
reason, seqno, seqs
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -503,14 +507,14 @@ fn cursor_movement_damage() {
|
||||
let seqno = term.current_seqno();
|
||||
term.print("fooo.");
|
||||
assert_visible_contents(&term, file!(), line!(), &["foo", "o."]);
|
||||
term.assert_cursor_pos(2, 1, None);
|
||||
term.assert_cursor_pos(2, 1, None, None);
|
||||
term.assert_dirty_lines(seqno, &[0, 1], None);
|
||||
|
||||
term.cup(0, 1);
|
||||
|
||||
let seqno = term.current_seqno();
|
||||
term.print("\x08");
|
||||
term.assert_cursor_pos(0, 1, Some("BS doesn't change the line"));
|
||||
term.assert_cursor_pos(0, 1, Some("BS doesn't change the line"), Some(seqno));
|
||||
// Since we didn't move, the line isn't dirty
|
||||
term.assert_dirty_lines(seqno, &[], None);
|
||||
|
||||
@ -518,9 +522,10 @@ fn cursor_movement_damage() {
|
||||
term.cup(0, 0);
|
||||
term.assert_dirty_lines(
|
||||
seqno,
|
||||
&[0, 1],
|
||||
Some("cursor movement dirties old and new lines"),
|
||||
&[],
|
||||
Some("cursor movement no longer dirties old and new lines"),
|
||||
);
|
||||
term.assert_cursor_pos(0, 0, None, None);
|
||||
}
|
||||
const NUM_COLS: usize = 3;
|
||||
|
||||
@ -664,7 +669,7 @@ fn test_delete_lines() {
|
||||
term.delete_lines(2);
|
||||
|
||||
assert_visible_contents(&term, file!(), line!(), &["111", "aaa", "", "", "bbb"]);
|
||||
term.assert_dirty_lines(seqno, &[0, 1, 2, 3], None);
|
||||
term.assert_dirty_lines(seqno, &[1, 2, 3], None);
|
||||
|
||||
// expand the scroll region to fill the screen
|
||||
term.set_scroll_region(0, 4);
|
||||
|
Loading…
Reference in New Issue
Block a user