summaryrefslogtreecommitdiff
path: root/alacritty_terminal/src/term/mod.rs
diff options
context:
space:
mode:
authorChristian Duerr <contact@christianduerr.com>2020-11-13 05:40:09 +0000
committerGitHub <noreply@github.com>2020-11-13 08:40:09 +0300
commit9a7844987693909925b8663d8aa905231d291410 (patch)
treee99b99bcbd0fc40aa1938fc203357321ec024777 /alacritty_terminal/src/term/mod.rs
parentb6d94e7b13eb9a14edea843a79c6d86b5b6d8803 (diff)
downloadalacritty-9a7844987693909925b8663d8aa905231d291410.tar.gz
alacritty-9a7844987693909925b8663d8aa905231d291410.zip
Add ability to select text during search
This removes the restriction of not being able to select text while the search is active, making it a bit less jarring of a UX when the user tries to interact with the terminal during search. Since the selection was used during vi-less search to highlight the focused match, there is now an option for a focused match color, which uses the inverted normal match color by default. This focused match is used for both search modes. Other mouse interactions are now also possible during search, like opening URLs or clicking inside of mouse mode applications.
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);
}