diff options
author | Sebastien Helleu <flashcode@flashtux.org> | 2013-12-11 18:54:06 +0100 |
---|---|---|
committer | Sebastien Helleu <flashcode@flashtux.org> | 2013-12-11 18:54:06 +0100 |
commit | 58f1403414f4868c6f5888c476852a60ab976ef4 (patch) | |
tree | cc9021e212ce0680341519f664e5b206e0b55db2 /src | |
parent | dd8650a2821b0db517557ebcbb778bafb51f1ea3 (diff) | |
parent | c82633e9e48e8a9e68d277c68f2fae12c43b0d16 (diff) | |
download | weechat-58f1403414f4868c6f5888c476852a60ab976ef4.zip |
Merge branch 'buffer-auto-renumber'
Diffstat (limited to 'src')
-rw-r--r-- | src/core/wee-command.c | 270 | ||||
-rw-r--r-- | src/core/wee-config.c | 34 | ||||
-rw-r--r-- | src/core/wee-config.h | 8 | ||||
-rw-r--r-- | src/gui/gui-bar-item.c | 48 | ||||
-rw-r--r-- | src/gui/gui-bar-item.h | 1 | ||||
-rw-r--r-- | src/gui/gui-buffer.c | 1012 | ||||
-rw-r--r-- | src/gui/gui-buffer.h | 11 | ||||
-rw-r--r-- | src/gui/gui-layout.c | 34 |
8 files changed, 991 insertions, 427 deletions
diff --git a/src/core/wee-command.c b/src/core/wee-command.c index a1f0ed654..c853855c3 100644 --- a/src/core/wee-command.c +++ b/src/core/wee-command.c @@ -474,6 +474,35 @@ COMMAND_CALLBACK(bar) } /* + * Checks if the buffer number is valid (in range 1 to GUI_BUFFER_NUMBER_MAX). + * + * If the number is not valid, a warning is displayed. + * + * Returns: + * 1: buffer number is valid + * 0: buffer number is invalid + */ + +int +command_buffer_check_number (long number) +{ + if ((number < 1) || (number > GUI_BUFFER_NUMBER_MAX)) + { + /* invalid number */ + gui_chat_printf (NULL, + _("%sError: buffer number %d is out of range " + "(it must be between 1 and %d)"), + gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], + number, + GUI_BUFFER_NUMBER_MAX); + return 0; + } + + /* number is OK */ + return 1; +} + +/* * Displays a local variable for a buffer. */ @@ -512,9 +541,9 @@ COMMAND_CALLBACK(buffer) { struct t_gui_buffer *ptr_buffer, *ptr_buffer2, *ptr_prev_buffer; struct t_gui_buffer *weechat_buffer; - long number, number1, number2; + long number, number1, number2, numbers[3]; char *error, *value, *pos, *str_number1, *pos_number2; - int i, target_buffer, error_main_buffer, num_buffers; + int i, error_main_buffer, num_buffers, count, prev_number; /* make C compiler happy */ (void) data; @@ -553,42 +582,24 @@ COMMAND_CALLBACK(buffer) { if (string_strcasecmp (argv[2], "-all") == 0) gui_buffer_clear_all (); - else if (string_strcasecmp (argv[2], "-merged") == 0) - { - for (ptr_buffer = gui_buffers; ptr_buffer; - ptr_buffer = ptr_buffer->next_buffer) - { - if ((ptr_buffer->number == buffer->number) - && (ptr_buffer->type == GUI_BUFFER_TYPE_FORMATTED)) - { - gui_buffer_clear (ptr_buffer); - } - } - } else { for (i = 2; i < argc; i++) { - error = NULL; - number = strtol (argv[i], &error, 10); - if (error && !error[0]) + ptr_buffer = (string_strcasecmp (argv[i], "-merged") == 0) ? + buffer : gui_buffer_search_by_number_or_name (argv[i]); + if (ptr_buffer) { - for (ptr_buffer = gui_buffers; ptr_buffer; - ptr_buffer = ptr_buffer->next_buffer) + for (ptr_buffer2 = gui_buffers; ptr_buffer2; + ptr_buffer2 = ptr_buffer2->next_buffer) { - if ((ptr_buffer->number == number) - && (ptr_buffer->type == GUI_BUFFER_TYPE_FORMATTED)) + if ((ptr_buffer2->number == ptr_buffer->number) + && (ptr_buffer2->type == GUI_BUFFER_TYPE_FORMATTED)) { - gui_buffer_clear (ptr_buffer); + gui_buffer_clear (ptr_buffer2); } } } - else - { - ptr_buffer = gui_buffer_search_by_full_name (argv[i]); - if (ptr_buffer) - gui_buffer_clear (ptr_buffer); - } } } } @@ -605,28 +616,41 @@ COMMAND_CALLBACK(buffer) if (string_strcasecmp (argv[1], "move") == 0) { COMMAND_MIN_ARGS(3, "buffer move"); - error = NULL; - number = strtol (((argv[2][0] == '+') || (argv[2][0] == '-')) ? - argv[2] + 1 : argv[2], - &error, 10); - if (error && !error[0]) + if (strcmp (argv[2], "-") == 0) { - if (argv[2][0] == '+') - gui_buffer_move_to_number (buffer, - buffer->number + ((int) number)); - else if (argv[2][0] == '-') - gui_buffer_move_to_number (buffer, - buffer->number - ((int) number)); - else - gui_buffer_move_to_number (buffer, (int) number); + gui_buffer_move_to_number (buffer, 1); + } + else if (strcmp (argv[2], "+") == 0) + { + number = last_gui_buffer->number + 1; + if (command_buffer_check_number (number)) + gui_buffer_move_to_number (buffer, number); } else { - /* invalid number */ - gui_chat_printf (NULL, - _("%sError: incorrect buffer number"), - gui_chat_prefix[GUI_CHAT_PREFIX_ERROR]); - return WEECHAT_RC_OK; + error = NULL; + number = strtol (((argv[2][0] == '+') || (argv[2][0] == '-')) ? + argv[2] + 1 : argv[2], + &error, 10); + if (error && !error[0] + && (number >= INT_MIN) && (number <= INT_MAX)) + { + if (argv[2][0] == '+') + number = buffer->number + number; + else if (argv[2][0] == '-') + number = buffer->number - number; + number = (int)number; + if (command_buffer_check_number (number)) + gui_buffer_move_to_number (buffer, number); + } + else + { + /* invalid number */ + gui_chat_printf (NULL, + _("%sError: incorrect buffer number"), + gui_chat_prefix[GUI_CHAT_PREFIX_ERROR]); + return WEECHAT_RC_OK; + } } return WEECHAT_RC_OK; @@ -640,33 +664,10 @@ COMMAND_CALLBACK(buffer) ptr_buffer = NULL; ptr_buffer2 = NULL; - /* first buffer for swap */ - number = strtol (argv[2], &error, 10); - if (error && !error[0]) - ptr_buffer = gui_buffer_search_by_number (number); - else - { - ptr_buffer = gui_buffer_search_by_full_name (argv[2]); - if (!ptr_buffer) - ptr_buffer = gui_buffer_search_by_partial_name (NULL, argv[2]); - } - - /* second buffer for swap */ - if (argc > 3) - { - number = strtol (argv[3], &error, 10); - if (error && !error[0]) - ptr_buffer2 = gui_buffer_search_by_number (number); - else - { - ptr_buffer2 = gui_buffer_search_by_full_name (argv[3]); - if (!ptr_buffer2) - ptr_buffer2 = gui_buffer_search_by_partial_name (NULL, argv[3]); - } - } - else - ptr_buffer2 = buffer; - + /* search buffers to swap */ + ptr_buffer = gui_buffer_search_by_number_or_name (argv[2]); + ptr_buffer2 = (argc > 3) ? + gui_buffer_search_by_number_or_name (argv[3]) : buffer; if (!ptr_buffer || !ptr_buffer2) { /* invalid buffer name/number */ @@ -676,7 +677,7 @@ COMMAND_CALLBACK(buffer) return WEECHAT_RC_OK; } - gui_buffer_swap (ptr_buffer, ptr_buffer2); + gui_buffer_swap (ptr_buffer->number, ptr_buffer2->number); return WEECHAT_RC_OK; } @@ -728,13 +729,55 @@ COMMAND_CALLBACK(buffer) gui_chat_prefix[GUI_CHAT_PREFIX_ERROR]); return WEECHAT_RC_OK; } + if (!command_buffer_check_number ((int)number)) + return WEECHAT_RC_ERROR; } } - gui_buffer_unmerge (buffer, (int) number); + gui_buffer_unmerge (buffer, (int)number); return WEECHAT_RC_OK; } + /* renumber buffers */ + if (string_strcasecmp (argv[1], "renumber") == 0) + { + if (CONFIG_BOOLEAN(config_look_buffer_auto_renumber)) + { + gui_chat_printf (NULL, + _("%sError: renumbering is allowed only if option " + "weechat.look.buffer_auto_renumber is off"), + gui_chat_prefix[GUI_CHAT_PREFIX_ERROR]); + return WEECHAT_RC_OK; + } + for (i = 0; i < 3; i++) + { + if (argc >= i + 3) + { + error = NULL; + numbers[i] = strtol (argv[i + 2], &error, 10); + if (!error || error[0]) + { + /* invalid number */ + gui_chat_printf (NULL, + _("%sError: incorrect buffer number"), + gui_chat_prefix[GUI_CHAT_PREFIX_ERROR]); + return WEECHAT_RC_OK; + } + if ((i == 2) && !command_buffer_check_number ((int)numbers[i])) + return WEECHAT_RC_OK; + } + else + numbers[i] = -1; + } + /* + * renumber the buffers; if we are renumbering all buffers (no numbers + * given), start at number 1 + */ + gui_buffer_renumber ((int)numbers[0], (int)numbers[1], + (argc == 2) ? 1 : (int)numbers[2]); + return WEECHAT_RC_OK; + } + /* close buffer */ if (string_strcasecmp (argv[1], "close") == 0) { @@ -945,12 +988,35 @@ COMMAND_CALLBACK(buffer) number = strtol (argv[1] + 1, &error, 10); if (error && !error[0]) { - target_buffer = buffer->number - (int) number; - if (target_buffer < 1) - target_buffer = (last_gui_buffer) ? - last_gui_buffer->number + target_buffer : 1; - gui_buffer_switch_by_number (gui_current_window, - target_buffer); + if (number <= 0) + return WEECHAT_RC_OK; + count = 0; + prev_number = gui_current_window->buffer->number; + ptr_buffer = gui_current_window->buffer; + while (1) + { + ptr_buffer = ptr_buffer->prev_buffer; + if (!ptr_buffer) + ptr_buffer = last_gui_buffer; + + /* if we have looped on all buffers, exit the loop */ + if (ptr_buffer == gui_current_window->buffer) + break; + + if ((ptr_buffer->number != gui_current_window->buffer->number) + && (ptr_buffer->number != prev_number)) + { + /* increase count each time we discover a different number */ + count++; + if (count == number) + { + gui_buffer_switch_by_number (gui_current_window, + ptr_buffer->number); + break; + } + } + prev_number = ptr_buffer->number; + } } else { @@ -971,11 +1037,35 @@ COMMAND_CALLBACK(buffer) number = strtol (argv[1] + 1, &error, 10); if (error && !error[0]) { - target_buffer = buffer->number + (int) number; - if (last_gui_buffer && target_buffer > last_gui_buffer->number) - target_buffer -= last_gui_buffer->number; - gui_buffer_switch_by_number (gui_current_window, - target_buffer); + if (number <= 0) + return WEECHAT_RC_OK; + count = 0; + prev_number = gui_current_window->buffer->number; + ptr_buffer = gui_current_window->buffer; + while (1) + { + ptr_buffer = ptr_buffer->next_buffer; + if (!ptr_buffer) + ptr_buffer = gui_buffers; + + /* if we have looped on all buffers, exit the loop */ + if (ptr_buffer == gui_current_window->buffer) + break; + + if ((ptr_buffer->number != gui_current_window->buffer->number) + && (ptr_buffer->number != prev_number)) + { + /* increase count each time we discover a different number */ + count++; + if (count == number) + { + gui_buffer_switch_by_number (gui_current_window, + ptr_buffer->number); + break; + } + } + prev_number = ptr_buffer->number; + } } else { @@ -6213,6 +6303,7 @@ command_init () " || move|merge <number>" " || swap <number1>|<name1> [<number2>|<name2>]" " || unmerge [<number>|-all]" + " || renumber [<number1> [<number2> [<start>]]]" " || close [<n1>[-<n2>]|<name>]" " || notify <level>" " || localvar" @@ -6234,6 +6325,8 @@ command_init () "buffers)\n" " unmerge: unmerge buffer from other buffers which have " "same number\n" + "renumber: renumber a range of buffers (works only if " + "option weechat.look.buffer_auto_renumber is off)\n" " close: close buffer (number/range or name is optional)\n" " notify: set notify level for current buffer: this " "level determines whether buffer will be added to " @@ -6273,11 +6366,14 @@ command_init () " /buffer #weechat\n" " jump to next buffer:\n" " /buffer +1"), - "clear -merged|-all|%(buffers_numbers)|%(buffers_plugins_names)" + "clear -merged|-all|%(buffers_numbers)|" + "%(buffers_plugins_names)" " || move %(buffers_numbers)" " || swap %(buffers_numbers)" " || merge %(buffers_numbers)" " || unmerge %(buffers_numbers)|-all" + " || renumber %(buffers_numbers) %(buffers_numbers) " + "%(buffers_numbers)" " || close %(buffers_plugins_names)" " || list" " || notify reset|none|highlight|message|all" diff --git a/src/core/wee-config.c b/src/core/wee-config.c index bbf7704c4..cfcdf4f9a 100644 --- a/src/core/wee-config.c +++ b/src/core/wee-config.c @@ -84,7 +84,9 @@ struct t_config_option *config_look_bar_more_left; struct t_config_option *config_look_bar_more_right; struct t_config_option *config_look_bar_more_up; struct t_config_option *config_look_bar_more_down; +struct t_config_option *config_look_buffer_auto_renumber; struct t_config_option *config_look_buffer_notify_default; +struct t_config_option *config_look_buffer_position; struct t_config_option *config_look_buffer_search_case_sensitive; struct t_config_option *config_look_buffer_search_force_default; struct t_config_option *config_look_buffer_search_regex; @@ -384,6 +386,21 @@ config_change_mouse (void *data, struct t_config_option *option) } /* + * Callback for changes on option "weechat.look.buffer_auto_renumber". + */ + +void +config_change_buffer_auto_renumber (void *data, struct t_config_option *option) +{ + /* make C compiler happy */ + (void) data; + (void) option; + + if (gui_buffers && CONFIG_BOOLEAN(config_look_buffer_auto_renumber)) + gui_buffer_renumber (-1, -1, 1); +} + +/* * Callback for changes on option "weechat.look.buffer_notify_default". */ @@ -1974,6 +1991,14 @@ config_weechat_init_options () N_("string displayed when bar can be scrolled down " "(for bars with filling different from \"horizontal\")"), NULL, 0, 0, "++", NULL, 0, NULL, NULL, &config_change_buffer_content, NULL, NULL, NULL); + config_look_buffer_auto_renumber = config_file_new_option ( + weechat_config_file, ptr_section, + "buffer_auto_renumber", "boolean", + N_("automatically renumber buffers to have only consecutive numbers " + "and start with number 1; if disabled, gaps between buffer numbers " + "are allowed and the first buffer can have a number > 1"), + NULL, 0, 0, "on", NULL, 0, NULL, NULL, + &config_change_buffer_auto_renumber, NULL, NULL, NULL); config_look_buffer_notify_default = config_file_new_option ( weechat_config_file, ptr_section, "buffer_notify_default", "integer", @@ -1984,6 +2009,15 @@ config_weechat_init_options () "none=never display in hotlist"), "none|highlight|message|all", 0, 0, "all", NULL, 0, NULL, NULL, &config_change_buffer_notify_default, NULL, NULL, NULL); + config_look_buffer_position = config_file_new_option ( + weechat_config_file, ptr_section, + "buffer_position", "integer", + N_("position of a new buffer: end = after the end of list (number = " + "last number + 1) (default), first_gap = at first available " + "number in the list (after the end of list if no number is " + "available); this option is used only if the buffer has no layout " + "number"), + "end|first_gap", 0, 0, "end", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); config_look_buffer_search_case_sensitive = config_file_new_option ( weechat_config_file, ptr_section, "buffer_search_case_sensitive", "boolean", diff --git a/src/core/wee-config.h b/src/core/wee-config.h index 9fe7eb2e2..cefed77ee 100644 --- a/src/core/wee-config.h +++ b/src/core/wee-config.h @@ -37,6 +37,12 @@ enum t_config_look_align_end_of_lines CONFIG_LOOK_ALIGN_END_OF_LINES_MESSAGE, }; +enum t_config_look_buffer_position +{ + CONFIG_LOOK_BUFFER_POSITION_END = 0, + CONFIG_LOOK_BUFFER_POSITION_FIRST_GAP, +}; + enum t_config_look_buffer_search_where { CONFIG_LOOK_BUFFER_SEARCH_PREFIX = 0, @@ -108,7 +114,9 @@ extern struct t_config_option *config_look_bar_more_left; extern struct t_config_option *config_look_bar_more_right; extern struct t_config_option *config_look_bar_more_up; extern struct t_config_option *config_look_bar_more_down; +extern struct t_config_option *config_look_buffer_auto_renumber; extern struct t_config_option *config_look_buffer_notify_default; +extern struct t_config_option *config_look_buffer_position; extern struct t_config_option *config_look_buffer_search_case_sensitive; extern struct t_config_option *config_look_buffer_search_force_default; extern struct t_config_option *config_look_buffer_search_regex; diff --git a/src/gui/gui-bar-item.c b/src/gui/gui-bar-item.c index 1ea72a931..d1698484b 100644 --- a/src/gui/gui-bar-item.c +++ b/src/gui/gui-bar-item.c @@ -58,10 +58,10 @@ struct t_gui_bar_item *gui_bar_items = NULL; /* first bar item */ struct t_gui_bar_item *last_gui_bar_item = NULL; /* last bar item */ char *gui_bar_item_names[GUI_BAR_NUM_ITEMS] = { "input_paste", "input_prompt", "input_search", "input_text", "time", - "buffer_count", "buffer_plugin", "buffer_number", "buffer_name", - "buffer_modes", "buffer_filter", "buffer_zoom", "buffer_nicklist_count", - "scroll", "hotlist", "completion", "buffer_title", "buffer_nicklist", - "window_number" + "buffer_count", "buffer_last_number", "buffer_plugin", "buffer_number", + "buffer_name", "buffer_modes", "buffer_filter", "buffer_zoom", + "buffer_nicklist_count", "scroll", "hotlist", "completion", "buffer_title", + "buffer_nicklist", "window_number" }; char *gui_bar_items_default_for_bars[][2] = { { GUI_BAR_DEFAULT_NAME_INPUT, @@ -949,6 +949,31 @@ gui_bar_item_default_buffer_count (void *data, struct t_gui_bar_item *item, (void) buffer; (void) extra_info; + snprintf (buf, sizeof (buf), "%d", gui_buffers_count); + + return strdup (buf); +} + +/* + * Default item for last buffer number. + */ + +char * +gui_bar_item_default_buffer_last_number (void *data, + struct t_gui_bar_item *item, + struct t_gui_window *window, + struct t_gui_buffer *buffer, + struct t_hashtable *extra_info) +{ + char buf[32]; + + /* make C compiler happy */ + (void) data; + (void) item; + (void) window; + (void) buffer; + (void) extra_info; + snprintf (buf, sizeof (buf), "%d", (last_gui_buffer) ? last_gui_buffer->number : 0); @@ -1891,6 +1916,21 @@ gui_bar_item_init () gui_bar_item_hook_signal ("buffer_closed", gui_bar_item_names[GUI_BAR_ITEM_BUFFER_COUNT]); + /* last buffer number */ + gui_bar_item_new (NULL, + gui_bar_item_names[GUI_BAR_ITEM_BUFFER_LAST_NUMBER], + &gui_bar_item_default_buffer_last_number, NULL); + gui_bar_item_hook_signal ("buffer_opened", + gui_bar_item_names[GUI_BAR_ITEM_BUFFER_LAST_NUMBER]); + gui_bar_item_hook_signal ("buffer_closed", + gui_bar_item_names[GUI_BAR_ITEM_BUFFER_LAST_NUMBER]); + gui_bar_item_hook_signal ("buffer_moved", + gui_bar_item_names[GUI_BAR_ITEM_BUFFER_LAST_NUMBER]); + gui_bar_item_hook_signal ("buffer_merged", + gui_bar_item_names[GUI_BAR_ITEM_BUFFER_LAST_NUMBER]); + gui_bar_item_hook_signal ("buffer_unmerged", + gui_bar_item_names[GUI_BAR_ITEM_BUFFER_LAST_NUMBER]); + /* buffer plugin */ gui_bar_item_new (NULL, gui_bar_item_names[GUI_BAR_ITEM_BUFFER_PLUGIN], diff --git a/src/gui/gui-bar-item.h b/src/gui/gui-bar-item.h index df75be82a..f24250149 100644 --- a/src/gui/gui-bar-item.h +++ b/src/gui/gui-bar-item.h @@ -28,6 +28,7 @@ enum t_gui_bar_item_weechat GUI_BAR_ITEM_INPUT_TEXT, GUI_BAR_ITEM_TIME, GUI_BAR_ITEM_BUFFER_COUNT, + GUI_BAR_ITEM_BUFFER_LAST_NUMBER, GUI_BAR_ITEM_BUFFER_PLUGIN, GUI_BAR_ITEM_BUFFER_NUMBER, GUI_BAR_ITEM_BUFFER_NAME, diff --git a/src/gui/gui-buffer.c b/src/gui/gui-buffer.c index dd48d17c4..7379685c7 100644 --- a/src/gui/gui-buffer.c +++ b/src/gui/gui-buffer.c @@ -61,6 +61,7 @@ struct t_gui_buffer *gui_buffers = NULL; /* first buffer */ struct t_gui_buffer *last_gui_buffer = NULL; /* last buffer */ +int gui_buffers_count = 0; /* number of buffers */ /* history of last visited buffers */ struct t_gui_buffer_visited *gui_buffers_visited = NULL; @@ -312,7 +313,11 @@ gui_buffer_notify_set_all () } /* - * Searches for position of buffer in list (to keep buffers sorted by number). + * Searches for position of buffer in list using its layout number + * (to keep buffers sorted by number). + * + * Returns the pointer to the buffer that will be after the new buffer in list. + * Returns NULL if position is undefined. */ struct t_gui_buffer * @@ -320,7 +325,7 @@ gui_buffer_find_pos (struct t_gui_buffer *buffer) { struct t_gui_buffer *ptr_buffer; - /* if no number is asked by layout, then add to the end by default */ + /* if no number is asked by layout, position is undefined */ if (buffer->layout_number < 1) return NULL; @@ -341,42 +346,119 @@ gui_buffer_find_pos (struct t_gui_buffer *buffer) } } - /* position not found, add to the end */ + /* position not found */ return NULL; } /* + * Shifts number of buffers (number + 1) until we find a gap (if auto renumber + * is OFF), or until last buffer. + */ + +void +gui_buffer_shift_numbers (struct t_gui_buffer *buffer) +{ + struct t_gui_buffer *ptr_buffer; + + for (ptr_buffer = buffer; ptr_buffer; ptr_buffer = ptr_buffer->next_buffer) + { + if (ptr_buffer->prev_buffer + && (ptr_buffer->number > ptr_buffer->prev_buffer->number)) + { + break; + } + ptr_buffer->number++; + } +} + +/* * Inserts a buffer in good position in list of buffers (keeping sort on * number). */ void -gui_buffer_insert (struct t_gui_buffer *buffer, int automatic_merge) +gui_buffer_insert (struct t_gui_buffer *buffer) { - struct t_gui_buffer *pos, *ptr_buffer; + struct t_gui_buffer *pos_buffer, *ptr_buffer; + int force_number; + + force_number = 0; + + pos_buffer = gui_buffer_find_pos (buffer); + + /* + * if position was not forced by layout and that buffer position is set + * to "first gap", search for the first available number in the list + * (if there is not, buffer will be added to the end of list) + */ + if (!pos_buffer + && (buffer->layout_number == 0) + && (CONFIG_INTEGER(config_look_buffer_position) == CONFIG_LOOK_BUFFER_POSITION_FIRST_GAP)) + { + for (ptr_buffer = gui_buffers; ptr_buffer; + ptr_buffer = ptr_buffer->next_buffer) + { + if (ptr_buffer->prev_buffer) + { + if (ptr_buffer->number > ptr_buffer->prev_buffer->number + 1) + { + pos_buffer = ptr_buffer; + force_number = ptr_buffer->prev_buffer->number + 1; + break; + } + } + else if (ptr_buffer->number > 1) + { + pos_buffer = ptr_buffer; + force_number = 1; + break; + } + } + } - pos = gui_buffer_find_pos (buffer); - if (pos) + if (pos_buffer) { /* add buffer into the list (before position found) */ - buffer->number = pos->number; - buffer->prev_buffer = pos->prev_buffer; - buffer->next_buffer = pos; - if (pos->prev_buffer) - (pos->prev_buffer)->next_buffer = buffer; + if (force_number > 0) + { + buffer->number = force_number; + } + else if (!CONFIG_BOOLEAN(config_look_buffer_auto_renumber) + && (buffer->layout_number > 0) + && (buffer->layout_number < pos_buffer->number) + && (!pos_buffer->prev_buffer + || (buffer->layout_number > pos_buffer->prev_buffer->number))) + { + buffer->number = buffer->layout_number; + } else - gui_buffers = buffer; - pos->prev_buffer = buffer; - for (ptr_buffer = pos; ptr_buffer; - ptr_buffer = ptr_buffer->next_buffer) { - ptr_buffer->number++; + buffer->number = pos_buffer->number; } + buffer->prev_buffer = pos_buffer->prev_buffer; + buffer->next_buffer = pos_buffer; + if (pos_buffer->prev_buffer) + (pos_buffer->prev_buffer)->next_buffer = buffer; + else + gui_buffers = buffer; + pos_buffer->prev_buffer = buffer; + if (buffer->number == pos_buffer->number) + gui_buffer_shift_numbers (pos_buffer); } else { /* add buffer to the end */ - buffer->number = (last_gui_buffer) ? last_gui_buffer->number + 1 : 1; + if (!CONFIG_BOOLEAN(config_look_buffer_auto_renumber) + && (buffer->layout_number > 0) + && (!last_gui_buffer + || (buffer->layout_number > last_gui_buffer->number))) + { + buffer->number = buffer->layout_number; + } + else + { + buffer->number = (last_gui_buffer) ? last_gui_buffer->number + 1 : 1; + } buffer->prev_buffer = last_gui_buffer; buffer->next_buffer = NULL; if (gui_buffers) @@ -387,7 +469,7 @@ gui_buffer_insert (struct t_gui_buffer *buffer, int automatic_merge) } /* merge buffer with previous or next, if they have layout number */ - if (automatic_merge && (buffer->layout_number >= 1)) + if (buffer->layout_number > 0) { if (buffer->prev_buffer && (buffer->layout_number == (buffer->prev_buffer)->layout_number)) @@ -397,7 +479,7 @@ gui_buffer_insert (struct t_gui_buffer *buffer, int automatic_merge) else if ((buffer->next_buffer) && (buffer->layout_number == (buffer->next_buffer)->layout_number)) { - gui_buffer_merge (buffer, buffer->next_buffer); + gui_buffer_merge (buffer->next_buffer, buffer); } } } @@ -452,152 +534,162 @@ gui_buffer_new (struct t_weechat_plugin *plugin, return NULL; } + if (gui_buffers_count >= GUI_BUFFERS_MAX) + { + gui_chat_printf (NULL, + _("%sError: maximum number of buffers is reached " + "(%d)"), + gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], + GUI_BUFFERS_MAX); + return NULL; + } + /* create new buffer */ new_buffer = malloc (sizeof (*new_buffer)); - if (new_buffer) - { - /* init buffer */ - new_buffer->plugin = plugin; - new_buffer->plugin_name_for_upgrade = NULL; - - /* number will be set later (when inserting buffer in list) */ - gui_layout_buffer_get_number (gui_layout_current, - plugin_get_name (plugin), - name, - &(new_buffer->layout_number), - &(new_buffer->layout_number_merge_order)); - new_buffer->name = strdup (name); - new_buffer->full_name = NULL; - gui_buffer_build_full_name (new_buffer); - new_buffer->short_name = NULL; - new_buffer->type = GUI_BUFFER_TYPE_FORMATTED; - new_buffer->notify = CONFIG_INTEGER(config_look_buffer_notify_default); - new_buffer->num_displayed = 0; - new_buffer->active = 1; - new_buffer->print_hooks_enabled = 1; - new_buffer->day_change = 1; - - /* close callback */ - new_buffer->close_callback = close_callback; - new_buffer->close_callback_data = close_callback_data; - - /* title */ - new_buffer->title = NULL; - - /* chat content */ - new_buffer->own_lines = gui_lines_alloc (); - new_buffer->mixed_lines = NULL; - new_buffer->lines = new_buffer->own_lines; - new_buffer->time_for_each_line = 1; - new_buffer->chat_refresh_needed = 2; - - /* nicklist */ - new_buffer->nicklist = 0; - new_buffer->nicklist_case_sensitive = 0; - new_buffer->nicklist_root = NULL; - new_buffer->nicklist_max_length = 0; - new_buffer->nicklist_display_groups = 1; - new_buffer->nicklist_count = 0; - new_buffer->nicklist_groups_count = 0; - new_buffer->nicklist_nicks_count = 0; - new_buffer->nicklist_visible_count = 0; - new_buffer->nickcmp_callback = NULL; - new_buffer->nickcmp_callback_data = NULL; - gui_nicklist_add_group (new_buffer, NULL, "root", NULL, 0); - - /* input */ - new_buffer->input = 1; - new_buffer->input_callback = input_callback; - new_buffer->input_callback_data = input_callback_data; - new_buffer->input_get_unknown_commands = 0; - gui_buffer_input_buffer_init (new_buffer); - - /* undo for input */ - new_buffer->input_undo_snap = malloc (sizeof (*(new_buffer->input_undo_snap))); - (new_buffer->input_undo_snap)->data = NULL; - (new_buffer->input_undo_snap)->pos = 0; - (new_buffer->input_undo_snap)->prev_undo = NULL; /* not used */ - (new_buffer->input_undo_snap)->next_undo = NULL; /* not used */ - new_buffer->input_undo = NULL; - new_buffer->last_input_undo = NULL; - new_buffer->ptr_input_undo = NULL; - new_buffer->input_undo_count = 0; - - /* init completion */ - new_completion = malloc (sizeof (*new_completion)); - if (new_completion) - { - new_buffer->completion = new_completion; - gui_completion_buffer_init (new_completion, new_buffer); - } + if (!new_buffer) + return NULL; - /* init history */ - new_buffer->history = NULL; - new_buffer->last_history = NULL; - new_buffer->ptr_history = NULL; - new_buffer->num_history = 0; - - /* text search */ - new_buffer->text_search = GUI_TEXT_SEARCH_DISABLED; - new_buffer->text_search_exact = 0; - new_buffer->text_search_regex = 0; - new_buffer->text_search_regex_compiled = NULL; - new_buffer->text_search_where = 0; - new_buffer->text_search_found = 0; - new_buffer->text_search_input = NULL; - - /* highlight */ - new_buffer->highlight_words = NULL; - new_buffer->highlight_regex = NULL; - new_buffer->highlight_regex_compiled = NULL; - new_buffer->highlight_tags = NULL; - new_buffer->highlight_tags_count = 0; - new_buffer->highlight_tags_array = NULL; - - /* hotlist */ - new_buffer->hotlist_max_level_nicks = hashtable_new (32, - WEECHAT_HASHTABLE_STRING, - WEECHAT_HASHTABLE_INTEGER, - NULL, - NULL); - - /* keys */ - new_buffer->keys = NULL; - new_buffer->last_key = NULL; - new_buffer->keys_count = 0; - - /* local variables */ - new_buffer->local_variables = hashtable_new (32, - WEECHAT_HASHTABLE_STRING, - WEECHAT_HASHTABLE_STRING, - NULL, - NULL); - hashtable_set (new_buffer->local_variables, - "plugin", plugin_get_name (plugin)); - hashtable_set (new_buffer->local_variables, "name", name); - - /* add buffer to buffers list */ - first_buffer_creation = (gui_buffers == NULL); - gui_buffer_insert (new_buffer, 1); - - /* set notify level */ - new_buffer->notify = gui_buffer_notify_get (new_buffer); - - /* assign this buffer to windows of layout */ - gui_layout_window_assign_buffer (new_buffer); - - if (first_buffer_creation) - { - gui_buffer_visited_add (new_buffer); - } - else - { - hook_signal_send ("buffer_opened", - WEECHAT_HOOK_SIGNAL_POINTER, new_buffer); - } + /* init buffer */ + new_buffer->plugin = plugin; + new_buffer->plugin_name_for_upgrade = NULL; + + /* number will be set later (when inserting buffer in list) */ + gui_layout_buffer_get_number (gui_layout_current, + plugin_get_name (plugin), + name, + &(new_buffer->layout_number), + &(new_buffer->layout_number_merge_order)); + new_buffer->name = strdup (name); + new_buffer->full_name = NULL; + gui_buffer_build_full_name (new_buffer); + new_buffer->short_name = NULL; + new_buffer->type = GUI_BUFFER_TYPE_FORMATTED; + new_buffer->notify = CONFIG_INTEGER(config_look_buffer_notify_default); + new_buffer->num_displayed = 0; + new_buffer->active = 1; + new_buffer->print_hooks_enabled = 1; + new_buffer->day_change = 1; + + /* close callback */ + new_buffer->close_callback = close_callback; + new_buffer->close_callback_data = close_callback_data; + + /* title */ + new_buffer->title = NULL; + + /* chat content */ + new_buffer->own_lines = gui_lines_alloc (); + new_buffer->mixed_lines = NULL; + new_buffer->lines = new_buffer->own_lines; + new_buffer->time_for_each_line = 1; + new_buffer->chat_refresh_needed = 2; + + /* nicklist */ + new_buffer->nicklist = 0; + new_buffer->nicklist_case_sensitive = 0; + new_buffer->nicklist_root = NULL; + new_buffer->nicklist_max_length = 0; + new_buffer->nicklist_display_groups = 1; + new_buffer->nicklist_count = 0; + new_buffer->nicklist_groups_count = 0; + new_buffer->nicklist_nicks_count = 0; + new_buffer->nicklist_visible_count = 0; + new_buffer->nickcmp_callback = NULL; + new_buffer->nickcmp_callback_data = NULL; + gui_nicklist_add_group (new_buffer, NULL, "root", NULL, 0); + + /* input */ + new_buffer->input = 1; + new_buffer->input_callback = input_callback; + new_buffer->input_callback_data = input_callback_data; + new_buffer->input_get_unknown_commands = 0; + gui_buffer_input_buffer_init (new_buffer); + + /* undo for input */ + new_buffer->input_undo_snap = malloc (sizeof (*(new_buffer->input_undo_snap))); + (new_buffer->input_undo_snap)->data = NULL; + (new_buffer->input_undo_snap)->pos = 0; + (new_buffer->input_undo_snap)->prev_undo = NULL; /* not used */ + (new_buffer->input_undo_snap)->next_undo = NULL; /* not used */ + new_buffer->input_undo = NULL; + new_buffer->last_input_undo = NULL; + new_buffer->ptr_input_undo = NULL; + new_buffer->input_undo_count = 0; + + /* init completion */ + new_completion = malloc (sizeof (*new_completion)); + if (new_completion) + { + new_buffer->completion = new_completion; + gui_completion_buffer_init (new_completion, new_buffer); + } + + /* init history */ + new_buffer->history = NULL; + new_buffer->last_history = NULL; + new_buffer->ptr_history = NULL; + new_buffer->num_history = 0; + + /* text search */ + new_buffer->text_search = GUI_TEXT_SEARCH_DISABLED; + new_buffer->text_search_exact = 0; + new_buffer->text_search_regex = 0; + new_buffer->text_search_regex_compiled = NULL; + new_buffer->text_search_where = 0; + new_buffer->text_search_found = 0; + new_buffer->text_search_input = NULL; + + /* highlight */ + new_buffer->highlight_words = NULL; + new_buffer->highlight_regex = NULL; + new_buffer->highlight_regex_compiled = NULL; + new_buffer->highlight_tags = NULL; + new_buffer->highlight_tags_count = 0; + new_buffer->highlight_tags_array = NULL; + + /* hotlist */ + new_buffer->hotlist_max_level_nicks = hashtable_new (32, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_INTEGER, + NULL, + NULL); + + /* keys */ + new_buffer->keys = NULL; + new_buffer->last_key = NULL; + new_buffer->keys_count = 0; + + /* local variables */ + new_buffer->local_variables = hashtable_new (32, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); + hashtable_set (new_buffer->local_variables, + "plugin", plugin_get_name (plugin)); + hashtable_set (new_buffer->local_variables, "name", name); + + /* add buffer to buffers list */ + first_buffer_creation = (gui_buffers == NULL); + gui_buffer_insert (new_buffer); + + gui_buffers_count++; + + /* set notify level */ + new_buffer->notify = gui_buffer_notify_get (new_buffer); + + /* assign this buffer to windows of layout */ + gui_layout_window_assign_buffer (new_buffer); + + if (first_buffer_creation) + { + gui_buffer_visited_add (new_buffer); } else - return NULL; + { + hook_signal_send ("buffer_opened", + WEECHAT_HOOK_SIGNAL_POINTER, new_buffer); + } return new_buffer; } @@ -1999,6 +2091,32 @@ gui_buffer_search_by_number (int number) } /* + * Searches for a buffer by number, full name or partial name. + */ + +struct t_gui_buffer * +gui_buffer_search_by_number_or_name (const char *string) +{ + struct t_gui_buffer *ptr_buffer; + long number; + char *error; + + ptr_buffer = NULL; + + number = strtol (string, &error, 10); + if (error && !error[0]) + ptr_buffer = gui_buffer_search_by_number (number); + else + { + ptr_buffer = gui_buffer_search_by_full_name (string); + if (!ptr_buffer) + ptr_buffer = gui_buffer_search_by_partial_name (NULL, string); + } + + return ptr_buffer; +} + +/* * Searches for a buffer by layout number. */ @@ -2023,6 +2141,62 @@ gui_buffer_search_by_layout_number (int layout_number, } /* + * Searches a range of buffer between "number1" and "number2" (both are + * included in the range). + * + * Arguments "ptr_first_buffer" and "ptr_last_buffer" must NOT be NULL. + * They are set with the first buffer with number >= number1 and the last + * buffer with number <= number2. + * + * If "different_numbers" is not NULL, it is set with the number of + * "different numbers" from number1 to number2 (including these numbers). + * + * Note: first/last buffers returned may have different number than + * number1/number2. + * For example with buffers: 1 2 5 7 10, if number1 == 3 and number2 == 8, + * the function will return: + * first: pointer to buffer 5 (first merged buffer in case of merged buffers) + * last : pointer to buffer 7 (last merged buffer in case of merged buffers) + */ + +void +gui_buffer_search_range (int number1, int number2, + struct t_gui_buffer **ptr_first_buffer, + struct t_gui_buffer **ptr_last_buffer, + int *different_numbers) +{ + struct t_gui_buffer *ptr_buffer; + int prev_number; + + *ptr_first_buffer = NULL; + *ptr_last_buffer = NULL; + if (different_numbers) + *different_numbers = 0; + + if ((number1 < 1) || (number2 < 1) || (number1 > number2)) + return; + + prev_number = -1; + for (ptr_buffer = gui_buffers; + ptr_buffer && (ptr_buffer->number <= number2); + ptr_buffer = ptr_buffer->next_buffer) + { + if (!*ptr_first_buffer && (ptr_buffer->number >= number1)) + *ptr_first_buffer = ptr_buffer; + + *ptr_last_buffer = ptr_buffer; + + /* count the number of different numbers between number1 & 2 */ + if (different_numbers && *ptr_first_buffer + && (ptr_buffer->number != prev_number)) + { + (*different_numbers)++; + } + prev_number = ptr_buffer->number; + } +} + +/* * Returns number of merged buffers (buffers with same number). */ @@ -2160,7 +2334,7 @@ gui_buffer_close (struct t_gui_buffer *buffer) if (gui_buffer_count_merged_buffers (buffer->number) > 1) { ptr_back_to_buffer = gui_buffer_get_next_active_buffer (buffer); - gui_buffer_unmerge (buffer, -1); + gui_buffer_unmerge (buffer, last_gui_buffer->number + 1); } if (!weechat_quit) @@ -2231,11 +2405,14 @@ gui_buffer_close (struct t_gui_buffer *buffer) gui_buffer_visited_remove_by_buffer (buffer); - /* decrease buffer number for all next buffers */ - for (ptr_buffer = buffer->next_buffer; ptr_buffer; - ptr_buffer = ptr_buffer->next_buffer) + /* compute "number - 1" on next buffers if auto renumber is ON */ + if (CONFIG_BOOLEAN(config_look_buffer_auto_renumber)) { - ptr_buffer->number--; + for (ptr_buffer = buffer->next_buffer; ptr_buffer; + ptr_buffer = ptr_buffer->next_buffer) + { + ptr_buffer->number--; + } } /* free all lines */ @@ -2313,6 +2490,9 @@ gui_buffer_close (struct t_gui_buffer *buffer) if (gui_buffer_last_displayed == buffer) gui_buffer_last_displayed = NULL; + if (gui_buffers_count > 0) + gui_buffers_count--; + hook_signal_send ("buffer_closed", WEECHAT_HOOK_SIGNAL_POINTER, buffer); @@ -2441,6 +2621,116 @@ gui_buffer_get_previous_active_buffer (struct t_gui_buffer *buffer) } /* + * Renumbers buffers with consecutive numbers between the range + * number1 -> number2, sarting with new number "start_number". + * + * If number1 < 1, then renumber starts at first buffer in list (with lowest + * number). + * If number2 < 1, then renumber ends at last buffer in list (with highest + * number). + * If start_number is < 1, then the numbers will start with the first number + * seen in range number1-number2. + * + * Note: the start_number must be strictly greater than the buffer before + * "number1". + * + * Examples (^^^ == the buffers affected/renumbered): + * + * renumber(4, 10, 4): 1 2 6 8 10 15 + * --> 1 2 4 5 6 15 + * ^^^^^^^^ + * + * renumber(4, 10, -1): 1 2 6 8 10 15 + * --> 1 2 6 7 8 15 + * ^^^^^^^^ + * + * renumber(3, -1, 10): 1 2 6 8 10 15 + * --> 1 2 10 11 12 13 + * ^^^^^^^^^^^^^^ + * + * renumber(-1, -1, -1): 1 2 6 8 10 15 + * --> 1 2 3 4 5 6 + * ^^^^^^^^^^^^^^^^^^ + * + * renumber(-1, -1, 5): 1 2 6 8 10 15 + * --> 5 6 7 8 9 10 + * ^^^^^^^^^^^^^^^^^^ + */ + +void +gui_buffer_renumber (int number1, int number2, int start_number) +{ + struct t_gui_buffer *ptr_buffer, *ptr_buffer2, *ptr_buffer_moved; + struct t_gui_buffer *ptr_first_buffer, *ptr_last_buffer; + int different_numbers, current_number, number; + + /* if numbers are >= 1, from_number must be <= to_number */ + if ((number1 >= 1) && (number2 >= 1) && (number1 > number2)) + return; + + /* replace negative buffer numbers */ + if (number1 < 1) + number1 = gui_buffers->number; + if (number2 < 1) + number2 = last_gui_buffer->number; + + /* search for first and last buffers affected by renumbering */ + gui_buffer_search_range (number1, number2, + &ptr_first_buffer, &ptr_last_buffer, + &different_numbers); + if (!ptr_first_buffer || !ptr_last_buffer) + return; + + if (start_number < 1) + start_number = ptr_first_buffer->number; + else if (start_number > GUI_BUFFER_NUMBER_MAX) + start_number = GUI_BUFFER_NUMBER_MAX; + + /* the start number must be greater than buffer before first buffer */ + if (ptr_first_buffer->prev_buffer + && (start_number <= ptr_first_buffer->prev_buffer->number)) + { + return; + } + + /* + * start_number + different_numbers must be lower than buffer after + * last buffer + */ + if (ptr_last_buffer->next_buffer + && (start_number + different_numbers - 1 >= ptr_last_buffer->next_buffer->number)) + { + return; + } + + /* let's go for the renumbering! */ + current_number = start_number; + ptr_buffer = ptr_first_buffer; + while (ptr_buffer) + { + number = ptr_buffer->number; + ptr_buffer_moved = (number != current_number) ? ptr_buffer : NULL; + ptr_buffer2 = ptr_buffer; + while (ptr_buffer && (ptr_buffer->number == number)) + { + ptr_buffer->number = current_number; + ptr_buffer2 = ptr_buffer; + ptr_buffer = ptr_buffer->next_buffer; + } + if (ptr_buffer_moved) + { + hook_signal_send ("buffer_moved", + WEECHAT_HOOK_SIGNAL_POINTER, ptr_buffer_moved); + } + ptr_buffer = ptr_buffer2; + if (ptr_buffer == ptr_last_buffer) + break; + ptr_buffer = ptr_buffer->next_buffer; + current_number++; + } +} + +/* * Moves a buffer to another number. */ @@ -2449,123 +2739,116 @@ gui_buffer_move_to_number (struct t_gui_buffer *buffer, int number) { struct t_gui_buffer *ptr_first_buffer, *ptr_last_buffer, *ptr_buffer; struct t_gui_buffer *ptr_buffer_pos; + int auto_renumber; - /* if only one buffer then return */ - if (gui_buffers == last_gui_buffer) + auto_renumber = CONFIG_BOOLEAN(config_look_buffer_auto_renumber); + + /* nothing to do if auto renumber is ON and that there is only one buffer */ + if (auto_renumber && (gui_buffers == last_gui_buffer)) return; if (number < 1) number = 1; + if (number > GUI_BUFFER_NUMBER_MAX) + number = GUI_BUFFER_NUMBER_MAX; + /* buffer number is already OK ? */ if (number == buffer->number) return; - ptr_first_buffer = NULL; - ptr_last_buffer = NULL; - for (ptr_buffer = gui_buffers; ptr_buffer; - ptr_buffer = ptr_buffer->next_buffer) - { - if (ptr_buffer->number == buffer->number) - { - if (!ptr_first_buffer) - ptr_first_buffer = ptr_buffer; - ptr_last_buffer = ptr_buffer; - } - } - - /* error when looking for buffers */ + /* search for first and last buffer to move */ + gui_buffer_search_range (buffer->number, buffer->number, + &ptr_first_buffer, + &ptr_last_buffer, + NULL); if (!ptr_first_buffer || !ptr_last_buffer) return; - /* if group of buffers found is all buffers, then we can't move buffers! */ - if ((ptr_first_buffer == gui_buffers) && (ptr_last_buffer == last_gui_buffer)) + /* + * if group of buffers found is all buffers, then we can't move buffers! + * (allowed only if auto renumber is OFF) + */ + if (auto_renumber + && (ptr_first_buffer == gui_buffers) + && (ptr_last_buffer == last_gui_buffer)) + { return; + } /* remove buffer(s) from list */ - if (ptr_first_buffer == gui_buffers) - { - gui_buffers = ptr_last_buffer->next_buffer; - gui_buffers->prev_buffer = NULL; - } - else if (ptr_last_buffer == last_gui_buffer) - { - last_gui_buffer = ptr_first_buffer->prev_buffer; - last_gui_buffer->next_buffer = NULL; - } if (ptr_first_buffer->prev_buffer) (ptr_first_buffer->prev_buffer)->next_buffer = ptr_last_buffer->next_buffer; if (ptr_last_buffer->next_buffer) (ptr_last_buffer->next_buffer)->prev_buffer = ptr_first_buffer->prev_buffer; + if (gui_buffers == ptr_first_buffer) + gui_buffers = ptr_last_buffer->next_buffer; + if (last_gui_buffer == ptr_last_buffer) + last_gui_buffer = ptr_first_buffer->prev_buffer; - /* compute "number - 1" for all buffers after buffer(s) */ - for (ptr_buffer = ptr_last_buffer->next_buffer; ptr_buffer; - ptr_buffer = ptr_buffer->next_buffer) + /* compute "number - 1" on next buffers if auto renumber is ON */ + if (auto_renumber) + { + for (ptr_buffer = ptr_last_buffer->next_buffer; ptr_buffer; + ptr_buffer = ptr_buffer->next_buffer) + { + ptr_buffer->number--; + } + } + + /* search for new position in the list */ + for (ptr_buffer_pos = gui_buffers; ptr_buffer_pos; + ptr_buffer_pos = ptr_buffer_pos->next_buffer) { - ptr_buffer->number--; + if (ptr_buffer_pos->number >= number) + break; } - if (number == 1) + if (ptr_buffer_pos) { + /* insert before buffer found */ for (ptr_buffer = ptr_first_buffer; ptr_buffer; ptr_buffer = ptr_buffer->next_buffer) { - ptr_buffer->number = 1; + ptr_buffer->number = number; if (ptr_buffer == ptr_last_buffer) break; } - gui_buffers->prev_buffer = ptr_last_buffer; - ptr_first_buffer->prev_buffer = NULL; - ptr_last_buffer->next_buffer = gui_buffers; - gui_buffers = ptr_first_buffer; + ptr_first_buffer->prev_buffer = ptr_buffer_pos->prev_buffer; + if (!ptr_first_buffer->prev_buffer) + gui_buffers = ptr_first_buffer; + ptr_last_buffer->next_buffer = ptr_buffer_pos; + if (!ptr_last_buffer->next_buffer) + last_gui_buffer = ptr_last_buffer; + if (ptr_buffer_pos->prev_buffer) + (ptr_buffer_pos->prev_buffer)->next_buffer = ptr_first_buffer; + ptr_buffer_pos->prev_buffer = ptr_last_buffer; + + /* compute "number + 1" on next buffers */ + if (ptr_last_buffer->next_buffer + && (ptr_last_buffer->next_buffer->number == number)) + { + gui_buffer_shift_numbers (ptr_last_buffer->next_buffer); + } } else { - /* search for new position in the list */ - for (ptr_buffer_pos = gui_buffers; ptr_buffer_pos; - ptr_buffer_pos = ptr_buffer_pos->next_buffer) + /* number not found (too big)? => add to the end */ + for (ptr_buffer = ptr_first_buffer; ptr_buffer; + ptr_buffer = ptr_buffer->next_buffer) { - if (ptr_buffer_pos->number >= number) + ptr_buffer->number = (auto_renumber) ? + last_gui_buffer->number + 1 : number; + if (ptr_buffer == ptr_last_buffer) break; } - if (ptr_buffer_pos) - { - /* insert before buffer found */ - for (ptr_buffer = ptr_first_buffer; ptr_buffer; - ptr_buffer = ptr_buffer->next_buffer) - { - ptr_buffer->number = ptr_buffer_pos->number; - if (ptr_buffer == ptr_last_buffer) - break; - } - ptr_first_buffer->prev_buffer = ptr_buffer_pos->prev_buffer; - ptr_last_buffer->next_buffer = ptr_buffer_pos; - if (ptr_buffer_pos->prev_buffer) - (ptr_buffer_pos->prev_buffer)->next_buffer = ptr_first_buffer; - ptr_buffer_pos->prev_buffer = ptr_last_buffer; - } - else - { - /* number not found (too big)? => add to end */ - for (ptr_buffer = ptr_first_buffer; ptr_buffer; - ptr_buffer = ptr_buffer->next_buffer) - { - ptr_buffer->number = last_gui_buffer->number + 1; - if (ptr_buffer == ptr_last_buffer) - break; - } - ptr_first_buffer->prev_buffer = last_gui_buffer; - ptr_last_buffer->next_buffer = NULL; + ptr_first_buffer->prev_buffer = last_gui_buffer; + ptr_last_buffer->next_buffer = NULL; + if (!gui_buffers) + gui_buffers = ptr_first_buffer; + if (last_gui_buffer) last_gui_buffer->next_buffer = ptr_first_buffer; - last_gui_buffer = ptr_last_buffer; - } - } - - /* compute "number + 1" for all buffers after buffer(s) */ - for (ptr_buffer = ptr_last_buffer->next_buffer; ptr_buffer; - ptr_buffer = ptr_buffer->next_buffer) - { - ptr_buffer->number++; + last_gui_buffer = ptr_last_buffer; } hook_signal_send ("buffer_moved", @@ -2573,58 +2856,123 @@ gui_buffer_move_to_number (struct t_gui_buffer *buffer, int number) } /* - * Swaps two buffers. + * Swaps two buffers (or merged buffers). */ void -gui_buffer_swap (struct t_gui_buffer *buffer1, struct t_gui_buffer *buffer2) +gui_buffer_swap (int number1, int number2) { - struct t_gui_buffer *ptr_buffer1, *ptr_buffer2; - int number1, number2; + struct t_gui_buffer *ptr_buffer, *ptr_first_buffer[2], *ptr_last_buffer[2]; + int number; - if (!buffer1 || !buffer2) + /* swap buffer with itself? nothing to do! */ + if (number1 == number2) return; - /* store pointers and numbers, with number1 < number2 */ - ptr_buffer1 = (buffer1->number < buffer2->number) ? buffer1 : buffer2; - ptr_buffer2 = (buffer1->number < buffer2->number) ? buffer2 : buffer1; - number1 = ptr_buffer1->number; - number2 = ptr_buffer2->number; + /* ensure we have number1 < number2: if not, exchange numbers */ + if (number1 > number2) + { + number = number1; + number1 = number2; + number2 = number; + } - /* swap buffer with itself? nothing to do! */ - if (number1 == number2) + /* search for first and last buffers, for each number */ + gui_buffer_search_range (number1, number1, + &ptr_first_buffer[0], + &ptr_last_buffer[0], + NULL); + if (!ptr_first_buffer[0] || !ptr_last_buffer[0]) + return; + gui_buffer_search_range (number2, number2, + &ptr_first_buffer[1], + &ptr_last_buffer[1], + NULL); + if (!ptr_first_buffer[1] || !ptr_last_buffer[1]) return; - /* move number2 before number1 */ - gui_buffer_move_to_number (ptr_buffer2, number1); + /* first set gui_buffers/last_gui_buffers if they are affected by the swap */ + if (gui_buffers == ptr_first_buffer[0]) + gui_buffers = ptr_first_buffer[1]; + if (last_gui_buffer == ptr_last_buffer[1]) + last_gui_buffer = ptr_last_buffer[0]; + + /* swap the pointer outside elements in the linked list */ + if (ptr_first_buffer[0]->prev_buffer) + (ptr_first_buffer[0]->prev_buffer)->next_buffer = ptr_first_buffer[1]; + if (ptr_last_buffer[1]->next_buffer) + (ptr_last_buffer[1]->next_buffer)->prev_buffer = ptr_last_buffer[0]; + if (ptr_last_buffer[0]->next_buffer == ptr_first_buffer[1]) + { + /* special case: adjacent buffers */ + ptr_first_buffer[1]->prev_buffer = ptr_first_buffer[0]->prev_buffer; + ptr_first_buffer[0]->prev_buffer = ptr_last_buffer[1]; + ptr_last_buffer[0]->next_buffer = ptr_last_buffer[1]->next_buffer; + ptr_last_buffer[1]->next_buffer = ptr_first_buffer[0]; + } + else + { + if (ptr_first_buffer[1]->prev_buffer) + (ptr_first_buffer[1]->prev_buffer)->next_buffer = ptr_first_buffer[0]; + if (ptr_last_buffer[0]->next_buffer) + (ptr_last_buffer[0]->next_buffer)->prev_buffer = ptr_last_buffer[1]; + /* swap first[0]->prev <-> first[1]->prev */ + ptr_buffer = ptr_first_buffer[0]->prev_buffer; + ptr_first_buffer[0]->prev_buffer = ptr_first_buffer[1]->prev_buffer; + ptr_first_buffer[1]->prev_buffer = ptr_buffer; + /* swap last[0]->next <-> last[1]->next */ + ptr_buffer = ptr_last_buffer[0]->next_buffer; + ptr_last_buffer[0]->next_buffer = ptr_last_buffer[1]->next_buffer; + ptr_last_buffer[1]->next_buffer = ptr_buffer; + } + + /* swap the numbers inside buffers */ + for (ptr_buffer = ptr_first_buffer[0]; ptr_buffer; + ptr_buffer = ptr_buffer->next_buffer) + { + ptr_buffer->number = number2; + if (ptr_buffer == ptr_last_buffer[0]) + break; + } + for (ptr_buffer = ptr_first_buffer[1]; ptr_buffer; + ptr_buffer = ptr_buffer->next_buffer) + { + ptr_buffer->number = number1; + if (ptr_buffer == ptr_last_buffer[1]) + break; + } - /* move number1 before number2 */ - if (number2 > number1 + 1) - gui_buffer_move_to_number (ptr_buffer1, number2); + /* send signals */ + hook_signal_send ("buffer_moved", + WEECHAT_HOOK_SIGNAL_POINTER, ptr_first_buffer[0]); + hook_signal_send ("buffer_moved", + WEECHAT_HOOK_SIGNAL_POINTER, ptr_first_buffer[1]); } /* - * Merges a buffer to another buffer. + * Merges a buffer into another buffer. */ void gui_buffer_merge (struct t_gui_buffer *buffer, struct t_gui_buffer *target_buffer) { - struct t_gui_buffer *ptr_buffer; - int target_number; + struct t_gui_buffer *ptr_buffer, *ptr_first_buffer[2], *ptr_last_buffer[2]; - /* if only one buffer then return */ - if (gui_buffers == last_gui_buffer) - return; - - if ((buffer == target_buffer) || (buffer->number == target_buffer->number)) + /* + * nothing to do if: + * - there is only one buffer + * - buffer and target are the same + * - numbers of buffers are the same (already merged) + */ + if ((gui_buffers == last_gui_buffer) + || (buffer == target_buffer) + || (buffer->number == target_buffer->number)) + { return; + } - if (gui_buffer_count_merged_buffers (buffer->number) > 1) - gui_buffer_unmerge (buffer, -1); - - /* check if current buffer and target buffers are type "formatted" */ + /* check if current buffer and target buffers have "formatted" content */ if ((buffer->type != GUI_BUFFER_TYPE_FORMATTED) || (target_buffer->type != GUI_BUFFER_TYPE_FORMATTED)) { @@ -2635,28 +2983,66 @@ gui_buffer_merge (struct t_gui_buffer *buffer, return; } - /* move buffer immediately after number we want to merge to */ - target_number = (buffer->number < target_buffer->number) ? - target_buffer->number : target_buffer->number + 1; - if (buffer->number != target_number) - gui_buffer_move_to_number (buffer, target_number); + /* search for first and last buffer to merge */ + gui_buffer_search_range (buffer->number, buffer->number, + &ptr_first_buffer[0], + &ptr_last_buffer[0], + NULL); + if (!ptr_first_buffer[0] || !ptr_last_buffer[0]) + return; - /* change number */ - buffer->number--; + /* search for first and last target buffer */ + gui_buffer_search_range (target_buffer->number, target_buffer->number, + &ptr_first_buffer[1], + &ptr_last_buffer[1], + NULL); + if (!ptr_first_buffer[1] || !ptr_last_buffer[1]) + return; - /* mix lines */ - gui_line_mix_buffers (buffer); + /* remove buffer(s) to merge from list */ + if (ptr_first_buffer[0]->prev_buffer) + (ptr_first_buffer[0]->prev_buffer)->next_buffer = ptr_last_buffer[0]->next_buffer; + if (ptr_last_buffer[0]->next_buffer) + (ptr_last_buffer[0]->next_buffer)->prev_buffer = ptr_first_buffer[0]->prev_buffer; + if (gui_buffers == ptr_first_buffer[0]) + gui_buffers = ptr_last_buffer[0]->next_buffer; + if (last_gui_buffer == ptr_last_buffer[0]) + last_gui_buffer = ptr_first_buffer[0]->prev_buffer; - /* set buffer as active in merged buffers group */ - gui_buffer_set_active_buffer (buffer); + /* compute "number - 1" on next buffers if auto renumber is ON */ + if (CONFIG_BOOLEAN(config_look_buffer_auto_renumber)) + { + for (ptr_buffer = ptr_last_buffer[0]->next_buffer; ptr_buffer; + ptr_buffer = ptr_buffer->next_buffer) + { + ptr_buffer->number--; + } + } + + /* insert new merged buffers after target buffer */ + if (ptr_last_buffer[1] == last_gui_buffer) + last_gui_buffer = ptr_last_buffer[0]; + if (ptr_last_buffer[1]->next_buffer) + (ptr_last_buffer[1]->next_buffer)->prev_buffer = ptr_last_buffer[0]; + ptr_last_buffer[0]->next_buffer = ptr_last_buffer[1]->next_buffer; + ptr_last_buffer[1]->next_buffer = ptr_first_buffer[0]; + ptr_first_buffer[0]->prev_buffer = ptr_last_buffer[1]; - /* compute "number - 1" for next buffers */ - for (ptr_buffer = buffer->next_buffer; ptr_buffer; + /* change number in new merged buffer(s) */ + for (ptr_buffer = ptr_first_buffer[0]; ptr_buffer; ptr_buffer = ptr_buffer->next_buffer) { - ptr_buffer->number--; + ptr_buffer->number = target_buffer->number; + if (ptr_buffer == ptr_last_buffer[0]) + break; } + /* mix lines */ + gui_line_mix_buffers (buffer); + + /* set buffer as active in merged buffers group */ + gui_buffer_set_active_buffer (buffer); + gui_buffer_compute_num_displayed (); gui_window_ask_refresh (1); @@ -2678,18 +3064,20 @@ gui_buffer_unmerge (struct t_gui_buffer *buffer, int number) int num_merged; struct t_gui_buffer *ptr_buffer, *ptr_new_active_buffer; - /* if only one buffer then return */ + /* nothing to do if there is only one buffer */ if (gui_buffers == last_gui_buffer) return; - ptr_new_active_buffer = NULL; - + /* nothing to do if buffer is not merged with at least one buffer */ num_merged = gui_buffer_count_merged_buffers (buffer->number); - - /* can't unmerge if buffer is not merged to at least one buffer */ if (num_merged < 2) return; + ptr_new_active_buffer = NULL; + + if (number > GUI_BUFFER_NUMBER_MAX) + number = GUI_BUFFER_NUMBER_MAX; + /* by default, we move buffer to buffer->number + 1 */ if ((number < 1) || (number == buffer->number)) { @@ -2697,8 +3085,12 @@ gui_buffer_unmerge (struct t_gui_buffer *buffer, int number) } else { - if (number > last_gui_buffer->number + 1) + /* if auto renumber is ON, max number is last buffer + 1 */ + if (CONFIG_BOOLEAN(config_look_buffer_auto_renumber) + && (number > last_gui_buffer->number + 1)) + { number = last_gui_buffer->number + 1; + } } if (num_merged == 2) @@ -2766,10 +3158,12 @@ gui_buffer_unmerge (struct t_gui_buffer *buffer, int number) } buffer->active = 1; buffer->number = number; - for (ptr_buffer = buffer->next_buffer; ptr_buffer; - ptr_buffer = ptr_buffer->next_buffer) + + /* compute "number + 1" on next buffers */ + if (buffer->next_buffer + && (buffer->next_buffer->number == number)) { - ptr_buffer->number++; + gui_buffer_shift_numbers (buffer->next_buffer); } gui_buffer_compute_num_displayed (); @@ -2793,21 +3187,24 @@ gui_buffer_unmerge (struct t_gui_buffer *buffer, int number) void gui_buffer_unmerge_all () { + struct t_gui_buffer *ptr_buffer, *ptr_next_buffer; int number; - struct t_gui_buffer *ptr_buffer; - number = 1; - while (number <= last_gui_buffer->number) + ptr_buffer = gui_buffers; + while (ptr_buffer) { + number = ptr_buffer->number; while (gui_buffer_count_merged_buffers (number) > 1) { - ptr_buffer = gui_buffer_search_by_number (number); - if (ptr_buffer) - gui_buffer_unmerge (ptr_buffer, -1); - else - break; + ptr_next_buffer = ptr_buffer->next_buffer; + gui_buffer_unmerge (ptr_buffer, -1); + ptr_buffer = ptr_next_buffer; + } + /* go to the next number */ + while (ptr_buffer && (ptr_buffer->number == number)) + { + ptr_buffer = ptr_buffer->next_buffer; } - number++; } } @@ -2828,7 +3225,7 @@ gui_buffer_sort_by_layout_number () while (ptr_buffer) { ptr_next_buffer = ptr_buffer->next_buffer; - gui_buffer_insert (ptr_buffer, 0); + gui_buffer_insert (ptr_buffer); ptr_buffer = ptr_next_buffer; } } @@ -3569,6 +3966,7 @@ gui_buffer_print_log () log_printf (""); log_printf ("gui_buffers . . . . . . . . . : 0x%lx", gui_buffers); log_printf ("last_gui_buffer . . . . . . . : 0x%lx", last_gui_buffer); + log_printf ("gui_buffers_count . . . . . . : %d", gui_buffers_count); log_printf ("gui_buffers_visited . . . . . : 0x%lx", gui_buffers_visited); log_printf ("last_gui_buffer_visited . . . : 0x%lx", last_gui_buffer_visited); log_printf ("gui_buffers_visited_index . . : %d", gui_buffers_visited_index); diff --git a/src/gui/gui-buffer.h b/src/gui/gui-buffer.h index 0e0c4aa7b..a370abb90 100644 --- a/src/gui/gui-buffer.h +++ b/src/gui/gui-buffer.h @@ -20,6 +20,7 @@ #ifndef __WEECHAT_GUI_BUFFER_H #define __WEECHAT_GUI_BUFFER_H 1 +#include <limits.h> #include <regex.h> struct t_hashtable; @@ -46,6 +47,10 @@ enum t_gui_buffer_notify #define GUI_BUFFER_MAIN "weechat" +#define GUI_BUFFERS_MAX 10000 + +#define GUI_BUFFER_NUMBER_MAX (INT_MAX - 10000) + #define GUI_TEXT_SEARCH_DISABLED 0 #define GUI_TEXT_SEARCH_BACKWARD 1 #define GUI_TEXT_SEARCH_FORWARD 2 @@ -205,6 +210,7 @@ struct t_gui_buffer_visited extern struct t_gui_buffer *gui_buffers; extern struct t_gui_buffer *last_gui_buffer; +extern int gui_buffers_count; extern struct t_gui_buffer_visited *gui_buffers_visited; extern struct t_gui_buffer_visited *last_gui_buffer_visited; extern int gui_buffers_visited_index; @@ -276,6 +282,7 @@ extern struct t_gui_buffer *gui_buffer_search_by_full_name (const char *full_nam extern struct t_gui_buffer *gui_buffer_search_by_partial_name (const char *plugin, const char *name); extern struct t_gui_buffer *gui_buffer_search_by_number (int number); +extern struct t_gui_buffer *gui_buffer_search_by_number_or_name (const char *string); extern struct t_gui_buffer *gui_buffer_search_by_layout_number (int layout_number, int layout_number_merge_order); extern int gui_buffer_count_merged_buffers (int number); @@ -288,9 +295,9 @@ extern void gui_buffer_switch_by_number (struct t_gui_window *window, extern void gui_buffer_set_active_buffer (struct t_gui_buffer *buffer); extern struct t_gui_buffer *gui_buffer_get_next_active_buffer (struct t_gui_buffer *buffer); extern struct t_gui_buffer *gui_buffer_get_previous_active_buffer (struct t_gui_buffer *buffer); +extern void gui_buffer_renumber (int number1, int number2, int start_number); extern void gui_buffer_move_to_number (struct t_gui_buffer *buffer, int number); -extern void gui_buffer_swap (struct t_gui_buffer *buffer1, - struct t_gui_buffer *buffer2); +extern void gui_buffer_swap (int number1, int number2); extern void gui_buffer_merge (struct t_gui_buffer *buffer, struct t_gui_buffer *target_buffer); extern void gui_buffer_unmerge (struct t_gui_buffer *buffer, int number); diff --git a/src/gui/gui-layout.c b/src/gui/gui-layout.c index 42a143bf0..672af41e7 100644 --- a/src/gui/gui-layout.c +++ b/src/gui/gui-layout.c @@ -342,8 +342,7 @@ gui_layout_buffer_save (struct t_gui_layout *layout) void gui_layout_buffer_apply (struct t_gui_layout *layout) { - struct t_gui_buffer *ptr_buffer, *ptr_next_buffer; - int number, count_merged; + struct t_gui_buffer *ptr_buffer; if (!layout) return; @@ -357,35 +356,16 @@ gui_layout_buffer_apply (struct t_gui_layout *layout) /* sort buffers by layout number (without merge) */ gui_buffer_sort_by_layout_number (); - /* merge buffers */ - ptr_buffer = gui_buffers->next_buffer; - while (ptr_buffer) - { - ptr_next_buffer = ptr_buffer->next_buffer; - - if ((ptr_buffer->layout_number >= 1) - && (ptr_buffer->layout_number == (ptr_buffer->prev_buffer)->layout_number)) - { - gui_buffer_merge (ptr_buffer, ptr_buffer->prev_buffer); - } - - ptr_buffer = ptr_next_buffer; - } - /* set appropriate active buffers */ - number = 1; - while (number <= last_gui_buffer->number) + for (ptr_buffer = gui_buffers; ptr_buffer; + ptr_buffer = ptr_buffer->next_buffer) { - count_merged = gui_buffer_count_merged_buffers (number); - if (count_merged > 1) + if ((gui_buffer_count_merged_buffers (ptr_buffer->number) > 1) + && (ptr_buffer->layout_number == ptr_buffer->number) + && (ptr_buffer->layout_number_merge_order == 0)) { - ptr_buffer = gui_buffer_search_by_layout_number (number, 0); - if (ptr_buffer && !ptr_buffer->active) - { - gui_buffer_set_active_buffer (ptr_buffer); - } + gui_buffer_set_active_buffer (ptr_buffer); } - number++; } } |