weechat/src/plugins/buflist/buflist-bar-item.c

747 lines
26 KiB
C

/*
* buflist-bar-item.c - bar item for buflist plugin
*
* Copyright (C) 2003-2020 Sébastien 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 <https://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../weechat-plugin.h"
#include "buflist.h"
#include "buflist-bar-item.h"
#include "buflist-config.h"
struct t_gui_bar_item *buflist_bar_item_buflist[BUFLIST_BAR_NUM_ITEMS] =
{ NULL, NULL, NULL };
struct t_hashtable *buflist_hashtable_pointers = NULL;
struct t_hashtable *buflist_hashtable_extra_vars = NULL;
struct t_hashtable *buflist_hashtable_options_conditions = NULL;
struct t_arraylist *buflist_list_buffers[BUFLIST_BAR_NUM_ITEMS] =
{ NULL, NULL, NULL };
int old_line_number_current_buffer[BUFLIST_BAR_NUM_ITEMS] = { -1, -1, -1 };
/*
* Returns the bar item name with an index.
*/
const char *
buflist_bar_item_get_name (int index)
{
static char item_name[32];
if (index == 0)
{
snprintf (item_name, sizeof (item_name), "%s", BUFLIST_BAR_ITEM_NAME);
}
else
{
snprintf (item_name, sizeof (item_name),
"%s%d",
BUFLIST_BAR_ITEM_NAME,
index + 1);
}
return item_name;
}
/*
* Returns the bar item index with an item name, -1 if not found.
*/
int
buflist_bar_item_get_index (const char *item_name)
{
int i;
const char *ptr_item_name;
for (i = 0; i < BUFLIST_BAR_NUM_ITEMS; i++)
{
ptr_item_name = buflist_bar_item_get_name (i);
if (strcmp (ptr_item_name, item_name) == 0)
return i;
}
return -1;
}
/*
* Returns the bar item index with a bar item pointer, -1 if not found.
*/
int
buflist_bar_item_get_index_with_pointer (struct t_gui_bar_item *item)
{
int i;
for (i = 0; i < BUFLIST_BAR_NUM_ITEMS; i++)
{
if (buflist_bar_item_buflist[i] == item)
return i;
}
return -1;
}
/*
* Updates buflist bar item if buflist is enabled (or if force argument is 1).
*/
void
buflist_bar_item_update (int force)
{
int i;
if (force || weechat_config_boolean (buflist_config_look_enabled))
{
for (i = 0; i < BUFLIST_BAR_NUM_ITEMS; i++)
{
weechat_bar_item_update (buflist_bar_item_get_name (i));
}
}
}
/*
* Checks if the bar can be scrolled, the bar must have:
* - a position "left" or "right"
* - a filling "vertical"
* - the item_name as first item.
*
* Returns:
* 1: bar can be scrolled
* 0: bar must not be scrolled
*/
int
buflist_bar_item_bar_can_scroll (struct t_gui_bar *bar, const char *item_name)
{
const char *ptr_bar_name, *ptr_bar_position, *ptr_bar_filling;
int items_count, *items_subcount;
char ***items_name, str_option[1024];
ptr_bar_name = weechat_hdata_string (buflist_hdata_bar, bar, "name");
if (!ptr_bar_name)
return 0;
/* check that bar option "position" is "left" or "right" */
snprintf (str_option, sizeof (str_option),
"weechat.bar.%s.position",
ptr_bar_name);
ptr_bar_position = weechat_config_string (weechat_config_get (str_option));
if (!ptr_bar_position
|| ((strcmp (ptr_bar_position, "left") != 0)
&& (strcmp (ptr_bar_position, "right") != 0)))
{
return 0;
}
/* check that bar option "filling_left_right" is "vertical" */
snprintf (str_option, sizeof (str_option),
"weechat.bar.%s.filling_left_right",
ptr_bar_name);
ptr_bar_filling = weechat_config_string (weechat_config_get (str_option));
if (!ptr_bar_filling || (strcmp (ptr_bar_filling, "vertical") != 0))
{
return 0;
}
/* check that "buflist" is the first item in bar */
items_count = weechat_hdata_integer (buflist_hdata_bar, bar,
"items_count");
if (items_count <= 0)
return 0;
items_subcount = weechat_hdata_pointer (buflist_hdata_bar, bar,
"items_subcount");
if (!items_subcount || (items_subcount[0] <= 0))
return 0;
items_name = weechat_hdata_pointer (buflist_hdata_bar, bar, "items_name");
if (!items_name || !items_name[0] || !items_name[0][0]
|| (strcmp (items_name[0][0], item_name) != 0))
{
return 0;
}
/* OK, bar can be scrolled! */
return 1;
}
/*
* Auto-scrolls a bar window displaying buflist item.
*/
void
buflist_bar_item_auto_scroll_bar_window (struct t_gui_bar_window *bar_window,
int line_number)
{
int height, scroll_y, new_scroll_y, auto_scroll;
char str_scroll[64];
struct t_hashtable *hashtable;
if (!bar_window || (line_number < 0))
return;
height = weechat_hdata_integer (buflist_hdata_bar_window, bar_window,
"height");
scroll_y = weechat_hdata_integer (buflist_hdata_bar_window, bar_window,
"scroll_y");
/* no scroll needed if the line_number is already displayed */
if ((line_number >= scroll_y) && (line_number < scroll_y + height))
return;
hashtable = weechat_hashtable_new (8,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL, NULL);
if (hashtable)
{
auto_scroll = weechat_config_integer (buflist_config_look_auto_scroll);
new_scroll_y = line_number - (((height - 1) * auto_scroll) / 100);
if (new_scroll_y < 0)
new_scroll_y = 0;
snprintf (str_scroll, sizeof (str_scroll),
"%d", new_scroll_y);
weechat_hashtable_set (hashtable, "scroll_y", str_scroll);
weechat_hdata_update (buflist_hdata_bar_window, bar_window, hashtable);
weechat_hashtable_free (hashtable);
}
}
/*
* Auto-scrolls all bars with a given buflist item as first item.
*/
void
buflist_bar_item_auto_scroll (const char *item_name, int line_number)
{
struct t_gui_bar *ptr_bar;
struct t_gui_bar_window *ptr_bar_window;
struct t_gui_window *ptr_window;
if (line_number < 0)
return;
/* auto-scroll in root bars */
ptr_bar = weechat_hdata_get_list (buflist_hdata_bar, "gui_bars");
while (ptr_bar)
{
ptr_bar_window = weechat_hdata_pointer (buflist_hdata_bar, ptr_bar,
"bar_window");
if (ptr_bar_window && buflist_bar_item_bar_can_scroll (ptr_bar,
item_name))
{
buflist_bar_item_auto_scroll_bar_window (ptr_bar_window,
line_number);
}
ptr_bar = weechat_hdata_move (buflist_hdata_bar, ptr_bar, 1);
}
/* auto-scroll in window bars */
ptr_window = weechat_hdata_get_list (buflist_hdata_window, "gui_windows");
while (ptr_window)
{
ptr_bar_window = weechat_hdata_pointer (buflist_hdata_window,
ptr_window, "bar_windows");
while (ptr_bar_window)
{
ptr_bar = weechat_hdata_pointer (buflist_hdata_bar_window,
ptr_bar_window, "bar");
if (buflist_bar_item_bar_can_scroll (ptr_bar, item_name))
{
buflist_bar_item_auto_scroll_bar_window (ptr_bar_window,
line_number);
}
ptr_bar_window = weechat_hdata_move (buflist_hdata_bar_window,
ptr_bar_window, 1);
}
ptr_window = weechat_hdata_move (buflist_hdata_window, ptr_window, 1);
}
}
/*
* Returns content of bar item "buffer_plugin": bar item with buffer plugin.
*/
char *
buflist_bar_item_buflist_cb (const void *pointer, void *data,
struct t_gui_bar_item *item,
struct t_gui_window *window,
struct t_gui_buffer *buffer,
struct t_hashtable *extra_info)
{
struct t_arraylist *buffers;
struct t_gui_buffer *ptr_buffer, *ptr_current_buffer;
struct t_gui_buffer *ptr_buffer_prev, *ptr_buffer_next;
struct t_gui_nick *ptr_gui_nick;
struct t_gui_hotlist *ptr_hotlist;
void *ptr_server, *ptr_channel;
char **buflist, *str_buflist, *condition;
char str_format_number[32], str_format_number_empty[32];
char str_nick_prefix[32], str_color_nick_prefix[32];
char str_number[32], str_number2[32], *line, **hotlist, *str_hotlist;
char str_hotlist_count[32];
const char *ptr_format, *ptr_format_current, *ptr_format_indent;
const char *ptr_name, *ptr_type, *ptr_nick, *ptr_nick_prefix;
const char *ptr_hotlist_format, *ptr_hotlist_priority;
const char *hotlist_priority_none = "none";
const char *hotlist_priority[4] = { "low", "message", "private",
"highlight" };
const char indent_empty[1] = { '\0' };
const char *ptr_lag, *ptr_item_name;
int item_index, num_buffers, is_channel, is_private;
int i, j, length_max_number, current_buffer, number, prev_number, priority;
int rc, count, line_number, line_number_current_buffer;
/* make C compiler happy */
(void) data;
(void) buffer;
(void) extra_info;
if (!weechat_config_boolean (buflist_config_look_enabled))
return NULL;
prev_number = -1;
line_number = 0;
line_number_current_buffer = 0;
buflist = weechat_string_dyn_alloc (256);
item_index = (int)((unsigned long)pointer);
weechat_hashtable_set (buflist_hashtable_pointers, "bar_item", item);
weechat_hashtable_set (buflist_hashtable_pointers, "window", window);
ptr_format = buflist_config_format_buffer_eval;
ptr_format_current = buflist_config_format_buffer_current_eval;
ptr_current_buffer = weechat_current_buffer ();
ptr_buffer = weechat_hdata_get_list (buflist_hdata_buffer,
"last_gui_buffer");
length_max_number = snprintf (
str_number, sizeof (str_number),
"%d",
weechat_hdata_integer (buflist_hdata_buffer, ptr_buffer, "number"));
snprintf (str_format_number, sizeof (str_format_number),
"%%%dd", length_max_number);
snprintf (str_format_number_empty, sizeof (str_format_number_empty),
"%%-%ds", length_max_number);
if (buflist_list_buffers[item_index])
weechat_arraylist_free (buflist_list_buffers[item_index]);
buflist_list_buffers[item_index] = weechat_arraylist_new (
16, 0, 1,
NULL, NULL, NULL, NULL);
buffers = buflist_sort_buffers (item);
num_buffers = weechat_arraylist_size (buffers);
for (i = 0; i < num_buffers; i++)
{
ptr_buffer = weechat_arraylist_get (buffers, i);
/* set pointers */
weechat_hashtable_set (buflist_hashtable_pointers,
"buffer", ptr_buffer);
/* set IRC server/channel pointers */
buflist_buffer_get_irc_pointers (ptr_buffer, &ptr_server, &ptr_channel);
weechat_hashtable_set (buflist_hashtable_pointers,
"irc_server", ptr_server);
weechat_hashtable_set (buflist_hashtable_pointers,
"irc_channel", ptr_channel);
/* name / short name */
ptr_name = weechat_hdata_string (buflist_hdata_buffer,
ptr_buffer, "short_name");
if (!ptr_name)
{
ptr_name = weechat_hdata_string (buflist_hdata_buffer,
ptr_buffer, "name");
}
/* current buffer */
current_buffer = (ptr_buffer == ptr_current_buffer);
weechat_hashtable_set (buflist_hashtable_extra_vars,
"current_buffer",
(current_buffer) ? "1" : "0");
/* buffer number */
number = weechat_hdata_integer (buflist_hdata_buffer,
ptr_buffer, "number");
if (number != prev_number)
{
snprintf (str_number, sizeof (str_number),
str_format_number, number);
weechat_hashtable_set (buflist_hashtable_extra_vars,
"number_displayed", "1");
}
else
{
snprintf (str_number, sizeof (str_number),
str_format_number_empty, " ");
weechat_hashtable_set (buflist_hashtable_extra_vars,
"number_displayed", "0");
}
snprintf (str_number2, sizeof (str_number2),
str_format_number, number);
/* buffer merged */
ptr_buffer_prev = weechat_hdata_move (buflist_hdata_buffer,
ptr_buffer, -1);
ptr_buffer_next = weechat_hdata_move (buflist_hdata_buffer,
ptr_buffer, 1);
if ((ptr_buffer_prev
&& (weechat_hdata_integer (buflist_hdata_buffer,
ptr_buffer_prev,
"number") == number))
|| (ptr_buffer_next
&& (weechat_hdata_integer (buflist_hdata_buffer,
ptr_buffer_next,
"number") == number)))
{
weechat_hashtable_set (buflist_hashtable_extra_vars,
"merged", "1");
}
else
{
weechat_hashtable_set (buflist_hashtable_extra_vars,
"merged", "0");
}
/* buffer name */
ptr_type = weechat_buffer_get_string (ptr_buffer, "localvar_type");
is_channel = (ptr_type && (strcmp (ptr_type, "channel") == 0));
is_private = (ptr_type && (strcmp (ptr_type, "private") == 0));
ptr_format_indent = (is_channel || is_private) ?
weechat_config_string (buflist_config_format_indent) : indent_empty;
/* nick prefix */
str_nick_prefix[0] = '\0';
str_color_nick_prefix[0] = '\0';
if (is_channel
&& weechat_config_boolean (buflist_config_look_nick_prefix))
{
snprintf (str_nick_prefix, sizeof (str_nick_prefix),
"%s",
(weechat_config_boolean (buflist_config_look_nick_prefix_empty)) ?
" " : "");
ptr_nick = weechat_buffer_get_string (ptr_buffer, "localvar_nick");
if (ptr_nick)
{
ptr_gui_nick = weechat_nicklist_search_nick (ptr_buffer, NULL,
ptr_nick);
if (ptr_gui_nick)
{
ptr_nick_prefix = weechat_nicklist_nick_get_string (
ptr_buffer, ptr_gui_nick, "prefix");
if (ptr_nick_prefix && (ptr_nick_prefix[0] != ' '))
{
snprintf (str_color_nick_prefix,
sizeof (str_color_nick_prefix),
"%s",
weechat_color (
weechat_nicklist_nick_get_string (
ptr_buffer, ptr_gui_nick,
"prefix_color")));
snprintf (str_nick_prefix, sizeof (str_nick_prefix),
"%s",
ptr_nick_prefix);
}
}
}
}
weechat_hashtable_set (buflist_hashtable_extra_vars,
"nick_prefix", str_nick_prefix);
weechat_hashtable_set (buflist_hashtable_extra_vars,
"color_nick_prefix", str_color_nick_prefix);
weechat_hashtable_set (buflist_hashtable_extra_vars,
"format_nick_prefix",
weechat_config_string (
buflist_config_format_nick_prefix));
/* set extra variables */
weechat_hashtable_set (buflist_hashtable_extra_vars,
"format_buffer",
buflist_config_format_buffer_eval);
weechat_hashtable_set (buflist_hashtable_extra_vars,
"number", str_number);
weechat_hashtable_set (buflist_hashtable_extra_vars,
"number2", str_number2);
weechat_hashtable_set (buflist_hashtable_extra_vars,
"format_number",
weechat_config_string (
buflist_config_format_number));
weechat_hashtable_set (buflist_hashtable_extra_vars,
"indent", ptr_format_indent);
weechat_hashtable_set (buflist_hashtable_extra_vars,
"name", ptr_name);
weechat_hashtable_set (buflist_hashtable_extra_vars,
"format_name",
weechat_config_string (
buflist_config_format_name));
/* hotlist */
ptr_hotlist = weechat_hdata_pointer (buflist_hdata_buffer,
ptr_buffer, "hotlist");
ptr_hotlist_format = weechat_config_string (
buflist_config_format_hotlist_level_none);
ptr_hotlist_priority = hotlist_priority_none;
if (ptr_hotlist)
{
priority = weechat_hdata_integer (buflist_hdata_hotlist,
ptr_hotlist, "priority");
if ((priority >= 0) && (priority < 4))
{
ptr_hotlist_format = weechat_config_string (
buflist_config_format_hotlist_level[priority]);
ptr_hotlist_priority = hotlist_priority[priority];
}
}
weechat_hashtable_set (buflist_hashtable_extra_vars,
"color_hotlist", ptr_hotlist_format);
weechat_hashtable_set (buflist_hashtable_extra_vars,
"hotlist_priority", ptr_hotlist_priority);
str_hotlist = NULL;
if (ptr_hotlist)
{
hotlist = weechat_string_dyn_alloc (64);
if (hotlist)
{
for (j = 3; j >= 0; j--)
{
snprintf (str_hotlist_count, sizeof (str_hotlist_count),
"%02d|count", j);
count = weechat_hdata_integer (buflist_hdata_hotlist,
ptr_hotlist,
str_hotlist_count);
if (count > 0)
{
if (*hotlist[0])
{
weechat_string_dyn_concat (
hotlist,
weechat_config_string (
buflist_config_format_hotlist_separator));
}
weechat_string_dyn_concat (
hotlist,
weechat_config_string (
buflist_config_format_hotlist_level[j]));
snprintf (str_hotlist_count, sizeof (str_hotlist_count),
"%d", count);
weechat_string_dyn_concat (hotlist, str_hotlist_count);
}
}
str_hotlist = *hotlist;
weechat_string_dyn_free (hotlist, 0);
}
}
weechat_hashtable_set (
buflist_hashtable_extra_vars,
"format_hotlist",
(str_hotlist) ? buflist_config_format_hotlist_eval : "");
weechat_hashtable_set (buflist_hashtable_extra_vars,
"hotlist",
(str_hotlist) ? str_hotlist : "");
if (str_hotlist)
free (str_hotlist);
/* lag */
ptr_lag = weechat_buffer_get_string (ptr_buffer, "localvar_lag");
if (ptr_lag && ptr_lag[0])
{
weechat_hashtable_set (
buflist_hashtable_extra_vars,
"format_lag",
weechat_config_string (buflist_config_format_lag));
}
else
{
weechat_hashtable_set (buflist_hashtable_extra_vars,
"format_lag", "");
}
/* check condition: if false, the buffer is not displayed */
condition = weechat_string_eval_expression (
weechat_config_string (buflist_config_look_display_conditions),
buflist_hashtable_pointers,
buflist_hashtable_extra_vars,
buflist_hashtable_options_conditions);
rc = (condition && (strcmp (condition, "1") == 0));
if (condition)
free (condition);
if (!rc)
continue;
/* add buffer in list */
weechat_arraylist_add (buflist_list_buffers[item_index], ptr_buffer);
/* set some other variables */
if (current_buffer)
line_number_current_buffer = line_number;
prev_number = number;
/* add newline between each buffer (if needed) */
if (weechat_config_boolean (buflist_config_look_add_newline)
&& *buflist[0])
{
if (!weechat_string_dyn_concat (buflist, "\n"))
goto error;
}
/* build string */
line = weechat_string_eval_expression (
(current_buffer) ? ptr_format_current : ptr_format,
buflist_hashtable_pointers,
buflist_hashtable_extra_vars,
NULL);
/* concatenate string */
rc = weechat_string_dyn_concat (buflist, line);
free (line);
if (!rc)
goto error;
line_number++;
}
str_buflist = *buflist;
goto end;
error:
str_buflist = NULL;
end:
weechat_string_dyn_free (buflist, 0);
weechat_arraylist_free (buffers);
if ((line_number_current_buffer != old_line_number_current_buffer[item_index])
&& (weechat_config_integer (buflist_config_look_auto_scroll) >= 0))
{
ptr_item_name = weechat_hdata_string (buflist_hdata_bar_item,
item, "name");
buflist_bar_item_auto_scroll (ptr_item_name,
line_number_current_buffer);
}
old_line_number_current_buffer[item_index] = line_number_current_buffer;
return str_buflist;
}
/*
* Initializes buflist bar items.
*
* Returns:
* 1: OK
* 0: error
*/
int
buflist_bar_item_init ()
{
int i;
/* create hashtables used by the bar item callback */
buflist_hashtable_pointers = weechat_hashtable_new (
32,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_POINTER,
NULL,
NULL);
if (!buflist_hashtable_pointers)
return 0;
buflist_hashtable_extra_vars = weechat_hashtable_new (
128,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL,
NULL);
if (!buflist_hashtable_extra_vars)
{
weechat_hashtable_free (buflist_hashtable_pointers);
return 0;
}
buflist_hashtable_options_conditions = weechat_hashtable_new (
32,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL, NULL);
if (!buflist_hashtable_options_conditions)
{
weechat_hashtable_free (buflist_hashtable_pointers);
weechat_hashtable_free (buflist_hashtable_extra_vars);
return 0;
}
weechat_hashtable_set (buflist_hashtable_options_conditions,
"type", "condition");
/* bar items */
for (i = 0; i < BUFLIST_BAR_NUM_ITEMS; i++)
{
buflist_list_buffers[i] = NULL;
old_line_number_current_buffer[i] = -1;
buflist_bar_item_buflist[i] = weechat_bar_item_new (
buflist_bar_item_get_name (i),
&buflist_bar_item_buflist_cb,
(const void *)((unsigned long)i), NULL);
}
return 1;
}
/*
* Ends buflist bar items.
*/
void
buflist_bar_item_end ()
{
int i;
for (i = 0; i < BUFLIST_BAR_NUM_ITEMS; i++)
{
weechat_bar_item_remove (buflist_bar_item_buflist[i]);
}
weechat_hashtable_free (buflist_hashtable_pointers);
buflist_hashtable_pointers = NULL;
weechat_hashtable_free (buflist_hashtable_extra_vars);
buflist_hashtable_extra_vars = NULL;
weechat_hashtable_free (buflist_hashtable_options_conditions);
buflist_hashtable_options_conditions = NULL;
for (i = 0; i < BUFLIST_BAR_NUM_ITEMS; i++)
{
if (buflist_list_buffers[i])
{
weechat_arraylist_free (buflist_list_buffers[i]);
buflist_list_buffers[i] = NULL;
}
}
}