diff options
author | Trygve Aaberge <trygveaa@gmail.com> | 2023-04-09 00:17:52 +0200 |
---|---|---|
committer | Sébastien Helleu <flashcode@flashtux.org> | 2023-04-19 16:47:44 +0200 |
commit | 031bd45e360ce619838d0197442cd39734b0b96f (patch) | |
tree | 2351ffcb33b4f6b0b256ed5bfb197aacfc56885f | |
parent | 2b7f7453692d2325e27e2464e4796b150c708aa4 (diff) | |
download | weechat-031bd45e360ce619838d0197442cd39734b0b96f.zip |
core: render newline characters in chat line messages
If a chat line message contains a newline character (\n) it was
previously rendered as J with reverse video. This commit makes it
render as an actual newline instead, so messages with multiple lines
become supported.
The rendering is fixed in normal mode as well as bare mode both when
scrolled to the bottom and when scrolled up (which is different code
paths). Focus events has also been updated to support this (except for
_chat_line_y which returns -1 for all lines, but the docs says this
variable is only for buffers with free content).
Currently, the only way to include a \n in a chat line message is with
hdata_update because printf splits on \n and creates multiple separate
lines, but hopefully either printf can be changed to not split on \n, or
a new command which doesn't split can be added.
-rw-r--r-- | src/gui/curses/gui-curses-chat.c | 343 | ||||
-rw-r--r-- | src/gui/gui-chat.c | 9 | ||||
-rw-r--r-- | src/gui/gui-chat.h | 3 | ||||
-rw-r--r-- | src/gui/gui-window.c | 14 | ||||
-rw-r--r-- | tests/unit/gui/test-gui-chat.cpp | 33 |
5 files changed, 267 insertions, 135 deletions
diff --git a/src/gui/curses/gui-curses-chat.c b/src/gui/curses/gui-curses-chat.c index 28d3b8520..d7dec68d8 100644 --- a/src/gui/curses/gui-curses-chat.c +++ b/src/gui/curses/gui-curses-chat.c @@ -488,6 +488,80 @@ gui_chat_display_word_raw (struct t_gui_window *window, struct t_gui_line *line, } /* + * Displays the prefix_suffix in the beginning of a line. + * + * Returns number of chars displayed on screen. + */ + +int +gui_chat_display_prefix_suffix (struct t_gui_window *window, + struct t_gui_line *line, + const char *word, + int pre_lines_displayed, int *lines_displayed, + int simulate, + int apply_style_inactive, + int nick_offline) +{ + char str_space[] = " "; + int chars_displayed, length_align; + + chars_displayed = 0; + + /* insert spaces for aligning text under time/nick */ + length_align = gui_line_get_align (window->buffer, line, 0, 0); + + /* in the beginning of a line */ + if ((window->win_chat_cursor_x == 0) + && (*lines_displayed > pre_lines_displayed) + /* FIXME: modify arbitrary value for non aligning messages on time/nick? */ + && (length_align < (window->win_chat_width - 5))) + { + /* in the beginning of a word or in the middle of a word with multiline word align */ + if ((chars_displayed == 0) + || CONFIG_BOOLEAN(config_look_align_multiline_words)) + { + window->win_chat_cursor_x += length_align; + + if ((CONFIG_INTEGER(config_look_align_end_of_lines) == CONFIG_LOOK_ALIGN_END_OF_LINES_MESSAGE) + && (CONFIG_INTEGER(config_look_prefix_align) != CONFIG_LOOK_PREFIX_ALIGN_NONE) + && CONFIG_STRING(config_look_prefix_suffix) + && CONFIG_STRING(config_look_prefix_suffix)[0] + && line->data->date > 0) + { + if (!simulate) + { + gui_window_save_style (GUI_WINDOW_OBJECTS(window)->win_chat); + gui_window_set_weechat_color (GUI_WINDOW_OBJECTS(window)->win_chat, + GUI_COLOR_CHAT_PREFIX_SUFFIX); + gui_window_current_emphasis = 0; + } + chars_displayed += gui_chat_display_word_raw (window, line, + CONFIG_STRING(config_look_prefix_suffix), + 0, simulate, + apply_style_inactive, + nick_offline); + window->win_chat_cursor_x += gui_chat_strlen_screen (CONFIG_STRING(config_look_prefix_suffix)); + chars_displayed += gui_chat_display_word_raw (window, line, + str_space, + 0, simulate, + apply_style_inactive, + nick_offline); + window->win_chat_cursor_x += gui_chat_strlen_screen (str_space); + if (!simulate) + gui_window_restore_style (GUI_WINDOW_OBJECTS(window)->win_chat); + } + } + if (!simulate && (window->win_chat_cursor_y < window->coords_size)) + { + window->coords[window->win_chat_cursor_y].line = line; + window->coords[window->win_chat_cursor_y].data = (char *)word; + } + } + + return chars_displayed; +} + +/* * Displays a word on chat buffer. * * Returns number of chars displayed on screen. @@ -503,9 +577,8 @@ gui_chat_display_word (struct t_gui_window *window, int apply_style_inactive, int nick_offline) { - char *data, *ptr_data, *end_line, saved_char, str_space[] = " "; + char *data, *ptr_data, *end_line, saved_char; int chars_displayed, pos_saved_char, chars_to_display, num_displayed; - int length_align; chars_displayed = 0; @@ -530,56 +603,13 @@ gui_chat_display_word (struct t_gui_window *window, ptr_data = data; while (ptr_data && ptr_data[0]) { - /* insert spaces for aligning text under time/nick */ - length_align = gui_line_get_align (window->buffer, line, 0, 0); - - /* in the beginning of a line */ - if ((window->win_chat_cursor_x == 0) - && (*lines_displayed > pre_lines_displayed) - /* FIXME: modify arbitrary value for non aligning messages on time/nick? */ - && (length_align < (window->win_chat_width - 5))) - { - /* in the beginning of a word or in the middle of a word with multiline word align */ - if ((chars_displayed == 0) - || CONFIG_BOOLEAN(config_look_align_multiline_words)) - { - window->win_chat_cursor_x += length_align; - - if ((CONFIG_INTEGER(config_look_align_end_of_lines) == CONFIG_LOOK_ALIGN_END_OF_LINES_MESSAGE) - && (CONFIG_INTEGER(config_look_prefix_align) != CONFIG_LOOK_PREFIX_ALIGN_NONE) - && CONFIG_STRING(config_look_prefix_suffix) - && CONFIG_STRING(config_look_prefix_suffix)[0] - && line->data->date > 0) - { - if (!simulate) - { - gui_window_save_style (GUI_WINDOW_OBJECTS(window)->win_chat); - gui_window_set_weechat_color (GUI_WINDOW_OBJECTS(window)->win_chat, - GUI_COLOR_CHAT_PREFIX_SUFFIX); - gui_window_current_emphasis = 0; - } - chars_displayed += gui_chat_display_word_raw (window, line, - CONFIG_STRING(config_look_prefix_suffix), - 0, simulate, - apply_style_inactive, - nick_offline); - window->win_chat_cursor_x += gui_chat_strlen_screen (CONFIG_STRING(config_look_prefix_suffix)); - chars_displayed += gui_chat_display_word_raw (window, line, - str_space, - 0, simulate, - apply_style_inactive, - nick_offline); - window->win_chat_cursor_x += gui_chat_strlen_screen (str_space); - if (!simulate) - gui_window_restore_style (GUI_WINDOW_OBJECTS(window)->win_chat); - } - } - if (!simulate && (window->win_chat_cursor_y < window->coords_size)) - { - window->coords[window->win_chat_cursor_y].line = line; - window->coords[window->win_chat_cursor_y].data = (char *)word + (ptr_data - data); - } - } + chars_displayed += gui_chat_display_prefix_suffix(window, line, + word + (ptr_data - data), + pre_lines_displayed, + lines_displayed, + simulate, + apply_style_inactive, + nick_offline); chars_to_display = gui_chat_strlen_screen (ptr_data); @@ -1352,7 +1382,7 @@ gui_chat_display_line (struct t_gui_window *window, struct t_gui_line *line, int num_lines, x, y, pre_lines_displayed, lines_displayed, line_align; int read_marker_x, read_marker_y; int word_start_offset, word_end_offset; - int word_length_with_spaces, word_length; + int word_length_with_spaces, word_length, word_is_newlines; char *message_with_tags, *message_with_search; const char *ptr_data, *ptr_end_offset, *ptr_style, *next_char; struct t_gui_line *ptr_prev_line, *ptr_next_line; @@ -1492,7 +1522,7 @@ gui_chat_display_line (struct t_gui_window *window, struct t_gui_line *line, ptr_data, &word_start_offset, &word_end_offset, - &word_length_with_spaces, &word_length); + &word_length_with_spaces, &word_length, &word_is_newlines); ptr_end_offset = ptr_data + word_end_offset; @@ -1505,43 +1535,68 @@ gui_chat_display_line (struct t_gui_window *window, struct t_gui_line *line, if (word_length >= 0) { - line_align = gui_line_get_align (window->buffer, line, 1, - (lines_displayed == 0) ? 1 : 0); - if ((window->win_chat_cursor_x + word_length_with_spaces > gui_chat_get_real_width (window)) - && (word_length <= gui_chat_get_real_width (window) - line_align)) + if (word_is_newlines) { - /* spaces + word too long for current line but OK for next line */ - gui_chat_display_new_line (window, num_lines, count, - &lines_displayed, simulate); - /* apply styles before jumping to start of word */ - if (!simulate && (word_start_offset > 0)) + /* jump to start of word */ + ptr_data += word_start_offset; + + while (ptr_data && ptr_data[0] == '\n') { - ptr_style = ptr_data; - while (ptr_style < ptr_data + word_start_offset) + gui_chat_display_new_line (window, num_lines, count, + &lines_displayed, simulate); + ptr_data++; + gui_chat_display_prefix_suffix(window, line, + ptr_data, + pre_lines_displayed, &lines_displayed, + simulate, + CONFIG_BOOLEAN(config_look_color_inactive_message), + 0); + } + + if (!ptr_data[0]) + gui_chat_display_new_line (window, num_lines, count, + &lines_displayed, simulate); + } + else + { + line_align = gui_line_get_align (window->buffer, line, 1, + (lines_displayed == 0) ? 1 : 0); + if ((window->win_chat_cursor_x + word_length_with_spaces > gui_chat_get_real_width (window)) + && (word_length <= gui_chat_get_real_width (window) - line_align)) + { + /* spaces + word too long for current line but OK for next line */ + gui_chat_display_new_line (window, num_lines, count, + &lines_displayed, simulate); + /* apply styles before jumping to start of word */ + if (!simulate && (word_start_offset > 0)) { - /* loop until no style/char available */ - ptr_style = gui_chat_string_next_char (window, line, - (unsigned char *)ptr_style, - 1, - CONFIG_BOOLEAN(config_look_color_inactive_message), - 0); - if (!ptr_style) - break; - ptr_style = utf8_next_char (ptr_style); + ptr_style = ptr_data; + while (ptr_style < ptr_data + word_start_offset) + { + /* loop until no style/char available */ + ptr_style = gui_chat_string_next_char (window, line, + (unsigned char *)ptr_style, + 1, + CONFIG_BOOLEAN(config_look_color_inactive_message), + 0); + if (!ptr_style) + break; + ptr_style = utf8_next_char (ptr_style); + } } + /* jump to start of word */ + ptr_data += word_start_offset; } - /* jump to start of word */ - ptr_data += word_start_offset; - } - /* display word */ - gui_chat_display_word (window, line, ptr_data, - ptr_end_offset + 1, - 0, num_lines, count, - pre_lines_displayed, &lines_displayed, - simulate, - CONFIG_BOOLEAN(config_look_color_inactive_message), - 0); + /* display word */ + gui_chat_display_word (window, line, ptr_data, + ptr_end_offset + 1, + 0, num_lines, count, + pre_lines_displayed, &lines_displayed, + simulate, + CONFIG_BOOLEAN(config_look_color_inactive_message), + 0); + } if ((!simulate) && (window->win_chat_cursor_y >= window->win_chat_height)) ptr_data = NULL; @@ -1552,7 +1607,7 @@ gui_chat_display_line (struct t_gui_window *window, struct t_gui_line *line, if (*(ptr_data - 1) == '\0') ptr_data = NULL; - if (window->win_chat_cursor_x == 0) + if (window->win_chat_cursor_x == 0 && !word_is_newlines) { while (ptr_data && (ptr_data[0] == ' ')) { @@ -2107,8 +2162,8 @@ end: void gui_chat_draw_bare (struct t_gui_window *window) { - struct t_gui_line *ptr_line; - char *line; + struct t_gui_line *ptr_gui_line; + char *line, *ptr_line_start, *ptr_line_end; int y, length, num_lines; /* in bare display, we display ONLY the current window/buffer */ @@ -2126,53 +2181,117 @@ gui_chat_draw_bare (struct t_gui_window *window) y = 0; if (window->scroll->start_line) { - ptr_line = window->scroll->start_line; + ptr_gui_line = window->scroll->start_line; window->scroll->first_line_displayed = - (ptr_line == gui_line_get_first_displayed (window->buffer)); + (ptr_gui_line == gui_line_get_first_displayed (window->buffer)); } else { - ptr_line = gui_line_get_first_displayed (window->buffer); + ptr_gui_line = gui_line_get_first_displayed (window->buffer); window->scroll->first_line_displayed = 1; } - while (ptr_line && (y < gui_term_lines)) + while (ptr_gui_line && (y < gui_term_lines)) { - line = gui_chat_get_bare_line (ptr_line); + line = gui_chat_get_bare_line (ptr_gui_line); if (!line) break; - length = utf8_strlen_screen (line); - num_lines = length / gui_term_cols; - if (length % gui_term_cols != 0) - num_lines++; - if (y + num_lines <= gui_term_lines) - printf ("\033[%d;1H%s", y + 1, line); + + ptr_line_start = line; + ptr_line_end = line; + while (ptr_line_start) + { + ptr_line_end = strchr (ptr_line_start, '\n'); + if (ptr_line_end) + ptr_line_end[0] = '\0'; + + length = utf8_strlen_screen (ptr_line_start); + num_lines = length == 0 ? 1 : length / gui_term_cols; + if (length % gui_term_cols != 0) + num_lines++; + if (y + num_lines <= gui_term_lines) + printf ("\033[%d;1H%s", y + 1, ptr_line_start); + y += num_lines; + + if (ptr_line_end) + { + ptr_line_end[0] = '\n'; + ptr_line_start = ptr_line_end + 1; + } + else + { + ptr_line_start = NULL; + } + } + free (line); - y += num_lines; - ptr_line = gui_line_get_next_displayed (ptr_line); + ptr_gui_line = gui_line_get_next_displayed (ptr_gui_line); } } else { /* display from bottom to top (starting with last line of buffer) */ y = gui_term_lines; - ptr_line = gui_line_get_last_displayed (window->buffer); - while (ptr_line && (y >= 0)) + ptr_gui_line = gui_line_get_last_displayed (window->buffer); + while (ptr_gui_line && (y >= 0)) { - line = gui_chat_get_bare_line (ptr_line); + line = gui_chat_get_bare_line (ptr_gui_line); if (!line) break; - length = utf8_strlen_screen (line); - num_lines = length / gui_term_cols; - if (length % gui_term_cols != 0) - num_lines++; - y -= num_lines; + + ptr_line_start = line; + ptr_line_end = line; + while (ptr_line_start) + { + ptr_line_end = strchr (ptr_line_start, '\n'); + if (ptr_line_end) + ptr_line_end[0] = '\0'; + length = utf8_strlen_screen (ptr_line_start); + num_lines = length == 0 ? 1 : length / gui_term_cols; + if (length % gui_term_cols != 0) + num_lines++; + y -= num_lines; + if (ptr_line_end) + { + ptr_line_end[0] = '\n'; + ptr_line_start = ptr_line_end + 1; + } + else + { + ptr_line_start = NULL; + } + } + if (y >= 0) - printf ("\033[%d;1H%s", y + 1, line); + { + printf ("\033[%d;1H", y + 1); + ptr_line_start = line; + ptr_line_end = line; + while (ptr_line_start) + { + ptr_line_end = strchr (ptr_line_start, '\n'); + if (ptr_line_end) + ptr_line_end[0] = '\0'; + + printf ("%s", ptr_line_start); + + if (ptr_line_end) + { + printf ("\r\n"); + ptr_line_end[0] = '\n'; + ptr_line_start = ptr_line_end + 1; + } + else + { + ptr_line_start = NULL; + } + } + } + free (line); - ptr_line = gui_line_get_prev_displayed (ptr_line); + ptr_gui_line = gui_line_get_prev_displayed (ptr_gui_line); } window->scroll->first_line_displayed = - (ptr_line == gui_line_get_first_displayed (window->buffer)); + (ptr_gui_line == gui_line_get_first_displayed (window->buffer)); } /* diff --git a/src/gui/gui-chat.c b/src/gui/gui-chat.c index 6841b95ff..e9b06a7a4 100644 --- a/src/gui/gui-chat.c +++ b/src/gui/gui-chat.c @@ -312,7 +312,8 @@ void gui_chat_get_word_info (struct t_gui_window *window, const char *data, int *word_start_offset, int *word_end_offset, - int *word_length_with_spaces, int *word_length) + int *word_length_with_spaces, int *word_length, + int *word_is_newlines) { const char *start_data, *next_char, *next_char2; int leading_spaces, char_size_screen; @@ -321,6 +322,7 @@ gui_chat_get_word_info (struct t_gui_window *window, *word_end_offset = 0; *word_length_with_spaces = 0; *word_length = -1; + *word_is_newlines = 0; start_data = data; @@ -334,8 +336,11 @@ gui_chat_get_word_info (struct t_gui_window *window, next_char2 = utf8_next_char (next_char); if (next_char2) { - if (next_char[0] != ' ') + if (next_char[0] != ' ' && + (leading_spaces || (next_char[0] == '\n') == *word_is_newlines)) { + if (next_char[0] == '\n') + *word_is_newlines = 1; if (leading_spaces) *word_start_offset = next_char - start_data; leading_spaces = 0; diff --git a/src/gui/gui-chat.h b/src/gui/gui-chat.h index 0971b93f9..28c222a69 100644 --- a/src/gui/gui-chat.h +++ b/src/gui/gui-chat.h @@ -83,7 +83,8 @@ extern void gui_chat_get_word_info (struct t_gui_window *window, const char *data, int *word_start_offset, int *word_end_offset, int *word_length_with_spaces, - int *word_length); + int *word_length, + int *word_is_newlines); extern char *gui_chat_get_time_string (time_t date); extern int gui_chat_get_time_length (); extern void gui_chat_change_time_format (); diff --git a/src/gui/gui-window.c b/src/gui/gui-window.c index 6cb8fc007..8bd621cca 100644 --- a/src/gui/gui-window.c +++ b/src/gui/gui-window.c @@ -141,7 +141,7 @@ gui_window_get_context_at_xy (struct t_gui_window *window, { int win_x, win_y, coords_x_message; char *data_next_line, *str_temp; - const char *ptr_data, *word_start, *word_end, *last_space; + const char *ptr_data, *word_start, *word_end, *last_whitespace; *chat = 0; *line = NULL; @@ -227,9 +227,9 @@ gui_window_get_context_at_xy (struct t_gui_window *window, free (str_temp); } *end = gui_color_decode (ptr_data, NULL); - if (ptr_data[0] != ' ') + if (ptr_data[0] != ' ' && ptr_data[0] != '\n') { - last_space = NULL; + last_whitespace = NULL; word_start = (*line)->data->message; while (word_start && (word_start < ptr_data)) { @@ -238,12 +238,12 @@ gui_window_get_context_at_xy (struct t_gui_window *window, 0, 0, 0); if (word_start) { - if (word_start[0] == ' ') - last_space = word_start; + if (word_start[0] == ' ' || word_start[0] == '\n') + last_whitespace = word_start; word_start = utf8_next_char (word_start); } } - word_start = (last_space) ? last_space + 1 : (*line)->data->message; + word_start = (last_whitespace) ? last_whitespace + 1 : (*line)->data->message; word_end = ptr_data; while (word_end && word_end[0]) { @@ -252,7 +252,7 @@ gui_window_get_context_at_xy (struct t_gui_window *window, 0, 0, 0); if (word_end) { - if (word_end[0] == ' ') + if (word_end[0] == ' ' || word_end[0] == '\n') break; word_end = utf8_next_char (word_end); } diff --git a/tests/unit/gui/test-gui-chat.cpp b/tests/unit/gui/test-gui-chat.cpp index 96c93c4ed..99152886b 100644 --- a/tests/unit/gui/test-gui-chat.cpp +++ b/tests/unit/gui/test-gui-chat.cpp @@ -34,19 +34,23 @@ extern "C" #define WEE_GET_WORD_INFO(__result_word_start_offset, \ __result_word_end_offset, \ __result_word_length_with_spaces, \ - __result_word_length, __string) \ + __result_word_length, \ + __result_word_is_newlines, __string) \ word_start_offset = -2; \ word_end_offset = -2; \ word_length_with_spaces = -2; \ word_length = -2; \ + word_is_newlines = -2; \ gui_chat_get_word_info (gui_windows, __string, \ &word_start_offset, &word_end_offset, \ - &word_length_with_spaces, &word_length); \ + &word_length_with_spaces, &word_length, \ + &word_is_newlines); \ LONGS_EQUAL(__result_word_start_offset, word_start_offset); \ LONGS_EQUAL(__result_word_end_offset, word_end_offset); \ LONGS_EQUAL(__result_word_length_with_spaces, \ word_length_with_spaces); \ - LONGS_EQUAL(__result_word_length, word_length); + LONGS_EQUAL(__result_word_length, word_length); \ + LONGS_EQUAL(__result_word_is_newlines, word_is_newlines); TEST_GROUP(GuiChat) { @@ -334,16 +338,19 @@ TEST(GuiChat, StringPos) TEST(GuiChat, GetWordInfo) { int word_start_offset, word_end_offset, word_length_with_spaces; - int word_length; - - WEE_GET_WORD_INFO (0, 0, 0, -1, NULL); - WEE_GET_WORD_INFO (0, 0, 0, -1, ""); - WEE_GET_WORD_INFO (0, 0, 1, 1, "a"); - WEE_GET_WORD_INFO (0, 2, 3, 3, "abc"); - WEE_GET_WORD_INFO (2, 4, 5, 3, " abc"); - WEE_GET_WORD_INFO (2, 4, 5, 3, " abc "); - WEE_GET_WORD_INFO (0, 4, 5, 5, "first second"); - WEE_GET_WORD_INFO (1, 5, 6, 5, " first second"); + int word_length, word_is_newlines; + + WEE_GET_WORD_INFO (0, 0, 0, -1, 0, NULL); + WEE_GET_WORD_INFO (0, 0, 0, -1, 0, ""); + WEE_GET_WORD_INFO (0, 0, 1, 1, 0, "a"); + WEE_GET_WORD_INFO (0, 2, 3, 3, 0, "abc"); + WEE_GET_WORD_INFO (2, 4, 5, 3, 0, " abc"); + WEE_GET_WORD_INFO (2, 4, 5, 3, 0, " abc "); + WEE_GET_WORD_INFO (0, 4, 5, 5, 0, "first second"); + WEE_GET_WORD_INFO (1, 5, 6, 5, 0, " first second"); + WEE_GET_WORD_INFO (0, 0, 1, 1, 1, "\nabc"); + WEE_GET_WORD_INFO (2, 2, 3, 1, 1, " \nabc"); + WEE_GET_WORD_INFO (2, 3, 4, 2, 1, " \n\nabc"); } /* |