aboutsummaryrefslogtreecommitdiff
path: root/alacritty/src
diff options
context:
space:
mode:
authorChristian Duerr <contact@christianduerr.com>2020-07-15 21:27:32 +0000
committerGitHub <noreply@github.com>2020-07-15 21:27:32 +0000
commit142f84efb955a9fa59f4205ec3a6db3964c5f433 (patch)
tree450d1f210dd961de872f8105cdb4290a13194d97 /alacritty/src
parentd868848ef162ce1d2d5e41b690a592199e9f652d (diff)
downloadr-alacritty-142f84efb955a9fa59f4205ec3a6db3964c5f433.tar.gz
r-alacritty-142f84efb955a9fa59f4205ec3a6db3964c5f433.tar.bz2
r-alacritty-142f84efb955a9fa59f4205ec3a6db3964c5f433.zip
Add support for searching without vi mode
This implements search without vi mode by using the selection to track the active search match and advancing it on user input. The keys to go to the next or previous match are not configurable and are bound to enter and shift enter based on Firefox's behavior. Fixes #3937.
Diffstat (limited to 'alacritty/src')
-rw-r--r--alacritty/src/config/bindings.rs16
-rw-r--r--alacritty/src/event.rs102
-rw-r--r--alacritty/src/input.rs25
3 files changed, 106 insertions, 37 deletions
diff --git a/alacritty/src/config/bindings.rs b/alacritty/src/config/bindings.rs
index 77521318..1c07a33b 100644
--- a/alacritty/src/config/bindings.rs
+++ b/alacritty/src/config/bindings.rs
@@ -176,11 +176,11 @@ pub enum Action {
/// Allow receiving char input.
ReceiveChar,
- /// Start a buffer search.
- Search,
+ /// Start a forward buffer search.
+ SearchForward,
- /// Start a reverse buffer search.
- SearchReverse,
+ /// Start a backward buffer search.
+ SearchBackward,
/// No action.
None,
@@ -378,8 +378,8 @@ pub fn default_key_bindings() -> Vec<KeyBinding> {
D, ModifiersState::CTRL, +TermMode::VI; Action::ScrollHalfPageDown;
Y, +TermMode::VI; Action::Copy;
Y, +TermMode::VI; Action::ClearSelection;
- Slash, +TermMode::VI; Action::Search;
- Slash, ModifiersState::SHIFT, +TermMode::VI; Action::SearchReverse;
+ Slash, +TermMode::VI; Action::SearchForward;
+ Slash, ModifiersState::SHIFT, +TermMode::VI; Action::SearchBackward;
V, +TermMode::VI; ViAction::ToggleNormalSelection;
V, ModifiersState::SHIFT, +TermMode::VI; ViAction::ToggleLineSelection;
V, ModifiersState::CTRL, +TermMode::VI; ViAction::ToggleBlockSelection;
@@ -487,6 +487,8 @@ fn common_keybindings() -> Vec<KeyBinding> {
KeyBinding;
V, ModifiersState::CTRL | ModifiersState::SHIFT, ~TermMode::VI; Action::Paste;
C, ModifiersState::CTRL | ModifiersState::SHIFT; Action::Copy;
+ F, ModifiersState::CTRL | ModifiersState::SHIFT; Action::SearchForward;
+ B, ModifiersState::CTRL | ModifiersState::SHIFT; Action::SearchBackward;
C, ModifiersState::CTRL | ModifiersState::SHIFT, +TermMode::VI; Action::ClearSelection;
Insert, ModifiersState::SHIFT, ~TermMode::VI; Action::PasteSelection;
Key0, ModifiersState::CTRL; Action::ResetFontSize;
@@ -532,6 +534,8 @@ pub fn platform_key_bindings() -> Vec<KeyBinding> {
M, ModifiersState::LOGO; Action::Minimize;
Q, ModifiersState::LOGO; Action::Quit;
W, ModifiersState::LOGO; Action::Quit;
+ F, ModifiersState::LOGO; Action::SearchForward;
+ B, ModifiersState::LOGO; Action::SearchBackward;
)
}
diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs
index eed5624f..f06b818e 100644
--- a/alacritty/src/event.rs
+++ b/alacritty/src/event.rs
@@ -31,7 +31,7 @@ use font::{self, Size};
use alacritty_terminal::config::LOG_TARGET_CONFIG;
use alacritty_terminal::event::{Event as TerminalEvent, EventListener, Notify, OnResize};
use alacritty_terminal::grid::{Dimensions, Scroll};
-use alacritty_terminal::index::{Column, Direction, Line, Point, Side};
+use alacritty_terminal::index::{Boundary, Column, Direction, Line, Point, Side};
use alacritty_terminal::selection::{Selection, SelectionType};
use alacritty_terminal::sync::FairMutex;
use alacritty_terminal::term::cell::Cell;
@@ -91,8 +91,8 @@ pub struct SearchState {
/// Change in display offset since the beginning of the search.
display_offset_delta: isize,
- /// Vi cursor position before search.
- vi_cursor_point: Point,
+ /// Search origin in viewport coordinates relative to original display offset.
+ origin: Point,
}
impl SearchState {
@@ -106,7 +106,7 @@ impl Default for SearchState {
Self {
direction: Direction::Right,
display_offset_delta: 0,
- vi_cursor_point: Point::default(),
+ origin: Point::default(),
regex: None,
}
}
@@ -142,8 +142,16 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
}
fn scroll(&mut self, scroll: Scroll) {
+ let old_offset = self.terminal.grid().display_offset() as isize;
+
self.terminal.scroll_display(scroll);
+ // Keep track of manual display offset changes during search.
+ if self.search_active() {
+ let display_offset = self.terminal.grid().display_offset();
+ self.search_state.display_offset_delta += old_offset - display_offset as isize;
+ }
+
// Update selection.
if self.terminal.mode().contains(TermMode::VI)
&& self.terminal.selection.as_ref().map(|s| s.is_empty()) != Some(true)
@@ -339,10 +347,14 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
self.search_state.regex = Some(String::new());
self.search_state.direction = direction;
- // Store original vi cursor position as search origin and for resetting.
- self.search_state.vi_cursor_point = if self.terminal.mode().contains(TermMode::VI) {
+ // Store original search position as origin and reset location.
+ self.search_state.display_offset_delta = 0;
+ 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),
@@ -355,9 +367,6 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
#[inline]
fn confirm_search(&mut self) {
- // Enter vi mode once search is confirmed.
- self.terminal.set_vi_mode();
-
// Force unlimited search if the previous one was interrupted.
if self.scheduler.scheduled(TimerId::DelayedSearch) {
self.goto_match(None);
@@ -368,9 +377,6 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
self.terminal.vi_mode_cursor.point.line += 1;
}
- // Clear reset state.
- self.search_state.display_offset_delta = 0;
-
self.display_update_pending.dirty = true;
self.search_state.regex = None;
self.terminal.dirty = true;
@@ -419,6 +425,29 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
}
#[inline]
+ fn advance_search_origin(&mut self, direction: Direction) {
+ let origin = self.absolute_origin();
+ self.terminal.scroll_to_point(origin);
+
+ // Move the search origin right in front of the next match in the specified direction.
+ if let Some(regex_match) = self.terminal.search_next(origin, direction, Side::Left, None) {
+ let origin = match direction {
+ Direction::Right => *regex_match.end(),
+ Direction::Left => {
+ regex_match.start().sub_absolute(self.terminal, Boundary::Wrap, 1)
+ },
+ };
+ self.terminal.scroll_to_point(origin);
+
+ let origin_relative = self.terminal.grid().clamp_buffer_to_visible(origin);
+ self.search_state.origin = origin_relative;
+ self.search_state.display_offset_delta = 0;
+
+ self.update_search();
+ }
+ }
+
+ #[inline]
fn search_direction(&self) -> Direction {
self.search_state.direction
}
@@ -487,10 +516,10 @@ impl<'a, N: Notify + 'a, T: EventListener> ActionContext<'a, N, T> {
self.search_state.display_offset_delta = 0;
// Reset vi mode cursor.
- let mut vi_cursor_point = self.search_state.vi_cursor_point;
- vi_cursor_point.line = min(vi_cursor_point.line, self.terminal.screen_lines() - 1);
- vi_cursor_point.col = min(vi_cursor_point.col, self.terminal.cols() - 1);
- self.terminal.vi_mode_cursor.point = vi_cursor_point;
+ let mut origin = self.search_state.origin;
+ origin.line = min(origin.line, self.terminal.screen_lines() - 1);
+ origin.col = min(origin.col, self.terminal.cols() - 1);
+ self.terminal.vi_mode_cursor.point = origin;
// Unschedule pending timers.
self.scheduler.unschedule(TimerId::DelayedSearch);
@@ -506,19 +535,23 @@ impl<'a, N: Notify + 'a, T: EventListener> ActionContext<'a, N, T> {
// Limit search only when enough lines are available to run into the limit.
limit = limit.filter(|&limit| limit <= self.terminal.total_lines());
- // Use original position as search origin.
- let mut vi_cursor_point = self.search_state.vi_cursor_point;
- vi_cursor_point.line = min(vi_cursor_point.line, self.terminal.screen_lines() - 1);
- let mut origin = self.terminal.visible_to_buffer(vi_cursor_point);
- origin.line = (origin.line as isize + self.search_state.display_offset_delta) as usize;
-
// Jump to the next match.
let direction = self.search_state.direction;
- match self.terminal.search_next(origin, direction, Side::Left, limit) {
+ match self.terminal.search_next(self.absolute_origin(), direction, Side::Left, limit) {
Some(regex_match) => {
let old_offset = self.terminal.grid().display_offset() as isize;
- self.terminal.vi_goto_point(*regex_match.start());
+ if self.terminal.mode().contains(TermMode::VI) {
+ // Move vi cursor to the start of the match.
+ self.terminal.vi_goto_point(*regex_match.start());
+ } 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);
+ }
// Store number of lines the viewport had to be moved.
let display_offset = self.terminal.grid().display_offset();
@@ -544,6 +577,19 @@ impl<'a, N: Notify + 'a, T: EventListener> ActionContext<'a, N, T> {
self.search_state.regex = Some(regex);
}
+
+ /// Get the absolute position of the search origin.
+ ///
+ /// This takes the relative motion of the viewport since the start of the search into account.
+ /// So while the absolute point of the origin might have changed since new content was printed,
+ /// this will still return the correct absolute position.
+ fn absolute_origin(&self) -> Point<usize> {
+ let mut relative_origin = self.search_state.origin;
+ relative_origin.line = min(relative_origin.line, self.terminal.screen_lines() - 1);
+ let mut origin = self.terminal.visible_to_buffer(relative_origin);
+ origin.line = (origin.line as isize + self.search_state.display_offset_delta) as usize;
+ origin
+ }
}
#[derive(Debug, Eq, PartialEq)]
@@ -1047,9 +1093,11 @@ impl<N: Notify + OnResize> Processor<N> {
// Compute cursor positions before resize.
let num_lines = terminal.screen_lines();
let cursor_at_bottom = terminal.grid().cursor.point.line + 1 == num_lines;
- let origin_at_bottom = (!terminal.mode().contains(TermMode::VI)
- && self.search_state.direction == Direction::Left)
- || terminal.vi_mode_cursor.point.line == num_lines - 1;
+ let origin_at_bottom = if terminal.mode().contains(TermMode::VI) {
+ terminal.vi_mode_cursor.point.line == num_lines - 1
+ } else {
+ self.search_state.direction == Direction::Left
+ };
self.display.handle_update(
terminal,
diff --git a/alacritty/src/input.rs b/alacritty/src/input.rs
index 58ca42cb..80f3e5d9 100644
--- a/alacritty/src/input.rs
+++ b/alacritty/src/input.rs
@@ -100,6 +100,7 @@ pub trait ActionContext<T: EventListener> {
fn push_search(&mut self, c: char);
fn pop_search(&mut self);
fn pop_word_search(&mut self);
+ fn advance_search_origin(&mut self, direction: Direction);
fn search_direction(&self) -> Direction;
fn search_active(&self) -> bool;
}
@@ -224,8 +225,8 @@ impl<T: EventListener> Execute<T> for Action {
ctx.terminal_mut().vi_goto_point(*regex_match.end());
}
},
- Action::Search => ctx.start_search(Direction::Right),
- Action::SearchReverse => ctx.start_search(Direction::Left),
+ Action::SearchForward => ctx.start_search(Direction::Right),
+ Action::SearchBackward => ctx.start_search(Direction::Left),
Action::ToggleFullscreen => ctx.window_mut().toggle_fullscreen(),
#[cfg(target_os = "macos")]
Action::ToggleSimpleFullscreen => ctx.window_mut().toggle_simple_fullscreen(),
@@ -359,12 +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;
- if !self.ctx.selection_is_empty() && lmb_pressed {
+ if !self.ctx.selection_is_empty() && lmb_pressed && !search_active {
self.update_selection_scrolling(y);
}
@@ -405,6 +407,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
let last_term_line = self.ctx.terminal().grid().screen_lines() - 1;
if (lmb_pressed || self.ctx.mouse().right_button_state == ElementState::Pressed)
&& (self.ctx.modifiers().shift() || !self.ctx.mouse_mode())
+ && !search_active
{
// Treat motion over message bar like motion over the last line.
let line = min(point.line, last_term_line);
@@ -811,9 +814,21 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
self.ctx.pop_search();
*self.ctx.suppress_chars() = true;
},
+ (Some(VirtualKeyCode::Return), ModifiersState::SHIFT)
+ if !self.ctx.terminal().mode().contains(TermMode::VI) =>
+ {
+ let direction = self.ctx.search_direction().opposite();
+ self.ctx.advance_search_origin(direction);
+ *self.ctx.suppress_chars() = true;
+ }
(Some(VirtualKeyCode::Return), _)
| (Some(VirtualKeyCode::J), ModifiersState::CTRL) => {
- self.ctx.confirm_search();
+ if self.ctx.terminal().mode().contains(TermMode::VI) {
+ self.ctx.confirm_search();
+ } else {
+ self.ctx.advance_search_origin(self.ctx.search_direction());
+ }
+
*self.ctx.suppress_chars() = true;
},
(Some(VirtualKeyCode::Escape), _) => {
@@ -1143,6 +1158,8 @@ mod tests {
fn pop_word_search(&mut self) {}
+ fn advance_search_origin(&mut self, _direction: Direction) {}
+
fn search_direction(&self) -> Direction {
Direction::Right
}