1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-29 21:44:24 +03:00

improve resize handling

Both in terms of resizing the window and running the `resize` utility.
This commit is contained in:
Wez Furlong 2018-02-04 09:17:05 -08:00
parent 4c8e3ffd75
commit 09c70930b9
3 changed files with 182 additions and 139 deletions

View File

@ -159,11 +159,31 @@ impl<'a> TerminalWindow<'a> {
self.width = width;
self.height = height;
let rows = height / self.cell_height as u16;
let cols = width / self.cell_width as u16;
let rows = (height as f64 / self.cell_height).floor() as u16;
let cols = (width as f64 / self.cell_width).floor() as u16;
self.pty.resize(rows, cols, width, height)?;
self.terminal.resize(rows as usize, cols as usize);
// If we have partial rows or columns to the bottom or right,
// clear those out as they may contains artifacts from prior to
// the resize.
let palette = term::color::ColorPalette::default();
let background_color = palette.resolve(&term::color::ColorAttribute::Background);
self.buffer_image.clear_rect(
cols as isize * self.cell_width as isize,
0,
width as usize - (cols as usize * self.cell_width as usize),
self.height as usize,
background_color.into(),
);
self.buffer_image.clear_rect(
0,
rows as isize * self.cell_height as isize,
width as usize,
height as usize - (rows as usize * self.cell_height as usize),
background_color.into(),
);
Ok(true)
} else {
debug!("ignoring extra resize");

View File

@ -351,6 +351,17 @@ impl<'a> CSIParser<'a> {
bottom: bottom - 1,
})
}
&[] => {
// Default is to restore the region to the full size of
// the screen. We don't have that information here, so
// we're just reporting the maximum possible range and
// relying on the code that acts on this to clamp accordingly
Some(CSIAction::SetScrollingRegion {
top: 0,
bottom: i64::max_value(),
})
}
_ => {
println!("set_scroll_region: invalid sequence: {:?}", params);
None

View File

@ -461,8 +461,10 @@ impl Screen {
#[inline]
fn dirty_line(&mut self, idx: VisibleRowIndex) {
let line_idx = self.phys_row(idx);
if line_idx < self.lines.len() {
self.lines[line_idx].set_dirty();
}
}
/// Clears the dirty flag for a line. The line is relative to the visible origin.
#[inline]
@ -788,6 +790,7 @@ impl TerminalState {
pub fn resize(&mut self, physical_rows: usize, physical_cols: usize) {
self.screen.resize(physical_rows, physical_cols);
self.alt_screen.resize(physical_rows, physical_cols);
self.scroll_region = 0..physical_rows as i64;
}
/// Returns true if any of the visible lines are marked dirty
@ -907,6 +910,145 @@ impl TerminalState {
};
self.set_cursor_pos(&Position::Relative(0), &Position::Absolute(y as i64));
}
fn perform_csi(&mut self, act: CSIAction) {
debug!("{:?}", act);
match act {
CSIAction::SetPen(pen) => {
self.pen = pen;
}
CSIAction::SetForegroundColor(color) => {
self.pen.foreground = color;
}
CSIAction::SetBackgroundColor(color) => {
self.pen.background = color;
}
CSIAction::SetIntensity(level) => {
self.pen.set_intensity(level);
}
CSIAction::SetUnderline(level) => {
self.pen.set_underline(level);
}
CSIAction::SetItalic(on) => {
self.pen.set_italic(on);
}
CSIAction::SetBlink(on) => {
self.pen.set_blink(on);
}
CSIAction::SetReverse(on) => {
self.pen.set_reverse(on);
}
CSIAction::SetStrikethrough(on) => {
self.pen.set_strikethrough(on);
}
CSIAction::SetInvisible(on) => {
self.pen.set_invisible(on);
}
CSIAction::SetCursorXY { x, y } => {
self.set_cursor_pos(&x, &y);
}
CSIAction::EraseInLine(erase) => {
let cx = self.cursor.x;
let cy = self.cursor.y;
let mut screen = self.screen_mut();
let cols = screen.physical_cols;
match erase {
LineErase::ToRight => {
screen.clear_line(cy, cx..cols);
}
LineErase::ToLeft => {
screen.clear_line(cy, 0..cx);
}
LineErase::All => {
screen.clear_line(cy, 0..cols);
}
}
}
CSIAction::EraseInDisplay(erase) => {
let cy = self.cursor.y;
let mut screen = self.screen_mut();
let cols = screen.physical_cols;
let rows = screen.physical_rows as VisibleRowIndex;
match erase {
DisplayErase::Below => {
for y in cy..rows {
screen.clear_line(y, 0..cols);
}
}
DisplayErase::Above => {
for y in 0..cy {
screen.clear_line(y, 0..cols);
}
}
DisplayErase::All => {
for y in 0..rows {
screen.clear_line(y, 0..cols);
}
}
DisplayErase::SavedLines => {
println!("ed: no support for xterm Erase Saved Lines yet");
}
}
}
CSIAction::SetDecPrivateMode(DecPrivateMode::ApplicationCursorKeys, on) => {
self.application_cursor_keys = on;
}
CSIAction::SetDecPrivateMode(DecPrivateMode::BrackedPaste, on) => {
self.bracketed_paste = on;
}
CSIAction::DeviceStatusReport => {
// "OK"
self.push_answerback(b"\x1b[0n");
}
CSIAction::ReportCursorPosition => {
let row = self.cursor.y + 1;
let col = self.cursor.x + 1;
self.push_answerback(format!("\x1b[{};{}R", row, col).as_bytes());
}
CSIAction::SetScrollingRegion { top, bottom } => {
let rows = self.screen().physical_rows;
let mut top = top.min(rows as i64 - 1);
let mut bottom = bottom.min(rows as i64 - 1);
if top > bottom {
std::mem::swap(&mut top, &mut bottom);
}
self.scroll_region = top..bottom + 1;
}
CSIAction::RequestDeviceAttributes => {
self.push_answerback(DEVICE_IDENT);
}
CSIAction::DeleteLines(n) => {
if in_range(self.cursor.y, &self.scroll_region) {
let scroll_region = self.cursor.y..self.scroll_region.end;
self.screen_mut().scroll_up(&scroll_region, n as usize);
}
}
CSIAction::InsertLines(n) => {
if in_range(self.cursor.y, &self.scroll_region) {
let scroll_region = self.cursor.y..self.scroll_region.end;
self.screen_mut().scroll_down(&scroll_region, n as usize);
}
}
CSIAction::SaveCursor => {
self.saved_cursor = self.cursor;
}
CSIAction::RestoreCursor => {
let x = self.saved_cursor.x;
let y = self.saved_cursor.y;
self.set_cursor_pos(&Position::Absolute(x as i64), &Position::Absolute(y));
}
CSIAction::LinePosition(row) => {
self.set_cursor_pos(&Position::Relative(0), &row);
}
CSIAction::ScrollLines(amount) => {
if amount > 0 {
self.scroll_down(amount as usize);
} else {
self.scroll_up((-amount) as usize);
}
}
}
}
}
pub struct Terminal {
@ -1045,142 +1187,7 @@ impl vte::Perform for TerminalState {
}
fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, byte: char) {
for act in CSIParser::new(params, intermediates, ignore, byte) {
debug!("{:?}", act);
match act {
CSIAction::SetPen(pen) => {
self.pen = pen;
}
CSIAction::SetForegroundColor(color) => {
self.pen.foreground = color;
}
CSIAction::SetBackgroundColor(color) => {
self.pen.background = color;
}
CSIAction::SetIntensity(level) => {
self.pen.set_intensity(level);
}
CSIAction::SetUnderline(level) => {
self.pen.set_underline(level);
}
CSIAction::SetItalic(on) => {
self.pen.set_italic(on);
}
CSIAction::SetBlink(on) => {
self.pen.set_blink(on);
}
CSIAction::SetReverse(on) => {
self.pen.set_reverse(on);
}
CSIAction::SetStrikethrough(on) => {
self.pen.set_strikethrough(on);
}
CSIAction::SetInvisible(on) => {
self.pen.set_invisible(on);
}
CSIAction::SetCursorXY { x, y } => {
self.set_cursor_pos(&x, &y);
}
CSIAction::EraseInLine(erase) => {
let cx = self.cursor.x;
let cy = self.cursor.y;
let mut screen = self.screen_mut();
let cols = screen.physical_cols;
match erase {
LineErase::ToRight => {
screen.clear_line(cy, cx..cols);
}
LineErase::ToLeft => {
screen.clear_line(cy, 0..cx);
}
LineErase::All => {
screen.clear_line(cy, 0..cols);
}
}
}
CSIAction::EraseInDisplay(erase) => {
let cy = self.cursor.y;
let mut screen = self.screen_mut();
let cols = screen.physical_cols;
let rows = screen.physical_rows as VisibleRowIndex;
match erase {
DisplayErase::Below => {
for y in cy..rows {
screen.clear_line(y, 0..cols);
}
}
DisplayErase::Above => {
for y in 0..cy {
screen.clear_line(y, 0..cols);
}
}
DisplayErase::All => {
for y in 0..rows {
screen.clear_line(y, 0..cols);
}
}
DisplayErase::SavedLines => {
println!("ed: no support for xterm Erase Saved Lines yet");
}
}
}
CSIAction::SetDecPrivateMode(DecPrivateMode::ApplicationCursorKeys, on) => {
self.application_cursor_keys = on;
}
CSIAction::SetDecPrivateMode(DecPrivateMode::BrackedPaste, on) => {
self.bracketed_paste = on;
}
CSIAction::DeviceStatusReport => {
// "OK"
self.push_answerback(b"\x1b[0n");
}
CSIAction::ReportCursorPosition => {
let row = self.cursor.y + 1;
let col = self.cursor.x + 1;
self.push_answerback(format!("\x1b[{};{}R", row, col).as_bytes());
}
CSIAction::SetScrollingRegion { top, bottom } => {
let rows = self.screen().physical_rows;
let mut top = top.min(rows as i64 - 1);
let mut bottom = bottom.min(rows as i64 - 1);
if top > bottom {
std::mem::swap(&mut top, &mut bottom);
}
self.scroll_region = top..bottom + 1;
}
CSIAction::RequestDeviceAttributes => {
self.push_answerback(DEVICE_IDENT);
}
CSIAction::DeleteLines(n) => {
if in_range(self.cursor.y, &self.scroll_region) {
let scroll_region = self.cursor.y..self.scroll_region.end;
self.screen_mut().scroll_up(&scroll_region, n as usize);
}
}
CSIAction::InsertLines(n) => {
if in_range(self.cursor.y, &self.scroll_region) {
let scroll_region = self.cursor.y..self.scroll_region.end;
self.screen_mut().scroll_down(&scroll_region, n as usize);
}
}
CSIAction::SaveCursor => {
self.saved_cursor = self.cursor;
}
CSIAction::RestoreCursor => {
let x = self.saved_cursor.x;
let y = self.saved_cursor.y;
self.set_cursor_pos(&Position::Absolute(x as i64), &Position::Absolute(y));
}
CSIAction::LinePosition(row) => {
self.set_cursor_pos(&Position::Relative(0), &row);
}
CSIAction::ScrollLines(amount) => {
if amount > 0 {
self.scroll_down(amount as usize);
} else {
self.scroll_up((-amount) as usize);
}
}
}
self.perform_csi(act);
}
}
@ -1215,6 +1222,11 @@ impl vte::Perform for TerminalState {
// Exit alternate character set mode (rmacs)
(b'B', &[b'('], &[]) => {}
// DECSC - Save Cursor
(b'7', &[], &[]) => self.perform_csi(CSIAction::SaveCursor),
// DECRC - Restore Cursor
(b'8', &[], &[]) => self.perform_csi(CSIAction::RestoreCursor),
(..) => {
println!(
"ESC unhandled params={:?}, intermediates={:?} b={:02x} {}",