diff options
author | Christian Duerr <contact@christianduerr.com> | 2020-11-13 05:40:09 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-13 08:40:09 +0300 |
commit | 9a7844987693909925b8663d8aa905231d291410 (patch) | |
tree | e99b99bcbd0fc40aa1938fc203357321ec024777 /alacritty | |
parent | b6d94e7b13eb9a14edea843a79c6d86b5b6d8803 (diff) | |
download | r-alacritty-9a7844987693909925b8663d8aa905231d291410.tar.gz r-alacritty-9a7844987693909925b8663d8aa905231d291410.tar.bz2 r-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')
-rw-r--r-- | alacritty/src/display.rs | 28 | ||||
-rw-r--r-- | alacritty/src/event.rs | 46 | ||||
-rw-r--r-- | alacritty/src/input.rs | 18 | ||||
-rw-r--r-- | alacritty/src/renderer/mod.rs | 1 | ||||
-rw-r--r-- | alacritty/src/url.rs | 1 |
5 files changed, 70 insertions, 24 deletions
diff --git a/alacritty/src/display.rs b/alacritty/src/display.rs index 6d683336..af21001e 100644 --- a/alacritty/src/display.rs +++ b/alacritty/src/display.rs @@ -27,7 +27,7 @@ use crossfont::{self, Rasterize, Rasterizer}; use alacritty_terminal::event::{EventListener, OnResize}; use alacritty_terminal::index::{Column, Direction, Point}; use alacritty_terminal::selection::Selection; -use alacritty_terminal::term::{RenderableCell, SizeInfo, Term, TermMode}; +use alacritty_terminal::term::{SizeInfo, Term, TermMode}; use alacritty_terminal::term::{MIN_COLS, MIN_SCREEN_LINES}; use crate::config::font::Font; @@ -437,7 +437,13 @@ impl Display { mods: ModifiersState, search_state: &SearchState, ) { - let grid_cells: Vec<RenderableCell> = terminal.renderable_cells(config).collect(); + // Convert search match from viewport to absolute indexing. + let search_active = search_state.regex().is_some(); + let viewport_match = search_state + .focused_match() + .and_then(|focused_match| terminal.grid().clamp_buffer_range_to_visible(focused_match)); + + let grid_cells = terminal.renderable_cells(config, !search_active).collect::<Vec<_>>(); let visual_bell_intensity = terminal.visual_bell.intensity(); let background_color = terminal.background_color(); let cursor_point = terminal.grid().cursor.point; @@ -471,7 +477,21 @@ impl Display { self.renderer.with_api(&config.ui_config, config.cursor, &size_info, |mut api| { // Iterate over all non-empty cells in the grid. - for cell in grid_cells { + for mut cell in grid_cells { + // Invert the active match in vi-less search. + let cell_point = Point::new(cell.line, cell.column); + if cell.is_match + && viewport_match + .as_ref() + .map_or(false, |viewport_match| viewport_match.contains(&cell_point)) + { + let colors = config.colors.search.focused_match; + let match_fg = colors.foreground().color(cell.fg, cell.bg); + cell.bg = colors.background().color(cell.fg, cell.bg); + cell.fg = match_fg; + cell.bg_alpha = 1.0; + } + // Update URL underlines. urls.update(size_info.cols(), &cell); @@ -525,7 +545,7 @@ impl Display { } if let Some(message) = message_buffer.message() { - let search_offset = if search_state.regex().is_some() { 1 } else { 0 }; + let search_offset = if search_active { 1 } else { 0 }; let text = message.text(&size_info); // Create a new rectangle for the background. diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs index 20f087c3..c1f81300 100644 --- a/alacritty/src/event.rs +++ b/alacritty/src/event.rs @@ -9,6 +9,7 @@ use std::fs; use std::fs::File; use std::io::Write; use std::mem; +use std::ops::RangeInclusive; use std::path::PathBuf; #[cfg(not(any(target_os = "macos", windows)))] use std::sync::atomic::Ordering; @@ -94,6 +95,9 @@ pub struct SearchState { /// Search origin in viewport coordinates relative to original display offset. origin: Point, + + /// Focused match during active search. + focused_match: Option<RangeInclusive<Point<usize>>>, } impl SearchState { @@ -110,6 +114,11 @@ impl SearchState { pub fn direction(&self) -> Direction { self.direction } + + /// Focused match during vi-less search. + pub fn focused_match(&self) -> Option<&RangeInclusive<Point<usize>>> { + self.focused_match.as_ref() + } } impl Default for SearchState { @@ -118,6 +127,7 @@ impl Default for SearchState { direction: Direction::Right, display_offset_delta: 0, origin: Point::default(), + focused_match: None, regex: None, } } @@ -209,7 +219,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon selection.update(absolute_point, side); // Move vi cursor and expand selection. - if self.terminal.mode().contains(TermMode::VI) { + if self.terminal.mode().contains(TermMode::VI) && !self.search_active() { self.terminal.vi_mode_cursor.point = point; selection.include_all(); } @@ -385,6 +395,7 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon let num_lines = self.terminal.screen_lines(); let num_cols = self.terminal.cols(); + self.search_state.focused_match = None; self.search_state.regex = Some(String::new()); self.search_state.direction = direction; @@ -393,9 +404,6 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon self.search_state.origin = if self.terminal.mode().contains(TermMode::VI) { self.terminal.vi_mode_cursor.point } else { - // Clear search, since it is used as the active match. - self.terminal.selection = None; - match direction { Direction::Right => Point::new(Line(0), Column(0)), Direction::Left => Point::new(num_lines - 2, num_cols - 1), @@ -420,9 +428,15 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon fn cancel_search(&mut self) { self.terminal.cancel_search(); - // Recover pre-search state in vi mode. if self.terminal.mode().contains(TermMode::VI) { + // Recover pre-search state in vi mode. self.search_reset_state(); + } else if let Some(focused_match) = &self.search_state.focused_match { + // Create a selection for the focused match. + let start = self.terminal.grid().clamp_buffer_to_visible(*focused_match.start()); + let end = self.terminal.grid().clamp_buffer_to_visible(*focused_match.end()); + self.start_selection(SelectionType::Simple, start, Side::Left); + self.update_selection(end, Side::Right); } self.exit_search(); @@ -431,8 +445,8 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon #[inline] fn push_search(&mut self, c: char) { if let Some(regex) = self.search_state.regex.as_mut() { - // Prevent previous search selections from sticking around when not in vi mode. if !self.terminal.mode().contains(TermMode::VI) { + // Clear selection so we do not obstruct any matches. self.terminal.selection = None; } @@ -533,8 +547,8 @@ impl<'a, N: Notify + 'a, T: EventListener> ActionContext<'a, N, T> { self.search_reset_state(); self.terminal.cancel_search(); - // Restart search without vi mode to clear the search origin. if !self.terminal.mode().contains(TermMode::VI) { + // Restart search without vi mode to clear the search origin. self.start_search(self.search_state.direction); } } else { @@ -554,6 +568,9 @@ impl<'a, N: Notify + 'a, T: EventListener> ActionContext<'a, N, T> { self.terminal.scroll_display(Scroll::Delta(self.search_state.display_offset_delta)); self.search_state.display_offset_delta = 0; + // Clear focused match. + self.search_state.focused_match = None; + // Reset vi mode cursor. let mut origin = self.search_state.origin; origin.line = min(origin.line, self.terminal.screen_lines() - 1); @@ -586,12 +603,11 @@ impl<'a, N: Notify + 'a, T: EventListener> ActionContext<'a, N, T> { } else { // Select the match when vi mode is not active. self.terminal.scroll_to_point(*regex_match.start()); - let start = self.terminal.grid().clamp_buffer_to_visible(*regex_match.start()); - let end = self.terminal.grid().clamp_buffer_to_visible(*regex_match.end()); - self.start_selection(SelectionType::Simple, start, Side::Left); - self.update_selection(end, Side::Right); } + // Update the focused match. + self.search_state.focused_match = Some(regex_match); + // Store number of lines the viewport had to be moved. let display_offset = self.terminal.grid().display_offset(); self.search_state.display_offset_delta += old_offset - display_offset as isize; @@ -611,13 +627,16 @@ impl<'a, N: Notify + 'a, T: EventListener> ActionContext<'a, N, T> { TimerId::DelayedSearch, ); } + + // Clear focused match. + self.search_state.focused_match = None; }, } self.search_state.regex = Some(regex); } - /// Close the search bar. + /// Cleanup the search state. fn exit_search(&mut self) { // Move vi cursor down if resize will pull content from history. if self.terminal.history_size() != 0 @@ -630,6 +649,9 @@ impl<'a, N: Notify + 'a, T: EventListener> ActionContext<'a, N, T> { self.display_update_pending.dirty = true; self.search_state.regex = None; self.terminal.dirty = true; + + // Clear focused match. + self.search_state.focused_match = None; } /// Get the absolute position of the search origin. diff --git a/alacritty/src/input.rs b/alacritty/src/input.rs index 9c75753a..348db610 100644 --- a/alacritty/src/input.rs +++ b/alacritty/src/input.rs @@ -360,14 +360,13 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> { #[inline] pub fn mouse_moved(&mut self, position: PhysicalPosition<f64>) { - let search_active = self.ctx.search_active(); let size_info = self.ctx.size_info(); let (x, y) = position.into(); let lmb_pressed = self.ctx.mouse().left_button_state == ElementState::Pressed; let rmb_pressed = self.ctx.mouse().right_button_state == ElementState::Pressed; - if !self.ctx.selection_is_empty() && (lmb_pressed || rmb_pressed) && !search_active { + if !self.ctx.selection_is_empty() && (lmb_pressed || rmb_pressed) { self.update_selection_scrolling(y); } @@ -405,9 +404,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> { // Don't launch URLs if mouse has moved. self.ctx.mouse_mut().block_url_launcher = true; - if (lmb_pressed || rmb_pressed) - && (self.ctx.modifiers().shift() || !self.ctx.mouse_mode()) - && !search_active + if (lmb_pressed || rmb_pressed) && (self.ctx.modifiers().shift() || !self.ctx.mouse_mode()) { self.ctx.update_selection(point, cell_side); } else if inside_text_area @@ -600,7 +597,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> { self.ctx.update_selection(point, cell_side); // Move vi mode cursor to mouse click position. - if self.ctx.terminal().mode().contains(TermMode::VI) { + if self.ctx.terminal().mode().contains(TermMode::VI) && !self.ctx.search_active() { self.ctx.terminal_mut().vi_mode_cursor.point = point; } } @@ -635,7 +632,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> { }; // Move vi mode cursor to mouse click position. - if self.ctx.terminal().mode().contains(TermMode::VI) { + if self.ctx.terminal().mode().contains(TermMode::VI) && !self.ctx.search_active() { self.ctx.terminal_mut().vi_mode_cursor.point = point; } } @@ -791,7 +788,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> { }; self.ctx.window_mut().set_mouse_cursor(new_icon); - } else if !self.ctx.search_active() { + } else { match state { ElementState::Pressed => { self.process_mouse_bindings(button); @@ -963,6 +960,11 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> { /// The provided mode, mods, and key must match what is allowed by a binding /// for its action to be executed. fn process_mouse_bindings(&mut self, button: MouseButton) { + // Ignore bindings while search is active. + if self.ctx.search_active() { + return; + } + let mods = *self.ctx.modifiers(); let mode = *self.ctx.terminal().mode(); let mouse_mode = self.ctx.mouse_mode(); diff --git a/alacritty/src/renderer/mod.rs b/alacritty/src/renderer/mod.rs index f628d24f..b347556d 100644 --- a/alacritty/src/renderer/mod.rs +++ b/alacritty/src/renderer/mod.rs @@ -958,6 +958,7 @@ impl<'a> RenderApi<'a> { bg_alpha, fg, bg: bg.unwrap_or(Rgb { r: 0, g: 0, b: 0 }), + is_match: false, }) .collect::<Vec<_>>(); diff --git a/alacritty/src/url.rs b/alacritty/src/url.rs index f3f60dd3..5d35667d 100644 --- a/alacritty/src/url.rs +++ b/alacritty/src/url.rs @@ -207,6 +207,7 @@ mod tests { bg: Default::default(), bg_alpha: 0., flags: Flags::empty(), + is_match: false, }) .collect() } |