Fix cursor flickering on url hover
This commit fixes the regression introduced in 84aca67
and also fixes url
highlight bounds computation when url ends on a last column.
Fixes #2665.
This commit is contained in:
parent
14a48a2533
commit
72dfa477a9
|
@ -410,6 +410,7 @@ impl<N: Notify> Processor<N> {
|
||||||
processor.ctx.terminal.next_is_urgent = Some(false);
|
processor.ctx.terminal.next_is_urgent = Some(false);
|
||||||
} else {
|
} else {
|
||||||
processor.ctx.terminal.reset_url_highlight();
|
processor.ctx.terminal.reset_url_highlight();
|
||||||
|
processor.ctx.terminal.reset_mouse_cursor();
|
||||||
processor.ctx.terminal.dirty = true;
|
processor.ctx.terminal.dirty = true;
|
||||||
*hide_mouse = false;
|
*hide_mouse = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -383,7 +383,30 @@ impl From<&'static str> for Action {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum MousePosition {
|
||||||
|
Url(Url),
|
||||||
|
MessageBar,
|
||||||
|
MessageBarButton,
|
||||||
|
Terminal,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
||||||
|
fn mouse_position(&mut self, point: Point) -> MousePosition {
|
||||||
|
if let Some(message) = self.message_at_point(Some(point)) {
|
||||||
|
if self.message_close_at_point(point, message) {
|
||||||
|
MousePosition::MessageBarButton
|
||||||
|
} else {
|
||||||
|
MousePosition::MessageBar
|
||||||
|
}
|
||||||
|
// Check for url should be after check for message bar, since we're not looking into
|
||||||
|
// message bar content.
|
||||||
|
} else if let Some(url) = self.ctx.terminal().url_search(point.into()) {
|
||||||
|
MousePosition::Url(url)
|
||||||
|
} else {
|
||||||
|
MousePosition::Terminal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mouse_moved(&mut self, x: usize, y: usize, modifiers: ModifiersState) {
|
pub fn mouse_moved(&mut self, x: usize, y: usize, modifiers: ModifiersState) {
|
||||||
self.ctx.mouse_mut().x = x;
|
self.ctx.mouse_mut().x = x;
|
||||||
|
@ -408,21 +431,38 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only report motions when cell changed and mouse is not over the message bar
|
|
||||||
if let Some(message) = self.message_at_point(Some(point)) {
|
|
||||||
self.update_message_cursor(point, message);
|
|
||||||
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
self.ctx.terminal_mut().reset_mouse_cursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't launch URLs if mouse has moved
|
// Don't launch URLs if mouse has moved
|
||||||
self.ctx.mouse_mut().block_url_launcher = true;
|
self.ctx.mouse_mut().block_url_launcher = true;
|
||||||
|
|
||||||
// Underline URLs and change cursor on hover
|
match self.mouse_position(point) {
|
||||||
if cell_changed {
|
MousePosition::Url(url) => {
|
||||||
self.update_url_highlight(point, modifiers);
|
let mouse_mode =
|
||||||
|
TermMode::MOUSE_MOTION | TermMode::MOUSE_DRAG | TermMode::MOUSE_REPORT_CLICK;
|
||||||
|
|
||||||
|
if self.mouse_config.url.mods().relaxed_eq(modifiers)
|
||||||
|
&& (!self.ctx.terminal().mode().intersects(mouse_mode) || modifiers.shift)
|
||||||
|
&& self.mouse_config.url.launcher.is_some()
|
||||||
|
{
|
||||||
|
let url_bounds = self.url_bounds_at_point(url, point);
|
||||||
|
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 => {
|
||||||
|
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();
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.ctx.mouse().left_button_state == ElementState::Pressed
|
if self.ctx.mouse().left_button_state == ElementState::Pressed
|
||||||
|
@ -445,22 +485,8 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Underline URLs and change the mouse cursor when URL hover state changes.
|
fn url_bounds_at_point(&self, url: Url, point: Point) -> RangeInclusive<Linear> {
|
||||||
fn update_url_highlight(&mut self, point: Point, modifiers: ModifiersState) {
|
let Url { origin, text } = url;
|
||||||
let mouse_mode =
|
|
||||||
TermMode::MOUSE_MOTION | TermMode::MOUSE_DRAG | TermMode::MOUSE_REPORT_CLICK;
|
|
||||||
|
|
||||||
// Only show URLs as launchable when all required modifiers are pressed
|
|
||||||
let url = if self.mouse_config.url.mods().relaxed_eq(modifiers)
|
|
||||||
&& (!self.ctx.terminal().mode().intersects(mouse_mode) || modifiers.shift)
|
|
||||||
&& self.mouse_config.url.launcher.is_some()
|
|
||||||
{
|
|
||||||
self.ctx.terminal().url_search(point.into())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(Url { origin, text }) = url {
|
|
||||||
let cols = self.ctx.size_info().cols().0;
|
let cols = self.ctx.size_info().cols().0;
|
||||||
|
|
||||||
// Calculate the URL's start position
|
// Calculate the URL's start position
|
||||||
|
@ -472,23 +498,32 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
||||||
let start_line = point.line.0 - lines_before;
|
let start_line = point.line.0 - lines_before;
|
||||||
(start_col, start_line)
|
(start_col, start_line)
|
||||||
};
|
};
|
||||||
|
|
||||||
let start = Point::new(start_line, Column(start_col));
|
let start = Point::new(start_line, Column(start_col));
|
||||||
|
|
||||||
// Calculate the URL's end position
|
// Calculate the URL's highlight end position
|
||||||
let len = text.width();
|
let len = text.width();
|
||||||
let end_col = (point.col.0 + len - origin) % cols - 1;
|
let url_end_col_denormilized = point.col.0 + len - origin;
|
||||||
let end_line = point.line.0 + (point.col.0 + len - origin) / cols;
|
|
||||||
|
// This means that url ends at the last cell of the line
|
||||||
|
let end_col = if url_end_col_denormilized % cols == 0 {
|
||||||
|
cols - 1
|
||||||
|
} else {
|
||||||
|
url_end_col_denormilized % cols - 1
|
||||||
|
};
|
||||||
|
|
||||||
|
let end_line = if end_col == cols - 1 {
|
||||||
|
point.line.0 + (url_end_col_denormilized) / cols - 1
|
||||||
|
} else {
|
||||||
|
point.line.0 + (url_end_col_denormilized) / cols
|
||||||
|
};
|
||||||
|
|
||||||
let end = Point::new(end_line, Column(end_col));
|
let end = Point::new(end_line, Column(end_col));
|
||||||
|
|
||||||
let start = Linear::from_point(Column(cols), start);
|
let start = Linear::from_point(Column(cols), start);
|
||||||
let end = Linear::from_point(Column(cols), end);
|
let end = Linear::from_point(Column(cols), end);
|
||||||
|
|
||||||
self.ctx.terminal_mut().set_url_highlight(RangeInclusive::new(start, end));
|
RangeInclusive::new(start, end)
|
||||||
self.ctx.terminal_mut().set_mouse_cursor(MouseCursor::Hand);
|
|
||||||
self.ctx.terminal_mut().dirty = true;
|
|
||||||
} else {
|
|
||||||
self.ctx.terminal_mut().reset_url_highlight();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_mouse_side(&self) -> Side {
|
fn get_mouse_side(&self) -> Side {
|
||||||
|
@ -908,15 +943,6 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
||||||
has_binding
|
has_binding
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the cursor depending on where the mouse is on the message bar
|
|
||||||
fn update_message_cursor(&mut self, point: Point, message: Message) {
|
|
||||||
if self.message_close_at_point(point, message) {
|
|
||||||
self.ctx.terminal_mut().set_mouse_cursor(MouseCursor::Hand);
|
|
||||||
} else {
|
|
||||||
self.ctx.terminal_mut().set_mouse_cursor(MouseCursor::Default);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the message bar's message if there is some at the specified point
|
/// Return the message bar's message if there is some at the specified point
|
||||||
fn message_at_point(&mut self, point: Option<Point>) -> Option<Message> {
|
fn message_at_point(&mut self, point: Option<Point>) -> Option<Message> {
|
||||||
if let (Some(point), Some(message)) =
|
if let (Some(point), Some(message)) =
|
||||||
|
@ -945,12 +971,8 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
||||||
ElementState::Pressed => {
|
ElementState::Pressed => {
|
||||||
if self.message_close_at_point(point, message) {
|
if self.message_close_at_point(point, message) {
|
||||||
self.ctx.terminal_mut().message_buffer_mut().pop();
|
self.ctx.terminal_mut().message_buffer_mut().pop();
|
||||||
if let Some(message) = self.message_at_point(Some(point)) {
|
|
||||||
self.update_message_cursor(point, message);
|
|
||||||
} else {
|
|
||||||
self.ctx.terminal_mut().reset_mouse_cursor();
|
self.ctx.terminal_mut().reset_mouse_cursor();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
self.ctx.clear_selection();
|
self.ctx.clear_selection();
|
||||||
},
|
},
|
||||||
|
|
|
@ -896,6 +896,7 @@ impl Term {
|
||||||
pub fn scroll_display(&mut self, scroll: Scroll) {
|
pub fn scroll_display(&mut self, scroll: Scroll) {
|
||||||
self.grid.scroll_display(scroll);
|
self.grid.scroll_display(scroll);
|
||||||
self.reset_url_highlight();
|
self.reset_url_highlight();
|
||||||
|
self.reset_mouse_cursor();
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1360,8 +1361,6 @@ impl Term {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reset_url_highlight(&mut self) {
|
pub fn reset_url_highlight(&mut self) {
|
||||||
self.reset_mouse_cursor();
|
|
||||||
|
|
||||||
self.grid.url_highlight = None;
|
self.grid.url_highlight = None;
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue