diff --git a/ChangeLog.adoc b/ChangeLog.adoc index cc2181036..9ce6ed2cf 100644 --- a/ChangeLog.adoc +++ b/ChangeLog.adoc @@ -15,6 +15,7 @@ For a list of important changes that require manual actions, please look at rele New features:: + * core: add unique identifier "id" in buffer (issue #2081) * core: add option `malloc_trim` in command `/sys` * core: add support of SGR mouse events (issue #2082) * core: reintroduce help on the variables and operators in `/help eval` (issue #2005) diff --git a/doc/en/weechat_plugin_api.en.adoc b/doc/en/weechat_plugin_api.en.adoc index 4ef7eb658..9a3b67636 100644 --- a/doc/en/weechat_plugin_api.en.adoc +++ b/doc/en/weechat_plugin_api.en.adoc @@ -14639,6 +14639,7 @@ Arguments: * _buffer_: buffer pointer * _property_: property name: +** _id_: unique identifier _(WeeChat ≥ 4.3.0)_ ** _plugin_: name of plugin which created this buffer ("core" for WeeChat main buffer) ** _name_: name of buffer ** _full_name_: full name of buffer ("plugin.name") _(WeeChat ≥ 0.3.7)_ diff --git a/doc/fr/weechat_plugin_api.fr.adoc b/doc/fr/weechat_plugin_api.fr.adoc index f8afcae20..18d18b049 100644 --- a/doc/fr/weechat_plugin_api.fr.adoc +++ b/doc/fr/weechat_plugin_api.fr.adoc @@ -14955,6 +14955,7 @@ Paramètres : * _buffer_ : pointeur vers le tampon * _property_ : nom de la propriété : +** _id_ : identifiant unique _(WeeChat ≥ 4.3.0)_ ** _plugin_ : nom de l'extension qui a créé ce tampon ("core" pour le tampon principal WeeChat) ** _name_ : nom du tampon ** _full_name_ : nom complet du tampon ("extension.nom") _(WeeChat ≥ 0.3.7)_ diff --git a/doc/it/weechat_plugin_api.it.adoc b/doc/it/weechat_plugin_api.it.adoc index ac20083bc..ba611b731 100644 --- a/doc/it/weechat_plugin_api.it.adoc +++ b/doc/it/weechat_plugin_api.it.adoc @@ -15327,6 +15327,8 @@ Argomenti: * _buffer_: puntatore al buffer * _property_: nome proprietà: +// TRANSLATION MISSING +** _id_: unique identifier _(WeeChat ≥ 4.3.0)_ ** _plugin_: nome del plugin che ha creato questo buffer ("core" per il buffer principale di WeeChat) ** _name_: nome del buffer ** _full_name_: nome completo del buffer ("plugin.nome") _(WeeChat ≥ 0.3.7)_ diff --git a/doc/ja/weechat_plugin_api.ja.adoc b/doc/ja/weechat_plugin_api.ja.adoc index 3822fbb67..6c6461782 100644 --- a/doc/ja/weechat_plugin_api.ja.adoc +++ b/doc/ja/weechat_plugin_api.ja.adoc @@ -14861,6 +14861,8 @@ const char *weechat_buffer_get_string (struct t_gui_buffer *buffer, * _buffer_: バッファへのポインタ * _property_: プロパティ名: +// TRANSLATION MISSING +** _id_: unique identifier _(WeeChat ≥ 4.3.0)_ ** _plugin_: バッファを作成したプラグインの名前 ("core" は WeeChat メインバッファ) ** _name_: バッファの名前 ** _full_name_: バッファの完全な名前 ("plugin.name") _(WeeChat バージョン 0.3.7 以上で利用可)_ diff --git a/doc/sr/weechat_plugin_api.sr.adoc b/doc/sr/weechat_plugin_api.sr.adoc index eae7b8cc4..10bf970a6 100644 --- a/doc/sr/weechat_plugin_api.sr.adoc +++ b/doc/sr/weechat_plugin_api.sr.adoc @@ -14222,6 +14222,8 @@ const char *weechat_buffer_get_string (struct t_gui_buffer *buffer, * _buffer_: показивач на бафер * _property_: име особине: +// TRANSLATION MISSING +** _id_: unique identifier _(WeeChat ≥ 4.3.0)_ ** _plugin_: име додатка који је креирао овај бафер („core” за главни бафер програма WeeChat) ** _name_: име бафера ** _full_name_: пуно име бафера („додатак.име”) _(WeeChat ≥ 0.3.7)_ diff --git a/src/core/wee-upgrade.c b/src/core/wee-upgrade.c index 91920f37d..05c1b9a50 100644 --- a/src/core/wee-upgrade.c +++ b/src/core/wee-upgrade.c @@ -405,10 +405,27 @@ void upgrade_weechat_read_buffer (struct t_infolist *infolist) { struct t_gui_buffer *ptr_buffer; - const char *key, *var_name, *name, *plugin_name; + const char *key, *var_name, *name, *plugin_name, *ptr_id; const char *str; - char option_name[64], *option_key, *option_var; + char option_name[64], *option_key, *option_var, *error; int index, length, main_buffer; + long long id; + + /* "id" is new in WeeChat 4.3.0 */ + id = -1; + if (infolist_search_var (infolist, "id")) + { + ptr_id = infolist_string (infolist, "id"); + if (ptr_id) + { + error = NULL; + id = strtoll (ptr_id, &error, 10); + if (!error || error[0]) + id = -1; + } + } + if (id < 0) + id = gui_buffer_generate_id (); plugin_name = infolist_string (infolist, "plugin_name"); name = infolist_string (infolist, "name"); @@ -420,19 +437,25 @@ upgrade_weechat_read_buffer (struct t_infolist *infolist) { /* use WeeChat main buffer */ upgrade_current_buffer = gui_buffers; + upgrade_current_buffer->id = id; } else { /* create buffer it it's not main buffer */ - upgrade_current_buffer = gui_buffer_new (NULL, - infolist_string (infolist, - "name"), - NULL, NULL, NULL, - NULL, NULL, NULL); + upgrade_current_buffer = gui_buffer_new_props_with_id ( + id, + NULL, /* plugin */ + infolist_string (infolist, "name"), + NULL, /* properties */ + NULL, NULL, NULL, /* input callback */ + NULL, NULL, NULL); /* close callback */ } if (!upgrade_current_buffer) return; + if (upgrade_current_buffer->id > gui_buffer_last_id_assigned) + gui_buffer_last_id_assigned = upgrade_current_buffer->id; + ptr_buffer = upgrade_current_buffer; if (infolist_integer (infolist, "current_buffer")) @@ -799,6 +822,8 @@ upgrade_weechat_read_cb (const void *pointer, void *data, (void) data; (void) upgrade_file; + gui_buffer_last_id_assigned = -1; + infolist_reset_item_cursor (infolist); while (infolist_next (infolist)) { diff --git a/src/gui/gui-buffer.c b/src/gui/gui-buffer.c index 3da3088b5..8ad9949a0 100644 --- a/src/gui/gui-buffer.c +++ b/src/gui/gui-buffer.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "../core/weechat.h" @@ -75,6 +76,8 @@ int gui_buffers_visited_count = 0; /* number of visited buffers*/ int gui_buffers_visited_frozen = 0; /* 1 to forbid list updates */ struct t_gui_buffer *gui_buffer_last_displayed = NULL; /* last b. displayed */ +long long gui_buffer_last_id_assigned = -1; /* last id assigned */ + char *gui_buffer_reserved_names[] = { GUI_BUFFER_MAIN, SECURE_BUFFER_NAME, GUI_COLOR_BUFFER_NAME, NULL @@ -106,7 +109,7 @@ char *gui_buffer_properties_get_integer[] = NULL }; char *gui_buffer_properties_get_string[] = -{ "plugin", "name", "full_name", "old_full_name", "short_name", "title", +{ "id", "plugin", "name", "full_name", "old_full_name", "short_name", "title", "input", "text_search_input", "highlight_words", "highlight_disable_regex", "highlight_regex", "highlight_tags_restrict", "highlight_tags", "hotlist_max_level_nicks", @@ -605,6 +608,34 @@ gui_buffer_insert (struct t_gui_buffer *buffer) } } +/* + * Returns a new unique id for a buffer. + * + * The id is the current time with microseconds precision. + * The same time (including microseconds) can be used only one time, so that + * all buffer ids are guaranteed to be unique. + */ + +long long +gui_buffer_generate_id () +{ + struct timeval tv; + long long id; + + gettimeofday (&tv, NULL); + + id = ((long long)tv.tv_sec * 1000000LL) + (long long)(tv.tv_usec); + + /* + * ensure we never use the same id for two buffers and that the returned + * id is strictly greater than the last assigned one + */ + if (id <= gui_buffer_last_id_assigned) + id = gui_buffer_last_id_assigned + 1; + + return id; +} + /* * Initializes input_buffer_* variables in a buffer. */ @@ -746,26 +777,28 @@ gui_buffer_apply_config_properties (struct t_gui_buffer *buffer) } /* - * Creates a new buffer in current window with some optional properties. + * Creates a new buffer in current window with some optional properties, + * using id (this function is for internal use only). * * Returns pointer to new buffer, NULL if error. */ struct t_gui_buffer * -gui_buffer_new_props (struct t_weechat_plugin *plugin, - const char *name, - struct t_hashtable *properties, - int (*input_callback)(const void *pointer, - void *data, - struct t_gui_buffer *buffer, - const char *input_data), - const void *input_callback_pointer, - void *input_callback_data, - int (*close_callback)(const void *pointer, - void *data, - struct t_gui_buffer *buffer), - const void *close_callback_pointer, - void *close_callback_data) +gui_buffer_new_props_with_id (long long id, + struct t_weechat_plugin *plugin, + const char *name, + struct t_hashtable *properties, + int (*input_callback)(const void *pointer, + void *data, + struct t_gui_buffer *buffer, + const char *input_data), + const void *input_callback_pointer, + void *input_callback_data, + int (*close_callback)(const void *pointer, + void *data, + struct t_gui_buffer *buffer), + const void *close_callback_pointer, + void *close_callback_data) { struct t_gui_buffer *new_buffer; int first_buffer_creation; @@ -797,6 +830,9 @@ gui_buffer_new_props (struct t_weechat_plugin *plugin, return NULL; /* init buffer */ + new_buffer->id = id; + if (new_buffer->id > gui_buffer_last_id_assigned) + gui_buffer_last_id_assigned = new_buffer->id; new_buffer->opening = 1; new_buffer->plugin = plugin; new_buffer->plugin_name_for_upgrade = NULL; @@ -971,6 +1007,41 @@ gui_buffer_new_props (struct t_weechat_plugin *plugin, return new_buffer; } +/* + * Creates a new buffer in current window with some optional properties. + * + * Returns pointer to new buffer, NULL if error. + */ + +struct t_gui_buffer * +gui_buffer_new_props (struct t_weechat_plugin *plugin, + const char *name, + struct t_hashtable *properties, + int (*input_callback)(const void *pointer, + void *data, + struct t_gui_buffer *buffer, + const char *input_data), + const void *input_callback_pointer, + void *input_callback_data, + int (*close_callback)(const void *pointer, + void *data, + struct t_gui_buffer *buffer), + const void *close_callback_pointer, + void *close_callback_data) +{ + return gui_buffer_new_props_with_id ( + gui_buffer_generate_id (), + plugin, + name, + properties, + input_callback, + input_callback_pointer, + input_callback_data, + close_callback, + close_callback_pointer, + close_callback_data); +} + /* * Creates a new buffer in current window. * @@ -1441,11 +1512,17 @@ const char * gui_buffer_get_string (struct t_gui_buffer *buffer, const char *property) { const char *ptr_value; + static char str_value[64]; if (!buffer || !property) return NULL; - if (strcmp (property, "plugin") == 0) + if (strcmp (property, "id") == 0) + { + snprintf (str_value, sizeof (str_value), "%lld", buffer->id); + return str_value; + } + else if (strcmp (property, "plugin") == 0) return gui_buffer_get_plugin_name (buffer); else if (strcmp (property, "name") == 0) return buffer->name; @@ -5012,6 +5089,7 @@ gui_buffer_hdata_buffer_cb (const void *pointer, void *data, 0, 0, NULL, NULL); if (hdata) { + HDATA_VAR(struct t_gui_buffer, id, LONGLONG, 0, NULL, NULL); HDATA_VAR(struct t_gui_buffer, opening, INTEGER, 0, NULL, NULL); HDATA_VAR(struct t_gui_buffer, plugin, POINTER, 0, NULL, "plugin"); HDATA_VAR(struct t_gui_buffer, plugin_name_for_upgrade, STRING, 0, NULL, NULL); @@ -5183,7 +5261,7 @@ gui_buffer_add_to_infolist (struct t_infolist *infolist, { struct t_infolist_item *ptr_item; struct t_gui_key *ptr_key; - char option_name[64]; + char option_name[64], str_value[64]; int i; if (!infolist || !buffer) @@ -5198,6 +5276,9 @@ gui_buffer_add_to_infolist (struct t_infolist *infolist, if (!infolist_new_var_integer (ptr_item, "current_buffer", (gui_current_window->buffer == buffer) ? 1 : 0)) return 0; + snprintf (str_value, sizeof (str_value), "%lld", buffer->id); + if (!infolist_new_var_string (ptr_item, "id", str_value)) + return 0; if (!infolist_new_var_integer (ptr_item, "opening", buffer->opening)) return 0; if (!infolist_new_var_pointer (ptr_item, "plugin", buffer->plugin)) @@ -5457,6 +5538,7 @@ gui_buffer_print_log () { log_printf (""); log_printf ("[buffer (addr:0x%lx)]", ptr_buffer); + log_printf (" id. . . . . . . . . . . : %lld", ptr_buffer->id); log_printf (" opening . . . . . . . . : %d", ptr_buffer->opening); log_printf (" plugin. . . . . . . . . : 0x%lx ('%s')", ptr_buffer->plugin, gui_buffer_get_plugin_name (ptr_buffer)); diff --git a/src/gui/gui-buffer.h b/src/gui/gui-buffer.h index c97947e72..b8a20e301 100644 --- a/src/gui/gui-buffer.h +++ b/src/gui/gui-buffer.h @@ -98,6 +98,8 @@ struct t_gui_input_undo struct t_gui_buffer { + long long id; /* unique id for buffer */ + /* (timestamp with microseconds) */ int opening; /* 1 if buffer is being opened */ struct t_weechat_plugin *plugin; /* plugin which created this buffer */ /* (NULL for a WeeChat buffer) */ @@ -276,6 +278,7 @@ extern int gui_buffers_visited_index; extern int gui_buffers_visited_count; extern int gui_buffers_visited_frozen; extern struct t_gui_buffer *gui_buffer_last_displayed; +extern long long gui_buffer_last_id_assigned; extern char *gui_buffer_reserved_names[]; extern char *gui_buffer_type_string[]; extern char *gui_buffer_notify_string[]; @@ -300,9 +303,25 @@ extern void gui_buffer_local_var_add (struct t_gui_buffer *buffer, extern void gui_buffer_local_var_remove (struct t_gui_buffer *buffer, const char *name); extern void gui_buffer_notify_set_all (); +extern long long gui_buffer_generate_id (); extern int gui_buffer_is_reserved_name (const char *name); extern void gui_buffer_apply_config_option_property (struct t_gui_buffer *buffer, struct t_config_option *option); +extern struct t_gui_buffer *gui_buffer_new_props_with_id (long long id, + struct t_weechat_plugin *plugin, + const char *name, + struct t_hashtable *properties, + int (*input_callback)(const void *pointer, + void *data, + struct t_gui_buffer *buffer, + const char *input_data), + const void *input_callback_pointer, + void *input_callback_data, + int (*close_callback)(const void *pointer, + void *data, + struct t_gui_buffer *buffer), + const void *close_callback_pointer, + void *close_callback_data); extern struct t_gui_buffer *gui_buffer_new_props (struct t_weechat_plugin *plugin, const char *name, struct t_hashtable *properties, diff --git a/tests/scripts/python/testapi.py b/tests/scripts/python/testapi.py index de3023bb3..920b8ddc3 100644 --- a/tests/scripts/python/testapi.py +++ b/tests/scripts/python/testapi.py @@ -705,7 +705,7 @@ def test_hdata(): line2 = weechat.hdata_pointer(hdata_line, line1, 'next_line') line3 = weechat.hdata_pointer(hdata_line, line2, 'next_line') # hdata_get_var_offset - check(weechat.hdata_get_var_offset(hdata_buffer, 'opening') == 0) + check(weechat.hdata_get_var_offset(hdata_buffer, 'id') == 0) check(weechat.hdata_get_var_offset(hdata_buffer, 'plugin') > 0) # hdata_get_var_type_string check(weechat.hdata_get_var_type_string(hdata_buffer, 'plugin') == 'pointer') @@ -751,6 +751,8 @@ def test_hdata(): weechat.buffer_set(buffer, 'hotlist', weechat.WEECHAT_HOTLIST_MESSAGE) gui_hotlist = weechat.hdata_get_list(hdata_hotlist, 'gui_hotlist') check(weechat.hdata_long(hdata_hotlist, gui_hotlist, 'creation_time.tv_usec') >= 0) + # hdata_longlong + check(weechat.hdata_longlong(hdata_buffer, buffer2, 'id') > 1708874542000000) # hdata_string check(weechat.hdata_string(hdata_buffer, buffer2, 'name') == 'test') # hdata_pointer diff --git a/tests/unit/gui/test-gui-buffer.cpp b/tests/unit/gui/test-gui-buffer.cpp index 66a219c66..b61dc1352 100644 --- a/tests/unit/gui/test-gui-buffer.cpp +++ b/tests/unit/gui/test-gui-buffer.cpp @@ -383,6 +383,23 @@ TEST(GuiBuffer, Insert) /* TODO: write tests */ } +/* + * Tests functions: + * gui_buffer_generate_id + */ + +TEST(GuiBuffer, GenerateId) +{ + long long id; + + id = gui_buffer_generate_id (); + CHECK(id > gui_buffer_last_id_assigned); + id = gui_buffer_generate_id (); + CHECK(id > gui_buffer_last_id_assigned); + id = gui_buffer_generate_id (); + CHECK(id > gui_buffer_last_id_assigned); +} + /* * Tests functions: * gui_buffer_input_buffer_init @@ -492,6 +509,7 @@ test_buffer_close_cb (const void *pointer, void *data, /* * Tests functions: + * gui_buffer_new_props_with_id * gui_buffer_new_props */