From f1cfd6f73f0f5cc16b9b919d64406a35aa81c7cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Helleu?= Date: Sun, 4 Dec 2022 20:03:21 +0100 Subject: [PATCH] core: do not display non printable chars, fix function utf8_char_size_screen Now the function utf8_char_size_screen can return -1 when the char is not printable. It has a specific behavior for some chars: - U+0009: value of option weechat.look.tab_width - U+0001 to U+001F (except U+0009): 1 - U+00AD (soft hyphen): -1 - U+200B (zero width space): -1 --- doc/en/weechat_plugin_api.en.adoc | 22 ++++- doc/fr/weechat_plugin_api.fr.adoc | 23 ++++- doc/it/weechat_plugin_api.it.adoc | 34 +++++-- doc/ja/weechat_plugin_api.ja.adoc | 31 +++++- doc/sr/weechat_plugin_api.sr.adoc | 28 +++++- src/core/wee-utf8.c | 33 +++++-- src/gui/curses/gui-curses-bar-window.c | 8 +- src/gui/curses/gui-curses-chat.c | 76 +++++++------- src/gui/gui-chat.c | 68 +++---------- src/gui/gui-chat.h | 1 - tests/unit/core/test-core-command.cpp | 6 +- tests/unit/core/test-core-utf8.cpp | 50 ++++++++-- tests/unit/gui/test-gui-chat.cpp | 132 +++++++++++++++++-------- 13 files changed, 337 insertions(+), 175 deletions(-) diff --git a/doc/en/weechat_plugin_api.en.adoc b/doc/en/weechat_plugin_api.en.adoc index 3a2c5cba3..ecd867599 100644 --- a/doc/en/weechat_plugin_api.en.adoc +++ b/doc/en/weechat_plugin_api.en.adoc @@ -894,11 +894,12 @@ This function is not available in scripting API. ==== strlen_screen -_WeeChat ≥ 0.4.2._ +_WeeChat ≥ 0.4.2, updated in 3.8._ Return number of chars needed on screen to display UTF-8 string. -Non-printable chars have a width of 1 (this is the difference with the function -<<_utf8_strlen_screen,utf8_strlen_screen>>). + +WeeChat color codes are skipped and don't count in the result (this is the only +difference with the function <<_utf8_strlen_screen,utf8_strlen_screen>>). Prototype: @@ -3639,6 +3640,8 @@ This function is not available in scripting API. ==== utf8_char_size_screen +_Updated in 3.8._ + Return number of chars needed on screen to display UTF-8 char. Prototype: @@ -3654,7 +3657,18 @@ Arguments: Return value: -* number of chars needed on screen to display UTF-8 char +* number of chars needed on screen to display UTF-8 char: +** -1: non printable char +** ≥ 0: printable char + +The result is the return value of function `wcwidth` (see `man wcwidth`), with +exception for the following chars, that have a specific behavior in WeeChat: + +* U+0009 (Tabulation): value of option + link:weechat_user.en.html#option_weechat.look.tab_width[weechat.look.tab_width ^↗^,window=_blank] +* U+0001 (1) to U+001F (31), except U+0009 (Tabulation): 1 +* U+00AD (173, soft hyphen): -1 +* U+200B (8203, zero width space): -1 C example: diff --git a/doc/fr/weechat_plugin_api.fr.adoc b/doc/fr/weechat_plugin_api.fr.adoc index 898000318..69f7fad46 100644 --- a/doc/fr/weechat_plugin_api.fr.adoc +++ b/doc/fr/weechat_plugin_api.fr.adoc @@ -906,12 +906,13 @@ Cette fonction n'est pas disponible dans l'API script. ==== strlen_screen -_WeeChat ≥ 0.4.2._ +_WeeChat ≥ 0.4.2, mis à jour dans la 3.8._ Retourner le nombre de caractères nécessaires pour afficher la chaîne UTF-8 sur l'écran. -Les caractères non affichables ont une longueur de 1 (c'est la différence avec -la fonction <<_utf8_strlen_screen,utf8_strlen_screen>>). + +Les codes couleur de WeeChat sont sautés et ne comptent pas dans le résultat +(ceci est la seule différence avec la fonction <<_utf8_strlen_screen,utf8_strlen_screen>>). Prototype : @@ -3698,6 +3699,8 @@ Cette fonction n'est pas disponible dans l'API script. ==== utf8_char_size_screen +_Mis à jour dans la 3.8._ + Retourner le nombre de caractères nécessaires pour afficher le caractère UTF-8 sur l'écran. @@ -3714,7 +3717,19 @@ Paramètres : Valeur de retour : -* nombre de caractères nécessaires pour afficher le caractère UTF-8 sur l'écran +* nombre de caractères nécessaires pour afficher le caractère UTF-8 sur l'écran : +** -1 : caractère non affichable +** ≥ 0 : caractère affichable + +Le résultat est la valeur de retour de la fonction `wcwidth` (voir `man wcwidth`), +avec une exception pour les caractères suivants, qui ont un comportement +spécifique dans WeeChat : + +* U+0009 (Tabulation) : valeur de l'option + link:weechat_user.fr.html#option_weechat.look.tab_width[weechat.look.tab_width ^↗^,window=_blank] +* U+0001 (1) to U+001F (31), sauf U+0009 (Tabulation) : 1 +* U+00AD (173, trait d'union conditionnel) : -1 +* U+200B (8203, espace sans chasse) : -1 Exemple en C : diff --git a/doc/it/weechat_plugin_api.it.adoc b/doc/it/weechat_plugin_api.it.adoc index 088b728c0..fa054b1a4 100644 --- a/doc/it/weechat_plugin_api.it.adoc +++ b/doc/it/weechat_plugin_api.it.adoc @@ -939,13 +939,15 @@ Questa funzione non è disponibile nelle API per lo scripting. ==== strlen_screen -_WeeChat ≥ 0.4.2._ - -Restituisce il numero di caratteri necessari per visualizzare la stringa -UTF-8 su schermo. // TRANSLATION MISSING -Non-printable chars have a width of 1 (this is the difference with the function -<<_utf8_strlen_screen,utf8_strlen_screen>>). +_WeeChat ≥ 0.4.2, updated in 3.8._ + +// TRANSLATION MISSING +Return number of chars needed on screen to display UTF-8 string. + +// TRANSLATION MISSING +WeeChat color codes are skipped and don't count in the result (this is the only +difference with the function <<_utf8_strlen_screen,utf8_strlen_screen>>). Prototipo: @@ -3781,6 +3783,9 @@ Questa funzione non è disponibile nelle API per lo scripting. ==== utf8_char_size_screen +// TRANSLATION MISSING +_Updated in 3.8._ + Restituisce il numero di caratteri necessari per visualizzare il carattere UTF-8 sullo schermo. @@ -3798,7 +3803,22 @@ Argomenti: Valore restituito: * numero di caratteri necessario per visualizzare il carattere - UTF-8 su schermo + UTF-8 su schermo: +// TRANSLATION MISSING +** -1: non printable char +// TRANSLATION MISSING +** ≥ 0: printable char + +// TRANSLATION MISSING +The result is the return value of function `wcwidth` (see `man wcwidth`), with +exception for the following chars, that have a specific behavior in WeeChat: + +// TRANSLATION MISSING +* U+0009 (Tabulation): value of option + link:weechat_user.it.html#option_weechat.look.tab_width[weechat.look.tab_width ^↗^,window=_blank] +* U+0001 (1) to U+001F (31), except U+0009 (Tabulation): 1 +* U+00AD (173, soft hyphen): -1 +* U+200B (8203, zero width space): -1 Esempio in C: diff --git a/doc/ja/weechat_plugin_api.ja.adoc b/doc/ja/weechat_plugin_api.ja.adoc index 81ce7668a..a5c729fbd 100644 --- a/doc/ja/weechat_plugin_api.ja.adoc +++ b/doc/ja/weechat_plugin_api.ja.adoc @@ -907,11 +907,15 @@ const char *pos = weechat_strcasestr ("aBcDeF", "de"); /* result: pointer to "D ==== strlen_screen -_WeeChat バージョン 0.4.2 以上で利用可。_ +// TRANSLATION MISSING +_WeeChat ≥ 0.4.2, updated in 3.8._ -UTF-8 文字列を画面上に表示するために必要な画面幅を返す。非表示文字を -1 文字として数えます (これが -<<_utf8_strlen_screen,utf8_strlen_screen>> 関数との違いです)。 +// TRANSLATION MISSING +Return number of chars needed on screen to display UTF-8 string. + +// TRANSLATION MISSING +WeeChat color codes are skipped and don't count in the result (this is the only +difference with the function <<_utf8_strlen_screen,utf8_strlen_screen>>). プロトタイプ: @@ -3705,6 +3709,8 @@ int diff = weechat_utf8_charcasecmp ("aaa", "CCC"); /* == -2 */ ==== utf8_char_size_screen +_WeeChat バージョン 3.8 で更新。_ + UTF-8 文字を画面上に表示するために必要な画面幅を返す。 プロトタイプ: @@ -3720,7 +3726,22 @@ int weechat_utf8_char_size_screen (const char *string); 戻り値: -* UTF-8 文字を画面上に表示するために必要な画面幅 +* UTF-8 文字を画面上に表示するために必要な画面幅: +// TRANSLATION MISSING +** -1: non printable char +// TRANSLATION MISSING +** ≥ 0: printable char + +// TRANSLATION MISSING +The result is the return value of function `wcwidth` (see `man wcwidth`), with +exception for the following chars, that have a specific behavior in WeeChat: + +// TRANSLATION MISSING +* U+0009 (Tabulation): value of option + link:weechat_user.ja.html#option_weechat.look.tab_width[weechat.look.tab_width ^↗^,window=_blank] +* U+0001 (1) to U+001F (31), except U+0009 (Tabulation): 1 +* U+00AD (173, soft hyphen): -1 +* U+200B (8203, zero width space): -1 C 言語での使用例: diff --git a/doc/sr/weechat_plugin_api.sr.adoc b/doc/sr/weechat_plugin_api.sr.adoc index 3739ddcd3..8ae2b157e 100644 --- a/doc/sr/weechat_plugin_api.sr.adoc +++ b/doc/sr/weechat_plugin_api.sr.adoc @@ -865,9 +865,14 @@ const char *pos = weechat_strcasestr ("aBcDeF", "de"); /* резултат: п ==== strlen_screen -_WeeChat ≥ 0.4.2._ +_WeeChat ≥ 0.4.2, ажурирано у верзији 3.8._ -Враћа број карактера на екрану који су потребни за приказивање UTF-8 стринга. Карактери који не могу да се одштампају имају ширину 1 (ово је разлика у односу на функцију <<_utf8_strlen_screen,utf8_strlen_screen>>). +// TRANSLATION MISSING +Return number of chars needed on screen to display UTF-8 string. + +// TRANSLATION MISSING +WeeChat color codes are skipped and don't count in the result (this is the only +difference with the function <<_utf8_strlen_screen,utf8_strlen_screen>>). Прототип: @@ -3511,6 +3516,8 @@ int diff = weechat_utf8_charcasecmp ("aaa", "CCC"); /* == -2 */ ==== utf8_char_size_screen +_Ажурирано у верзији 3.8._ + Враћа број карактера потребних на екрану за испис UTF-8 карактера. Прототип: @@ -3526,7 +3533,22 @@ int weechat_utf8_char_size_screen (const char *string); Повратна вредност: -* број карактера на екрану потребних за испис UTF-8 карактера +* број карактера на екрану потребних за испис UTF-8 карактера: +// TRANSLATION MISSING +** -1: non printable char +// TRANSLATION MISSING +** ≥ 0: printable char + +// TRANSLATION MISSING +The result is the return value of function `wcwidth` (see `man wcwidth`), with +exception for the following chars, that have a specific behavior in WeeChat: + +// TRANSLATION MISSING +* U+0009 (Tabulation): value of option + link:weechat_user.sr.html#option_weechat.look.tab_width[weechat.look.tab_width ^↗^,window=_blank] +* U+0001 (1) to U+001F (31), except U+0009 (Tabulation): 1 +* U+00AD (173, soft hyphen): -1 +* U+200B (8203, zero width space): -1 C пример: diff --git a/src/core/wee-utf8.c b/src/core/wee-utf8.c index 6f6526319..c976f7441 100644 --- a/src/core/wee-utf8.c +++ b/src/core/wee-utf8.c @@ -489,18 +489,34 @@ utf8_strnlen (const char *string, int bytes) int utf8_char_size_screen (const char *string) { - int width; + wchar_t codepoint; - if (!string) + if (!string || !string[0]) return 0; if (string[0] == '\t') return CONFIG_INTEGER(config_look_tab_width); - width = wcwidth ((wchar_t)utf8_char_int (string)); + /* + * chars < 32 are displayed with a letter/symbol and reverse video, + * so exactly one column + */ + if (((unsigned char)string[0]) < 32) + return 1; - /* non printable chars are displayed with a space (so size = 1) */ - return (width >= 0) ? width : 1; + codepoint = (wchar_t)utf8_char_int (string); + + /* + * special chars not displayed (because not handled by WeeChat): + * U+00AD: soft hyphen (wcwidth == 1) + * U+200B: zero width space (wcwidth == 0) + */ + if ((codepoint == 0x00AD) || (codepoint == 0x200B)) + { + return -1; + } + + return wcwidth (codepoint); } /* @@ -512,7 +528,7 @@ utf8_char_size_screen (const char *string) int utf8_strlen_screen (const char *string) { - int size_screen; + int size_screen, size_screen_char; const char *ptr_string; if (!string) @@ -525,7 +541,10 @@ utf8_strlen_screen (const char *string) ptr_string = string; while (ptr_string && ptr_string[0]) { - size_screen += utf8_char_size_screen (ptr_string); + size_screen_char = utf8_char_size_screen (ptr_string); + /* count only chars that use at least one column */ + if (size_screen_char > 0) + size_screen += size_screen_char; ptr_string = utf8_next_char (ptr_string); } diff --git a/src/gui/curses/gui-curses-bar-window.c b/src/gui/curses/gui-curses-bar-window.c index 99d64b21b..5d1ea4378 100644 --- a/src/gui/curses/gui-curses-bar-window.c +++ b/src/gui/curses/gui-curses-bar-window.c @@ -361,12 +361,6 @@ gui_bar_window_print_string (struct t_gui_bar_window *bar_window, reverse_video = (gui_window_current_color_attr & A_REVERSE) ? 0 : 1; } - else - { - /* display non printable chars as spaces */ - if (!gui_chat_utf_char_valid (utf_char)) - snprintf (utf_char, sizeof (utf_char), " "); - } while (ptr_char && ptr_char[0]) { @@ -411,8 +405,8 @@ gui_bar_window_print_string (struct t_gui_bar_window *bar_window, *x += size_on_screen; } - ptr_char = utf8_next_char (ptr_char); } + ptr_char = utf8_next_char (ptr_char); } string = utf8_next_char (string); break; diff --git a/src/gui/curses/gui-curses-chat.c b/src/gui/curses/gui-curses-chat.c index e106a43ef..40bc38577 100644 --- a/src/gui/curses/gui-curses-chat.c +++ b/src/gui/curses/gui-curses-chat.c @@ -373,7 +373,8 @@ gui_chat_display_word_raw (struct t_gui_window *window, struct t_gui_line *line, int apply_style_inactive, int nick_offline) { - char *output, utf_char[16], *ptr_char; + const char *ptr_char; + char *output, utf_char[16], utf_char2[16]; int x, chars_displayed, display_char, size_on_screen, reverse_video; if (!simulate) @@ -416,13 +417,6 @@ gui_chat_display_word_raw (struct t_gui_window *window, struct t_gui_line *line, reverse_video = (gui_window_current_color_attr & A_REVERSE) ? 0 : 1; } - else - { - /* display non printable chars as spaces */ - if (!gui_chat_utf_char_valid (utf_char)) - snprintf (utf_char, sizeof (utf_char), " "); - - } display_char = (window->buffer->type != GUI_BUFFER_TYPE_FREE) || (x >= window->scroll->start_col); @@ -433,37 +427,51 @@ gui_chat_display_word_raw (struct t_gui_window *window, struct t_gui_line *line, { return chars_displayed; } - if (display_char && (size_on_screen >= 0)) - { - if (!simulate) - { - output = string_iconv_from_internal (NULL, ptr_char); - if (reverse_video) - { - wattron (GUI_WINDOW_OBJECTS(window)->win_chat, - A_REVERSE); - } - waddstr (GUI_WINDOW_OBJECTS(window)->win_chat, - (output) ? output : ptr_char); - if (reverse_video) - { - wattroff (GUI_WINDOW_OBJECTS(window)->win_chat, - A_REVERSE); - } - if (output) - free (output); - if (gui_window_current_emphasis) + if (display_char) + { + while (ptr_char && ptr_char[0]) + { + utf8_strncpy (utf_char2, ptr_char, 1); + size_on_screen = utf8_char_size_screen (utf_char2); + if (size_on_screen >= 0) { - gui_window_emphasize (GUI_WINDOW_OBJECTS(window)->win_chat, - x - window->scroll->start_col, - window->win_chat_cursor_y, - size_on_screen); + if (!simulate) + { + output = string_iconv_from_internal (NULL, utf_char2); + if (reverse_video) + { + wattron (GUI_WINDOW_OBJECTS(window)->win_chat, + A_REVERSE); + } + waddstr (GUI_WINDOW_OBJECTS(window)->win_chat, + (output) ? output : utf_char2); + if (reverse_video) + { + wattroff (GUI_WINDOW_OBJECTS(window)->win_chat, + A_REVERSE); + } + if (output) + free (output); + + if (gui_window_current_emphasis) + { + gui_window_emphasize (GUI_WINDOW_OBJECTS(window)->win_chat, + x - window->scroll->start_col, + window->win_chat_cursor_y, + size_on_screen); + } + } + chars_displayed += size_on_screen; + x += size_on_screen; } + ptr_char = utf8_next_char (ptr_char); } - chars_displayed += size_on_screen; } - x += size_on_screen; + else + { + x += size_on_screen; + } } string = utf8_next_char (string); diff --git a/src/gui/gui-chat.c b/src/gui/gui-chat.c index f7bc8943f..26d82aaf3 100644 --- a/src/gui/gui-chat.c +++ b/src/gui/gui-chat.c @@ -125,51 +125,6 @@ gui_chat_prefix_build () } } -/* - * Checks if an UTF-8 char is valid for screen. - * - * Returns: - * 1: char is valid - * 0: char is not valid - */ - -int -gui_chat_utf_char_valid (const char *utf_char) -{ - if (!utf_char) - return 0; - - /* chars below 32 are not valid (except TAB) */ - if (((unsigned char)utf_char[0] < 32) && (utf_char[0] != '\t')) - return 0; - - /* 146 or 0x7F are not valid */ - if ((((unsigned char)(utf_char[0]) == 146) - || ((unsigned char)(utf_char[0]) == 0x7F)) - && (!utf_char[1])) - return 0; - - /* any other char is valid */ - return 1; -} - -/* - * Returns number of char needed on screen to display a char. - */ - -int -gui_chat_char_size_screen (const char *utf_char) -{ - if (!utf_char) - return 0; - - /* if char is invalid, it will be displayed as one space on screen */ - if (!gui_chat_utf_char_valid (utf_char)) - return 1; - - return utf8_char_size_screen (utf_char); -} - /* * Returns number of char in a string (special chars like colors/attributes are * ignored). @@ -211,7 +166,7 @@ gui_chat_strlen_screen (const char *string) (unsigned char *)string, 0, 0, 0); if (string) { - size_on_screen = gui_chat_char_size_screen (string); + size_on_screen = utf8_char_size_screen (string); if (size_on_screen > 0) length += size_on_screen; string = utf8_next_char (string); @@ -259,10 +214,13 @@ gui_chat_string_add_offset_screen (const char *string, int offset_screen) 0, 0, 0); if (string) { - size_on_screen = gui_chat_char_size_screen (string); - offset_screen -= size_on_screen; - if (offset_screen < 0) - return string; + size_on_screen = utf8_char_size_screen (string); + if (size_on_screen > 0) + { + offset_screen -= size_on_screen; + if (offset_screen < 0) + return string; + } string = utf8_next_char (string); } } @@ -300,7 +258,7 @@ gui_chat_string_real_pos (const char *string, int pos, int use_screen_size) 0, 0, 0); if (ptr_string) { - size_on_screen = gui_chat_char_size_screen (ptr_string); + size_on_screen = utf8_char_size_screen (ptr_string); if (size_on_screen > 0) pos -= (use_screen_size) ? size_on_screen : 1; ptr_string = utf8_next_char (ptr_string); @@ -382,11 +340,13 @@ gui_chat_get_word_info (struct t_gui_window *window, *word_start_offset = next_char - start_data; leading_spaces = 0; *word_end_offset = next_char2 - start_data - 1; - char_size_screen = gui_chat_char_size_screen (next_char); - (*word_length_with_spaces) += char_size_screen; + char_size_screen = utf8_char_size_screen (next_char); + if (char_size_screen > 0) + (*word_length_with_spaces) += char_size_screen; if (*word_length < 0) *word_length = 0; - (*word_length) += char_size_screen; + if (char_size_screen > 0) + (*word_length) += char_size_screen; } else { diff --git a/src/gui/gui-chat.h b/src/gui/gui-chat.h index 6a5e7b194..c51b23048 100644 --- a/src/gui/gui-chat.h +++ b/src/gui/gui-chat.h @@ -71,7 +71,6 @@ extern int gui_chat_display_tags; extern void gui_chat_init (); extern void gui_chat_prefix_build (); -extern int gui_chat_utf_char_valid (const char *utf_char); extern int gui_chat_strlen (const char *string); extern int gui_chat_strlen_screen (const char *string); extern const char *gui_chat_string_add_offset (const char *string, int offset); diff --git a/tests/unit/core/test-core-command.cpp b/tests/unit/core/test-core-command.cpp index 75216ebbf..7293b9f50 100644 --- a/tests/unit/core/test-core-command.cpp +++ b/tests/unit/core/test-core-command.cpp @@ -151,9 +151,8 @@ TEST(CoreCommand, Debug) { const char *command_debug_unicode = "/debug unicode " - "\u00AD" /* soft hyphen */ "\u00E9" /* é */ - "\u200B" /* zero width space */ + "\u26C4" /* ⛄ (snowman without snow) */ ""; /* test command "/debug list" */ @@ -215,9 +214,8 @@ TEST(CoreCommand, Debug) /* test command "/debug unicode" */ WEE_CMD_CORE(command_debug_unicode); - WEE_CHECK_MSG_CORE(" \"\u00AD\" (U+00AD, 173, 0xC2 0xAD): 2 / 1, 1 / 1, 1, 1, 1"); WEE_CHECK_MSG_CORE(" \"\u00E9\" (U+00E9, 233, 0xC3 0xA9): 2 / 1, 1 / 1, 1, 1, 1"); - WEE_CHECK_MSG_CORE(" \"\u200B\" (U+200B, 8203, 0xE2 0x80 0x8B): 3 / 1, 1 / 0, 0, 0, 0"); + WEE_CHECK_MSG_CORE(" \"\u26C4\" (U+26C4, 9924, 0xE2 0x9B 0x84): 3 / 1, 1 / 2, 2, 2, 2"); /* test command "/debug windows" */ /* TODO: write tests */ diff --git a/tests/unit/core/test-core-utf8.cpp b/tests/unit/core/test-core-utf8.cpp index 2bcb6f3f0..26f42bde2 100644 --- a/tests/unit/core/test-core-utf8.cpp +++ b/tests/unit/core/test-core-utf8.cpp @@ -44,6 +44,30 @@ extern "C" STRCMP_EQUAL(__result, __dest); \ } +/* + * delete: + * [] + * U+007F (127) + * UTF-8: 1 byte = 0x7F + */ +#define UNICODE_DELETE "\u007f" + +/* + * next line: + * [] + * U+0085 (133) + * UTF-8: 2 bytes = 0xC2 0x85 + */ +#define UNICODE_NEXT_LINE "\u0085" + +/* + * private use two: + * [’] + * U+0092 (146) + * UTF-8: 2 bytes = 0xC2 0X92 + */ +#define UNICODE_PRIVATE_USE_TWO "\u0092" + /* * soft hyphen: * [­] @@ -474,6 +498,9 @@ TEST(CoreUtf8, Size) LONGS_EQUAL(2, utf8_char_size ("ë")); LONGS_EQUAL(3, utf8_char_size ("€")); LONGS_EQUAL(1, utf8_char_size ("\x01")); + LONGS_EQUAL(1, utf8_char_size (UNICODE_DELETE)); + LONGS_EQUAL(2, utf8_char_size (UNICODE_NEXT_LINE)); + LONGS_EQUAL(2, utf8_char_size (UNICODE_PRIVATE_USE_TWO)); LONGS_EQUAL(2, utf8_char_size (UNICODE_SOFT_HYPHEN)); LONGS_EQUAL(3, utf8_char_size (UNICODE_ZERO_WIDTH_SPACE)); LONGS_EQUAL(3, utf8_char_size (UNICODE_SNOWMAN)); @@ -495,13 +522,16 @@ TEST(CoreUtf8, Size) LONGS_EQUAL(1, utf8_char_size_screen ("ë")); LONGS_EQUAL(1, utf8_char_size_screen ("€")); LONGS_EQUAL(1, utf8_char_size_screen ("\x01")); - LONGS_EQUAL(1, utf8_char_size_screen (UNICODE_SOFT_HYPHEN)); - LONGS_EQUAL(0, utf8_char_size_screen (UNICODE_ZERO_WIDTH_SPACE)); + LONGS_EQUAL(-1, utf8_char_size_screen (UNICODE_DELETE)); + LONGS_EQUAL(-1, utf8_char_size_screen (UNICODE_NEXT_LINE)); + LONGS_EQUAL(-1, utf8_char_size_screen (UNICODE_PRIVATE_USE_TWO)); + LONGS_EQUAL(-1, utf8_char_size_screen (UNICODE_SOFT_HYPHEN)); + LONGS_EQUAL(-1, utf8_char_size_screen (UNICODE_ZERO_WIDTH_SPACE)); LONGS_EQUAL(2, utf8_char_size_screen (UNICODE_SNOWMAN)); LONGS_EQUAL(2, utf8_char_size_screen (UNICODE_CJK_YELLOW)); LONGS_EQUAL(2, utf8_char_size_screen (UNICODE_HAN_CHAR)); /* ë as iso-8859-15: invalid UTF-8 */ - LONGS_EQUAL(1, utf8_char_size_screen ("\xeb")); + LONGS_EQUAL(-1, utf8_char_size_screen ("\xeb")); /* ël as iso-8859-15: invalid UTF-8 */ LONGS_EQUAL(1, utf8_char_size_screen ("\xebl")); /* ëlm as iso-8859-15: invalid UTF-8 */ @@ -517,6 +547,9 @@ TEST(CoreUtf8, Size) LONGS_EQUAL(1, utf8_strlen ("€")); LONGS_EQUAL(1, utf8_strlen ("\x01")); LONGS_EQUAL(4, utf8_strlen (UTF8_NOEL_VALID)); + LONGS_EQUAL(1, utf8_strlen (UNICODE_DELETE)); + LONGS_EQUAL(1, utf8_strlen (UNICODE_NEXT_LINE)); + LONGS_EQUAL(1, utf8_strlen (UNICODE_PRIVATE_USE_TWO)); LONGS_EQUAL(1, utf8_strlen (UNICODE_SOFT_HYPHEN)); LONGS_EQUAL(1, utf8_strlen (UNICODE_ZERO_WIDTH_SPACE)); LONGS_EQUAL(1, utf8_strlen (UNICODE_SNOWMAN)); @@ -537,13 +570,18 @@ TEST(CoreUtf8, Size) LONGS_EQUAL(1, utf8_strlen_screen ("A")); LONGS_EQUAL(1, utf8_strlen_screen ("ë")); LONGS_EQUAL(1, utf8_strlen_screen ("€")); - LONGS_EQUAL(1, utf8_strlen_screen ("\x7f")); LONGS_EQUAL(1, utf8_strlen_screen ("\x01")); LONGS_EQUAL(4, utf8_strlen_screen (UTF8_NOEL_VALID)); LONGS_EQUAL(4, utf8_strlen_screen ("abc\x01")); LONGS_EQUAL(8, utf8_strlen_screen ("a" "\x01" UTF8_NOEL_VALID "\x02" "b")); - LONGS_EQUAL(1, utf8_strlen_screen (UNICODE_SOFT_HYPHEN)); - LONGS_EQUAL(5, utf8_strlen_screen ("a" "\x01" UNICODE_SOFT_HYPHEN "\x02" "b")); + LONGS_EQUAL(0, utf8_strlen_screen (UNICODE_DELETE)); + LONGS_EQUAL(4, utf8_strlen_screen ("a" "\x01" UNICODE_DELETE "\x02" "b")); + LONGS_EQUAL(0, utf8_strlen_screen (UNICODE_NEXT_LINE)); + LONGS_EQUAL(4, utf8_strlen_screen ("a" "\x01" UNICODE_NEXT_LINE "\x02" "b")); + LONGS_EQUAL(0, utf8_strlen_screen (UNICODE_PRIVATE_USE_TWO)); + LONGS_EQUAL(4, utf8_strlen_screen ("a" "\x01" UNICODE_PRIVATE_USE_TWO "\x02" "b")); + LONGS_EQUAL(0, utf8_strlen_screen (UNICODE_SOFT_HYPHEN)); + LONGS_EQUAL(4, utf8_strlen_screen ("a" "\x01" UNICODE_SOFT_HYPHEN "\x02" "b")); LONGS_EQUAL(0, utf8_strlen_screen (UNICODE_ZERO_WIDTH_SPACE)); LONGS_EQUAL(4, utf8_strlen_screen ("a" "\x01" UNICODE_ZERO_WIDTH_SPACE "\x02" "b")); LONGS_EQUAL(2, utf8_strlen_screen (UNICODE_SNOWMAN)); diff --git a/tests/unit/gui/test-gui-chat.cpp b/tests/unit/gui/test-gui-chat.cpp index e359595e3..f5c8ddfaa 100644 --- a/tests/unit/gui/test-gui-chat.cpp +++ b/tests/unit/gui/test-gui-chat.cpp @@ -26,10 +26,9 @@ extern "C" #include #include "src/gui/gui-buffer.h" #include "src/gui/gui-chat.h" +#include "src/gui/gui-color.h" #include "src/gui/gui-line.h" #include "src/gui/gui-window.h" - -extern int gui_chat_char_size_screen (const char *utf_char); } #define WEE_GET_WORD_INFO(__result_word_start_offset, \ @@ -73,43 +72,6 @@ TEST(GuiChat, PrefixBuild) /* TODO: write tests */ } -/* - * Tests functions: - * gui_chat_utf_char_valid - */ - -TEST(GuiChat, UtfCharValid) -{ - LONGS_EQUAL(0, gui_chat_utf_char_valid (NULL)); - LONGS_EQUAL(0, gui_chat_utf_char_valid ("")); - - LONGS_EQUAL(0, gui_chat_utf_char_valid ("\x01")); - LONGS_EQUAL(0, gui_chat_utf_char_valid ("\x1F")); - - LONGS_EQUAL(0, gui_chat_utf_char_valid ("\x92")); - LONGS_EQUAL(0, gui_chat_utf_char_valid ("\x7F")); - - LONGS_EQUAL(1, gui_chat_utf_char_valid ("\x93")); - LONGS_EQUAL(1, gui_chat_utf_char_valid ("\x80")); - - LONGS_EQUAL(1, gui_chat_utf_char_valid ("abc")); -} - -/* - * Tests functions: - * gui_chat_char_size_screen - */ - -TEST(GuiChat, CharSizeScreen) -{ - LONGS_EQUAL(0, gui_chat_char_size_screen (NULL)); - - LONGS_EQUAL(1, gui_chat_char_size_screen ("\x01")); - - LONGS_EQUAL(1, gui_chat_char_size_screen ("no\xc3\xabl")); - LONGS_EQUAL(2, gui_chat_char_size_screen ("\xe2\xbb\xa9")); -} - /* * Tests functions: * gui_chat_strlen @@ -117,12 +79,33 @@ TEST(GuiChat, CharSizeScreen) TEST(GuiChat, Strlen) { + char string[128]; + LONGS_EQUAL(0, gui_chat_strlen (NULL)); LONGS_EQUAL(0, gui_chat_strlen ("")); + /* soft hyphen */ + LONGS_EQUAL(1, gui_chat_strlen ("\u00ad")); + + /* zero width space */ + LONGS_EQUAL(1, gui_chat_strlen ("\u200b")); + + /* next line (non printable char */ + LONGS_EQUAL(1, gui_chat_strlen ("\u0085")); + LONGS_EQUAL(3, gui_chat_strlen ("abc")); LONGS_EQUAL(4, gui_chat_strlen ("no\xc3\xabl")); LONGS_EQUAL(1, gui_chat_strlen ("\xe2\xbb\xa9")); + + /* "é" + color + "à" */ + snprintf (string, sizeof (string), + "é%sà", gui_color_get_custom ("red")); + LONGS_EQUAL(2, gui_chat_strlen (string)); + + /* "a" + soft hyphen + color + zero width space + "b" */ + snprintf (string, sizeof (string), + "a" "\u00ad" "%s" "\u200b" "b", gui_color_get_custom ("red")); + LONGS_EQUAL(4, gui_chat_strlen (string)); } /* @@ -132,12 +115,33 @@ TEST(GuiChat, Strlen) TEST(GuiChat, StrlenScreen) { + char string[128]; + LONGS_EQUAL(0, gui_chat_strlen_screen (NULL)); LONGS_EQUAL(0, gui_chat_strlen_screen ("")); + /* soft hyphen */ + LONGS_EQUAL(0, gui_chat_strlen_screen ("\u00ad")); + + /* zero width space */ + LONGS_EQUAL(0, gui_chat_strlen_screen ("\u200b")); + + /* next line (non printable char) */ + LONGS_EQUAL(0, gui_chat_strlen_screen ("\u0085")); + LONGS_EQUAL(3, gui_chat_strlen_screen ("abc")); LONGS_EQUAL(4, gui_chat_strlen_screen ("no\xc3\xabl")); LONGS_EQUAL(2, gui_chat_strlen_screen ("\xe2\xbb\xa9")); + + /* "é" + color + "à" */ + snprintf (string, sizeof (string), + "é%sà", gui_color_get_custom ("red")); + LONGS_EQUAL(2, gui_chat_strlen_screen (string)); + + /* "a" + soft hyphen + color + zero width space + "b" */ + snprintf (string, sizeof (string), + "a" "\u00ad" "%s" "\u200b" "b", gui_color_get_custom ("red")); + LONGS_EQUAL(2, gui_chat_strlen_screen (string)); } /* @@ -150,6 +154,8 @@ TEST(GuiChat, StringAddOffset) const char *str_empty = ""; const char *str_noel = "no\xc3\xabl"; const char *str_other = "A\xe2\xbb\xa9Z"; + const char *str_soft_hyphen = "A" "\u00ad" "Z"; + const char *str_zero_width_space = "A" "\u200b" "Z"; POINTERS_EQUAL(NULL, gui_chat_string_add_offset (NULL, -1)); POINTERS_EQUAL(NULL, gui_chat_string_add_offset (NULL, 0)); @@ -174,6 +180,20 @@ TEST(GuiChat, StringAddOffset) POINTERS_EQUAL(str_other + 5, gui_chat_string_add_offset (str_other, 3)); POINTERS_EQUAL(str_other + 5, gui_chat_string_add_offset (str_other, 4)); POINTERS_EQUAL(str_other + 5, gui_chat_string_add_offset (str_other, 5)); + + POINTERS_EQUAL(str_soft_hyphen, gui_chat_string_add_offset (str_soft_hyphen, -1)); + POINTERS_EQUAL(str_soft_hyphen, gui_chat_string_add_offset (str_soft_hyphen, 0)); + POINTERS_EQUAL(str_soft_hyphen + 1, gui_chat_string_add_offset (str_soft_hyphen, 1)); + POINTERS_EQUAL(str_soft_hyphen + 3, gui_chat_string_add_offset (str_soft_hyphen, 2)); + POINTERS_EQUAL(str_soft_hyphen + 4, gui_chat_string_add_offset (str_soft_hyphen, 3)); + POINTERS_EQUAL(str_soft_hyphen + 4, gui_chat_string_add_offset (str_soft_hyphen, 4)); + + POINTERS_EQUAL(str_zero_width_space, gui_chat_string_add_offset (str_zero_width_space, -1)); + POINTERS_EQUAL(str_zero_width_space, gui_chat_string_add_offset (str_zero_width_space, 0)); + POINTERS_EQUAL(str_zero_width_space + 1, gui_chat_string_add_offset (str_zero_width_space, 1)); + POINTERS_EQUAL(str_zero_width_space + 4, gui_chat_string_add_offset (str_zero_width_space, 2)); + POINTERS_EQUAL(str_zero_width_space + 5, gui_chat_string_add_offset (str_zero_width_space, 3)); + POINTERS_EQUAL(str_zero_width_space + 5, gui_chat_string_add_offset (str_zero_width_space, 4)); } /* @@ -186,6 +206,8 @@ TEST(GuiChat, StringAddOffsetScreen) const char *str_empty = ""; const char *str_noel = "no\xc3\xabl"; const char *str_other = "A\xe2\xbb\xa9Z"; + const char *str_soft_hyphen = "A" "\u00ad" "Z"; + const char *str_zero_width_space = "A" "\u200b" "Z"; POINTERS_EQUAL(NULL, gui_chat_string_add_offset_screen (NULL, -1)); POINTERS_EQUAL(NULL, gui_chat_string_add_offset_screen (NULL, 0)); @@ -210,6 +232,18 @@ TEST(GuiChat, StringAddOffsetScreen) POINTERS_EQUAL(str_other + 4, gui_chat_string_add_offset_screen (str_other, 3)); POINTERS_EQUAL(str_other + 5, gui_chat_string_add_offset_screen (str_other, 4)); POINTERS_EQUAL(str_other + 5, gui_chat_string_add_offset_screen (str_other, 5)); + + POINTERS_EQUAL(str_soft_hyphen, gui_chat_string_add_offset_screen (str_soft_hyphen, -1)); + POINTERS_EQUAL(str_soft_hyphen, gui_chat_string_add_offset_screen (str_soft_hyphen, 0)); + POINTERS_EQUAL(str_soft_hyphen + 3, gui_chat_string_add_offset_screen (str_soft_hyphen, 1)); + POINTERS_EQUAL(str_soft_hyphen + 4, gui_chat_string_add_offset_screen (str_soft_hyphen, 2)); + POINTERS_EQUAL(str_soft_hyphen + 4, gui_chat_string_add_offset_screen (str_soft_hyphen, 3)); + + POINTERS_EQUAL(str_zero_width_space, gui_chat_string_add_offset_screen (str_zero_width_space, -1)); + POINTERS_EQUAL(str_zero_width_space, gui_chat_string_add_offset_screen (str_zero_width_space, 0)); + POINTERS_EQUAL(str_zero_width_space + 4, gui_chat_string_add_offset_screen (str_zero_width_space, 1)); + POINTERS_EQUAL(str_zero_width_space + 5, gui_chat_string_add_offset_screen (str_zero_width_space, 2)); + POINTERS_EQUAL(str_zero_width_space + 5, gui_chat_string_add_offset_screen (str_zero_width_space, 3)); } /* @@ -242,6 +276,16 @@ TEST(GuiChat, StringRealPos) LONGS_EQUAL(0, gui_chat_string_real_pos ("\xe2\xbb\xa9", 0, 1)); LONGS_EQUAL(0, gui_chat_string_real_pos ("\xe2\xbb\xa9", 1, 1)); LONGS_EQUAL(3, gui_chat_string_real_pos ("\xe2\xbb\xa9", 2, 1)); + + /* soft hyphen */ + LONGS_EQUAL(0, gui_chat_string_real_pos ("A" "\u00ad" "Z", 0, 0)); + LONGS_EQUAL(3, gui_chat_string_real_pos ("A" "\u00ad" "Z", 1, 0)); + LONGS_EQUAL(4, gui_chat_string_real_pos ("A" "\u00ad" "Z", 2, 0)); + + /* zero width space */ + LONGS_EQUAL(0, gui_chat_string_real_pos ("A" "\u200b" "Z", 0, 1)); + LONGS_EQUAL(4, gui_chat_string_real_pos ("A" "\u200b" "Z", 1, 1)); + LONGS_EQUAL(5, gui_chat_string_real_pos ("A" "\u200b" "Z", 2, 1)); } /* @@ -270,6 +314,16 @@ TEST(GuiChat, StringPos) LONGS_EQUAL(0, gui_chat_string_pos ("\xe2\xbb\xa9", 0)); LONGS_EQUAL(1, gui_chat_string_pos ("\xe2\xbb\xa9", 1)); LONGS_EQUAL(1, gui_chat_string_pos ("\xe2\xbb\xa9", 2)); + + /* soft hyphen */ + LONGS_EQUAL(0, gui_chat_string_pos ("A" "\u00ad" "Z", 0)); + LONGS_EQUAL(1, gui_chat_string_pos ("A" "\u00ad" "Z", 1)); + LONGS_EQUAL(2, gui_chat_string_pos ("A" "\u00ad" "Z", 2)); + + /* zero width space */ + LONGS_EQUAL(0, gui_chat_string_pos ("A" "\u200b" "Z", 0)); + LONGS_EQUAL(1, gui_chat_string_pos ("A" "\u200b" "Z", 1)); + LONGS_EQUAL(2, gui_chat_string_pos ("A" "\u200b" "Z", 2)); } /*