diff --git a/doc/en/weechat_plugin_api.en.adoc b/doc/en/weechat_plugin_api.en.adoc index 9e4f8b8a3..c348c570d 100644 --- a/doc/en/weechat_plugin_api.en.adoc +++ b/doc/en/weechat_plugin_api.en.adoc @@ -10628,7 +10628,7 @@ hook = weechat.hook_connect("", "my.server.org", 1234, 1, 0, "", ==== hook_line -_WeeChat ≥ 2.3, updated in 3.7._ +_WeeChat ≥ 2.3, updated in 3.7, 4.1.0._ Hook a line to be printed in a buffer. @@ -10699,13 +10699,13 @@ Line data sent to the callback is a hashtable, with following values | Key | Value (formatted buffer) | Value (free buffer) | Examples | buffer -| Buffer pointer. -| Buffer pointer. +| Comma-separated list of buffer pointers. +| Comma-separated list of buffer pointers. | `+0x1234abcd+` | buffer_name -| Buffer name. -| Buffer name. +| Comma-separated list of buffer names. +| Comma-separated list of buffer names. | `+core.weechat+` + `+irc.server.libera+` + `+irc.libera.#weechat+` @@ -10793,16 +10793,20 @@ in this hashtable): | Key | Allowed value (formatted buffer) | Allowed value (free buffer) | Result | buffer -| Pointer of a buffer with formatted content. -| Pointer of a buffer with free content. -| The line is displayed on this buffer. + +| Comma-separated list buffer pointers (with formatted content) + (multiple buffers are supported only with WeeChat ≥ 4.1.0). +| Comma-separated list buffer pointers (with free content) + (multiple buffers are supported only with WeeChat ≥ 4.1.0). +| The line is displayed on these buffers. + If the value is empty, the line is deleted (anything else in the hashtable is then ignored); the next hooks of type "line" are not called. | buffer_name -| Name of a buffer with formatted content. -| Name of a buffer with free content. -| The line is displayed on this buffer. + +| Comma-separated list buffer names (with formatted content) + (multiple buffers are supported only with WeeChat ≥ 4.1.0). +| Comma-separated list buffer names (with free content) + (multiple buffers are supported only with WeeChat ≥ 4.1.0). +| The line is displayed on these buffers. + If `buffer` is also set, the value of `+buffer_name+` has higher priority and is used. + If the value is empty, the line is deleted (anything else in the hashtable is then ignored); the next hooks of type "line" are not called. diff --git a/doc/fr/weechat_plugin_api.fr.adoc b/doc/fr/weechat_plugin_api.fr.adoc index c0d52917a..957715cd3 100644 --- a/doc/fr/weechat_plugin_api.fr.adoc +++ b/doc/fr/weechat_plugin_api.fr.adoc @@ -10831,7 +10831,7 @@ hook = weechat.hook_connect("", "my.server.org", 1234, 1, 0, "", ==== hook_line -_WeeChat ≥ 2.3, mis à jour dans la 3.7._ +_WeeChat ≥ 2.3, mis à jour dans la 3.7, 4.1.0._ Intercepter une ligne sur le point d'être affichée dans un tampon. @@ -10909,13 +10909,13 @@ de hachage, avec les valeurs suivantes (les clés et valeurs sont des chaînes) | Clé | Valeur (tampon formaté) | Valeur (tampon libre) | Exemples | buffer -| Pointeur vers le tampon. -| Pointeur vers le tampon. +| Liste de pointeurs vers les tampons, séparés par des virgules. +| Liste de pointeurs vers les tampons, séparés par des virgules. | `+0x1234abcd+` | buffer_name -| Nom du tampon. -| Nom du tampon. +| Liste de noms de tampons, séparés par des virgules. +| Liste de noms de tampons, séparés par des virgules. | `+core.weechat+` + `+irc.server.libera+` + `+irc.libera.#weechat+` @@ -11004,16 +11004,20 @@ valeurs sont des chaînes dans cette table de hachage) : | Clé | Valeur autorisée (tampon formaté) | Valeur autorisée (tampon libre) | Résultat | buffer -| Pointeur vers un tampon avec contenu formaté. -| Pointeur vers un tampon avec contenu libre. -| La ligne est affichée sur ce tampon. + +| Liste de pointeurs vers les tampons, séparés par des virgules (avec contenu formaté) + (plusieurs tampons sont supportés seulement avec WeeChat ≥ 4.1.0). +| Liste de pointeurs vers les tampons, séparés par des virgules (avec contenu libre) + (plusieurs tampons sont supportés seulement avec WeeChat ≥ 4.1.0). +| La ligne est affichée sur ces tampons. + Si la valeur est vide, la ligne est supprimée (le reste de la table de hachage est alors ignoré) ; les "hooks" suivants de type "line" ne sont pas appelés. | buffer_name -| Nom d'un tampon avec contenu formaté. -| Nom d'un tampon avec contenu libre. -| La ligne est affichée sur ce tampon. + +| Liste de noms de tampons, séparés par des virgules (avec contenu formaté) + (multiple buffers are supported only with WeeChat ≥ 4.1.0). +| Liste de noms de tampons, séparés par des virgules (avec contenu libre) + (multiple buffers are supported only with WeeChat ≥ 4.1.0). +| La ligne est affichée sur ces tampons. + Si `buffer` est également défini, la valeur de `+buffer_name+` a une priorité plus haute est est utilisée. + Si la valeur est vide, la ligne est supprimée (le reste de la table de hachage diff --git a/doc/it/weechat_plugin_api.it.adoc b/doc/it/weechat_plugin_api.it.adoc index 4026f38c4..6cda03dbe 100644 --- a/doc/it/weechat_plugin_api.it.adoc +++ b/doc/it/weechat_plugin_api.it.adoc @@ -11016,7 +11016,7 @@ hook = weechat.hook_connect("", "my.server.org", 1234, 1, 0, "", // TRANSLATION MISSING ==== hook_line -_WeeChat ≥ 2.3, updated in 3.7._ +_WeeChat ≥ 2.3, updated in 3.7, 4.1.0._ Hook a line to be printed in a buffer. @@ -11087,13 +11087,13 @@ Line data sent to the callback is a hashtable, with following values | Key | Value (formatted buffer) | Value (free buffer) | Examples | buffer -| Buffer pointer. -| Buffer pointer. +| Comma-separated list of buffer pointers. +| Comma-separated list of buffer pointers. | `+0x1234abcd+` | buffer_name -| Buffer name. -| Buffer name. +| Comma-separated list of buffer names. +| Comma-separated list of buffer names. | `+core.weechat+` + `+irc.server.libera+` + `+irc.libera.#weechat+` @@ -11181,16 +11181,20 @@ in this hashtable): | Key | Allowed value (formatted buffer) | Allowed value (free buffer) | Result | buffer -| Pointer of a buffer with formatted content. -| Pointer of a buffer with free content. -| The line is displayed on this buffer. + +| Comma-separated list buffer pointers (with formatted content) + (multiple buffers are supported only with WeeChat ≥ 4.1.0). +| Comma-separated list buffer pointers (with free content) + (multiple buffers are supported only with WeeChat ≥ 4.1.0). +| The line is displayed on these buffers. + If the value is empty, the line is deleted (anything else in the hashtable is then ignored); the next hooks of type "line" are not called. | buffer_name -| Name of a buffer with formatted content. -| Name of a buffer with free content. -| The line is displayed on this buffer. + +| Comma-separated list buffer names (with formatted content) + (multiple buffers are supported only with WeeChat ≥ 4.1.0). +| Comma-separated list buffer names (with free content) + (multiple buffers are supported only with WeeChat ≥ 4.1.0). +| The line is displayed on these buffers. + If `buffer` is also set, the value of `+buffer_name+` has higher priority and is used. + If the value is empty, the line is deleted (anything else in the hashtable is then ignored); the next hooks of type "line" are not called. diff --git a/doc/ja/weechat_plugin_api.ja.adoc b/doc/ja/weechat_plugin_api.ja.adoc index bdc9d1908..94a4830e9 100644 --- a/doc/ja/weechat_plugin_api.ja.adoc +++ b/doc/ja/weechat_plugin_api.ja.adoc @@ -10741,7 +10741,7 @@ hook = weechat.hook_connect("", "my.server.org", 1234, 1, 0, "", ==== hook_line // TRANSLATION MISSING -_WeeChat ≥ 2.3, updated in 3.7._ +_WeeChat ≥ 2.3, updated in 3.7, 4.1.0._ バッファに対する行表示をフックする。 @@ -10811,14 +10811,16 @@ struct t_hook *weechat_hook_line (const char *buffer_type, |=== | キー | 値 (フォーマット済みバッファ) | 値 (自由内容バッファ) | 例 +// TRANSLATION MISSING | buffer -| バッファポインタ -| バッファポインタ +| Comma-separated list of buffer pointers. +| Comma-separated list of buffer pointers. | `+0x1234abcd+` +// TRANSLATION MISSING | buffer_name -| バッファ名 -| バッファ名 +| Comma-separated list of buffer names. +| Comma-separated list of buffer names. | `+core.weechat+` + `+irc.server.libera+` + `+irc.libera.#weechat+` @@ -10906,17 +10908,23 @@ WeeChat はそれらを無視します。 |=== | キー | 設定可能な値 (フォーマット済みバッファ) | 設定可能な値 (自由内容バッファ) | 結果 +// TRANSLATION MISSING | buffer -| フォーマット済みバッファへのポインタ -| 自由内容バッファへのポインタ -| 行を表示するバッファ。 + +| Comma-separated list buffer pointers (with formatted content) + (multiple buffers are supported only with WeeChat ≥ 4.1.0). +| Comma-separated list buffer pointers (with free content) + (multiple buffers are supported only with WeeChat ≥ 4.1.0). +| The line is displayed on these buffers. + この値が空の場合、行は削除されます (ハッシュテーブルに含まれるその他の情報も無視されます); "line" 型の次のフックも呼び出されません。 +// TRANSLATION MISSING | buffer_name -| フォーマット済み内容バッファの名前. -| 自由内容バッファの名前 -| 行を表示するバッファ。 + +| Comma-separated list buffer names (with formatted content) + (multiple buffers are supported only with WeeChat ≥ 4.1.0). +| Comma-separated list buffer names (with free content) + (multiple buffers are supported only with WeeChat ≥ 4.1.0). +| The line is displayed on these buffers. + `buffer` と `+buffer_name+` の両方が設定された場合、`+buffer_name+` の値が優先されます + この値が空の場合、行は削除されます (ハッシュテーブルに含まれるその他の情報も無視されます); "line" 型の次のフックも呼び出されません。 diff --git a/doc/sr/weechat_plugin_api.sr.adoc b/doc/sr/weechat_plugin_api.sr.adoc index fa26cfc82..1b600e3fc 100644 --- a/doc/sr/weechat_plugin_api.sr.adoc +++ b/doc/sr/weechat_plugin_api.sr.adoc @@ -10293,7 +10293,7 @@ hook = weechat.hook_connect("", "my.server.org", 1234, 1, 0, "", ==== hook_line -_WeeChat ≥ 2.3, ажурирано у 3.7._ +_WeeChat ≥ 2.3, ажурирано у 3.7, 4.1.0._ Качи се на линију која треба да се испише у бафер. @@ -10349,14 +10349,16 @@ struct t_hook *weechat_hook_line (const char *buffer_type, |=== | Кључ | Вредност (форматирани бафер) | Вредност (слободни бафер) | Примери +// TRANSLATION MISSING | buffer -| Показивач на бафер. -| Показивач на бафер. +| Comma-separated list of buffer pointers. +| Comma-separated list of buffer pointers. | `+0x1234abcd+` +// TRANSLATION MISSING | buffer_name -| Име бафера. -| Име бафера. +| Comma-separated list of buffer names. +| Comma-separated list of buffer names. | `+core.weechat+` + `+irc.server.libera+` + `+irc.libera.#weechat+` @@ -10441,17 +10443,23 @@ struct t_hook *weechat_hook_line (const char *buffer_type, |=== | Кључ | Дозвољена вредност (форматирани бафер) | Дозвољена вредност (слободни бафер) | Резултат +// TRANSLATION MISSING | buffer -| Показивач на бафер са форматираним садржајем. -| Показивач на бафер са слободним садржајем. -| Линија се приказује у овом баферу. + +| Comma-separated list buffer pointers (with formatted content) + (multiple buffers are supported only with WeeChat ≥ 4.1.0). +| Comma-separated list buffer pointers (with free content) + (multiple buffers are supported only with WeeChat ≥ 4.1.0). +| The line is displayed on these buffers. + Ако је вредност празна, линија се брише (тада се све остало у хеш табели игнорише); наредне куке типа „line” се не позивају. +// TRANSLATION MISSING | buffer_name -| Име бафера са форматираним садржајем. -| Име бафера са слободним садржајем. -| Линија се приказује у овом баферу. + +| Comma-separated list buffer names (with formatted content) + (multiple buffers are supported only with WeeChat ≥ 4.1.0). +| Comma-separated list buffer names (with free content) + (multiple buffers are supported only with WeeChat ≥ 4.1.0). +| The line is displayed on these buffers. + Ако је и `buffer` постављено, вредност `+buffer_name+` има виши приоритет и она се користи. + Ако је вредност празна, линија се брише (тада се све остало у хеш табели игнорише); наредне куке типа „line” се не позивају. diff --git a/src/core/hook/wee-hook-line.c b/src/core/hook/wee-hook-line.c index 6b3305fc4..3894df59b 100644 --- a/src/core/hook/wee-hook-line.c +++ b/src/core/hook/wee-hook-line.c @@ -27,6 +27,7 @@ #include #include "../weechat.h" +#include "../wee-arraylist.h" #include "../wee-hashtable.h" #include "../wee-hook.h" #include "../wee-infolist.h" @@ -121,17 +122,31 @@ hook_line (struct t_weechat_plugin *plugin, const char *buffer_type, * Executes a line hook and updates the line data. */ -void +struct t_arraylist * hook_line_exec (struct t_gui_line *line) { struct t_hook *ptr_hook, *next_hook; struct t_hashtable *hashtable, *hashtable2; - char str_value[128], *str_tags; - - if (!weechat_hooks[HOOK_TYPE_LINE]) - return; + struct t_arraylist *buffers; + struct t_gui_buffer *ptr_buffer; + char str_value[128], *str_tags, **str_buffers; + int i, size; hashtable = NULL; + buffers = NULL; + str_buffers = NULL; + + buffers = arraylist_new (16, 0, 0, NULL, NULL, NULL, NULL); + if (!buffers) + goto end; + arraylist_add (buffers, line->data->buffer); + + if (!weechat_hooks[HOOK_TYPE_LINE]) + goto end; + + str_buffers = string_dyn_alloc (256); + if (!str_buffers) + goto end; hook_exec_start (); @@ -161,8 +176,28 @@ hook_line_exec (struct t_gui_line *line) if (!hashtable) break; } - HASHTABLE_SET_POINTER("buffer", line->data->buffer); - HASHTABLE_SET_STR("buffer_name", line->data->buffer->full_name); + size = arraylist_size (buffers); + /* build list of buffer pointers */ + string_dyn_copy (str_buffers, NULL); + for (i = 0; i < size; i++) + { + if (i > 0) + string_dyn_concat (str_buffers, ",", -1); + snprintf (str_value, sizeof (str_value), + "0x%lx", (unsigned long)(arraylist_get (buffers, i))); + string_dyn_concat (str_buffers, str_value, -1); + } + HASHTABLE_SET_STR("buffer", *str_buffers); + /* build list of buffer names */ + string_dyn_copy (str_buffers, NULL); + for (i = 0; i < size; i++) + { + if (i > 0) + string_dyn_concat (str_buffers, ",", -1); + ptr_buffer = (struct t_gui_buffer *)arraylist_get (buffers, i); + string_dyn_concat (str_buffers, ptr_buffer->full_name, -1); + } + HASHTABLE_SET_STR("buffer_name", *str_buffers); HASHTABLE_SET_STR("buffer_type", gui_buffer_type_string[line->data->buffer->type]); HASHTABLE_SET_INT("y", line->data->y); @@ -191,7 +226,7 @@ hook_line_exec (struct t_gui_line *line) if (hashtable2) { - gui_line_hook_update (line, hashtable, hashtable2); + gui_line_hook_update (line, buffers, hashtable, hashtable2); hashtable_free (hashtable2); if (!line->data->buffer) break; @@ -203,8 +238,17 @@ hook_line_exec (struct t_gui_line *line) hook_exec_end (); +end: if (hashtable) hashtable_free (hashtable); + + if (str_buffers) + string_dyn_free (str_buffers, 1); + + if (line->data->buffer && buffers && (arraylist_size (buffers) == 0)) + arraylist_add (buffers, line->data->buffer); + + return buffers; } /* diff --git a/src/core/hook/wee-hook-line.h b/src/core/hook/wee-hook-line.h index 9d6160f54..470c8ca23 100644 --- a/src/core/hook/wee-hook-line.h +++ b/src/core/hook/wee-hook-line.h @@ -51,7 +51,7 @@ extern struct t_hook *hook_line (struct t_weechat_plugin *plugin, t_hook_callback_line *callback, const void *callback_pointer, void *callback_data); -extern void hook_line_exec (struct t_gui_line *line); +extern struct t_arraylist *hook_line_exec (struct t_gui_line *line); extern void hook_line_free_data (struct t_hook *hook); extern int hook_line_add_to_infolist (struct t_infolist_item *item, struct t_hook *hook); diff --git a/src/gui/gui-chat.c b/src/gui/gui-chat.c index 0eb3d168c..70e5c7de9 100644 --- a/src/gui/gui-chat.c +++ b/src/gui/gui-chat.c @@ -32,6 +32,7 @@ #include #include "../core/weechat.h" +#include "../core/wee-arraylist.h" #include "../core/wee-config.h" #include "../core/wee-eval.h" #include "../core/wee-hashtable.h" @@ -592,15 +593,18 @@ gui_chat_printf_date_tags_internal (struct t_gui_buffer *buffer, const char *tags, char *message) { - int display_time, length_data, length_str; + int i, display_time, length_data, length_str, num_buffers; char *ptr_msg, *pos_prefix, *pos_tab; char *modifier_data, *string, *new_string, *pos_newline; - struct t_gui_line *new_line; + struct t_gui_line *new_line, *new_line2; + struct t_arraylist *buffers; new_line = NULL; + new_line2 = NULL; string = NULL; modifier_data = NULL; new_string = NULL; + buffers = NULL; display_time = 1; @@ -643,134 +647,132 @@ gui_chat_printf_date_tags_internal (struct t_gui_buffer *buffer, if (!new_line) goto no_print; - hook_line_exec (new_line); - - if (!new_line->data->buffer) + buffers = hook_line_exec (new_line); + if (!buffers || !new_line->data->buffer) goto no_print; - /* call modifier for message printed ("weechat_print") */ - length_data = 64 + 1 + ((tags) ? strlen (tags) : 0) + 1; - modifier_data = malloc (length_data); - length_str = ((new_line->data->prefix && new_line->data->prefix[0]) ? strlen (new_line->data->prefix) : 1) + - 1 + - (new_line->data->message ? strlen (new_line->data->message) : 0) + - 1; - string = malloc (length_str); - if (modifier_data && string) + num_buffers = arraylist_size (buffers); + for (i = 0; i < num_buffers; i++) { - snprintf (modifier_data, length_data, - "0x%lx;%s", - (unsigned long)buffer, - (tags) ? tags : ""); - if (display_time) - { - snprintf (string, length_str, - "%s\t%s", - (new_line->data->prefix && new_line->data->prefix[0]) ? - new_line->data->prefix : " ", - (new_line->data->message) ? new_line->data->message : ""); - } - else - { - snprintf (string, length_str, - "\t\t%s", - (new_line->data->message) ? new_line->data->message : ""); - } - new_string = hook_modifier_exec (NULL, - "weechat_print", - modifier_data, - string); - if (new_string) - { - if (!new_string[0] && string[0]) - { - /* - * modifier returned empty message, then we'll not - * print anything - */ - goto no_print; - } - else if (strcmp (string, new_string) != 0) - { - if (!buffer->input_multiline) - { - /* if input_multiline is not set, keep only first line */ - pos_newline = strchr (new_string, '\n'); - if (pos_newline) - pos_newline[0] = '\0'; - } + new_line2 = gui_line_dup_for_buffer (new_line, + arraylist_get (buffers, i)); + if (!new_line2) + goto no_print; - /* use new message if there are changes */ - display_time = 1; - pos_prefix = NULL; - ptr_msg = new_string; - /* space followed by tab => prefix ignored */ - if ((ptr_msg[0] == ' ') && (ptr_msg[1] == '\t')) + /* call modifier for message printed ("weechat_print") */ + length_data = 64 + 1 + ((tags) ? strlen (tags) : 0) + 1; + modifier_data = malloc (length_data); + length_str = ((new_line2->data->prefix && new_line2->data->prefix[0]) ? strlen (new_line2->data->prefix) : 1) + + 1 + + (new_line2->data->message ? strlen (new_line2->data->message) : 0) + + 1; + string = malloc (length_str); + if (modifier_data && string) + { + snprintf (modifier_data, length_data, + "0x%lx;%s", + (unsigned long)buffer, + (tags) ? tags : ""); + if (display_time) + { + snprintf (string, length_str, + "%s\t%s", + (new_line2->data->prefix && new_line2->data->prefix[0]) ? + new_line2->data->prefix : " ", + (new_line2->data->message) ? new_line2->data->message : ""); + } + else + { + snprintf (string, length_str, + "\t\t%s", + (new_line2->data->message) ? new_line2->data->message : ""); + } + new_string = hook_modifier_exec (NULL, + "weechat_print", + modifier_data, + string); + if (new_string) + { + if (!new_string[0] && string[0]) { - ptr_msg += 2; + /* + * modifier returned empty message, then we'll not + * print anything + */ + goto no_print; } - else + else if (strcmp (string, new_string) != 0) { - /* if two first chars are tab, then do not display time */ - if ((ptr_msg[0] == '\t') && (ptr_msg[1] == '\t')) + if (!buffer->input_multiline) + { + /* if input_multiline is not set, keep only first line */ + pos_newline = strchr (new_string, '\n'); + if (pos_newline) + pos_newline[0] = '\0'; + } + + /* use new message if there are changes */ + display_time = 1; + pos_prefix = NULL; + ptr_msg = new_string; + /* space followed by tab => prefix ignored */ + if ((ptr_msg[0] == ' ') && (ptr_msg[1] == '\t')) { - display_time = 0; - new_line->data->date = 0; ptr_msg += 2; } else { - /* if tab found, use prefix (before tab) */ - pos_tab = strchr (ptr_msg, '\t'); - if (pos_tab) + /* if two first chars are tab, then do not display time */ + if ((ptr_msg[0] == '\t') && (ptr_msg[1] == '\t')) { - pos_tab[0] = '\0'; - pos_prefix = ptr_msg; - ptr_msg = pos_tab + 1; + display_time = 0; + new_line2->data->date = 0; + ptr_msg += 2; + } + else + { + /* if tab found, use prefix (before tab) */ + pos_tab = strchr (ptr_msg, '\t'); + if (pos_tab) + { + pos_tab[0] = '\0'; + pos_prefix = ptr_msg; + ptr_msg = pos_tab + 1; + } } } + if ((new_line2->data->date == 0) && display_time) + new_line2->data->date = new_line2->data->date_printed; + if (new_line2->data->prefix) + string_shared_free (new_line2->data->prefix); + if (pos_prefix) + { + new_line2->data->prefix = (char *)string_shared_get (pos_prefix); + } + else + { + new_line2->data->prefix = (new_line2->data->date != 0) ? + (char *)string_shared_get ("") : NULL; + } + new_line2->data->prefix_length = gui_chat_strlen_screen ( + new_line2->data->prefix); + if (new_line2->data->message) + free (new_line2->data->message); + new_line2->data->message = strdup (ptr_msg); } - if ((new_line->data->date == 0) && display_time) - new_line->data->date = new_line->data->date_printed; - if (new_line->data->prefix) - string_shared_free (new_line->data->prefix); - if (pos_prefix) - { - new_line->data->prefix = (char *)string_shared_get (pos_prefix); - } - else - { - new_line->data->prefix = (new_line->data->date != 0) ? - (char *)string_shared_get ("") : NULL; - } - new_line->data->prefix_length = gui_chat_strlen_screen ( - new_line->data->prefix); - if (new_line->data->message) - free (new_line->data->message); - new_line->data->message = strdup (ptr_msg); } } + + /* add line in the buffer */ + gui_line_add (new_line2); + + /* run hook_print for the new line */ + if (new_line2->data->buffer && new_line2->data->buffer->print_hooks_enabled) + hook_print_exec (new_line2->data->buffer, new_line2); + + gui_buffer_ask_chat_refresh (new_line2->data->buffer, 1); } - /* add line in the buffer */ - gui_line_add (new_line); - - /* run hook_print for the new line */ - if (new_line->data->buffer && new_line->data->buffer->print_hooks_enabled) - hook_print_exec (new_line->data->buffer, new_line); - - gui_buffer_ask_chat_refresh (new_line->data->buffer, 1); - - if (string) - free (string); - if (modifier_data) - free (modifier_data); - if (new_string) - free (new_string); - - return; - -no_print: if (new_line) { gui_line_free_data (new_line); @@ -782,6 +784,30 @@ no_print: free (modifier_data); if (new_string) free (new_string); + if (buffers) + arraylist_free (buffers); + + return; + +no_print: + if (new_line) + { + gui_line_free_data (new_line); + free (new_line); + } + if (new_line2) + { + gui_line_free_data (new_line2); + free (new_line2); + } + if (string) + free (string); + if (modifier_data) + free (modifier_data); + if (new_string) + free (new_string); + if (buffers) + arraylist_free (buffers); } /* @@ -932,9 +958,13 @@ void gui_chat_printf_y_date_tags (struct t_gui_buffer *buffer, int y, time_t date, const char *tags, const char *message, ...) { - struct t_gui_line *ptr_line, *new_line, *new_line_empty; + struct t_gui_line *ptr_line, *new_line, *new_line2, *new_line_empty; + struct t_arraylist *buffers; time_t date_printed; - int i, last_y, num_lines_to_add; + int i, last_y, num_lines_to_add, num_buffers; + + new_line = NULL; + buffers = NULL; if (!message) return; @@ -964,84 +994,96 @@ gui_chat_printf_y_date_tags (struct t_gui_buffer *buffer, int y, time_t date, if (!new_line) goto end; - hook_line_exec (new_line); - - if (!new_line->data->buffer) + buffers = hook_line_exec (new_line); + if (!buffers || !new_line->data->buffer) { gui_line_free_data (new_line); free (new_line); goto end; } - if (new_line->data->message && new_line->data->message[0]) + num_buffers = arraylist_size (buffers); + for (i = 0; i < num_buffers; i++) { - if (gui_init_ok) + new_line2 = gui_line_dup_for_buffer (new_line, + arraylist_get (buffers, i)); + if (new_line2->data->message && new_line2->data->message[0]) { - /* compute the number of lines to add before y */ - if (new_line->data->buffer->own_lines - && new_line->data->buffer->own_lines->last_line) + if (gui_init_ok) { - num_lines_to_add = y - new_line->data->buffer->own_lines->last_line->data->y - 1; + /* compute the number of lines to add before y */ + if (new_line2->data->buffer->own_lines + && new_line2->data->buffer->own_lines->last_line) + { + num_lines_to_add = y - new_line2->data->buffer->own_lines->last_line->data->y - 1; + } + else + { + num_lines_to_add = y; + } + if (num_lines_to_add > 0) + { + /* + * add empty line(s) before asked line, to ensure there is at + * least "y" lines in buffer, and then be able to scroll + * properly buffer page by page + */ + for (i = y - num_lines_to_add; i < y; i++) + { + new_line_empty = gui_line_new (new_line2->data->buffer, + i, 0, 0, NULL, NULL, ""); + if (new_line_empty) + gui_line_add_y (new_line_empty); + } + } + gui_line_add_y (new_line2); } else { - num_lines_to_add = y; + string_fprintf (stdout, "%s\n", new_line2->data->message); + gui_line_free_data (new_line2); + free (new_line2); } - if (num_lines_to_add > 0) - { - /* - * add empty line(s) before asked line, to ensure there is at - * least "y" lines in buffer, and then be able to scroll - * properly buffer page by page - */ - for (i = y - num_lines_to_add; i < y; i++) - { - new_line_empty = gui_line_new (new_line->data->buffer, - i, 0, 0, NULL, NULL, ""); - if (new_line_empty) - gui_line_add_y (new_line_empty); - } - } - gui_line_add_y (new_line); } else { - string_fprintf (stdout, "%s\n", new_line->data->message); - gui_line_free_data (new_line); - free (new_line); - } - } - else - { - if (gui_init_ok) - { - /* delete line */ - last_y = (new_line->data->buffer->own_lines->last_line) ? - new_line->data->buffer->own_lines->last_line->data->y : 0; - if (y <= last_y) + if (gui_init_ok) { - for (ptr_line = new_line->data->buffer->own_lines->first_line; - ptr_line; ptr_line = ptr_line->next_line) + /* delete line */ + last_y = (new_line2->data->buffer->own_lines->last_line) ? + new_line2->data->buffer->own_lines->last_line->data->y : 0; + if (y <= last_y) { - if (ptr_line->data->y >= y) - break; - } - if (ptr_line && (ptr_line->data->y == y)) - { - if (ptr_line->next_line) - gui_line_clear (ptr_line); - else - gui_line_free (new_line->data->buffer, ptr_line); - gui_buffer_ask_chat_refresh (new_line->data->buffer, 2); + for (ptr_line = new_line2->data->buffer->own_lines->first_line; + ptr_line; ptr_line = ptr_line->next_line) + { + if (ptr_line->data->y >= y) + break; + } + if (ptr_line && (ptr_line->data->y == y)) + { + if (ptr_line->next_line) + gui_line_clear (ptr_line); + else + gui_line_free (new_line2->data->buffer, ptr_line); + gui_buffer_ask_chat_refresh (new_line2->data->buffer, 2); + } } } + gui_line_free_data (new_line2); + free (new_line2); } - gui_line_free_data (new_line); - free (new_line); } end: + if (new_line) + { + gui_line_free_data (new_line); + free (new_line); + } free (vbuffer); + if (buffers) + arraylist_free (buffers); } /* diff --git a/src/gui/gui-line.c b/src/gui/gui-line.c index efef30959..0b578a18a 100644 --- a/src/gui/gui-line.c +++ b/src/gui/gui-line.c @@ -30,6 +30,7 @@ #include #include "../core/weechat.h" +#include "../core/wee-arraylist.h" #include "../core/wee-config.h" #include "../core/wee-hashtable.h" #include "../core/wee-hdata.h" @@ -112,6 +113,45 @@ gui_line_tags_alloc (struct t_gui_line_data *line_data, const char *tags) } } +/* + * Duplicates array with tags of a line into another line. + */ + +void +gui_line_tags_dup (struct t_gui_line_data *line_data, + struct t_gui_line_data *line_data2) +{ + int i; + + if (!line_data || !line_data2) + return; + + if (line_data->tags_count > 0) + { + line_data2->tags_array = malloc ( + (line_data->tags_count + 1) * sizeof (*(line_data->tags_array))); + if (line_data2->tags_array) + { + line_data2->tags_count = line_data->tags_count; + for (i = 0; i < line_data->tags_count; i++) + { + line_data2->tags_array[i] = (char *)string_shared_get ( + line_data->tags_array[i]); + } + line_data2->tags_array[line_data->tags_count] = NULL; + } + else + { + line_data2->tags_count = 0; + } + } + else + { + line_data2->tags_count = 0; + line_data2->tags_array = NULL; + } +} + /* * Frees array with tags in a line_data. */ @@ -1561,12 +1601,96 @@ gui_line_new (struct t_gui_buffer *buffer, int y, time_t date, return new_line; } +/* + * Duplicates a line to print it on another buffer. + */ + +struct t_gui_line * +gui_line_dup_for_buffer (struct t_gui_line *line, struct t_gui_buffer *buffer) +{ + struct t_gui_line *new_line; + struct t_gui_line_data *new_line_data; + + if (!line || !buffer) + return NULL; + + /* create new line */ + new_line = malloc (sizeof (*new_line)); + if (!new_line) + return NULL; + + /* create data for line */ + new_line_data = malloc (sizeof (*new_line_data)); + if (!new_line_data) + { + free (new_line); + return NULL; + } + new_line->data = new_line_data; + + /* fill data in new line */ + new_line->data->buffer = buffer; + new_line->data->message = (line->data->message) ? + strdup (line->data->message) : strdup (""); + + if (buffer->type == GUI_BUFFER_TYPE_FORMATTED) + { + /* + * the line identifier is almost unique: when reaching INT_MAX, it is + * reset to 0; it is extremely unlikely all integer are used in the + * same buffer, that would mean the buffer has a huge number of lines; + * when searching a line id in a buffer, it is recommended to start + * from the last line and loop to the first + */ + new_line->data->id = buffer->next_line_id; + buffer->next_line_id = (buffer->next_line_id == INT_MAX) ? + 0 : buffer->next_line_id + 1; + new_line->data->y = line->data->y; + new_line->data->date = line->data->date; + new_line->data->date_printed = line->data->date_printed; + new_line->data->str_time = (line->data->str_time) ? + strdup (line->data->str_time) : NULL; + gui_line_tags_dup (line->data, new_line->data); + new_line->data->refresh_needed = line->data->refresh_needed; + new_line->data->prefix = (line->data->prefix) ? + (char *)string_shared_get (line->data->prefix) : NULL; + new_line->data->prefix_length = line->data->prefix_length; + new_line->data->notify_level = line->data->notify_level; + new_line->data->highlight = line->data->highlight; + } + else + { + new_line->data->id = line->data->y; + new_line->data->y = line->data->y; + new_line->data->date = line->data->date; + new_line->data->date_printed = line->data->date_printed; + new_line->data->str_time = (line->data->str_time) ? + strdup (line->data->str_time) : NULL; + gui_line_tags_dup (line->data, new_line->data); + new_line->data->refresh_needed = line->data->refresh_needed; + new_line->data->prefix = (line->data->prefix) ? + (char *)string_shared_get (line->data->prefix) : NULL; + new_line->data->prefix_length = line->data->prefix_length; + new_line->data->notify_level = line->data->notify_level; + new_line->data->highlight = line->data->highlight; + } + + /* set display flag (check if line is filtered or not) */ + new_line->data->displayed = gui_filter_check_line (new_line->data); + + new_line->prev_line = NULL; + new_line->next_line = NULL; + + return new_line; +} + /* * Updates data in a line via the hook_line. */ void gui_line_hook_update (struct t_gui_line *line, + struct t_arraylist *buffers, struct t_hashtable *hashtable, struct t_hashtable *hashtable2) { @@ -1574,9 +1698,9 @@ gui_line_hook_update (struct t_gui_line *line, struct t_gui_buffer *ptr_buffer; unsigned long value_pointer; long value; - char *error, *new_message, *pos_newline; - int rc, tags_updated, notify_level_updated, highlight_updated; - int max_notify_level; + char *error, *new_message, *pos_newline, **list_buffers; + int i, rc, tags_updated, notify_level_updated, highlight_updated; + int max_notify_level, num_buffers; tags_updated = 0; notify_level_updated = 0; @@ -1587,12 +1711,30 @@ gui_line_hook_update (struct t_gui_line *line, { if (ptr_value2[0]) { - ptr_buffer = gui_buffer_search_by_full_name (ptr_value2); - if (gui_chat_buffer_valid (ptr_buffer, line->data->buffer->type)) - line->data->buffer = ptr_buffer; + list_buffers = string_split ( + ptr_value2, ",", NULL, + WEECHAT_STRING_SPLIT_STRIP_LEFT + | WEECHAT_STRING_SPLIT_STRIP_RIGHT + | WEECHAT_STRING_SPLIT_COLLAPSE_SEPS, + 0, &num_buffers); + if (list_buffers) + { + arraylist_clear (buffers); + for (i = 0; i < num_buffers; i++) + { + ptr_buffer = gui_buffer_search_by_full_name (list_buffers[i]); + if (gui_chat_buffer_valid (ptr_buffer, + line->data->buffer->type)) + { + arraylist_add (buffers, ptr_buffer); + } + } + string_free_split (list_buffers); + } } else { + arraylist_clear (buffers); line->data->buffer = NULL; return; } @@ -1604,19 +1746,37 @@ gui_line_hook_update (struct t_gui_line *line, { if (ptr_value2[0]) { - if ((ptr_value2[0] == '0') && (ptr_value2[1] == 'x')) + list_buffers = string_split ( + ptr_value2, ",", NULL, + WEECHAT_STRING_SPLIT_STRIP_LEFT + | WEECHAT_STRING_SPLIT_STRIP_RIGHT + | WEECHAT_STRING_SPLIT_COLLAPSE_SEPS, + 0, &num_buffers); + if (list_buffers) { - rc = sscanf (ptr_value2 + 2, "%lx", &value_pointer); - ptr_buffer = (struct t_gui_buffer *)value_pointer; - if ((rc != EOF) && (rc >= 1) - && gui_chat_buffer_valid (ptr_buffer, line->data->buffer->type)) + arraylist_clear (buffers); + for (i = 0; i < num_buffers; i++) { - line->data->buffer = ptr_buffer; + if ((list_buffers[i][0] == '0') + && (list_buffers[i][1] == 'x')) + { + rc = sscanf (list_buffers[i] + 2, + "%lx", &value_pointer); + ptr_buffer = (struct t_gui_buffer *)value_pointer; + if ((rc != EOF) && (rc >= 1) + && gui_chat_buffer_valid ( + ptr_buffer, line->data->buffer->type)) + { + arraylist_add (buffers, ptr_buffer); + } + } } + string_free_split (list_buffers); } } else { + arraylist_clear (buffers); line->data->buffer = NULL; return; } diff --git a/src/gui/gui-line.h b/src/gui/gui-line.h index ba4d7fdee..8dd5daf2f 100644 --- a/src/gui/gui-line.h +++ b/src/gui/gui-line.h @@ -128,7 +128,10 @@ extern struct t_gui_line *gui_line_new (struct t_gui_buffer *buffer, const char *tags, const char *prefix, const char *message); +extern struct t_gui_line *gui_line_dup_for_buffer (struct t_gui_line *line, + struct t_gui_buffer *buffer); extern void gui_line_hook_update (struct t_gui_line *line, + struct t_arraylist *buffers, struct t_hashtable *hashtable, struct t_hashtable *hashtable2); extern void gui_line_add (struct t_gui_line *line); diff --git a/tests/unit/gui/test-gui-line.cpp b/tests/unit/gui/test-gui-line.cpp index 4312cf87e..f6cca788a 100644 --- a/tests/unit/gui/test-gui-line.cpp +++ b/tests/unit/gui/test-gui-line.cpp @@ -32,6 +32,9 @@ extern "C" #include "src/gui/gui-filter.h" #include "src/gui/gui-hotlist.h" #include "src/gui/gui-line.h" + +extern void gui_line_tags_dup (struct t_gui_line_data *line_data, + struct t_gui_line_data *line_data2); } #define WEE_BUILD_STR_PREFIX_MSG(__result, __prefix, __message) \ @@ -99,12 +102,13 @@ TEST(GuiLine, LinesAlloc) /* * Tests functions: * gui_line_tags_alloc + * gui_line_tags_dup * gui_line_tags_free */ TEST(GuiLine, TagsAlloc) { - struct t_gui_line_data line_data; + struct t_gui_line_data line_data, line_data2; memset (&line_data, 0, sizeof (line_data)); @@ -152,6 +156,42 @@ TEST(GuiLine, TagsAlloc) LONGS_EQUAL(3, line_data.tags_count); gui_line_tags_free (&line_data); + line_data.tags_array = NULL; + line_data.tags_count = 0; + line_data2.tags_array = (char **)0x1; + line_data2.tags_count = 1; + gui_line_tags_dup (&line_data, &line_data2); + POINTERS_EQUAL(NULL, line_data2.tags_array); + LONGS_EQUAL(0, line_data2.tags_count); + + line_data.tags_array = NULL; + line_data.tags_count = 0; + line_data2.tags_array = (char **)0x1; + line_data2.tags_count = 0; + gui_line_tags_alloc (&line_data, "tag1"); + gui_line_tags_dup (&line_data, &line_data2); + CHECK(line_data2.tags_array); + STRCMP_EQUAL("tag1", line_data2.tags_array[0]); + POINTERS_EQUAL(NULL, line_data2.tags_array[1]); + LONGS_EQUAL(1, line_data2.tags_count); + gui_line_tags_free (&line_data); + gui_line_tags_free (&line_data2); + + line_data.tags_array = NULL; + line_data.tags_count = 0; + line_data2.tags_array = (char **)0x1; + line_data2.tags_count = 0; + gui_line_tags_alloc (&line_data, "tag1,tag2,tag3"); + gui_line_tags_dup (&line_data, &line_data2); + CHECK(line_data2.tags_array); + STRCMP_EQUAL("tag1", line_data2.tags_array[0]); + STRCMP_EQUAL("tag2", line_data2.tags_array[1]); + STRCMP_EQUAL("tag3", line_data2.tags_array[2]); + POINTERS_EQUAL(NULL, line_data2.tags_array[3]); + LONGS_EQUAL(3, line_data2.tags_count); + gui_line_tags_free (&line_data); + gui_line_tags_free (&line_data2); + gui_line_tags_free (NULL); } @@ -984,6 +1024,101 @@ TEST(GuiLine, New) free (str_time); } +/* + * Tests functions: + * gui_line_dup_for_buffer + */ + +TEST(GuiLine, DupForBuffer) +{ + struct t_gui_buffer *buffer, *buffer2; + struct t_gui_line *line1, *line2; + time_t date_printed, date; + char *str_time; + + date_printed = time (NULL); + date = date_printed - 1; + str_time = gui_chat_get_time_string (date); + + POINTERS_EQUAL(NULL, gui_line_dup_for_buffer (NULL, NULL)); + + /* create two new test buffers (formatted content) */ + buffer = gui_buffer_new_user ("test", GUI_BUFFER_TYPE_FORMATTED); + CHECK(buffer); + buffer2 = gui_buffer_new_user ("test2", GUI_BUFFER_TYPE_FORMATTED); + CHECK(buffer2); + + line1 = gui_line_new (buffer, 0, date, date_printed, "tag1,tag2,tag3", + "prefix", "message"); + CHECK(line1); + CHECK(line1->data); + line2 = gui_line_dup_for_buffer (line1, buffer2); + CHECK(line2); + CHECK(line2->data); + POINTERS_EQUAL(NULL, line2->prev_line); + POINTERS_EQUAL(NULL, line2->next_line); + POINTERS_EQUAL(buffer2, line2->data->buffer); + LONGS_EQUAL(0, line2->data->id); + LONGS_EQUAL(-1, line2->data->y); + LONGS_EQUAL(date, line2->data->date); + LONGS_EQUAL(date_printed, line2->data->date_printed); + STRCMP_EQUAL(str_time, line2->data->str_time); + LONGS_EQUAL(3, line2->data->tags_count); + CHECK(line2->data->tags_array); + STRCMP_EQUAL("tag1", line2->data->tags_array[0]); + STRCMP_EQUAL("tag2", line2->data->tags_array[1]); + STRCMP_EQUAL("tag3", line2->data->tags_array[2]); + LONGS_EQUAL(1, line2->data->displayed); + LONGS_EQUAL(GUI_HOTLIST_LOW, line2->data->notify_level); + LONGS_EQUAL(0, line2->data->highlight); + LONGS_EQUAL(0, line2->data->refresh_needed); + STRCMP_EQUAL("prefix", line2->data->prefix); + LONGS_EQUAL(6, line2->data->prefix_length); + STRCMP_EQUAL("message", line2->data->message); + + gui_buffer_close (buffer); + gui_buffer_close (buffer2); + + /* create two new test buffers (free content) */ + buffer = gui_buffer_new_user ("test", GUI_BUFFER_TYPE_FREE); + CHECK(buffer); + buffer2 = gui_buffer_new_user ("test2", GUI_BUFFER_TYPE_FREE); + CHECK(buffer); + + line1 = gui_line_new (buffer, 3, date, date_printed, "tag1,tag2,tag3", + NULL, "message"); + CHECK(line1); + CHECK(line1->data); + line2 = gui_line_dup_for_buffer (line1, buffer2); + CHECK(line1); + CHECK(line1->data); + POINTERS_EQUAL(NULL, line2->prev_line); + POINTERS_EQUAL(NULL, line2->next_line); + POINTERS_EQUAL(buffer2, line2->data->buffer); + LONGS_EQUAL(3, line2->data->id); + LONGS_EQUAL(3, line2->data->y); + LONGS_EQUAL(date, line2->data->date); + LONGS_EQUAL(date_printed, line2->data->date_printed); + POINTERS_EQUAL(NULL, line2->data->str_time); + LONGS_EQUAL(3, line2->data->tags_count); + CHECK(line2->data->tags_array); + STRCMP_EQUAL("tag1", line2->data->tags_array[0]); + STRCMP_EQUAL("tag2", line2->data->tags_array[1]); + STRCMP_EQUAL("tag3", line2->data->tags_array[2]); + LONGS_EQUAL(1, line2->data->displayed); + LONGS_EQUAL(GUI_HOTLIST_LOW, line2->data->notify_level); + LONGS_EQUAL(0, line2->data->highlight); + LONGS_EQUAL(1, line2->data->refresh_needed); + POINTERS_EQUAL(NULL, line2->data->prefix); + LONGS_EQUAL(0, line2->data->prefix_length); + STRCMP_EQUAL("message", line2->data->message); + + gui_buffer_close (buffer); + gui_buffer_close (buffer2); + + free (str_time); +} + /* * Tests functions: * gui_line_hook_update