diff options
author | Christian Duerr <contact@christianduerr.com> | 2020-03-18 02:35:08 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-18 02:35:08 +0000 |
commit | 1a8cd172e520e493bacc9c6a2ae6f80de086eaa3 (patch) | |
tree | 0b837f1f52f72fe00e258afc34094d60b5d18f04 /alacritty/src/event.rs | |
parent | 64db7d3daaed4e06fb8292227622bbc4cdaa2cf0 (diff) | |
download | r-alacritty-1a8cd172e520e493bacc9c6a2ae6f80de086eaa3.tar.gz r-alacritty-1a8cd172e520e493bacc9c6a2ae6f80de086eaa3.tar.bz2 r-alacritty-1a8cd172e520e493bacc9c6a2ae6f80de086eaa3.zip |
Add modal keyboard motion mode
This implements a basic mode for navigating inside of Alacritty's
history with keyboard bindings. They're bound by default to vi's motion
shortcuts but are fully customizable. Since this relies on key bindings
only single key bindings are currently supported (so no `ge`, or
repetition).
Other than navigating the history and moving the viewport, this mode
should enable making use of all available selection modes to copy
content to the clipboard and launch URLs below the cursor.
This also changes the rendering of the block cursor at the side of
selections, since previously it could be inverted to be completely
invisible. Since that would have caused some troubles with this keyboard
selection mode, the block cursor now is no longer inverted when it is at
the edges of a selection.
Fixes #262.
Diffstat (limited to 'alacritty/src/event.rs')
-rw-r--r-- | alacritty/src/event.rs | 88 |
1 files changed, 63 insertions, 25 deletions
diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs index e635283b..9757893d 100644 --- a/alacritty/src/event.rs +++ b/alacritty/src/event.rs @@ -27,10 +27,10 @@ use alacritty_terminal::event::{Event, EventListener, Notify}; use alacritty_terminal::grid::Scroll; use alacritty_terminal::index::{Column, Line, Point, Side}; use alacritty_terminal::message_bar::{Message, MessageBuffer}; -use alacritty_terminal::selection::Selection; +use alacritty_terminal::selection::{Selection, SelectionType}; use alacritty_terminal::sync::FairMutex; use alacritty_terminal::term::cell::Cell; -use alacritty_terminal::term::{SizeInfo, Term}; +use alacritty_terminal::term::{SizeInfo, Term, TermMode}; #[cfg(not(windows))] use alacritty_terminal::tty; use alacritty_terminal::util::{limit, start_daemon}; @@ -40,6 +40,7 @@ use crate::config; use crate::config::Config; use crate::display::Display; use crate::input::{self, ActionContext as _, FONT_SIZE_STEP}; +use crate::url::{Url, Urls}; use crate::window::Window; #[derive(Default, Clone, Debug, PartialEq)] @@ -68,6 +69,7 @@ pub struct ActionContext<'a, N, T> { pub display_update_pending: &'a mut DisplayUpdate, pub config: &'a mut Config, pub event_loop: &'a EventLoopWindowTarget<Event>, + pub urls: &'a Urls, font_size: &'a mut Size, } @@ -83,7 +85,12 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon fn scroll(&mut self, scroll: Scroll) { self.terminal.scroll_display(scroll); - if let ElementState::Pressed = self.mouse().left_button_state { + // Update selection + if self.terminal.mode().contains(TermMode::VI) + && self.terminal.selection().as_ref().map(|s| s.is_empty()) != Some(true) + { + self.update_selection(self.terminal.vi_mode_cursor.point, Side::Right); + } else if ElementState::Pressed == self.mouse().left_button_state { let (x, y) = (self.mouse().x, self.mouse().y); let size_info = self.size_info(); let point = size_info.pixels_to_coords(x, y); @@ -113,35 +120,35 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon let point = self.terminal.visible_to_buffer(point); // Update selection if one exists - if let Some(ref mut selection) = self.terminal.selection_mut() { + let vi_mode = self.terminal.mode().contains(TermMode::VI); + if let Some(selection) = self.terminal.selection_mut() { selection.update(point, side); - } - - self.terminal.dirty = true; - } - fn simple_selection(&mut self, point: Point, side: Side) { - let point = self.terminal.visible_to_buffer(point); - *self.terminal.selection_mut() = Some(Selection::simple(point, side)); - self.terminal.dirty = true; - } + if vi_mode { + selection.include_all(); + } - fn block_selection(&mut self, point: Point, side: Side) { - let point = self.terminal.visible_to_buffer(point); - *self.terminal.selection_mut() = Some(Selection::block(point, side)); - self.terminal.dirty = true; + self.terminal.dirty = true; + } } - fn semantic_selection(&mut self, point: Point) { + fn start_selection(&mut self, ty: SelectionType, point: Point, side: Side) { let point = self.terminal.visible_to_buffer(point); - *self.terminal.selection_mut() = Some(Selection::semantic(point)); + *self.terminal.selection_mut() = Some(Selection::new(ty, point, side)); self.terminal.dirty = true; } - fn line_selection(&mut self, point: Point) { - let point = self.terminal.visible_to_buffer(point); - *self.terminal.selection_mut() = Some(Selection::lines(point)); - self.terminal.dirty = true; + fn toggle_selection(&mut self, ty: SelectionType, point: Point, side: Side) { + match self.terminal.selection_mut() { + Some(selection) if selection.ty == ty && !selection.is_empty() => { + self.clear_selection(); + }, + Some(selection) if !selection.is_empty() => { + selection.ty = ty; + self.terminal.dirty = true; + }, + _ => self.start_selection(ty, point, side), + } } fn mouse_coords(&self) -> Option<Point> { @@ -156,6 +163,12 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon } #[inline] + fn mouse_mode(&self) -> bool { + self.terminal.mode().intersects(TermMode::MOUSE_MODE) + && !self.terminal.mode().contains(TermMode::VI) + } + + #[inline] fn mouse_mut(&mut self) -> &mut Mouse { self.mouse } @@ -254,8 +267,32 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionCon fn event_loop(&self) -> &EventLoopWindowTarget<Event> { self.event_loop } + + fn urls(&self) -> &Urls { + self.urls + } + + /// Spawn URL launcher when clicking on URLs. + fn launch_url(&self, url: Url) { + if self.mouse.block_url_launcher { + return; + } + + if let Some(ref launcher) = self.config.ui_config.mouse.url.launcher { + let mut args = launcher.args().to_vec(); + let start = self.terminal.visible_to_buffer(url.start()); + let end = self.terminal.visible_to_buffer(url.end()); + args.push(self.terminal.bounds_to_string(start, end)); + + match start_daemon(launcher.program(), &args) { + Ok(_) => debug!("Launched {} with args {:?}", launcher.program(), args), + Err(_) => warn!("Unable to launch {} with args {:?}", launcher.program(), args), + } + } + } } +#[derive(Debug)] pub enum ClickState { None, Click, @@ -264,6 +301,7 @@ pub enum ClickState { } /// State of the mouse +#[derive(Debug)] pub struct Mouse { pub x: usize, pub y: usize, @@ -412,10 +450,10 @@ impl<N: Notify + OnResize> Processor<N> { window: &mut self.display.window, font_size: &mut self.font_size, config: &mut self.config, + urls: &self.display.urls, event_loop, }; - let mut processor = - input::Processor::new(context, &self.display.urls, &self.display.highlighted_url); + let mut processor = input::Processor::new(context, &self.display.highlighted_url); for event in event_queue.drain(..) { Processor::handle_event(event, &mut processor); |