From 4d982894a6859b6d4eeb967ec6dbbf5965c79165 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Thu, 29 Apr 2021 17:06:44 +0000 Subject: Fix replacement of fullwidth characters Fixes #3726. --- alacritty_terminal/src/term/cell.rs | 8 +++++ alacritty_terminal/src/term/mod.rs | 62 +++++++++++++++++++++++++------------ 2 files changed, 50 insertions(+), 20 deletions(-) (limited to 'alacritty_terminal') diff --git a/alacritty_terminal/src/term/cell.rs b/alacritty_terminal/src/term/cell.rs index 255cbce7..64de5492 100644 --- a/alacritty_terminal/src/term/cell.rs +++ b/alacritty_terminal/src/term/cell.rs @@ -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 { diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs index 0e6fa07f..409d4ebe 100644 --- a/alacritty_terminal/src/term/mod.rs +++ b/alacritty_terminal/src/term/mod.rs @@ -761,13 +761,33 @@ impl Term { /// 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 Term { cursor_cell.fg = fg; cursor_cell.bg = bg; cursor_cell.flags = flags; - - cursor_cell } } @@ -810,18 +828,18 @@ impl Handler for Term { // 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 Handler for Term { 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 Handler for Term { 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 Handler for Term { } // 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 Handler for Term { } } - /// Backspace `count` characters. + /// Backspace. #[inline] fn backspace(&mut self) { trace!("Backspace"); -- cgit v1.2.3