Fix crash with empty post-processed matches
Fixes #5492. Co-authored-by: Christian Duerr <contact@christianduerr.com>
This commit is contained in:
parent
b885ec9cd3
commit
e648aae0eb
|
@ -27,6 +27,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Line indicator obstructing vi mode cursor when scrolled into history
|
- Line indicator obstructing vi mode cursor when scrolled into history
|
||||||
- Vi mode search starting in the line below the vi cursor
|
- Vi mode search starting in the line below the vi cursor
|
||||||
- Invisible cursor with matching foreground/background colors
|
- Invisible cursor with matching foreground/background colors
|
||||||
|
- Crash when hovering over a match emptied by post-processing
|
||||||
|
|
||||||
## 0.9.0
|
## 0.9.0
|
||||||
|
|
||||||
|
|
|
@ -306,13 +306,16 @@ struct HintPostProcessor<'a, T> {
|
||||||
impl<'a, T> HintPostProcessor<'a, T> {
|
impl<'a, T> HintPostProcessor<'a, T> {
|
||||||
/// Create a new iterator for an unprocessed match.
|
/// Create a new iterator for an unprocessed match.
|
||||||
fn new(term: &'a Term<T>, regex: &'a RegexSearch, regex_match: Match) -> Self {
|
fn new(term: &'a Term<T>, regex: &'a RegexSearch, regex_match: Match) -> Self {
|
||||||
let end = *regex_match.end();
|
let mut post_processor = Self {
|
||||||
let mut post_processor = Self { next_match: None, start: end, end, term, regex };
|
next_match: None,
|
||||||
|
start: *regex_match.start(),
|
||||||
|
end: *regex_match.end(),
|
||||||
|
term,
|
||||||
|
regex,
|
||||||
|
};
|
||||||
|
|
||||||
// Post-process the first hint match.
|
// Post-process the first hint match.
|
||||||
let next_match = post_processor.hint_post_processing(®ex_match);
|
post_processor.next_processed_match(regex_match);
|
||||||
post_processor.start = next_match.end().add(term, Boundary::Grid, 1);
|
|
||||||
post_processor.next_match = Some(next_match);
|
|
||||||
|
|
||||||
post_processor
|
post_processor
|
||||||
}
|
}
|
||||||
|
@ -323,7 +326,7 @@ impl<'a, T> HintPostProcessor<'a, T> {
|
||||||
/// to be unlikely to be intentionally part of the hint.
|
/// to be unlikely to be intentionally part of the hint.
|
||||||
///
|
///
|
||||||
/// This is most useful for identifying URLs appropriately.
|
/// This is most useful for identifying URLs appropriately.
|
||||||
fn hint_post_processing(&self, regex_match: &Match) -> Match {
|
fn hint_post_processing(&self, regex_match: &Match) -> Option<Match> {
|
||||||
let mut iter = self.term.grid().iter_from(*regex_match.start());
|
let mut iter = self.term.grid().iter_from(*regex_match.start());
|
||||||
|
|
||||||
let mut c = iter.cell().c;
|
let mut c = iter.cell().c;
|
||||||
|
@ -378,7 +381,31 @@ impl<'a, T> HintPostProcessor<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start..=iter.point()
|
if start > iter.point() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(start..=iter.point())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Loop over submatches until a non-empty post-processed match is found.
|
||||||
|
fn next_processed_match(&mut self, mut regex_match: Match) {
|
||||||
|
self.next_match = loop {
|
||||||
|
if let Some(next_match) = self.hint_post_processing(®ex_match) {
|
||||||
|
self.start = next_match.end().add(self.term, Boundary::Grid, 1);
|
||||||
|
break Some(next_match);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.start = regex_match.start().add(self.term, Boundary::Grid, 1);
|
||||||
|
if self.start > self.end {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.term.regex_search_right(self.regex, self.start, self.end) {
|
||||||
|
Some(rm) => regex_match = rm,
|
||||||
|
None => return,
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,9 +417,7 @@ impl<'a, T> Iterator for HintPostProcessor<'a, T> {
|
||||||
|
|
||||||
if self.start <= self.end {
|
if self.start <= self.end {
|
||||||
if let Some(rm) = self.term.regex_search_right(self.regex, self.start, self.end) {
|
if let Some(rm) = self.term.regex_search_right(self.regex, self.start, self.end) {
|
||||||
let regex_match = self.hint_post_processing(&rm);
|
self.next_processed_match(rm);
|
||||||
self.start = regex_match.end().add(self.term, Boundary::Grid, 1);
|
|
||||||
self.next_match = Some(regex_match);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,6 +427,9 @@ impl<'a, T> Iterator for HintPostProcessor<'a, T> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use alacritty_terminal::index::{Column, Line};
|
||||||
|
use alacritty_terminal::term::test::mock_term;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -442,4 +470,21 @@ mod tests {
|
||||||
assert_eq!(generator.next(), vec!['3', '3', '3', '0']);
|
assert_eq!(generator.next(), vec!['3', '3', '3', '0']);
|
||||||
assert_eq!(generator.next(), vec!['3', '3', '3', '1']);
|
assert_eq!(generator.next(), vec!['3', '3', '3', '1']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn closed_bracket_does_not_result_in_infinite_iterator() {
|
||||||
|
let term = mock_term(" ) ");
|
||||||
|
|
||||||
|
let search = RegexSearch::new("[^/ ]").unwrap();
|
||||||
|
|
||||||
|
let count = HintPostProcessor::new(
|
||||||
|
&term,
|
||||||
|
&search,
|
||||||
|
Point::new(Line(0), Column(1))..=Point::new(Line(0), Column(1)),
|
||||||
|
)
|
||||||
|
.take(1)
|
||||||
|
.count();
|
||||||
|
|
||||||
|
assert_eq!(count, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue