mirror of
https://github.com/weechat/weechat.git
synced 2026-06-28 05:46:38 +02:00
9a160509d7
The problem happened because we used a pointer to a "struct t_gui_buffer_visited" for the switch to another buffer, when the buffer is closed. This is executed in all windows displaying the buffer, but on each switch to buffer, the visited buffers are updated and therefore the address can change. The pointer becomes invalid, and WeeChat still uses it on next windows for the buffer switch. It happened rarely because the visited buffer is freed and allocated immediately after, so the address is often the same in memory. Thanks to silverd for the tests on OS X to track the problem.
3728 lines
117 KiB
C
3728 lines
117 KiB
C
/*
|
|
* gui-buffer.c - buffer functions (used by all GUI)
|
|
*
|
|
* Copyright (C) 2003-2013 Sebastien Helleu <flashcode@flashtux.org>
|
|
*
|
|
* This file is part of WeeChat, the extensible chat client.
|
|
*
|
|
* WeeChat is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* WeeChat is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with WeeChat. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <time.h>
|
|
#include <ctype.h>
|
|
|
|
#include "../core/weechat.h"
|
|
#include "../core/wee-config.h"
|
|
#include "../core/wee-hashtable.h"
|
|
#include "../core/wee-hdata.h"
|
|
#include "../core/wee-hook.h"
|
|
#include "../core/wee-infolist.h"
|
|
#include "../core/wee-list.h"
|
|
#include "../core/wee-log.h"
|
|
#include "../core/wee-string.h"
|
|
#include "../core/wee-utf8.h"
|
|
#include "../plugins/plugin.h"
|
|
#include "gui-buffer.h"
|
|
#include "gui-chat.h"
|
|
#include "gui-color.h"
|
|
#include "gui-completion.h"
|
|
#include "gui-history.h"
|
|
#include "gui-hotlist.h"
|
|
#include "gui-input.h"
|
|
#include "gui-key.h"
|
|
#include "gui-layout.h"
|
|
#include "gui-line.h"
|
|
#include "gui-main.h"
|
|
#include "gui-nicklist.h"
|
|
#include "gui-window.h"
|
|
|
|
|
|
struct t_gui_buffer *gui_buffers = NULL; /* first buffer */
|
|
struct t_gui_buffer *last_gui_buffer = NULL; /* last buffer */
|
|
|
|
/* history of last visited buffers */
|
|
struct t_gui_buffer_visited *gui_buffers_visited = NULL;
|
|
struct t_gui_buffer_visited *last_gui_buffer_visited = NULL;
|
|
int gui_buffers_visited_index = -1; /* index of pointer in list */
|
|
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 */
|
|
|
|
char *gui_buffer_notify_string[GUI_BUFFER_NUM_NOTIFY] =
|
|
{ "none", "highlight", "message", "all" };
|
|
|
|
char *gui_buffer_properties_get_integer[] =
|
|
{ "number", "layout_number", "layout_number_merge_order", "type", "notify",
|
|
"num_displayed", "active", "print_hooks_enabled", "lines_hidden",
|
|
"prefix_max_length", "time_for_each_line", "nicklist",
|
|
"nicklist_case_sensitive", "nicklist_max_length", "nicklist_display_groups",
|
|
"nicklist_count", "nicklist_groups_count", "nicklist_nicks_count",
|
|
"nicklist_visible_count", "input", "input_get_unknown_commands",
|
|
"input_size", "input_length", "input_pos", "input_1st_display",
|
|
"num_history", "text_search", "text_search_exact", "text_search_regex",
|
|
"text_search_where", "text_search_found",
|
|
NULL
|
|
};
|
|
char *gui_buffer_properties_get_string[] =
|
|
{ "plugin", "name", "full_name", "short_name", "title", "input",
|
|
"text_search_input", "highlight_words", "highlight_regex", "highlight_tags",
|
|
"hotlist_max_level_nicks",
|
|
NULL
|
|
};
|
|
char *gui_buffer_properties_get_pointer[] =
|
|
{ "plugin", "text_search_regex_compiled", "highlight_regex_compiled",
|
|
NULL
|
|
};
|
|
char *gui_buffer_properties_set[] =
|
|
{ "unread", "display", "print_hooks_enabled", "number", "name", "short_name",
|
|
"type", "notify", "title", "time_for_each_line", "nicklist",
|
|
"nicklist_case_sensitive", "nicklist_display_groups", "highlight_words",
|
|
"highlight_words_add", "highlight_words_del", "highlight_regex",
|
|
"highlight_tags", "hotlist_max_level_nicks", "hotlist_max_level_nicks_add",
|
|
"hotlist_max_level_nicks_del", "input", "input_pos",
|
|
"input_get_unknown_commands",
|
|
NULL
|
|
};
|
|
|
|
|
|
/*
|
|
* Gets plugin name of buffer.
|
|
*
|
|
* Note: during upgrade process (at startup after /upgrade), the name of plugin
|
|
* is retrieved in temporary variable "plugin_name_for_upgrade".
|
|
*/
|
|
|
|
const char *
|
|
gui_buffer_get_plugin_name (struct t_gui_buffer *buffer)
|
|
{
|
|
if (buffer->plugin_name_for_upgrade)
|
|
return buffer->plugin_name_for_upgrade;
|
|
|
|
return plugin_get_name (buffer->plugin);
|
|
}
|
|
|
|
/*
|
|
* Get short name of buffer (of name if short_name is NULL).
|
|
*
|
|
* Note: this function never returns NULL.
|
|
*/
|
|
|
|
const char *
|
|
gui_buffer_get_short_name (struct t_gui_buffer *buffer)
|
|
{
|
|
return (buffer->short_name) ? buffer->short_name : buffer->name;
|
|
}
|
|
|
|
/*
|
|
* Builds "full_name" of buffer (for example after changing name or
|
|
* plugin_name_for_upgrade).
|
|
*/
|
|
|
|
void
|
|
gui_buffer_build_full_name (struct t_gui_buffer *buffer)
|
|
{
|
|
int length;
|
|
|
|
if (buffer->full_name)
|
|
free (buffer->full_name);
|
|
length = strlen (gui_buffer_get_plugin_name (buffer)) + 1 +
|
|
strlen (buffer->name) + 1;
|
|
buffer->full_name = malloc (length);
|
|
if (buffer->full_name)
|
|
{
|
|
snprintf (buffer->full_name, length, "%s.%s",
|
|
gui_buffer_get_plugin_name (buffer), buffer->name);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Adds a new local variable in a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_local_var_add (struct t_gui_buffer *buffer, const char *name,
|
|
const char *value)
|
|
{
|
|
void *ptr_value;
|
|
|
|
if (!buffer || !buffer->local_variables || !name || !value)
|
|
return;
|
|
|
|
ptr_value = hashtable_get (buffer->local_variables, name);
|
|
hashtable_set (buffer->local_variables, name, value);
|
|
hook_signal_send ((ptr_value) ?
|
|
"buffer_localvar_changed" : "buffer_localvar_added",
|
|
WEECHAT_HOOK_SIGNAL_POINTER, buffer);
|
|
}
|
|
|
|
/*
|
|
* Removes a local variable in a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_local_var_remove (struct t_gui_buffer *buffer, const char *name)
|
|
{
|
|
void *ptr_value;
|
|
|
|
if (!buffer || !buffer->local_variables || !name)
|
|
return;
|
|
|
|
ptr_value = hashtable_get (buffer->local_variables, name);
|
|
if (ptr_value)
|
|
{
|
|
hashtable_remove (buffer->local_variables, name);
|
|
hook_signal_send ("buffer_localvar_removed",
|
|
WEECHAT_HOOK_SIGNAL_POINTER, buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Removes all local variables in a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_local_var_remove_all (struct t_gui_buffer *buffer)
|
|
{
|
|
if (buffer && buffer->local_variables)
|
|
{
|
|
hashtable_remove_all (buffer->local_variables);
|
|
hook_signal_send ("buffer_localvar_removed",
|
|
WEECHAT_HOOK_SIGNAL_POINTER, buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Reads a notify level in configuration file.
|
|
*
|
|
* First tries with all arguments, then removes one by one to find notify level
|
|
* (from specific to general notify).
|
|
*/
|
|
|
|
int
|
|
gui_buffer_notify_get (struct t_gui_buffer *buffer)
|
|
{
|
|
char *option_name, *ptr_end;
|
|
int length;
|
|
struct t_config_option *ptr_option;
|
|
|
|
length = strlen (buffer->full_name) + 1;
|
|
option_name = malloc (length);
|
|
if (option_name)
|
|
{
|
|
snprintf (option_name, length, "%s", buffer->full_name);
|
|
|
|
ptr_end = option_name + strlen (option_name);
|
|
while (ptr_end >= option_name)
|
|
{
|
|
ptr_option = config_file_search_option (weechat_config_file,
|
|
weechat_config_section_notify,
|
|
option_name);
|
|
if (ptr_option)
|
|
{
|
|
free (option_name);
|
|
return CONFIG_INTEGER(ptr_option);
|
|
}
|
|
ptr_end--;
|
|
while ((ptr_end >= option_name) && (ptr_end[0] != '.'))
|
|
{
|
|
ptr_end--;
|
|
}
|
|
if ((ptr_end >= option_name) && (ptr_end[0] == '.'))
|
|
ptr_end[0] = '\0';
|
|
}
|
|
ptr_option = config_file_search_option (weechat_config_file,
|
|
weechat_config_section_notify,
|
|
option_name);
|
|
|
|
free (option_name);
|
|
|
|
if (ptr_option)
|
|
return CONFIG_INTEGER(ptr_option);
|
|
}
|
|
|
|
/* notify level not found */
|
|
return CONFIG_INTEGER(config_look_buffer_notify_default);
|
|
}
|
|
|
|
/*
|
|
* Sets notify value on a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_notify_set (struct t_gui_buffer *buffer)
|
|
{
|
|
int old_notify, new_notify;
|
|
|
|
old_notify = buffer->notify;
|
|
new_notify = gui_buffer_notify_get (buffer);
|
|
|
|
if (new_notify != old_notify)
|
|
{
|
|
buffer->notify = new_notify;
|
|
gui_chat_printf (NULL,
|
|
_("Notify changed for \"%s%s%s\": \"%s%s%s\" to \"%s%s%s\""),
|
|
GUI_COLOR(GUI_COLOR_CHAT_BUFFER),
|
|
buffer->full_name,
|
|
GUI_COLOR(GUI_COLOR_CHAT),
|
|
GUI_COLOR(GUI_COLOR_CHAT_VALUE),
|
|
gui_buffer_notify_string[old_notify],
|
|
GUI_COLOR(GUI_COLOR_CHAT),
|
|
GUI_COLOR(GUI_COLOR_CHAT_VALUE),
|
|
gui_buffer_notify_string[buffer->notify],
|
|
GUI_COLOR(GUI_COLOR_CHAT));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Sets notify values on all opened buffers.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_notify_set_all ()
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
gui_buffer_notify_set (ptr_buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Searches for position of buffer in list (to keep buffers sorted by number).
|
|
*/
|
|
|
|
struct t_gui_buffer *
|
|
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 (buffer->layout_number < 1)
|
|
return NULL;
|
|
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if ((ptr_buffer->layout_number < 1)
|
|
|| (buffer->layout_number < ptr_buffer->layout_number)
|
|
|| ((buffer->layout_number == ptr_buffer->layout_number)
|
|
&& (buffer->layout_number_merge_order <= ptr_buffer->layout_number_merge_order)))
|
|
{
|
|
/* not possible to insert a buffer between 2 merged buffers */
|
|
if (!ptr_buffer->prev_buffer
|
|
|| ((ptr_buffer->prev_buffer)->number != ptr_buffer->number))
|
|
{
|
|
return ptr_buffer;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* position not found, add to the end */
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* 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)
|
|
{
|
|
struct t_gui_buffer *pos, *ptr_buffer;
|
|
|
|
pos = gui_buffer_find_pos (buffer);
|
|
if (pos)
|
|
{
|
|
/* 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;
|
|
else
|
|
gui_buffers = buffer;
|
|
pos->prev_buffer = buffer;
|
|
for (ptr_buffer = pos; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
ptr_buffer->number++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* add buffer to the end */
|
|
buffer->number = (last_gui_buffer) ? last_gui_buffer->number + 1 : 1;
|
|
buffer->prev_buffer = last_gui_buffer;
|
|
buffer->next_buffer = NULL;
|
|
if (gui_buffers)
|
|
last_gui_buffer->next_buffer = buffer;
|
|
else
|
|
gui_buffers = buffer;
|
|
last_gui_buffer = buffer;
|
|
}
|
|
|
|
/* merge buffer with previous or next, if they have layout number */
|
|
if (automatic_merge && (buffer->layout_number >= 1))
|
|
{
|
|
if (buffer->prev_buffer
|
|
&& (buffer->layout_number == (buffer->prev_buffer)->layout_number))
|
|
{
|
|
gui_buffer_merge (buffer, buffer->prev_buffer);
|
|
}
|
|
else if ((buffer->next_buffer)
|
|
&& (buffer->layout_number == (buffer->next_buffer)->layout_number))
|
|
{
|
|
gui_buffer_merge (buffer, buffer->next_buffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Initializes input_buffer_* variables in a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_input_buffer_init (struct t_gui_buffer *buffer)
|
|
{
|
|
buffer->input_buffer_alloc = GUI_BUFFER_INPUT_BLOCK_SIZE;
|
|
buffer->input_buffer = malloc (GUI_BUFFER_INPUT_BLOCK_SIZE);
|
|
buffer->input_buffer[0] = '\0';
|
|
buffer->input_buffer_size = 0;
|
|
buffer->input_buffer_length = 0;
|
|
buffer->input_buffer_pos = 0;
|
|
buffer->input_buffer_1st_display = 0;
|
|
}
|
|
|
|
/*
|
|
* Creates a new buffer in current window.
|
|
*
|
|
* Returns pointer to new buffer, NULL if error.
|
|
*/
|
|
|
|
struct t_gui_buffer *
|
|
gui_buffer_new (struct t_weechat_plugin *plugin,
|
|
const char *name,
|
|
int (*input_callback)(void *data,
|
|
struct t_gui_buffer *buffer,
|
|
const char *input_data),
|
|
void *input_callback_data,
|
|
int (*close_callback)(void *data,
|
|
struct t_gui_buffer *buffer),
|
|
void *close_callback_data)
|
|
{
|
|
struct t_gui_buffer *new_buffer;
|
|
struct t_gui_completion *new_completion;
|
|
int first_buffer_creation;
|
|
|
|
if (!name || !name[0])
|
|
return NULL;
|
|
|
|
if (gui_buffer_search_by_name (plugin_get_name (plugin), name))
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("%sError: a buffer with same name (%s) already "
|
|
"exists"),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
|
name);
|
|
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;
|
|
|
|
/* 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, 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);
|
|
}
|
|
}
|
|
else
|
|
return NULL;
|
|
|
|
return new_buffer;
|
|
}
|
|
|
|
/*
|
|
* Checks if a buffer pointer is valid.
|
|
*
|
|
* Returns:
|
|
* 1: buffer exists
|
|
* 0: buffer does not exist
|
|
*/
|
|
|
|
int
|
|
gui_buffer_valid (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
|
|
/* NULL buffer is valid (it's for printing on first buffer) */
|
|
if (!buffer)
|
|
return 1;
|
|
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if (ptr_buffer == buffer)
|
|
return 1;
|
|
}
|
|
|
|
/* buffer not found */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Replaces local variables ($var) in a string, using value of local variables.
|
|
*
|
|
* Note: result must be freed after use.
|
|
*/
|
|
|
|
char *
|
|
gui_buffer_string_replace_local_var (struct t_gui_buffer *buffer,
|
|
const char *string)
|
|
{
|
|
int length, length_var, index_string, index_result;
|
|
char *result, *result2, *local_var;
|
|
const char *pos_end_name, *ptr_value;
|
|
|
|
if (!string)
|
|
return NULL;
|
|
|
|
length = strlen (string) + 1;
|
|
result = malloc (length);
|
|
if (result)
|
|
{
|
|
index_string = 0;
|
|
index_result = 0;
|
|
while (string[index_string])
|
|
{
|
|
if ((string[index_string] == '$')
|
|
&& ((index_string == 0) || (string[index_string - 1] != '\\')))
|
|
{
|
|
pos_end_name = string + index_string + 1;
|
|
while (pos_end_name[0])
|
|
{
|
|
if (isalnum ((unsigned char)pos_end_name[0])
|
|
&& (pos_end_name[0] != '_')
|
|
&& (pos_end_name[0] != '$'))
|
|
pos_end_name++;
|
|
else
|
|
break;
|
|
}
|
|
if (pos_end_name > string + index_string + 1)
|
|
{
|
|
local_var = string_strndup (string + index_string + 1,
|
|
pos_end_name - (string + index_string + 1));
|
|
if (local_var)
|
|
{
|
|
ptr_value = (const char *)hashtable_get (buffer->local_variables,
|
|
local_var);
|
|
if (ptr_value)
|
|
{
|
|
length_var = strlen (ptr_value);
|
|
length += length_var;
|
|
result2 = realloc (result, length);
|
|
if (!result2)
|
|
{
|
|
if (result)
|
|
free (result);
|
|
free (local_var);
|
|
return NULL;
|
|
}
|
|
result = result2;
|
|
strcpy (result + index_result, ptr_value);
|
|
index_result += length_var;
|
|
index_string += strlen (local_var) + 1;
|
|
}
|
|
else
|
|
result[index_result++] = string[index_string++];
|
|
|
|
free (local_var);
|
|
}
|
|
else
|
|
result[index_result++] = string[index_string++];
|
|
}
|
|
else
|
|
result[index_result++] = string[index_string++];
|
|
}
|
|
else
|
|
result[index_result++] = string[index_string++];
|
|
}
|
|
result[index_result] = '\0';
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Checks if full name of buffer matches (split) list of buffers.
|
|
*
|
|
* Returns:
|
|
* 1: full name matches list of buffers
|
|
* 0: full name does not match list of buffers
|
|
*/
|
|
|
|
int
|
|
gui_buffer_match_list_split (struct t_gui_buffer *buffer,
|
|
int num_buffers, char **buffers)
|
|
{
|
|
int i, match;
|
|
char *ptr_name;
|
|
|
|
match = 0;
|
|
|
|
for (i = 0; i < num_buffers; i++)
|
|
{
|
|
ptr_name = buffers[i];
|
|
if (ptr_name[0] == '!')
|
|
ptr_name++;
|
|
if (string_match (buffer->full_name, ptr_name, 0))
|
|
{
|
|
if (buffers[i][0] == '!')
|
|
return 0;
|
|
else
|
|
match = 1;
|
|
}
|
|
}
|
|
|
|
return match;
|
|
}
|
|
|
|
/*
|
|
* Checks if full name of buffer marches list of buffers.
|
|
*
|
|
* List is a comma-separated list of buffers, where exclusion is possible with
|
|
* char '!', and "*" means all buffers.
|
|
*
|
|
* Examples:
|
|
* "*"
|
|
* "*,!*#weechat*"
|
|
* "irc.freenode.*"
|
|
* "irc.freenode.*,irc.oftc.#channel"
|
|
* "irc.freenode.#weechat,irc.freenode.#other"
|
|
*/
|
|
|
|
int
|
|
gui_buffer_match_list (struct t_gui_buffer *buffer, const char *string)
|
|
{
|
|
char **buffers;
|
|
int num_buffers, match;
|
|
|
|
if (!string || !string[0])
|
|
return 0;
|
|
|
|
match = 0;
|
|
|
|
buffers = string_split (string, ",", 0, 0, &num_buffers);
|
|
if (buffers)
|
|
{
|
|
match = gui_buffer_match_list_split (buffer, num_buffers, buffers);
|
|
string_free_split (buffers);
|
|
}
|
|
|
|
return match;
|
|
}
|
|
|
|
/*
|
|
* Sets plugin pointer for buffers with a given name (used after /upgrade).
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set_plugin_for_upgrade (char *name, struct t_weechat_plugin *plugin)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if (ptr_buffer->plugin_name_for_upgrade
|
|
&& (strcmp (ptr_buffer->plugin_name_for_upgrade, name) == 0))
|
|
{
|
|
free (ptr_buffer->plugin_name_for_upgrade);
|
|
ptr_buffer->plugin_name_for_upgrade = NULL;
|
|
|
|
ptr_buffer->plugin = plugin;
|
|
|
|
gui_buffer_build_full_name (ptr_buffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check if a property is in the list of properties.
|
|
*
|
|
* Returns:
|
|
* 1: property is in list
|
|
* 0: property is not in list
|
|
*/
|
|
|
|
int
|
|
gui_buffer_property_in_list (char *properties[], char *property)
|
|
{
|
|
int i;
|
|
|
|
if (!properties || !property)
|
|
return 0;
|
|
|
|
for (i = 0; properties[i]; i++)
|
|
{
|
|
if (strcmp (properties[i], property) == 0)
|
|
return 1;
|
|
}
|
|
|
|
/* property not found in list */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Gets a buffer property as integer.
|
|
*/
|
|
|
|
int
|
|
gui_buffer_get_integer (struct t_gui_buffer *buffer, const char *property)
|
|
{
|
|
if (buffer && property)
|
|
{
|
|
if (string_strcasecmp (property, "number") == 0)
|
|
return buffer->number;
|
|
else if (string_strcasecmp (property, "layout_number") == 0)
|
|
return buffer->layout_number;
|
|
else if (string_strcasecmp (property, "layout_number_merge_order") == 0)
|
|
return buffer->layout_number_merge_order;
|
|
else if (string_strcasecmp (property, "short_name_is_set") == 0)
|
|
return (buffer->short_name) ? 1 : 0;
|
|
else if (string_strcasecmp (property, "type") == 0)
|
|
return buffer->type;
|
|
else if (string_strcasecmp (property, "notify") == 0)
|
|
return buffer->notify;
|
|
else if (string_strcasecmp (property, "num_displayed") == 0)
|
|
return buffer->num_displayed;
|
|
else if (string_strcasecmp (property, "active") == 0)
|
|
return buffer->active;
|
|
else if (string_strcasecmp (property, "print_hooks_enabled") == 0)
|
|
return buffer->print_hooks_enabled;
|
|
else if (string_strcasecmp (property, "lines_hidden") == 0)
|
|
return buffer->lines->lines_hidden;
|
|
else if (string_strcasecmp (property, "prefix_max_length") == 0)
|
|
return buffer->lines->prefix_max_length;
|
|
else if (string_strcasecmp (property, "time_for_each_line") == 0)
|
|
return buffer->time_for_each_line;
|
|
else if (string_strcasecmp (property, "nicklist") == 0)
|
|
return buffer->nicklist;
|
|
else if (string_strcasecmp (property, "nicklist_case_sensitive") == 0)
|
|
return buffer->nicklist_case_sensitive;
|
|
else if (string_strcasecmp (property, "nicklist_max_length") == 0)
|
|
return buffer->nicklist_max_length;
|
|
else if (string_strcasecmp (property, "nicklist_display_groups") == 0)
|
|
return buffer->nicklist_display_groups;
|
|
else if (string_strcasecmp (property, "nicklist_count") == 0)
|
|
return buffer->nicklist_count;
|
|
else if (string_strcasecmp (property, "nicklist_groups_count") == 0)
|
|
return buffer->nicklist_groups_count;
|
|
else if (string_strcasecmp (property, "nicklist_nicks_count") == 0)
|
|
return buffer->nicklist_nicks_count;
|
|
else if (string_strcasecmp (property, "nicklist_visible_count") == 0)
|
|
return buffer->nicklist_visible_count;
|
|
else if (string_strcasecmp (property, "input") == 0)
|
|
return buffer->input;
|
|
else if (string_strcasecmp (property, "input_get_unknown_commands") == 0)
|
|
return buffer->input_get_unknown_commands;
|
|
else if (string_strcasecmp (property, "input_size") == 0)
|
|
return buffer->input_buffer_size;
|
|
else if (string_strcasecmp (property, "input_length") == 0)
|
|
return buffer->input_buffer_length;
|
|
else if (string_strcasecmp (property, "input_pos") == 0)
|
|
return buffer->input_buffer_pos;
|
|
else if (string_strcasecmp (property, "input_1st_display") == 0)
|
|
return buffer->input_buffer_1st_display;
|
|
else if (string_strcasecmp (property, "num_history") == 0)
|
|
return buffer->num_history;
|
|
else if (string_strcasecmp (property, "text_search") == 0)
|
|
return buffer->text_search;
|
|
else if (string_strcasecmp (property, "text_search_exact") == 0)
|
|
return buffer->text_search_exact;
|
|
else if (string_strcasecmp (property, "text_search_regex") == 0)
|
|
return buffer->text_search_regex;
|
|
else if (string_strcasecmp (property, "text_search_where") == 0)
|
|
return buffer->text_search_where;
|
|
else if (string_strcasecmp (property, "text_search_found") == 0)
|
|
return buffer->text_search_found;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Gets a buffer property as string.
|
|
*/
|
|
|
|
const char *
|
|
gui_buffer_get_string (struct t_gui_buffer *buffer, const char *property)
|
|
{
|
|
const char *ptr_value;
|
|
|
|
if (buffer && property)
|
|
{
|
|
if (string_strcasecmp (property, "plugin") == 0)
|
|
return gui_buffer_get_plugin_name (buffer);
|
|
else if (string_strcasecmp (property, "name") == 0)
|
|
return buffer->name;
|
|
else if (string_strcasecmp (property, "full_name") == 0)
|
|
return buffer->full_name;
|
|
else if (string_strcasecmp (property, "short_name") == 0)
|
|
return gui_buffer_get_short_name (buffer);
|
|
else if (string_strcasecmp (property, "title") == 0)
|
|
return buffer->title;
|
|
else if (string_strcasecmp (property, "input") == 0)
|
|
return buffer->input_buffer;
|
|
else if (string_strcasecmp (property, "text_search_input") == 0)
|
|
return buffer->text_search_input;
|
|
else if (string_strcasecmp (property, "highlight_words") == 0)
|
|
return buffer->highlight_words;
|
|
else if (string_strcasecmp (property, "highlight_regex") == 0)
|
|
return buffer->highlight_regex;
|
|
else if (string_strcasecmp (property, "highlight_tags") == 0)
|
|
return buffer->highlight_tags;
|
|
else if (string_strcasecmp (property, "hotlist_max_level_nicks") == 0)
|
|
return hashtable_get_string (buffer->hotlist_max_level_nicks, "keys_values");
|
|
else if (string_strncasecmp (property, "localvar_", 9) == 0)
|
|
{
|
|
ptr_value = (const char *)hashtable_get (buffer->local_variables,
|
|
property + 9);
|
|
if (ptr_value)
|
|
return ptr_value;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Gets a buffer property as pointer.
|
|
*/
|
|
|
|
void *
|
|
gui_buffer_get_pointer (struct t_gui_buffer *buffer, const char *property)
|
|
{
|
|
if (buffer && property)
|
|
{
|
|
if (string_strcasecmp (property, "plugin") == 0)
|
|
return buffer->plugin;
|
|
else if (string_strcasecmp (property, "text_search_regex_compiled") == 0)
|
|
return buffer->text_search_regex_compiled;
|
|
else if (string_strcasecmp (property, "highlight_regex_compiled") == 0)
|
|
return buffer->highlight_regex_compiled;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Sets flag "chat_refresh_needed".
|
|
*/
|
|
|
|
void
|
|
gui_buffer_ask_chat_refresh (struct t_gui_buffer *buffer, int refresh)
|
|
{
|
|
if (refresh > buffer->chat_refresh_needed)
|
|
buffer->chat_refresh_needed = refresh;
|
|
}
|
|
|
|
/*
|
|
* Sets name for a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set_name (struct t_gui_buffer *buffer, const char *name)
|
|
{
|
|
if (name && name[0])
|
|
{
|
|
if (buffer->name)
|
|
free (buffer->name);
|
|
buffer->name = strdup (name);
|
|
gui_buffer_build_full_name (buffer);
|
|
|
|
gui_buffer_local_var_add (buffer, "name", name);
|
|
|
|
hook_signal_send ("buffer_renamed",
|
|
WEECHAT_HOOK_SIGNAL_POINTER, buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Sets short name for a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set_short_name (struct t_gui_buffer *buffer, const char *short_name)
|
|
{
|
|
if (buffer->short_name)
|
|
{
|
|
free (buffer->short_name);
|
|
buffer->short_name = NULL;
|
|
}
|
|
buffer->short_name = (short_name && short_name[0]) ?
|
|
strdup (short_name) : NULL;
|
|
|
|
if (buffer->mixed_lines)
|
|
buffer->mixed_lines->buffer_max_length_refresh = 1;
|
|
gui_buffer_ask_chat_refresh (buffer, 1);
|
|
|
|
hook_signal_send ("buffer_renamed",
|
|
WEECHAT_HOOK_SIGNAL_POINTER, buffer);
|
|
}
|
|
|
|
/*
|
|
* Sets buffer type.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set_type (struct t_gui_buffer *buffer, enum t_gui_buffer_type type)
|
|
{
|
|
if (buffer->type == type)
|
|
return;
|
|
|
|
gui_line_free_all (buffer);
|
|
|
|
buffer->type = type;
|
|
gui_buffer_ask_chat_refresh (buffer, 2);
|
|
|
|
hook_signal_send ("buffer_type_changed",
|
|
WEECHAT_HOOK_SIGNAL_POINTER, buffer);
|
|
}
|
|
|
|
/*
|
|
* Sets title for a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set_title (struct t_gui_buffer *buffer, const char *new_title)
|
|
{
|
|
if (buffer->title)
|
|
free (buffer->title);
|
|
buffer->title = (new_title && new_title[0]) ? strdup (new_title) : NULL;
|
|
|
|
hook_signal_send ("buffer_title_changed",
|
|
WEECHAT_HOOK_SIGNAL_POINTER, buffer);
|
|
}
|
|
|
|
/*
|
|
* Sets flag "time for each line" for a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set_time_for_each_line (struct t_gui_buffer *buffer,
|
|
int time_for_each_line)
|
|
{
|
|
buffer->time_for_each_line = (time_for_each_line) ? 1 : 0;
|
|
gui_buffer_ask_chat_refresh (buffer, 2);
|
|
}
|
|
|
|
/*
|
|
* Sets nicklist for a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set_nicklist (struct t_gui_buffer *buffer, int nicklist)
|
|
{
|
|
buffer->nicklist = (nicklist) ? 1 : 0;
|
|
gui_window_ask_refresh (1);
|
|
}
|
|
|
|
/*
|
|
* Sets case_sensitive flag for a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set_nicklist_case_sensitive (struct t_gui_buffer *buffer,
|
|
int case_sensitive)
|
|
{
|
|
buffer->nicklist_case_sensitive = (case_sensitive) ? 1 : 0;
|
|
}
|
|
|
|
/*
|
|
* Sets flag "display_groups" for a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set_nicklist_display_groups (struct t_gui_buffer *buffer,
|
|
int display_groups)
|
|
{
|
|
buffer->nicklist_display_groups = (display_groups) ? 1 : 0;
|
|
buffer->nicklist_visible_count = 0;
|
|
gui_nicklist_compute_visible_count (buffer, buffer->nicklist_root);
|
|
gui_window_ask_refresh (1);
|
|
}
|
|
|
|
/*
|
|
* Sets highlight words for a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set_highlight_words (struct t_gui_buffer *buffer,
|
|
const char *new_highlight_words)
|
|
{
|
|
if (buffer->highlight_words)
|
|
free (buffer->highlight_words);
|
|
buffer->highlight_words = (new_highlight_words && new_highlight_words[0]) ?
|
|
strdup (new_highlight_words) : NULL;
|
|
}
|
|
|
|
/*
|
|
* Sets highlight words for a buffer with a list.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set_highlight_words_list (struct t_gui_buffer *buffer,
|
|
struct t_weelist *list)
|
|
{
|
|
struct t_weelist_item *ptr_list_item;
|
|
int length;
|
|
const char *ptr_string;
|
|
char *words;
|
|
|
|
/* compute length */
|
|
length = 0;
|
|
for (ptr_list_item = weelist_get (list, 0); ptr_list_item;
|
|
ptr_list_item = weelist_next (ptr_list_item))
|
|
{
|
|
ptr_string = weelist_string (ptr_list_item);
|
|
if (ptr_string)
|
|
length += strlen (ptr_string) + 1;
|
|
}
|
|
length += 2; /* '\n' + '\0' */
|
|
|
|
/* allocate memory */
|
|
words = malloc (length);
|
|
if (!words)
|
|
return;
|
|
|
|
/* build string */
|
|
words[0] = '\0';
|
|
for (ptr_list_item = weelist_get (list, 0); ptr_list_item;
|
|
ptr_list_item = weelist_next (ptr_list_item))
|
|
{
|
|
ptr_string = weelist_string (ptr_list_item);
|
|
if (ptr_string)
|
|
{
|
|
strcat (words, ptr_string);
|
|
if (weelist_next (ptr_list_item))
|
|
strcat (words, ",");
|
|
}
|
|
}
|
|
|
|
gui_buffer_set_highlight_words (buffer, words);
|
|
|
|
free (words);
|
|
}
|
|
|
|
/*
|
|
* Adds highlight words for a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_add_highlight_words (struct t_gui_buffer *buffer,
|
|
const char *words_to_add)
|
|
{
|
|
char **current_words, **add_words;
|
|
int current_count, add_count, i;
|
|
struct t_weelist *list;
|
|
|
|
if (!words_to_add)
|
|
return;
|
|
|
|
list = weelist_new ();
|
|
if (!list)
|
|
return;
|
|
|
|
current_words = string_split (buffer->highlight_words, ",", 0, 0,
|
|
¤t_count);
|
|
add_words = string_split (words_to_add, ",", 0, 0,
|
|
&add_count);
|
|
|
|
for (i = 0; i < current_count; i++)
|
|
{
|
|
if (!weelist_search (list, current_words[i]))
|
|
weelist_add (list, current_words[i], WEECHAT_LIST_POS_END, NULL);
|
|
}
|
|
for (i = 0; i < add_count; i++)
|
|
{
|
|
if (!weelist_search (list, add_words[i]))
|
|
weelist_add (list, add_words[i], WEECHAT_LIST_POS_END, NULL);
|
|
}
|
|
|
|
gui_buffer_set_highlight_words_list (buffer, list);
|
|
|
|
weelist_free (list);
|
|
|
|
if (current_words)
|
|
string_free_split (current_words);
|
|
if (add_words)
|
|
string_free_split (add_words);
|
|
}
|
|
|
|
/*
|
|
* Removes highlight words in a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_remove_highlight_words (struct t_gui_buffer *buffer,
|
|
const char *words_to_remove)
|
|
{
|
|
char **current_words, **remove_words;
|
|
int current_count, remove_count, i, j, to_remove;
|
|
struct t_weelist *list;
|
|
|
|
if (!words_to_remove)
|
|
return;
|
|
|
|
list = weelist_new ();
|
|
if (!list)
|
|
return;
|
|
|
|
current_words = string_split (buffer->highlight_words, ",", 0, 0,
|
|
¤t_count);
|
|
remove_words = string_split (words_to_remove, ",", 0, 0,
|
|
&remove_count);
|
|
|
|
for (i = 0; i < current_count; i++)
|
|
{
|
|
/* search if word is to be removed or not */
|
|
to_remove = 0;
|
|
for (j = 0; j < remove_count; j++)
|
|
{
|
|
if (strcmp (current_words[i], remove_words[j]) == 0)
|
|
{
|
|
to_remove = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!to_remove)
|
|
weelist_add (list, current_words[i], WEECHAT_LIST_POS_END, NULL);
|
|
}
|
|
|
|
gui_buffer_set_highlight_words_list (buffer, list);
|
|
|
|
weelist_free (list);
|
|
|
|
if (current_words)
|
|
string_free_split (current_words);
|
|
if (remove_words)
|
|
string_free_split (remove_words);
|
|
}
|
|
|
|
/*
|
|
* Sets highlight regex for a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set_highlight_regex (struct t_gui_buffer *buffer,
|
|
const char *new_highlight_regex)
|
|
{
|
|
if (buffer->highlight_regex)
|
|
{
|
|
free (buffer->highlight_regex);
|
|
buffer->highlight_regex = NULL;
|
|
}
|
|
if (buffer->highlight_regex_compiled)
|
|
{
|
|
regfree (buffer->highlight_regex_compiled);
|
|
free (buffer->highlight_regex_compiled);
|
|
buffer->highlight_regex_compiled = NULL;
|
|
}
|
|
|
|
if (new_highlight_regex && new_highlight_regex[0])
|
|
{
|
|
buffer->highlight_regex = strdup (new_highlight_regex);
|
|
if (buffer->highlight_regex)
|
|
{
|
|
buffer->highlight_regex_compiled =
|
|
malloc (sizeof (*buffer->highlight_regex_compiled));
|
|
if (buffer->highlight_regex_compiled)
|
|
{
|
|
if (string_regcomp (buffer->highlight_regex_compiled,
|
|
buffer->highlight_regex,
|
|
REG_EXTENDED | REG_ICASE) != 0)
|
|
{
|
|
free (buffer->highlight_regex_compiled);
|
|
buffer->highlight_regex_compiled = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Sets highlight tags for a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set_highlight_tags (struct t_gui_buffer *buffer,
|
|
const char *new_highlight_tags)
|
|
{
|
|
if (buffer->highlight_tags)
|
|
{
|
|
free (buffer->highlight_tags);
|
|
buffer->highlight_tags = NULL;
|
|
}
|
|
if (buffer->highlight_tags_array)
|
|
{
|
|
string_free_split (buffer->highlight_tags_array);
|
|
buffer->highlight_tags_array = NULL;
|
|
}
|
|
buffer->highlight_tags_count = 0;
|
|
|
|
if (new_highlight_tags)
|
|
{
|
|
buffer->highlight_tags = strdup (new_highlight_tags);
|
|
if (buffer->highlight_tags)
|
|
{
|
|
buffer->highlight_tags_array = string_split (new_highlight_tags,
|
|
",", 0, 0,
|
|
&buffer->highlight_tags_count);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Sets hotlist_max_level_nicks for a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set_hotlist_max_level_nicks (struct t_gui_buffer *buffer,
|
|
const char *new_hotlist_max_level_nicks)
|
|
{
|
|
char **nicks, *pos, *error;
|
|
int nicks_count, value, i;
|
|
long number;
|
|
|
|
hashtable_remove_all (buffer->hotlist_max_level_nicks);
|
|
|
|
if (new_hotlist_max_level_nicks && new_hotlist_max_level_nicks[0])
|
|
{
|
|
nicks = string_split (new_hotlist_max_level_nicks, ",", 0, 0,
|
|
&nicks_count);
|
|
if (nicks)
|
|
{
|
|
for (i = 0; i < nicks_count; i++)
|
|
{
|
|
value = -1;
|
|
pos = strchr (nicks[i], ':');
|
|
if (pos)
|
|
{
|
|
pos[0] = '\0';
|
|
pos++;
|
|
error = NULL;
|
|
number = strtol (pos, &error, 10);
|
|
if (error && !error[0])
|
|
value = (int)number;
|
|
}
|
|
hashtable_set (buffer->hotlist_max_level_nicks, nicks[i],
|
|
&value);
|
|
}
|
|
string_free_split (nicks);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Adds nicks to hotlist_max_level_nicks for a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_add_hotlist_max_level_nicks (struct t_gui_buffer *buffer,
|
|
const char *nicks_to_add)
|
|
{
|
|
char **nicks, *pos, *error;
|
|
int nicks_count, value, i;
|
|
long number;
|
|
|
|
if (!nicks_to_add)
|
|
return;
|
|
|
|
nicks = string_split (nicks_to_add, ",", 0, 0, &nicks_count);
|
|
if (nicks)
|
|
{
|
|
for (i = 0; i < nicks_count; i++)
|
|
{
|
|
value = -1;
|
|
pos = strchr (nicks[i], ':');
|
|
if (pos)
|
|
{
|
|
pos[0] = '\0';
|
|
pos++;
|
|
error = NULL;
|
|
number = strtol (pos, &error, 10);
|
|
if (error && !error[0])
|
|
value = (int)number;
|
|
}
|
|
hashtable_set (buffer->hotlist_max_level_nicks, nicks[i],
|
|
&value);
|
|
}
|
|
string_free_split (nicks);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Removes nicks from hotlist_max_level_nicks in a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_remove_hotlist_max_level_nicks (struct t_gui_buffer *buffer,
|
|
const char *nicks_to_remove)
|
|
{
|
|
char **nicks, *pos;
|
|
int nicks_count, i;
|
|
|
|
if (!nicks_to_remove)
|
|
return;
|
|
|
|
nicks = string_split (nicks_to_remove, ",", 0, 0, &nicks_count);
|
|
if (nicks)
|
|
{
|
|
for (i = 0; i < nicks_count; i++)
|
|
{
|
|
pos = strchr (nicks[i], ':');
|
|
if (pos)
|
|
pos[0] = '\0';
|
|
hashtable_remove (buffer->hotlist_max_level_nicks, nicks[i]);
|
|
}
|
|
string_free_split (nicks);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Sets flag "input_get_unknown_commands" for a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set_input_get_unknown_commands (struct t_gui_buffer *buffer,
|
|
int input_get_unknown_commands)
|
|
{
|
|
buffer->input_get_unknown_commands = (input_get_unknown_commands) ? 1 : 0;
|
|
}
|
|
|
|
/*
|
|
* Sets unread marker for a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set_unread (struct t_gui_buffer *buffer)
|
|
{
|
|
int refresh;
|
|
|
|
if (buffer->type == GUI_BUFFER_TYPE_FORMATTED)
|
|
{
|
|
refresh = ((buffer->lines->last_read_line != NULL)
|
|
&& (buffer->lines->last_read_line != buffer->lines->last_line));
|
|
|
|
buffer->lines->last_read_line = buffer->lines->last_line;
|
|
buffer->lines->first_line_not_read = (buffer->lines->last_read_line) ? 0 : 1;
|
|
|
|
if (refresh)
|
|
gui_buffer_ask_chat_refresh (buffer, 2);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Sets a buffer property (string).
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set (struct t_gui_buffer *buffer, const char *property,
|
|
const char *value)
|
|
{
|
|
long number;
|
|
char *error;
|
|
|
|
if (!property || !value)
|
|
return;
|
|
|
|
/* properties that does NOT need a buffer */
|
|
if (string_strcasecmp (property, "hotlist") == 0)
|
|
{
|
|
if (strcmp (value, "-") == 0)
|
|
gui_add_hotlist = 0;
|
|
else if (strcmp (value, "+") == 0)
|
|
gui_add_hotlist = 1;
|
|
else
|
|
{
|
|
error = NULL;
|
|
number = strtol (value, &error, 10);
|
|
if (error && !error[0])
|
|
(void) gui_hotlist_add (buffer, number, NULL);
|
|
}
|
|
}
|
|
else if (string_strcasecmp (property, "completion_freeze") == 0)
|
|
{
|
|
gui_completion_freeze = (strcmp (value, "1") == 0) ? 1 : 0;
|
|
}
|
|
|
|
if (!buffer)
|
|
return;
|
|
|
|
/* properties that need a buffer */
|
|
if (string_strcasecmp (property, "unread") == 0)
|
|
{
|
|
gui_buffer_set_unread (buffer);
|
|
}
|
|
else if (string_strcasecmp (property, "display") == 0)
|
|
{
|
|
/*
|
|
* if it is auto-switch to a buffer, then we don't set read marker,
|
|
* otherwise we reset it (if current buffer is not displayed) after
|
|
* switch
|
|
*/
|
|
gui_window_switch_to_buffer (gui_current_window, buffer,
|
|
(string_strcasecmp (value, "auto") == 0) ?
|
|
0 : 1);
|
|
}
|
|
else if (string_strcasecmp (property, "print_hooks_enabled") == 0)
|
|
{
|
|
error = NULL;
|
|
number = strtol (value, &error, 10);
|
|
if (error && !error[0])
|
|
buffer->print_hooks_enabled = (number) ? 1 : 0;
|
|
}
|
|
else if (string_strcasecmp (property, "number") == 0)
|
|
{
|
|
error = NULL;
|
|
number = strtol (value, &error, 10);
|
|
if (error && !error[0] && (number >= 1))
|
|
gui_buffer_move_to_number (buffer, number);
|
|
}
|
|
else if (string_strcasecmp (property, "name") == 0)
|
|
{
|
|
gui_buffer_set_name (buffer, value);
|
|
}
|
|
else if (string_strcasecmp (property, "short_name") == 0)
|
|
{
|
|
gui_buffer_set_short_name (buffer, value);
|
|
}
|
|
else if (string_strcasecmp (property, "type") == 0)
|
|
{
|
|
if (string_strcasecmp (value, "formatted") == 0)
|
|
gui_buffer_set_type (buffer, GUI_BUFFER_TYPE_FORMATTED);
|
|
else if (string_strcasecmp (value, "free") == 0)
|
|
gui_buffer_set_type (buffer, GUI_BUFFER_TYPE_FREE);
|
|
}
|
|
else if (string_strcasecmp (property, "notify") == 0)
|
|
{
|
|
error = NULL;
|
|
number = strtol (value, &error, 10);
|
|
if (error && !error[0]
|
|
&& (number < GUI_BUFFER_NUM_NOTIFY))
|
|
{
|
|
if (number < 0)
|
|
buffer->notify = CONFIG_INTEGER(config_look_buffer_notify_default);
|
|
else
|
|
buffer->notify = number;
|
|
}
|
|
}
|
|
else if (string_strcasecmp (property, "title") == 0)
|
|
{
|
|
gui_buffer_set_title (buffer, value);
|
|
}
|
|
else if (string_strcasecmp (property, "time_for_each_line") == 0)
|
|
{
|
|
error = NULL;
|
|
number = strtol (value, &error, 10);
|
|
if (error && !error[0])
|
|
gui_buffer_set_time_for_each_line (buffer, number);
|
|
}
|
|
else if (string_strcasecmp (property, "nicklist") == 0)
|
|
{
|
|
error = NULL;
|
|
number = strtol (value, &error, 10);
|
|
if (error && !error[0])
|
|
gui_buffer_set_nicklist (buffer, number);
|
|
}
|
|
else if (string_strcasecmp (property, "nicklist_case_sensitive") == 0)
|
|
{
|
|
error = NULL;
|
|
number = strtol (value, &error, 10);
|
|
if (error && !error[0])
|
|
gui_buffer_set_nicklist_case_sensitive (buffer, number);
|
|
}
|
|
else if (string_strcasecmp (property, "nicklist_display_groups") == 0)
|
|
{
|
|
error = NULL;
|
|
number = strtol (value, &error, 10);
|
|
if (error && !error[0])
|
|
gui_buffer_set_nicklist_display_groups (buffer, number);
|
|
}
|
|
else if (string_strcasecmp (property, "highlight_words") == 0)
|
|
{
|
|
gui_buffer_set_highlight_words (buffer, value);
|
|
}
|
|
else if (string_strcasecmp (property, "highlight_words_add") == 0)
|
|
{
|
|
gui_buffer_add_highlight_words (buffer, value);
|
|
}
|
|
else if (string_strcasecmp (property, "highlight_words_del") == 0)
|
|
{
|
|
gui_buffer_remove_highlight_words (buffer, value);
|
|
}
|
|
else if (string_strcasecmp (property, "highlight_regex") == 0)
|
|
{
|
|
gui_buffer_set_highlight_regex (buffer, value);
|
|
}
|
|
else if (string_strcasecmp (property, "highlight_tags") == 0)
|
|
{
|
|
gui_buffer_set_highlight_tags (buffer, value);
|
|
}
|
|
else if (string_strcasecmp (property, "hotlist_max_level_nicks") == 0)
|
|
{
|
|
gui_buffer_set_hotlist_max_level_nicks (buffer, value);
|
|
}
|
|
else if (string_strcasecmp (property, "hotlist_max_level_nicks_add") == 0)
|
|
{
|
|
gui_buffer_add_hotlist_max_level_nicks (buffer, value);
|
|
}
|
|
else if (string_strcasecmp (property, "hotlist_max_level_nicks_del") == 0)
|
|
{
|
|
gui_buffer_remove_hotlist_max_level_nicks (buffer, value);
|
|
}
|
|
else if (string_strncasecmp (property, "key_bind_", 9) == 0)
|
|
{
|
|
gui_key_bind (buffer, 0, property + 9, value);
|
|
}
|
|
else if (string_strncasecmp (property, "key_unbind_", 11) == 0)
|
|
{
|
|
if (strcmp (property + 11, "*") == 0)
|
|
{
|
|
gui_key_free_all (&buffer->keys, &buffer->last_key,
|
|
&buffer->keys_count);
|
|
}
|
|
else
|
|
gui_key_unbind (buffer, 0, property + 11);
|
|
}
|
|
else if (string_strcasecmp (property, "input") == 0)
|
|
{
|
|
gui_buffer_undo_snap (buffer);
|
|
gui_input_replace_input (buffer, value);
|
|
gui_input_text_changed_modifier_and_signal (buffer,
|
|
1, /* save undo */
|
|
1); /* stop completion */
|
|
}
|
|
else if (string_strcasecmp (property, "input_pos") == 0)
|
|
{
|
|
error = NULL;
|
|
number = strtol (value, &error, 10);
|
|
if (error && !error[0])
|
|
gui_input_set_pos (buffer, number);
|
|
}
|
|
else if (string_strcasecmp (property, "input_get_unknown_commands") == 0)
|
|
{
|
|
error = NULL;
|
|
number = strtol (value, &error, 10);
|
|
if (error && !error[0])
|
|
gui_buffer_set_input_get_unknown_commands (buffer, number);
|
|
}
|
|
else if (string_strncasecmp (property, "localvar_set_", 13) == 0)
|
|
{
|
|
if (value)
|
|
gui_buffer_local_var_add (buffer, property + 13, value);
|
|
}
|
|
else if (string_strncasecmp (property, "localvar_del_", 13) == 0)
|
|
{
|
|
gui_buffer_local_var_remove (buffer, property + 13);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Sets a buffer property (pointer).
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set_pointer (struct t_gui_buffer *buffer, const char *property,
|
|
void *pointer)
|
|
{
|
|
if (!buffer || !property)
|
|
return;
|
|
|
|
if (string_strcasecmp (property, "close_callback") == 0)
|
|
{
|
|
buffer->close_callback = pointer;
|
|
}
|
|
else if (string_strcasecmp (property, "close_callback_data") == 0)
|
|
{
|
|
buffer->close_callback_data = pointer;
|
|
}
|
|
else if (string_strcasecmp (property, "nickcmp_callback") == 0)
|
|
{
|
|
buffer->nickcmp_callback = pointer;
|
|
}
|
|
else if (string_strcasecmp (property, "nickcmp_callback_data") == 0)
|
|
{
|
|
buffer->nickcmp_callback_data = pointer;
|
|
}
|
|
else if (string_strcasecmp (property, "input_callback") == 0)
|
|
{
|
|
buffer->input_callback = pointer;
|
|
}
|
|
else if (string_strcasecmp (property, "input_callback_data") == 0)
|
|
{
|
|
buffer->input_callback_data = pointer;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Computes "num_displayed" for all buffers.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_compute_num_displayed ()
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
struct t_gui_window *ptr_window;
|
|
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
ptr_buffer->num_displayed = 0;
|
|
}
|
|
|
|
for (ptr_window = gui_windows; ptr_window;
|
|
ptr_window = ptr_window->next_window)
|
|
{
|
|
if (ptr_window->buffer)
|
|
ptr_window->buffer->num_displayed++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Adds value to "num_displayed" variable for a buffer (value can be negative).
|
|
*/
|
|
|
|
void
|
|
gui_buffer_add_value_num_displayed (struct t_gui_buffer *buffer, int value)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if (ptr_buffer->number == buffer->number)
|
|
{
|
|
ptr_buffer->num_displayed += value;
|
|
if (ptr_buffer->num_displayed < 0)
|
|
ptr_buffer->num_displayed = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Checks if a buffer is the WeeChat core buffer.
|
|
*
|
|
* Returns:
|
|
* 1: buffer is WeeChat core buffer
|
|
* 0: buffer is another buffer
|
|
*/
|
|
|
|
int
|
|
gui_buffer_is_main (const char *plugin_name, const char *name)
|
|
{
|
|
/* if plugin is set and is not "core", then it's NOT main buffer */
|
|
if (plugin_name && (strcmp (plugin_name, plugin_get_name (NULL)) != 0))
|
|
return 0;
|
|
|
|
/* if name is set and is not "weechat", then it's NOT main buffer */
|
|
if (name && (strcmp (name, GUI_BUFFER_MAIN) != 0))
|
|
return 0;
|
|
|
|
/* it's main buffer */
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Gets main buffer (weechat one, created at startup).
|
|
*/
|
|
|
|
struct t_gui_buffer *
|
|
gui_buffer_search_main ()
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if ((!ptr_buffer->plugin)
|
|
&& (ptr_buffer->name)
|
|
&& (strcmp (ptr_buffer->name, GUI_BUFFER_MAIN) == 0))
|
|
return ptr_buffer;
|
|
}
|
|
|
|
/* buffer not found (should never occur!) */
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Searches for a buffer by plugin and name.
|
|
*/
|
|
|
|
struct t_gui_buffer *
|
|
gui_buffer_search_by_name (const char *plugin, const char *name)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
int plugin_match;
|
|
|
|
if (!name || !name[0])
|
|
return gui_current_window->buffer;
|
|
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if (ptr_buffer->name)
|
|
{
|
|
plugin_match = 1;
|
|
if (plugin && plugin[0])
|
|
{
|
|
if (strcmp (plugin, gui_buffer_get_plugin_name (ptr_buffer)) != 0)
|
|
plugin_match = 0;
|
|
}
|
|
if (plugin_match && (strcmp (ptr_buffer->name, name) == 0))
|
|
{
|
|
return ptr_buffer;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* buffer not found */
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Searches for a buffer by full name (example: "irc.freenode.#weechat").
|
|
*/
|
|
|
|
struct t_gui_buffer *
|
|
gui_buffer_search_by_full_name (const char *full_name)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if (ptr_buffer->full_name
|
|
&& (strcmp (ptr_buffer->full_name, full_name) == 0))
|
|
{
|
|
return ptr_buffer;
|
|
}
|
|
}
|
|
|
|
/* buffer not found */
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Searches for a buffer by plugin and partial name.
|
|
*/
|
|
|
|
struct t_gui_buffer *
|
|
gui_buffer_search_by_partial_name (const char *plugin, const char *name)
|
|
{
|
|
struct t_gui_buffer *ptr_start_buffer, *ptr_buffer, *buffer_partial_match[3];
|
|
int plugin_match, length_name;
|
|
const char *pos;
|
|
|
|
if (!name || !name[0])
|
|
return gui_current_window->buffer;
|
|
|
|
/* 0: matches beginning of buffer name, 1: in the middle, 2: the end */
|
|
buffer_partial_match[0] = NULL;
|
|
buffer_partial_match[1] = NULL;
|
|
buffer_partial_match[2] = NULL;
|
|
|
|
length_name = strlen (name);
|
|
|
|
ptr_buffer = gui_current_window->buffer->next_buffer;
|
|
if (!ptr_buffer)
|
|
ptr_buffer = gui_buffers;
|
|
ptr_start_buffer = ptr_buffer;
|
|
|
|
while (ptr_buffer)
|
|
{
|
|
if (ptr_buffer->name)
|
|
{
|
|
plugin_match = 1;
|
|
if (plugin && plugin[0])
|
|
{
|
|
if (strcmp (plugin, gui_buffer_get_plugin_name (ptr_buffer)) != 0)
|
|
plugin_match = 0;
|
|
}
|
|
if (plugin_match)
|
|
{
|
|
pos = strstr (ptr_buffer->name, name);
|
|
if (pos)
|
|
{
|
|
if (pos == ptr_buffer->name)
|
|
{
|
|
if (!pos[length_name])
|
|
{
|
|
/* matches full name, return it immediately */
|
|
return ptr_buffer;
|
|
}
|
|
/* matches beginning of name */
|
|
if (!buffer_partial_match[0])
|
|
buffer_partial_match[0] = ptr_buffer;
|
|
}
|
|
else
|
|
{
|
|
if (pos[length_name])
|
|
{
|
|
/* matches middle of buffer name */
|
|
if (!buffer_partial_match[1])
|
|
buffer_partial_match[1] = ptr_buffer;
|
|
}
|
|
else
|
|
{
|
|
/* matches end of buffer name */
|
|
if (!buffer_partial_match[2])
|
|
buffer_partial_match[2] = ptr_buffer;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ptr_buffer = ptr_buffer->next_buffer;
|
|
if (!ptr_buffer)
|
|
ptr_buffer = gui_buffers;
|
|
if (ptr_buffer == ptr_start_buffer)
|
|
break;
|
|
}
|
|
|
|
/* matches end of name? */
|
|
if (buffer_partial_match[2])
|
|
return buffer_partial_match[2];
|
|
|
|
/* matches beginning of name? */
|
|
if (buffer_partial_match[0])
|
|
return buffer_partial_match[0];
|
|
|
|
/*
|
|
* return buffer partially matching in name
|
|
* (may be NULL if no buffer was found)
|
|
*/
|
|
return buffer_partial_match[1];
|
|
}
|
|
|
|
/*
|
|
* Searches for a buffer by number.
|
|
*/
|
|
|
|
struct t_gui_buffer *
|
|
gui_buffer_search_by_number (int number)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if (ptr_buffer->number == number)
|
|
return ptr_buffer;
|
|
}
|
|
|
|
/* buffer not found */
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Searches for a buffer by layout number.
|
|
*/
|
|
|
|
struct t_gui_buffer *
|
|
gui_buffer_search_by_layout_number (int layout_number,
|
|
int layout_number_merge_order)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if ((ptr_buffer->layout_number == layout_number)
|
|
&& (ptr_buffer->layout_number_merge_order == layout_number_merge_order))
|
|
{
|
|
return ptr_buffer;
|
|
}
|
|
}
|
|
|
|
/* buffer not found */
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Returns number of merged buffers (buffers with same number).
|
|
*/
|
|
|
|
int
|
|
gui_buffer_count_merged_buffers (int number)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
int count;
|
|
|
|
count = 0;
|
|
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if (ptr_buffer->number == number)
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
/*
|
|
* Checks if a buffer is scrolled.
|
|
*
|
|
* Returns:
|
|
* 1: all windows displaying buffer are scrolled (user doesn't see end of
|
|
* buffer)
|
|
* 0: at least one window displaying buffer is NOT scrolled
|
|
*/
|
|
|
|
int
|
|
gui_buffer_is_scrolled (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *ptr_win;
|
|
int buffer_found;
|
|
|
|
if (!buffer)
|
|
return 0;
|
|
|
|
buffer_found = 0;
|
|
for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
|
|
{
|
|
if (ptr_win->buffer == buffer)
|
|
{
|
|
buffer_found = 1;
|
|
/* buffer found and not scrolled, exit immediately */
|
|
if (!ptr_win->scroll->scrolling)
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* buffer found, and all windows were scrolled */
|
|
if (buffer_found)
|
|
return 1;
|
|
|
|
/* buffer not found */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Clears content of buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_clear (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *ptr_win;
|
|
|
|
if (!buffer)
|
|
return;
|
|
|
|
/* remove all lines */
|
|
gui_line_free_all (buffer);
|
|
|
|
/* remove any scroll for buffer */
|
|
for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
|
|
{
|
|
if (ptr_win->buffer == buffer)
|
|
{
|
|
ptr_win->scroll->first_line_displayed = 1;
|
|
ptr_win->scroll->start_line = NULL;
|
|
ptr_win->scroll->start_line_pos = 0;
|
|
}
|
|
}
|
|
|
|
gui_hotlist_remove_buffer (buffer);
|
|
|
|
gui_buffer_ask_chat_refresh (buffer, 2);
|
|
}
|
|
|
|
/*
|
|
* Clears content of all buffers.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_clear_all ()
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if (ptr_buffer->type == GUI_BUFFER_TYPE_FORMATTED)
|
|
gui_buffer_clear (ptr_buffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Closes a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_close (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_window *ptr_window;
|
|
struct t_gui_buffer *ptr_buffer, *ptr_back_to_buffer;
|
|
struct t_gui_buffer *ptr_buffer_visited_buffer;
|
|
int index;
|
|
struct t_gui_buffer_visited *ptr_buffer_visited;
|
|
|
|
hook_signal_send ("buffer_closing",
|
|
WEECHAT_HOOK_SIGNAL_POINTER, buffer);
|
|
|
|
if (buffer->close_callback)
|
|
{
|
|
(void)(buffer->close_callback) (buffer->close_callback_data, buffer);
|
|
}
|
|
|
|
ptr_back_to_buffer = NULL;
|
|
|
|
/* first unmerge buffer if it is merged to at least one other 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);
|
|
}
|
|
|
|
if (!weechat_quit)
|
|
{
|
|
/*
|
|
* find other buffer to display: previously visited buffer if current
|
|
* window is displaying buffer, or buffer # - 1
|
|
*/
|
|
ptr_buffer_visited_buffer = NULL;
|
|
if (CONFIG_BOOLEAN(config_look_jump_previous_buffer_when_closing)
|
|
&& gui_current_window && (gui_current_window->buffer == buffer))
|
|
{
|
|
index = gui_buffer_visited_get_index_previous ();
|
|
if (index >= 0)
|
|
{
|
|
ptr_buffer_visited = gui_buffer_visited_search_by_number (index);
|
|
if (ptr_buffer_visited
|
|
&& (ptr_buffer_visited->buffer != buffer))
|
|
{
|
|
ptr_buffer_visited_buffer = ptr_buffer_visited->buffer;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* switch to another buffer in each window that displays buffer */
|
|
for (ptr_window = gui_windows; ptr_window;
|
|
ptr_window = ptr_window->next_window)
|
|
{
|
|
if ((buffer == ptr_window->buffer) &&
|
|
((buffer->next_buffer) || (buffer->prev_buffer)))
|
|
{
|
|
/* switch to previous buffer */
|
|
if (gui_buffers != last_gui_buffer)
|
|
{
|
|
if (ptr_back_to_buffer)
|
|
{
|
|
gui_window_switch_to_buffer (ptr_window,
|
|
ptr_back_to_buffer,
|
|
1);
|
|
}
|
|
else if (ptr_buffer_visited_buffer)
|
|
{
|
|
gui_window_switch_to_buffer (ptr_window,
|
|
ptr_buffer_visited_buffer,
|
|
1);
|
|
}
|
|
else if (ptr_window->buffer->prev_buffer)
|
|
{
|
|
gui_window_switch_to_buffer (ptr_window,
|
|
ptr_window->buffer->prev_buffer,
|
|
1);
|
|
}
|
|
else
|
|
{
|
|
gui_window_switch_to_buffer (ptr_window,
|
|
last_gui_buffer,
|
|
1);
|
|
}
|
|
}
|
|
gui_window_scroll_remove_buffer (ptr_window, buffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
gui_hotlist_remove_buffer (buffer);
|
|
if (gui_hotlist_initial_buffer == buffer)
|
|
gui_hotlist_initial_buffer = NULL;
|
|
|
|
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)
|
|
{
|
|
ptr_buffer->number--;
|
|
}
|
|
|
|
/* free all lines */
|
|
gui_line_free_all (buffer);
|
|
if (buffer->own_lines)
|
|
free (buffer->own_lines);
|
|
if (buffer->mixed_lines)
|
|
free (buffer->mixed_lines);
|
|
|
|
/* free some data */
|
|
gui_buffer_undo_free_all (buffer);
|
|
gui_history_buffer_free (buffer);
|
|
if (buffer->completion)
|
|
gui_completion_free (buffer->completion);
|
|
gui_nicklist_remove_all (buffer);
|
|
gui_nicklist_remove_group (buffer, buffer->nicklist_root);
|
|
if (buffer->hotlist_max_level_nicks)
|
|
hashtable_free (buffer->hotlist_max_level_nicks);
|
|
gui_key_free_all (&buffer->keys, &buffer->last_key,
|
|
&buffer->keys_count);
|
|
gui_buffer_local_var_remove_all (buffer);
|
|
hashtable_free (buffer->local_variables);
|
|
if (buffer->plugin_name_for_upgrade)
|
|
free (buffer->plugin_name_for_upgrade);
|
|
if (buffer->name)
|
|
free (buffer->name);
|
|
if (buffer->full_name)
|
|
free (buffer->full_name);
|
|
if (buffer->short_name)
|
|
free (buffer->short_name);
|
|
if (buffer->title)
|
|
free (buffer->title);
|
|
if (buffer->input_buffer)
|
|
free (buffer->input_buffer);
|
|
if (buffer->input_undo_snap)
|
|
free (buffer->input_undo_snap);
|
|
if (buffer->text_search_input)
|
|
free (buffer->text_search_input);
|
|
if (buffer->text_search_regex_compiled)
|
|
{
|
|
regfree (buffer->text_search_regex_compiled);
|
|
free (buffer->text_search_regex_compiled);
|
|
}
|
|
if (buffer->highlight_words)
|
|
free (buffer->highlight_words);
|
|
if (buffer->highlight_regex)
|
|
free (buffer->highlight_regex);
|
|
if (buffer->highlight_regex_compiled)
|
|
{
|
|
regfree (buffer->highlight_regex_compiled);
|
|
free (buffer->highlight_regex_compiled);
|
|
}
|
|
if (buffer->highlight_tags)
|
|
free (buffer->highlight_tags);
|
|
if (buffer->highlight_tags_array)
|
|
string_free_split (buffer->highlight_tags_array);
|
|
|
|
/* remove buffer from buffers list */
|
|
if (buffer->prev_buffer)
|
|
(buffer->prev_buffer)->next_buffer = buffer->next_buffer;
|
|
if (buffer->next_buffer)
|
|
(buffer->next_buffer)->prev_buffer = buffer->prev_buffer;
|
|
if (gui_buffers == buffer)
|
|
gui_buffers = buffer->next_buffer;
|
|
if (last_gui_buffer == buffer)
|
|
last_gui_buffer = buffer->prev_buffer;
|
|
|
|
for (ptr_window = gui_windows; ptr_window;
|
|
ptr_window = ptr_window->next_window)
|
|
{
|
|
if (ptr_window->buffer == buffer)
|
|
ptr_window->buffer = gui_buffers;
|
|
}
|
|
|
|
if (gui_buffer_last_displayed == buffer)
|
|
gui_buffer_last_displayed = NULL;
|
|
|
|
hook_signal_send ("buffer_closed",
|
|
WEECHAT_HOOK_SIGNAL_POINTER, buffer);
|
|
|
|
free (buffer);
|
|
}
|
|
|
|
/*
|
|
* Switches to another buffer with number.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_switch_by_number (struct t_gui_window *window, int number)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
|
|
/* invalid buffer */
|
|
if ((number < 0) || (number == window->buffer->number))
|
|
return;
|
|
|
|
/* search for buffer in the list */
|
|
for (ptr_buffer = gui_buffers; ptr_buffer; ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if ((ptr_buffer != window->buffer) && (number == ptr_buffer->number)
|
|
&& ptr_buffer->active)
|
|
{
|
|
gui_window_switch_to_buffer (window, ptr_buffer, 1);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Sets active buffer (when many buffers are merged).
|
|
*/
|
|
|
|
void
|
|
gui_buffer_set_active_buffer (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
int active;
|
|
|
|
active = 1;
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if ((ptr_buffer->number == buffer->number) && (ptr_buffer->active))
|
|
{
|
|
active = ptr_buffer->active;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if (ptr_buffer->number == buffer->number)
|
|
{
|
|
if (ptr_buffer == buffer)
|
|
{
|
|
if (active == 2)
|
|
ptr_buffer->lines = ptr_buffer->own_lines;
|
|
ptr_buffer->active = active;
|
|
}
|
|
else
|
|
{
|
|
if (ptr_buffer->active == 2)
|
|
ptr_buffer->lines = ptr_buffer->mixed_lines;
|
|
ptr_buffer->active = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Gets next active buffer (when many buffers are merged).
|
|
*/
|
|
|
|
struct t_gui_buffer *
|
|
gui_buffer_get_next_active_buffer (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
|
|
if (buffer->next_buffer
|
|
&& (buffer->next_buffer->number == buffer->number))
|
|
return buffer->next_buffer;
|
|
else
|
|
{
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if ((ptr_buffer != buffer)
|
|
&& (ptr_buffer->number == buffer->number))
|
|
{
|
|
return ptr_buffer;
|
|
}
|
|
}
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
/*
|
|
* Gets previous active buffer (when many buffers are merged).
|
|
*/
|
|
|
|
struct t_gui_buffer *
|
|
gui_buffer_get_previous_active_buffer (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
|
|
if (buffer->prev_buffer
|
|
&& (buffer->prev_buffer->number == buffer->number))
|
|
return buffer->prev_buffer;
|
|
else
|
|
{
|
|
for (ptr_buffer = last_gui_buffer; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->prev_buffer)
|
|
{
|
|
if ((ptr_buffer != buffer)
|
|
&& (ptr_buffer->number == buffer->number))
|
|
{
|
|
return ptr_buffer;
|
|
}
|
|
}
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
/*
|
|
* Moves a buffer to another number.
|
|
*/
|
|
|
|
void
|
|
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;
|
|
|
|
/* if only one buffer then return */
|
|
if (gui_buffers == last_gui_buffer)
|
|
return;
|
|
|
|
if (number < 1)
|
|
number = 1;
|
|
|
|
/* 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 */
|
|
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))
|
|
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;
|
|
|
|
/* 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--;
|
|
}
|
|
|
|
if (number == 1)
|
|
{
|
|
for (ptr_buffer = ptr_first_buffer; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
ptr_buffer->number = 1;
|
|
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;
|
|
}
|
|
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)
|
|
{
|
|
if (ptr_buffer_pos->number >= number)
|
|
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;
|
|
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++;
|
|
}
|
|
|
|
hook_signal_send ("buffer_moved",
|
|
WEECHAT_HOOK_SIGNAL_POINTER, buffer);
|
|
}
|
|
|
|
/*
|
|
* Swaps two buffers.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_swap (struct t_gui_buffer *buffer1, struct t_gui_buffer *buffer2)
|
|
{
|
|
struct t_gui_buffer *ptr_buffer1, *ptr_buffer2;
|
|
int number1, number2;
|
|
|
|
if (!buffer1 || !buffer2)
|
|
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;
|
|
|
|
/* swap buffer with itself? nothing to do! */
|
|
if (number1 == number2)
|
|
return;
|
|
|
|
/* move number2 before number1 */
|
|
gui_buffer_move_to_number (ptr_buffer2, number1);
|
|
|
|
/* move number1 before number2 */
|
|
if (number2 > number1 + 1)
|
|
gui_buffer_move_to_number (ptr_buffer1, number2);
|
|
}
|
|
|
|
/*
|
|
* Merges a buffer to 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;
|
|
|
|
/* if only one buffer then return */
|
|
if (gui_buffers == last_gui_buffer)
|
|
return;
|
|
|
|
if ((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" */
|
|
if ((buffer->type != GUI_BUFFER_TYPE_FORMATTED)
|
|
|| (target_buffer->type != GUI_BUFFER_TYPE_FORMATTED))
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("%sError: it is only possible to merge buffers "
|
|
"with formatted content"),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR]);
|
|
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);
|
|
|
|
/* change number */
|
|
buffer->number--;
|
|
|
|
/* mix lines */
|
|
gui_line_mix_buffers (buffer);
|
|
|
|
/* set buffer as active in merged buffers group */
|
|
gui_buffer_set_active_buffer (buffer);
|
|
|
|
/* compute "number - 1" for next buffers */
|
|
for (ptr_buffer = buffer->next_buffer; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
ptr_buffer->number--;
|
|
}
|
|
|
|
gui_buffer_compute_num_displayed ();
|
|
|
|
gui_window_ask_refresh (1);
|
|
|
|
hook_signal_send ("buffer_merged",
|
|
WEECHAT_HOOK_SIGNAL_POINTER, buffer);
|
|
}
|
|
|
|
/*
|
|
* Unmerges a buffer from group of merged buffers.
|
|
*
|
|
* If number >= 1, then moves buffer to this number, otherwise moves buffer to
|
|
* buffer->number + 1.
|
|
*/
|
|
|
|
void
|
|
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 */
|
|
if (gui_buffers == last_gui_buffer)
|
|
return;
|
|
|
|
ptr_new_active_buffer = NULL;
|
|
|
|
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;
|
|
|
|
/* by default, we move buffer to buffer->number + 1 */
|
|
if ((number < 1) || (number == buffer->number))
|
|
{
|
|
number = buffer->number + 1;
|
|
}
|
|
else
|
|
{
|
|
if (number > last_gui_buffer->number + 1)
|
|
number = last_gui_buffer->number + 1;
|
|
}
|
|
|
|
if (num_merged == 2)
|
|
{
|
|
/* only one buffer will remain, so it will not be merged any more */
|
|
gui_line_mixed_free_all (buffer);
|
|
gui_lines_free (buffer->mixed_lines);
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if (ptr_buffer->number == buffer->number)
|
|
{
|
|
ptr_buffer->active = 1;
|
|
ptr_buffer->mixed_lines = NULL;
|
|
ptr_buffer->lines = ptr_buffer->own_lines;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* remove this buffer from mixed_lines, but keep other buffers merged */
|
|
ptr_new_active_buffer = gui_buffer_get_next_active_buffer (buffer);
|
|
if (ptr_new_active_buffer)
|
|
gui_buffer_set_active_buffer (ptr_new_active_buffer);
|
|
gui_line_mixed_free_buffer (buffer);
|
|
buffer->mixed_lines = NULL;
|
|
buffer->lines = buffer->own_lines;
|
|
}
|
|
|
|
/* remove buffer from list */
|
|
if (buffer->prev_buffer)
|
|
(buffer->prev_buffer)->next_buffer = buffer->next_buffer;
|
|
if (buffer->next_buffer)
|
|
(buffer->next_buffer)->prev_buffer = buffer->prev_buffer;
|
|
if (gui_buffers == buffer)
|
|
gui_buffers = buffer->next_buffer;
|
|
if (last_gui_buffer == buffer)
|
|
last_gui_buffer = buffer->prev_buffer;
|
|
|
|
/* move buffer */
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
if (ptr_buffer->number >= number)
|
|
break;
|
|
}
|
|
if (ptr_buffer)
|
|
{
|
|
/* insert buffer into the list (before buffer found) */
|
|
buffer->prev_buffer = ptr_buffer->prev_buffer;
|
|
buffer->next_buffer = ptr_buffer;
|
|
if (ptr_buffer->prev_buffer)
|
|
(ptr_buffer->prev_buffer)->next_buffer = buffer;
|
|
else
|
|
gui_buffers = buffer;
|
|
ptr_buffer->prev_buffer = buffer;
|
|
}
|
|
else
|
|
{
|
|
/* add buffer to the end */
|
|
buffer->prev_buffer = last_gui_buffer;
|
|
buffer->next_buffer = NULL;
|
|
last_gui_buffer->next_buffer = buffer;
|
|
last_gui_buffer = buffer;
|
|
}
|
|
buffer->active = 1;
|
|
buffer->number = number;
|
|
for (ptr_buffer = buffer->next_buffer; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
ptr_buffer->number++;
|
|
}
|
|
|
|
gui_buffer_compute_num_displayed ();
|
|
|
|
if (ptr_new_active_buffer)
|
|
{
|
|
ptr_new_active_buffer->mixed_lines->prefix_max_length_refresh = 1;
|
|
ptr_new_active_buffer->mixed_lines->buffer_max_length_refresh = 1;
|
|
}
|
|
|
|
gui_window_ask_refresh (1);
|
|
|
|
hook_signal_send ("buffer_unmerged",
|
|
WEECHAT_HOOK_SIGNAL_POINTER, buffer);
|
|
}
|
|
|
|
/*
|
|
* Unmerges all merged buffers.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_unmerge_all ()
|
|
{
|
|
int number;
|
|
struct t_gui_buffer *ptr_buffer;
|
|
|
|
number = 1;
|
|
while (number <= last_gui_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;
|
|
}
|
|
number++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Sorts buffers by layout number.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_sort_by_layout_number ()
|
|
{
|
|
struct t_gui_buffer *ptr_buffer, *ptr_next_buffer;
|
|
|
|
ptr_buffer = gui_buffers;
|
|
|
|
gui_buffers = NULL;
|
|
last_gui_buffer = NULL;
|
|
|
|
while (ptr_buffer)
|
|
{
|
|
ptr_next_buffer = ptr_buffer->next_buffer;
|
|
gui_buffer_insert (ptr_buffer, 0);
|
|
ptr_buffer = ptr_next_buffer;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Makes a "snapshot" of buffer input (save content and position).
|
|
*/
|
|
|
|
void
|
|
gui_buffer_undo_snap (struct t_gui_buffer *buffer)
|
|
{
|
|
if ((buffer->input_undo_snap)->data)
|
|
{
|
|
free ((buffer->input_undo_snap)->data);
|
|
(buffer->input_undo_snap)->data = NULL;
|
|
}
|
|
(buffer->input_undo_snap)->pos = 0;
|
|
|
|
if (CONFIG_INTEGER(config_look_input_undo_max) > 0)
|
|
{
|
|
(buffer->input_undo_snap)->data = (buffer->input_buffer) ?
|
|
strdup (buffer->input_buffer) : NULL;
|
|
(buffer->input_undo_snap)->pos = buffer->input_buffer_pos;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Frees "snapshot" of buffer input.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_undo_snap_free (struct t_gui_buffer *buffer)
|
|
{
|
|
if ((buffer->input_undo_snap)->data)
|
|
{
|
|
free ((buffer->input_undo_snap)->data);
|
|
(buffer->input_undo_snap)->data = NULL;
|
|
}
|
|
(buffer->input_undo_snap)->pos = 0;
|
|
}
|
|
|
|
/*
|
|
* Adds undo in list, with current input buffer + position.
|
|
*
|
|
* If before_undo is not NULL, then adds undo before this undo, otherwise adds
|
|
* to the end of list.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_undo_add (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_input_undo *new_undo;
|
|
|
|
/* undo disabled by configuration */
|
|
if (CONFIG_INTEGER(config_look_input_undo_max) == 0)
|
|
goto end;
|
|
|
|
/*
|
|
* if nothing has changed since snapshot of input buffer, then do nothing
|
|
* (just discard snapshot)
|
|
*/
|
|
if ((buffer->input_undo_snap)->data
|
|
&& (strcmp (buffer->input_buffer, (buffer->input_undo_snap)->data) == 0))
|
|
{
|
|
goto end;
|
|
}
|
|
|
|
/* max number of undo reached? */
|
|
if ((buffer->input_undo_count > 0)
|
|
&& (buffer->input_undo_count >= CONFIG_INTEGER(config_look_input_undo_max) + 1))
|
|
{
|
|
/* remove older undo in buffer (first in list) */
|
|
gui_buffer_undo_free (buffer, buffer->input_undo);
|
|
}
|
|
|
|
/* remove all undos after current undo */
|
|
if (buffer->ptr_input_undo)
|
|
{
|
|
while (buffer->ptr_input_undo->next_undo)
|
|
{
|
|
gui_buffer_undo_free (buffer, buffer->ptr_input_undo->next_undo);
|
|
}
|
|
}
|
|
|
|
/* if input is the same as current undo, then do not add it */
|
|
if (buffer->ptr_input_undo
|
|
&& (buffer->ptr_input_undo)->data
|
|
&& (buffer->input_undo_snap)->data
|
|
&& (strcmp ((buffer->input_undo_snap)->data, (buffer->ptr_input_undo)->data) == 0))
|
|
{
|
|
goto end;
|
|
}
|
|
|
|
new_undo = (struct t_gui_input_undo *)malloc (sizeof (*new_undo));
|
|
if (!new_undo)
|
|
goto end;
|
|
|
|
if ((buffer->input_undo_snap)->data)
|
|
{
|
|
new_undo->data = strdup ((buffer->input_undo_snap)->data);
|
|
new_undo->pos = (buffer->input_undo_snap)->pos;
|
|
}
|
|
else
|
|
{
|
|
new_undo->data = (buffer->input_buffer) ?
|
|
strdup (buffer->input_buffer) : NULL;
|
|
new_undo->pos = buffer->input_buffer_pos;
|
|
}
|
|
|
|
/* add undo to the list */
|
|
new_undo->prev_undo = buffer->last_input_undo;
|
|
new_undo->next_undo = NULL;
|
|
if (buffer->input_undo)
|
|
(buffer->last_input_undo)->next_undo = new_undo;
|
|
else
|
|
buffer->input_undo = new_undo;
|
|
buffer->last_input_undo = new_undo;
|
|
|
|
buffer->ptr_input_undo = new_undo;
|
|
buffer->input_undo_count++;
|
|
|
|
end:
|
|
gui_buffer_undo_snap_free (buffer);
|
|
}
|
|
|
|
/*
|
|
* Frees undo and removes it from list.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_undo_free (struct t_gui_buffer *buffer,
|
|
struct t_gui_input_undo *undo)
|
|
{
|
|
/* update current undo if needed */
|
|
if (buffer->ptr_input_undo == undo)
|
|
{
|
|
if ((buffer->ptr_input_undo)->next_undo)
|
|
buffer->ptr_input_undo = (buffer->ptr_input_undo)->next_undo;
|
|
else
|
|
buffer->ptr_input_undo = (buffer->ptr_input_undo)->prev_undo;
|
|
}
|
|
|
|
/* free data */
|
|
if (undo->data)
|
|
free (undo->data);
|
|
|
|
/* remove undo from list */
|
|
if (undo->prev_undo)
|
|
(undo->prev_undo)->next_undo = undo->next_undo;
|
|
if (undo->next_undo)
|
|
(undo->next_undo)->prev_undo = undo->prev_undo;
|
|
if (buffer->input_undo == undo)
|
|
buffer->input_undo = undo->next_undo;
|
|
if (buffer->last_input_undo == undo)
|
|
buffer->last_input_undo = undo->prev_undo;
|
|
|
|
free (undo);
|
|
|
|
buffer->input_undo_count--;
|
|
}
|
|
|
|
/*
|
|
* Frees all undos of a buffer.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_undo_free_all (struct t_gui_buffer *buffer)
|
|
{
|
|
gui_buffer_undo_snap_free (buffer);
|
|
|
|
while (buffer->input_undo)
|
|
{
|
|
gui_buffer_undo_free (buffer, buffer->input_undo);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Searches for a visited buffer in list of visited buffers.
|
|
*/
|
|
|
|
struct t_gui_buffer_visited *
|
|
gui_buffer_visited_search (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_buffer_visited *ptr_buffer_visited;
|
|
|
|
if (!buffer)
|
|
return NULL;
|
|
|
|
for (ptr_buffer_visited = gui_buffers_visited; ptr_buffer_visited;
|
|
ptr_buffer_visited = ptr_buffer_visited->next_buffer)
|
|
{
|
|
if (ptr_buffer_visited->buffer == buffer)
|
|
return ptr_buffer_visited;
|
|
}
|
|
|
|
/* visited buffer not found */
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Searches for a visited buffer in list of visited buffers (by number).
|
|
*/
|
|
|
|
struct t_gui_buffer_visited *
|
|
gui_buffer_visited_search_by_number (int number)
|
|
{
|
|
struct t_gui_buffer_visited *ptr_buffer_visited;
|
|
int i;
|
|
|
|
if ((number < 0) || (number >= gui_buffers_visited_count))
|
|
return NULL;
|
|
|
|
i = 0;
|
|
for (ptr_buffer_visited = gui_buffers_visited; ptr_buffer_visited;
|
|
ptr_buffer_visited = ptr_buffer_visited->next_buffer)
|
|
{
|
|
if (i == number)
|
|
return ptr_buffer_visited;
|
|
i++;
|
|
}
|
|
|
|
/* visited buffer not found (should never be reached) */
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Removes a visited buffer from list of visited buffers.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_visited_remove (struct t_gui_buffer_visited *buffer_visited)
|
|
{
|
|
if (!buffer_visited)
|
|
return;
|
|
|
|
/* remove visited buffer from list */
|
|
if (buffer_visited->prev_buffer)
|
|
(buffer_visited->prev_buffer)->next_buffer = buffer_visited->next_buffer;
|
|
if (buffer_visited->next_buffer)
|
|
(buffer_visited->next_buffer)->prev_buffer = buffer_visited->prev_buffer;
|
|
if (gui_buffers_visited == buffer_visited)
|
|
gui_buffers_visited = buffer_visited->next_buffer;
|
|
if (last_gui_buffer_visited == buffer_visited)
|
|
last_gui_buffer_visited = buffer_visited->prev_buffer;
|
|
|
|
free (buffer_visited);
|
|
|
|
if (gui_buffers_visited_count > 0)
|
|
gui_buffers_visited_count--;
|
|
|
|
if (gui_buffers_visited_index >= gui_buffers_visited_count)
|
|
gui_buffers_visited_index = -1;
|
|
}
|
|
|
|
/*
|
|
* Removes a visited buffer from list of visited buffers.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_visited_remove_by_buffer (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_buffer_visited *buffer_visited;
|
|
|
|
if (!buffer)
|
|
return;
|
|
|
|
buffer_visited = gui_buffer_visited_search (buffer);
|
|
if (buffer_visited)
|
|
gui_buffer_visited_remove (buffer_visited);
|
|
}
|
|
|
|
/*
|
|
* Removes all visited buffers from list.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_visited_remove_all ()
|
|
{
|
|
while (gui_buffers_visited)
|
|
{
|
|
gui_buffer_visited_remove (gui_buffers_visited);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Adds a visited buffer to list of visited buffers.
|
|
*/
|
|
|
|
struct t_gui_buffer_visited *
|
|
gui_buffer_visited_add (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_buffer_visited *new_buffer_visited;
|
|
|
|
if (!buffer)
|
|
return NULL;
|
|
|
|
new_buffer_visited = gui_buffer_visited_search (buffer);
|
|
if (new_buffer_visited)
|
|
gui_buffer_visited_remove (new_buffer_visited);
|
|
|
|
/* remove old buffer(s) visited if list is too long */
|
|
while (gui_buffers_visited_count > CONFIG_INTEGER(config_history_max_visited_buffers))
|
|
{
|
|
gui_buffer_visited_remove (gui_buffers_visited);
|
|
}
|
|
|
|
new_buffer_visited = malloc (sizeof (*new_buffer_visited));
|
|
if (new_buffer_visited)
|
|
{
|
|
new_buffer_visited->buffer = buffer;
|
|
|
|
new_buffer_visited->prev_buffer = last_gui_buffer_visited;
|
|
new_buffer_visited->next_buffer = NULL;
|
|
if (gui_buffers_visited)
|
|
last_gui_buffer_visited->next_buffer = new_buffer_visited;
|
|
else
|
|
gui_buffers_visited = new_buffer_visited;
|
|
last_gui_buffer_visited = new_buffer_visited;
|
|
|
|
gui_buffers_visited_count++;
|
|
gui_buffers_visited_index = -1;
|
|
}
|
|
|
|
return new_buffer_visited;
|
|
}
|
|
|
|
/*
|
|
* Gets index for previously visited buffer.
|
|
*
|
|
* Returns -1 if there's no previously buffer in history, starting from current
|
|
* index.
|
|
*/
|
|
|
|
int
|
|
gui_buffer_visited_get_index_previous ()
|
|
{
|
|
if ((gui_buffers_visited_count < 2) || (gui_buffers_visited_index == 0))
|
|
return -1;
|
|
|
|
if (gui_buffers_visited_index < 0)
|
|
return gui_buffers_visited_count - 2;
|
|
else
|
|
return gui_buffers_visited_index - 1;
|
|
}
|
|
|
|
/*
|
|
* Gets index for next visited buffer.
|
|
*
|
|
* Returns -1 if there's no next buffer in history, starting from current index.
|
|
*/
|
|
|
|
int
|
|
gui_buffer_visited_get_index_next ()
|
|
{
|
|
if ((gui_buffers_visited_count < 2)
|
|
|| (gui_buffers_visited_index >= gui_buffers_visited_count - 1))
|
|
return -1;
|
|
|
|
return gui_buffers_visited_index + 1;
|
|
}
|
|
|
|
/*
|
|
* Returns hdata for buffer.
|
|
*/
|
|
|
|
struct t_hdata *
|
|
gui_buffer_hdata_buffer_cb (void *data, const char *hdata_name)
|
|
{
|
|
struct t_hdata *hdata;
|
|
|
|
/* make C compiler happy */
|
|
(void) data;
|
|
|
|
hdata = hdata_new (NULL, hdata_name, "prev_buffer", "next_buffer",
|
|
0, 0, NULL, NULL);
|
|
if (hdata)
|
|
{
|
|
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);
|
|
HDATA_VAR(struct t_gui_buffer, number, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, layout_number, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, layout_number_merge_order, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, name, STRING, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, full_name, STRING, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, short_name, STRING, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, type, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, notify, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, num_displayed, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, active, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, print_hooks_enabled, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, close_callback, POINTER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, close_callback_data, POINTER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, title, STRING, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, own_lines, POINTER, 0, NULL, "lines");
|
|
HDATA_VAR(struct t_gui_buffer, mixed_lines, POINTER, 0, NULL, "lines");
|
|
HDATA_VAR(struct t_gui_buffer, lines, POINTER, 0, NULL, "lines");
|
|
HDATA_VAR(struct t_gui_buffer, time_for_each_line, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, chat_refresh_needed, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, nicklist, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, nicklist_case_sensitive, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, nicklist_root, POINTER, 0, NULL, "nick_group");
|
|
HDATA_VAR(struct t_gui_buffer, nicklist_max_length, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, nicklist_display_groups, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, nicklist_count, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, nicklist_groups_count, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, nicklist_nicks_count, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, nicklist_visible_count, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, nickcmp_callback, POINTER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, nickcmp_callback_data, POINTER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, input, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, input_callback, POINTER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, input_callback_data, POINTER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, input_get_unknown_commands, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, input_buffer, STRING, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, input_buffer_alloc, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, input_buffer_size, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, input_buffer_length, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, input_buffer_pos, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, input_buffer_1st_display, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, input_undo_snap, POINTER, 0, NULL, "input_undo");
|
|
HDATA_VAR(struct t_gui_buffer, input_undo, POINTER, 0, NULL, "input_undo");
|
|
HDATA_VAR(struct t_gui_buffer, last_input_undo, POINTER, 0, NULL, "input_undo");
|
|
HDATA_VAR(struct t_gui_buffer, ptr_input_undo, POINTER, 0, NULL, "input_undo");
|
|
HDATA_VAR(struct t_gui_buffer, input_undo_count, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, completion, POINTER, 0, NULL, "completion");
|
|
HDATA_VAR(struct t_gui_buffer, history, POINTER, 0, NULL, "history");
|
|
HDATA_VAR(struct t_gui_buffer, last_history, POINTER, 0, NULL, "history");
|
|
HDATA_VAR(struct t_gui_buffer, ptr_history, POINTER, 0, NULL, "history");
|
|
HDATA_VAR(struct t_gui_buffer, num_history, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, text_search, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, text_search_exact, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, text_search_regex, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, text_search_regex_compiled, POINTER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, text_search_where, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, text_search_found, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, text_search_input, STRING, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, highlight_words, STRING, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, highlight_regex, STRING, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, highlight_regex_compiled, POINTER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, highlight_tags, STRING, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, highlight_tags_count, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, highlight_tags_array, STRING, 0, "highlight_tags_count", NULL);
|
|
HDATA_VAR(struct t_gui_buffer, hotlist_max_level_nicks, HASHTABLE, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, keys, POINTER, 0, NULL, "key");
|
|
HDATA_VAR(struct t_gui_buffer, last_key, POINTER, 0, NULL, "key");
|
|
HDATA_VAR(struct t_gui_buffer, keys_count, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, local_variables, HASHTABLE, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_buffer, prev_buffer, POINTER, 0, NULL, hdata_name);
|
|
HDATA_VAR(struct t_gui_buffer, next_buffer, POINTER, 0, NULL, hdata_name);
|
|
HDATA_LIST(gui_buffers);
|
|
HDATA_LIST(last_gui_buffer);
|
|
HDATA_LIST(gui_buffer_last_displayed);
|
|
}
|
|
return hdata;
|
|
}
|
|
|
|
/*
|
|
* Returns hdata for input undo.
|
|
*/
|
|
|
|
struct t_hdata *
|
|
gui_buffer_hdata_input_undo_cb (void *data, const char *hdata_name)
|
|
{
|
|
struct t_hdata *hdata;
|
|
|
|
/* make C compiler happy */
|
|
(void) data;
|
|
|
|
hdata = hdata_new (NULL, hdata_name, "prev_undo", "next_undo",
|
|
0, 0, NULL, NULL);
|
|
if (hdata)
|
|
{
|
|
HDATA_VAR(struct t_gui_input_undo, data, STRING, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_input_undo, pos, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_gui_input_undo, prev_undo, POINTER, 0, NULL, hdata_name);
|
|
HDATA_VAR(struct t_gui_input_undo, next_undo, POINTER, 0, NULL, hdata_name);
|
|
}
|
|
return hdata;
|
|
}
|
|
|
|
/*
|
|
* Returns hdata for buffer visited.
|
|
*/
|
|
|
|
struct t_hdata *
|
|
gui_buffer_hdata_buffer_visited_cb (void *data, const char *hdata_name)
|
|
{
|
|
struct t_hdata *hdata;
|
|
|
|
/* make C compiler happy */
|
|
(void) data;
|
|
|
|
hdata = hdata_new (NULL, hdata_name, "prev_buffer", "next_buffer",
|
|
0, 0, NULL, NULL);
|
|
if (hdata)
|
|
{
|
|
HDATA_VAR(struct t_gui_buffer_visited, buffer, POINTER, 0, NULL, "buffer");
|
|
HDATA_VAR(struct t_gui_buffer_visited, prev_buffer, POINTER, 0, NULL, hdata_name);
|
|
HDATA_VAR(struct t_gui_buffer_visited, next_buffer, POINTER, 0, NULL, hdata_name);
|
|
HDATA_LIST(gui_buffers_visited);
|
|
HDATA_LIST(last_gui_buffer_visited);
|
|
}
|
|
return hdata;
|
|
}
|
|
|
|
/*
|
|
* Adds a buffer in an infolist.
|
|
*
|
|
* Returns:
|
|
* 1: OK
|
|
* 0: error
|
|
*/
|
|
|
|
int
|
|
gui_buffer_add_to_infolist (struct t_infolist *infolist,
|
|
struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_infolist_item *ptr_item;
|
|
struct t_gui_key *ptr_key;
|
|
char option_name[64];
|
|
int i;
|
|
|
|
if (!infolist || !buffer)
|
|
return 0;
|
|
|
|
ptr_item = infolist_new_item (infolist);
|
|
if (!ptr_item)
|
|
return 0;
|
|
|
|
if (!infolist_new_var_pointer (ptr_item, "pointer", buffer))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "current_buffer",
|
|
(gui_current_window->buffer == buffer) ? 1 : 0))
|
|
return 0;
|
|
if (!infolist_new_var_pointer (ptr_item, "plugin", buffer->plugin))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "plugin_name",
|
|
gui_buffer_get_plugin_name (buffer)))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "number", buffer->number))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "layout_number", buffer->layout_number))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "layout_number_merge_order", buffer->layout_number_merge_order))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "name", buffer->name))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "full_name", buffer->full_name))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "short_name", gui_buffer_get_short_name (buffer)))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "type", buffer->type))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "notify", buffer->notify))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "num_displayed", buffer->num_displayed))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "active", buffer->active))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "print_hooks_enabled", buffer->print_hooks_enabled))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "first_line_not_read", buffer->lines->first_line_not_read))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "lines_hidden", buffer->lines->lines_hidden))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "prefix_max_length", buffer->lines->prefix_max_length))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "time_for_each_line", buffer->time_for_each_line))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "nicklist_case_sensitive", buffer->nicklist_case_sensitive))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "nicklist_display_groups", buffer->nicklist_display_groups))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "nicklist_max_length", buffer->nicklist_max_length))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "nicklist_count", buffer->nicklist_count))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "nicklist_groups_count", buffer->nicklist_groups_count))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "nicklist_nicks_count", buffer->nicklist_nicks_count))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "nicklist_visible_count", buffer->nicklist_visible_count))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "title", buffer->title))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "input", buffer->input))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "input_get_unknown_commands", buffer->input_get_unknown_commands))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "input_buffer", buffer->input_buffer))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "input_buffer_alloc", buffer->input_buffer_alloc))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "input_buffer_size", buffer->input_buffer_size))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "input_buffer_length", buffer->input_buffer_length))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "input_buffer_pos", buffer->input_buffer_pos))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "input_buffer_1st_display", buffer->input_buffer_1st_display))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "num_history", buffer->num_history))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "text_search", buffer->text_search))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "text_search_exact", buffer->text_search_exact))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "text_search_regex", buffer->text_search_regex))
|
|
return 0;
|
|
if (!infolist_new_var_pointer (ptr_item, "text_search_regex_compiled", buffer->text_search_regex_compiled))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "text_search_where", buffer->text_search_where))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "text_search_found", buffer->text_search_found))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "text_search_input", buffer->text_search_input))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "highlight_words", buffer->highlight_words))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "highlight_regex", buffer->highlight_regex))
|
|
return 0;
|
|
if (!infolist_new_var_pointer (ptr_item, "highlight_regex_compiled", buffer->highlight_regex_compiled))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "highlight_tags", buffer->highlight_tags))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "hotlist_max_level_nicks", hashtable_get_string (buffer->hotlist_max_level_nicks, "keys_values")))
|
|
return 0;
|
|
i = 0;
|
|
for (ptr_key = buffer->keys; ptr_key; ptr_key = ptr_key->next_key)
|
|
{
|
|
snprintf (option_name, sizeof (option_name), "key_%05d", i);
|
|
if (!infolist_new_var_string (ptr_item, option_name, ptr_key->key))
|
|
return 0;
|
|
snprintf (option_name, sizeof (option_name), "key_command_%05d", i);
|
|
if (!infolist_new_var_string (ptr_item, option_name, ptr_key->command))
|
|
return 0;
|
|
i++;
|
|
}
|
|
if (!infolist_new_var_integer (ptr_item, "keys_count", buffer->keys_count))
|
|
return 0;
|
|
if (!hashtable_add_to_infolist (buffer->local_variables, ptr_item, "localvar"))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Dumps content of buffer as hexa data in WeeChat log file.
|
|
*/
|
|
|
|
void
|
|
gui_buffer_dump_hexa (struct t_gui_buffer *buffer)
|
|
{
|
|
struct t_gui_line *ptr_line;
|
|
int num_line;
|
|
char *prefix_without_colors, *message_without_colors, *tags;
|
|
char buf[256];
|
|
|
|
log_printf ("[buffer dump hexa (addr:0x%lx)]", buffer);
|
|
num_line = 1;
|
|
for (ptr_line = buffer->lines->first_line; ptr_line;
|
|
ptr_line = ptr_line->next_line)
|
|
{
|
|
/* display line without colors */
|
|
prefix_without_colors = (ptr_line->data->prefix) ?
|
|
gui_color_decode (ptr_line->data->prefix, NULL) : NULL;
|
|
message_without_colors = (ptr_line->data->message) ?
|
|
gui_color_decode (ptr_line->data->message, NULL) : NULL;
|
|
log_printf ("");
|
|
log_printf (" line %d: %s | %s",
|
|
num_line,
|
|
(prefix_without_colors) ? prefix_without_colors : "(null)",
|
|
(message_without_colors) ? message_without_colors : "(null)");
|
|
if (prefix_without_colors)
|
|
free (prefix_without_colors);
|
|
if (message_without_colors)
|
|
free (message_without_colors);
|
|
tags = string_build_with_split_string ((const char **)ptr_line->data->tags_array,
|
|
",");
|
|
log_printf (" tags: '%s', displayed: %d, highlight: %d",
|
|
(tags) ? tags : "(none)",
|
|
ptr_line->data->displayed,
|
|
ptr_line->data->highlight);
|
|
if (tags)
|
|
free (tags);
|
|
snprintf (buf, sizeof (buf), "%s", ctime (&ptr_line->data->date));
|
|
buf[strlen (buf) - 1] = '\0';
|
|
log_printf (" date: %d = %s", ptr_line->data->date, buf);
|
|
snprintf (buf, sizeof (buf), "%s", ctime (&ptr_line->data->date_printed));
|
|
buf[strlen (buf) - 1] = '\0';
|
|
log_printf (" date_printed: %d = %s", ptr_line->data->date_printed, buf);
|
|
|
|
/* display raw message for line */
|
|
if (ptr_line->data->message)
|
|
{
|
|
log_printf ("");
|
|
if (ptr_line->data->prefix && ptr_line->data->prefix[0])
|
|
{
|
|
log_printf (" raw prefix for line %d:", num_line);
|
|
log_printf_hexa (" ", ptr_line->data->prefix);
|
|
}
|
|
else
|
|
{
|
|
log_printf (" no prefix for line %d", num_line);
|
|
}
|
|
if (ptr_line->data->message && ptr_line->data->message[0])
|
|
{
|
|
log_printf (" raw message for line %d:", num_line);
|
|
log_printf_hexa (" ", ptr_line->data->message);
|
|
}
|
|
else
|
|
{
|
|
log_printf (" no message for line %d", num_line);
|
|
}
|
|
}
|
|
|
|
num_line++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Prints buffer infos in WeeChat log file (usually for crash dump).
|
|
*/
|
|
|
|
void
|
|
gui_buffer_print_log ()
|
|
{
|
|
struct t_gui_buffer *ptr_buffer;
|
|
struct t_gui_line *ptr_line;
|
|
struct t_gui_buffer_visited *ptr_buffer_visited;
|
|
struct t_gui_input_undo *ptr_undo;
|
|
char *tags;
|
|
int num;
|
|
|
|
log_printf ("");
|
|
log_printf ("gui_buffers . . . . . . . . . : 0x%lx", gui_buffers);
|
|
log_printf ("last_gui_buffer . . . . . . . : 0x%lx", last_gui_buffer);
|
|
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);
|
|
log_printf ("gui_buffers_visited_count . . : %d", gui_buffers_visited_count);
|
|
log_printf ("gui_buffers_visited_frozen. . : %d", gui_buffers_visited_frozen);
|
|
log_printf ("gui_buffer_last_displayed . . : 0x%lx", gui_buffer_last_displayed);
|
|
|
|
for (ptr_buffer = gui_buffers; ptr_buffer;
|
|
ptr_buffer = ptr_buffer->next_buffer)
|
|
{
|
|
log_printf ("");
|
|
log_printf ("[buffer (addr:0x%lx)]", ptr_buffer);
|
|
log_printf (" plugin. . . . . . . . . : 0x%lx ('%s')",
|
|
ptr_buffer->plugin, gui_buffer_get_plugin_name (ptr_buffer));
|
|
log_printf (" plugin_name_for_upgrade : '%s'", ptr_buffer->plugin_name_for_upgrade);
|
|
log_printf (" number. . . . . . . . . : %d", ptr_buffer->number);
|
|
log_printf (" layout_number . . . . . : %d", ptr_buffer->layout_number);
|
|
log_printf (" layout_number_merge_order: %d", ptr_buffer->layout_number_merge_order);
|
|
log_printf (" name. . . . . . . . . . : '%s'", ptr_buffer->name);
|
|
log_printf (" full_name . . . . . . . : '%s'", ptr_buffer->full_name);
|
|
log_printf (" short_name. . . . . . . : '%s'", ptr_buffer->short_name);
|
|
log_printf (" type. . . . . . . . . . : %d", ptr_buffer->type);
|
|
log_printf (" notify. . . . . . . . . : %d", ptr_buffer->notify);
|
|
log_printf (" num_displayed . . . . . : %d", ptr_buffer->num_displayed);
|
|
log_printf (" active. . . . . . . . . : %d", ptr_buffer->active);
|
|
log_printf (" print_hooks_enabled . . : %d", ptr_buffer->print_hooks_enabled);
|
|
log_printf (" close_callback. . . . . : 0x%lx", ptr_buffer->close_callback);
|
|
log_printf (" close_callback_data . . : 0x%lx", ptr_buffer->close_callback_data);
|
|
log_printf (" title . . . . . . . . . : '%s'", ptr_buffer->title);
|
|
log_printf (" own_lines . . . . . . . : 0x%lx", ptr_buffer->own_lines);
|
|
gui_lines_print_log (ptr_buffer->own_lines);
|
|
log_printf (" mixed_lines . . . . . . : 0x%lx", ptr_buffer->mixed_lines);
|
|
gui_lines_print_log (ptr_buffer->mixed_lines);
|
|
log_printf (" lines . . . . . . . . . : 0x%lx", ptr_buffer->lines);
|
|
log_printf (" time_for_each_line. . . : %d", ptr_buffer->time_for_each_line);
|
|
log_printf (" chat_refresh_needed . . : %d", ptr_buffer->chat_refresh_needed);
|
|
log_printf (" nicklist. . . . . . . . : %d", ptr_buffer->nicklist);
|
|
log_printf (" nicklist_case_sensitive : %d", ptr_buffer->nicklist_case_sensitive);
|
|
log_printf (" nicklist_root . . . . . : 0x%lx", ptr_buffer->nicklist_root);
|
|
log_printf (" nicklist_max_length . . : %d", ptr_buffer->nicklist_max_length);
|
|
log_printf (" nicklist_display_groups : %d", ptr_buffer->nicklist_display_groups);
|
|
log_printf (" nicklist_count. . . . . : %d", ptr_buffer->nicklist_count);
|
|
log_printf (" nicklist_groups_count . : %d", ptr_buffer->nicklist_groups_count);
|
|
log_printf (" nicklist_nicks_count. . : %d", ptr_buffer->nicklist_nicks_count);
|
|
log_printf (" nicklist_visible_count. : %d", ptr_buffer->nicklist_visible_count);
|
|
log_printf (" nickcmp_callback. . . . : 0x%lx", ptr_buffer->nickcmp_callback);
|
|
log_printf (" nickcmp_callback_data . : 0x%lx", ptr_buffer->nickcmp_callback_data);
|
|
log_printf (" input . . . . . . . . . : %d", ptr_buffer->input);
|
|
log_printf (" input_callback. . . . . : 0x%lx", ptr_buffer->input_callback);
|
|
log_printf (" input_callback_data . . : 0x%lx", ptr_buffer->input_callback_data);
|
|
log_printf (" input_get_unknown_cmd . : %d", ptr_buffer->input_get_unknown_commands);
|
|
log_printf (" input_buffer. . . . . . : '%s'", ptr_buffer->input_buffer);
|
|
log_printf (" input_buffer_alloc. . . : %d", ptr_buffer->input_buffer_alloc);
|
|
log_printf (" input_buffer_size . . . : %d", ptr_buffer->input_buffer_size);
|
|
log_printf (" input_buffer_length . . : %d", ptr_buffer->input_buffer_length);
|
|
log_printf (" input_buffer_pos. . . . : %d", ptr_buffer->input_buffer_pos);
|
|
log_printf (" input_buffer_1st_disp . : %d", ptr_buffer->input_buffer_1st_display);
|
|
log_printf (" input_undo_snap->data . : '%s'", (ptr_buffer->input_undo_snap)->data);
|
|
log_printf (" input_undo_snap->pos. . : %d", (ptr_buffer->input_undo_snap)->pos);
|
|
log_printf (" input_undo. . . . . . . : 0x%lx", ptr_buffer->input_undo);
|
|
log_printf (" last_input_undo . . . . : 0x%lx", ptr_buffer->last_input_undo);
|
|
log_printf (" ptr_input_undo. . . . . : 0x%lx", ptr_buffer->ptr_input_undo);
|
|
log_printf (" input_undo_count. . . . : %d", ptr_buffer->input_undo_count);
|
|
num = 0;
|
|
for (ptr_undo = ptr_buffer->input_undo; ptr_undo;
|
|
ptr_undo = ptr_undo->next_undo)
|
|
{
|
|
log_printf (" undo[%04d]. . . . . . : 0x%lx ('%s' / %d)",
|
|
num, ptr_undo, ptr_undo->data, ptr_undo->pos);
|
|
num++;
|
|
}
|
|
log_printf (" completion. . . . . . . : 0x%lx", ptr_buffer->completion);
|
|
log_printf (" history . . . . . . . . : 0x%lx", ptr_buffer->history);
|
|
log_printf (" last_history. . . . . . : 0x%lx", ptr_buffer->last_history);
|
|
log_printf (" ptr_history . . . . . . : 0x%lx", ptr_buffer->ptr_history);
|
|
log_printf (" num_history . . . . . . : %d", ptr_buffer->num_history);
|
|
log_printf (" text_search . . . . . . : %d", ptr_buffer->text_search);
|
|
log_printf (" text_search_exact . . . : %d", ptr_buffer->text_search_exact);
|
|
log_printf (" text_search_regex . . . : %d", ptr_buffer->text_search_regex);
|
|
log_printf (" text_search_regex_compiled: 0x%lx", ptr_buffer->text_search_regex_compiled);
|
|
log_printf (" text_search_where . . . : %d", ptr_buffer->text_search_where);
|
|
log_printf (" text_search_found . . . : %d", ptr_buffer->text_search_found);
|
|
log_printf (" text_search_input . . . : '%s'", ptr_buffer->text_search_input);
|
|
log_printf (" highlight_words . . . . : '%s'", ptr_buffer->highlight_words);
|
|
log_printf (" highlight_regex . . . . : '%s'", ptr_buffer->highlight_regex);
|
|
log_printf (" highlight_regex_compiled: 0x%lx", ptr_buffer->highlight_regex_compiled);
|
|
log_printf (" highlight_tags. . . . . : '%s'", ptr_buffer->highlight_tags);
|
|
log_printf (" highlight_tags_count. . : %d", ptr_buffer->highlight_tags_count);
|
|
log_printf (" highlight_tags_array. . : 0x%lx", ptr_buffer->highlight_tags_array);
|
|
log_printf (" keys. . . . . . . . . . : 0x%lx", ptr_buffer->keys);
|
|
log_printf (" last_key. . . . . . . . : 0x%lx", ptr_buffer->last_key);
|
|
log_printf (" keys_count. . . . . . . : %d", ptr_buffer->keys_count);
|
|
log_printf (" local_variables . . . . : 0x%lx", ptr_buffer->local_variables);
|
|
log_printf (" prev_buffer . . . . . . : 0x%lx", ptr_buffer->prev_buffer);
|
|
log_printf (" next_buffer . . . . . . : 0x%lx", ptr_buffer->next_buffer);
|
|
|
|
if (ptr_buffer->hotlist_max_level_nicks)
|
|
{
|
|
hashtable_print_log (ptr_buffer->hotlist_max_level_nicks,
|
|
"hotlist_max_level_nicks");
|
|
}
|
|
|
|
if (ptr_buffer->keys)
|
|
{
|
|
log_printf ("");
|
|
log_printf (" => keys:");
|
|
gui_key_print_log (ptr_buffer);
|
|
}
|
|
|
|
if (ptr_buffer->local_variables)
|
|
{
|
|
hashtable_print_log (ptr_buffer->local_variables,
|
|
"local_variables");
|
|
}
|
|
|
|
log_printf ("");
|
|
log_printf (" => nicklist:");
|
|
gui_nicklist_print_log (ptr_buffer->nicklist_root, 0);
|
|
|
|
log_printf ("");
|
|
log_printf (" => last 100 lines:");
|
|
num = 0;
|
|
ptr_line = ptr_buffer->own_lines->last_line;
|
|
while (ptr_line && (num < 100))
|
|
{
|
|
num++;
|
|
ptr_line = ptr_line->prev_line;
|
|
}
|
|
if (!ptr_line)
|
|
ptr_line = ptr_buffer->own_lines->first_line;
|
|
else
|
|
ptr_line = ptr_line->next_line;
|
|
|
|
while (ptr_line)
|
|
{
|
|
num--;
|
|
tags = string_build_with_split_string ((const char **)ptr_line->data->tags_array,
|
|
",");
|
|
log_printf (" line N-%05d: y:%d, str_time:'%s', tags:'%s', "
|
|
"displayed:%d, highlight:%d, refresh_needed:%d, "
|
|
"prefix:'%s'",
|
|
num, ptr_line->data->y, ptr_line->data->str_time,
|
|
(tags) ? tags : "",
|
|
(int)(ptr_line->data->displayed),
|
|
(int)(ptr_line->data->highlight),
|
|
(int)(ptr_line->data->refresh_needed),
|
|
ptr_line->data->prefix);
|
|
log_printf (" data: '%s'",
|
|
ptr_line->data->message);
|
|
if (tags)
|
|
free (tags);
|
|
|
|
ptr_line = ptr_line->next_line;
|
|
}
|
|
|
|
if (ptr_buffer->completion)
|
|
{
|
|
log_printf ("");
|
|
gui_completion_print_log (ptr_buffer->completion);
|
|
}
|
|
}
|
|
|
|
log_printf ("");
|
|
log_printf ("[visited buffers]");
|
|
num = 1;
|
|
for (ptr_buffer_visited = gui_buffers_visited; ptr_buffer_visited;
|
|
ptr_buffer_visited = ptr_buffer_visited->next_buffer)
|
|
{
|
|
log_printf (" #%d:", num);
|
|
log_printf (" buffer . . . . . . . . : 0x%lx", ptr_buffer_visited->buffer);
|
|
log_printf (" prev_buffer. . . . . . : 0x%lx", ptr_buffer_visited->prev_buffer);
|
|
log_printf (" next_buffer. . . . . . : 0x%lx", ptr_buffer_visited->next_buffer);
|
|
num++;
|
|
}
|
|
}
|