summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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.