aboutsummaryrefslogtreecommitdiff
path: root/alacritty/src/event.rs
diff options
context:
space:
mode:
authorChristian Duerr <contact@christianduerr.com>2020-03-18 02:35:08 +0000
committerGitHub <noreply@github.com>2020-03-18 02:35:08 +0000
commit1a8cd172e520e493bacc9c6a2ae6f80de086eaa3 (patch)
tree0b837f1f52f72fe00e258afc34094d60b5d18f04 /alacritty/src/event.rs
parent64db7d3daaed4e06fb8292227622bbc4cdaa2cf0 (diff)
downloadr-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.rs88
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);