diff options
author | Christian Duerr <contact@christianduerr.com> | 2020-01-09 23:06:41 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-09 23:06:41 +0000 |
commit | 3fb631b91caec163707858bd1d435015e6e6cb18 (patch) | |
tree | cfc575f224622b7c83a21281c2e23a7f8af83364 /alacritty_terminal/src/term/mod.rs | |
parent | 5651c3f7114dff611e616865ad02e682779979d9 (diff) | |
download | alacritty-3fb631b91caec163707858bd1d435015e6e6cb18.tar.gz alacritty-3fb631b91caec163707858bd1d435015e6e6cb18.zip |
Fix cut off full width glyphs in last column
This resolves the issue with full width glyphs getting rendered in the
last column. Since they need at least two glyphs, it is not possible to
properly render them in the last column.
Instead of rendering half of the glyph in the last column, with the
other half cut off, an additional spacer is now inserted before the wide
glyph. This means that the specific glyph in question is then three
cells wide.
Fixes #2385.
Diffstat (limited to 'alacritty_terminal/src/term/mod.rs')
-rw-r--r-- | alacritty_terminal/src/term/mod.rs | 146 |
1 files changed, 85 insertions, 61 deletions
diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs index 4aafde1f..acd14e7e 100644 --- a/alacritty_terminal/src/term/mod.rs +++ b/alacritty_terminal/src/term/mod.rs @@ -69,7 +69,9 @@ impl<T> Search for Term<T> { let last_col = self.grid.num_cols() - Column(1); while let Some(cell) = iter.prev() { - if self.semantic_escape_chars.contains(cell.c) { + if !cell.flags.intersects(Flags::WIDE_CHAR | Flags::WIDE_CHAR_SPACER) + && self.semantic_escape_chars.contains(cell.c) + { break; } @@ -91,7 +93,9 @@ impl<T> Search for Term<T> { let last_col = self.grid.num_cols() - 1; while let Some(cell) = iter.next() { - if self.semantic_escape_chars.contains(cell.c) { + if !cell.flags.intersects(Flags::WIDE_CHAR | Flags::WIDE_CHAR_SPACER) + && self.semantic_escape_chars.contains(cell.c) + { break; } @@ -1181,6 +1185,42 @@ impl<T> Term<T> { pub fn clipboard(&mut self) -> &mut Clipboard { &mut self.clipboard } + + /// Insert a linebreak at the current cursor position. + #[inline] + fn wrapline(&mut self) + where + T: EventListener, + { + if !self.mode.contains(TermMode::LINE_WRAP) { + return; + } + + trace!("Wrapping input"); + + self.grid[&self.cursor.point].flags.insert(Flags::WRAPLINE); + + if (self.cursor.point.line + 1) >= self.scroll_region.end { + self.linefeed(); + } else { + self.cursor.point.line += 1; + } + + self.cursor.point.col = Column(0); + self.input_needs_wrap = false; + } + + /// Write `c` to the cell at the cursor position. + #[inline] + fn write_at_cursor(&mut self, c: char) -> &mut Cell + where + T: EventListener, + { + let cell = &mut self.grid[&self.cursor.point]; + *cell = self.cursor.template; + cell.c = self.cursor.charsets[self.active_charset].map(c); + cell + } } impl<T> TermInfo for Term<T> { @@ -1195,7 +1235,7 @@ impl<T> TermInfo for Term<T> { } } -impl<T: EventListener> ansi::Handler for Term<T> { +impl<T: EventListener> Handler for Term<T> { #[inline] #[cfg(not(windows))] fn set_title(&mut self, title: &str) { @@ -1238,77 +1278,61 @@ impl<T: EventListener> ansi::Handler for Term<T> { self.scroll_display(Scroll::Bottom); } - if self.input_needs_wrap { - if !self.mode.contains(TermMode::LINE_WRAP) { - return; + // Number of cells the char will occupy + let width = match c.width() { + Some(width) => width, + None => return, + }; + + // Handle zero-width characters + if width == 0 { + let mut col = self.cursor.point.col.0.saturating_sub(1); + let line = self.cursor.point.line; + if self.grid[line][Column(col)].flags.contains(Flags::WIDE_CHAR_SPACER) { + col = col.saturating_sub(1); } + self.grid[line][Column(col)].push_extra(c); + return; + } - trace!("Wrapping input"); + // Move cursor to next line + if self.input_needs_wrap { + self.wrapline(); + } - { - let location = Point { line: self.cursor.point.line, col: self.cursor.point.col }; + let num_cols = self.grid.num_cols(); - let cell = &mut self.grid[&location]; - cell.flags.insert(Flags::WRAPLINE); - } + // If in insert mode, first shift cells to the right + if self.mode.contains(TermMode::INSERT) && self.cursor.point.col + width < num_cols { + let line = self.cursor.point.line; + let col = self.cursor.point.col; + let line = &mut self.grid[line]; - if (self.cursor.point.line + 1) >= self.scroll_region.end { - self.linefeed(); - } else { - self.cursor.point.line += 1; + let src = line[col..].as_ptr(); + let dst = line[(col + width)..].as_mut_ptr(); + unsafe { + ptr::copy(src, dst, (num_cols - col - width).0); } - - self.cursor.point.col = Column(0); - self.input_needs_wrap = false; } - // Number of cells the char will occupy - if let Some(width) = c.width() { - let num_cols = self.grid.num_cols(); - - // If in insert mode, first shift cells to the right. - if self.mode.contains(TermMode::INSERT) && self.cursor.point.col + width < num_cols { - let line = self.cursor.point.line; - let col = self.cursor.point.col; - let line = &mut self.grid[line]; - - let src = line[col..].as_ptr(); - let dst = line[(col + width)..].as_mut_ptr(); - unsafe { - // memmove - ptr::copy(src, dst, (num_cols - col - width).0); - } + if width == 1 { + self.write_at_cursor(c); + } else { + // Insert extra placeholder before wide char if glyph doesn't fit in this row anymore + if self.cursor.point.col + 1 >= num_cols { + self.write_at_cursor(' ').flags.insert(Flags::WIDE_CHAR_SPACER); + self.wrapline(); } - // Handle zero-width characters - if width == 0 { - let mut col = self.cursor.point.col.0.saturating_sub(1); - let line = self.cursor.point.line; - if self.grid[line][Column(col)].flags.contains(Flags::WIDE_CHAR_SPACER) { - col = col.saturating_sub(1); - } - self.grid[line][Column(col)].push_extra(c); - return; - } + // Write full width glyph to current cursor cell + self.write_at_cursor(c).flags.insert(Flags::WIDE_CHAR); - let cell = &mut self.grid[&self.cursor.point]; - *cell = self.cursor.template; - cell.c = self.cursor.charsets[self.active_charset].map(c); - - // Handle wide chars - if width == 2 { - cell.flags.insert(Flags::WIDE_CHAR); - - if self.cursor.point.col + 1 < num_cols { - self.cursor.point.col += 1; - let spacer = &mut self.grid[&self.cursor.point]; - *spacer = self.cursor.template; - spacer.flags.insert(Flags::WIDE_CHAR_SPACER); - } - } + // Write spacer to cell following the wide glyph + self.cursor.point.col += 1; + self.write_at_cursor(' ').flags.insert(Flags::WIDE_CHAR_SPACER); } - if (self.cursor.point.col + 1) < self.grid.num_cols() { + if self.cursor.point.col + 1 < num_cols { self.cursor.point.col += 1; } else { self.input_needs_wrap = true; |