summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Duerr <contact@christianduerr.com>2020-06-23 09:57:15 +0000
committerGitHub <noreply@github.com>2020-06-23 12:57:15 +0300
commit43c0ad6ea9d2467ccf867a310c4f1e30f5b627c6 (patch)
tree18ca8bad91c9ca47d22fca45222566a462aaa303
parent87e5b1aa25ea61937fa5f79668d2a46e88707c5e (diff)
downloadalacritty-43c0ad6ea9d2467ccf867a310c4f1e30f5b627c6.tar.gz
alacritty-43c0ad6ea9d2467ccf867a310c4f1e30f5b627c6.zip
Add selection expansion
This allows for expanding the selection using the right mouse button. The new selection type depends on the number of clicks and applies to both sides of the selection. Fixes #1554.
-rw-r--r--CHANGELOG.md1
-rw-r--r--alacritty/src/event.rs4
-rw-r--r--alacritty/src/input.rs113
-rw-r--r--alacritty/src/scheduler.rs8
4 files changed, 83 insertions, 43 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b5abe418..84d34746 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Support for Fontconfig embolden and matrix options
- Opt-out compilation flag `winpty` to disable WinPTY support
- Scrolling during selection when mouse is at top/bottom of window
+- Expanding existing selections using the right mouse button
### Changed
diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs
index 084ebe1e..630e8ef0 100644
--- a/alacritty/src/event.rs
+++ b/alacritty/src/event.rs
@@ -15,7 +15,7 @@ use std::sync::Arc;
use std::time::Instant;
use glutin::dpi::PhysicalSize;
-use glutin::event::{ElementState, Event as GlutinEvent, ModifiersState, WindowEvent};
+use glutin::event::{ElementState, Event as GlutinEvent, ModifiersState, MouseButton, WindowEvent};
use glutin::event_loop::{ControlFlow, EventLoop, EventLoopProxy, EventLoopWindowTarget};
use glutin::platform::desktop::EventLoopExtDesktop;
#[cfg(not(any(target_os = "macos", windows)))]
@@ -351,6 +351,7 @@ pub struct Mouse {
pub middle_button_state: ElementState,
pub right_button_state: ElementState,
pub last_click_timestamp: Instant,
+ pub last_click_button: MouseButton,
pub click_state: ClickState,
pub scroll_px: f64,
pub line: Line,
@@ -367,6 +368,7 @@ impl Default for Mouse {
x: 0,
y: 0,
last_click_timestamp: Instant::now(),
+ last_click_button: MouseButton::Left,
left_button_state: ElementState::Released,
middle_button_state: ElementState::Released,
right_button_state: ElementState::Released,
diff --git a/alacritty/src/input.rs b/alacritty/src/input.rs
index d43bb26f..b0a6eb80 100644
--- a/alacritty/src/input.rs
+++ b/alacritty/src/input.rs
@@ -492,44 +492,80 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
};
self.mouse_report(code, ElementState::Pressed);
- } else if button == MouseButton::Left {
- self.on_left_click();
} else {
- // Do nothing when using buttons other than LMB.
- self.ctx.mouse_mut().click_state = ClickState::None;
+ // Calculate time since the last click to handle double/triple clicks.
+ let now = Instant::now();
+ let elapsed = now - self.ctx.mouse().last_click_timestamp;
+ self.ctx.mouse_mut().last_click_timestamp = now;
+
+ // Update multi-click state.
+ let mouse_config = &self.ctx.config().ui_config.mouse;
+ self.ctx.mouse_mut().click_state = match self.ctx.mouse().click_state {
+ // Reset click state if button has changed.
+ _ if button != self.ctx.mouse().last_click_button => {
+ self.ctx.mouse_mut().last_click_button = button;
+ ClickState::Click
+ },
+ ClickState::Click if elapsed < mouse_config.double_click.threshold => {
+ ClickState::DoubleClick
+ },
+ ClickState::DoubleClick if elapsed < mouse_config.triple_click.threshold => {
+ ClickState::TripleClick
+ },
+ _ => ClickState::Click,
+ };
+
+ // Load mouse point, treating message bar and padding as the closest cell.
+ let mouse = self.ctx.mouse();
+ let mut point = self.ctx.size_info().pixels_to_coords(mouse.x, mouse.y);
+ point.line = min(point.line, self.ctx.terminal().grid().num_lines() - 1);
+
+ match button {
+ MouseButton::Left => self.on_left_click(point),
+ MouseButton::Right => self.on_right_click(point),
+ // Do nothing when using buttons other than LMB.
+ _ => self.ctx.mouse_mut().click_state = ClickState::None,
+ }
}
}
- /// Handle left click selection and vi mode cursor movement.
- fn on_left_click(&mut self) {
- // Calculate time since the last click to handle double/triple clicks in normal mode.
- let now = Instant::now();
- let elapsed = now - self.ctx.mouse().last_click_timestamp;
- self.ctx.mouse_mut().last_click_timestamp = now;
+ /// Handle selection expansion on right click.
+ fn on_right_click(&mut self, point: Point) {
+ match self.ctx.mouse().click_state {
+ ClickState::Click => {
+ let selection_type = if self.ctx.modifiers().ctrl() {
+ SelectionType::Block
+ } else {
+ SelectionType::Simple
+ };
- // Load mouse point, treating message bar and padding as closest cell.
- let mouse = self.ctx.mouse();
- let mut point = self.ctx.size_info().pixels_to_coords(mouse.x, mouse.y);
- point.line = min(point.line, self.ctx.terminal().grid().num_lines() - 1);
+ self.expand_selection(point, selection_type);
+ },
+ ClickState::DoubleClick => self.expand_selection(point, SelectionType::Semantic),
+ ClickState::TripleClick => self.expand_selection(point, SelectionType::Lines),
+ ClickState::None => (),
+ }
+ }
+
+ /// Expand existing selection.
+ fn expand_selection(&mut self, point: Point, selection_type: SelectionType) {
+ let cell_side = self.ctx.mouse().cell_side;
+
+ let selection = match &mut self.ctx.terminal_mut().selection {
+ Some(selection) => selection,
+ None => return,
+ };
+
+ selection.ty = selection_type;
+ self.ctx.update_selection(point, cell_side);
+ }
+ /// Handle left click selection and vi mode cursor movement.
+ fn on_left_click(&mut self, point: Point) {
let side = self.ctx.mouse().cell_side;
- self.ctx.mouse_mut().click_state = match self.ctx.mouse().click_state {
- ClickState::Click
- if elapsed < self.ctx.config().ui_config.mouse.double_click.threshold =>
- {
- self.ctx.mouse_mut().block_url_launcher = true;
- self.ctx.start_selection(SelectionType::Semantic, point, side);
- ClickState::DoubleClick
- }
- ClickState::DoubleClick
- if elapsed < self.ctx.config().ui_config.mouse.triple_click.threshold =>
- {
- self.ctx.mouse_mut().block_url_launcher = true;
- self.ctx.start_selection(SelectionType::Lines, point, side);
- ClickState::TripleClick
- }
- _ => {
+ match self.ctx.mouse().click_state {
+ ClickState::Click => {
// Don't launch URLs if this click cleared the selection.
self.ctx.mouse_mut().block_url_launcher = !self.ctx.selection_is_empty();
@@ -541,9 +577,16 @@ impl<'a, T: EventListener, A: ActionContext<T>> Processor<'a, T, A> {
} else {
self.ctx.start_selection(SelectionType::Simple, point, side);
}
-
- ClickState::Click
},
+ ClickState::DoubleClick => {
+ self.ctx.mouse_mut().block_url_launcher = true;
+ self.ctx.start_selection(SelectionType::Semantic, point, side);
+ },
+ ClickState::TripleClick => {
+ self.ctx.mouse_mut().block_url_launcher = true;
+ self.ctx.start_selection(SelectionType::Lines, point, side);
+ },
+ ClickState::None => (),
};
// Move vi mode cursor to mouse position.
@@ -1080,7 +1123,7 @@ mod tests {
unimplemented!();
}
- fn scheduler_mut (&mut self) -> &mut Scheduler {
+ fn scheduler_mut(&mut self) -> &mut Scheduler {
unimplemented!();
}
}
@@ -1209,7 +1252,7 @@ mod tests {
},
window_id: unsafe { std::mem::transmute_copy(&0) },
},
- end_state: ClickState::None,
+ end_state: ClickState::Click,
}
test_clickstate! {
@@ -1273,7 +1316,7 @@ mod tests {
},
window_id: unsafe { std::mem::transmute_copy(&0) },
},
- end_state: ClickState::None,
+ end_state: ClickState::Click,
}
test_process_binding! {
diff --git a/alacritty/src/scheduler.rs b/alacritty/src/scheduler.rs
index a6559acc..673029ae 100644
--- a/alacritty/src/scheduler.rs
+++ b/alacritty/src/scheduler.rs
@@ -46,13 +46,7 @@ impl Scheduler {
}
/// Schedule a new event.
- pub fn schedule(
- &mut self,
- event: Event,
- interval: Duration,
- repeat: bool,
- timer_id: TimerId,
- ) {
+ pub fn schedule(&mut self, event: Event, interval: Duration, repeat: bool, timer_id: TimerId) {
let deadline = Instant::now() + interval;
// Get insert position in the schedule.