mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-18 13:55:23 -05:00
parent
629ea247cd
commit
ad0365219f
5 changed files with 112 additions and 65 deletions
|
@ -40,6 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- URL parser incorrectly handling Markdown URLs and angled brackets
|
||||
- Intermediate bytes of CSI sequences not checked
|
||||
- Wayland clipboard integration
|
||||
- Use text mouse cursor when mouse mode is temporarily disabled with shift
|
||||
|
||||
## 0.3.3
|
||||
|
||||
|
|
|
@ -52,11 +52,7 @@ fn parse_rgb_color(color: &[u8]) -> Option<Rgb> {
|
|||
Some((255 * value / max) as u8)
|
||||
};
|
||||
|
||||
Some(Rgb {
|
||||
r: scale(colors[0])?,
|
||||
g: scale(colors[1])?,
|
||||
b: scale(colors[2])?,
|
||||
})
|
||||
Some(Rgb { r: scale(colors[0])?, g: scale(colors[1])?, b: scale(colors[2])? })
|
||||
}
|
||||
|
||||
// Parse colors in `#r(rrr)g(ggg)b(bbb)` format
|
||||
|
@ -1449,8 +1445,8 @@ pub mod C1 {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{
|
||||
parse_number, xparse_color, Attr, CharsetIndex, Color, Handler, Processor,
|
||||
StandardCharset, TermInfo,
|
||||
parse_number, xparse_color, Attr, CharsetIndex, Color, Handler, Processor, StandardCharset,
|
||||
TermInfo,
|
||||
};
|
||||
use crate::index::{Column, Line};
|
||||
use crate::term::color::Rgb;
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::sync::mpsc;
|
|||
use std::time::Instant;
|
||||
|
||||
use glutin::dpi::PhysicalSize;
|
||||
use glutin::{self, ElementState, Event, ModifiersState, MouseButton};
|
||||
use glutin::{self, ElementState, Event, MouseButton};
|
||||
use parking_lot::MutexGuard;
|
||||
|
||||
use crate::clipboard::ClipboardType;
|
||||
|
@ -15,7 +15,7 @@ use crate::config::{self, Config, StartupMode};
|
|||
use crate::display::OnResize;
|
||||
use crate::grid::Scroll;
|
||||
use crate::index::{Column, Line, Point, Side};
|
||||
use crate::input::{self, KeyBinding, MouseBinding};
|
||||
use crate::input::{self, KeyBinding, Modifiers, MouseBinding};
|
||||
use crate::selection::Selection;
|
||||
use crate::sync::FairMutex;
|
||||
use crate::term::{SizeInfo, Term};
|
||||
|
@ -39,7 +39,7 @@ pub struct ActionContext<'a, N> {
|
|||
pub mouse: &'a mut Mouse,
|
||||
pub received_count: &'a mut usize,
|
||||
pub suppress_chars: &'a mut bool,
|
||||
pub last_modifiers: &'a mut ModifiersState,
|
||||
pub modifiers: &'a mut Modifiers,
|
||||
pub window_changes: &'a mut WindowChanges,
|
||||
}
|
||||
|
||||
|
@ -141,8 +141,8 @@ impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn last_modifiers(&mut self) -> &mut ModifiersState {
|
||||
&mut self.last_modifiers
|
||||
fn modifiers(&mut self) -> &mut Modifiers {
|
||||
&mut self.modifiers
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -287,7 +287,7 @@ pub struct Processor<N> {
|
|||
hide_mouse: bool,
|
||||
received_count: usize,
|
||||
suppress_chars: bool,
|
||||
last_modifiers: ModifiersState,
|
||||
modifiers: Modifiers,
|
||||
pending_events: Vec<Event>,
|
||||
window_changes: WindowChanges,
|
||||
save_to_clipboard: bool,
|
||||
|
@ -331,7 +331,7 @@ impl<N: Notify> Processor<N> {
|
|||
hide_mouse: false,
|
||||
received_count: 0,
|
||||
suppress_chars: false,
|
||||
last_modifiers: Default::default(),
|
||||
modifiers: Default::default(),
|
||||
pending_events: Vec::with_capacity(4),
|
||||
window_changes: Default::default(),
|
||||
save_to_clipboard: config.selection.save_to_clipboard,
|
||||
|
@ -406,11 +406,9 @@ impl<N: Notify> Processor<N> {
|
|||
*window_is_focused = is_focused;
|
||||
|
||||
if is_focused {
|
||||
processor.ctx.terminal.dirty = true;
|
||||
processor.ctx.terminal.next_is_urgent = Some(false);
|
||||
processor.ctx.terminal.dirty = true;
|
||||
} else {
|
||||
processor.ctx.terminal.reset_url_highlight();
|
||||
processor.ctx.terminal.reset_mouse_cursor();
|
||||
processor.ctx.terminal.dirty = true;
|
||||
*hide_mouse = false;
|
||||
}
|
||||
|
@ -426,6 +424,7 @@ impl<N: Notify> Processor<N> {
|
|||
processor.ctx.size_info.dpr = new_dpr;
|
||||
processor.ctx.terminal.dirty = true;
|
||||
},
|
||||
CursorLeft { .. } => processor.ctx.terminal.reset_url_highlight(),
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
|
@ -478,7 +477,7 @@ impl<N: Notify> Processor<N> {
|
|||
size_info: &mut self.size_info,
|
||||
received_count: &mut self.received_count,
|
||||
suppress_chars: &mut self.suppress_chars,
|
||||
last_modifiers: &mut self.last_modifiers,
|
||||
modifiers: &mut self.modifiers,
|
||||
window_changes: &mut self.window_changes,
|
||||
};
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ use std::time::Instant;
|
|||
|
||||
use glutin::{
|
||||
ElementState, KeyboardInput, ModifiersState, MouseButton, MouseCursor, MouseScrollDelta,
|
||||
TouchPhase,
|
||||
TouchPhase, VirtualKeyCode,
|
||||
};
|
||||
|
||||
use crate::ansi::{ClearMode, Handler};
|
||||
|
@ -73,7 +73,7 @@ pub trait ActionContext {
|
|||
fn mouse_coords(&self) -> Option<Point>;
|
||||
fn received_count(&mut self) -> &mut usize;
|
||||
fn suppress_chars(&mut self) -> &mut bool;
|
||||
fn last_modifiers(&mut self) -> &mut ModifiersState;
|
||||
fn modifiers(&mut self) -> &mut Modifiers;
|
||||
fn scroll(&mut self, scroll: Scroll);
|
||||
fn hide_window(&mut self);
|
||||
fn terminal(&self) -> &Term;
|
||||
|
@ -84,6 +84,47 @@ pub trait ActionContext {
|
|||
fn toggle_simple_fullscreen(&mut self);
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
pub struct Modifiers {
|
||||
mods: ModifiersState,
|
||||
lshift: bool,
|
||||
rshift: bool,
|
||||
}
|
||||
|
||||
impl Modifiers {
|
||||
pub fn update(&mut self, input: KeyboardInput) {
|
||||
match input.virtual_keycode {
|
||||
Some(VirtualKeyCode::LShift) => self.lshift = input.state == ElementState::Pressed,
|
||||
Some(VirtualKeyCode::RShift) => self.rshift = input.state == ElementState::Pressed,
|
||||
_ => (),
|
||||
}
|
||||
|
||||
self.mods = input.modifiers;
|
||||
}
|
||||
|
||||
pub fn shift(self) -> bool {
|
||||
self.lshift || self.rshift
|
||||
}
|
||||
|
||||
pub fn ctrl(self) -> bool {
|
||||
self.mods.ctrl
|
||||
}
|
||||
|
||||
pub fn logo(self) -> bool {
|
||||
self.mods.logo
|
||||
}
|
||||
|
||||
pub fn alt(self) -> bool {
|
||||
self.mods.alt
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Modifiers> for ModifiersState {
|
||||
fn from(mods: Modifiers) -> ModifiersState {
|
||||
ModifiersState { shift: mods.shift(), ..mods.mods }
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes a state and action to take in that state
|
||||
///
|
||||
/// This is the shared component of `MouseBinding` and `KeyBinding`
|
||||
|
@ -381,41 +422,48 @@ impl From<&'static str> for Action {
|
|||
}
|
||||
}
|
||||
|
||||
enum MousePosition {
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub enum MouseState {
|
||||
Url(Url),
|
||||
MessageBar,
|
||||
MessageBarButton,
|
||||
Terminal,
|
||||
Mouse,
|
||||
Text,
|
||||
}
|
||||
|
||||
impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
||||
fn mouse_position(&mut self, point: Point, modifiers: ModifiersState) -> MousePosition {
|
||||
fn mouse_state(&mut self, point: Point) -> MouseState {
|
||||
let mouse_mode =
|
||||
TermMode::MOUSE_MOTION | TermMode::MOUSE_DRAG | TermMode::MOUSE_REPORT_CLICK;
|
||||
|
||||
// Check message bar before URL to ignore URLs in the message bar
|
||||
if let Some(message) = self.message_at_point(Some(point)) {
|
||||
if self.message_close_at_point(point, message) {
|
||||
return MousePosition::MessageBarButton;
|
||||
return MouseState::MessageBarButton;
|
||||
} else {
|
||||
return MousePosition::MessageBar;
|
||||
return MouseState::MessageBar;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for URL at point with required modifiers held
|
||||
if self.mouse_config.url.mods().relaxed_eq(modifiers)
|
||||
&& (!self.ctx.terminal().mode().intersects(mouse_mode) || modifiers.shift)
|
||||
let mods = *self.ctx.modifiers();
|
||||
if self.mouse_config.url.mods().relaxed_eq(mods.into())
|
||||
&& (!self.ctx.terminal().mode().intersects(mouse_mode) || mods.shift())
|
||||
&& self.mouse_config.url.launcher.is_some()
|
||||
{
|
||||
let buffer_point = self.ctx.terminal().visible_to_buffer(point);
|
||||
if let Some(url) =
|
||||
self.ctx.terminal().urls().drain(..).find(|url| url.contains(buffer_point))
|
||||
{
|
||||
return MousePosition::Url(url);
|
||||
return MouseState::Url(url);
|
||||
}
|
||||
}
|
||||
|
||||
MousePosition::Terminal
|
||||
if self.ctx.terminal().mode().intersects(mouse_mode) && !self.ctx.modifiers().shift() {
|
||||
MouseState::Mouse
|
||||
} else {
|
||||
MouseState::Text
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -445,27 +493,18 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
|||
// Don't launch URLs if mouse has moved
|
||||
self.ctx.mouse_mut().block_url_launcher = true;
|
||||
|
||||
match self.mouse_position(point, modifiers) {
|
||||
MousePosition::Url(url) => {
|
||||
let mouse_state = self.mouse_state(point);
|
||||
self.update_mouse_cursor(mouse_state);
|
||||
match mouse_state {
|
||||
MouseState::Url(url) => {
|
||||
let url_bounds = url.linear_bounds(self.ctx.terminal());
|
||||
self.ctx.terminal_mut().set_url_highlight(url_bounds);
|
||||
self.ctx.terminal_mut().set_mouse_cursor(MouseCursor::Hand);
|
||||
self.ctx.terminal_mut().dirty = true;
|
||||
},
|
||||
MousePosition::MessageBar => {
|
||||
MouseState::MessageBar | MouseState::MessageBarButton => {
|
||||
self.ctx.terminal_mut().reset_url_highlight();
|
||||
self.ctx.terminal_mut().set_mouse_cursor(MouseCursor::Default);
|
||||
return;
|
||||
},
|
||||
MousePosition::MessageBarButton => {
|
||||
self.ctx.terminal_mut().reset_url_highlight();
|
||||
self.ctx.terminal_mut().set_mouse_cursor(MouseCursor::Hand);
|
||||
return;
|
||||
},
|
||||
MousePosition::Terminal => {
|
||||
self.ctx.terminal_mut().reset_url_highlight();
|
||||
self.ctx.terminal_mut().reset_mouse_cursor();
|
||||
},
|
||||
_ => self.ctx.terminal_mut().reset_url_highlight(),
|
||||
}
|
||||
|
||||
if self.ctx.mouse().left_button_state == ElementState::Pressed
|
||||
|
@ -798,9 +837,20 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
|||
|
||||
/// Process key input
|
||||
pub fn process_key(&mut self, input: KeyboardInput) {
|
||||
self.ctx.modifiers().update(input);
|
||||
|
||||
// Update mouse cursor for temporarily disabling mouse mode
|
||||
if input.virtual_keycode == Some(VirtualKeyCode::LShift)
|
||||
|| input.virtual_keycode == Some(VirtualKeyCode::RShift)
|
||||
{
|
||||
if let Some(point) = self.ctx.mouse_coords() {
|
||||
let mouse_state = self.mouse_state(point);
|
||||
self.update_mouse_cursor(mouse_state);
|
||||
}
|
||||
}
|
||||
|
||||
match input.state {
|
||||
ElementState::Pressed => {
|
||||
*self.ctx.last_modifiers() = input.modifiers;
|
||||
*self.ctx.received_count() = 0;
|
||||
*self.ctx.suppress_chars() = false;
|
||||
|
||||
|
@ -830,7 +880,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
|||
|
||||
if self.alt_send_esc
|
||||
&& *self.ctx.received_count() == 0
|
||||
&& self.ctx.last_modifiers().alt
|
||||
&& self.ctx.modifiers().alt()
|
||||
&& utf8_len == 1
|
||||
{
|
||||
bytes.insert(0, b'\x1b');
|
||||
|
@ -934,8 +984,9 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
|||
ElementState::Released => self.copy_selection(),
|
||||
ElementState::Pressed => {
|
||||
if self.message_close_at_point(point, message) {
|
||||
let mouse_state = self.mouse_state(point);
|
||||
self.update_mouse_cursor(mouse_state);
|
||||
self.ctx.terminal_mut().message_buffer_mut().pop();
|
||||
self.ctx.terminal_mut().reset_mouse_cursor();
|
||||
}
|
||||
|
||||
self.ctx.clear_selection();
|
||||
|
@ -950,6 +1001,17 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
|||
}
|
||||
self.ctx.copy_selection(ClipboardType::Selection);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn update_mouse_cursor(&mut self, mouse_state: MouseState) {
|
||||
let mouse_cursor = match mouse_state {
|
||||
MouseState::Url(_) | MouseState::MessageBarButton => MouseCursor::Hand,
|
||||
MouseState::Text => MouseCursor::Text,
|
||||
_ => MouseCursor::Default,
|
||||
};
|
||||
|
||||
self.ctx.terminal_mut().set_mouse_cursor(mouse_cursor);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -968,7 +1030,7 @@ mod tests {
|
|||
use crate::selection::Selection;
|
||||
use crate::term::{SizeInfo, Term, TermMode};
|
||||
|
||||
use super::{Action, Binding, Processor};
|
||||
use super::{Action, Binding, Modifiers, Processor};
|
||||
|
||||
const KEY: VirtualKeyCode = VirtualKeyCode::Key0;
|
||||
|
||||
|
@ -1112,7 +1174,7 @@ mod tests {
|
|||
pub last_action: MultiClick,
|
||||
pub received_count: usize,
|
||||
pub suppress_chars: bool,
|
||||
pub last_modifiers: ModifiersState,
|
||||
pub modifiers: Modifiers,
|
||||
pub window_changes: &'a mut WindowChanges,
|
||||
}
|
||||
|
||||
|
@ -1189,8 +1251,8 @@ mod tests {
|
|||
&mut self.suppress_chars
|
||||
}
|
||||
|
||||
fn last_modifiers(&mut self) -> &mut ModifiersState {
|
||||
&mut self.last_modifiers
|
||||
fn modifiers(&mut self) -> &mut Modifiers {
|
||||
&mut self.modifiers
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1232,7 +1294,7 @@ mod tests {
|
|||
last_action: MultiClick::None,
|
||||
received_count: 0,
|
||||
suppress_chars: false,
|
||||
last_modifiers: ModifiersState::default(),
|
||||
modifiers: Default::default(),
|
||||
window_changes: &mut WindowChanges::default(),
|
||||
};
|
||||
|
||||
|
|
|
@ -841,9 +841,9 @@ impl Term {
|
|||
|
||||
#[inline]
|
||||
pub fn scroll_display(&mut self, scroll: Scroll) {
|
||||
self.set_mouse_cursor(MouseCursor::Text);
|
||||
self.grid.scroll_display(scroll);
|
||||
self.reset_url_highlight();
|
||||
self.reset_mouse_cursor();
|
||||
self.dirty = true;
|
||||
}
|
||||
|
||||
|
@ -1296,18 +1296,7 @@ impl Term {
|
|||
#[inline]
|
||||
pub fn set_url_highlight(&mut self, hl: RangeInclusive<index::Linear>) {
|
||||
self.grid.url_highlight = Some(hl);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn reset_mouse_cursor(&mut self) {
|
||||
let mouse_mode =
|
||||
TermMode::MOUSE_MOTION | TermMode::MOUSE_DRAG | TermMode::MOUSE_REPORT_CLICK;
|
||||
let mouse_cursor = if self.mode().intersects(mouse_mode) {
|
||||
MouseCursor::Default
|
||||
} else {
|
||||
MouseCursor::Text
|
||||
};
|
||||
self.set_mouse_cursor(mouse_cursor);
|
||||
self.dirty = true;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
Loading…
Reference in a new issue