diff options
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | alacritty/src/event.rs | 4 | ||||
-rw-r--r-- | alacritty/src/input.rs | 113 | ||||
-rw-r--r-- | alacritty/src/scheduler.rs | 8 |
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. |