aboutsummaryrefslogtreecommitdiff
path: root/alacritty/src/input.rs
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty/src/input.rs')
-rw-r--r--alacritty/src/input.rs166
1 files changed, 64 insertions, 102 deletions
diff --git a/alacritty/src/input.rs b/alacritty/src/input.rs
index d6296a5d..d5afbbd2 100644
--- a/alacritty/src/input.rs
+++ b/alacritty/src/input.rs
@@ -15,7 +15,6 @@ use log::trace;
use glutin::dpi::PhysicalPosition;
use glutin::event::{
ElementState, KeyboardInput, ModifiersState, MouseButton, MouseScrollDelta, TouchPhase,
- VirtualKeyCode,
};
use glutin::event_loop::EventLoopWindowTarget;
#[cfg(target_os = "macos")]
@@ -32,7 +31,7 @@ use alacritty_terminal::term::{ClipboardType, SizeInfo, Term};
use alacritty_terminal::vi_mode::ViMotion;
use crate::clipboard::Clipboard;
-use crate::config::{Action, Binding, Config, Key, ViAction};
+use crate::config::{Action, Binding, BindingMode, Config, Key, SearchAction, ViAction};
use crate::daemon::start_daemon;
use crate::event::{ClickState, Event, Mouse, TYPING_SEARCH_DELAY};
use crate::message_bar::{self, Message};
@@ -97,8 +96,7 @@ pub trait ActionContext<T: EventListener> {
fn start_search(&mut self, direction: Direction);
fn confirm_search(&mut self);
fn cancel_search(&mut self);
- fn push_search(&mut self, c: char);
- fn pop_search(&mut self);
+ fn search_input(&mut self, c: char);
fn pop_word_search(&mut self);
fn advance_search_origin(&mut self, direction: Direction);
fn search_direction(&self) -> Direction;
@@ -145,17 +143,6 @@ impl<T: EventListener> Execute<T> for Action {
ctx.scroll(Scroll::Bottom);
ctx.write_to_pty(s.clone().into_bytes())
},
- Action::Copy => ctx.copy_selection(ClipboardType::Clipboard),
- #[cfg(not(any(target_os = "macos", windows)))]
- Action::CopySelection => ctx.copy_selection(ClipboardType::Selection),
- Action::Paste => {
- let text = ctx.clipboard_mut().load(ClipboardType::Clipboard);
- paste(ctx, &text);
- },
- Action::PasteSelection => {
- let text = ctx.clipboard_mut().load(ClipboardType::Selection);
- paste(ctx, &text);
- },
Action::Command(ref program) => {
let args = program.args();
let program = program.program();
@@ -163,7 +150,6 @@ impl<T: EventListener> Execute<T> for Action {
start_daemon(program, args);
},
- Action::ClearSelection => ctx.clear_selection(),
Action::ToggleViMode => ctx.terminal_mut().toggle_vi_mode(),
Action::ViMotion(motion) => {
ctx.on_typing_start();
@@ -221,8 +207,35 @@ impl<T: EventListener> Execute<T> for Action {
ctx.terminal_mut().vi_goto_point(*regex_match.end());
}
},
+ Action::SearchAction(SearchAction::SearchFocusNext) => {
+ ctx.advance_search_origin(ctx.search_direction());
+ },
+ Action::SearchAction(SearchAction::SearchFocusPrevious) => {
+ let direction = ctx.search_direction().opposite();
+ ctx.advance_search_origin(direction);
+ },
+ Action::SearchAction(SearchAction::SearchConfirm) => ctx.confirm_search(),
+ Action::SearchAction(SearchAction::SearchCancel) => ctx.cancel_search(),
+ Action::SearchAction(SearchAction::SearchClear) => {
+ let direction = ctx.search_direction();
+ ctx.cancel_search();
+ ctx.start_search(direction);
+ },
+ Action::SearchAction(SearchAction::SearchDeleteWord) => ctx.pop_word_search(),
Action::SearchForward => ctx.start_search(Direction::Right),
Action::SearchBackward => 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),
+ Action::ClearSelection => ctx.clear_selection(),
+ Action::Paste => {
+ let text = ctx.clipboard_mut().load(ClipboardType::Clipboard);
+ paste(ctx, &text);
+ },
+ Action::PasteSelection => {
+ let text = ctx.clipboard_mut().load(ClipboardType::Selection);
+ paste(ctx, &text);
+ },
Action::ToggleFullscreen => ctx.window_mut().toggle_fullscreen(),
#[cfg(target_os = "macos")]
Action::ToggleSimpleFullscreen => ctx.window_mut().toggle_simple_fullscreen(),
@@ -315,7 +328,11 @@ impl<T: EventListener> Execute<T> for Action {
}
fn paste<T: EventListener, A: ActionContext<T>>(ctx: &mut A, contents: &str) {
- if ctx.terminal().mode().contains(TermMode::BRACKETED_PASTE) {
+ if ctx.search_active() {
+ for c in contents.chars() {
+ ctx.search_input(c);
+ }
+ } else if ctx.terminal().mode().contains(TermMode::BRACKETED_PASTE) {
ctx.write_to_pty(&b"\x1b[200~"[..]);
ctx.write_to_pty(contents.replace("\x1b", "").into_bytes());
ctx.write_to_pty(&b"\x1b[201~"[..]);
@@ -796,57 +813,14 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
/// Process key input.
pub fn key_input(&mut self, input: KeyboardInput) {
- match input.state {
- ElementState::Pressed if self.ctx.search_active() => {
- match (input.virtual_keycode, *self.ctx.modifiers()) {
- (Some(VirtualKeyCode::Back), _) => {
- 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) => {
- 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), _)
- | (Some(VirtualKeyCode::C), ModifiersState::CTRL) => {
- self.ctx.cancel_search();
- *self.ctx.suppress_chars() = true;
- },
- (Some(VirtualKeyCode::U), ModifiersState::CTRL) => {
- let direction = self.ctx.search_direction();
- self.ctx.cancel_search();
- self.ctx.start_search(direction);
- *self.ctx.suppress_chars() = true;
- },
- (Some(VirtualKeyCode::H), ModifiersState::CTRL) => {
- self.ctx.pop_search();
- *self.ctx.suppress_chars() = true;
- },
- (Some(VirtualKeyCode::W), ModifiersState::CTRL) => {
- self.ctx.pop_word_search();
- *self.ctx.suppress_chars() = true;
- },
- _ => (),
- }
+ // Reset search delay when the user is still typing.
+ if self.ctx.search_active() {
+ if let Some(timer) = self.ctx.scheduler_mut().get_mut(TimerId::DelayedSearch) {
+ timer.deadline = Instant::now() + TYPING_SEARCH_DELAY;
+ }
+ }
- // Reset search delay when the user is still typing.
- if let Some(timer) = self.ctx.scheduler_mut().get_mut(TimerId::DelayedSearch) {
- timer.deadline = Instant::now() + TYPING_SEARCH_DELAY;
- }
- },
+ match input.state {
ElementState::Pressed => {
*self.ctx.received_count() = 0;
self.process_key_bindings(input);
@@ -877,14 +851,8 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
let suppress_chars = *self.ctx.suppress_chars();
let search_active = self.ctx.search_active();
if suppress_chars || self.ctx.terminal().mode().contains(TermMode::VI) || search_active {
- if search_active {
- // Skip control characters.
- let c_decimal = c as isize;
- let is_printable = (c_decimal >= 0x20 && c_decimal < 0x7f) || c_decimal >= 0xa0;
-
- if !suppress_chars && is_printable {
- self.ctx.push_search(c);
- }
+ if search_active && !suppress_chars {
+ self.ctx.search_input(c);
}
*self.ctx.suppress_chars() = false;
@@ -922,6 +890,7 @@ 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_key_bindings(&mut self, input: KeyboardInput) {
+ let mode = BindingMode::new(self.ctx.terminal().mode(), self.ctx.search_active());
let mods = *self.ctx.modifiers();
let mut suppress_chars = None;
@@ -934,7 +903,7 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
_ => continue,
};
- if binding.is_triggered_by(*self.ctx.terminal().mode(), mods, &key) {
+ if binding.is_triggered_by(mode, mods, &key) {
// Binding was triggered; run the action.
let binding = binding.clone();
binding.execute(&mut self.ctx);
@@ -953,14 +922,9 @@ 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 mode = BindingMode::new(self.ctx.terminal().mode(), self.ctx.search_active());
let mouse_mode = self.ctx.mouse_mode();
+ let mods = *self.ctx.modifiers();
for i in 0..self.ctx.config().ui_config.mouse_bindings.len() {
let mut binding = self.ctx.config().ui_config.mouse_bindings[i].clone();
@@ -1151,9 +1115,7 @@ mod tests {
fn cancel_search(&mut self) {}
- fn push_search(&mut self, _c: char) {}
-
- fn pop_search(&mut self) {}
+ fn search_input(&mut self, _c: char) {}
fn pop_word_search(&mut self) {}
@@ -1462,65 +1424,65 @@ mod tests {
test_process_binding! {
name: process_binding_nomode_shiftmod_require_shift,
- binding: Binding { trigger: KEY, mods: ModifiersState::SHIFT, action: Action::from("\x1b[1;2D"), mode: TermMode::NONE, notmode: TermMode::NONE },
+ binding: Binding { trigger: KEY, mods: ModifiersState::SHIFT, action: Action::from("\x1b[1;2D"), mode: BindingMode::empty(), notmode: BindingMode::empty() },
triggers: true,
- mode: TermMode::NONE,
+ mode: BindingMode::empty(),
mods: ModifiersState::SHIFT,
}
test_process_binding! {
name: process_binding_nomode_nomod_require_shift,
- binding: Binding { trigger: KEY, mods: ModifiersState::SHIFT, action: Action::from("\x1b[1;2D"), mode: TermMode::NONE, notmode: TermMode::NONE },
+ binding: Binding { trigger: KEY, mods: ModifiersState::SHIFT, action: Action::from("\x1b[1;2D"), mode: BindingMode::empty(), notmode: BindingMode::empty() },
triggers: false,
- mode: TermMode::NONE,
+ mode: BindingMode::empty(),
mods: ModifiersState::empty(),
}
test_process_binding! {
name: process_binding_nomode_controlmod,
- binding: Binding { trigger: KEY, mods: ModifiersState::CTRL, action: Action::from("\x1b[1;5D"), mode: TermMode::NONE, notmode: TermMode::NONE },
+ binding: Binding { trigger: KEY, mods: ModifiersState::CTRL, action: Action::from("\x1b[1;5D"), mode: BindingMode::empty(), notmode: BindingMode::empty() },
triggers: true,
- mode: TermMode::NONE,
+ mode: BindingMode::empty(),
mods: ModifiersState::CTRL,
}
test_process_binding! {
name: process_binding_nomode_nomod_require_not_appcursor,
- binding: Binding { trigger: KEY, mods: ModifiersState::empty(), action: Action::from("\x1b[D"), mode: TermMode::NONE, notmode: TermMode::APP_CURSOR },
+ binding: Binding { trigger: KEY, mods: ModifiersState::empty(), action: Action::from("\x1b[D"), mode: BindingMode::empty(), notmode: BindingMode::APP_CURSOR },
triggers: true,
- mode: TermMode::NONE,
+ mode: BindingMode::empty(),
mods: ModifiersState::empty(),
}
test_process_binding! {
name: process_binding_appcursormode_nomod_require_appcursor,
- binding: Binding { trigger: KEY, mods: ModifiersState::empty(), action: Action::from("\x1bOD"), mode: TermMode::APP_CURSOR, notmode: TermMode::NONE },
+ binding: Binding { trigger: KEY, mods: ModifiersState::empty(), action: Action::from("\x1bOD"), mode: BindingMode::APP_CURSOR, notmode: BindingMode::empty() },
triggers: true,
- mode: TermMode::APP_CURSOR,
+ mode: BindingMode::APP_CURSOR,
mods: ModifiersState::empty(),
}
test_process_binding! {
name: process_binding_nomode_nomod_require_appcursor,
- binding: Binding { trigger: KEY, mods: ModifiersState::empty(), action: Action::from("\x1bOD"), mode: TermMode::APP_CURSOR, notmode: TermMode::NONE },
+ binding: Binding { trigger: KEY, mods: ModifiersState::empty(), action: Action::from("\x1bOD"), mode: BindingMode::APP_CURSOR, notmode: BindingMode::empty() },
triggers: false,
- mode: TermMode::NONE,
+ mode: BindingMode::empty(),
mods: ModifiersState::empty(),
}
test_process_binding! {
name: process_binding_appcursormode_appkeypadmode_nomod_require_appcursor,
- binding: Binding { trigger: KEY, mods: ModifiersState::empty(), action: Action::from("\x1bOD"), mode: TermMode::APP_CURSOR, notmode: TermMode::NONE },
+ binding: Binding { trigger: KEY, mods: ModifiersState::empty(), action: Action::from("\x1bOD"), mode: BindingMode::APP_CURSOR, notmode: BindingMode::empty() },
triggers: true,
- mode: TermMode::APP_CURSOR | TermMode::APP_KEYPAD,
+ mode: BindingMode::APP_CURSOR | BindingMode::APP_KEYPAD,
mods: ModifiersState::empty(),
}
test_process_binding! {
name: process_binding_fail_with_extra_mods,
- binding: Binding { trigger: KEY, mods: ModifiersState::LOGO, action: Action::from("arst"), mode: TermMode::NONE, notmode: TermMode::NONE },
+ binding: Binding { trigger: KEY, mods: ModifiersState::LOGO, action: Action::from("arst"), mode: BindingMode::empty(), notmode: BindingMode::empty() },
triggers: false,
- mode: TermMode::NONE,
+ mode: BindingMode::empty(),
mods: ModifiersState::ALT | ModifiersState::LOGO,
}
}