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.rs216
1 files changed, 115 insertions, 101 deletions
diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs
index 6084d8b0..6e20f0e1 100644
--- a/alacritty_terminal/src/term/mod.rs
+++ b/alacritty_terminal/src/term/mod.rs
@@ -136,12 +136,44 @@ pub struct RenderableCellsIter<'a, C> {
inner: DisplayIter<'a, Cell>,
grid: &'a Grid<Cell>,
cursor: RenderableCursor,
+ show_cursor: bool,
config: &'a Config<C>,
colors: &'a color::List,
selection: Option<SelectionRange<Line>>,
search: RenderableSearch<'a>,
}
+impl<'a, C> Iterator for RenderableCellsIter<'a, C> {
+ type Item = RenderableCell;
+
+ /// Gets the next renderable cell.
+ ///
+ /// Skips empty (background) cells and applies any flags to the cell state
+ /// (eg. invert fg and bg colors).
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ loop {
+ if self.show_cursor && self.cursor.point == self.inner.point() {
+ // Handle cursor rendering.
+ if self.cursor.rendered {
+ return self.next_cursor_cell();
+ } else {
+ return self.next_cursor();
+ }
+ } else {
+ // Handle non-cursor cells.
+ let cell = self.inner.next()?;
+ let cell = RenderableCell::new(self, cell);
+
+ // Skip empty cells.
+ if !cell.is_empty() {
+ return Some(cell);
+ }
+ }
+ }
+ }
+}
+
impl<'a, C> RenderableCellsIter<'a, C> {
/// Create the renderable cells iterator.
///
@@ -150,44 +182,63 @@ impl<'a, C> RenderableCellsIter<'a, C> {
fn new<T>(
term: &'a Term<T>,
config: &'a Config<C>,
- selection: Option<SelectionRange>,
+ show_cursor: bool,
) -> RenderableCellsIter<'a, C> {
- let grid = &term.grid;
+ RenderableCellsIter {
+ cursor: term.renderable_cursor(config),
+ show_cursor,
+ grid: &term.grid,
+ inner: term.grid.display_iter(),
+ selection: term.visible_selection(),
+ config,
+ colors: &term.colors,
+ search: RenderableSearch::new(term),
+ }
+ }
- let selection_range = selection.and_then(|span| {
- let (limit_start, limit_end) = if span.is_block {
- (span.start.col, span.end.col)
- } else {
- (Column(0), grid.cols() - 1)
+ /// Get the next renderable cell as the cell below the cursor.
+ fn next_cursor_cell(&mut self) -> Option<RenderableCell> {
+ // Handle cell below cursor.
+ let cell = self.inner.next()?;
+ let mut cell = RenderableCell::new(self, cell);
+
+ if self.cursor.key.style == CursorStyle::Block {
+ cell.fg = match self.cursor.cursor_color {
+ // Apply cursor color, or invert the cursor if it has a fixed background
+ // close to the cell's background.
+ CellRgb::Rgb(col) if col.contrast(cell.bg) < MIN_CURSOR_CONTRAST => cell.bg,
+ _ => self.cursor.text_color.color(cell.fg, cell.bg),
};
+ }
- // Do not render completely offscreen selection.
- let viewport_end = grid.display_offset();
- let viewport_start = viewport_end + grid.screen_lines().0 - 1;
- if span.end.line > viewport_start || span.start.line < viewport_end {
- return None;
- }
+ Some(cell)
+ }
- // Get on-screen lines of the selection's locations.
- let mut start = grid.clamp_buffer_to_visible(span.start);
- let mut end = grid.clamp_buffer_to_visible(span.end);
+ /// Get the next renderable cell as the cursor.
+ fn next_cursor(&mut self) -> Option<RenderableCell> {
+ // Handle cursor.
+ self.cursor.rendered = true;
- // Trim start/end with partially visible block selection.
- start.col = max(limit_start, start.col);
- end.col = min(limit_end, end.col);
+ let buffer_point = self.grid.visible_to_buffer(self.cursor.point);
+ let cell = Indexed {
+ inner: &self.grid[buffer_point.line][buffer_point.col],
+ column: self.cursor.point.col,
+ line: self.cursor.point.line,
+ };
- Some(SelectionRange::new(start, end, span.is_block))
- });
+ let mut cell = RenderableCell::new(self, cell);
+ cell.inner = RenderableCellContent::Cursor(self.cursor.key);
- RenderableCellsIter {
- cursor: term.renderable_cursor(config),
- grid,
- inner: grid.display_iter(),
- selection: selection_range,
- config,
- colors: &term.colors,
- search: RenderableSearch::new(term),
+ // Apply cursor color, or invert the cursor if it has a fixed background close
+ // to the cell's background.
+ if !matches!(
+ self.cursor.cursor_color,
+ CellRgb::Rgb(color) if color.contrast(cell.bg) < MIN_CURSOR_CONTRAST
+ ) {
+ cell.fg = self.cursor.cursor_color.color(cell.fg, cell.bg);
}
+
+ Some(cell)
}
/// Check selection state of a cell.
@@ -265,6 +316,7 @@ pub struct RenderableCell {
pub bg: Rgb,
pub bg_alpha: f32,
pub flags: Flags,
+ pub is_match: bool,
}
impl RenderableCell {
@@ -282,9 +334,11 @@ impl RenderableCell {
Self::compute_bg_alpha(cell.bg)
};
+ let mut is_match = false;
+
if iter.is_selected(point) {
let config_bg = iter.config.colors.selection.background();
- let selected_fg = iter.config.colors.selection.text().color(fg_rgb, bg_rgb);
+ let selected_fg = iter.config.colors.selection.foreground().color(fg_rgb, bg_rgb);
bg_rgb = config_bg.color(fg_rgb, bg_rgb);
fg_rgb = selected_fg;
@@ -306,6 +360,8 @@ impl RenderableCell {
if config_bg != CellRgb::CellBackground {
bg_alpha = 1.0;
}
+
+ is_match = true;
}
let zerowidth = cell.zerowidth().map(|zerowidth| zerowidth.to_vec());
@@ -318,6 +374,7 @@ impl RenderableCell {
bg: bg_rgb,
bg_alpha,
flags: cell.flags,
+ is_match,
}
}
@@ -391,73 +448,6 @@ impl RenderableCell {
}
}
-impl<'a, C> Iterator for RenderableCellsIter<'a, C> {
- type Item = RenderableCell;
-
- /// Gets the next renderable cell.
- ///
- /// Skips empty (background) cells and applies any flags to the cell state
- /// (eg. invert fg and bg colors).
- #[inline]
- fn next(&mut self) -> Option<Self::Item> {
- loop {
- if self.cursor.point.line == self.inner.line()
- && self.cursor.point.col == self.inner.column()
- {
- if self.cursor.rendered {
- // Handle cell below cursor.
- let cell = self.inner.next()?;
- let mut cell = RenderableCell::new(self, cell);
-
- if self.cursor.key.style == CursorStyle::Block {
- cell.fg = match self.cursor.cursor_color {
- // Apply cursor color, or invert the cursor if it has a fixed background
- // close to the cell's background.
- CellRgb::Rgb(col) if col.contrast(cell.bg) < MIN_CURSOR_CONTRAST => {
- cell.bg
- },
- _ => self.cursor.text_color.color(cell.fg, cell.bg),
- };
- }
-
- return Some(cell);
- } else {
- // Handle cursor.
- self.cursor.rendered = true;
-
- let buffer_point = self.grid.visible_to_buffer(self.cursor.point);
- let cell = Indexed {
- inner: &self.grid[buffer_point.line][buffer_point.col],
- column: self.cursor.point.col,
- line: self.cursor.point.line,
- };
-
- let mut cell = RenderableCell::new(self, cell);
- cell.inner = RenderableCellContent::Cursor(self.cursor.key);
-
- // Apply cursor color, or invert the cursor if it has a fixed background close
- // to the cell's background.
- if !matches!(
- self.cursor.cursor_color,
- CellRgb::Rgb(color) if color.contrast(cell.bg) < MIN_CURSOR_CONTRAST
- ) {
- cell.fg = self.cursor.cursor_color.color(cell.fg, cell.bg);
- }
-
- return Some(cell);
- }
- } else {
- let cell = self.inner.next()?;
- let cell = RenderableCell::new(self, cell);
-
- if !cell.is_empty() {
- return Some(cell);
- }
- }
- }
- }
-}
-
pub mod mode {
use bitflags::bitflags;
@@ -1049,10 +1039,34 @@ impl<T> Term<T> {
/// A renderable cell is any cell which has content other than the default
/// 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.selection.as_ref().and_then(|s| s.to_range(self));
+ pub fn renderable_cells<'b, C>(
+ &'b self,
+ config: &'b Config<C>,
+ show_cursor: bool,
+ ) -> RenderableCellsIter<'_, C> {
+ RenderableCellsIter::new(&self, config, show_cursor)
+ }
+
+ /// Get the selection within the viewport.
+ pub fn visible_selection(&self) -> Option<SelectionRange<Line>> {
+ let selection = self.selection.as_ref()?.to_range(self)?;
+
+ // Set horizontal limits for block selection.
+ let (limit_start, limit_end) = if selection.is_block {
+ (selection.start.col, selection.end.col)
+ } else {
+ (Column(0), self.cols() - 1)
+ };
+
+ let range = self.grid.clamp_buffer_range_to_visible(&(selection.start..=selection.end))?;
+ let mut start = *range.start();
+ let mut end = *range.end();
+
+ // Trim start/end with partially visible block selection.
+ start.col = max(limit_start, start.col);
+ end.col = min(limit_end, end.col);
- RenderableCellsIter::new(&self, config, selection)
+ Some(SelectionRange::new(start, end, selection.is_block))
}
/// Resize terminal to new dimensions.
@@ -2836,7 +2850,7 @@ mod benches {
mem::swap(&mut terminal.grid, &mut grid);
b.iter(|| {
- let iter = terminal.renderable_cells(&config);
+ let iter = terminal.renderable_cells(&config, true);
for cell in iter {
test::black_box(cell);
}