Fix crash with empty post-processed matches

Fixes #5492.

Co-authored-by: Christian Duerr <contact@christianduerr.com>
This commit is contained in:
Scott Freeman 2021-11-11 14:04:25 -05:00 committed by GitHub
parent b885ec9cd3
commit e648aae0eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 10 deletions

View File

@ -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
- Vi mode search starting in the line below the vi cursor
- Invisible cursor with matching foreground/background colors
- Crash when hovering over a match emptied by post-processing
## 0.9.0

View File

@ -306,13 +306,16 @@ struct HintPostProcessor<'a, T> {
impl<'a, T> HintPostProcessor<'a, T> {
/// Create a new iterator for an unprocessed match.
fn new(term: &'a Term<T>, regex: &'a RegexSearch, regex_match: Match) -> Self {
let end = *regex_match.end();
let mut post_processor = Self { next_match: None, start: end, end, term, regex };
let mut post_processor = Self {
next_match: None,
start: *regex_match.start(),
end: *regex_match.end(),
term,
regex,
};
// Post-process the first hint match.
let next_match = post_processor.hint_post_processing(&regex_match);
post_processor.start = next_match.end().add(term, Boundary::Grid, 1);
post_processor.next_match = Some(next_match);
post_processor.next_processed_match(regex_match);
post_processor
}
@ -323,7 +326,7 @@ impl<'a, T> HintPostProcessor<'a, T> {
/// to be unlikely to be intentionally part of the hint.
///
/// 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 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(&regex_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 let Some(rm) = self.term.regex_search_right(self.regex, self.start, self.end) {
let regex_match = self.hint_post_processing(&rm);
self.start = regex_match.end().add(self.term, Boundary::Grid, 1);
self.next_match = Some(regex_match);
self.next_processed_match(rm);
}
}
@ -402,6 +427,9 @@ impl<'a, T> Iterator for HintPostProcessor<'a, T> {
#[cfg(test)]
mod tests {
use alacritty_terminal::index::{Column, Line};
use alacritty_terminal::term::test::mock_term;
use super::*;
#[test]
@ -442,4 +470,21 @@ mod tests {
assert_eq!(generator.next(), vec!['3', '3', '3', '0']);
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);
}
}