Fix replacement of fullwidth characters

Fixes #3726.
This commit is contained in:
Christian Duerr 2021-04-29 17:06:44 +00:00 committed by GitHub
parent 11cbc439c8
commit 4d982894a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 51 additions and 20 deletions

View File

@ -31,6 +31,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Incorrect underline cursor thickness on wide cell
- Viewport moving around when resizing while scrolled into history
- Block cursor not expanding across fullwidth characters when on the right side of it
- Overwriting fullwidth characters only clearing one of the involved cells
### Removed

View File

@ -99,6 +99,14 @@ impl Cell {
self.extra = None;
}
}
/// Remove all wide char data from a cell.
#[inline(never)]
pub fn clear_wide(&mut self) {
self.flags.remove(Flags::WIDE_CHAR);
self.drop_extra();
self.c = ' ';
}
}
impl GridCell for Cell {

View File

@ -761,13 +761,33 @@ impl<T> Term<T> {
/// Write `c` to the cell at the cursor position.
#[inline(always)]
fn write_at_cursor(&mut self, c: char) -> &mut Cell {
fn write_at_cursor(&mut self, c: char) {
let c = self.grid.cursor.charsets[self.active_charset].map(c);
let fg = self.grid.cursor.template.fg;
let bg = self.grid.cursor.template.bg;
let flags = self.grid.cursor.template.flags;
let cursor_cell = self.grid.cursor_cell();
let mut cursor_cell = self.grid.cursor_cell();
// Clear all related cells when overwriting a fullwidth cell.
if cursor_cell.flags.intersects(Flags::WIDE_CHAR | Flags::WIDE_CHAR_SPACER) {
// Remove wide char and spacer.
let wide = cursor_cell.flags.contains(Flags::WIDE_CHAR);
let point = self.grid.cursor.point;
if wide {
self.grid[point.line][point.column + 1].flags.remove(Flags::WIDE_CHAR_SPACER);
} else {
self.grid[point.line][point.column - 1].clear_wide();
}
// Remove leading spacers.
if point.column <= 1 && point.line != self.topmost_line() {
let column = self.last_column();
self.grid[point.line - 1i32][column].flags.remove(Flags::LEADING_WIDE_CHAR_SPACER);
}
cursor_cell = self.grid.cursor_cell();
}
cursor_cell.drop_extra();
@ -775,8 +795,6 @@ impl<T> Term<T> {
cursor_cell.fg = fg;
cursor_cell.bg = bg;
cursor_cell.flags = flags;
cursor_cell
}
}
@ -810,18 +828,18 @@ impl<T: EventListener> Handler for Term<T> {
// Handle zero-width characters.
if width == 0 {
// Get previous column.
let mut col = self.grid.cursor.point.column.0;
let mut column = self.grid.cursor.point.column;
if !self.grid.cursor.input_needs_wrap {
col = col.saturating_sub(1);
column.0 = column.saturating_sub(1);
}
// Put zerowidth characters over first fullwidth character cell.
let line = self.grid.cursor.point.line;
if self.grid[line][Column(col)].flags.contains(Flags::WIDE_CHAR_SPACER) {
col = col.saturating_sub(1);
if self.grid[line][column].flags.contains(Flags::WIDE_CHAR_SPACER) {
column.0 = column.saturating_sub(1);
}
self.grid[line][Column(col)].push_zerowidth(c);
self.grid[line][column].push_zerowidth(c);
return;
}
@ -830,16 +848,14 @@ impl<T: EventListener> Handler for Term<T> {
self.wrapline();
}
let num_cols = self.columns();
// If in insert mode, first shift cells to the right.
if self.mode.contains(TermMode::INSERT) && self.grid.cursor.point.column + width < num_cols
{
let columns = self.columns();
if self.mode.contains(TermMode::INSERT) && self.grid.cursor.point.column + width < columns {
let line = self.grid.cursor.point.line;
let col = self.grid.cursor.point.column;
let row = &mut self.grid[line][..];
for col in (col.0..(num_cols - width)).rev() {
for col in (col.0..(columns - width)).rev() {
row.swap(col + width, col);
}
}
@ -847,10 +863,12 @@ impl<T: EventListener> Handler for Term<T> {
if width == 1 {
self.write_at_cursor(c);
} else {
if self.grid.cursor.point.column + 1 >= num_cols {
if self.grid.cursor.point.column + 1 >= columns {
if self.mode.contains(TermMode::LINE_WRAP) {
// Insert placeholder before wide char if glyph does not fit in this row.
self.write_at_cursor(' ').flags.insert(Flags::LEADING_WIDE_CHAR_SPACER);
self.grid.cursor.template.flags.insert(Flags::LEADING_WIDE_CHAR_SPACER);
self.write_at_cursor(' ');
self.grid.cursor.template.flags.remove(Flags::LEADING_WIDE_CHAR_SPACER);
self.wrapline();
} else {
// Prevent out of bounds crash when linewrapping is disabled.
@ -860,14 +878,18 @@ impl<T: EventListener> Handler for Term<T> {
}
// Write full width glyph to current cursor cell.
self.write_at_cursor(c).flags.insert(Flags::WIDE_CHAR);
self.grid.cursor.template.flags.insert(Flags::WIDE_CHAR);
self.write_at_cursor(c);
self.grid.cursor.template.flags.remove(Flags::WIDE_CHAR);
// Write spacer to cell following the wide glyph.
self.grid.cursor.point.column += 1;
self.write_at_cursor(' ').flags.insert(Flags::WIDE_CHAR_SPACER);
self.grid.cursor.template.flags.insert(Flags::WIDE_CHAR_SPACER);
self.write_at_cursor(' ');
self.grid.cursor.template.flags.remove(Flags::WIDE_CHAR_SPACER);
}
if self.grid.cursor.point.column + 1 < num_cols {
if self.grid.cursor.point.column + 1 < columns {
self.grid.cursor.point.column += 1;
} else {
self.grid.cursor.input_needs_wrap = true;
@ -1046,7 +1068,7 @@ impl<T: EventListener> Handler for Term<T> {
}
}
/// Backspace `count` characters.
/// Backspace.
#[inline]
fn backspace(&mut self) {
trace!("Backspace");