mirror of
https://github.com/alacritty/alacritty.git
synced 2025-04-21 18:02:37 -04:00
Fix crashes with cut-off fullwidth characters
There's a few places in Alacritty where it was assumed that after a WIDE_CHAR cell, there'd always be a WIDE_CHAR_SPACER. However since resizes in the alternate screen buffer do not reflow any content, it's possible to have a WIDE_CHAR without any WIDE_CHAR_SPACER right behind it. This patch changes these instances to be more defensive about accepting potentially unreasonable input data caused by alt screen resizes. Fixes #5185. Fixes #5170.
This commit is contained in:
parent
3c61e075fe
commit
3e867a0560
3 changed files with 38 additions and 11 deletions
|
@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
### Fixed
|
||||
|
||||
- Regression in rendering performance with dense grids since 0.6.0
|
||||
- Crash/Freezes with partially visible fullwidth characters due to alt screen resize
|
||||
|
||||
## 0.8.0
|
||||
|
||||
|
|
|
@ -699,7 +699,9 @@ impl<T> Term<T> {
|
|||
point.column = Column(1);
|
||||
point.line += 1;
|
||||
},
|
||||
Direction::Right if flags.contains(Flags::WIDE_CHAR) => point.column += 1,
|
||||
Direction::Right if flags.contains(Flags::WIDE_CHAR) => {
|
||||
point.column = min(point.column + 1, self.last_column());
|
||||
},
|
||||
Direction::Left if flags.intersects(Flags::WIDE_CHAR | Flags::WIDE_CHAR_SPACER) => {
|
||||
if flags.contains(Flags::WIDE_CHAR_SPACER) {
|
||||
point.column -= 1;
|
||||
|
@ -774,7 +776,7 @@ impl<T> Term<T> {
|
|||
// Remove wide char and spacer.
|
||||
let wide = cursor_cell.flags.contains(Flags::WIDE_CHAR);
|
||||
let point = self.grid.cursor.point;
|
||||
if wide {
|
||||
if wide && point.column + 1 < self.columns() {
|
||||
self.grid[point.line][point.column + 1].flags.remove(Flags::WIDE_CHAR_SPACER);
|
||||
} else {
|
||||
self.grid[point.line][point.column - 1].clear_wide();
|
||||
|
|
|
@ -239,7 +239,12 @@ impl<T> Term<T> {
|
|||
}
|
||||
|
||||
// Stop once we've reached the target point.
|
||||
if point == end {
|
||||
//
|
||||
// We check beyond the point itself to account for skipped characters after wide chars
|
||||
// without spacer.
|
||||
if (direction == Direction::Right && point >= end)
|
||||
|| (direction == Direction::Left && point <= end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -497,8 +502,10 @@ impl<'a, T> Iterator for RegexIter<'a, T> {
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::index::{Column, Line};
|
||||
use crate::term::test::mock_term;
|
||||
use crate::term::SizeInfo;
|
||||
|
||||
#[test]
|
||||
fn regex_right() {
|
||||
|
@ -571,8 +578,8 @@ mod tests {
|
|||
");
|
||||
|
||||
let dfas = RegexSearch::new("nothing").unwrap();
|
||||
let start = Point::new(Line(2), Column(0));
|
||||
let end = Point::new(Line(0), Column(4));
|
||||
let start = Point::new(Line(0), Column(0));
|
||||
let end = Point::new(Line(2), Column(4));
|
||||
assert_eq!(term.regex_search_right(&dfas, start, end), None);
|
||||
}
|
||||
|
||||
|
@ -586,8 +593,8 @@ mod tests {
|
|||
");
|
||||
|
||||
let dfas = RegexSearch::new("nothing").unwrap();
|
||||
let start = Point::new(Line(0), Column(4));
|
||||
let end = Point::new(Line(2), Column(0));
|
||||
let start = Point::new(Line(2), Column(4));
|
||||
let end = Point::new(Line(0), Column(0));
|
||||
assert_eq!(term.regex_search_left(&dfas, start, end), None);
|
||||
}
|
||||
|
||||
|
@ -723,15 +730,15 @@ mod tests {
|
|||
");
|
||||
|
||||
let dfas = RegexSearch::new("🦇x").unwrap();
|
||||
let start = Point::new(Line(1), Column(0));
|
||||
let end = Point::new(Line(0), Column(3));
|
||||
let start = Point::new(Line(0), Column(0));
|
||||
let end = Point::new(Line(1), Column(3));
|
||||
let match_start = Point::new(Line(0), Column(0));
|
||||
let match_end = Point::new(Line(0), Column(2));
|
||||
assert_eq!(term.regex_search_right(&dfas, start, end), Some(match_start..=match_end));
|
||||
|
||||
let dfas = RegexSearch::new("x🦇").unwrap();
|
||||
let start = Point::new(Line(0), Column(2));
|
||||
let end = Point::new(Line(1), Column(0));
|
||||
let start = Point::new(Line(1), Column(2));
|
||||
let end = Point::new(Line(0), Column(0));
|
||||
let match_start = Point::new(Line(1), Column(1));
|
||||
let match_end = Point::new(Line(1), Column(3));
|
||||
assert_eq!(term.regex_search_left(&dfas, start, end), Some(match_start..=match_end));
|
||||
|
@ -774,4 +781,21 @@ mod tests {
|
|||
let match_end = Point::new(Line(1), Column(1));
|
||||
assert_eq!(term.regex_search_left(&dfas, start, end), Some(match_start..=match_end));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_without_spacer() {
|
||||
let size = SizeInfo::new(2., 2., 1., 1., 0., 0., false);
|
||||
let mut term = Term::new(&Config::<()>::default(), size, ());
|
||||
term.grid[Line(0)][Column(0)].c = 'x';
|
||||
term.grid[Line(0)][Column(1)].c = '字';
|
||||
term.grid[Line(0)][Column(1)].flags = Flags::WIDE_CHAR;
|
||||
|
||||
let dfas = RegexSearch::new("test").unwrap();
|
||||
|
||||
let start = Point::new(Line(0), Column(0));
|
||||
let end = Point::new(Line(0), Column(1));
|
||||
|
||||
let mut iter = RegexIter::new(start, end, Direction::Right, &term, &dfas);
|
||||
assert_eq!(iter.next(), None);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue