Fix a regression that broke rendering of unicode regional indicators

At some point, unicode regional indicators became combining chars in the
unicode standard, which broke the handling of them in draw_codepoint().
The fix has the added advantage of improving performance in the common
case by only checking for combining chars. The flag check happens only
if the first check matches.

Fixes #4407
This commit is contained in:
Kovid Goyal 2021-12-31 09:28:47 +05:30
parent ea63efa522
commit e45697f78a
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 21 additions and 7 deletions

View File

@ -664,12 +664,13 @@ draw_codepoint(Screen *self, char_type och, bool from_input_stream) {
uint32_t ch = och < 256 ? self->g_charset[och] : och;
bool is_cc = is_combining_char(ch);
if (UNLIKELY(is_cc)) {
draw_combining_char(self, ch);
return;
}
bool is_flag = is_flag_codepoint(ch);
if (UNLIKELY(is_flag)) {
if (draw_second_flag_codepoint(self, ch)) return;
bool is_flag = is_flag_codepoint(ch);
if (UNLIKELY(is_flag)) {
if (draw_second_flag_codepoint(self, ch)) return;
} else {
draw_combining_char(self, ch);
return;
}
}
int char_width = wcwidth_std(ch);
if (UNLIKELY(char_width < 1)) {

View File

@ -383,8 +383,10 @@ class TestDataTypes(BaseTest):
self.ae(wcswidth('\U0001F1E6\U0001F1E8\U0001F1E6'), 4)
self.ae(wcswidth('a\u00adb'), 2)
# Regional indicator symbols (unicode flags) are defined as having
# Emoji_Presentation so must have width 2
# Emoji_Presentation so must have width 2 but combined must have
# width 2 not 4
self.ae(tuple(map(w, '\U0001f1ee\U0001f1f3')), (2, 2))
self.ae(wcswidth('\U0001f1ee\U0001f1f3'), 2)
tpl = truncate_point_for_length
self.ae(tpl('abc', 4), 3)
self.ae(tpl('abc', 2), 2)

View File

@ -110,6 +110,17 @@ class TestScreen(BaseTest):
self.ae(str(s.line(0)), q)
self.ae(s.cursor.x, 2)
def test_regional_indicators(self):
s = self.create_screen()
flag = '\U0001f1ee\U0001f1f3'
s.draw(flag)
self.ae(str(s.line(0)), flag)
self.ae(s.cursor.x, 2)
s = self.create_screen()
s.draw('a'), s.draw(flag[0]), s.draw('b')
self.ae(str(s.line(0)), 'a' + flag[0] + 'b')
self.ae(s.cursor.x, 4)
def test_zwj(self):
s = self.create_screen(cols=20)
q = '\U0001f468\u200d\U0001f469\u200d\U0001f467\u200d\U0001f466'