diff options
Diffstat (limited to 'alacritty/src')
-rw-r--r-- | alacritty/src/config/bindings.rs | 16 | ||||
-rw-r--r-- | alacritty/src/event.rs | 102 | ||||
-rw-r--r-- | alacritty/src/input.rs | 25 |
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 } |