summaryrefslogtreecommitdiff
path: root/alacritty_terminal/src/term/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty_terminal/src/term/mod.rs')
-rw-r--r--alacritty_terminal/src/term/mod.rs509
1 files changed, 211 insertions, 298 deletions
diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs
index d5759421..bcb4853f 100644
--- a/alacritty_terminal/src/term/mod.rs
+++ b/alacritty_terminal/src/term/mod.rs
@@ -49,6 +49,9 @@ const TITLE_STACK_MAX_DEPTH: usize = 4096;
/// Default tab interval, corresponding to terminfo `it` value.
const INITIAL_TABSTOPS: usize = 8;
+/// Minimum number of columns and lines.
+const MIN_SIZE: usize = 2;
+
/// A type that can expand a given point to a region.
///
/// Usually this is implemented for some 2-D array type since
@@ -290,7 +293,7 @@ impl<'a, C> RenderableCellsIter<'a, C> {
return true;
}
- let num_cols = self.grid.num_cols().0;
+ let num_cols = self.grid.num_cols();
let cell = self.grid[&point];
// Check if wide char's spacers are selected.
@@ -543,86 +546,6 @@ pub mod mode {
pub use crate::term::mode::TermMode;
-trait CharsetMapping {
- fn map(&self, c: char) -> char {
- c
- }
-}
-
-impl CharsetMapping for StandardCharset {
- /// Switch/Map character to the active charset. Ascii is the common case and
- /// for that we want to do as little as possible.
- #[inline]
- fn map(&self, c: char) -> char {
- match *self {
- StandardCharset::Ascii => c,
- StandardCharset::SpecialCharacterAndLineDrawing => match c {
- '`' => '◆',
- 'a' => '▒',
- 'b' => '\t',
- 'c' => '\u{000c}',
- 'd' => '\r',
- 'e' => '\n',
- 'f' => '°',
- 'g' => '±',
- 'h' => '\u{2424}',
- 'i' => '\u{000b}',
- 'j' => '┘',
- 'k' => '┐',
- 'l' => '┌',
- 'm' => '└',
- 'n' => '┼',
- 'o' => '⎺',
- 'p' => '⎻',
- 'q' => '─',
- 'r' => '⎼',
- 's' => '⎽',
- 't' => '├',
- 'u' => '┤',
- 'v' => '┴',
- 'w' => '┬',
- 'x' => '│',
- 'y' => '≤',
- 'z' => '≥',
- '{' => 'π',
- '|' => '≠',
- '}' => '£',
- '~' => '·',
- _ => c,
- },
- }
- }
-}
-
-#[derive(Default, Copy, Clone)]
-struct Charsets([StandardCharset; 4]);
-
-impl Index<CharsetIndex> for Charsets {
- type Output = StandardCharset;
-
- fn index(&self, index: CharsetIndex) -> &StandardCharset {
- &self.0[index as usize]
- }
-}
-
-impl IndexMut<CharsetIndex> for Charsets {
- fn index_mut(&mut self, index: CharsetIndex) -> &mut StandardCharset {
- &mut self.0[index as usize]
- }
-}
-
-#[derive(Default, Copy, Clone)]
-pub struct Cursor {
- /// The location of this cursor.
- pub point: Point,
-
- /// Template cell when using this cursor.
- template: Cell,
-
- /// Currently configured graphic character sets.
- charsets: Charsets,
-}
-
pub struct VisualBell {
/// Visual bell animation.
animation: VisualBellAnimation,
@@ -803,9 +726,20 @@ impl SizeInfo {
}
pub struct Term<T> {
- /// Terminal focus.
+ /// Terminal requires redraw.
+ pub dirty: bool,
+
+ /// Visual bell configuration and status.
+ pub visual_bell: VisualBell,
+
+ /// Terminal focus controlling the cursor shape.
pub is_focused: bool,
+ /// Cursor for keyboard selection.
+ pub vi_mode_cursor: ViModeCursor,
+
+ pub selection: Option<Selection>,
+
/// The grid.
grid: Grid<Cell>,
@@ -822,12 +756,6 @@ pub struct Term<T> {
/// Alt is active.
alt: bool,
- /// The cursor.
- cursor: Cursor,
-
- /// Cursor location for vi mode.
- pub vi_mode_cursor: ViModeCursor,
-
/// Index into `charsets`, pointing to what ASCII is currently being mapped to.
active_charset: CharsetIndex,
@@ -842,16 +770,6 @@ pub struct Term<T> {
/// Range going from top to bottom of the terminal, indexed from the top of the viewport.
scroll_region: Range<Line>,
- pub dirty: bool,
-
- pub visual_bell: VisualBell,
-
- /// Saved cursor from main grid.
- cursor_save: Cursor,
-
- /// Saved cursor from alt grid.
- cursor_save_alt: Cursor,
-
semantic_escape_chars: String,
/// Colors used for rendering.
@@ -893,14 +811,6 @@ pub struct Term<T> {
}
impl<T> Term<T> {
- pub fn selection(&self) -> &Option<Selection> {
- &self.grid.selection
- }
-
- pub fn selection_mut(&mut self) -> &mut Option<Selection> {
- &mut self.grid.selection
- }
-
#[inline]
pub fn scroll_display(&mut self, scroll: Scroll)
where
@@ -938,10 +848,7 @@ impl<T> Term<T> {
alt_grid: alt,
alt: false,
active_charset: Default::default(),
- cursor: Default::default(),
vi_mode_cursor: Default::default(),
- cursor_save: Default::default(),
- cursor_save_alt: Default::default(),
tabs,
mode: Default::default(),
scroll_region,
@@ -959,6 +866,7 @@ impl<T> Term<T> {
title: None,
default_title: config.window.title.clone(),
title_stack: Vec::new(),
+ selection: None,
}
}
@@ -1000,8 +908,8 @@ impl<T> Term<T> {
/// Convert the active selection to a String.
pub fn selection_to_string(&self) -> Option<String> {
- let selection = self.grid.selection.clone()?;
- let SelectionRange { start, end, is_block } = selection.to_range(self)?;
+ let selection_range = self.selection.as_ref().and_then(|s| s.to_range(self))?;
+ let SelectionRange { start, end, is_block } = selection_range;
let mut res = String::new();
@@ -1125,7 +1033,7 @@ impl<T> Term<T> {
/// background color. Cells with an alternate background color are
/// considered renderable as are cells with any text content.
pub fn renderable_cells<'b, C>(&'b self, config: &'b Config<C>) -> RenderableCellsIter<'_, C> {
- let selection = self.grid.selection.as_ref().and_then(|s| s.to_range(self));
+ let selection = self.selection.as_ref().and_then(|s| s.to_range(self));
RenderableCellsIter::new(&self, config, selection)
}
@@ -1134,52 +1042,31 @@ impl<T> Term<T> {
pub fn resize(&mut self, size: &SizeInfo) {
let old_cols = self.grid.num_cols();
let old_lines = self.grid.num_lines();
- let mut num_cols = size.cols();
- let mut num_lines = size.lines();
+ let num_cols = max(size.cols(), Column(MIN_SIZE));
+ let num_lines = max(size.lines(), Line(MIN_SIZE));
if old_cols == num_cols && old_lines == num_lines {
debug!("Term::resize dimensions unchanged");
return;
}
- self.grid.selection = None;
- self.alt_grid.selection = None;
-
- // Should not allow less than 2 cols, causes all sorts of checks to be required.
- if num_cols <= Column(1) {
- num_cols = Column(2);
- }
-
- // Should not allow less than 2 lines, causes all sorts of checks to be required.
- if num_lines <= Line(1) {
- num_lines = Line(2);
- }
-
debug!("New num_cols is {} and num_lines is {}", num_cols, num_lines);
let is_alt = self.mode.contains(TermMode::ALT_SCREEN);
- let alt_cursor_point =
- if is_alt { &mut self.cursor_save.point } else { &mut self.cursor_save_alt.point };
- // Resize grids to new size.
- self.grid.resize(!is_alt, num_lines, num_cols, &mut self.cursor.point, &Cell::default());
- self.alt_grid.resize(is_alt, num_lines, num_cols, alt_cursor_point, &Cell::default());
+ self.grid.resize(!is_alt, num_lines, num_cols);
+ self.alt_grid.resize(is_alt, num_lines, num_cols);
- // Reset scrolling region to new size.
- self.scroll_region = Line(0)..self.grid.num_lines();
-
- // Ensure cursors are in-bounds.
- self.cursor.point.col = min(self.cursor.point.col, num_cols - 1);
- self.cursor.point.line = min(self.cursor.point.line, num_lines - 1);
- self.cursor_save.point.col = min(self.cursor_save.point.col, num_cols - 1);
- self.cursor_save.point.line = min(self.cursor_save.point.line, num_lines - 1);
- self.cursor_save_alt.point.col = min(self.cursor_save_alt.point.col, num_cols - 1);
- self.cursor_save_alt.point.line = min(self.cursor_save_alt.point.line, num_lines - 1);
+ // Clamp vi cursor to viewport.
self.vi_mode_cursor.point.col = min(self.vi_mode_cursor.point.col, num_cols - 1);
self.vi_mode_cursor.point.line = min(self.vi_mode_cursor.point.line, num_lines - 1);
// Recreate tabs list.
self.tabs.resize(self.grid.num_cols());
+
+ // Reset scrolling region and selection.
+ self.scroll_region = Line(0)..self.grid.num_lines();
+ self.selection = None;
}
#[inline]
@@ -1187,20 +1074,16 @@ impl<T> Term<T> {
&self.mode
}
- #[inline]
- pub fn cursor(&self) -> &Cursor {
- &self.cursor
- }
-
pub fn swap_alt(&mut self) {
if self.alt {
- let template = self.cursor.template;
+ let template = self.grid.cursor.template;
self.grid.region_mut(..).each(|c| c.reset(&template));
}
- self.grid.selection = None;
self.alt = !self.alt;
mem::swap(&mut self.grid, &mut self.alt_grid);
+
+ self.selection = None;
}
/// Scroll screen down.
@@ -1210,12 +1093,25 @@ impl<T> Term<T> {
#[inline]
fn scroll_down_relative(&mut self, origin: Line, mut lines: Line) {
trace!("Scrolling down relative: origin={}, lines={}", origin, lines);
+
+ let num_lines = self.grid.num_lines();
+ let num_cols = self.grid.num_cols();
+
lines = min(lines, self.scroll_region.end - self.scroll_region.start);
lines = min(lines, self.scroll_region.end - origin);
+ let region = origin..self.scroll_region.end;
+ let absolute_region = (num_lines - region.end)..(num_lines - region.start);
+
+ // Scroll selection.
+ self.selection = self
+ .selection
+ .take()
+ .and_then(|s| s.rotate(num_lines, num_cols, &absolute_region, -(lines.0 as isize)));
+
// Scroll between origin and bottom
- let template = Cell { bg: self.cursor.template.bg, ..Cell::default() };
- self.grid.scroll_down(&(origin..self.scroll_region.end), lines, &template);
+ let template = Cell { bg: self.grid.cursor.template.bg, ..Cell::default() };
+ self.grid.scroll_down(&region, lines, template);
}
/// Scroll screen up
@@ -1223,13 +1119,25 @@ impl<T> Term<T> {
/// Text moves up; clear at top
/// Expects origin to be in scroll range.
#[inline]
- fn scroll_up_relative(&mut self, origin: Line, lines: Line) {
+ fn scroll_up_relative(&mut self, origin: Line, mut lines: Line) {
trace!("Scrolling up relative: origin={}, lines={}", origin, lines);
- let lines = min(lines, self.scroll_region.end - self.scroll_region.start);
+ let num_lines = self.grid.num_lines();
+ let num_cols = self.grid.num_cols();
+
+ lines = min(lines, self.scroll_region.end - self.scroll_region.start);
+
+ let region = origin..self.scroll_region.end;
+ let absolute_region = (num_lines - region.end)..(num_lines - region.start);
+
+ // Scroll selection.
+ self.selection = self
+ .selection
+ .take()
+ .and_then(|s| s.rotate(num_lines, num_cols, &absolute_region, lines.0 as isize));
// Scroll from origin to bottom less number of lines.
- let template = Cell { bg: self.cursor.template.bg, ..Cell::default() };
- self.grid.scroll_up(&(origin..self.scroll_region.end), lines, &template);
+ let template = Cell { bg: self.grid.cursor.template.bg, ..Cell::default() };
+ self.grid.scroll_up(&region, lines, template);
}
fn deccolm(&mut self)
@@ -1241,7 +1149,7 @@ impl<T> Term<T> {
self.set_scrolling_region(1, self.grid.num_lines().0);
// Clear grid.
- let template = self.cursor.template;
+ let template = self.grid.cursor.template;
self.grid.region_mut(..).each(|c| c.reset(&template));
}
@@ -1267,12 +1175,13 @@ impl<T> Term<T> {
#[inline]
pub fn toggle_vi_mode(&mut self) {
self.mode ^= TermMode::VI;
- self.grid.selection = None;
+ self.selection = None;
// Reset vi mode cursor position to match primary cursor.
if self.mode.contains(TermMode::VI) {
- let line = min(self.cursor.point.line + self.grid.display_offset(), self.lines() - 1);
- self.vi_mode_cursor = ViModeCursor::new(Point::new(line, self.cursor.point.col));
+ let cursor = self.grid.cursor.point;
+ let line = min(cursor.line + self.grid.display_offset(), self.lines() - 1);
+ self.vi_mode_cursor = ViModeCursor::new(Point::new(line, cursor.col));
}
self.dirty = true;
@@ -1294,8 +1203,8 @@ impl<T> Term<T> {
// Update selection if one is active.
let viewport_point = self.visible_to_buffer(self.vi_mode_cursor.point);
- if let Some(selection) = &mut self.grid.selection {
- // Do not extend empty selections started by single mouse click.
+ if let Some(selection) = &mut self.selection {
+ // Do not extend empty selections started by a single mouse click.
if !selection.is_empty() {
selection.update(viewport_point, Side::Left);
selection.include_all();
@@ -1322,15 +1231,15 @@ impl<T> Term<T> {
trace!("Wrapping input");
- self.grid[&self.cursor.point].flags.insert(Flags::WRAPLINE);
+ self.grid.cursor_cell().flags.insert(Flags::WRAPLINE);
- if (self.cursor.point.line + 1) >= self.scroll_region.end {
+ if (self.grid.cursor.point.line + 1) >= self.scroll_region.end {
self.linefeed();
} else {
- self.cursor.point.line += 1;
+ self.grid.cursor.point.line += 1;
}
- self.cursor.point.col = Column(0);
+ self.grid.cursor.point.col = Column(0);
self.input_needs_wrap = false;
}
@@ -1340,10 +1249,13 @@ impl<T> Term<T> {
where
T: EventListener,
{
- let cell = &mut self.grid[&self.cursor.point];
- *cell = self.cursor.template;
- cell.c = self.cursor.charsets[self.active_charset].map(c);
- cell
+ let mut cell = self.grid.cursor.template;
+ cell.c = self.grid.cursor.charsets[self.active_charset].map(c);
+
+ let cursor_cell = self.grid.cursor_cell();
+ *cursor_cell = cell;
+
+ cursor_cell
}
/// Get rendering information about the active cursor.
@@ -1354,7 +1266,7 @@ impl<T> Term<T> {
let mut point = if vi_mode {
self.vi_mode_cursor.point
} else {
- let mut point = self.cursor.point;
+ let mut point = self.grid.cursor.point;
point.line += self.grid.display_offset();
point
};
@@ -1430,8 +1342,8 @@ impl<T: EventListener> Handler for Term<T> {
// Handle zero-width characters.
if width == 0 {
- let mut col = self.cursor.point.col.0.saturating_sub(1);
- let line = self.cursor.point.line;
+ let mut col = self.grid.cursor.point.col.0.saturating_sub(1);
+ let line = self.grid.cursor.point.line;
if self.grid[line][Column(col)].flags.contains(Flags::WIDE_CHAR_SPACER) {
col = col.saturating_sub(1);
}
@@ -1447,9 +1359,9 @@ impl<T: EventListener> Handler for Term<T> {
let num_cols = self.grid.num_cols();
// If in insert mode, first shift cells to the right.
- if self.mode.contains(TermMode::INSERT) && self.cursor.point.col + width < num_cols {
- let line = self.cursor.point.line;
- let col = self.cursor.point.col;
+ if self.mode.contains(TermMode::INSERT) && self.grid.cursor.point.col + width < num_cols {
+ let line = self.grid.cursor.point.line;
+ let col = self.grid.cursor.point.col;
let line = &mut self.grid[line];
let src = line[col..].as_ptr();
@@ -1462,7 +1374,7 @@ impl<T: EventListener> Handler for Term<T> {
if width == 1 {
self.write_at_cursor(c);
} else {
- if self.cursor.point.col + 1 >= num_cols {
+ if self.grid.cursor.point.col + 1 >= num_cols {
if self.mode.contains(TermMode::LINE_WRAP) {
// Insert placeholder before wide char if glyph does not fit in this row.
self.write_at_cursor(' ').flags.insert(Flags::WIDE_CHAR_SPACER);
@@ -1478,12 +1390,12 @@ impl<T: EventListener> Handler for Term<T> {
self.write_at_cursor(c).flags.insert(Flags::WIDE_CHAR);
// Write spacer to cell following the wide glyph.
- self.cursor.point.col += 1;
+ self.grid.cursor.point.col += 1;
self.write_at_cursor(' ').flags.insert(Flags::WIDE_CHAR_SPACER);
}
- if self.cursor.point.col + 1 < num_cols {
- self.cursor.point.col += 1;
+ if self.grid.cursor.point.col + 1 < num_cols {
+ self.grid.cursor.point.col += 1;
} else {
self.input_needs_wrap = true;
}
@@ -1506,34 +1418,35 @@ impl<T: EventListener> Handler for Term<T> {
(Line(0), self.grid.num_lines() - 1)
};
- self.cursor.point.line = min(line + y_offset, max_y);
- self.cursor.point.col = min(col, self.grid.num_cols() - 1);
+ self.grid.cursor.point.line = min(line + y_offset, max_y);
+ self.grid.cursor.point.col = min(col, self.grid.num_cols() - 1);
self.input_needs_wrap = false;
}
#[inline]
fn goto_line(&mut self, line: Line) {
trace!("Going to line: {}", line);
- self.goto(line, self.cursor.point.col)
+ self.goto(line, self.grid.cursor.point.col)
}
#[inline]
fn goto_col(&mut self, col: Column) {
trace!("Going to column: {}", col);
- self.goto(self.cursor.point.line, col)
+ self.goto(self.grid.cursor.point.line, col)
}
#[inline]
fn insert_blank(&mut self, count: Column) {
- // Ensure inserting within terminal bounds.
+ let cursor = self.grid.cursor;
- let count = min(count, self.grid.num_cols() - self.cursor.point.col);
+ // Ensure inserting within terminal bounds
+ let count = min(count, self.grid.num_cols() - cursor.point.col);
- let source = self.cursor.point.col;
- let destination = self.cursor.point.col + count;
+ let source = cursor.point.col;
+ let destination = cursor.point.col + count;
let num_cells = (self.grid.num_cols() - destination).0;
- let line = &mut self.grid[self.cursor.point.line];
+ let line = &mut self.grid[cursor.point.line];
unsafe {
let src = line[source..].as_ptr();
@@ -1545,35 +1458,36 @@ impl<T: EventListener> Handler for Term<T> {
// Cells were just moved out towards the end of the line; fill in
// between source and dest with blanks.
for c in &mut line[source..destination] {
- c.reset(&self.cursor.template);
+ c.reset(&cursor.template);
}
}
#[inline]
fn move_up(&mut self, lines: Line) {
trace!("Moving up: {}", lines);
- let move_to = Line(self.cursor.point.line.0.saturating_sub(lines.0));
- self.goto(move_to, self.cursor.point.col)
+ let move_to = Line(self.grid.cursor.point.line.0.saturating_sub(lines.0));
+ self.goto(move_to, self.grid.cursor.point.col)
}
#[inline]
fn move_down(&mut self, lines: Line) {
trace!("Moving down: {}", lines);
- let move_to = self.cursor.point.line + lines;
- self.goto(move_to, self.cursor.point.col)
+ let move_to = self.grid.cursor.point.line + lines;
+ self.goto(move_to, self.grid.cursor.point.col)
}
#[inline]
fn move_forward(&mut self, cols: Column) {
trace!("Moving forward: {}", cols);
- self.cursor.point.col = min(self.cursor.point.col + cols, self.grid.num_cols() - 1);
+ let num_cols = self.grid.num_cols();
+ self.grid.cursor.point.col = min(self.grid.cursor.point.col + cols, num_cols - 1);
self.input_needs_wrap = false;
}
#[inline]
fn move_backward(&mut self, cols: Column) {
trace!("Moving backward: {}", cols);
- self.cursor.point.col -= min(self.cursor.point.col, cols);
+ self.grid.cursor.point.col = Column(self.grid.cursor.point.col.saturating_sub(cols.0));
self.input_needs_wrap = false;
}
@@ -1591,7 +1505,7 @@ impl<T: EventListener> Handler for Term<T> {
let _ = writer.write_all(b"\x1b[0n");
},
6 => {
- let pos = self.cursor.point;
+ let pos = self.grid.cursor.point;
let response = format!("\x1b[{};{}R", pos.line + 1, pos.col + 1);
let _ = writer.write_all(response.as_bytes());
},
@@ -1602,14 +1516,14 @@ impl<T: EventListener> Handler for Term<T> {
#[inline]
fn move_down_and_cr(&mut self, lines: Line) {
trace!("Moving down and cr: {}", lines);
- let move_to = self.cursor.point.line + lines;
+ let move_to = self.grid.cursor.point.line + lines;
self.goto(move_to, Column(0))
}
#[inline]
fn move_up_and_cr(&mut self, lines: Line) {
trace!("Moving up and cr: {}", lines);
- let move_to = Line(self.cursor.point.line.0.saturating_sub(lines.0));
+ let move_to = Line(self.grid.cursor.point.line.0.saturating_sub(lines.0));
self.goto(move_to, Column(0))
}
@@ -1622,22 +1536,23 @@ impl<T: EventListener> Handler for Term<T> {
return;
}
- while self.cursor.point.col < self.grid.num_cols() && count != 0 {
+ while self.grid.cursor.point.col < self.grid.num_cols() && count != 0 {
count -= 1;
- let cell = &mut self.grid[&self.cursor.point];
+ let c = self.grid.cursor.charsets[self.active_charset].map('\t');
+ let cell = self.grid.cursor_cell();
if cell.c == ' ' {
- cell.c = self.cursor.charsets[self.active_charset].map('\t');
+ cell.c = c;
}
loop {
- if (self.cursor.point.col + 1) == self.grid.num_cols() {
+ if (self.grid.cursor.point.col + 1) == self.grid.num_cols() {
break;
}
- self.cursor.point.col += 1;
+ self.grid.cursor.point.col += 1;
- if self.tabs[self.cursor.point.col] {
+ if self.tabs[self.grid.cursor.point.col] {
break;
}
}
@@ -1648,8 +1563,9 @@ impl<T: EventListener> Handler for Term<T> {
#[inline]
fn backspace(&mut self) {
trace!("Backspace");
- if self.cursor.point.col > Column(0) {
- self.cursor.point.col -= 1;
+
+ if self.grid.cursor.point.col > Column(0) {
+ self.grid.cursor.point.col -= 1;
self.input_needs_wrap = false;
}
}
@@ -1658,7 +1574,7 @@ impl<T: EventListener> Handler for Term<T> {
#[inline]
fn carriage_return(&mut self) {
trace!("Carriage return");
- self.cursor.point.col = Column(0);
+ self.grid.cursor.point.col = Column(0);
self.input_needs_wrap = false;
}
@@ -1666,11 +1582,11 @@ impl<T: EventListener> Handler for Term<T> {
#[inline]
fn linefeed(&mut self) {
trace!("Linefeed");
- let next = self.cursor.point.line + 1;
+ let next = self.grid.cursor.point.line + 1;
if next == self.scroll_region.end {
self.scroll_up(Line(1));
} else if next < self.grid.num_lines() {
- self.cursor.point.line += 1;
+ self.grid.cursor.point.line += 1;
}
}
@@ -1721,8 +1637,7 @@ impl<T: EventListener> Handler for Term<T> {
#[inline]
fn set_horizontal_tabstop(&mut self) {
trace!("Setting horizontal tabstop");
- let column = self.cursor.point.col;
- self.tabs[column] = true;
+ self.tabs[self.grid.cursor.point.col] = true;
}
#[inline]
@@ -1740,49 +1655,54 @@ impl<T: EventListener> Handler for Term<T> {
#[inline]
fn insert_blank_lines(&mut self, lines: Line) {
trace!("Inserting blank {} lines", lines);
- if self.scroll_region.contains(&self.cursor.point.line) {
- let origin = self.cursor.point.line;
+
+ let origin = self.grid.cursor.point.line;
+ if self.scroll_region.contains(&origin) {
self.scroll_down_relative(origin, lines);
}
}
#[inline]
fn delete_lines(&mut self, lines: Line) {
- let origin = self.cursor.point.line;
+ let origin = self.grid.cursor.point.line;
let lines = min(self.lines() - origin, lines);
trace!("Deleting {} lines", lines);
- if lines.0 > 0 && self.scroll_region.contains(&self.cursor.point.line) {
+ if lines.0 > 0 && self.scroll_region.contains(&self.grid.cursor.point.line) {
self.scroll_up_relative(origin, lines);
}
}
#[inline]
fn erase_chars(&mut self, count: Column) {
- trace!("Erasing chars: count={}, col={}", count, self.cursor.point.col);
- let start = self.cursor.point.col;
+ let cursor = self.grid.cursor;
+
+ trace!("Erasing chars: count={}, col={}", count, cursor.point.col);
+
+ let start = cursor.point.col;
let end = min(start + count, self.grid.num_cols());
- let row = &mut self.grid[self.cursor.point.line];
// Cleared cells have current background color set.
+ let row = &mut self.grid[cursor.point.line];
for c in &mut row[start..end] {
- c.reset(&self.cursor.template);
+ c.reset(&cursor.template);
}
}
#[inline]
fn delete_chars(&mut self, count: Column) {
let cols = self.grid.num_cols();
+ let cursor = self.grid.cursor;
// Ensure deleting within terminal bounds.
let count = min(count, cols);
- let start = self.cursor.point.col;
+ let start = cursor.point.col;
let end = min(start + count, cols - 1);
let n = (cols - end).0;
- let line = &mut self.grid[self.cursor.point.line];
+ let line = &mut self.grid[cursor.point.line];
unsafe {
let src = line[end..].as_ptr();
@@ -1795,7 +1715,7 @@ impl<T: EventListener> Handler for Term<T> {
// 1 cell.
let end = cols - count;
for c in &mut line[end..] {
- c.reset(&self.cursor.template);
+ c.reset(&cursor.template);
}
}
@@ -1804,14 +1724,14 @@ impl<T: EventListener> Handler for Term<T> {
trace!("Moving backward {} tabs", count);
for _ in 0..count {
- let mut col = self.cursor.point.col;
+ let mut col = self.grid.cursor.point.col;
for i in (0..(col.0)).rev() {
if self.tabs[index::Column(i)] {
col = index::Column(i);
break;
}
}
- self.cursor.point.col = col;
+ self.grid.cursor.point.col = col;
}
}
@@ -1823,44 +1743,39 @@ impl<T: EventListener> Handler for Term<T> {
#[inline]
fn save_cursor_position(&mut self) {
trace!("Saving cursor position");
- let cursor = if self.alt { &mut self.cursor_save_alt } else { &mut self.cursor_save };
- *cursor = self.cursor;
+ self.grid.saved_cursor = self.grid.cursor;
}
#[inline]
fn restore_cursor_position(&mut self) {
trace!("Restoring cursor position");
- let source = if self.alt { &self.cursor_save_alt } else { &self.cursor_save };
- self.cursor = *source;
- self.cursor.point.line = min(self.cursor.point.line, self.grid.num_lines() - 1);
- self.cursor.point.col = min(self.cursor.point.col, self.grid.num_cols() - 1);
+ self.grid.cursor = self.grid.saved_cursor;
}
#[inline]
fn clear_line(&mut self, mode: ansi::LineClearMode) {
trace!("Clearing line: {:?}", mode);
- let col = self.cursor.point.col;
-
+ let cursor = self.grid.cursor;
match mode {
ansi::LineClearMode::Right => {
- let row = &mut self.grid[self.cursor.point.line];
- for cell in &mut row[col..] {
- cell.reset(&self.cursor.template);
+ let row = &mut self.grid[cursor.point.line];
+ for cell in &mut row[cursor.point.col..] {
+ cell.reset(&cursor.template);
}
},
ansi::LineClearMode::Left => {
- let row = &mut self.grid[self.cursor.point.line];
- for cell in &mut row[..=col] {
- cell.reset(&self.cursor.template);
+ let row = &mut self.grid[cursor.point.line];
+ for cell in &mut row[..=cursor.point.col] {
+ cell.reset(&cursor.template);
}
},
ansi::LineClearMode::All => {
- let row = &mut self.grid[self.cursor.point.line];
+ let row = &mut self.grid[cursor.point.line];
for cell in &mut row[..] {
- cell.reset(&self.cursor.template);
+ cell.reset(&cursor.template);
}
},
}
@@ -1934,34 +1849,34 @@ impl<T: EventListener> Handler for Term<T> {
#[inline]
fn clear_screen(&mut self, mode: ansi::ClearMode) {
trace!("Clearing screen: {:?}", mode);
- let template = self.cursor.template;
+ let template = self.grid.cursor.template;
// Remove active selections.
- self.grid.selection = None;
+ self.selection = None;
match mode {
ansi::ClearMode::Above => {
+ let cursor = self.grid.cursor.point;
+
// If clearing more than one line.
- if self.cursor.point.line > Line(1) {
+ if cursor.line > Line(1) {
// Fully clear all lines before the current line.
- self.grid
- .region_mut(..self.cursor.point.line)
- .each(|cell| cell.reset(&template));
+ self.grid.region_mut(..cursor.line).each(|cell| cell.reset(&template));
}
+
// Clear up to the current column in the current line.
- let end = min(self.cursor.point.col + 1, self.grid.num_cols());
- for cell in &mut self.grid[self.cursor.point.line][..end] {
+ let end = min(cursor.col + 1, self.grid.num_cols());
+ for cell in &mut self.grid[cursor.line][..end] {
cell.reset(&template);
}
},
ansi::ClearMode::Below => {
- for cell in &mut self.grid[self.cursor.point.line][self.cursor.point.col..] {
+ let cursor = self.grid.cursor.point;
+ for cell in &mut self.grid[cursor.line][cursor.col..] {
cell.reset(&template);
}
- if self.cursor.point.line < self.grid.num_lines() - 1 {
- self.grid
- .region_mut((self.cursor.point.line + 1)..)
- .each(|cell| cell.reset(&template));
+ if cursor.line < self.grid.num_lines() - 1 {
+ self.grid.region_mut((cursor.line + 1)..).each(|cell| cell.reset(&template));
}
},
ansi::ClearMode::All => {
@@ -1969,7 +1884,7 @@ impl<T: EventListener> Handler for Term<T> {
self.grid.region_mut(..).each(|c| c.reset(&template));
} else {
let template = Cell { bg: template.bg, ..Cell::default() };
- self.grid.clear_viewport(&template);
+ self.grid.clear_viewport(template);
}
},
ansi::ClearMode::Saved => self.grid.clear_history(),
@@ -1981,8 +1896,7 @@ impl<T: EventListener> Handler for Term<T> {
trace!("Clearing tabs: {:?}", mode);
match mode {
ansi::TabulationClearMode::Current => {
- let column = self.cursor.point.col;
- self.tabs[column] = false;
+ self.tabs[self.grid.cursor.point.col] = false;
},
ansi::TabulationClearMode::All => {
self.tabs.clear_all();
@@ -1997,30 +1911,28 @@ impl<T: EventListener> Handler for Term<T> {
self.swap_alt();
}
self.input_needs_wrap = false;
- self.cursor = Default::default();
self.active_charset = Default::default();
self.mode = Default::default();
- self.cursor_save = Default::default();
- self.cursor_save_alt = Default::default();
self.colors = self.original_colors;
self.color_modified = [false; color::COUNT];
self.cursor_style = None;
- self.grid.reset(&Cell::default());
- self.alt_grid.reset(&Cell::default());
+ self.grid.reset(Cell::default());
+ self.alt_grid.reset(Cell::default());
self.scroll_region = Line(0)..self.grid.num_lines();
self.tabs = TabStops::new(self.grid.num_cols());
self.title_stack = Vec::new();
self.title = None;
+ self.selection = None;
}
#[inline]
fn reverse_index(&mut self) {
trace!("Reversing index");
- // If cursor is at the top.
- if self.cursor.point.line == self.scroll_region.start {
+
+ if self.grid.cursor.point.line == self.scroll_region.start {
self.scroll_down(Line(1));
} else {
- self.cursor.point.line -= min(self.cursor.point.line, Line(1));
+ self.grid.cursor.point.line = Line(self.grid.cursor.point.line.saturating_sub(1));
}
}
@@ -2028,28 +1940,29 @@ impl<T: EventListener> Handler for Term<T> {
#[inline]
fn terminal_attribute(&mut self, attr: Attr) {
trace!("Setting attribute: {:?}", attr);
+ let cursor = &mut self.grid.cursor;
match attr {
- Attr::Foreground(color) => self.cursor.template.fg = color,
- Attr::Background(color) => self.cursor.template.bg = color,
+ Attr::Foreground(color) => cursor.template.fg = color,
+ Attr::Background(color) => cursor.template.bg = color,
Attr::Reset => {
- self.cursor.template.fg = Color::Named(NamedColor::Foreground);
- self.cursor.template.bg = Color::Named(NamedColor::Background);
- self.cursor.template.flags = Flags::empty();
+ cursor.template.fg = Color::Named(NamedColor::Foreground);
+ cursor.template.bg = Color::Named(NamedColor::Background);
+ cursor.template.flags = Flags::empty();
},
- Attr::Reverse => self.cursor.template.flags.insert(Flags::INVERSE),
- Attr::CancelReverse => self.cursor.template.flags.remove(Flags::INVERSE),
- Attr::Bold => self.cursor.template.flags.insert(Flags::BOLD),
- Attr::CancelBold => self.cursor.template.flags.remove(Flags::BOLD),
- Attr::Dim => self.cursor.template.flags.insert(Flags::DIM),
- Attr::CancelBoldDim => self.cursor.template.flags.remove(Flags::BOLD | Flags::DIM),
- Attr::Italic => self.cursor.template.flags.insert(Flags::ITALIC),
- Attr::CancelItalic => self.cursor.template.flags.remove(Flags::ITALIC),
- Attr::Underline => self.cursor.template.flags.insert(Flags::UNDERLINE),
- Attr::CancelUnderline => self.cursor.template.flags.remove(Flags::UNDERLINE),
- Attr::Hidden => self.cursor.template.flags.insert(Flags::HIDDEN),
- Attr::CancelHidden => self.cursor.template.flags.remove(Flags::HIDDEN),
- Attr::Strike => self.cursor.template.flags.insert(Flags::STRIKEOUT),
- Attr::CancelStrike => self.cursor.template.flags.remove(Flags::STRIKEOUT),
+ Attr::Reverse => cursor.template.flags.insert(Flags::INVERSE),
+ Attr::CancelReverse => cursor.template.flags.remove(Flags::INVERSE),
+ Attr::Bold => cursor.template.flags.insert(Flags::BOLD),
+ Attr::CancelBold => cursor.template.flags.remove(Flags::BOLD),
+ Attr::Dim => cursor.template.flags.insert(Flags::DIM),
+ Attr::CancelBoldDim => cursor.template.flags.remove(Flags::BOLD | Flags::DIM),
+ Attr::Italic => cursor.template.flags.insert(Flags::ITALIC),
+ Attr::CancelItalic => cursor.template.flags.remove(Flags::ITALIC),
+ Attr::Underline => cursor.template.flags.insert(Flags::UNDERLINE),
+ Attr::CancelUnderline => cursor.template.flags.remove(Flags::UNDERLINE),
+ Attr::Hidden => cursor.template.flags.insert(Flags::HIDDEN),
+ Attr::CancelHidden => cursor.template.flags.remove(Flags::HIDDEN),
+ Attr::Strike => cursor.template.flags.insert(Flags::STRIKEOUT),
+ Attr::CancelStrike => cursor.template.flags.remove(Flags::STRIKEOUT),
_ => {
debug!("Term got unhandled attr: {:?}", attr);
},
@@ -2187,7 +2100,7 @@ impl<T: EventListener> Handler for Term<T> {
#[inline]
fn configure_charset(&mut self, index: CharsetIndex, charset: StandardCharset) {
trace!("Configuring charset {:?} as {:?}", index, charset);
- self.cursor.charsets[index] = charset;
+ self.grid.cursor.charsets[index] = charset;
}
#[inline]
@@ -2337,7 +2250,7 @@ mod tests {
mem::swap(&mut term.semantic_escape_chars, &mut escape_chars);
{
- *term.selection_mut() = Some(Selection::new(
+ term.selection = Some(Selection::new(
SelectionType::Semantic,
Point { line: 2, col: Column(1) },
Side::Left,
@@ -2346,7 +2259,7 @@ mod tests {
}
{
- *term.selection_mut() = Some(Selection::new(
+ term.selection = Some(Selection::new(
SelectionType::Semantic,
Point { line: 2, col: Column(4) },
Side::Left,
@@ -2355,7 +2268,7 @@ mod tests {
}
{
- *term.selection_mut() = Some(Selection::new(
+ term.selection = Some(Selection::new(
SelectionType::Semantic,
Point { line: 1, col: Column(1) },
Side::Left,
@@ -2385,7 +2298,7 @@ mod tests {
mem::swap(&mut term.grid, &mut grid);
- *term.selection_mut() = Some(Selection::new(
+ term.selection = Some(Selection::new(
SelectionType::Lines,
Point { line: 0, col: Column(3) },
Side::Left,
@@ -2419,7 +2332,7 @@ mod tests {
let mut selection =
Selection::new(SelectionType::Simple, Point { line: 2, col: Column(0) }, Side::Left);
selection.update(Point { line: 0, col: Column(2) }, Side::Right);
- *term.selection_mut() = Some(selection);
+ term.selection = Some(selection);
assert_eq!(term.selection_to_string(), Some("aaa\n\naaa\n".into()));
}
@@ -2471,7 +2384,7 @@ mod tests {
let mut term = Term::new(&MockConfig::default(), &size, Clipboard::new_nop(), Mock);
// Add one line of scrollback.
- term.grid.scroll_up(&(Line(0)..Line(1)), Line(1), &Cell::default());
+ term.grid.scroll_up(&(Line(0)..Line(1)), Line(1), Cell::default());
// Clear the history.
term.clear_screen(ansi::ClearMode::Saved);
@@ -2505,14 +2418,14 @@ mod tests {
term.newline();
}
assert_eq!(term.grid.history_size(), 10);
- assert_eq!(term.cursor.point, Point::new(Line(9), Column(0)));
+ assert_eq!(term.grid.cursor.point, Point::new(Line(9), Column(0)));
// Increase visible lines.
size.height = 30.;
term.resize(&size);
assert_eq!(term.grid.history_size(), 0);
- assert_eq!(term.cursor.point, Point::new(Line(19), Column(0)));
+ assert_eq!(term.grid.cursor.point, Point::new(Line(19), Column(0)));
}
#[test]
@@ -2533,7 +2446,7 @@ mod tests {
term.newline();
}
assert_eq!(term.grid.history_size(), 10);
- assert_eq!(term.cursor.point, Point::new(Line(9), Column(0)));
+ assert_eq!(term.grid.cursor.point, Point::new(Line(9), Column(0)));
// Enter alt screen.
term.set_mode(ansi::Mode::SwapScreenAndSetRestoreCursor);
@@ -2546,7 +2459,7 @@ mod tests {
term.unset_mode(ansi::Mode::SwapScreenAndSetRestoreCursor);
assert_eq!(term.grid().history_size(), 0);
- assert_eq!(term.cursor.point, Point::new(Line(19), Column(0)));
+ assert_eq!(term.grid.cursor.point, Point::new(Line(19), Column(0)));
}
#[test]
@@ -2567,14 +2480,14 @@ mod tests {
term.newline();
}
assert_eq!(term.grid.history_size(), 10);
- assert_eq!(term.cursor.point, Point::new(Line(9), Column(0)));
+ assert_eq!(term.grid.cursor.point, Point::new(Line(9), Column(0)));
// Increase visible lines.
size.height = 5.;
term.resize(&size);
assert_eq!(term.grid().history_size(), 15);
- assert_eq!(term.cursor.point, Point::new(Line(4), Column(0)));
+ assert_eq!(term.grid.cursor.point, Point::new(Line(4), Column(0)));
}
#[test]
@@ -2595,7 +2508,7 @@ mod tests {
term.newline();
}
assert_eq!(term.grid.history_size(), 10);
- assert_eq!(term.cursor.point, Point::new(Line(9), Column(0)));
+ assert_eq!(term.grid.cursor.point, Point::new(Line(9), Column(0)));
// Enter alt screen.
term.set_mode(ansi::Mode::SwapScreenAndSetRestoreCursor);
@@ -2608,7 +2521,7 @@ mod tests {
term.unset_mode(ansi::Mode::SwapScreenAndSetRestoreCursor);
assert_eq!(term.grid().history_size(), 15);
- assert_eq!(term.cursor.point, Point::new(Line(4), Column(0)));
+ assert_eq!(term.grid.cursor.point, Point::new(Line(4), Column(0)));
}
#[test]