Implement zero width roundtripped chars in multicell segmentation as well

This commit is contained in:
Kovid Goyal 2025-04-03 13:05:42 +05:30
parent f5e8de2e4f
commit 4c2bd8ffb1
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
2 changed files with 16 additions and 3 deletions

View file

@ -1101,6 +1101,11 @@ draw_control_char(Screen *self, text_loop_state *s, uint32_t ch) {
}
}
static bool
is_roundtripped_zero_width_char(char_type ch) {
return ch == 0xad || ch == 0x200b || ch == 0x2060;
}
static void
draw_text_loop(Screen *self, const uint32_t *chars, size_t num_chars, text_loop_state *s) {
init_text_loop_line(self, s);
@ -1122,7 +1127,7 @@ draw_text_loop(Screen *self, const uint32_t *chars, size_t num_chars, text_loop_
// check for some zero width chars that we want to preserve for
// round tripping that are not added to prev cell by grapheme
// segmentation.
if (s->prev.cc && (ch == 0xad || ch == 0x200b || ch == 0x2060)) { // soft hyphen, zero width space, word joiner
if (s->prev.cc && is_roundtripped_zero_width_char(ch)) { // soft hyphen, zero width space, word joiner
draw_combining_char(self, s, ch);
}
continue; // we cannot represent zero width chars except as combining chars
@ -1312,10 +1317,11 @@ screen_handle_multicell_command(Screen *self, const MultiCellCommand *cmd, const
char_type ch = self->lc->chars[i];
CharProps cp = char_props_for(ch);
if (cp.is_invalid) continue;
if ((s = grapheme_segmentation_step(s, cp)).add_to_current_cell) lc.chars[lc.count++] = ch;
if ((s = grapheme_segmentation_step(s, cp)).add_to_current_cell || (wcwidth_std(cp) == 0 && is_roundtripped_zero_width_char(ch) && lc.count)) lc.chars[lc.count++] = ch;
else {
if (lc.count) handle_variable_width_multicell_command(self, mcd, &lc);
lc.chars[0] = ch; lc.count = 1;
if (wcwidth_std(cp) < 1) lc.count = 0;
else { lc.chars[0] = ch; lc.count = 1; }
}
}
if (lc.count) handle_variable_width_multicell_command(self, mcd, &lc);

View file

@ -141,6 +141,13 @@ def comb(x, y):
for x in range(s.columns):
ac(x, y, is_multicell=True, x=x, y=y)
# Test zero width roundtripping
for preserved in '\xad\u200b\u2060':
s.reset()
multicell(s, f'|{preserved}|', scale=2)
assert_cursor_at(4, 0)
ac(0, 0, text=f'|{preserved}')
# Test wrapping
s = self.create_screen(cols=6, lines=6)
s.draw('x' * (s.columns - 1))