Fix URL highlight crash
The URL highlight stores the state of the last URL highlight with the position of the URL start position. However when resizing, it's possible that the indices of this point change which will cause a crash if the old positions are not within the grid anymore. This has been resolved by resetting the URL highlight state whenever the terminal is resized. The original PR incorrectly required the shift modifier to be required when the user was in the alternate screen buffer. However the correct behavior is to require it when the mouse mode is enabled. This has been resolved and URLs are now highlighted in the alt screen even if no shift modifier is pressed. This fixes #2194.
This commit is contained in:
parent
d8272662db
commit
3e36d714fe
11
src/event.rs
11
src/event.rs
|
@ -10,7 +10,7 @@ use std::env;
|
|||
|
||||
use serde_json as json;
|
||||
use parking_lot::MutexGuard;
|
||||
use glutin::{self, ModifiersState, Event, ElementState, MouseButton, MouseCursor};
|
||||
use glutin::{self, ModifiersState, Event, ElementState, MouseButton};
|
||||
use copypasta::{Clipboard, Load, Store, Buffer as ClipboardBuffer};
|
||||
use glutin::dpi::PhysicalSize;
|
||||
|
||||
|
@ -222,13 +222,6 @@ pub enum ClickState {
|
|||
TripleClick,
|
||||
}
|
||||
|
||||
/// Temporary save state for restoring mouse cursor and underline after unhovering a URL.
|
||||
pub struct UrlHoverSaveState {
|
||||
pub mouse_cursor: MouseCursor,
|
||||
pub underlined: Vec<bool>,
|
||||
pub start: Point<usize>,
|
||||
}
|
||||
|
||||
/// State of the mouse
|
||||
pub struct Mouse {
|
||||
pub x: usize,
|
||||
|
@ -245,7 +238,6 @@ pub struct Mouse {
|
|||
pub lines_scrolled: f32,
|
||||
pub block_url_launcher: bool,
|
||||
pub last_button: MouseButton,
|
||||
pub url_hover_save: Option<UrlHoverSaveState>,
|
||||
}
|
||||
|
||||
impl Default for Mouse {
|
||||
|
@ -265,7 +257,6 @@ impl Default for Mouse {
|
|||
lines_scrolled: 0.0,
|
||||
block_url_launcher: false,
|
||||
last_button: MouseButton::Other(0),
|
||||
url_hover_save: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
34
src/input.rs
34
src/input.rs
|
@ -31,9 +31,9 @@ use glutin::{
|
|||
|
||||
use crate::config::{self, Key};
|
||||
use crate::grid::Scroll;
|
||||
use crate::event::{ClickState, Mouse, UrlHoverSaveState};
|
||||
use crate::event::{ClickState, Mouse};
|
||||
use crate::index::{Line, Column, Side, Point};
|
||||
use crate::term::{Term, SizeInfo, Search};
|
||||
use crate::term::{Term, SizeInfo, Search, UrlHoverSaveState};
|
||||
use crate::term::mode::TermMode;
|
||||
use crate::term::cell::Flags;
|
||||
use crate::util::fmt::Red;
|
||||
|
@ -440,7 +440,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
|||
|
||||
// Only show URLs as launchable when all required modifiers are pressed
|
||||
let url = if self.mouse_config.url.modifiers.relaxed_eq(modifiers)
|
||||
&& (!self.ctx.terminal().mode().contains(TermMode::ALT_SCREEN) || modifiers.shift)
|
||||
&& (!self.ctx.terminal().mode().intersects(mouse_mode) || modifiers.shift)
|
||||
{
|
||||
self.ctx.terminal().url_search(point.into())
|
||||
} else {
|
||||
|
@ -463,14 +463,12 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
|||
let start = Point::new(line, Column(col));
|
||||
|
||||
// Update URLs only on change, so they don't all get marked as underlined
|
||||
if self.ctx.mouse().url_hover_save.as_ref().map(|hs| hs.start) == Some(start) {
|
||||
if self.ctx.terminal().url_highlight_start() == Some(start) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Since the URL changed without reset, we need to clear the previous underline
|
||||
if let Some(hover_save) = self.ctx.mouse_mut().url_hover_save.take() {
|
||||
self.reset_underline(&hover_save);
|
||||
}
|
||||
self.ctx.terminal_mut().reset_url_highlight();
|
||||
|
||||
// Underline all cells and store their current underline state
|
||||
let mut underlined = Vec::with_capacity(len);
|
||||
|
@ -482,7 +480,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
|||
}
|
||||
|
||||
// Save the higlight state for restoring it again
|
||||
self.ctx.mouse_mut().url_hover_save = Some(UrlHoverSaveState {
|
||||
self.ctx.terminal_mut().set_url_highlight(UrlHoverSaveState {
|
||||
mouse_cursor,
|
||||
underlined,
|
||||
start,
|
||||
|
@ -490,24 +488,8 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
|
|||
|
||||
self.ctx.terminal_mut().set_mouse_cursor(MouseCursor::Hand);
|
||||
self.ctx.terminal_mut().dirty = true;
|
||||
} else if let Some(hover_save) = self.ctx.mouse_mut().url_hover_save.take() {
|
||||
self.ctx.terminal_mut().set_mouse_cursor(hover_save.mouse_cursor);
|
||||
self.ctx.terminal_mut().dirty = true;
|
||||
self.reset_underline(&hover_save);
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset the underline state after unhovering a URL.
|
||||
fn reset_underline(&mut self, hover_save: &UrlHoverSaveState) {
|
||||
let last_col = self.ctx.size_info().cols() - 1;
|
||||
let last_line = self.ctx.size_info().lines().0 - 1;
|
||||
|
||||
let mut iter = once(hover_save.start).chain(hover_save.start.iter(last_col, last_line));
|
||||
for underlined in &hover_save.underlined {
|
||||
if let (Some(point), false) = (iter.next(), underlined) {
|
||||
let cell = &mut self.ctx.terminal_mut().grid_mut()[point.line][point.col];
|
||||
cell.flags.remove(Flags::UNDERLINE);
|
||||
}
|
||||
} else {
|
||||
self.ctx.terminal_mut().reset_url_highlight();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ use std::ops::{Range, Index, IndexMut, RangeInclusive};
|
|||
use std::{ptr, io, mem};
|
||||
use std::cmp::{min, max};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::iter::once;
|
||||
|
||||
use arraydeque::ArrayDeque;
|
||||
use unicode_width::UnicodeWidthChar;
|
||||
|
@ -36,7 +37,7 @@ use crate::input::FONT_SIZE_STEP;
|
|||
use crate::url::{Url, UrlParser};
|
||||
use crate::message_bar::MessageBuffer;
|
||||
use crate::term::color::Rgb;
|
||||
use crate::term::cell::{LineLength, Cell};
|
||||
use crate::term::cell::{LineLength, Cell, Flags};
|
||||
|
||||
#[cfg(windows)]
|
||||
use crate::tty;
|
||||
|
@ -823,6 +824,16 @@ pub struct Term {
|
|||
|
||||
/// Hint that Alacritty should be closed
|
||||
should_exit: bool,
|
||||
|
||||
/// URL highlight save state
|
||||
url_hover_save: Option<UrlHoverSaveState>,
|
||||
}
|
||||
|
||||
/// Temporary save state for restoring mouse cursor and underline after unhovering a URL.
|
||||
pub struct UrlHoverSaveState {
|
||||
pub mouse_cursor: MouseCursor,
|
||||
pub underlined: Vec<bool>,
|
||||
pub start: Point<usize>,
|
||||
}
|
||||
|
||||
/// Terminal size info
|
||||
|
@ -955,6 +966,7 @@ impl Term {
|
|||
auto_scroll: config.scrolling().auto_scroll,
|
||||
message_buffer,
|
||||
should_exit: false,
|
||||
url_hover_save: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1200,6 +1212,8 @@ impl Term {
|
|||
return;
|
||||
}
|
||||
|
||||
self.reset_url_highlight();
|
||||
|
||||
let old_cols = self.grid.num_cols();
|
||||
let old_lines = self.grid.num_lines();
|
||||
let mut num_cols = size.cols();
|
||||
|
@ -1365,6 +1379,41 @@ impl Term {
|
|||
pub fn should_exit(&self) -> bool {
|
||||
self.should_exit
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_url_highlight(&mut self, hover_save: UrlHoverSaveState) {
|
||||
self.url_hover_save = Some(hover_save);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn url_highlight_start(&self) -> Option<Point<usize>> {
|
||||
self.url_hover_save.as_ref().map(|hs| hs.start)
|
||||
}
|
||||
|
||||
/// Remove the URL highlight and restore the previous mouse cursor and underline state.
|
||||
pub fn reset_url_highlight(&mut self) {
|
||||
let hover_save = match self.url_hover_save.take() {
|
||||
Some(hover_save) => hover_save,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
// Reset the mouse cursor
|
||||
self.set_mouse_cursor(hover_save.mouse_cursor);
|
||||
|
||||
let last_line = self.size_info.lines().0 - 1;
|
||||
let last_col = self.size_info.cols() - 1;
|
||||
|
||||
// Reset the underline state after unhovering a URL
|
||||
let mut iter = once(hover_save.start).chain(hover_save.start.iter(last_col, last_line));
|
||||
for underlined in &hover_save.underlined {
|
||||
if let (Some(point), false) = (iter.next(), underlined) {
|
||||
let cell = &mut self.grid[point.line][point.col];
|
||||
cell.flags.remove(Flags::UNDERLINE);
|
||||
}
|
||||
}
|
||||
|
||||
self.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
impl ansi::TermInfo for Term {
|
||||
|
|
Loading…
Reference in New Issue