Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions alacritty/src/config/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,10 @@ pub enum ViAction {
InlineSearchNext,
/// Jump to the previous inline search match.
InlineSearchPrevious,
/// Search forward for highlighted region or word under cursor.
CurrentWordSearchForward,
/// Search backward for highlighted region or word under cursor.
CurrentWordSearchBackward,
}

/// Search mode specific actions.
Expand Down Expand Up @@ -488,6 +492,8 @@ pub fn default_key_bindings() -> Vec<KeyBinding> {
"t", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViAction::InlineSearchBackwardShort;
";", +BindingMode::VI, ~BindingMode::SEARCH; ViAction::InlineSearchNext;
",", +BindingMode::VI, ~BindingMode::SEARCH; ViAction::InlineSearchPrevious;
"*", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViAction::CurrentWordSearchForward;
"#", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViAction::CurrentWordSearchBackward;
"k", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Up;
"j", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Down;
"h", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Left;
Expand All @@ -511,6 +517,9 @@ pub fn default_key_bindings() -> Vec<KeyBinding> {
"w", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::WordRight;
"e", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::WordRightEnd;
"%", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Bracket;
"{", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::ParagraphUp;
"}", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::ParagraphDown;
"o", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::VisualSelection;
Enter, +BindingMode::VI, +BindingMode::SEARCH; SearchAction::SearchConfirm;
// Plain search.
Escape, +BindingMode::SEARCH; SearchAction::SearchCancel;
Expand Down
44 changes: 44 additions & 0 deletions alacritty/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ use alacritty_terminal::index::{Boundary, Column, Direction, Line, Point, Side};
use alacritty_terminal::selection::{Selection, SelectionType};
use alacritty_terminal::term::search::{Match, RegexSearch};
use alacritty_terminal::term::{self, ClipboardType, Term, TermMode};
use alacritty_terminal::vi_mode::ViMotion;
use alacritty_terminal::vte::ansi::NamedColor;

#[cfg(unix)]
Expand Down Expand Up @@ -1008,6 +1009,49 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon
self.update_search();
}

#[inline]
fn search_selection(&mut self, direction: Direction) {
if let Some(text) = self.terminal().selection_to_string() {
self.clear_selection();
self.start_search(direction);

// escape regex search characters
text.chars().for_each(|c| {
if ".*+^$?\\()[]{}|".contains(c) {
self.search_input('\\');
}
self.search_input(c);
});

// mode-independent search
match self.terminal().mode().contains(TermMode::VI) {
true => self.confirm_search(),
false => self.advance_search_origin(direction),
}
}
}

#[inline]
fn search_current_word(&mut self, direction: Direction) {
if self.terminal.selection.as_ref().map_or(true, |s| s.is_empty()) {
let mut cursor = self.terminal_mut().vi_mode_cursor;
let origin = cursor.point;

// move forward to next semantic block if not already in one
let escape_chars = self.terminal.semantic_escape_chars().to_owned();
while escape_chars.contains(self.terminal().grid()[cursor.point].c) {
cursor = cursor.motion(self.terminal_mut(), ViMotion::SemanticRight);
// don't search if no semantic block is found after cursor
if cursor.point.line != origin.line {
cursor.point = origin;
return;
}
}
self.start_selection(SelectionType::Semantic, cursor.point, Side::Left);
}
self.search_selection(direction);
}

#[inline]
fn search_pop_word(&mut self) {
if let Some(regex) = self.search_state.regex_mut() {
Expand Down
28 changes: 26 additions & 2 deletions alacritty/src/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ pub trait ActionContext<T: EventListener> {
fn confirm_search(&mut self) {}
fn cancel_search(&mut self) {}
fn search_input(&mut self, _c: char) {}
fn search_selection(&mut self, _direction: Direction) {}
fn search_current_word(&mut self, _direction: Direction) {}
fn search_pop_word(&mut self) {}
fn search_history_previous(&mut self) {}
fn search_history_next(&mut self) {}
Expand Down Expand Up @@ -278,6 +280,12 @@ impl<T: EventListener> Execute<T> for Action {
},
Action::Vi(ViAction::InlineSearchNext) => ctx.inline_search_next(),
Action::Vi(ViAction::InlineSearchPrevious) => ctx.inline_search_previous(),
Action::Vi(ViAction::CurrentWordSearchForward) => {
ctx.search_current_word(Direction::Right)
},
Action::Vi(ViAction::CurrentWordSearchBackward) => {
ctx.search_current_word(Direction::Left)
},
action @ Action::Search(_) if !ctx.search_active() => {
debug!("Ignoring {action:?}: Search mode inactive");
},
Expand All @@ -299,8 +307,24 @@ impl<T: EventListener> Execute<T> for Action {
Action::Search(SearchAction::SearchHistoryPrevious) => ctx.search_history_previous(),
Action::Search(SearchAction::SearchHistoryNext) => ctx.search_history_next(),
Action::Mouse(MouseAction::ExpandSelection) => ctx.expand_selection(),
Action::SearchForward => ctx.start_search(Direction::Right),
Action::SearchBackward => ctx.start_search(Direction::Left),
Action::SearchForward => {
if ctx.terminal().selection.is_some()
&& !ctx.terminal().mode().contains(TermMode::VI)
{
ctx.search_selection(Direction::Right);
} else {
ctx.start_search(Direction::Right);
}
},
Action::SearchBackward => {
if !ctx.terminal().mode().contains(TermMode::VI)
&& ctx.terminal().selection.is_some()
{
ctx.search_selection(Direction::Left);
} else {
ctx.start_search(Direction::Left);
}
},
Action::Copy => ctx.copy_selection(ClipboardType::Clipboard),
#[cfg(not(any(target_os = "macos", windows)))]
Action::CopySelection => ctx.copy_selection(ClipboardType::Selection),
Expand Down
6 changes: 6 additions & 0 deletions alacritty_terminal/src/selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,12 @@ impl Selection {
}
}

/// Swap ends of highlighted region, returning new end of region location.
pub fn swap_anchors(&mut self) -> Point {
mem::swap(&mut self.region.start, &mut self.region.end);
self.region.end.point
}

fn range_semantic<T>(term: &Term<T>, mut start: Point, mut end: Point) -> SelectionRange {
if start == end {
if let Some(matching) = term.bracket_search(start) {
Expand Down
37 changes: 37 additions & 0 deletions alacritty_terminal/src/vi_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ pub enum ViMotion {
WordRightEnd,
/// Move to opposing bracket.
Bracket,
/// Move up to first empty row.
ParagraphUp,
/// Move down to first empty row.
ParagraphDown,
/// Move to highlighted region opposite selection marker.
VisualSelection,
}

/// Cursor tracking vi mode position.
Expand Down Expand Up @@ -153,6 +159,37 @@ impl ViModeCursor {
self.point = word(term, self.point, Direction::Right, Side::Right);
},
ViMotion::Bracket => self.point = term.bracket_search(self.point).unwrap_or(self.point),
ViMotion::ParagraphUp => {
self.point.column = Column(0);
while self.point.line > term.topmost_line()
&& term.grid()[self.point.line].is_clear()
{
self.point.line -= 1;
}
while self.point.line > term.topmost_line()
&& !term.grid()[self.point.line].is_clear()
{
self.point.line -= 1;
}
},
ViMotion::ParagraphDown => {
self.point.column = Column(0);
while self.point.line + 1 < term.screen_lines()
&& term.grid()[self.point.line].is_clear()
{
self.point.line += 1;
}
while self.point.line + 1 < term.screen_lines()
&& !term.grid()[self.point.line].is_clear()
{
self.point.line += 1;
}
},
ViMotion::VisualSelection => {
if let Some(selection) = &mut term.selection {
self.point = selection.swap_anchors();
}
},
}

term.scroll_to_point(self.point);
Expand Down
20 changes: 20 additions & 0 deletions extra/man/alacritty-bindings.5.scd
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,14 @@ configuration. See *alacritty*(5) for full configuration format documentation.
:[
: _"Vi|~Search"_
: _"InlineSearchPrevious"_
| _"\*"_
: _"Shift"_
: _"Vi|~Search"_
: _"CurrentWordSearchForward"_
| _"#"_
: _"Shift"_
: _"Vi|~Search"_
: _"CurrentWordSearchBackward"_
| _"K"_
:[
: _"Vi|~Search"_
Expand Down Expand Up @@ -281,6 +289,18 @@ configuration. See *alacritty*(5) for full configuration format documentation.
: _"Shift"_
: _"Vi|~Search"_
: _"Bracket"_
| _"{"_
:[
: _"Vi|~Search"_
: _"ParagraphUp"_
| _"}"_
:[
: _"Vi|~Search"_
: _"ParagraphDown"_
| _"o"_
:[
: _"Vi|~Search"_
: _"VisualSelection"_
| _"/"_
:[
: _"Vi|~Search"_
Expand Down
10 changes: 10 additions & 0 deletions extra/man/alacritty.5.scd
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,12 @@ _https://docs.rs/winit/latest/winit/keyboard/enum.Key.html#variant.Dead_
Move to end of whitespace separated word.
*Bracket*
Move to opposing bracket.
*ParagraphUp*
Move up to first empty row.
*ParagraphDown*
Move down to first empty row.
*VisualSelection*
Move to highlighted region opposite selection marker.
*ToggleNormalSelection*
Toggle normal vi selection.
*ToggleLineSelection*
Expand Down Expand Up @@ -926,6 +932,10 @@ _https://docs.rs/winit/latest/winit/keyboard/enum.Key.html#variant.Dead_
Jump to the next inline search match.
*InlineSearchPrevious*
Jump to the previous inline search match.
*CurrentWordSearchForward*
Search forward for highlighted region or word under cursor.
*CurrentWordSearchBackward*
Search backward for highlighted region or word under cursor.

_Search actions:_

Expand Down