diff --git a/.weechat/autosort.conf b/.weechat/autosort.conf new file mode 100644 index 0000000..430ff3d --- /dev/null +++ b/.weechat/autosort.conf @@ -0,0 +1,11 @@ +# +# weechat -- autosort.conf +# + +[sorting] +case_sensitive = off +group_irc = on +replacements = "[["##", "#"]]" +rules = "[["core", 0], ["irc", 2], ["*", 1], ["irc.irc_raw", 0], ["irc.server", 1], ["irc.server.*.&*", 0], ["irc.server.*.&*", 0], ["irc.server.*.#*", 1], ["irc.server.*.\\*status", 2]]" +signals = "buffer_opened buffer_merged buffer_unmerged buffer_renamed" +sort_on_config_change = on diff --git a/.weechat/buffers.conf b/.weechat/buffers.conf new file mode 100644 index 0000000..dd7a6a0 --- /dev/null +++ b/.weechat/buffers.conf @@ -0,0 +1,73 @@ +# +# weechat -- buffers.conf +# + +[color] +current_bg = red +current_fg = lightcyan +default_bg = default +default_fg = default +hotlist_highlight_bg = default +hotlist_highlight_fg = magenta +hotlist_low_bg = default +hotlist_low_fg = white +hotlist_message_bg = default +hotlist_message_fg = yellow +hotlist_private_bg = default +hotlist_private_fg = lightgreen +none_channel_bg = default +none_channel_fg = default +number = lightgreen +number_char = lightgreen +prefix_bufname = default +queries_default_bg = default +queries_default_fg = default +queries_highlight_bg = default +queries_highlight_fg = default +queries_message_bg = default +queries_message_fg = default +suffix_bufname = default +whitelist_default_bg = default +whitelist_default_fg = default +whitelist_highlight_bg = default +whitelist_highlight_fg = default +whitelist_low_bg = default +whitelist_low_fg = default +whitelist_message_bg = default +whitelist_message_fg = default +whitelist_private_bg = default +whitelist_private_fg = default + +[look] +core_to_front = off +detach = 600 +detach_buffer_immediately = "" +detach_buffer_immediately_level = 2 +detach_display_window_number = off +detach_displayed_buffers = on +detach_free_content = off +detach_query = off +hide_merged_buffers = server +hotlist_counter = off +immune_detach_buffers = "" +indenting = on +indenting_amount = 2 +indenting_number = on +jump_prev_next_visited_buffer = off +mark_inactive = off +mouse_move_buffer = on +mouse_wheel = on +name_crop_suffix = "+" +name_size_max = 0 +number_char = "." +prefix = off +prefix_bufname = "" +prefix_empty = on +prefix_for_query = "" +short_names = on +show_lag = off +show_number = on +sort = number +suffix_bufname = "" +toggle_bar = on +whitelist_buffers = "" diff --git a/.weechat/colorize_nicks.conf b/.weechat/colorize_nicks.conf new file mode 100644 index 0000000..f0f12ec --- /dev/null +++ b/.weechat/colorize_nicks.conf @@ -0,0 +1,12 @@ +# +# weechat -- colorize_nicks.conf +# + +[look] +blacklist_channels = "" +blacklist_nicks = "so,root" +colorize_input = off +greedy_matching = on +ignore_nicks_in_urls = off +ignore_tags = "" +min_nick_length = 2 diff --git a/.weechat/irc.conf b/.weechat/irc.conf index 836157b..54b1497 100644 --- a/.weechat/irc.conf +++ b/.weechat/irc.conf @@ -5,7 +5,7 @@ [look] buffer_open_before_autojoin = on buffer_open_before_join = off -buffer_switch_autojoin = on +buffer_switch_autojoin = off buffer_switch_join = on color_nicks_in_names = off color_nicks_in_nicklist = off @@ -48,7 +48,7 @@ part_closes_buffer = off pv_buffer = independent pv_tags = "notify_private" raw_messages = 256 -server_buffer = merge_with_core +server_buffer = independent smart_filter = on smart_filter_delay = 5 smart_filter_join = on @@ -180,3 +180,42 @@ pivotal.msg_kick pivotal.msg_part pivotal.msg_quit pivotal.notify +mozilla.addresses = "irc.mozilla.org/6697" +mozilla.proxy +mozilla.ipv6 +mozilla.ssl = on +mozilla.ssl_cert +mozilla.ssl_priorities +mozilla.ssl_dhkey_size +mozilla.ssl_fingerprint +mozilla.ssl_verify +mozilla.password +mozilla.capabilities +mozilla.sasl_mechanism +mozilla.sasl_username +mozilla.sasl_password +mozilla.sasl_key +mozilla.sasl_timeout +mozilla.sasl_fail +mozilla.autoconnect = on +mozilla.autoreconnect +mozilla.autoreconnect_delay +mozilla.nicks = "kejadlen" +mozilla.nicks_alternate +mozilla.username = "kejadlen" +mozilla.realname +mozilla.local_hostname +mozilla.command +mozilla.command_delay +mozilla.autojoin = "#rust,#rust-beginners" +mozilla.autorejoin +mozilla.autorejoin_delay +mozilla.connection_timeout +mozilla.anti_flood_prio_high +mozilla.anti_flood_prio_low +mozilla.away_check +mozilla.away_check_max_nicks +mozilla.msg_kick +mozilla.msg_part +mozilla.msg_quit +mozilla.notify diff --git a/.weechat/iset.conf b/.weechat/iset.conf new file mode 100644 index 0000000..cafe04f --- /dev/null +++ b/.weechat/iset.conf @@ -0,0 +1,30 @@ +# +# weechat -- iset.conf +# + +[color] +bg_selected = red +help_default_value = green +help_option_name = white +help_text = default +option = default +option_selected = white +type = brown +type_selected = yellow +value = cyan +value_diff = magenta +value_diff_selected = lightmagenta +value_selected = lightcyan +value_undef = green +value_undef_selected = lightgreen + +[help] +show_help_bar = on +show_help_extra_info = on +show_plugin_description = off + +[look] +scroll_horiz = 10 +show_current_line = on +use_mute = off +value_search_char = "=" diff --git a/.weechat/perl/autoload/buffers.pl b/.weechat/perl/autoload/buffers.pl new file mode 120000 index 0000000..445dc3c --- /dev/null +++ b/.weechat/perl/autoload/buffers.pl @@ -0,0 +1 @@ +../buffers.pl \ No newline at end of file diff --git a/.weechat/perl/autoload/highmon.pl b/.weechat/perl/autoload/highmon.pl new file mode 120000 index 0000000..2eb5e1e --- /dev/null +++ b/.weechat/perl/autoload/highmon.pl @@ -0,0 +1 @@ +../highmon.pl \ No newline at end of file diff --git a/.weechat/perl/autoload/iset.pl b/.weechat/perl/autoload/iset.pl new file mode 120000 index 0000000..2746e0d --- /dev/null +++ b/.weechat/perl/autoload/iset.pl @@ -0,0 +1 @@ +../iset.pl \ No newline at end of file diff --git a/.weechat/perl/buffers.pl b/.weechat/perl/buffers.pl new file mode 100644 index 0000000..73eb4b5 --- /dev/null +++ b/.weechat/perl/buffers.pl @@ -0,0 +1,1840 @@ +# +# Copyright (C) 2008-2014 Sebastien Helleu +# Copyright (C) 2011-2013 Nils G +# +# This program 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. +# +# This program 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 this program. If not, see . +# +# +# Display sidebar with list of buffers. +# +# History: +# +# 2016-05-01, mumixam : +# v5.4: added option "detach_buffer_immediately_level" +# 2015-08-21, Matthew Cox +# v5.3: add option "indenting_amount", to adjust the indenting of channel buffers +# 2015-05-02, arza : +# v5.2: truncate long names (name_size_max) more when mark_inactive adds parenthesis +# 2015-03-29, Ed Santiago : +# v5.1: merged buffers: always indent, except when filling is horizontal +# 2014-12-12 +# v5.0: fix cropping non-latin buffer names +# 2014-08-29, Patrick Steinhardt : +# v4.9: add support for specifying custom buffer names +# 2014-07-19, Sebastien Helleu : +# v4.8: add support of ctrl + mouse wheel to jump to previous/next buffer, +# new option "mouse_wheel" +# 2014-06-22, Sebastien Helleu : +# v4.7: fix typos in options +# 2014-04-05, Sebastien Helleu : +# v4.6: add support of hidden buffers (WeeChat >= 0.4.4) +# 2014-01-01, Sebastien Helleu : +# v4.5: add option "mouse_move_buffer" +# 2013-12-11, Sebastien Helleu : +# v4.4: fix buffer number on drag to the end of list when option +# weechat.look.buffer_auto_renumber is off +# 2013-12-10, nils_2@freenode.#weechat: +# v4.3: add options "prefix_bufname" and "suffix_bufname (idea by silverd) +# : fix hook_timer() for show_lag wasn't disabled +# : improved signal handling (less updating of buffers list) +# 2013-11-07, Sebastien Helleu : +# v4.2: use default filling "columns_vertical" when bar position is top/bottom +# 2013-10-31, nils_2@freenode.#weechat: +# v4.1: add option "detach_buffer_immediately" (idea by farn) +# 2013-10-20, nils_2@freenode.#weechat: +# v4.0: add options "detach_displayed_buffers", "detach_display_window_number" +# 2013-09-27, nils_2@freenode.#weechat: +# v3.9: add option "toggle_bar" and option "show_prefix_query" (idea by IvarB) +# : fix problem with linefeed at end of list of buffers (reported by grawity) +# 2012-10-18, nils_2@freenode.#weechat: +# v3.8: add option "mark_inactive", to mark buffers you are not in (idea by xrdodrx) +# : add wildcard "*" for immune_detach_buffers (idea by StarWeaver) +# : add new options "detach_query" and "detach_free_content" (idea by StarWeaver) +# 2012-10-06, Nei : +# v3.7: call menu on right mouse if menu script is loaded. +# 2012-10-06, nils_2 : +# v3.6: add new option "hotlist_counter" (idea by torque). +# 2012-06-02, nils_2 : +# v3.5: add values "server|channel|private|all|keepserver|none" to option "hide_merged_buffers" (suggested by dominikh). +# 2012-05-25, nils_2 : +# v3.4: add new option "show_lag". +# 2012-04-07, Sebastien Helleu : +# v3.3: fix truncation of wide chars in buffer name (option name_size_max) (bug #36034) +# 2012-03-15, nils_2 : +# v3.2: add new option "detach"(weechat >= 0.3.8) +# add new option "immune_detach_buffers" (requested by Mkaysi) +# add new function buffers_whitelist add|del|reset (suggested by FiXato) +# add new function buffers_detach add|del|reset +# 2012-03-09, Sebastien Helleu : +# v3.1: fix reload of config file +# 2012-01-29, nils_2 : +# v3.0: fix: buffers did not update directly during window_switch (reported by FiXato) +# 2012-01-29, nils_2 : +# v2.9: add options "name_size_max" and "name_crop_suffix" +# 2012-01-08, nils_2 : +# v2.8: fix indenting for option "show_number off" +# fix unset of buffer activity in hotlist when buffer was moved with mouse +# add buffer with free content and core buffer sorted first (suggested by nyuszika7h) +# add options queries_default_fg/bg and queries_message_fg/bg (suggested by FiXato) +# add clicking with left button on current buffer will do a jump_previously_visited_buffer (suggested by FiXato) +# add clicking with right button on current buffer will do a jump_next_visited_buffer +# add additional informations in help texts +# add default_fg and default_bg for whitelist channels +# internal changes (script is now 3Kb smaller) +# 2012-01-04, Sebastien Helleu : +# v2.7: fix regex lookup in whitelist buffers list +# 2011-12-04, nils_2 : +# v2.6: add own config file (buffers.conf) +# add new behavior for indenting (under_name) +# add new option to set different color for server buffers and buffers with free content +# 2011-10-30, nils_2 : +# v2.5: add new options "show_number_char" and "color_number_char", +# add help-description for options +# 2011-08-24, Sebastien Helleu : +# v2.4: add mouse support +# 2011-06-06, nils_2 : +# v2.3: added: missed option "color_whitelist_default" +# 2011-03-23, Sebastien Helleu : +# v2.2: fix color of nick prefix with WeeChat >= 0.3.5 +# 2011-02-13, nils_2 : +# v2.1: add options "color_whitelist_*" +# 2010-10-05, Sebastien Helleu : +# v2.0: add options "sort" and "show_number" +# 2010-04-12, Sebastien Helleu : +# v1.9: replace call to log() by length() to align buffer numbers +# 2010-04-02, Sebastien Helleu : +# v1.8: fix bug with background color and option indenting_number +# 2010-04-02, Helios : +# v1.7: add indenting_number option +# 2010-02-25, m4v : +# v1.6: add option to hide empty prefixes +# 2010-02-12, Sebastien Helleu : +# v1.5: add optional nick prefix for buffers like IRC channels +# 2009-09-30, Sebastien Helleu : +# v1.4: remove spaces for indenting when bar position is top/bottom +# 2009-06-14, Sebastien Helleu : +# v1.3: add option "hide_merged_buffers" +# 2009-06-14, Sebastien Helleu : +# v1.2: improve display with merged buffers +# 2009-05-02, Sebastien Helleu : +# v1.1: sync with last API changes +# 2009-02-21, Sebastien Helleu : +# v1.0: remove timer used to update bar item first time (not needed any more) +# 2009-02-17, Sebastien Helleu : +# v0.9: fix bug with indenting of private buffers +# 2009-01-04, Sebastien Helleu : +# v0.8: update syntax for command /set (comments) +# 2008-10-20, Jiri Golembiovsky : +# v0.7: add indenting option +# 2008-10-01, Sebastien Helleu : +# v0.6: add default color for buffers, and color for current active buffer +# 2008-09-18, Sebastien Helleu : +# v0.5: fix color for "low" level entry in hotlist +# 2008-09-18, Sebastien Helleu : +# v0.4: rename option "show_category" to "short_names", +# remove option "color_slash" +# 2008-09-15, Sebastien Helleu : +# v0.3: fix bug with priority in hotlist (var not defined) +# 2008-09-02, Sebastien Helleu : +# v0.2: add color for buffers with activity and config options for +# colors, add config option to display/hide categories +# 2008-03-15, Sebastien Helleu : +# v0.1: script creation +# +# Help about settings: +# display all settings for script (or use iset.pl script to change settings): +# /set buffers* +# show help text for option buffers.look.whitelist_buffers: +# /help buffers.look.whitelist_buffers +# +# Mouse-support (standard key bindings): +# left mouse-button: +# - click on a buffer to switch to selected buffer +# - click on current buffer will do action jump_previously_visited_buffer +# - drag a buffer and drop it on another position will move the buffer to position +# right mouse-button: +# - click on current buffer will do action jump_next_visited_buffer +# - moving buffer to the left/right will close buffer. +# + +use strict; +use Encode qw( decode encode ); +# -----------------------------[ internal ]------------------------------------- +my $SCRIPT_NAME = "buffers"; +my $SCRIPT_VERSION = "5.4"; + +my $BUFFERS_CONFIG_FILE_NAME = "buffers"; +my $buffers_config_file; +my $cmd_buffers_whitelist= "buffers_whitelist"; +my $cmd_buffers_detach = "buffers_detach"; + +my $maxlength; + +my %mouse_keys = ("\@item(buffers):button1*" => "hsignal:buffers_mouse", + "\@item(buffers):button2*" => "hsignal:buffers_mouse", + "\@bar(buffers):ctrl-wheelup" => "hsignal:buffers_mouse", + "\@bar(buffers):ctrl-wheeldown" => "hsignal:buffers_mouse"); +my %options; +my %hotlist_level = (0 => "low", 1 => "message", 2 => "private", 3 => "highlight"); +my @whitelist_buffers = (); +my @immune_detach_buffers= (); +my @detach_buffer_immediately= (); +my @buffers_focus = (); +my %buffers_timer = (); +my %Hooks = (); + +# --------------------------------[ init ]-------------------------------------- +weechat::register($SCRIPT_NAME, "Sebastien Helleu ", + $SCRIPT_VERSION, "GPL3", + "Sidebar with list of buffers", "shutdown_cb", ""); +my $weechat_version = weechat::info_get("version_number", "") || 0; + +buffers_config_init(); +buffers_config_read(); + +weechat::bar_item_new($SCRIPT_NAME, "build_buffers", ""); +weechat::bar_new($SCRIPT_NAME, "0", "0", "root", "", "left", "columns_vertical", + "vertical", "0", "0", "default", "default", "default", "1", + $SCRIPT_NAME); + +if ( check_bar_item() == 0 ) +{ + weechat::command("", "/bar show " . $SCRIPT_NAME) if ( weechat::config_boolean($options{"toggle_bar"}) eq 1 ); +} + +weechat::hook_signal("buffer_opened", "buffers_signal_buffer", ""); +weechat::hook_signal("buffer_closed", "buffers_signal_buffer", ""); +weechat::hook_signal("buffer_merged", "buffers_signal_buffer", ""); +weechat::hook_signal("buffer_unmerged", "buffers_signal_buffer", ""); +weechat::hook_signal("buffer_moved", "buffers_signal_buffer", ""); +weechat::hook_signal("buffer_renamed", "buffers_signal_buffer", ""); +weechat::hook_signal("buffer_switch", "buffers_signal_buffer", ""); +weechat::hook_signal("buffer_hidden", "buffers_signal_buffer", ""); # WeeChat >= 0.4.4 +weechat::hook_signal("buffer_unhidden", "buffers_signal_buffer", ""); # WeeChat >= 0.4.4 +weechat::hook_signal("buffer_localvar_added", "buffers_signal_buffer", ""); +weechat::hook_signal("buffer_localvar_changed", "buffers_signal_buffer", ""); + +weechat::hook_signal("window_switch", "buffers_signal_buffer", ""); +weechat::hook_signal("hotlist_changed", "buffers_signal_hotlist", ""); +#weechat::hook_command_run("/input switch_active_*", "buffers_signal_buffer", ""); +weechat::bar_item_update($SCRIPT_NAME); + + +if ($weechat_version >= 0x00030600) +{ + weechat::hook_focus($SCRIPT_NAME, "buffers_focus_buffers", ""); + weechat::hook_hsignal("buffers_mouse", "buffers_hsignal_mouse", ""); + weechat::key_bind("mouse", \%mouse_keys); +} + +weechat::hook_command($cmd_buffers_whitelist, + "add/del current buffer to/from buffers whitelist", + "[add] || [del] || [reset]", + " add: add current buffer in configuration file\n". + " del: delete current buffer from configuration file\n". + "reset: reset all buffers from configuration file ". + "(no confirmation!)\n\n". + "Examples:\n". + "/$cmd_buffers_whitelist add\n", + "add %-||". + "del %-||". + "reset %-", + "buffers_cmd_whitelist", ""); +weechat::hook_command($cmd_buffers_detach, + "add/del current buffer to/from buffers detach", + "[add] || [del] || [reset]", + " add: add current buffer in configuration file\n". + " del: delete current buffer from configuration file\n". + "reset: reset all buffers from configuration file ". + "(no confirmation!)\n\n". + "Examples:\n". + "/$cmd_buffers_detach add\n", + "add %-||". + "del %-||". + "reset %-", + "buffers_cmd_detach", ""); + +if ($weechat_version >= 0x00030800) +{ + weechat::hook_config("buffers.look.detach", "hook_timer_detach", ""); + if (weechat::config_integer($options{"detach"}) > 0) + { + $Hooks{timer_detach} = weechat::hook_timer(weechat::config_integer($options{"detach"}) * 1000, + 60, 0, "buffers_signal_hotlist", ""); + } +} + +weechat::hook_config("buffers.look.show_lag", "hook_timer_lag", ""); + +if (weechat::config_boolean($options{"show_lag"})) +{ + $Hooks{timer_lag} = weechat::hook_timer( + weechat::config_integer(weechat::config_get("irc.network.lag_refresh_interval")) * 1000, + 0, 0, "buffers_signal_hotlist", ""); +} + +# -------------------------------- [ command ] -------------------------------- +sub buffers_cmd_whitelist +{ +my ( $data, $buffer, $args ) = @_; + $args = lc($args); + my $buffers_whitelist = weechat::config_string( weechat::config_get("buffers.look.whitelist_buffers") ); + return weechat::WEECHAT_RC_OK if ( $buffers_whitelist eq "" and $args eq "del" or $buffers_whitelist eq "" and $args eq "reset" ); + my @buffers_list = split( /,/, $buffers_whitelist ); + # get buffers name + my $infolist = weechat::infolist_get("buffer", weechat::current_buffer(), ""); + weechat::infolist_next($infolist); + my $buffers_name = weechat::infolist_string($infolist, "name"); + weechat::infolist_free($infolist); + return weechat::WEECHAT_RC_OK if ( $buffers_name eq "" ); # should never happen + + if ( $args eq "add" ) + { + return weechat::WEECHAT_RC_OK if ( grep /^$buffers_name$/, @buffers_list ); # check if buffer already in list + push @buffers_list, ( $buffers_name ); + my $buffers_list = &create_whitelist(\@buffers_list); + weechat::config_option_set( weechat::config_get("buffers.look.whitelist_buffers"), $buffers_list, 1); + weechat::print(weechat::current_buffer(), "buffer \"$buffers_name\" added to buffers whitelist"); + } + elsif ( $args eq "del" ) + { + return weechat::WEECHAT_RC_OK unless ( grep /^$buffers_name$/, @buffers_list ); # check if buffer is in list + @buffers_list = grep {$_ ne $buffers_name} @buffers_list; # delete entry + my $buffers_list = &create_whitelist(\@buffers_list); + weechat::config_option_set( weechat::config_get("buffers.look.whitelist_buffers"), $buffers_list, 1); + weechat::print(weechat::current_buffer(), "buffer \"$buffers_name\" deleted from buffers whitelist"); + } + elsif ( $args eq "reset" ) + { + return weechat::WEECHAT_RC_OK if ( $buffers_whitelist eq "" ); + weechat::config_option_set( weechat::config_get("buffers.look.whitelist_buffers"), "", 1); + weechat::print(weechat::current_buffer(), "buffers whitelist is empty, now..."); + } + return weechat::WEECHAT_RC_OK; +} +sub buffers_cmd_detach +{ + my ( $data, $buffer, $args ) = @_; + $args = lc($args); + my $immune_detach_buffers = weechat::config_string( weechat::config_get("buffers.look.immune_detach_buffers") ); + return weechat::WEECHAT_RC_OK if ( $immune_detach_buffers eq "" and $args eq "del" or $immune_detach_buffers eq "" and $args eq "reset" ); + + my @buffers_list = split( /,/, $immune_detach_buffers ); + # get buffers name + my $infolist = weechat::infolist_get("buffer", weechat::current_buffer(), ""); + weechat::infolist_next($infolist); + my $buffers_name = weechat::infolist_string($infolist, "name"); + weechat::infolist_free($infolist); + return weechat::WEECHAT_RC_OK if ( $buffers_name eq "" ); # should never happen + + if ( $args eq "add" ) + { + return weechat::WEECHAT_RC_OK if ( grep /^$buffers_name$/, @buffers_list ); # check if buffer already in list + push @buffers_list, ( $buffers_name ); + my $buffers_list = &create_whitelist(\@buffers_list); + weechat::config_option_set( weechat::config_get("buffers.look.immune_detach_buffers"), $buffers_list, 1); + weechat::print(weechat::current_buffer(), "buffer \"$buffers_name\" added to immune detach buffers"); + } + elsif ( $args eq "del" ) + { + return weechat::WEECHAT_RC_OK unless ( grep /^$buffers_name$/, @buffers_list ); # check if buffer is in list + @buffers_list = grep {$_ ne $buffers_name} @buffers_list; # delete entry + my $buffers_list = &create_whitelist(\@buffers_list); + weechat::config_option_set( weechat::config_get("buffers.look.immune_detach_buffers"), $buffers_list, 1); + weechat::print(weechat::current_buffer(), "buffer \"$buffers_name\" deleted from immune detach buffers"); + } + elsif ( $args eq "reset" ) + { + return weechat::WEECHAT_RC_OK if ( $immune_detach_buffers eq "" ); + weechat::config_option_set( weechat::config_get("buffers.look.immune_detach_buffers"), "", 1); + weechat::print(weechat::current_buffer(), "immune detach buffers is empty, now..."); + } + return weechat::WEECHAT_RC_OK; +} + +sub create_whitelist +{ + my @buffers_list = @{$_[0]}; + my $buffers_list = ""; + foreach (@buffers_list) + { + $buffers_list .= $_ .","; + } + # remove last "," + chop $buffers_list; + return $buffers_list; +} + +# -------------------------------- [ config ] -------------------------------- +sub hook_timer_detach +{ + my $detach = $_[2]; + if ( $detach eq 0 ) + { + weechat::unhook($Hooks{timer_detach}) if $Hooks{timer_detach}; + $Hooks{timer_detach} = ""; + } + else + { + weechat::unhook($Hooks{timer_detach}) if $Hooks{timer_detach}; + $Hooks{timer_detach} = weechat::hook_timer( weechat::config_integer( $options{"detach"}) * 1000, 60, 0, "buffers_signal_hotlist", ""); + } + weechat::bar_item_update($SCRIPT_NAME); + return weechat::WEECHAT_RC_OK; +} + +sub hook_timer_lag +{ + my $lag = $_[2]; + if ( $lag eq "off" ) + { + weechat::unhook($Hooks{timer_lag}) if $Hooks{timer_lag}; + $Hooks{timer_lag} = ""; + } + else + { + weechat::unhook($Hooks{timer_lag}) if $Hooks{timer_lag}; + $Hooks{timer_lag} = weechat::hook_timer( weechat::config_integer(weechat::config_get("irc.network.lag_refresh_interval")) * 1000, 0, 0, "buffers_signal_hotlist", ""); + } + weechat::bar_item_update($SCRIPT_NAME); + return weechat::WEECHAT_RC_OK; +} + +sub buffers_config_read +{ + return weechat::config_read($buffers_config_file) if ($buffers_config_file ne ""); +} +sub buffers_config_write +{ + return weechat::config_write($buffers_config_file) if ($buffers_config_file ne ""); +} +sub buffers_config_reload_cb +{ + my ($data, $config_file) = ($_[0], $_[1]); + return weechat::config_reload($config_file) +} +sub buffers_config_init +{ + $buffers_config_file = weechat::config_new($BUFFERS_CONFIG_FILE_NAME, + "buffers_config_reload_cb", ""); + return if ($buffers_config_file eq ""); + +my %default_options_color = +("color_current_fg" => [ + "current_fg", "color", + "foreground color for current buffer", + "", 0, 0, "lightcyan", "lightcyan", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_current_bg" => [ + "current_bg", "color", + "background color for current buffer", + "", 0, 0, "red", "red", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_default_fg" => [ + "default_fg", "color", + "default foreground color for buffer name", + "", 0, 0, "default", "default", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_default_bg" => [ + "default_bg", "color", + "default background color for buffer name", + "", 0, 0, "default", "default", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_hotlist_highlight_fg" => [ + "hotlist_highlight_fg", "color", + "change foreground color of buffer name if a highlight messaged received", + "", 0, 0, "magenta", "magenta", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_hotlist_highlight_bg" => [ + "hotlist_highlight_bg", "color", + "change background color of buffer name if a highlight messaged received", + "", 0, 0, "default", "default", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_hotlist_low_fg" => [ + "hotlist_low_fg", "color", + "change foreground color of buffer name if a low message received", + "", 0, 0, "white", "white", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_hotlist_low_bg" => [ + "hotlist_low_bg", "color", + "change background color of buffer name if a low message received", + "", 0, 0, "default", "default", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_hotlist_message_fg" => [ + "hotlist_message_fg", "color", + "change foreground color of buffer name if a normal message received", + "", 0, 0, "yellow", "yellow", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_hotlist_message_bg" => [ + "hotlist_message_bg", "color", + "change background color of buffer name if a normal message received", + "", 0, 0, "default", "default", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_hotlist_private_fg" => [ + "hotlist_private_fg", "color", + "change foreground color of buffer name if a private message received", + "", 0, 0, "lightgreen", "lightgreen", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_hotlist_private_bg" => [ + "hotlist_private_bg", "color", + "change background color of buffer name if a private message received", + "", 0, 0, "default", "default", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_number" => [ + "number", "color", + "color for buffer number", + "", 0, 0, "lightgreen", "lightgreen", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_number_char" => [ + "number_char", "color", + "color for buffer number char", + "", 0, 0, "lightgreen", "lightgreen", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_whitelist_default_fg" => [ + "whitelist_default_fg", "color", + "default foreground color for whitelist buffer name", + "", 0, 0, "", "", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_whitelist_default_bg" => [ + "whitelist_default_bg", "color", + "default background color for whitelist buffer name", + "", 0, 0, "", "", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_whitelist_low_fg" => [ + "whitelist_low_fg", "color", + "low color of whitelist buffer name", + "", 0, 0, "", "", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_whitelist_low_bg" => [ + "whitelist_low_bg", "color", + "low color of whitelist buffer name", + "", 0, 0, "", "", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_whitelist_message_fg" => [ + "whitelist_message_fg", "color", + "message color of whitelist buffer name", + "", 0, 0, "", "", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_whitelist_message_bg" => [ + "whitelist_message_bg", "color", + "message color of whitelist buffer name", + "", 0, 0, "", "", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_whitelist_private_fg" => [ + "whitelist_private_fg", "color", + "private color of whitelist buffer name", + "", 0, 0, "", "", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_whitelist_private_bg" => [ + "whitelist_private_bg", "color", + "private color of whitelist buffer name", + "", 0, 0, "", "", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_whitelist_highlight_fg" => [ + "whitelist_highlight_fg", "color", + "highlight color of whitelist buffer name", + "", 0, 0, "", "", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_whitelist_highlight_bg" => [ + "whitelist_highlight_bg", "color", + "highlight color of whitelist buffer name", + "", 0, 0, "", "", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_none_channel_fg" => [ + "none_channel_fg", "color", + "foreground color for none channel buffer (e.g.: core/server/plugin ". + "buffer)", + "", 0, 0, "default", "default", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_none_channel_bg" => [ + "none_channel_bg", "color", + "background color for none channel buffer (e.g.: core/server/plugin ". + "buffer)", + "", 0, 0, "default", "default", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "queries_default_fg" => [ + "queries_default_fg", "color", + "foreground color for query buffer without message", + "", 0, 0, "default", "default", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "queries_default_bg" => [ + "queries_default_bg", "color", + "background color for query buffer without message", + "", 0, 0, "default", "default", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "queries_message_fg" => [ + "queries_message_fg", "color", + "foreground color for query buffer with unread message", + "", 0, 0, "default", "default", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "queries_message_bg" => [ + "queries_message_bg", "color", + "background color for query buffer with unread message", + "", 0, 0, "default", "default", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "queries_highlight_fg" => [ + "queries_highlight_fg", "color", + "foreground color for query buffer with unread highlight", + "", 0, 0, "default", "default", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "queries_highlight_bg" => [ + "queries_highlight_bg", "color", + "background color for query buffer with unread highlight", + "", 0, 0, "default", "default", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_prefix_bufname" => [ + "prefix_bufname", "color", + "color for prefix of buffer name", + "", 0, 0, "default", "default", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "color_suffix_bufname" => [ + "suffix_bufname", "color", + "color for suffix of buffer name", + "", 0, 0, "default", "default", 0, + "", "", "buffers_signal_config", "", "", "" + ], +); + +my %default_options_look = +( + "hotlist_counter" => [ + "hotlist_counter", "boolean", + "show number of message for the buffer (this option needs WeeChat >= ". + "0.3.5). The relevant option for notification is \"weechat.look.". + "buffer_notify_default\"", + "", 0, 0, "off", "off", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "show_lag" => [ + "show_lag", "boolean", + "show lag behind server name. This option is using \"irc.color.". + "item_lag_finished\", ". + "\"irc.network.lag_min_show\" and \"irc.network.lag_refresh_interval\"", + "", 0, 0, "off", "off", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "look_whitelist_buffers" => [ + "whitelist_buffers", "string", + "comma separated list of buffers for using a different color scheme ". + "(for example: freenode.#weechat,freenode.#weechat-fr)", + "", 0, 0, "", "", 0, + "", "", "buffers_signal_config_whitelist", "", "", "" + ], + "hide_merged_buffers" => [ + "hide_merged_buffers", "integer", + "hide merged buffers. The value determines which merged buffers should ". + "be hidden, keepserver meaning 'all except server buffers'. Other values ". + "correspondent to the buffer type.", + "server|channel|private|keepserver|all|none", 0, 0, "none", "none", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "indenting" => [ + "indenting", "integer", "use indenting for channel and query buffers. ". + "This option only takes effect if bar is left/right positioned", + "off|on|under_name", 0, 0, "off", "off", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "indenting_number" => [ + "indenting_number", "boolean", + "use indenting for numbers. This option only takes effect if bar is ". + "left/right positioned", + "", 0, 0, "on", "on", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "indenting_amount" => [ + "indenting_amount", "integer", + "amount of indenting to use. This option only takes effect if bar ". + "is left/right positioned, and indenting is enabled", + "", 0, 16, 2, 2, 0, + "", "", "buffers_signal_config", "", "", "" + ], + "short_names" => [ + "short_names", "boolean", + "display short names (remove text before first \".\" in buffer name)", + "", 0, 0, "on", "on", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "show_number" => [ + "show_number", "boolean", + "display buffer number in front of buffer name", + "", 0, 0, "on", "on", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "show_number_char" => [ + "number_char", "string", + "display a char behind buffer number", + "", 0, 0, ".", ".", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "show_prefix_bufname" => [ + "prefix_bufname", "string", + "prefix displayed in front of buffer name", + "", 0, 0, "", "", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "show_suffix_bufname" => [ + "suffix_bufname", "string", + "suffix displayed at end of buffer name", + "", 0, 0, "", "", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "show_prefix" => [ + "prefix", "boolean", + "displays your prefix for channel in front of buffer name", + "", 0, 0, "off", "off", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "show_prefix_empty" => [ + "prefix_empty", "boolean", + "use a placeholder for channels without prefix", + "", 0, 0, "on", "on", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "show_prefix_query" => [ + "prefix_for_query", "string", + "prefix displayed in front of query buffer", + "", 0, 0, "", "", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "sort" => [ + "sort", "integer", + "sort buffer-list by \"number\" or \"name\"", + "number|name", 0, 0, "number", "number", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "core_to_front" => [ + "core_to_front", "boolean", + "core buffer and buffers with free content will be listed first. ". + "Take only effect if buffer sort is by name", + "", 0, 0, "off", "off", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "jump_prev_next_visited_buffer" => [ + "jump_prev_next_visited_buffer", "boolean", + "jump to previously or next visited buffer if you click with ". + "left/right mouse button on currently visiting buffer", + "", 0, 0, "off", "off", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "name_size_max" => [ + "name_size_max", "integer", + "maximum size of buffer name. 0 means no limitation", + "", 0, 256, 0, 0, 0, + "", "", "buffers_signal_config", "", "", "" + ], + "name_crop_suffix" => [ + "name_crop_suffix", "string", + "contains an optional char(s) that is appended when buffer name is ". + "shortened", + "", 0, 0, "+", "+", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "detach" => [ + "detach", "integer", + "detach buffer from buffers list after a specific period of time ". + "(in seconds) without action (weechat ≥ 0.3.8 required) (0 means \"off\")", + "", 0, 31536000, 0, "number", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "immune_detach_buffers" => [ + "immune_detach_buffers", "string", + "comma separated list of buffers to NOT automatically detach. ". + "Allows \"*\" wildcard. Ex: \"BitlBee,freenode.*\"", + "", 0, 0, "", "", 0, + "", "", "buffers_signal_config_immune_detach_buffers", "", "", "" + ], + "detach_query" => [ + "detach_query", "boolean", + "query buffer will be detached", + "", 0, 0, "off", "off", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "detach_buffer_immediately" => [ + "detach_buffer_immediately", "string", + "comma separated list of buffers to detach immediately. Buffers ". + "will attach again based on notify level set in ". + "\"detach_buffer_immediately_level\". Allows \"*\" wildcard. ". + "Ex: \"BitlBee,freenode.*\"", + "", 0, 0, "", "", 0, + "", "", "buffers_signal_config_detach_buffer_immediately", "", "", "" + ], + "detach_buffer_immediately_level" => [ + "detach_buffer_immediately_level", "integer", + "The value determines what notify level messages are reattached from activity. ". + " This option works in conjunction with \"detach_buffer_immediately\" ". + "0: low priority (like join/part messages), ". + "1: message, ". + "2: private, ". + "3: highlight", + "", 0, 3, 2, 2, 0, + "", "", "buffers_signal_config", "", "", "" + ], + "detach_free_content" => [ + "detach_free_content", "boolean", + "buffers with free content will be detached (Ex: iset, chanmon)", + "", 0, 0, "off", "off", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "detach_displayed_buffers" => [ + "detach_displayed_buffers", "boolean", + "buffers displayed in a (split) window will be detached", + "", 0, 0, "on", "on", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "detach_display_window_number" => [ + "detach_display_window_number", "boolean", + "window number will be add, behind buffer name (this option takes only ". + "effect with \"detach_displayed_buffers\" option)", + "", 0, 0, "off", "off", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "mark_inactive" => [ + "mark_inactive", "boolean", + "if option is \"on\", inactive buffers (those you are not in) will have ". + "parentheses around them. An inactive buffer will not be detached.", + "", 0, 0, "off", "off", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "toggle_bar" => [ + "toggle_bar", "boolean", + "if option is \"on\", buffers bar will hide/show when script is ". + "(un)loaded.", + "", 0, 0, "on", "on", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "mouse_move_buffer" => [ + "mouse_move_buffer", "boolean", + "if option is \"on\", mouse gestures (drag & drop) can move buffers in list.", + "", 0, 0, "on", "on", 0, + "", "", "buffers_signal_config", "", "", "" + ], + "mouse_wheel" => [ + "mouse_wheel", "boolean", + "if option is \"on\", mouse wheel jumps to previous/next buffer in list.", + "", 0, 0, "on", "on", 0, + "", "", "buffers_signal_config", "", "", "" + ], +); + # section "color" + my $section_color = weechat::config_new_section( + $buffers_config_file, + "color", 0, 0, "", "", "", "", "", "", "", "", "", ""); + if ($section_color eq "") + { + weechat::config_free($buffers_config_file); + return; + } + foreach my $option (keys %default_options_color) + { + $options{$option} = weechat::config_new_option( + $buffers_config_file, + $section_color, + $default_options_color{$option}[0], + $default_options_color{$option}[1], + $default_options_color{$option}[2], + $default_options_color{$option}[3], + $default_options_color{$option}[4], + $default_options_color{$option}[5], + $default_options_color{$option}[6], + $default_options_color{$option}[7], + $default_options_color{$option}[8], + $default_options_color{$option}[9], + $default_options_color{$option}[10], + $default_options_color{$option}[11], + $default_options_color{$option}[12], + $default_options_color{$option}[13], + $default_options_color{$option}[14]); + } + + # section "look" + my $section_look = weechat::config_new_section( + $buffers_config_file, + "look", 0, 0, "", "", "", "", "", "", "", "", "", ""); + if ($section_look eq "") + { + weechat::config_free($buffers_config_file); + return; + } + foreach my $option (keys %default_options_look) + { + $options{$option} = weechat::config_new_option( + $buffers_config_file, + $section_look, + $default_options_look{$option}[0], + $default_options_look{$option}[1], + $default_options_look{$option}[2], + $default_options_look{$option}[3], + $default_options_look{$option}[4], + $default_options_look{$option}[5], + $default_options_look{$option}[6], + $default_options_look{$option}[7], + $default_options_look{$option}[8], + $default_options_look{$option}[9], + $default_options_look{$option}[10], + $default_options_look{$option}[11], + $default_options_look{$option}[12], + $default_options_look{$option}[13], + $default_options_look{$option}[14], + $default_options_look{$option}[15]); + } +} + +sub build_buffers +{ + my $str = ""; + + # get bar position (left/right/top/bottom) + my $position = "left"; + my $option_position = weechat::config_get("weechat.bar.buffers.position"); + if ($option_position ne "") + { + $position = weechat::config_string($option_position); + } + + # read hotlist + my %hotlist; + my $infolist = weechat::infolist_get("hotlist", "", ""); + while (weechat::infolist_next($infolist)) + { + $hotlist{weechat::infolist_pointer($infolist, "buffer_pointer")} = + weechat::infolist_integer($infolist, "priority"); + if ( weechat::config_boolean( $options{"hotlist_counter"} ) eq 1 and $weechat_version >= 0x00030500) + { + $hotlist{weechat::infolist_pointer($infolist, "buffer_pointer")."_count_00"} = + weechat::infolist_integer($infolist, "count_00"); # low message + $hotlist{weechat::infolist_pointer($infolist, "buffer_pointer")."_count_01"} = + weechat::infolist_integer($infolist, "count_01"); # channel message + $hotlist{weechat::infolist_pointer($infolist, "buffer_pointer")."_count_02"} = + weechat::infolist_integer($infolist, "count_02"); # private message + $hotlist{weechat::infolist_pointer($infolist, "buffer_pointer")."_count_03"} = + weechat::infolist_integer($infolist, "count_03"); # highlight message + } + } + weechat::infolist_free($infolist); + + # read buffers list + @buffers_focus = (); + my @buffers; + my @current1 = (); + my @current2 = (); + my $old_number = -1; + my $max_number = 0; + my $max_number_digits = 0; + my $active_seen = 0; + $infolist = weechat::infolist_get("buffer", "", ""); + while (weechat::infolist_next($infolist)) + { + # ignore hidden buffers (WeeChat >= 0.4.4) + if ($weechat_version >= 0x00040400) + { + next if (weechat::infolist_integer($infolist, "hidden")); + } + my $buffer; + my $number = weechat::infolist_integer($infolist, "number"); + if ($number ne $old_number) + { + @buffers = (@buffers, @current2, @current1); + @current1 = (); + @current2 = (); + $active_seen = 0; + } + if ($number > $max_number) + { + $max_number = $number; + } + $old_number = $number; + my $active = weechat::infolist_integer($infolist, "active"); + if ($active) + { + $active_seen = 1; + } + $buffer->{"pointer"} = weechat::infolist_pointer($infolist, "pointer"); + $buffer->{"number"} = $number; + $buffer->{"active"} = $active; + $buffer->{"current_buffer"} = weechat::infolist_integer($infolist, "current_buffer"); + $buffer->{"num_displayed"} = weechat::infolist_integer($infolist, "num_displayed"); + $buffer->{"plugin_name"} = weechat::infolist_string($infolist, "plugin_name"); + $buffer->{"name"} = weechat::infolist_string($infolist, "name"); + $buffer->{"short_name"} = weechat::infolist_string($infolist, "short_name"); + $buffer->{"full_name"} = $buffer->{"plugin_name"}.".".$buffer->{"name"}; + $buffer->{"type"} = weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type"); + #weechat::print("", $buffer->{"type"}); + + # check if buffer is active (or maybe a /part, /kick channel) + if ($buffer->{"type"} eq "channel" and weechat::config_boolean( $options{"mark_inactive"} ) eq 1) + { + my $server = weechat::buffer_get_string($buffer->{"pointer"}, "localvar_server"); + my $channel = weechat::buffer_get_string($buffer->{"pointer"}, "localvar_channel"); + my $infolist_channel = weechat::infolist_get("irc_channel", "", $server.",".$channel); + if ($infolist_channel) + { + weechat::infolist_next($infolist_channel); + $buffer->{"nicks_count"} = weechat::infolist_integer($infolist_channel, "nicks_count"); + }else + { + $buffer->{"nicks_count"} = 0; + } + weechat::infolist_free($infolist_channel); + } + + my $result = check_immune_detached_buffers($buffer->{"name"}); # checking for wildcard + my $maxlevel = weechat::config_integer($options{"detach_buffer_immediately_level"}); + next if ( check_detach_buffer_immediately($buffer->{"name"}) eq 1 + and $buffer->{"current_buffer"} eq 0 + and ( not exists $hotlist{$buffer->{"pointer"}} or $hotlist{$buffer->{"pointer"}} < $maxlevel) ); # checking for buffer to immediately detach + + unless ($result) + { + my $detach_time = weechat::config_integer( $options{"detach"}); + my $current_time = time(); + # set timer for buffers with no hotlist action + $buffers_timer{$buffer->{"pointer"}} = $current_time + if ( not exists $hotlist{$buffer->{"pointer"}} + and $buffer->{"type"} eq "channel" + and not exists $buffers_timer{$buffer->{"pointer"}} + and $detach_time > 0); + + $buffers_timer{$buffer->{"pointer"}} = $current_time + if (weechat::config_boolean($options{"detach_query"}) eq 1 + and not exists $hotlist{$buffer->{"pointer"}} + and $buffer->{"type"} eq "private" + and not exists $buffers_timer{$buffer->{"pointer"}} + and $detach_time > 0); + + $detach_time = 0 + if (weechat::config_boolean($options{"detach_query"}) eq 0 + and $buffer->{"type"} eq "private"); + + # free content buffer + $buffers_timer{$buffer->{"pointer"}} = $current_time + if (weechat::config_boolean($options{"detach_free_content"}) eq 1 + and not exists $hotlist{$buffer->{"pointer"}} + and $buffer->{"type"} eq "" + and not exists $buffers_timer{$buffer->{"pointer"}} + and $detach_time > 0); + $detach_time = 0 + if (weechat::config_boolean($options{"detach_free_content"}) eq 0 + and $buffer->{"type"} eq ""); + + $detach_time = 0 if (weechat::config_boolean($options{"mark_inactive"}) eq 1 and defined $buffer->{"nicks_count"} and $buffer->{"nicks_count"} == 0); + + # check for detach + unless ( $buffer->{"current_buffer"} eq 0 + and not exists $hotlist{$buffer->{"pointer"}} +# and $buffer->{"type"} eq "channel" + and exists $buffers_timer{$buffer->{"pointer"}} + and $detach_time > 0 + and $weechat_version >= 0x00030800 + and $current_time - $buffers_timer{$buffer->{"pointer"}} >= $detach_time) + { + if ($active_seen) + { + push(@current2, $buffer); + } + else + { + push(@current1, $buffer); + } + } + elsif ( $buffer->{"current_buffer"} eq 0 + and not exists $hotlist{$buffer->{"pointer"}} +# and $buffer->{"type"} eq "channel" + and exists $buffers_timer{$buffer->{"pointer"}} + and $detach_time > 0 + and $weechat_version >= 0x00030800 + and $current_time - $buffers_timer{$buffer->{"pointer"}} >= $detach_time) + { # check for option detach_displayed_buffers and if buffer is displayed in a split window + if ( $buffer->{"num_displayed"} eq 1 + and weechat::config_boolean($options{"detach_displayed_buffers"}) eq 0 ) + { + my $infolist_window = weechat::infolist_get("window", "", ""); + while (weechat::infolist_next($infolist_window)) + { + my $buffer_ptr = weechat::infolist_pointer($infolist_window, "buffer"); + if ($buffer_ptr eq $buffer->{"pointer"}) + { + $buffer->{"window"} = weechat::infolist_integer($infolist_window, "number"); + } + } + weechat::infolist_free($infolist_window); + + push(@current2, $buffer); + } + } + } + else # buffer in "immune_detach_buffers" + { + if ($active_seen) + { + push(@current2, $buffer); + } + else + { + push(@current1, $buffer); + } + } + } # while end + + + if ($max_number >= 1) + { + $max_number_digits = length(int($max_number)); + } + @buffers = (@buffers, @current2, @current1); + weechat::infolist_free($infolist); + + # sort buffers by number, name or shortname + my %sorted_buffers; + if (1) + { + my $number = 0; + for my $buffer (@buffers) + { + my $key; + if (weechat::config_integer( $options{"sort"} ) eq 1) # number = 0; name = 1 + { + my $name = weechat::buffer_get_string($buffer->{"pointer"}, "localvar_custom_name"); + if (not defined $name or $name eq "") { + if (weechat::config_boolean( $options{"short_names"} ) eq 1) { + $name = $buffer->{"short_name"}; + } else { + $name = $buffer->{"name"}; + } + } + if (weechat::config_integer($options{"name_size_max"}) >= 1) + { + $maxlength = weechat::config_integer($options{"name_size_max"}); + if($buffer->{"type"} eq "channel" and weechat::config_boolean( $options{"mark_inactive"} ) eq 1 and $buffer->{"nicks_count"} == 0) + { + $maxlength -= 2; + } + $name = encode("UTF-8", substr(decode("UTF-8", $name), 0, $maxlength)); + } + if ( weechat::config_boolean($options{"core_to_front"}) eq 1) + { + if ( (weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") ne "channel" ) and ( weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") ne "private") ) + { + my $type = weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type"); + if ( $type eq "" and $name ne "weechat") + { + $name = " " . $name + }else + { + $name = " " . $name; + } + } + } + $key = sprintf("%s%08d", lc($name), $buffer->{"number"}); + } + else + { + $key = sprintf("%08d", $number); + } + $sorted_buffers{$key} = $buffer; + $number++; + } + } + + # build string with buffers + $old_number = -1; + foreach my $key (sort keys %sorted_buffers) + { + my $buffer = $sorted_buffers{$key}; + + if ( weechat::config_string($options{"hide_merged_buffers"}) eq "server" ) + { + # buffer type "server" or merged with core? + if ( ($buffer->{"type"} eq "server" or $buffer->{"plugin_name"} eq "core") && (! $buffer->{"active"}) ) + { + next; + } + } + if ( weechat::config_string($options{"hide_merged_buffers"}) eq "channel" ) + { + # buffer type "channel" or merged with core? + if ( ($buffer->{"type"} eq "channel" or $buffer->{"plugin_name"} eq "core") && (! $buffer->{"active"}) ) + { + next; + } + } + if ( weechat::config_string($options{"hide_merged_buffers"}) eq "private" ) + { + # buffer type "private" or merged with core? + if ( ($buffer->{"type"} eq "private" or $buffer->{"plugin_name"} eq "core") && (! $buffer->{"active"}) ) + { + next; + } + } + if ( weechat::config_string($options{"hide_merged_buffers"}) eq "keepserver" ) + { + if ( ($buffer->{"type"} ne "server" or $buffer->{"plugin_name"} eq "core") && (! $buffer->{"active"}) ) + { + next; + } + } + if ( weechat::config_string($options{"hide_merged_buffers"}) eq "all" ) + { + if ( ! $buffer->{"active"} ) + { + next; + } + } + + push(@buffers_focus, $buffer); # buffer > buffers_focus, for mouse support + my $color = ""; + my $bg = ""; + + $color = weechat::config_color( $options{"color_default_fg"} ); + $bg = weechat::config_color( $options{"color_default_bg"} ); + + if ( weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") eq "private" ) + { + if ( (weechat::config_color($options{"queries_default_bg"})) ne "default" || (weechat::config_color($options{"queries_default_fg"})) ne "default" ) + { + $bg = weechat::config_color( $options{"queries_default_bg"} ); + $color = weechat::config_color( $options{"queries_default_fg"} ); + } + } + # check for core and buffer with free content + if ( (weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") ne "channel" ) and ( weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") ne "private") ) + { + $color = weechat::config_color( $options{"color_none_channel_fg"} ); + $bg = weechat::config_color( $options{"color_none_channel_bg"} ); + } + # default whitelist buffer? + if (grep {$_ eq $buffer->{"name"}} @whitelist_buffers) + { + $color = weechat::config_color( $options{"color_whitelist_default_fg"} ); + $bg = weechat::config_color( $options{"color_whitelist_default_bg"} ); + } + + $color = "default" if ($color eq ""); + + # color for channel and query buffer + if (exists $hotlist{$buffer->{"pointer"}}) + { + delete $buffers_timer{$buffer->{"pointer"}}; + # check if buffer is in whitelist buffer + if (grep {$_ eq $buffer->{"name"}} @whitelist_buffers) + { + $bg = weechat::config_color( $options{"color_whitelist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}."_bg"} ); + $color = weechat::config_color( $options{"color_whitelist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}."_fg"} ); + } + elsif ( weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") eq "private" ) + { + # queries_default_fg/bg and buffers.color.queries_message_fg/bg + if ( (weechat::config_color($options{"queries_highlight_fg"})) ne "default" || + (weechat::config_color($options{"queries_highlight_bg"})) ne "default" || + (weechat::config_color($options{"queries_message_fg"})) ne "default" || + (weechat::config_color($options{"queries_message_bg"})) ne "default" ) + { + if ( ($hotlist{$buffer->{"pointer"}}) == 2 ) + { + $bg = weechat::config_color( $options{"queries_message_bg"} ); + $color = weechat::config_color( $options{"queries_message_fg"} ); + } + + elsif ( ($hotlist{$buffer->{"pointer"}}) == 3 ) + { + $bg = weechat::config_color( $options{"queries_highlight_bg"} ); + $color = weechat::config_color( $options{"queries_highlight_fg"} ); + } + }else + { + $bg = weechat::config_color( $options{"color_hotlist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}."_bg"} ); + $color = weechat::config_color( $options{"color_hotlist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}."_fg"} ); + } + }else + { + $bg = weechat::config_color( $options{"color_hotlist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}."_bg"} ); + $color = weechat::config_color( $options{"color_hotlist_".$hotlist_level{$hotlist{$buffer->{"pointer"}}}."_fg"} ); + } + } + + if ($buffer->{"current_buffer"}) + { + $color = weechat::config_color( $options{"color_current_fg"} ); + $bg = weechat::config_color( $options{"color_current_bg"} ); + } + my $color_bg = ""; + $color_bg = weechat::color(",".$bg) if ($bg ne ""); + + # create channel number for output + if ( weechat::config_string( $options{"show_prefix_bufname"} ) ne "" ) + { + $str .= $color_bg . + weechat::color( weechat::config_color( $options{"color_prefix_bufname"} ) ). + weechat::config_string( $options{"show_prefix_bufname"} ). + weechat::color("default"); + } + + if ( weechat::config_boolean( $options{"show_number"} ) eq 1 ) # on + { + if (( weechat::config_boolean( $options{"indenting_number"} ) eq 1) + && (($position eq "left") || ($position eq "right"))) + { + $str .= weechat::color("default").$color_bg + .(" " x ($max_number_digits - length(int($buffer->{"number"})))); + } + if ($old_number ne $buffer->{"number"}) + { + $str .= weechat::color( weechat::config_color( $options{"color_number"} ) ) + .$color_bg + .$buffer->{"number"} + .weechat::color("default") + .$color_bg + .weechat::color( weechat::config_color( $options{"color_number_char"} ) ) + .weechat::config_string( $options{"show_number_char"} ) + .$color_bg; + } + else + { + # Indentation aligns channels in a visually appealing way + # when viewing list top-to-bottom... + my $indent = (" " x length($buffer->{"number"}))." "; + # ...except when list is top/bottom and channels left-to-right. + my $option_pos = weechat::config_string( weechat::config_get( "weechat.bar.buffers.position" ) ); + if (($option_pos eq 'top') || ($option_pos eq 'bottom')) { + my $option_filling = weechat::config_string( weechat::config_get( "weechat.bar.buffers.filling_top_bottom" ) ); + if ($option_filling =~ /horizontal/) { + $indent = ''; + } + } + $str .= weechat::color("default") + .$color_bg + .$indent; + } + } + + if (( weechat::config_integer( $options{"indenting"} ) ne 0 ) # indenting NOT off + && (($position eq "left") || ($position eq "right"))) + { + my $type = weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type"); + if (($type eq "channel") || ($type eq "private")) + { + if ( weechat::config_integer( $options{"indenting"} ) eq 1 ) + { + $str .= (" " x weechat::config_integer( $options{"indenting_amount"} ) ); + } + elsif ( (weechat::config_integer($options{"indenting"}) eq 2) and (weechat::config_integer($options{"indenting_number"}) eq 0) ) #under_name + { + if ( weechat::config_boolean( $options{"show_number"} ) eq 0 ) + { + $str .= (" " x weechat::config_integer( $options{"indenting_amount"} ) ); + } + else + { + $str .= ( (" " x ( $max_number_digits - length($buffer->{"number"}) )).(" " x weechat::config_integer( $options{"indenting_amount"} ) ) ); + } + } + } + } + + $str .= weechat::config_string( $options{"show_prefix_query"}) if (weechat::config_string( $options{"show_prefix_query"} ) ne "" and $buffer->{"type"} eq "private"); + + if (weechat::config_boolean( $options{"show_prefix"} ) eq 1) + { + my $nickname = weechat::buffer_get_string($buffer->{"pointer"}, "localvar_nick"); + if ($nickname ne "") + { + # with version >= 0.3.2, this infolist will return only nick + # with older versions, whole nicklist is returned for buffer, and this can be very slow + my $infolist_nick = weechat::infolist_get("nicklist", $buffer->{"pointer"}, "nick_".$nickname); + if ($infolist_nick ne "") + { + while (weechat::infolist_next($infolist_nick)) + { + if ((weechat::infolist_string($infolist_nick, "type") eq "nick") + && (weechat::infolist_string($infolist_nick, "name") eq $nickname)) + { + my $prefix = weechat::infolist_string($infolist_nick, "prefix"); + if (($prefix ne " ") or (weechat::config_boolean( $options{"show_prefix_empty"} ) eq 1)) + { + # with version >= 0.3.5, it is now a color name (for older versions: option name with color) + if (int($weechat_version) >= 0x00030500) + { + $str .= weechat::color(weechat::infolist_string($infolist_nick, "prefix_color")); + } + else + { + $str .= weechat::color(weechat::config_color( + weechat::config_get( + weechat::infolist_string($infolist_nick, "prefix_color")))); + } + $str .= $prefix; + } + last; + } + } + weechat::infolist_free($infolist_nick); + } + } + } + if ($buffer->{"type"} eq "channel" and weechat::config_boolean( $options{"mark_inactive"} ) eq 1 and $buffer->{"nicks_count"} == 0) + { + $str .= "("; + } + + $str .= weechat::color($color) . weechat::color(",".$bg); + + my $name = weechat::buffer_get_string($buffer->{"pointer"}, "localvar_custom_name"); + if (not defined $name or $name eq "") + { + if (weechat::config_boolean( $options{"short_names"} ) eq 1) { + $name = $buffer->{"short_name"}; + } else { + $name = $buffer->{"name"}; + } + } + + if (weechat::config_integer($options{"name_size_max"}) >= 1) # check max_size of buffer name + { + $name = decode("UTF-8", $name); + + $maxlength = weechat::config_integer($options{"name_size_max"}); + if($buffer->{"type"} eq "channel" and weechat::config_boolean( $options{"mark_inactive"} ) eq 1 and $buffer->{"nicks_count"} == 0) + { + $maxlength -= 2; + } + + $str .= encode("UTF-8", substr($name, 0, $maxlength)); + $str .= weechat::color(weechat::config_color( $options{"color_number_char"})).weechat::config_string($options{"name_crop_suffix"}) if (length($name) > weechat::config_integer($options{"name_size_max"})); + $str .= add_inactive_parentless($buffer->{"type"}, $buffer->{"nicks_count"}); + $str .= add_hotlist_count($buffer->{"pointer"}, %hotlist); + } + else + { + $str .= $name; + $str .= add_inactive_parentless($buffer->{"type"}, $buffer->{"nicks_count"}); + $str .= add_hotlist_count($buffer->{"pointer"}, %hotlist); + } + + if ( weechat::buffer_get_string($buffer->{"pointer"}, "localvar_type") eq "server" and weechat::config_boolean($options{"show_lag"}) eq 1) + { + my $color_lag = weechat::config_color(weechat::config_get("irc.color.item_lag_finished")); + my $min_lag = weechat::config_integer(weechat::config_get("irc.network.lag_min_show")); + my $infolist_server = weechat::infolist_get("irc_server", "", $buffer->{"short_name"}); + weechat::infolist_next($infolist_server); + my $lag = (weechat::infolist_integer($infolist_server, "lag")); + weechat::infolist_free($infolist_server); + if ( int($lag) > int($min_lag) ) + { + $lag = $lag / 1000; + $str .= weechat::color("default") . " (" . weechat::color($color_lag) . $lag . weechat::color("default") . ")"; + } + } + if (weechat::config_boolean($options{"detach_displayed_buffers"}) eq 0 + and weechat::config_boolean($options{"detach_display_window_number"}) eq 1) + { + if ($buffer->{"window"}) + { + $str .= weechat::color("default") . " (" . weechat::color(weechat::config_color( $options{"color_number"})) . $buffer->{"window"} . weechat::color("default") . ")"; + } + } + $str .= weechat::color("default"); + + if ( weechat::config_string( $options{"show_suffix_bufname"} ) ne "" ) + { + $str .= weechat::color( weechat::config_color( $options{"color_suffix_bufname"} ) ). + weechat::config_string( $options{"show_suffix_bufname"} ). + weechat::color("default"); + } + + $str .= "\n"; + $old_number = $buffer->{"number"}; + } + + # remove spaces and/or linefeed at the end + $str =~ s/\s+$//; + chomp($str); + return $str; +} + +sub add_inactive_parentless +{ +my ($buf_type, $buf_nicks_count) = @_; +my $str = ""; + if ($buf_type eq "channel" and weechat::config_boolean( $options{"mark_inactive"} ) eq 1 and $buf_nicks_count == 0) + { + $str .= weechat::color(weechat::config_color( $options{"color_number_char"})); + $str .= ")"; + } +return $str; +} + +sub add_hotlist_count +{ +my ($bufpointer, %hotlist) = @_; + +return "" if ( weechat::config_boolean( $options{"hotlist_counter"} ) eq 0 or ($weechat_version < 0x00030500)); # off +my $col_number_char = weechat::color(weechat::config_color( $options{"color_number_char"}) ); +my $str = " ".$col_number_char."("; + +# 0 = low level +if (defined $hotlist{$bufpointer."_count_00"}) +{ + my $bg = weechat::config_color( $options{"color_hotlist_low_bg"} ); + my $color = weechat::config_color( $options{"color_hotlist_low_fg"} ); + $str .= weechat::color($bg). + weechat::color($color). + $hotlist{$bufpointer."_count_00"} if ($hotlist{$bufpointer."_count_00"} ne "0"); +} + +# 1 = message +if (defined $hotlist{$bufpointer."_count_01"}) +{ + my $bg = weechat::config_color( $options{"color_hotlist_message_bg"} ); + my $color = weechat::config_color( $options{"color_hotlist_message_fg"} ); + if ($str =~ /[0-9]$/) + { + $str .= ",". + weechat::color($bg). + weechat::color($color). + $hotlist{$bufpointer."_count_01"} if ($hotlist{$bufpointer."_count_01"} ne "0"); + }else + { + $str .= weechat::color($bg). + weechat::color($color). + $hotlist{$bufpointer."_count_01"} if ($hotlist{$bufpointer."_count_01"} ne "0"); + } +} +# 2 = private +if (defined $hotlist{$bufpointer."_count_02"}) +{ + my $bg = weechat::config_color( $options{"color_hotlist_private_bg"} ); + my $color = weechat::config_color( $options{"color_hotlist_private_fg"} ); + if ($str =~ /[0-9]$/) + { + $str .= ",". + weechat::color($bg). + weechat::color($color). + $hotlist{$bufpointer."_count_02"} if ($hotlist{$bufpointer."_count_02"} ne "0"); + }else + { + $str .= weechat::color($bg). + weechat::color($color). + $hotlist{$bufpointer."_count_02"} if ($hotlist{$bufpointer."_count_02"} ne "0"); + } +} +# 3 = highlight +if (defined $hotlist{$bufpointer."_count_03"}) +{ + my $bg = weechat::config_color( $options{"color_hotlist_highlight_bg"} ); + my $color = weechat::config_color( $options{"color_hotlist_highlight_fg"} ); + if ($str =~ /[0-9]$/) + { + $str .= ",". + weechat::color($bg). + weechat::color($color). + $hotlist{$bufpointer."_count_03"} if ($hotlist{$bufpointer."_count_03"} ne "0"); + }else + { + $str .= weechat::color($bg). + weechat::color($color). + $hotlist{$bufpointer."_count_03"} if ($hotlist{$bufpointer."_count_03"} ne "0"); + } +} +$str .= $col_number_char. ")"; + +$str = "" if (weechat::string_remove_color($str, "") eq " ()"); # remove color and check for buffer with no messages +return $str; +} + +sub buffers_signal_buffer +{ + my ($data, $signal, $signal_data) = @_; + + # check for buffer_switch and set or remove detach time + if ($weechat_version >= 0x00030800) + { + if ($signal eq "buffer_switch") + { + my $pointer = weechat::hdata_get_list (weechat::hdata_get("buffer"), "gui_buffer_last_displayed"); # get switched buffer + my $current_time = time(); + if ( weechat::buffer_get_string($pointer, "localvar_type") eq "channel") + { + $buffers_timer{$pointer} = $current_time; + } + else + { + delete $buffers_timer{$pointer}; + } + } + if ($signal eq "buffer_opened") + { + my $current_time = time(); + $buffers_timer{$signal_data} = $current_time; + } + if ($signal eq "buffer_closing") + { + delete $buffers_timer{$signal_data}; + } + } + weechat::bar_item_update($SCRIPT_NAME); + return weechat::WEECHAT_RC_OK; +} + +sub buffers_signal_hotlist +{ + weechat::bar_item_update($SCRIPT_NAME); + return weechat::WEECHAT_RC_OK; +} + + +sub buffers_signal_config_whitelist +{ + @whitelist_buffers = (); + @whitelist_buffers = split( /,/, weechat::config_string( $options{"look_whitelist_buffers"} ) ); + weechat::bar_item_update($SCRIPT_NAME); + return weechat::WEECHAT_RC_OK; +} + +sub buffers_signal_config_immune_detach_buffers +{ + @immune_detach_buffers = (); + @immune_detach_buffers = split( /,/, weechat::config_string( $options{"immune_detach_buffers"} ) ); + weechat::bar_item_update($SCRIPT_NAME); + return weechat::WEECHAT_RC_OK; +} + +sub buffers_signal_config_detach_buffer_immediately +{ + @detach_buffer_immediately = (); + @detach_buffer_immediately = split( /,/, weechat::config_string( $options{"detach_buffer_immediately"} ) ); + weechat::bar_item_update($SCRIPT_NAME); + return weechat::WEECHAT_RC_OK; +} + +sub buffers_signal_config +{ + weechat::bar_item_update($SCRIPT_NAME); + return weechat::WEECHAT_RC_OK; +} + +# called when mouse click occured in buffers item: this callback returns buffer +# hash according to line of item where click occured +sub buffers_focus_buffers +{ + my %info = %{$_[1]}; + my $item_line = int($info{"_bar_item_line"}); + undef my $hash; + if (($info{"_bar_item_name"} eq $SCRIPT_NAME) && ($item_line >= 0) && ($item_line <= $#buffers_focus)) + { + $hash = $buffers_focus[$item_line]; + } + else + { + $hash = {}; + my $hash_focus = $buffers_focus[0]; + foreach my $key (keys %$hash_focus) + { + $hash->{$key} = "?"; + } + } + return $hash; +} + +# called when a mouse action is done on buffers item, to execute action +# possible actions: jump to a buffer or move buffer in list (drag & drop of buffer) +sub buffers_hsignal_mouse +{ + my ($data, $signal, %hash) = ($_[0], $_[1], %{$_[2]}); + my $current_buffer = weechat::buffer_get_integer(weechat::current_buffer(), "number"); # get current buffer number + + if ( $hash{"_key"} eq "button1" ) + { + # left mouse button + if ($hash{"number"} eq $hash{"number2"}) + { + if ( weechat::config_boolean($options{"jump_prev_next_visited_buffer"}) ) + { + if ( $current_buffer eq $hash{"number"} ) + { + weechat::command("", "/input jump_previously_visited_buffer"); + } + else + { + weechat::command("", "/buffer ".$hash{"full_name"}); + } + } + else + { + weechat::command("", "/buffer ".$hash{"full_name"}); + } + } + else + { + move_buffer(%hash) if (weechat::config_boolean($options{"mouse_move_buffer"})); + } + } + elsif ( ($hash{"_key"} eq "button2") && (weechat::config_boolean($options{"jump_prev_next_visited_buffer"})) ) + { + # right mouse button + if ( $current_buffer eq $hash{"number2"} ) + { + weechat::command("", "/input jump_next_visited_buffer"); + } + } + elsif ( $hash{"_key"} =~ /wheelup$/ ) + { + # wheel up + if (weechat::config_boolean($options{"mouse_wheel"})) + { + weechat::command("", "/buffer -1"); + } + } + elsif ( $hash{"_key"} =~ /wheeldown$/ ) + { + # wheel down + if (weechat::config_boolean($options{"mouse_wheel"})) + { + weechat::command("", "/buffer +1"); + } + } + else + { + my $infolist = weechat::infolist_get("hook", "", "command,menu"); + my $has_menu_command = weechat::infolist_next($infolist); + weechat::infolist_free($infolist); + + if ( $has_menu_command && $hash{"_key"} =~ /button2/ ) + { + if ($hash{"number"} eq $hash{"number2"}) + { + weechat::command($hash{"pointer"}, "/menu buffer1 $hash{short_name} $hash{number}"); + } + else + { + weechat::command($hash{"pointer"}, "/menu buffer2 $hash{short_name}/$hash{short_name2} $hash{number} $hash{number2}") + } + } + else + { + move_buffer(%hash) if (weechat::config_boolean($options{"mouse_move_buffer"})); + } + } +} + +sub move_buffer +{ + my %hash = @_; + my $number2 = $hash{"number2"}; + if ($number2 eq "?") + { + # if number 2 is not known (end of gesture outside buffers list), then set it + # according to mouse gesture + $number2 = "1"; + if (($hash{"_key"} =~ /gesture-right/) || ($hash{"_key"} =~ /gesture-down/)) + { + $number2 = "999999"; + if ($weechat_version >= 0x00030600) + { + my $hdata_buffer = weechat::hdata_get("buffer"); + my $last_gui_buffer = weechat::hdata_get_list($hdata_buffer, "last_gui_buffer"); + if ($last_gui_buffer) + { + $number2 = weechat::hdata_integer($hdata_buffer, $last_gui_buffer, "number") + 1; + } + } + } + } + my $ptrbuf = weechat::current_buffer(); + weechat::command($hash{"pointer"}, "/buffer move ".$number2); +} + +sub check_immune_detached_buffers +{ + my ($buffername) = @_; + foreach ( @immune_detach_buffers ){ + my $immune_buffer = weechat::string_mask_to_regex($_); + if ($buffername =~ /^$immune_buffer$/i) + { + return 1; + } + } + return 0; +} + +sub check_detach_buffer_immediately +{ + my ($buffername) = @_; + foreach ( @detach_buffer_immediately ){ + my $detach_buffer = weechat::string_mask_to_regex($_); + if ($buffername =~ /^$detach_buffer$/i) + { + return 1; + } + } + return 0; +} + +sub shutdown_cb +{ + weechat::command("", "/bar hide " . $SCRIPT_NAME) if ( weechat::config_boolean($options{"toggle_bar"}) eq 1 ); + return weechat::WEECHAT_RC_OK +} + +sub check_bar_item +{ + my $item = 0; + my $infolist = weechat::infolist_get("bar", "", ""); + while (weechat::infolist_next($infolist)) + { + my $bar_items = weechat::infolist_string($infolist, "items"); + if (index($bar_items, $SCRIPT_NAME) != -1) + { + my $name = weechat::infolist_string($infolist, "name"); + if ($name ne $SCRIPT_NAME) + { + $item = 1; + last; + } + } + } + weechat::infolist_free($infolist); + return $item; +} diff --git a/.weechat/perl/highmon.pl b/.weechat/perl/highmon.pl new file mode 100644 index 0000000..1c07712 --- /dev/null +++ b/.weechat/perl/highmon.pl @@ -0,0 +1,1139 @@ +# +# highmon.pl - Highlight Monitoring for weechat 0.3.0 +# Version 2.5 +# +# Add 'Highlight Monitor' buffer/bar to log all highlights in one spot +# +# Usage: +# /highmon [help] | [monitor [channel [server]]] | [clean default|orphan|all] | clearbar +# Command wrapper for highmon commands +# +# /highmon clean default|orphan|all will clean the config section of default 'on' entries, +# channels you are no longer joined, or both +# +# /highmon clearbar will clear the contents of highmon's bar output +# +# /highmon monitor [channel] [server] is used to toggle a highlight monitoring on and off, this +# can be used in the channel buffer for the channel you wish to toggle, or be given +# with arguments e.g. /highmon monitor #weechat freenode +# +# /set plugins.var.perl.highmon.alignment +# The config setting "alignment" can be changed to; +# "channel", "schannel", "nchannel", "channel,nick", "schannel,nick", "nchannel,nick" +# to change how the monitor appears +# The 'channel' value will show: "#weechat" +# The 'schannel' value will show: "6" +# The 'nchannel' value will show: "6:#weechat" +# +# /set plugins.var.perl.highmon.short_names +# Setting this to 'on' will trim the network name from highmon, ala buffers.pl +# +# /set plugins.var.perl.highmon.merge_private +# Setting this to 'on' will merge private messages to highmon's display +# +# /set plugins.var.perl.highmon.color_buf +# This turns colored buffer names on or off, you can also set a single fixed color by using a weechat color name. +# This *must* be a valid color name, or weechat will likely do unexpected things :) +# +# /set plugins.var.perl.highmon.hotlist_show +# Setting this to 'on' will let the highmon buffer appear in hotlists +# (status bar/buffer.pl) +# +# /set plugins.var.perl.highmon.away_only +# Setting this to 'on' will only put messages in the highmon buffer when +# you set your status to away +# +# /set plugins.var.perl.highmon.logging +# Toggles logging status for highmon buffer (default: off) +# +# /set plugins.var.perl.highmon.output +# Changes where output method of highmon; takes either "bar" or "buffer" (default; buffer) +# /set plugins.var.perl.highmon.bar_lines +# Changes the amount of lines the output bar will hold. +# (Only appears once output has been set to bar, defaults to 10) +# /set plugins.var.perl.highmon.bar_scrolldown +# Toggles the bar scrolling at the bottom when new highlights are received +# (Only appears once output has been set to bar, defaults to off) +# +# /set plugins.var.perl.highmon.nick_prefix +# /set plugins.var.perl.highmon.nick_suffix +# Sets the prefix and suffix chars in the highmon buffer +# (Defaults to <> if nothing set, and blank if there is) +# +# servername.#channel +# servername is the internal name for the server (set when you use /server add) +# #channel is the channel name, (where # is whatever channel type that channel happens to be) +# +# Optional, set up tweaks; Hide the status and input lines on highmon +# +# /set weechat.bar.status.conditions "${window.buffer.full_name} != perl.highmon" +# /set weechat.bar.input.conditions "${window.buffer.full_name} != perl.highmon" +# + +# Bugs and feature requests at: https://github.com/KenjiE20/highmon + +# History: +# 2014-08-16, KenjiE20 : +# v2.5: -add: clearbar command to clear bar output +# -add: firstrun output prompt to check the help text for set up hints as they were being missed +# and update hint for conditions to use eval +# -change: Make all outputs use the date callback for more accurate timestamps (thanks Germainz) +# 2013-12-04, KenjiE20 : +# v2.4: -add: Support for eval style colour codes in time format used for bar output +# 2013-10-22, KenjiE20 : +# v2.3.3.2: -fix: Typo in fix command +# 2013-10-10, KenjiE20 : +# v2.3.3.1: -fix: Typo in closed buffer warning +# 2013-10-07, KenjiE20 : +# v2.3.3: -add: Warning and fixer for accidental buffer closes +# 2013-01-15, KenjiE20 : +# v2.3.2: -fix: Let bar output use the string set in weechat's config option +# -add: github info +# 2012-04-15, KenjiE20 : +# v2.3.1: -fix: Colour tags in bar timestamp string +# 2012-02-28, KenjiE20 : +# v2.3: -feature: Added merge_private option to display private messages (default: off) +# -fix: Channel name colours now show correctly when set to on +# 2011-08-07, Sitaktif : +# v2.2.1: -feature: Add "bar_scrolldown" option to have the bar display the latest hl at anytime +# -fix: Set up bar-specific config at startup if 'output' is already configured as 'bar' +# 2010-12-22, KenjiE20 : +# v2.2: -change: Use API instead of config to find channel colours, ready for 0.3.4 and 256 colours +# 2010-12-13, idl0r & KenjiE20 : +# v2.1.3: -fix: perl errors caused by bar line counter +# -fix: Add command list to inbuilt help +# 2010-09-30, KenjiE20 : +# v2.1.2: -fix: logging config was not correctly toggling back on (thanks to sleo for noticing) +# -version sync w/ chanmon +# 2010-08-27, KenjiE20 : +# v2.1: -feature: Add 'nchannel' option to alignment to display buffer and name +# 2010-04-25, KenjiE20 : +# v2.0: Release as version 2.0 +# 2010-04-24, KenjiE20 : +# v1.9: Rewrite for v2.0 +# Bring feature set in line with chanmon 2.0 +# -code change: Made more subs to shrink the code down in places +# -fix: Stop highmon attempting to double load/hook +# -fix: Add version dependant check for away status +# 2010-01-25, KenjiE20 : +# v1.7: -fixture: Let highmon be aware of nick_prefix/suffix +# and allow custom prefix/suffix for chanmon buffer +# (Defaults to <> if nothing set, and blank if there is) +# (Thanks to m4v for these) +# 2009-09-07, KenjiE20 : +# v1.6: -feature: colored buffer names +# -change: version sync with chanmon +# 2009-09-05, KenjiE20 : +# v1.2: -fix: disable buffer highlight +# 2009-09-02, KenjiE20 : +# v.1.1.1 -change: Stop unsightly text block on '/help' +# 2009-08-10, KenjiE20 : +# v1.1: In-client help added +# 2009-08-02, KenjiE20 : +# v1.0: Initial Public Release + +# Copyright (c) 2009 by KenjiE20 +# +# This program 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. +# +# This program 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 this program. If not, see . +# + +@bar_lines = (); +@bar_lines_time = (); +# Replicate info earlier for in-client help + +$highmonhelp = weechat::color("bold")."/highmon [help] | [monitor [channel [server]]] | [clean default|orphan|all] | clearbar".weechat::color("-bold")." + Command wrapper for highmon commands + +".weechat::color("bold")."/highmon clean default|orphan|all".weechat::color("-bold")." will clean the config section of default 'on' entries, channels you are no longer joined, or both + +".weechat::color("bold")."/highmon clearbar".weechat::color("-bold")." will clear the contents of highmon's bar output + +".weechat::color("bold")."/highmon monitor [channel] [server]".weechat::color("-bold")." is used to toggle a highlight monitoring on and off, this can be used in the channel buffer for the channel you wish to toggle, or be given with arguments e.g. /highmon monitor #weechat freenode + +".weechat::color("bold")."/set plugins.var.perl.highmon.alignment".weechat::color("-bold")." + The config setting \"alignment\" can be changed to; + \"channel\", \"schannel\", \"nchannel\", \"channel,nick\", \"schannel,nick\", \"nchannel,nick\" + to change how the monitor appears + The 'channel' value will show: \"#weechat\" + The 'schannel' value will show: \"6\" + The 'nchannel' value will show: \"6:#weechat\" + +".weechat::color("bold")."/set plugins.var.perl.highmon.short_names".weechat::color("-bold")." + Setting this to 'on' will trim the network name from highmon, ala buffers.pl + +".weechat::color("bold")."/set plugins.var.perl.highmon.merge_private".weechat::color("-bold")." + Setting this to 'on' will merge private messages to highmon's display + +".weechat::color("bold")."/set plugins.var.perl.highmon.color_buf".weechat::color("-bold")." + This turns colored buffer names on or off, you can also set a single fixed color by using a weechat color name. + This ".weechat::color("bold")."must".weechat::color("-bold")." be a valid color name, or weechat will likely do unexpected things :) + +".weechat::color("bold")."/set plugins.var.perl.highmon.hotlist_show".weechat::color("-bold")." +Setting this to 'on' will let the highmon buffer appear in hotlists (status bar/buffer.pl) + +".weechat::color("bold")."/set plugins.var.perl.highmon.away_only".weechat::color("-bold")." +Setting this to 'on' will only put messages in the highmon buffer when you set your status to away + +".weechat::color("bold")."/set plugins.var.perl.highmon.logging".weechat::color("-bold")." + Toggles logging status for highmon buffer (default: off) + +".weechat::color("bold")."/set plugins.var.perl.highmon.output".weechat::color("-bold")." + Changes where output method of highmon; takes either \"bar\" or \"buffer\" (default; buffer) +".weechat::color("bold")."/set plugins.var.perl.highmon.bar_lines".weechat::color("-bold")." + Changes the amount of lines the output bar will hold. + (Only appears once output has been set to bar, defaults to 10) +".weechat::color("bold")."/set plugins.var.perl.highmon.bar_scrolldown".weechat::color("-bold")." + Toggles the bar scrolling at the bottom when new highlights are received + (Only appears once output has been set to bar, defaults to off) + +".weechat::color("bold")."/set plugins.var.perl.highmon.nick_prefix".weechat::color("-bold")." +".weechat::color("bold")."/set plugins.var.perl.highmon.nick_suffix".weechat::color("-bold")." + Sets the prefix and suffix chars in the highmon buffer + (Defaults to <> if nothing set, and blank if there is) + +".weechat::color("bold")."servername.#channel".weechat::color("-bold")." + servername is the internal name for the server (set when you use /server add) + #channel is the channel name, (where # is whatever channel type that channel happens to be) + +".weechat::color("bold")."Optional, set up tweaks;".weechat::color("-bold")." Hide the status and input lines on highmon + +".weechat::color("bold")."/set weechat.bar.status.conditions \"\${window.buffer.full_name} != perl.highmon\"".weechat::color("-bold")." +".weechat::color("bold")."/set weechat.bar.input.conditions \"\${window.buffer.full_name} != perl.highmon\"".weechat::color("-bold"); +# Print verbose help +sub print_help +{ + weechat::print("", "\t".weechat::color("bold")."Highmon Help".weechat::color("-bold")."\n\n"); + weechat::print("", "\t".$highmonhelp); + return weechat::WEECHAT_RC_OK; +} + +# Bar item build +sub highmon_bar_build +{ + # Get max lines + $max_lines = weechat::config_get_plugin("bar_lines"); + $max_lines = $max_lines ? $max_lines : 10; + $str = ''; + $align_num = 0; + $count = 0; + # Keep lines within max + while ($#bar_lines > $max_lines) + { + shift(@bar_lines); + shift(@bar_lines_time); + } + # So long as we have some lines, build a string + if (@bar_lines) + { + # Build loop + $sep = " ".weechat::config_string(weechat::config_get("weechat.look.prefix_suffix"))." "; + foreach(@bar_lines) + { + # Find max align needed + $prefix_num = (index(weechat::string_remove_color($_, ""), $sep)); + $align_num = $prefix_num if ($prefix_num > $align_num); + } + foreach(@bar_lines) + { + # Get align for this line + $prefix_num = (index(weechat::string_remove_color($_, ""), $sep)); + + # Make string + $str = $str.$bar_lines_time[$count]." ".(" " x ($align_num - $prefix_num)).$_."\n"; + # Increment count for sync with time list + $count++; + } + } + return $str; +} + +# Make a new bar +sub highmon_bar_open +{ + # Make the bar item + weechat::bar_item_new("highmon", "highmon_bar_build", ""); + + $highmon_bar = weechat::bar_new ("highmon", "off", 100, "root", "", "bottom", "vertical", "vertical", 0, 0, "default", "cyan", "default", "on", "highmon"); + + return weechat::WEECHAT_RC_OK; +} +# Close bar +sub highmon_bar_close +{ + # Find if bar exists + $highmon_bar = weechat::bar_search("highmon"); + # If is does, close it + if ($highmon_bar ne "") + { + weechat::bar_remove($highmon_bar); + } + + # Find if bar item exists + $highmon_bar_item = weechat::bar_item_search("highmon_bar"); + # If is does, close it + if ($highmon_bar_item ne "") + { + weechat::bar_remove($highmon_bar_item); + } + + @bar_lines = (); + return weechat::WEECHAT_RC_OK; +} + +# Make a new buffer +sub highmon_buffer_open +{ + # Search for pre-existing buffer + $highmon_buffer = weechat::buffer_search("perl", "highmon"); + + # Make a new buffer + if ($highmon_buffer eq "") + { + $highmon_buffer = weechat::buffer_new("highmon", "highmon_buffer_input", "", "highmon_buffer_close", ""); + } + + # Turn off notify, highlights + if ($highmon_buffer ne "") + { + if (weechat::config_get_plugin("hotlist_show" eq "off")) + { + weechat::buffer_set($highmon_buffer, "notify", "0"); + } + weechat::buffer_set($highmon_buffer, "highlight_words", "-"); + weechat::buffer_set($highmon_buffer, "title", "Highlight Monitor"); + # Set no_log + if (weechat::config_get_plugin("logging") eq "off") + { + weechat::buffer_set($highmon_buffer, "localvar_set_no_log", "1"); + } + } + return weechat::WEECHAT_RC_OK; +} +# Buffer input has no action +sub highmon_buffer_input +{ + return weechat::WEECHAT_RC_OK; +} +# Close up +sub highmon_buffer_close +{ + $highmon_buffer = ""; + # If user hasn't changed output style warn user + if (weechat::config_get_plugin("output") eq "buffer") + { + weechat::print("", "\tHighmon buffer has been closed but output is still set to buffer, unusual results may occur. To recreate the buffer use ".weechat::color("bold")."/highmon fix".weechat::color("-bold")); + } + return weechat::WEECHAT_RC_OK; +} + +# Highmon command wrapper +sub highmon_command_cb +{ + $data = $_[0]; + $buffer = $_[1]; + $args = $_[2]; + my $cmd = ''; + my $arg = ''; + + if ($args ne "") + { + # Split argument up + @arg_array = split(/ /,$args); + # Take first as command + $cmd = shift(@arg_array); + # Rebuild string to pass to subs + if (@arg_array) + { + $arg = join(" ", @arg_array); + } + } + + # Help command + if ($cmd eq "" || $cmd eq "help") + { + print_help(); + } + # /monitor command + elsif ($cmd eq "monitor") + { + highmon_toggle($data, $buffer, $arg); + } + # /highclean command + elsif ($cmd eq "clean") + { + highmon_config_clean($data, $buffer, $arg); + } + # clearbar command + elsif ($cmd eq "clearbar") + { + if (weechat::config_get_plugin("output") eq "bar") + { + @bar_lines = (); + weechat::bar_item_update("highmon"); + } + } + # Fix closed buffer + elsif ($cmd eq "fix") + { + if (weechat::config_get_plugin("output") eq "buffer" && $highmon_buffer eq "") + { + highmon_buffer_open(); + } + } + return weechat::WEECHAT_RC_OK; +} + +# Clean up config entries +sub highmon_config_clean +{ + $data = $_[0]; + $buffer = $_[1]; + $args = $_[2]; + + # Don't do anything if bad option given + if ($args ne "default" && $args ne "orphan" && $args ne "all") + { + weechat::print("", "\thighmon.pl: Unknown option"); + return weechat::WEECHAT_RC_OK; + } + + @chans = (); + # Load an infolist of highmon options + $infolist = weechat::infolist_get("option", "", "*highmon*"); + while (weechat::infolist_next($infolist)) + { + $name = weechat::infolist_string($infolist, "option_name"); + $name =~ s/perl\.highmon\.(\w*)\.([#&\+!])(.*)/$1.$2$3/; + if ($name =~ /^(.*)\.([#&\+!])(.*)$/) + { + $action = 0; + # Clean up all 'on's + if ($args eq "default" || $args eq "all") + { + # If value in config is "on" + if (weechat::config_get_plugin($name) eq "on") + { + # Unset and if successful flag as changed + $rc = weechat::config_unset_plugin($name); + if ($rc eq weechat::WEECHAT_CONFIG_OPTION_UNSET_OK_REMOVED) + { + $action = 1; + } + } + } + # Clean non joined + if ($args eq "orphan" || $args eq "all") + { + # If we can't find the buffer for this entry + if (weechat::buffer_search("irc", $name) eq "") + { + # Unset and if successful flag as changed + $rc = weechat::config_unset_plugin($name); + if ($rc eq weechat::WEECHAT_CONFIG_OPTION_UNSET_OK_REMOVED) + { + $action = 1; + } + } + } + # Add changed entry names to list + push (@chans, $name) if ($action); + } + } + weechat::infolist_free($infolist); + # If channels were cleaned from config + if (@chans) + { + # If only one entry + if (@chans == 1) + { + $str = "\thighmon.pl: Cleaned ".@chans." entry from the config:"; + } + else + { + $str = "\thighmon.pl: Cleaned ".@chans." entries from the config:"; + } + # Build a list of channels + foreach(@chans) + { + $str = $str." ".$_; + } + # Print what happened + weechat::print("",$str); + } + # Config seemed to be clean + else + { + weechat::print("", "\thighmon.pl: No entries removed"); + } + return weechat::WEECHAT_RC_OK; +} + +# Check config elements +sub highmon_config_init +{ + # First run default + if (!(weechat::config_is_set_plugin ("first_run"))) + { + if (weechat::config_get_plugin("first_run") ne "true") + { + weechat::print("", "\tThis appears to be the first time highmon has been run. For help and common set up hints see /highmon help"); + weechat::config_set_plugin("first_run", "true"); + } + } + # Alignment default + if (!(weechat::config_is_set_plugin ("alignment"))) + { + weechat::config_set_plugin("alignment", "channel"); + } + if (weechat::config_get_plugin("alignment") eq "") + { + weechat::config_set_plugin("alignment", "none"); + } + + # Short name default + if (!(weechat::config_is_set_plugin ("short_names"))) + { + weechat::config_set_plugin("short_names", "off"); + } + + # Coloured names default + if (!(weechat::config_is_set_plugin ("color_buf"))) + { + weechat::config_set_plugin("color_buf", "on"); + } + + # Hotlist show default + if (!(weechat::config_is_set_plugin ("hotlist_show"))) + { + weechat::config_set_plugin("hotlist_show", "off"); + } + + # Away only default + if (!(weechat::config_is_set_plugin ("away_only"))) + { + weechat::config_set_plugin("away_only", "off"); + } + + # highmon log default + if (!(weechat::config_is_set_plugin ("logging"))) + { + weechat::config_set_plugin("logging", "off"); + } + + # Output default + if (!(weechat::config_is_set_plugin ("output"))) + { + weechat::config_set_plugin("output", "buffer"); + } + + # Private message merging + if (!(weechat::config_is_set_plugin ("merge_private"))) + { + weechat::config_set_plugin("merge_private", "off"); + } + + # Set bar config in case output was set to "bar" before even changing the setting + if (weechat::config_get_plugin("output") eq "bar") + { + # Output bar lines default + if (!(weechat::config_is_set_plugin ("bar_lines"))) + { + weechat::config_set_plugin("bar_lines", "10"); + } + if (!(weechat::config_is_set_plugin ("bar_scrolldown"))) + { + weechat::config_set_plugin("bar_scrolldown", "off"); + } + } + + # Check for exisiting prefix/suffix chars, and setup accordingly + $prefix = weechat::config_get("irc.look.nick_prefix"); + $prefix = weechat::config_string($prefix); + $suffix = weechat::config_get("irc.look.nick_suffix"); + $suffix = weechat::config_string($suffix); + + if (!(weechat::config_is_set_plugin("nick_prefix"))) + { + if ($prefix eq "" && $suffix eq "") + { + weechat::config_set_plugin("nick_prefix", "<"); + } + else + { + weechat::config_set_plugin("nick_prefix", ""); + } + } + + if (!(weechat::config_is_set_plugin("nick_suffix"))) + { + if ($prefix eq "" && $suffix eq "") + { + weechat::config_set_plugin("nick_suffix", ">"); + } + else + { + weechat::config_set_plugin("nick_suffix", ""); + } + } +} + +# Get config updates +sub highmon_config_cb +{ + $point = $_[0]; + $name = $_[1]; + $value = $_[2]; + + $name =~ s/^plugins\.var\.perl\.highmon\.//; + + # Set logging on buffer + if ($name eq "logging") + { + # Search for pre-existing buffer + $highmon_buffer = weechat::buffer_search("perl", "highmon"); + if ($value eq "off") + { + weechat::buffer_set($highmon_buffer, "localvar_set_no_log", "1"); + } + else + { + weechat::buffer_set($highmon_buffer, "localvar_del_no_log", ""); + } + } + # Output changer + elsif ($name eq "output") + { + if ($value eq "bar") + { + # Search for pre-existing buffer + $highmon_buffer = weechat::buffer_search("perl", "highmon"); + # Close if it exists + if ($highmon_buffer ne "") + { + weechat::buffer_close($highmon_buffer) + } + + # Output bar lines default + if (!(weechat::config_is_set_plugin ("bar_lines"))) + { + weechat::config_set_plugin("bar_lines", "10"); + } + if (!(weechat::config_is_set_plugin ("bar_scrolldown"))) + { + weechat::config_set_plugin("bar_scrolldown", "off"); + } + # Make a bar if doesn't exist + highmon_bar_open(); + } + elsif ($value eq "buffer") + { + # If a bar exists, close it + highmon_bar_close(); + # Open buffer + highmon_buffer_open(); + } + + } + # Change if hotlist config changes + elsif ($name eq "hotlist_show") + { + # Search for pre-existing buffer + $highmon_buffer = weechat::buffer_search("perl", "highmon"); + if ($value eq "off" && $highmon_buffer) + { + weechat::buffer_set($highmon_buffer, "notify", "0"); + } + elsif ($value ne "off" && $highmon_buffer) + { + weechat::buffer_set($highmon_buffer, "notify", "3"); + } + } + elsif ($name eq "weechat.look.prefix_suffix") + { + if (weechat::config_get_plugin("output") eq "bar") + { + @bar_lines = (); + weechat::print("", "\thighmon: weechat.look.prefix_suffix changed, clearing highmon bar"); + weechat::bar_item_update("highmon"); + } + } + return weechat::WEECHAT_RC_OK; +} + +# Set up weechat hooks / commands +sub highmon_hook +{ + weechat::hook_print("", "", "", 0, "highmon_new_message", ""); + weechat::hook_command("highclean", "Highmon config clean up", "default|orphan|all", " default: Cleans all config entries with the default \"on\" value\n orphan: Cleans all config entries for channels you aren't currently joined\n all: Does both defaults and orphan", "default|orphan|all", "highmon_config_clean", ""); + + weechat::hook_command("highmon", "Highmon help", "[help] | [monitor [channel [server]]] | [clean default|orphan|all] | clearbar", " help: Print help on config options for highmon\n monitor: Toggles monitoring for a channel\n clean: Highmon config clean up (/highclean)\nclearbar: Clear Highmon bar", "help || monitor %(irc_channels) %(irc_servers) || clean default|orphan|all || clearbar", "highmon_command_cb", ""); + + weechat::hook_config("plugins.var.perl.highmon.*", "highmon_config_cb", ""); + weechat::hook_config("weechat.look.prefix_suffix", "highmon_config_cb", ""); +} + +# Main body, Callback for hook_print +sub highmon_new_message +{ + my $net = ""; + my $chan = ""; + my $nick = ""; + my $outstr = ""; + my $window_displayed = ""; + my $dyncheck = "0"; + +# DEBUG point +# $string = "\t"."0: ".$_[0]." 1: ".$_[1]." 2: ".$_[2]." 3: ".$_[3]." 4: ".$_[4]." 5: ".$_[5]." 6: ".$_[6]." 7: ".$_[7]; +# weechat::print("", "\t".$string); + + $cb_datap = $_[0]; + $cb_bufferp = $_[1]; + $cb_date = $_[2]; + $cb_tags = $_[3]; + $cb_disp = $_[4]; + $cb_high = $_[5]; + $cb_prefix = $_[6]; + $cb_msg = $_[7]; + + # Only work on highlighted messages or private message when enabled + if ($cb_high == "1" || (weechat::config_get_plugin("merge_private") eq "on" && $cb_tags =~ /notify_private/)) + { + # Pre bug #29618 (0.3.3) away detect + if (weechat::info_get("version_number", "") <= 197120) + { + $away = ''; + # Get infolist for this server + $infolist = weechat::infolist_get("irc_server", "", weechat::buffer_get_string($cb_bufferp, "localvar_server")); + while (weechat::infolist_next($infolist)) + { + # Get away message is is_away is on + $away = weechat::infolist_string($infolist, "away_message") if (weechat::infolist_integer($infolist, "is_away")); + } + weechat::infolist_free($infolist); + } + # Post bug #29618 fix + else + { + $away = weechat::buffer_get_string($cb_bufferp, "localvar_away"); + } + if (weechat::config_get_plugin("away_only") ne "on" || ($away ne "")) + { + # Check buffer name is an IRC channel + $bufname = weechat::buffer_get_string($cb_bufferp, 'name'); + if ($bufname =~ /(.*)\.([#&\+!])(.*)/) + { + # Are we running on this channel + if (weechat::config_get_plugin($bufname) ne "off" && $cb_disp eq "1") + { + # Format nick + # Line isn't action or topic notify + if (!($cb_tags =~ /irc_action/) && !($cb_tags =~ /irc_topic/)) + { + # Strip nick colour + $uncolnick = weechat::string_remove_color($cb_prefix, ""); + # Format nick + $nick = " ".weechat::config_get_plugin("nick_prefix").weechat::color("chat_highlight").$uncolnick.weechat::color("reset").weechat::config_get_plugin("nick_suffix"); + } + # Topic line + elsif ($cb_tags =~ /irc_topic/) + { + $nick = " ".$cb_prefix.weechat::color("reset"); + } + # Action line + else + { + $uncolnick = weechat::string_remove_color($cb_prefix, ""); + $nick = weechat::color("chat_highlight").$uncolnick.weechat::color("reset"); + } + # Send to output + highmon_print ($cb_msg, $cb_bufferp, $nick, $cb_date, $cb_tags); + } + } + # Or is private message + elsif (weechat::config_get_plugin("merge_private") eq "on" && $cb_tags =~ /notify_private/) + { + # Strip nick colour + $uncolnick = weechat::buffer_get_string($cb_bufferp, 'short_name'); + # Format nick + $nick = " ".weechat::config_get_plugin("nick_prefix").weechat::color("chat_highlight").$uncolnick.weechat::color("reset").weechat::config_get_plugin("nick_suffix"); + #Send to output + highmon_print ($cb_msg, $cb_bufferp, $nick, $cb_date, $cb_tags); + } + } + } + return weechat::WEECHAT_RC_OK; +} + +# Output formatter and printer takes (msg bufpointer nick) +sub highmon_print +{ + $cb_msg = $_[0]; + my $cb_bufferp = $_[1] if ($_[1]); + my $nick = $_[2] if ($_[2]); + my $cb_date = $_[3] if ($_[3]); + my $cb_tags = $_[4] if ($_[4]); + + #Normal channel message + if ($cb_bufferp && $nick) + { + # Format buffer name + $bufname = format_buffer_name($cb_bufferp); + + # If alignment is #channel | nick msg + if (weechat::config_get_plugin("alignment") eq "channel") + { + $nick =~ s/\s(.*)/$1/; + # Build string + $outstr = $bufname."\t".$nick." ".$cb_msg; + } + # or if it is channel number | nick msg + elsif (weechat::config_get_plugin("alignment") eq "schannel") + { + $nick =~ s/\s(.*)/$1/; + # Use channel number instead + $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').weechat::color("reset"); + # Build string + $outstr = $bufname."\t".$nick." ".$cb_msg; + } + # or if it is number:#channel | nick msg + elsif (weechat::config_get_plugin("alignment") eq "nchannel") + { + $nick =~ s/\s(.*)/$1/; + # Place channel number in front of formatted name + $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').":".weechat::color("reset").$bufname; + # Build string + $outstr = $bufname."\t".$nick." ".$cb_msg; + } + # or if it is #channel nick | msg + elsif (weechat::config_get_plugin("alignment") eq "channel,nick") + { + # Build string + $outstr = $bufname.":".$nick."\t".$cb_msg; + } + # or if it is channel number nick | msg + elsif (weechat::config_get_plugin("alignment") eq "schannel,nick") + { + # Use channel number instead + $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').weechat::color("reset"); + # Build string + $outstr = $bufname.":".$nick."\t".$cb_msg; + } + # or if it is number:#channel nick | msg + elsif (weechat::config_get_plugin("alignment") eq "nchannel,nick") + { + # Place channel number in front of formatted name + $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').":".weechat::color("reset").$bufname; + # Build string + $outstr = $bufname.":".$nick."\t".$cb_msg; + } + # or finally | #channel nick msg + else + { + # Build string + $outstr = "\t".$bufname.":".$nick." ".$cb_msg; + } + } + # highmon channel toggle message + elsif ($cb_bufferp && !$nick) + { + # Format buffer name + $bufname = format_buffer_name($cb_bufferp); + + # If alignment is #channel * | * + if (weechat::config_get_plugin("alignment") =~ /channel/) + { + # If it's actually channel number * | * + if (weechat::config_get_plugin("alignment") =~ /schannel/) + { + # Use channel number instead + $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').weechat::color("reset"); + } + # Or if it's actually number:#channel * | * + if (weechat::config_get_plugin("alignment") =~ /nchannel/) + { + # Place channel number in front of formatted name + $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').":".weechat::color("reset").$bufname; + } + $outstr = $bufname."\t".$cb_msg; + } + # or if alignment is | * + else + { + $outstr = $bufname.": ".$cb_msg; + } + } + # highmon dynmon + elsif (!$cb_bufferp && !$nick) + { + $outstr = "\t".$cb_msg; + } + + # Send string to buffer + if (weechat::config_get_plugin("output") eq "buffer") + { + # Search for and confirm buffer + $highmon_buffer = weechat::buffer_search("perl", "highmon"); + # Print + if ($cb_date) + { + weechat::print_date_tags($highmon_buffer, $cb_date, $cb_tags, $outstr); + } + else + { + weechat::print($highmon_buffer, $outstr); + } + } + elsif (weechat::config_get_plugin("output") eq "bar") + { + # Add time string + use POSIX qw(strftime); + if ($cb_date) + { + $time = strftime(weechat::config_string(weechat::config_get("weechat.look.buffer_time_format")), localtime($cb_date)); + } + else + { + $time = strftime(weechat::config_string(weechat::config_get("weechat.look.buffer_time_format")), localtime); + } + # Colourise + if ($time =~ /\$\{(?:color:)?[\w,]+\}/) # Coloured string + { + while ($time =~ /\$\{(?:color:)?([\w,]+)\}/) + { + $color = weechat::color($1); + $time =~ s/\$\{(?:color:)?[\w,]+\}/$color/; + } + $time .= weechat::color("reset"); + } + else # Default string + { + $colour = weechat::color(weechat::config_string(weechat::config_get("weechat.color.chat_time_delimiters"))); + $reset = weechat::color("reset"); + $time =~ s/(\d*)(.)(\d*)/$1$colour$2$reset$3/g; + } + # Push updates to bar lists + push (@bar_lines_time, $time); + + # Change tab char + $delim = " ".weechat::color(weechat::config_string(weechat::config_get("weechat.color.chat_delimiters"))).weechat::config_string(weechat::config_get("weechat.look.prefix_suffix")).weechat::color("reset")." "; + $outstr =~ s/\t/$delim/; + + push (@bar_lines, $outstr); + # Trigger update + weechat::bar_item_update("highmon"); + + if (weechat::config_get_plugin("bar_scrolldown") eq "on") + { + weechat::command("", "/bar scroll highmon * ye") + } + } +} + +# Start the output display +sub highmon_start +{ + if (weechat::config_get_plugin("output") eq "buffer") + { + highmon_buffer_open(); + } + elsif (weechat::config_get_plugin("output") eq "bar") + { + highmon_bar_open(); + } +} + +# Takes two optional args (channel server), toggles monitoring on/off +sub highmon_toggle +{ + $data = $_[0]; + $buffer = $_[1]; + $args = $_[2]; + + # Check if we've been told what channel to act on + if ($args ne "") + { + # Split argument up + @arg_array = split(/ /,$args); + # Check if a server was given + if ($arg_array[1]) + { + # Find matching + $bufp = weechat::buffer_search("irc", $arg_array[1].".".$arg_array[0]); + } + else + { + $found_chans = 0; + # Loop through defined servers + $infolist = weechat::infolist_get("buffer", "", ""); + while (weechat::infolist_next($infolist)) + { + # Only interesting in IRC buffers + if (weechat::infolist_string($infolist, "plugin_name") eq "irc") + { + # Find buffers that maych + $sname = weechat::infolist_string($infolist, "short_name"); + if ($sname eq $arg_array[0]) + { + $found_chans++; + $bufp = weechat::infolist_pointer($infolist, "pointer"); + } + } + } + weechat::infolist_free($infolist); + # If the infolist found more than one channel, halt as we need to know which one + if ($found_chans > 1) + { + weechat::print("", "Channel name is not unique, please define server"); + return weechat::WEECHAT_RC_OK; + } + } + # Something didn't return right + if ($bufp eq "") + { + weechat::print("", "Could not find buffer"); + return weechat::WEECHAT_RC_OK; + } + } + else + { + # Get pointer from where we are + $bufp = weechat::current_buffer(); + } + # Get buffer name + $bufname = weechat::buffer_get_string($bufp, 'name'); + # Test if buffer is an IRC channel + if ($bufname =~ /(.*)\.([#&\+!])(.*)/) + { + if (weechat::config_get_plugin($bufname) eq "off") + { + # If currently off, set on + weechat::config_set_plugin($bufname, "on"); + + # Send to output formatter + highmon_print("Highlight Monitoring Enabled", $bufp); + return weechat::WEECHAT_RC_OK; + } + elsif (weechat::config_get_plugin($bufname) eq "on" || weechat::config_get_plugin($bufname) eq "") + { + # If currently on, set off + weechat::config_set_plugin($bufname, "off"); + + # Send to output formatter + highmon_print("Highlight Monitoring Disabled", $bufp); + return weechat::WEECHAT_RC_OK; + } + } +} + +# Takes a buffer pointer and returns a formatted name +sub format_buffer_name +{ + $cb_bufferp = $_[0]; + $bufname = weechat::buffer_get_string($cb_bufferp, 'name'); + + # Set colour from buffer name + if (weechat::config_get_plugin("color_buf") eq "on") + { + # Determine what colour to use + $color = weechat::info_get("irc_nick_color", $bufname); + if (!$color) + { + $color = 0; + @char_array = split(//,$bufname); + foreach $char (@char_array) + { + $color += ord($char); + } + $color %= 10; + $color = sprintf "weechat.color.chat_nick_color%02d", $color+1; + $color = weechat::config_get($color); + $color = weechat::config_string($color); + $color = weechat::color($color); + } + + # Private message just show network + if (weechat::config_get_plugin("merge_private") eq "on" && weechat::buffer_get_string($cb_bufferp, "localvar_type") eq "private") + { + $bufname = weechat::buffer_get_string($cb_bufferp, "localvar_server"); + } + # Format name to short or 'nicename' + elsif (weechat::config_get_plugin("short_names") eq "on") + { + $bufname = weechat::buffer_get_string($cb_bufferp, 'short_name'); + } + else + { + $bufname =~ s/(.*)\.([#&\+!])(.*)/$1$2$3/; + } + + # Build a coloured string + $bufname = $color.$bufname.weechat::color("reset"); + } + # User set colour name + elsif (weechat::config_get_plugin("color_buf") ne "off") + { + # Private message just show network + if (weechat::config_get_plugin("merge_private") eq "on" && weechat::buffer_get_string($cb_bufferp, "localvar_type") eq "private") + { + $bufname = weechat::buffer_get_string($cb_bufferp, "localvar_server"); + } + # Format name to short or 'nicename' + elsif (weechat::config_get_plugin("short_names") eq "on") + { + $bufname = weechat::buffer_get_string($cb_bufferp, 'short_name'); + } + else + { + $bufname =~ s/(.*)\.([#&\+!])(.*)/$1$2$3/; + } + + $color = weechat::config_get_plugin("color_buf"); + $bufname = weechat::color($color).$bufname.weechat::color("reset"); + } + # Stick with default colour + else + { + # Private message just show network + if (weechat::config_get_plugin("merge_private") eq "on" && weechat::buffer_get_string($cb_bufferp, "localvar_type") eq "private") + { + $bufname = weechat::buffer_get_string($cb_bufferp, "localvar_server"); + } + # Format name to short or 'nicename' + elsif (weechat::config_get_plugin("short_names") eq "on") + { + $bufname = weechat::buffer_get_string($cb_bufferp, 'short_name'); + } + else + { + $bufname =~ s/(.*)\.([#&\+!])(.*)/$1$2$3/; + } + } + + return $bufname; +} + +# Check result of register, and attempt to behave in a sane manner +if (!weechat::register("highmon", "KenjiE20", "2.5", "GPL3", "Highlight Monitor", "", "")) +{ + # Double load + weechat::print ("", "\tHighmon is already loaded"); + return weechat::WEECHAT_RC_OK; +} +else +{ + # Start everything + highmon_hook(); + highmon_config_init(); + highmon_start(); +} diff --git a/.weechat/perl/iset.pl b/.weechat/perl/iset.pl new file mode 100644 index 0000000..163dfb5 --- /dev/null +++ b/.weechat/perl/iset.pl @@ -0,0 +1,1624 @@ +# +# Copyright (C) 2008-2014 Sebastien Helleu +# Copyright (C) 2010-2015 Nils Görs +# +# This program 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. +# +# This program 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 this program. If not, see . +# +# Set WeeChat and plugins options interactively. +# +# History: +# +# 2016-07-08, nils_2 +# version 4.2: add diff function +# 2016-02-06, Sebastien Helleu : +# version 4.1: remove debug print +# 2015-12-24, Sebastien Helleu : +# version 4.0: add support of parent options (inherited values in irc servers) +# with WeeChat >= 1.4 +# 2015-05-16, Sebastien Helleu : +# version 3.9: fix cursor position when editing an option with WeeChat >= 1.2 +# 2015-05-02, arza : +# version 3.8: don't append "null" to /set when setting an undefined setting +# 2015-05-01, nils_2 : +# version 3.7: fix two perl warnings (reported by t3chguy) +# 2014-09-30, arza : +# version 3.6: fix current line counter when options aren't found +# 2014-06-03, nils_2 : +# version 3.5: add new option "use_mute" +# 2014-01-30, stfn : +# version 3.4: add new options "color_value_diff" and "color_value_diff_selected" +# 2014-01-16, luz : +# version 3.3: fix bug with column alignment in iset buffer when option +# name contains unicode characters +# 2013-08-03, Sebastien Helleu : +# version 3.2: allow "q" as input in iset buffer to close it +# 2013-07-14, Sebastien Helleu : +# version 3.1: remove unneeded calls to iset_refresh() in mouse callback +# (faster mouse actions when lot of options are displayed), +# fix bug when clicking on a line after the last option displayed +# 2013-04-30, arza : +# version 3.0: simpler title, fix refresh on unset +# 2012-12-16, nils_2 : +# version 2.9: fix focus window with iset buffer on mouse click +# 2012-08-25, nils_2 : +# version 2.8: most important key and mouse bindings for iset buffer added to title-bar (idea The-Compiler) +# 2012-07-31, nils_2 : +# version 2.7: add combined option and value search (see /help iset) +# : add exact value search (see /help iset) +# : fix problem with metacharacter in value search +# : fix use of uninitialized value for unset option and reset value of option +# 2012-07-25, nils_2 : +# version 2.6: switch to iset buffer (if existing) when command /iset is called with arguments +# 2012-03-17, Sebastien Helleu : +# version 2.5: fix check of sections when creating config file +# 2012-03-09, Sebastien Helleu : +# version 2.4: fix reload of config file +# 2012-02-02, nils_2 : +# version 2.3: fixed: refresh problem with new search results and cursor was outside window. +# : add: new option "current_line" in title bar +# version 2.2: fixed: refresh error when toggling plugins description +# 2011-11-05, nils_2 : +# version 2.1: use own config file (iset.conf), fix own help color (used immediately) +# 2011-10-16, nils_2 : +# version 2.0: add support for left-mouse-button and more sensitive mouse gesture (for integer/color options) +# add help text for mouse support +# 2011-09-20, Sebastien Helleu : +# version 1.9: add mouse support, fix iset buffer, fix errors on first load under FreeBSD +# 2011-07-21, nils_2 : +# version 1.8: added: option "show_plugin_description" (alt+p) +# fixed: typos in /help iset (lower case for alt+'x' keys) +# 2011-05-29, nils_2 : +# version 1.7: added: version check for future needs +# added: new option (scroll_horiz) and usage of scroll_horiz function (weechat >= 0.3.6 required) +# fixed: help_bar did not pop up immediately using key-shortcut +# 2011-02-19, nils_2 : +# version 1.6: added: display of all possible values in help bar (show_help_extra_info) +# fixed: external user options never loaded when starting iset first time +# 2011-02-13, Sebastien Helleu : +# version 1.5: use new help format for command arguments +# 2011-02-03, nils_2 : +# version 1.4: fixed: restore value filter after /upgrade using buffer local variable. +# 2011-01-14, nils_2 : +# version 1.3: added function to search for values (option value_search_char). +# code optimization. +# 2010-12-26, Sebastien Helleu : +# version 1.2: improve speed of /upgrade when iset buffer is open, +# restore filter used after /upgrade using buffer local variable, +# use /iset filter argument if buffer is open. +# 2010-11-21, drubin : +# version 1.1.1: fix bugs with cursor position +# 2010-11-20, nils_2 : +# version 1.1: cursor position set to value +# 2010-08-03, Sebastien Helleu : +# version 1.0: move misplaced call to infolist_free() +# 2010-02-02, rettub : +# version 0.9: turn all the help stuff off if option 'show_help_bar' is 'off', +# new key binding - to toggle help_bar and help stuff on/off +# 2010-01-30, nils_2 : +# version 0.8: fix error when option does not exist +# 2010-01-24, Sebastien Helleu : +# version 0.7: display iset bar only on iset buffer +# 2010-01-22, nils_2 and drubin: +# version 0.6: add description in a bar, fix singular/plural bug in title bar, +# fix selected line when switching buffer +# 2009-06-21, Sebastien Helleu : +# version 0.5: fix bug with iset buffer after /upgrade +# 2009-05-02, Sebastien Helleu : +# version 0.4: sync with last API changes +# 2009-01-04, Sebastien Helleu : +# version 0.3: open iset buffer when /iset command is executed +# 2009-01-04, Sebastien Helleu : +# version 0.2: use null values for options, add colors, fix refresh bugs, +# use new keys to reset/unset options, sort options by name, +# display number of options in buffer's title +# 2008-11-05, Sebastien Helleu : +# version 0.1: first official version +# 2008-04-19, Sebastien Helleu : +# script creation + +use strict; + +my $PRGNAME = "iset"; +my $VERSION = "4.2"; +my $DESCR = "Interactive Set for configuration options"; +my $AUTHOR = "Sebastien Helleu "; +my $LICENSE = "GPL3"; +my $LANG = "perl"; +my $ISET_CONFIG_FILE_NAME = "iset"; + +my $iset_config_file; +my $iset_buffer = ""; +my $wee_version_number = 0; +my @iset_focus = (); +my @options_names = (); +my @options_parent_names = (); +my @options_types = (); +my @options_values = (); +my @options_default_values = (); +my @options_parent_values = (); +my @options_is_null = (); +my $option_max_length = 0; +my $current_line = 0; +my $filter = "*"; +my $description = ""; +my $options_name_copy = ""; +my $iset_filter_title = ""; +# search modes: 0 = index() on value, 1 = grep() on value, 2 = grep() on option, 3 = grep on option & value, 4 = diff all, 5 = diff parts +my $search_mode = 2; +my $search_value = ""; +my $help_text_keys = "alt + space: toggle, +/-: increase/decrease, enter: change, ir: reset, iu: unset, v: toggle help bar"; +my $help_text_mouse = "Mouse: left: select, right: toggle/set, right + drag left/right: increase/decrease"; +my %options_iset; + +my %mouse_keys = ("\@chat(perl.$PRGNAME):button1" => "hsignal:iset_mouse", + "\@chat(perl.$PRGNAME):button2*" => "hsignal:iset_mouse", + "\@chat(perl.$PRGNAME):wheelup" => "/repeat 5 /iset **up", + "\@chat(perl.$PRGNAME):wheeldown" => "/repeat 5 /iset **down"); + + +sub iset_title +{ + if ($iset_buffer ne "") + { + my $current_line_counter = ""; + if (weechat::config_boolean($options_iset{"show_current_line"}) == 1) + { + if (@options_names eq 0) + { + $current_line_counter = "0/"; + } + else + { + $current_line_counter = ($current_line + 1) . "/"; + } + } + my $show_filter = ""; + if ($search_mode eq 0) + { + $iset_filter_title = "(value) "; + $show_filter = $search_value; + if ( substr($show_filter,0,1) eq weechat::config_string($options_iset{"value_search_char"}) ) + { + $show_filter = substr($show_filter,1,length($show_filter)); + } + } + elsif ($search_mode eq 1) + { + $iset_filter_title = "(value) "; + $show_filter = "*".$search_value."*"; + } + elsif ($search_mode eq 2) + { + $iset_filter_title = ""; + $filter = "*" if ($filter eq ""); + $show_filter = $filter; + } + elsif ($search_mode == 4 or $search_mode == 5) + { + $iset_filter_title = "diff: "; + $show_filter = "all"; + $show_filter = $search_value if $search_mode == 5; + } + elsif ($search_mode eq 3) + { + $iset_filter_title = "(option) "; + $show_filter = $filter + .weechat::color("default") + ." / (value) " + .weechat::color("yellow") + ."*".$search_value."*"; + } + weechat::buffer_set($iset_buffer, "title", + $iset_filter_title + .weechat::color("yellow") + .$show_filter + .weechat::color("default")." | " + .$current_line_counter + .@options_names + ." | " + .$help_text_keys + ." | " + .$help_text_mouse); + } +} + +sub iset_create_filter +{ + $filter = $_[0]; + if ( $search_mode == 3 ) + { + my @cmd_array = split(/ /,$filter); + my $array_count = @cmd_array; + $filter = $cmd_array[0]; + $filter = $cmd_array[0] . " " . $cmd_array[1] if ( $array_count >2 ); + } + $filter = "$1.*" if ($filter =~ /f (.*)/); # search file + $filter = "*.$1.*" if ($filter =~ /s (.*)/); # search section + if ((substr($filter, 0, 1) ne "*") && (substr($filter, -1, 1) ne "*")) + { + $filter = "*".$filter."*"; + } + if ($iset_buffer ne "") + { + weechat::buffer_set($iset_buffer, "localvar_set_iset_filter", $filter); + } +} + +sub iset_buffer_input +{ + my ($data, $buffer, $string) = ($_[0], $_[1], $_[2]); + + # string begins with space? + return weechat::WEECHAT_RC_OK if (substr($string, 0, 1 ) eq " "); + + if ($string eq "q") + { + weechat::buffer_close($buffer); + return weechat::WEECHAT_RC_OK; + } + $search_value = ""; + my @cmd_array = split(/ /,$string); + my $array_count = @cmd_array; + my $string2 = substr($string, 0, 1); + if ($string2 eq weechat::config_string($options_iset{"value_search_char"}) + or (defined $cmd_array[0] and $cmd_array[0] eq weechat::config_string($options_iset{"value_search_char"}).weechat::config_string($options_iset{"value_search_char"})) ) + { + $search_mode = 1; + $search_value = substr($string, 1); + iset_get_values($search_value); + if ($iset_buffer ne "") + { + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $search_value); + } + } + # show all diff values + elsif ($string eq "d") + { + $search_mode = 4; +# iset_title(); + iset_create_filter("*"); + iset_get_options("*"); + } + elsif ( $array_count >= 2 and $cmd_array[0] eq "d") + { + $search_mode = 5; + $search_value = substr($cmd_array[1], 0); # cut value_search_char + $search_value = substr($cmd_array[2], 0) if ( $array_count > 2); # cut value_search_char + iset_create_filter($search_value); + iset_get_options($search_value); + + } + else + { + $search_mode = 2; + if ( $array_count >= 2 and $cmd_array[0] ne "f" or $cmd_array[0] ne "s" ) + { + if ( defined $cmd_array[1] and substr($cmd_array[1], 0, 1) eq weechat::config_string($options_iset{"value_search_char"}) + or defined $cmd_array[2] and substr($cmd_array[2], 0, 1) eq weechat::config_string($options_iset{"value_search_char"}) ) + { + $search_mode = 3; + $search_value = substr($cmd_array[1], 1); # cut value_search_char + $search_value = substr($cmd_array[2], 1) if ( $array_count > 2); # cut value_search_char + } + } + if ( $search_mode == 3) + { + iset_create_filter($string); + iset_get_options($search_value); + } + else + { + iset_create_filter($string); + iset_get_options(""); + } + } + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_mode", $search_mode); + weechat::buffer_clear($buffer); + $current_line = 0; + iset_refresh(); + return weechat::WEECHAT_RC_OK; +} + +sub iset_buffer_close +{ + $iset_buffer = ""; + + return weechat::WEECHAT_RC_OK; +} + +sub iset_init +{ + $current_line = 0; + $iset_buffer = weechat::buffer_search($LANG, $PRGNAME); + if ($iset_buffer eq "") + { + $iset_buffer = weechat::buffer_new($PRGNAME, "iset_buffer_input", "", "iset_buffer_close", ""); + } + else + { + my $new_filter = weechat::buffer_get_string($iset_buffer, "localvar_iset_filter"); + $search_mode = weechat::buffer_get_string($iset_buffer, "localvar_iset_search_mode"); + $search_value = weechat::buffer_get_string($iset_buffer, "localvar_iset_search_value"); + $filter = $new_filter if ($new_filter ne ""); + } + if ($iset_buffer ne "") + { + weechat::buffer_set($iset_buffer, "type", "free"); + iset_title(); + weechat::buffer_set($iset_buffer, "key_bind_ctrl-L", "/iset **refresh"); + weechat::buffer_set($iset_buffer, "key_bind_meta2-A", "/iset **up"); + weechat::buffer_set($iset_buffer, "key_bind_meta2-B", "/iset **down"); + weechat::buffer_set($iset_buffer, "key_bind_meta2-23~", "/iset **left"); + weechat::buffer_set($iset_buffer, "key_bind_meta2-24~" , "/iset **right"); + weechat::buffer_set($iset_buffer, "key_bind_meta- ", "/iset **toggle"); + weechat::buffer_set($iset_buffer, "key_bind_meta-+", "/iset **incr"); + weechat::buffer_set($iset_buffer, "key_bind_meta--", "/iset **decr"); + weechat::buffer_set($iset_buffer, "key_bind_meta-imeta-r", "/iset **reset"); + weechat::buffer_set($iset_buffer, "key_bind_meta-imeta-u", "/iset **unset"); + weechat::buffer_set($iset_buffer, "key_bind_meta-ctrl-J", "/iset **set"); + weechat::buffer_set($iset_buffer, "key_bind_meta-ctrl-M", "/iset **set"); + weechat::buffer_set($iset_buffer, "key_bind_meta-meta2-1~", "/iset **scroll_top"); + weechat::buffer_set($iset_buffer, "key_bind_meta-meta2-4~", "/iset **scroll_bottom"); + weechat::buffer_set($iset_buffer, "key_bind_meta-v", "/iset **toggle_help"); + weechat::buffer_set($iset_buffer, "key_bind_meta-p", "/iset **toggle_show_plugin_desc"); + weechat::buffer_set($iset_buffer, "localvar_set_iset_filter", $filter); + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_mode", $search_mode); + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $search_value); + } +} + +sub iset_get_options +{ + my $var_value = $_[0]; + $var_value = "" if (not defined $var_value); + $var_value = lc($var_value); + $search_value = $var_value; + @iset_focus = (); + @options_names = (); + @options_parent_names = (); + @options_types = (); + @options_values = (); + @options_default_values = (); + @options_parent_values = (); + @options_is_null = (); + $option_max_length = 0; + my %options_internal = (); + my $i = 0; + my $key; + my $iset_struct; + my %iset_struct; + + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $var_value) if ($search_mode == 3); + + my $infolist = weechat::infolist_get("option", "", $filter); + while (weechat::infolist_next($infolist)) + { + $key = sprintf("%08d", $i); + my $name = weechat::infolist_string($infolist, "full_name"); + my $parent_name = weechat::infolist_string($infolist, "parent_name"); + next if (weechat::config_boolean($options_iset{"show_plugin_description"}) == 0 and index ($name, "plugins.desc.") != -1); + my $type = weechat::infolist_string($infolist, "type"); + my $value = weechat::infolist_string($infolist, "value"); + my $default_value = weechat::infolist_string($infolist, "default_value"); + my $parent_value; + if ($parent_name && (($wee_version_number < 0x00040300) || (weechat::infolist_search_var($infolist, "parent_value")))) + { + $parent_value = weechat::infolist_string($infolist, "parent_value"); + } + my $is_null = weechat::infolist_integer($infolist, "value_is_null"); + + if ($search_mode == 3) + { + my $value = weechat::infolist_string($infolist, "value"); + if ( grep /\Q$var_value/,lc($value) ) + { + $options_internal{$name}{"parent_name"} = $parent_name; + $options_internal{$name}{"type"} = $type; + $options_internal{$name}{"value"} = $value; + $options_internal{$name}{"default_value"} = $default_value; + $options_internal{$name}{"parent_value"} = $parent_value; + $options_internal{$name}{"is_null"} = $is_null; + $option_max_length = length($name) if (length($name) > $option_max_length); + $iset_struct{$key} = $options_internal{$name}; + push(@iset_focus, $iset_struct{$key}); + } + } + # search for diff? + elsif ( $search_mode == 4 or $search_mode == 5) + { + if ($value ne $default_value ) + { + $options_internal{$name}{"parent_name"} = $parent_name; + $options_internal{$name}{"type"} = $type; + $options_internal{$name}{"value"} = $value; + $options_internal{$name}{"default_value"} = $default_value; + $options_internal{$name}{"parent_value"} = $parent_value; + $options_internal{$name}{"is_null"} = $is_null; + $option_max_length = length($name) if (length($name) > $option_max_length); + $iset_struct{$key} = $options_internal{$name}; + push(@iset_focus, $iset_struct{$key}); + } + } + else + { + $options_internal{$name}{"parent_name"} = $parent_name; + $options_internal{$name}{"type"} = $type; + $options_internal{$name}{"value"} = $value; + $options_internal{$name}{"default_value"} = $default_value; + $options_internal{$name}{"parent_value"} = $parent_value; + $options_internal{$name}{"is_null"} = $is_null; + $option_max_length = length($name) if (length($name) > $option_max_length); + $iset_struct{$key} = $options_internal{$name}; + push(@iset_focus, $iset_struct{$key}); + } + $i++; + } + weechat::infolist_free($infolist); + + foreach my $name (sort keys %options_internal) + { + push(@options_names, $name); + push(@options_parent_names, $options_internal{$name}{"parent_name"}); + push(@options_types, $options_internal{$name}{"type"}); + push(@options_values, $options_internal{$name}{"value"}); + push(@options_default_values, $options_internal{$name}{"default_value"}); + push(@options_parent_values, $options_internal{$name}{"parent_value"}); + push(@options_is_null, $options_internal{$name}{"is_null"}); + } +} + +sub iset_get_values +{ + my $var_value = $_[0]; + $var_value = lc($var_value); + if (substr($var_value,0,1) eq weechat::config_string($options_iset{"value_search_char"}) and $var_value ne weechat::config_string($options_iset{"value_search_char"})) + { + $var_value = substr($var_value,1,length($var_value)); + $search_mode = 0; + } + iset_search_values($var_value,$search_mode); + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_mode", $search_mode); + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $var_value); + $search_value = $var_value; +} +sub iset_search_values +{ + my ($var_value,$search_mode) = ($_[0],$_[1]); + @options_names = (); + @options_parent_names = (); + @options_types = (); + @options_values = (); + @options_default_values = (); + @options_parent_values = (); + @options_is_null = (); + $option_max_length = 0; + my %options_internal = (); + my $i = 0; + my $infolist = weechat::infolist_get("option", "", "*"); + while (weechat::infolist_next($infolist)) + { + my $name = weechat::infolist_string($infolist, "full_name"); + my $parent_name = weechat::infolist_string($infolist, "parent_name"); + next if (weechat::config_boolean($options_iset{"show_plugin_description"}) == 0 and index ($name, "plugins.desc.") != -1); + my $type = weechat::infolist_string($infolist, "type"); + my $is_null = weechat::infolist_integer($infolist, "value_is_null"); + my $value = weechat::infolist_string($infolist, "value"); + my $default_value = weechat::infolist_string($infolist, "default_value"); + my $parent_value; + if ($parent_name && (($wee_version_number < 0x00040300) || (weechat::infolist_search_var($infolist, "parent_value")))) + { + $parent_value = weechat::infolist_string($infolist, "parent_value"); + } + if ($search_mode) + { + if ( grep /\Q$var_value/,lc($value) ) + { + $options_internal{$name}{"parent_name"} = $parent_name; + $options_internal{$name}{"type"} = $type; + $options_internal{$name}{"value"} = $value; + $options_internal{$name}{"default_value"} = $default_value; + $options_internal{$name}{"parent_value"} = $parent_value; + $options_internal{$name}{"is_null"} = $is_null; + $option_max_length = length($name) if (length($name) > $option_max_length); + } + } + else + { +# if ($value =~ /\Q$var_value/si) + if (lc($value) eq $var_value) + { + $options_internal{$name}{"parent_name"} = $parent_name; + $options_internal{$name}{"type"} = $type; + $options_internal{$name}{"value"} = $value; + $options_internal{$name}{"default_value"} = $default_value; + $options_internal{$name}{"parent_value"} = $parent_value; + $options_internal{$name}{"is_null"} = $is_null; + $option_max_length = length($name) if (length($name) > $option_max_length); + } + } + $i++; + } + weechat::infolist_free($infolist); + foreach my $name (sort keys %options_internal) + { + push(@options_names, $name); + push(@options_parent_names, $options_internal{$name}{"parent_name"}); + push(@options_types, $options_internal{$name}{"type"}); + push(@options_values, $options_internal{$name}{"value"}); + push(@options_default_values, $options_internal{$name}{"default_value"}); + push(@options_parent_values, $options_internal{$name}{"parent_value"}); + push(@options_is_null, $options_internal{$name}{"is_null"}); + } +} + +sub iset_refresh_line +{ + if ($iset_buffer ne "") + { + my $y = $_[0]; + if ($y <= $#options_names) + { + return if (! defined($options_types[$y])); + my $format = sprintf("%%s%%s%%s %%s %%-7s %%s %%s%%s%%s"); + my $padding; + if ($wee_version_number >= 0x00040200) + { + $padding = " " x ($option_max_length - weechat::strlen_screen($options_names[$y])); + } + else + { + $padding = " " x ($option_max_length - length($options_names[$y])); + } + my $around = ""; + $around = "\"" if ((!$options_is_null[$y]) && ($options_types[$y] eq "string")); + + my $color1 = weechat::color(weechat::config_color($options_iset{"color_option"})); + my $color2 = weechat::color(weechat::config_color($options_iset{"color_type"})); + my $color3 = ""; + my $color4 = ""; + if ($options_is_null[$y]) + { + $color3 = weechat::color(weechat::config_color($options_iset{"color_value_undef"})); + $color4 = weechat::color(weechat::config_color($options_iset{"color_value"})); + } + elsif ($options_values[$y] ne $options_default_values[$y]) + { + $color3 = weechat::color(weechat::config_color($options_iset{"color_value_diff"})); + } + else + { + $color3 = weechat::color(weechat::config_color($options_iset{"color_value"})); + } + if ($y == $current_line) + { + $color1 = weechat::color(weechat::config_color($options_iset{"color_option_selected"}).",".weechat::config_color($options_iset{"color_bg_selected"})); + $color2 = weechat::color(weechat::config_color($options_iset{"color_type_selected"}).",".weechat::config_color($options_iset{"color_bg_selected"})); + if ($options_is_null[$y]) + { + $color3 = weechat::color(weechat::config_color($options_iset{"color_value_undef_selected"}).",".weechat::config_color($options_iset{"color_bg_selected"})); + $color4 = weechat::color(weechat::config_color($options_iset{"color_value_selected"}).",".weechat::config_color($options_iset{"color_bg_selected"})); + } + elsif ($options_values[$y] ne $options_default_values[$y]) + { + $color3 = weechat::color(weechat::config_color($options_iset{"color_value_diff_selected"}).",".weechat::config_color($options_iset{"color_bg_selected"})); + } + else + { + $color3 = weechat::color(weechat::config_color($options_iset{"color_value_selected"}).",".weechat::config_color($options_iset{"color_bg_selected"})); + } + } + my $value = $options_values[$y]; + if ($options_is_null[$y]) + { + $value = "null"; + if ($options_parent_names[$y]) + { + if (defined $options_parent_values[$y]) + { + my $around_parent = ""; + $around_parent = "\"" if ($options_types[$y] eq "string"); + $value .= $color1." -> ".$color4.$around_parent.$options_parent_values[$y].$around_parent; + } + else + { + $value .= $color1." -> ".$color3."null"; + } + } + } + my $strline = sprintf($format, + $color1, $options_names[$y], $padding, + $color2, $options_types[$y], + $color3, $around, $value, $around); + weechat::print_y($iset_buffer, $y, $strline); + } + } +} + +sub iset_refresh +{ + iset_title(); + if (($iset_buffer ne "") && ($#options_names >= 0)) + { + foreach my $y (0 .. $#options_names) + { + iset_refresh_line($y); + } + } + + weechat::bar_item_update("isetbar_help") if (weechat::config_boolean($options_iset{"show_help_bar"}) == 1); +} + +sub iset_full_refresh +{ + $iset_buffer = weechat::buffer_search($LANG, $PRGNAME); + if ($iset_buffer ne "") + { + weechat::buffer_clear($iset_buffer) unless defined $_[0]; # iset_full_refresh(1) does a full refresh without clearing buffer + # search for "*" in $filter. + if ($filter =~ m/\*/ and $search_mode == 2) + { + iset_get_options(""); + } + else + { + if ($search_mode == 0) + { + $search_value = "=" . $search_value; + iset_get_values($search_value); + } + elsif ($search_mode == 1) + { + iset_get_values($search_value); + } + elsif ($search_mode == 3) + { + iset_create_filter($filter); + iset_get_options($search_value); + } + } + if (weechat::config_boolean($options_iset{"show_plugin_description"}) == 1) + { + iset_set_current_line($current_line); + }else + { + $current_line = $#options_names if ($current_line > $#options_names); + } + iset_refresh(); + weechat::command($iset_buffer, "/window refresh"); + } +} + +sub iset_set_current_line +{ + my $new_current_line = $_[0]; + if ($new_current_line >= 0) + { + my $old_current_line = $current_line; + $current_line = $new_current_line; + $current_line = $#options_names if ($current_line > $#options_names); + if ($old_current_line != $current_line) + { + iset_refresh_line($old_current_line); + iset_refresh_line($current_line); + weechat::bar_item_update("isetbar_help") if (weechat::config_boolean($options_iset{"show_help_bar"}) == 1); + } + } +} + +sub iset_signal_window_scrolled_cb +{ + my ($data, $signal, $signal_data) = ($_[0], $_[1], $_[2]); + if ($iset_buffer ne "") + { + my $infolist = weechat::infolist_get("window", $signal_data, ""); + if (weechat::infolist_next($infolist)) + { + if (weechat::infolist_pointer($infolist, "buffer") eq $iset_buffer) + { + my $old_current_line = $current_line; + my $new_current_line = $current_line; + my $start_line_y = weechat::infolist_integer($infolist, "start_line_y"); + my $chat_height = weechat::infolist_integer($infolist, "chat_height"); + $new_current_line += $chat_height if ($new_current_line < $start_line_y); + $new_current_line -= $chat_height if ($new_current_line >= $start_line_y + $chat_height); + $new_current_line = $start_line_y if ($new_current_line < $start_line_y); + $new_current_line = $start_line_y + $chat_height - 1 if ($new_current_line >= $start_line_y + $chat_height); + iset_set_current_line($new_current_line); + } + } + weechat::infolist_free($infolist); + } + + return weechat::WEECHAT_RC_OK; +} + +sub iset_get_window_number +{ + if ($iset_buffer ne "") + { + my $window = weechat::window_search_with_buffer($iset_buffer); + return "-window ".weechat::window_get_integer ($window, "number")." " if ($window ne ""); + } + return ""; +} + +sub iset_check_line_outside_window +{ + if ($iset_buffer ne "") + { + undef my $infolist; + if ($wee_version_number >= 0x00030500) + { + my $window = weechat::window_search_with_buffer($iset_buffer); + $infolist = weechat::infolist_get("window", $window, "") if $window; + } + else + { + $infolist = weechat::infolist_get("window", "", "current"); + } + if ($infolist) + { + if (weechat::infolist_next($infolist)) + { + my $start_line_y = weechat::infolist_integer($infolist, "start_line_y"); + my $chat_height = weechat::infolist_integer($infolist, "chat_height"); + my $window_number = ""; + if ($wee_version_number >= 0x00030500) + { + $window_number = "-window ".weechat::infolist_integer($infolist, "number")." "; + } + if ($start_line_y > $current_line) + { + weechat::command($iset_buffer, "/window scroll ".$window_number."-".($start_line_y - $current_line)); + } + else + { + if ($start_line_y <= $current_line - $chat_height) + { + weechat::command($iset_buffer, "/window scroll ".$window_number."+".($current_line - $start_line_y - $chat_height + 1)); + + } + } + } + weechat::infolist_free($infolist); + } + } +} + +sub iset_get_option_name_index +{ + my $option_name = $_[0]; + my $index = 0; + while ($index <= $#options_names) + { + return -1 if ($options_names[$index] gt $option_name); + return $index if ($options_names[$index] eq $option_name); + $index++; + } + return -1; +} + +sub iset_refresh_option +{ + my $option_name = $_[0]; + my $index = $_[1]; + my $infolist = weechat::infolist_get("option", "", $option_name); + if ($infolist) + { + weechat::infolist_next($infolist); + if (weechat::infolist_fields($infolist)) + { + $options_parent_names[$index] = weechat::infolist_string($infolist, "parent_name"); + $options_types[$index] = weechat::infolist_string($infolist, "type"); + $options_values[$index] = weechat::infolist_string($infolist, "value"); + $options_default_values[$index] = weechat::infolist_string($infolist, "default_value"); + $options_is_null[$index] = weechat::infolist_integer($infolist, "value_is_null"); + $options_parent_values[$index] = undef; + if ($options_parent_names[$index] + && (($wee_version_number < 0x00040300) || (weechat::infolist_search_var($infolist, "parent_value")))) + { + $options_parent_values[$index] = weechat::infolist_string($infolist, "parent_value"); + } + iset_refresh_line($index); + iset_title() if ($option_name eq "iset.look.show_current_line"); + } + else + { + iset_full_refresh(1); # if not found, refresh fully without clearing buffer + weechat::print_y($iset_buffer, $#options_names + 1, ""); + } + weechat::infolist_free($infolist); + } +} + +sub iset_config_cb +{ + my ($data, $option_name, $value) = ($_[0], $_[1], $_[2]); + + if ($iset_buffer ne "") + { + return weechat::WEECHAT_RC_OK if (weechat::info_get("weechat_upgrading", "") eq "1"); + + my $index = iset_get_option_name_index($option_name); + if ($index >= 0) + { + # refresh info about changed option + iset_refresh_option($option_name, $index); + # refresh any other option having this changed option as parent + foreach my $i (0 .. $#options_names) + { + if ($options_parent_names[$i] eq $option_name) + { + iset_refresh_option($options_names[$i], $i); + } + } + } + else + { + iset_full_refresh() if ($option_name ne "weechat.bar.isetbar.hidden"); + } + } + + return weechat::WEECHAT_RC_OK; +} + +sub iset_set_option +{ + my ($option, $value) = ($_[0],$_[1]); + if (defined $option and defined $value) + { + $option = weechat::config_get($option); + weechat::config_option_set($option, $value, 1) if ($option ne ""); + } +} + +sub iset_reset_option +{ + my $option = $_[0]; + if (defined $option) + { + $option = weechat::config_get($option); + weechat::config_option_reset($option, 1) if ($option ne ""); + } +} + +sub iset_unset_option +{ + my $option = $_[0]; + if (defined $option) + { + $option = weechat::config_get($option); + weechat::config_option_unset($option) if ($option ne ""); + } +} + + +sub iset_cmd_cb +{ + my ($data, $buffer, $args) = ($_[0], $_[1], $_[2]); + my $filter_set = 0; +# $search_value = ""; + if (($args ne "") && (substr($args, 0, 2) ne "**")) + { + my @cmd_array = split(/ /,$args); + my $array_count = @cmd_array; + if (substr($args, 0, 1) eq weechat::config_string($options_iset{"value_search_char"}) + or (defined $cmd_array[0] and $cmd_array[0] eq weechat::config_string($options_iset{"value_search_char"}).weechat::config_string($options_iset{"value_search_char"})) ) + { + $search_mode = 1; + my $search_value = substr($args, 1); # cut value_search_char + if ($iset_buffer ne "") + { + weechat::buffer_clear($iset_buffer); + weechat::command($iset_buffer, "/window refresh"); + } + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_mode", $search_mode); + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $search_value); + iset_init(); + iset_get_values($search_value); + iset_refresh(); + weechat::buffer_set($iset_buffer, "display", "1"); +# $filter = $var_value; + return weechat::WEECHAT_RC_OK; + } + else + { + # f/s option =value + # option =value + $search_mode = 2; # grep on option + if ( $array_count >= 2 and $cmd_array[0] ne "f" or $cmd_array[0] ne "s") + { + if ( defined $cmd_array[1] and substr($cmd_array[1], 0, 1) eq weechat::config_string($options_iset{"value_search_char"}) + or defined $cmd_array[2] and substr($cmd_array[2], 0, 1) eq weechat::config_string($options_iset{"value_search_char"}) ) + { + $search_mode = 3; # grep on option and value + $search_value = substr($cmd_array[1], 1); # cut value_search_char + $search_value = substr($cmd_array[2], 1) if ( $array_count > 2); # cut value_search_char + } + } + + # show all diff values + if ( $args eq "d") + { + $search_mode = 4; + $search_value = "*"; + $args = $search_value; + } + if ( $array_count >= 2 and $cmd_array[0] eq "d") + { + $search_mode = 5; + $search_value = substr($cmd_array[1], 0); # cut value_search_char + $search_value = substr($cmd_array[2], 0) if ( $array_count > 2); # cut value_search_char + $args = $search_value; + } + + iset_create_filter($args); + $filter_set = 1; + my $ptrbuf = weechat::buffer_search($LANG, $PRGNAME); + + if ($ptrbuf eq "") + { + iset_init(); + iset_get_options($search_value); + iset_full_refresh(); + weechat::buffer_set(weechat::buffer_search($LANG, $PRGNAME), "display", "1"); + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $search_value); + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_mode", $search_mode); + return weechat::WEECHAT_RC_OK; + } + else + { + iset_get_options($search_value); + iset_full_refresh(); + weechat::buffer_set($ptrbuf, "display", "1"); + } + } + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_mode", $search_mode); + weechat::buffer_set($iset_buffer, "localvar_set_iset_search_value", $search_value); + } + if ($iset_buffer eq "") + { + iset_init(); + iset_get_options(""); + iset_refresh(); + } + else + { +# iset_get_options($search_value); + iset_full_refresh() if ($filter_set); + } + + if ($args eq "") + { + weechat::buffer_set($iset_buffer, "display", "1"); + } + else + { + if ($args eq "**refresh") + { + iset_full_refresh(); + } + if ($args eq "**up") + { + if ($current_line > 0) + { + $current_line--; + iset_refresh_line($current_line + 1); + iset_refresh_line($current_line); + iset_check_line_outside_window(); + } + } + if ($args eq "**down") + { + if ($current_line < $#options_names) + { + $current_line++; + iset_refresh_line($current_line - 1); + iset_refresh_line($current_line); + iset_check_line_outside_window(); + } + } + if ($args eq "**left" && $wee_version_number >= 0x00030600) + { + weechat::command($iset_buffer, "/window scroll_horiz ".iset_get_window_number()."-".weechat::config_integer($options_iset{"scroll_horiz"})."%"); + } + if ($args eq "**right" && $wee_version_number >= 0x00030600) + { + weechat::command($iset_buffer, "/window scroll_horiz ".iset_get_window_number().weechat::config_integer($options_iset{"scroll_horiz"})."%"); + } + if ($args eq "**scroll_top") + { + my $old_current_line = $current_line; + $current_line = 0; + iset_refresh_line ($old_current_line); + iset_refresh_line ($current_line); + iset_title(); + weechat::command($iset_buffer, "/window scroll_top ".iset_get_window_number()); + } + if ($args eq "**scroll_bottom") + { + my $old_current_line = $current_line; + $current_line = $#options_names; + iset_refresh_line ($old_current_line); + iset_refresh_line ($current_line); + iset_title(); + weechat::command($iset_buffer, "/window scroll_bottom ".iset_get_window_number()); + } + if ($args eq "**toggle") + { + if ($options_types[$current_line] eq "boolean") + { + iset_set_option($options_names[$current_line], "toggle"); + } + } + if ($args eq "**incr") + { + if (($options_types[$current_line] eq "integer") + || ($options_types[$current_line] eq "color")) + { + iset_set_option($options_names[$current_line], "++1"); + } + } + if ($args eq "**decr") + { + if (($options_types[$current_line] eq "integer") + || ($options_types[$current_line] eq "color")) + { + iset_set_option($options_names[$current_line], "--1"); + } + } + if ($args eq "**reset") + { + iset_reset_option($options_names[$current_line]); + } + if ($args eq "**unset") + { + iset_unset_option($options_names[$current_line]); + } + if ($args eq "**toggle_help") + { + if (weechat::config_boolean($options_iset{"show_help_bar"}) == 1) + { + weechat::config_option_set($options_iset{"show_help_bar"},0,1); + iset_show_bar(0); + } + else + { + weechat::config_option_set($options_iset{"show_help_bar"},1,1); + iset_show_bar(1); + } + } + if ($args eq "**toggle_show_plugin_desc") + { + if (weechat::config_boolean($options_iset{"show_plugin_description"}) == 1) + { + weechat::config_option_set($options_iset{"show_plugin_description"},0,1); + iset_full_refresh(); + iset_check_line_outside_window(); + iset_title(); + } + else + { + weechat::config_option_set($options_iset{"show_plugin_description"},1,1); + iset_full_refresh(); + iset_check_line_outside_window(); + iset_title(); + } + } + if ($args eq "**set") + { + my $quote = ""; + my $value = $options_values[$current_line]; + if ($options_is_null[$current_line]) + { + $value = ""; + } + else + { + $quote = "\"" if ($options_types[$current_line] eq "string"); + } + $value = " ".$quote.$value.$quote if ($value ne "" or $quote ne ""); + + my $set_command = "/set"; + my $start_index = 5; + if (weechat::config_boolean($options_iset{"use_mute"}) == 1) + { + $set_command = "/mute ".$set_command; + $start_index += 11; + } + $set_command = $set_command." ".$options_names[$current_line].$value; + my $pos_space = index($set_command, " ", $start_index); + if ($pos_space < 0) + { + $pos_space = 9999; + } + else + { + $pos_space = $pos_space + 1; + $pos_space = $pos_space + 1 if ($quote ne ""); + } + weechat::buffer_set($iset_buffer, "input", $set_command); + weechat::buffer_set($iset_buffer, "input_pos", "".$pos_space); + } + } + weechat::bar_item_update("isetbar_help") if (weechat::config_boolean($options_iset{"show_help_bar"}) == 1); + return weechat::WEECHAT_RC_OK; +} + +sub iset_get_help +{ + my ($redraw) = ($_[0]); + + return '' if (weechat::config_boolean($options_iset{"show_help_bar"}) == 0); + + if (not defined $options_names[$current_line]) + { + return "No option selected. Set a new filter using command line (use '*' to see all options)"; + } + if ($options_name_copy eq $options_names[$current_line] and not defined $redraw) + { + return $description; + } + $options_name_copy = $options_names[$current_line]; + my $optionlist =""; + $optionlist = weechat::infolist_get("option", "", $options_names[$current_line]); + weechat::infolist_next($optionlist); + my $full_name = weechat::infolist_string($optionlist,"full_name"); + my $option_desc = ""; + my $option_default_value = ""; + my $option_range = ""; + my $possible_values = ""; + my $re = qq(\Q$full_name); + if (grep (/^$re$/,$options_names[$current_line])) + { + $option_desc = weechat::infolist_string($optionlist, "description_nls"); + $option_desc = weechat::infolist_string($optionlist, "description") if ($option_desc eq ""); + $option_desc = "No help found" if ($option_desc eq ""); + $option_default_value = weechat::infolist_string($optionlist, "default_value"); + $possible_values = weechat::infolist_string($optionlist, "string_values") if (weechat::infolist_string($optionlist, "string_values") ne ""); + if ((weechat::infolist_string($optionlist, "type") eq "integer") && ($possible_values eq "")) + { + $option_range = weechat::infolist_integer($optionlist, "min") + ." .. ".weechat::infolist_integer($optionlist, "max"); + } + } + weechat::infolist_free($optionlist); + iset_title(); + + $description = weechat::color(weechat::config_color($options_iset{"color_help_option_name"})).$options_names[$current_line] + .weechat::color("bar_fg").": " + .weechat::color(weechat::config_color($options_iset{"color_help_text"})).$option_desc; + + # show additional infos like default value and possible values + + if (weechat::config_boolean($options_iset{"show_help_extra_info"}) == 1) + { + $description .= + weechat::color("bar_delim")." [" + .weechat::color("bar_fg")."default: " + .weechat::color("bar_delim")."\"" + .weechat::color(weechat::config_color($options_iset{"color_help_default_value"})).$option_default_value + .weechat::color("bar_delim")."\""; + if ($option_range ne "") + { + $description .= weechat::color("bar_fg").", values: ".$option_range; + } + if ($possible_values ne "") + { + $possible_values =~ s/\|/", "/g; # replace '|' to '", "' + $description .= weechat::color("bar_fg").", values: ". "\"" . $possible_values . "\""; + + } + $description .= weechat::color("bar_delim")."]"; + } + return $description; +} + +sub iset_check_condition_isetbar_cb +{ + my ($data, $modifier, $modifier_data, $string) = ($_[0], $_[1], $_[2], $_[3]); + my $buffer = weechat::window_get_pointer($modifier_data, "buffer"); + if ($buffer ne "") + { + if ((weechat::buffer_get_string($buffer, "plugin") eq $LANG) + && (weechat::buffer_get_string($buffer, "name") eq $PRGNAME)) + { + return "1"; + } + } + return "0"; +} + +sub iset_show_bar +{ + my $show = $_[0]; + my $barhidden = weechat::config_get("weechat.bar.isetbar.hidden"); + if ($barhidden) + { + if ($show) + { + if (weechat::config_boolean($options_iset{"show_help_bar"}) == 1) + { + if (weechat::config_boolean($barhidden)) + { + weechat::config_option_set($barhidden, 0, 1); + } + } + } + else + { + if (!weechat::config_boolean($barhidden)) + { + weechat::config_option_set($barhidden, 1, 1); + } + } + } +} + +sub iset_signal_buffer_switch_cb +{ + my $buffer_pointer = $_[2]; + my $show_bar = 0; + $show_bar = 1 if (weechat::buffer_get_integer($iset_buffer, "num_displayed") > 0); + iset_show_bar($show_bar); + iset_check_line_outside_window() if ($buffer_pointer eq $iset_buffer); + return weechat::WEECHAT_RC_OK; +} + +sub iset_item_cb +{ + return iset_get_help(); +} + +sub iset_upgrade_ended +{ + iset_full_refresh(); +} + +sub iset_end +{ + # when script is unloaded, we hide bar + iset_show_bar(0); +} + +# -------------------------------[ mouse support ]------------------------------------- + +sub hook_focus_iset_cb +{ + my %info = %{$_[1]}; + my $bar_item_line = int($info{"_bar_item_line"}); + undef my $hash; + if (($info{"_buffer_name"} eq $PRGNAME) && $info{"_buffer_plugin"} eq $LANG && ($bar_item_line >= 0) && ($bar_item_line <= $#iset_focus)) + { + $hash = $iset_focus[$bar_item_line]; + } + else + { + $hash = {}; + my $hash_focus = $iset_focus[0]; + foreach my $key (keys %$hash_focus) + { + $hash->{$key} = "?"; + } + } + return $hash; +} + +# _chat_line_y contains selected line +sub iset_hsignal_mouse_cb +{ + my ($data, $signal, %hash) = ($_[0], $_[1], %{$_[2]}); + + return weechat::WEECHAT_RC_OK unless (@options_types); + + if ($hash{"_buffer_name"} eq $PRGNAME && ($hash{"_buffer_plugin"} eq $LANG)) + { + if ($hash{"_key"} eq "button1") + { + iset_set_current_line($hash{"_chat_line_y"}); + } + elsif ($hash{"_key"} eq "button2") + { + if ($options_types[$hash{"_chat_line_y"}] eq "boolean") + { + iset_set_option($options_names[$hash{"_chat_line_y"}], "toggle"); + iset_set_current_line($hash{"_chat_line_y"}); + } + elsif ($options_types[$hash{"_chat_line_y"}] eq "string") + { + iset_set_current_line($hash{"_chat_line_y"}); + weechat::command("", "/$PRGNAME **set"); + } + } + elsif ($hash{"_key"} eq "button2-gesture-left" or $hash{"_key"} eq "button2-gesture-left-long") + { + if ($options_types[$hash{"_chat_line_y"}] eq "integer" or ($options_types[$hash{"_chat_line_y"}] eq "color")) + { + iset_set_current_line($hash{"_chat_line_y"}); + my $distance = distance($hash{"_chat_line_x"},$hash{"_chat_line_x2"}); + weechat::command("", "/repeat $distance /$PRGNAME **decr"); + } + } + elsif ($hash{"_key"} eq "button2-gesture-right" or $hash{"_key"} eq "button2-gesture-right-long") + { + if ($options_types[$hash{"_chat_line_y"}] eq "integer" or ($options_types[$hash{"_chat_line_y"}] eq "color")) + { + iset_set_current_line($hash{"_chat_line_y"}); + my $distance = distance($hash{"_chat_line_x"},$hash{"_chat_line_x2"}); + weechat::command("", "/repeat $distance /$PRGNAME **incr"); + } + } + } + window_switch(); +} + +sub window_switch +{ + my $current_window = weechat::current_window(); + my $dest_window = weechat::window_search_with_buffer(weechat::buffer_search("perl","iset")); + return 0 if ($dest_window eq "" or $current_window eq $dest_window); + + my $infolist = weechat::infolist_get("window", $dest_window, ""); + weechat::infolist_next($infolist); + my $number = weechat::infolist_integer($infolist, "number"); + weechat::infolist_free($infolist); + weechat::command("","/window " . $number); +} + +sub distance +{ + my ($x1,$x2) = ($_[0], $_[1]); + my $distance; + $distance = $x1 - $x2; + $distance = abs($distance); + if ($distance > 0) + { + use integer; + $distance = $distance / 3; + $distance = 1 if ($distance == 0); + } + elsif ($distance == 0) + { + $distance = 1; + } + return $distance; +} + +# -----------------------------------[ config ]--------------------------------------- + +sub iset_config_init +{ + $iset_config_file = weechat::config_new($ISET_CONFIG_FILE_NAME,"iset_config_reload_cb",""); + return if ($iset_config_file eq ""); + + # section "color" + my $section_color = weechat::config_new_section($iset_config_file,"color", 0, 0, "", "", "", "", "", "", "", "", "", ""); + if ($section_color eq "") + { + weechat::config_free($iset_config_file); + return; + } + $options_iset{"color_option"} = weechat::config_new_option( + $iset_config_file, $section_color, + "option", "color", "Color for option name in iset buffer", "", 0, 0, + "default", "default", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_option_selected"} = weechat::config_new_option( + $iset_config_file, $section_color, + "option_selected", "color", "Color for selected option name in iset buffer", "", 0, 0, + "white", "white", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_type"} = weechat::config_new_option( + $iset_config_file, $section_color, + "type", "color", "Color for option type (integer, boolean, string)", "", 0, 0, + "brown", "brown", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_type_selected"} = weechat::config_new_option( + $iset_config_file, $section_color, + "type_selected", "color", "Color for selected option type (integer, boolean, string)", "", 0, 0, + "yellow", "yellow", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_value"} = weechat::config_new_option( + $iset_config_file, $section_color, + "value", "color", "Color for option value", "", 0, 0, + "cyan", "cyan", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_value_selected"} = weechat::config_new_option( + $iset_config_file, $section_color, + "value_selected", "color", "Color for selected option value", "", 0, 0, + "lightcyan", "lightcyan", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_value_diff"} = weechat::config_new_option( + $iset_config_file, $section_color, + "value_diff", "color", "Color for option value different from default", "", 0, 0, + "magenta", "magenta", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_value_diff_selected"} = weechat::config_new_option( + $iset_config_file, $section_color, + "value_diff_selected", "color", "Color for selected option value different from default", "", 0, 0, + "lightmagenta", "lightmagenta", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_value_undef"} = weechat::config_new_option( + $iset_config_file, $section_color, + "value_undef", "color", "Color for option value undef", "", 0, 0, + "green", "green", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_value_undef_selected"} = weechat::config_new_option( + $iset_config_file, $section_color, + "value_undef_selected", "color", "Color for selected option value undef", "", 0, 0, + "lightgreen", "lightgreen", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_bg_selected"} = weechat::config_new_option( + $iset_config_file, $section_color, + "bg_selected", "color", "Background color for current selected option", "", 0, 0, + "red", "red", 0, "", "", "full_refresh_cb", "", "", ""); + $options_iset{"color_help_option_name"} = weechat::config_new_option( + $iset_config_file, $section_color, + "help_option_name", "color", "Color for option name in help-bar", "", 0, 0, + "white", "white", 0, "", "", "bar_refresh", "", "", ""); + $options_iset{"color_help_text"} = weechat::config_new_option( + $iset_config_file, $section_color, + "help_text", "color", "Color for option description in help-bar", "", 0, 0, + "default", "default", 0, "", "", "bar_refresh", "", "", ""); + $options_iset{"color_help_default_value"} = weechat::config_new_option( + $iset_config_file, $section_color, + "help_default_value", "color", "Color for default option value in help-bar", "", 0, 0, + "green", "green", 0, "", "", "bar_refresh", "", "", ""); + + # section "help" + my $section_help = weechat::config_new_section($iset_config_file,"help", 0, 0, "", "", "", "", "", "", "", "", "", ""); + if ($section_help eq "") + { + weechat::config_free($iset_config_file); + return; + } + $options_iset{"show_help_bar"} = weechat::config_new_option( + $iset_config_file, $section_help, + "show_help_bar", "boolean", "Show help bar", "", 0, 0, + "on", "on", 0, "", "", "toggle_help_cb", "", "", ""); + $options_iset{"show_help_extra_info"} = weechat::config_new_option( + $iset_config_file, $section_help, + "show_help_extra_info", "boolean", "Show additional information in help bar (default value, max./min. value) ", "", 0, 0, + "on", "on", 0, "", "", "", "", "", ""); + $options_iset{"show_plugin_description"} = weechat::config_new_option( + $iset_config_file, $section_help, + "show_plugin_description", "boolean", "Show plugin description in iset buffer", "", 0, 0, + "off", "off", 0, "", "", "full_refresh_cb", "", "", ""); + + # section "look" + my $section_look = weechat::config_new_section($iset_config_file, "look", 0, 0, "", "", "", "", "", "", "", "", "", ""); + if ($section_look eq "") + { + weechat::config_free($iset_config_file); + return; + } + $options_iset{"value_search_char"} = weechat::config_new_option( + $iset_config_file, $section_look, + "value_search_char", "string", "Trigger char to tell iset to search for value instead of option (for example: =red)", "", 0, 0, + "=", "=", 0, "", "", "", "", "", ""); + $options_iset{"scroll_horiz"} = weechat::config_new_option( + $iset_config_file, $section_look, + "scroll_horiz", "integer", "scroll content of iset buffer n%", "", 1, 100, + "10", "10", 0, "", "", "", "", "", ""); + $options_iset{"show_current_line"} = weechat::config_new_option( + $iset_config_file, $section_look, + "show_current_line", "boolean", "show current line in title bar.", "", 0, 0, + "on", "on", 0, "", "", "", "", "", ""); + $options_iset{"use_mute"} = weechat::config_new_option( + $iset_config_file, $section_look, + "use_mute", "boolean", "/mute command will be used in input bar", "", 0, 0, + "off", "off", 0, "", "", "", "", "", ""); +} + +sub iset_config_reload_cb +{ + my ($data,$config_file) = ($_[0], $_[1]); + return weechat::config_reload($config_file) +} + +sub iset_config_read +{ + return weechat::config_read($iset_config_file) if ($iset_config_file ne ""); +} + +sub iset_config_write +{ + return weechat::config_write($iset_config_file) if ($iset_config_file ne ""); +} + +sub full_refresh_cb +{ + iset_full_refresh(); + return weechat::WEECHAT_RC_OK; +} + +sub bar_refresh +{ + iset_get_help(1); + weechat::bar_item_update("isetbar_help") if (weechat::config_boolean($options_iset{"show_help_bar"}) == 1); + return weechat::WEECHAT_RC_OK; +} + +sub toggle_help_cb +{ + my $value = weechat::config_boolean($options_iset{"show_help_bar"}); + iset_show_bar($value); + return weechat::WEECHAT_RC_OK; +} + +# -----------------------------------[ main ]----------------------------------------- + +weechat::register($PRGNAME, $AUTHOR, $VERSION, $LICENSE, + $DESCR, "iset_end", ""); + +$wee_version_number = weechat::info_get("version_number", "") || 0; + +iset_config_init(); +iset_config_read(); + +weechat::hook_command($PRGNAME, "Interactive set", "d || f || s
|| [=][=]", + "d : show only changed options\n". + "f file : show options for a file\n". + "s section: show options for a section\n". + "text : show options with 'text' in name\n". + weechat::config_string($options_iset{"value_search_char"})."text : show options with 'text' in value\n". + weechat::config_string($options_iset{"value_search_char"}).weechat::config_string($options_iset{"value_search_char"})."text : show options with exact 'text' in value\n\n". + "Keys for iset buffer:\n". + "f11,f12 : move iset content left/right\n". + "up,down : move one option up/down\n". + "pgup,pdwn : move one page up/down\n". + "home,end : move to first/last option\n". + "ctrl+'L' : refresh options and screen\n". + "alt+space : toggle boolean on/off\n". + "alt+'+' : increase value (for integer or color)\n". + "alt+'-' : decrease value (for integer or color)\n". + "alt+'i',alt+'r': reset value of option\n". + "alt+'i',alt+'u': unset option\n". + "alt+enter : set new value for option (edit it with command line)\n". + "text,enter : set a new filter using command line (use '*' to see all options)\n". + "alt+'v' : toggle help bar on/off\n". + "alt+'p' : toggle option \"show_plugin_description\" on/off\n". + "q : as input in iset buffer to close it\n". + "\n". + "Mouse actions:\n". + "wheel up/down : move cursor up/down\n". + "left button : select an option from list\n". + "right button : toggle boolean (on/off) or set a new value for option (edit it with command line)\n". + "right button + drag left/right: increase/decrease value (for integer or color)\n". + "\n". + "Examples:\n". + " show changed options in 'aspell' plugin\n". + " /iset d aspell\n". + " show options for file 'irc'\n". + " /iset f irc\n". + " show options for section 'look'\n". + " /iset s look\n". + " show all options with text 'nicklist' in name\n". + " /iset nicklist\n". + " show all values which contain 'red'. ('" . weechat::config_string($options_iset{"value_search_char"}) . "' is a trigger char).\n". + " /iset ". weechat::config_string($options_iset{"value_search_char"}) ."red\n". + " show all values which hit 'off'. ('" . weechat::config_string($options_iset{"value_search_char"}) . weechat::config_string($options_iset{"value_search_char"}) . "' is a trigger char).\n". + " /iset ". weechat::config_string($options_iset{"value_search_char"}) . weechat::config_string($options_iset{"value_search_char"}) ."off\n". + " show options for file 'weechat' which contains value 'off'\n". + " /iset f weechat ".weechat::config_string($options_iset{"value_search_char"})."off\n". + "", + "", "iset_cmd_cb", ""); +weechat::hook_signal("upgrade_ended", "iset_upgrade_ended", ""); +weechat::hook_signal("window_scrolled", "iset_signal_window_scrolled_cb", ""); +weechat::hook_signal("buffer_switch", "iset_signal_buffer_switch_cb",""); +weechat::bar_item_new("isetbar_help", "iset_item_cb", ""); +weechat::bar_new("isetbar", "on", "0", "window", "", "top", "horizontal", + "vertical", "3", "3", "default", "cyan", "default", "1", + "isetbar_help"); +weechat::hook_modifier("bar_condition_isetbar", "iset_check_condition_isetbar_cb", ""); +weechat::hook_config("*", "iset_config_cb", ""); +$iset_buffer = weechat::buffer_search($LANG, $PRGNAME); +iset_init() if ($iset_buffer ne ""); + +if ($wee_version_number >= 0x00030600) +{ + weechat::hook_focus("chat", "hook_focus_iset_cb", ""); + weechat::hook_hsignal($PRGNAME."_mouse", "iset_hsignal_mouse_cb", ""); + weechat::key_bind("mouse", \%mouse_keys); +} diff --git a/.weechat/plugins.conf b/.weechat/plugins.conf index c0b3234..c6975b7 100644 --- a/.weechat/plugins.conf +++ b/.weechat/plugins.conf @@ -4,6 +4,19 @@ [var] fifo.fifo = "on" +perl.check_license = "off" +perl.highmon.alignment = "channel" +perl.highmon.away_only = "off" +perl.highmon.color_buf = "on" +perl.highmon.first_run = "true" +perl.highmon.hotlist_show = "off" +perl.highmon.logging = "off" +perl.highmon.merge_private = "off" +perl.highmon.nick_prefix = "<" +perl.highmon.nick_suffix = ">" +perl.highmon.output = "buffer" +perl.highmon.short_names = "off" +python.check_license = "off" tcl.check_license = "off" [desc] diff --git a/.weechat/python/autoload/autosort.py b/.weechat/python/autoload/autosort.py new file mode 120000 index 0000000..1850897 --- /dev/null +++ b/.weechat/python/autoload/autosort.py @@ -0,0 +1 @@ +../autosort.py \ No newline at end of file diff --git a/.weechat/python/autoload/colorize_nicks.py b/.weechat/python/autoload/colorize_nicks.py new file mode 120000 index 0000000..3ee34e9 --- /dev/null +++ b/.weechat/python/autoload/colorize_nicks.py @@ -0,0 +1 @@ +../colorize_nicks.py \ No newline at end of file diff --git a/.weechat/python/autosort.py b/.weechat/python/autosort.py new file mode 100644 index 0000000..6854b9e --- /dev/null +++ b/.weechat/python/autosort.py @@ -0,0 +1,885 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013-2014 Maarten de Vries +# +# This program 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. +# +# This program 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 this program. If not, see . +# + +# +# Autosort automatically keeps your buffers sorted and grouped by server. +# You can define your own sorting rules. See /help autosort for more details. +# +# http://github.com/de-vri.es/weechat-autosort +# + +# +# Changelog: +# 2.8: +# * Fix compatibility with python 3 regarding unicode handling. +# 2.7: +# * Fix sorting of buffers with spaces in their name. +# 2.6: +# * Ignore case in rules when doing case insensitive sorting. +# 2.5: +# * Fix handling unicode buffer names. +# * Add hint to set irc.look.server_buffer to independent and buffers.look.indenting to on. +# 2.4: +# * Make script python3 compatible. +# 2.3: +# * Fix sorting items without score last (regressed in 2.2). +# 2.2: +# * Add configuration option for signals that trigger a sort. +# * Add command to manually trigger a sort (/autosort sort). +# * Add replacement patterns to apply before sorting. +# 2.1: +# * Fix some minor style issues. +# 2.0: +# * Allow for custom sort rules. +# + + +import weechat +import re +import json + +SCRIPT_NAME = 'autosort' +SCRIPT_AUTHOR = 'Maarten de Vries ' +SCRIPT_VERSION = '2.8' +SCRIPT_LICENSE = 'GPL3' +SCRIPT_DESC = 'Automatically or manually keep your buffers sorted and grouped by server.' + + +config = None +hooks = [] + +class HumanReadableError(Exception): + pass + + +def parse_int(arg, arg_name = 'argument'): + ''' Parse an integer and provide a more human readable error. ''' + arg = arg.strip() + try: + return int(arg) + except ValueError: + raise HumanReadableError('Invalid {0}: expected integer, got "{1}".'.format(arg_name, arg)) + + +class Pattern: + ''' A simple glob-like pattern for matching buffer names. ''' + + def __init__(self, pattern, case_sensitive): + ''' Construct a pattern from a string. ''' + escaped = False + char_class = 0 + chars = '' + regex = '' + for c in pattern: + if escaped and char_class: + escaped = False + chars += re.escape(c) + elif escaped: + escaped = False + regex += re.escape(c) + elif c == '\\': + escaped = True + elif c == '*' and not char_class: + regex += '[^.]*' + elif c == '?' and not char_class: + regex += '[^.]' + elif c == '[' and not char_class: + char_class = 1 + chars = '' + elif c == '^' and char_class and not chars: + chars += '^' + elif c == ']' and char_class and chars not in ('', '^'): + char_class = False + regex += '[' + chars + ']' + elif c == '-' and char_class: + chars += '-' + elif char_class: + chars += re.escape(c) + else: + regex += re.escape(c) + + if char_class: + raise ValueError("unmatched opening '['") + if escaped: + raise ValueError("unexpected trailing '\\'") + + if case_sensitive: + self.regex = re.compile('^' + regex + '$') + else: + self.regex = re.compile('^' + regex + '$', flags = re.IGNORECASE) + self.pattern = pattern + + def match(self, input): + ''' Match the pattern against a string. ''' + return self.regex.match(input) + + +class FriendlyList(object): + ''' A list with human readable errors. ''' + + def __init__(self): + self.__data = [] + + def raw(self): + return self.__data + + def append(self, value): + ''' Add a rule to the list. ''' + self.__data.append(value) + + def insert(self, index, value): + ''' Add a rule to the list. ''' + if not 0 <= index <= len(self): raise HumanReadableError('Index out of range: expected an integer in the range [0, {0}], got {1}.'.format(len(self), index)) + self.__data.insert(index, value) + + def pop(self, index): + ''' Remove a rule from the list and return it. ''' + if not 0 <= index < len(self): raise HumanReadableError('Index out of range: expected an integer in the range [0, {0}), got {1}.'.format(len(self), index)) + return self.__data.pop(index) + + def move(self, index_a, index_b): + ''' Move a rule to a new position in the list. ''' + self.insert(index_b, self.pop(index_a)) + + def swap(self, index_a, index_b): + ''' Swap two elements in the list. ''' + self[index_a], self[index_b] = self[index_b], self[index_a] + + def __len__(self): + return len(self.__data) + + def __getitem__(self, index): + if not 0 <= index < len(self): raise HumanReadableError('Index out of range: expected an integer in the range [0, {0}), got {1}.'.format(len(self), index)) + return self.__data[index] + + def __setitem__(self, index, value): + if not 0 <= index < len(self): raise HumanReadableError('Index out of range: expected an integer in the range [0, {0}), got {1}.'.format(len(self), index)) + self.__data[index] = value + + def __iter__(self): + return iter(self.__data) + + +class RuleList(FriendlyList): + ''' A list of rules to test buffer names against. ''' + rule_regex = re.compile(r'^(.*)=\s*([+-]?[^=]*)$') + + def __init__(self, rules): + ''' Construct a RuleList from a list of rules. ''' + super(RuleList, self).__init__() + for rule in rules: self.append(rule) + + def get_score(self, name): + ''' Get the sort score of a partial name according to a rule list. ''' + for rule in self: + if rule[0].match(name): return rule[1] + return 999999999 + + def encode(self): + ''' Encode the rules for storage. ''' + return json.dumps(list(map(lambda x: (x[0].pattern, x[1]), self))) + + @staticmethod + def decode(blob, case_sensitive): + ''' Parse rules from a string blob. ''' + result = [] + + try: + decoded = json.loads(blob) + except ValueError: + log('Invalid rules: expected JSON encoded list of pairs, got "{0}".'.format(blob)) + return [], 0 + + for rule in decoded: + # Rules must be a pattern,score pair. + if len(rule) != 2: + log('Invalid rule: expected (pattern, score), got "{0}". Rule ignored.'.format(rule)) + continue + + # Rules must have a valid pattern. + try: + pattern = Pattern(rule[0], case_sensitive) + except ValueError as e: + log('Invalid pattern: {0} in "{1}". Rule ignored.'.format(e, rule[0])) + continue + + # Rules must have a valid score. + try: + score = int(rule[1]) + except ValueError as e: + log('Invalid score: expected an integer, got "{0}". Rule ignored.'.format(score)) + continue + + result.append((pattern, score)) + + return RuleList(result) + + @staticmethod + def parse_rule(arg, case_sensitive): + ''' Parse a rule argument. ''' + arg = arg.strip() + match = RuleList.rule_regex.match(arg) + if not match: + raise HumanReadableError('Invalid rule: expected " = ", got "{0}".'.format(arg)) + + pattern = match.group(1).strip() + try: + pattern = Pattern(pattern, case_sensitive) + except ValueError as e: + raise HumanReadableError('Invalid pattern: {0} in "{1}".'.format(e, pattern)) + + score = parse_int(match.group(2), 'score') + return (pattern, score) + + +def decode_replacements(blob): + ''' Decode a replacement list encoded as JSON. ''' + result = FriendlyList() + try: + decoded = json.loads(blob) + except ValueError: + log('Invalid replacement list: expected JSON encoded list of pairs, got "{0}".'.format(blob)) + return [], 0 + + for replacement in decoded: + # Replacements must be a (string, string) pair. + if len(replacement) != 2: + log('Invalid replacement pattern: expected (pattern, replacement), got "{0}". Replacement ignored.'.format(rule)) + continue + result.append(replacement) + + return result + + +def encode_replacements(replacements): + ''' Encode a list of replacement patterns as JSON. ''' + return json.dumps(replacements.raw()) + + +class Config: + ''' The autosort configuration. ''' + + default_rules = json.dumps([ + ('core', 0), + ('irc', 2), + ('*', 1), + + ('irc.irc_raw', 0), + ('irc.server', 1), + ]) + + default_replacements = '[]' + default_signals = 'buffer_opened buffer_merged buffer_unmerged buffer_renamed' + + def __init__(self, filename): + ''' Initialize the configuration. ''' + + self.filename = filename + self.config_file = weechat.config_new(self.filename, '', '') + self.sorting_section = None + + self.case_sensitive = False + self.group_irc = True + self.rules = [] + self.replacements = [] + self.signals = [] + self.sort_on_config = True + + self.__case_sensitive = None + self.__group_irc = None + self.__rules = None + self.__replacements = None + self.__signals = None + self.__sort_on_config = None + + if not self.config_file: + log('Failed to initialize configuration file "{0}".'.format(self.filename)) + return + + self.sorting_section = weechat.config_new_section(self.config_file, 'sorting', False, False, '', '', '', '', '', '', '', '', '', '') + + if not self.sorting_section: + log('Failed to initialize section "sorting" of configuration file.') + weechat.config_free(self.config_file) + return + + self.__case_sensitive = weechat.config_new_option( + self.config_file, self.sorting_section, + 'case_sensitive', 'boolean', + 'If this option is on, sorting is case sensitive.', + '', 0, 0, 'off', 'off', 0, + '', '', '', '', '', '' + ) + + self.__group_irc = weechat.config_new_option( + self.config_file, self.sorting_section, + 'group_irc', 'boolean', + 'If this option is on, the script pretends that IRC channel/private buffers are renamed to "irc.server.{network}.{channel}" rather than "irc.{network}.{channel}".' + + 'This ensures that these buffers are grouped with their respective server buffer.', + '', 0, 0, 'on', 'on', 0, + '', '', '', '', '', '' + ) + + self.__rules = weechat.config_new_option( + self.config_file, self.sorting_section, + 'rules', 'string', + 'An ordered list of sorting rules encoded as JSON. See /help autosort for commands to manipulate these rules.', + '', 0, 0, Config.default_rules, Config.default_rules, 0, + '', '', '', '', '', '' + ) + + self.__replacements = weechat.config_new_option( + self.config_file, self.sorting_section, + 'replacements', 'string', + 'An ordered list of replacement patterns to use on buffer name components, encoded as JSON. See /help autosort for commands to manipulate these replacements.', + '', 0, 0, Config.default_replacements, Config.default_replacements, 0, + '', '', '', '', '', '' + ) + + self.__signals = weechat.config_new_option( + self.config_file, self.sorting_section, + 'signals', 'string', + 'The signals that will cause autosort to resort your buffer list. Seperate signals with spaces.', + '', 0, 0, Config.default_signals, Config.default_signals, 0, + '', '', '', '', '', '' + ) + + self.__sort_on_config = weechat.config_new_option( + self.config_file, self.sorting_section, + 'sort_on_config_change', 'boolean', + 'Decides if the buffer list should be sorted when autosort configuration changes.', + '', 0, 0, 'on', 'on', 0, + '', '', '', '', '', '' + ) + + if weechat.config_read(self.config_file) != weechat.WEECHAT_RC_OK: + log('Failed to load configuration file.') + + if weechat.config_write(self.config_file) != weechat.WEECHAT_RC_OK: + log('Failed to write configuration file.') + + self.reload() + + def reload(self): + ''' Load configuration variables. ''' + + self.case_sensitive = weechat.config_boolean(self.__case_sensitive) + self.group_irc = weechat.config_boolean(self.__group_irc) + + rules_blob = weechat.config_string(self.__rules) + replacements_blob = weechat.config_string(self.__replacements) + signals_blob = weechat.config_string(self.__signals) + + self.rules = RuleList.decode(rules_blob, self.case_sensitive) + self.replacements = decode_replacements(replacements_blob) + self.signals = signals_blob.split() + self.sort_on_config = weechat.config_boolean(self.__sort_on_config) + + def save_rules(self, run_callback = True): + ''' Save the current rules to the configuration. ''' + weechat.config_option_set(self.__rules, RuleList.encode(self.rules), run_callback) + + def save_replacements(self, run_callback = True): + ''' Save the current replacement patterns to the configuration. ''' + weechat.config_option_set(self.__replacements, encode_replacements(self.replacements), run_callback) + + +def pad(sequence, length, padding = None): + ''' Pad a list until is has a certain length. ''' + return sequence + [padding] * max(0, (length - len(sequence))) + + +def log(message, buffer = 'NULL'): + weechat.prnt(buffer, 'autosort: {0}'.format(message)) + + +def get_buffers(): + ''' Get a list of all the buffers in weechat. ''' + buffers = [] + + buffer_list = weechat.infolist_get('buffer', '', '') + + while weechat.infolist_next(buffer_list): + name = weechat.infolist_string (buffer_list, 'full_name') + number = weechat.infolist_integer(buffer_list, 'number') + + # Buffer is merged with one we already have in the list, skip it. + if number <= len(buffers): + continue + buffers.append((name, number - 1)) + + weechat.infolist_free(buffer_list) + return buffers + + +def preprocess(buffer, config): + ''' + Preprocess a buffers names. + ''' + + # Make sure the name is a unicode string. + # On python3 this is a NOP since the string type is already decoded as UTF-8. + if isinstance(buffer, bytes): + buffer = buffer.decode('utf-8') + + if not config.case_sensitive: + buffer = buffer.lower() + + for replacement in config.replacements: + buffer = buffer.replace(replacement[0], replacement[1]) + + buffer = buffer.split('.') + if config.group_irc and len(buffer) >= 2 and buffer[0] == 'irc' and buffer[1] not in ('server', 'irc_raw'): + buffer.insert(1, 'server') + + return buffer + + +def buffer_sort_key(rules): + ''' Create a sort key function for a buffer list from a rule list. ''' + def key(buffer): + result = [] + name = '' + for word in preprocess(buffer[0], config): + name += ('.' if name else '') + word + result.append((rules.get_score(name), word)) + return result + + return key + + +def apply_buffer_order(order): + ''' Sort the buffers in weechat according to the given order. ''' + indices = list(order) + reverse = [0] * len(indices) + for i, index in enumerate(indices): + reverse[index] = i + + for i in range(len(indices)): + wanted = indices[i] + if wanted == i: continue + # Weechat buffers are 1-indexed, but our indices aren't. + weechat.command('', '/buffer swap {0} {1}'.format(i + 1, wanted + 1)) + indices[reverse[i]] = wanted + reverse[wanted] = reverse[i] + + +def split_args(args, expected, optional = 0): + ''' Split an argument string in the desired number of arguments. ''' + split = args.split(' ', expected - 1) + if (len(split) < expected): + raise HumanReadableError('Expected at least {0} arguments, got {1}.'.format(expected, len(split))) + return split[:-1] + pad(split[-1].split(' ', optional), optional + 1, '') + + +def command_sort(buffer, command, args): + ''' Sort the buffers and print a confirmation. ''' + on_buffers_changed() + log("Finished sorting buffers.", buffer) + return weechat.WEECHAT_RC_OK + + +def command_rule_list(buffer, command, args): + ''' Show the list of sorting rules. ''' + output = 'Sorting rules:\n' + for i, rule in enumerate(config.rules): + output += ' {0}: {1} = {2}\n'.format(i, rule[0].pattern, rule[1]) + if not len(config.rules): + output += ' No sorting rules configured.\n' + log(output, buffer) + + return weechat.WEECHAT_RC_OK + + +def command_rule_add(buffer, command, args): + ''' Add a rule to the rule list. ''' + rule = RuleList.parse_rule(args, config.case_sensitive) + + config.rules.append(rule) + config.save_rules() + command_rule_list(buffer, command, '') + + return weechat.WEECHAT_RC_OK + + +def command_rule_insert(buffer, command, args): + ''' Insert a rule at the desired position in the rule list. ''' + index, rule = split_args(args, 2) + index = parse_int(index, 'index') + rule = RuleList.parse_rule(rule, config.case_sensitive) + + config.rules.insert(index, rule) + config.save_rules() + command_rule_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_rule_update(buffer, command, args): + ''' Update a rule in the rule list. ''' + index, rule = split_args(args, 2) + index = parse_int(index, 'index') + rule = RuleList.parse_rule(rule, config.case_sensitive) + + config.rules[index] = rule + config.save_rules() + command_rule_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_rule_delete(buffer, command, args): + ''' Delete a rule from the rule list. ''' + index = args.strip() + index = parse_int(index, 'index') + + config.rules.pop(index) + config.save_rules() + command_rule_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_rule_move(buffer, command, args): + ''' Move a rule to a new position. ''' + index_a, index_b = split_args(args, 2) + index_a = parse_int(index_a, 'index') + index_b = parse_int(index_b, 'index') + + config.rules.move(index_a, index_b) + config.save_rules() + command_rule_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_rule_swap(buffer, command, args): + ''' Swap two rules. ''' + index_a, index_b = split_args(args, 2) + index_a = parse_int(index_a, 'index') + index_b = parse_int(index_b, 'index') + + config.rules.swap(index_a, index_b) + config.save_rules() + command_rule_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_replacement_list(buffer, command, args): + ''' Show the list of sorting rules. ''' + output = 'Replacement patterns:\n' + for i, pattern in enumerate(config.replacements): + output += ' {0}: {1} -> {2}\n'.format(i, pattern[0], pattern[1]) + if not len(config.replacements): + output += ' No replacement patterns configured.' + log(output, buffer) + + return weechat.WEECHAT_RC_OK + + +def command_replacement_add(buffer, command, args): + ''' Add a rule to the rule list. ''' + pattern, replacement = split_args(args, 1, 1) + + config.replacements.append((pattern, replacement)) + config.save_replacements() + command_replacement_list(buffer, command, '') + + return weechat.WEECHAT_RC_OK + + +def command_replacement_insert(buffer, command, args): + ''' Insert a rule at the desired position in the rule list. ''' + index, pattern, replacement = split_args(args, 2, 1) + index = parse_int(index, 'index') + + config.replacements.insert(index, (pattern, replacement)) + config.save_replacements() + command_replacement_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_replacement_update(buffer, command, args): + ''' Update a rule in the rule list. ''' + index, pattern, replacement = split_args(args, 2, 1) + index = parse_int(index, 'index') + + config.replacements[index] = (pattern, replacement) + config.save_replacements() + command_replacement_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_replacement_delete(buffer, command, args): + ''' Delete a rule from the rule list. ''' + index = args.strip() + index = parse_int(index, 'index') + + config.replacements.pop(index) + config.save_replacements() + command_replacement_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_replacement_move(buffer, command, args): + ''' Move a rule to a new position. ''' + index_a, index_b = split_args(args, 2) + index_a = parse_int(index_a, 'index') + index_b = parse_int(index_b, 'index') + + config.replacements.move(index_a, index_b) + config.save_replacements() + command_replacement_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_replacement_swap(buffer, command, args): + ''' Swap two rules. ''' + index_a, index_b = split_args(args, 2) + index_a = parse_int(index_a, 'index') + index_b = parse_int(index_b, 'index') + + config.replacements.swap(index_a, index_b) + config.save_replacements() + command_replacement_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + + + +def call_command(buffer, command, args, subcommands): + ''' Call a subccommand from a dictionary. ''' + subcommand, tail = pad(args.split(' ', 1), 2, '') + subcommand = subcommand.strip() + if (subcommand == ''): + child = subcommands.get(' ') + else: + command = command + [subcommand] + child = subcommands.get(subcommand) + + if isinstance(child, dict): + return call_command(buffer, command, tail, child) + elif callable(child): + return child(buffer, command, tail) + + log('{0}: command not found'.format(' '.join(command))) + return weechat.WEECHAT_RC_ERROR + + +def on_buffers_changed(*args, **kwargs): + ''' Called whenever the buffer list changes. ''' + buffers = get_buffers() + buffers.sort(key=buffer_sort_key(config.rules)) + apply_buffer_order([i for _, i in buffers]) + return weechat.WEECHAT_RC_OK + + +def on_config_changed(*args, **kwargs): + ''' Called whenever the configuration changes. ''' + config.reload() + + # Unhook all signals and hook the new ones. + for hook in hooks: + weechat.unhook(hook) + for signal in config.signals: + hooks.append(weechat.hook_signal(signal, 'on_buffers_changed', '')) + + if config.sort_on_config: + on_buffers_changed() + + return weechat.WEECHAT_RC_OK + + +def on_autosort_command(data, buffer, args): + ''' Called when the autosort command is invoked. ''' + try: + return call_command(buffer, ['/autosort'], args, { + ' ': command_sort, + 'sort': command_sort, + + 'rules': { + ' ': command_rule_list, + 'list': command_rule_list, + 'add': command_rule_add, + 'insert': command_rule_insert, + 'update': command_rule_update, + 'delete': command_rule_delete, + 'move': command_rule_move, + 'swap': command_rule_swap, + }, + 'replacements': { + ' ': command_replacement_list, + 'list': command_replacement_list, + 'add': command_replacement_add, + 'insert': command_replacement_insert, + 'update': command_replacement_update, + 'delete': command_replacement_delete, + 'move': command_replacement_move, + 'swap': command_replacement_swap, + }, + 'sort': on_buffers_changed, + }) + except HumanReadableError as e: + log(e, buffer) + return weechat.WEECHAT_RC_ERROR + + +command_description = r''' +NOTE: For the best effect, you may want to consider setting the option irc.look.server_buffer to independent and buffers.look.indenting to on. + +# Commands + +## Miscellaneous +/autosort sort +Manually trigger the buffer sorting. + + +## Sorting rules + +/autosort rules list +Print the list of sort rules. + +/autosort rules add = +Add a new rule at the end of the list. + +/autosort rules insert = +Insert a new rule at the given index in the list. + +/autosort rules update = +Update a rule in the list with a new pattern and score. + +/autosort rules delete +Delete a rule from the list. + +/autosort rules move +Move a rule from one position in the list to another. + +/autosort rules swap +Swap two rules in the list + + +## Replacement patterns + +/autosort replacements list +Print the list of replacement patterns. + +/autosort replacements add +Add a new replacement pattern at the end of the list. + +/autosort replacements insert +Insert a new replacement pattern at the given index in the list. + +/autosort replacements update +Update a replacement pattern in the list. + +/autosort replacements delete +Delete a replacement pattern from the list. + +/autosort replacements move +Move a replacement pattern from one position in the list to another. + +/autosort replacements swap +Swap two replacement pattern in the list + + +# Introduction +Autosort is a weechat script to automatically keep your buffers sorted. +The sort order can be customized by defining your own sort rules, +but the default should be sane enough for most people. +It can also group IRC channel/private buffers under their server buffer if you like. + +Autosort first turns buffer names into a list of their components by splitting on them on the period character. +For example, the buffer name "irc.server.freenode" is turned into ['irc', 'server', 'freenode']. +The list of buffers is then lexicographically sorted. + +To facilitate custom sort orders, it is possible to assign a score to each component individually before the sorting is done. +Any name component that did not get a score assigned will be sorted after those that did receive a score. +Components are always sorted on their score first and on their name second. +Lower scores are sorted first. + +## Automatic or manual sorting +By default, autosort will automatically sort your buffer list whenever a buffer is opened, merged, unmerged or renamed. +This should keep your buffers sorted in almost all situations. +However, you may wish to change the list of signals that cause your buffer list to be sorted. +Simply edit the "autosort.sorting.signals" option to add or remove any signal you like. +If you remove all signals you can still sort your buffers manually with the "/autosort sort" command. +To prevent all automatic sorting, "autosort.sorting.sort_on_config_change" should also be set to off. + +## Grouping IRC buffers +In weechat, IRC channel/private buffers are named "irc..<#channel>", +and IRC server buffers are named "irc.server.". +This does not work very well with lexicographical sorting if you want all buffers for one network grouped together. +That is why autosort comes with the "autosort.sorting.group_irc" option, +which secretly pretends IRC channel/private buffers are called "irc.server..<#channel>". +The buffers are not actually renamed, autosort simply pretends they are for sorting purposes. + +## Replacement patterns +Sometimes you may want to ignore some characters for sorting purposes. +On Freenode for example, you may wish to ignore the difference between channels starting with a double or a single hash sign. +To do so, simply add a replacement pattern that replaces ## with # with the following command: +/autosort replacements add ## # + +Replacement patterns do not support wildcards or special characters at the moment. + +## Sort rules +You can assign scores to name components by defining sort rules. +The first rule that matches a component decides the score. +Further rules are not examined. +Sort rules use the following syntax: + = + +You can use the "/autosort rules" command to show and manipulate the list of sort rules. + + +Allowed special characters in the glob patterns are: + +Pattern | Meaning +--------|-------- +* | Matches a sequence of any characters except for periods. +? | Matches a single character, but not a period. +[a-z] | Matches a single character in the given regex-like character class. +[^ab] | A negated regex-like character class. +\* | A backslash escapes the next characters and removes its special meaning. +\\ | A literal backslash. + + +## Example +As an example, consider the following rule list: +0: core = 0 +1: irc = 2 +2: * = 1 + +3: irc.server.*.#* = 1 +4: irc.server.*.* = 0 + +Rule 0 ensures the core buffer is always sorted first. +Rule 1 sorts IRC buffers last and rule 2 puts all remaining buffers in between the two. + +Rule 3 and 4 would make no sense with the group_irc option off. +With the option on though, these rules will sort private buffers before regular channel buffers. +Rule 3 matches channel buffers and assigns them a higher score, +while rule 4 matches the buffers that remain and assigns them a lower score. +The same effect could also be achieved with a single rule: +irc.server.*.[^#]* = 0 +''' + +command_completion = 'sort||rules list|add|insert|update|delete|move|swap||replacements list|add|insert|update|delete|move|swap' + + +if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, "", ""): + config = Config('autosort') + + weechat.hook_config('autosort.*', 'on_config_changed', '') + weechat.hook_command('autosort', command_description, '', '', command_completion, 'on_autosort_command', 'NULL') + on_config_changed() diff --git a/.weechat/python/colorize_nicks.py b/.weechat/python/colorize_nicks.py new file mode 100644 index 0000000..506a3ab --- /dev/null +++ b/.weechat/python/colorize_nicks.py @@ -0,0 +1,350 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2010 by xt +# +# This program 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. +# +# This program 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 this program. If not, see . +# + +# This script colors nicks in IRC channels in the actual message +# not just in the prefix section. +# +# +# History: +# 2016-05-01, Simmo Saan +# version 22: invalidate cached colors on hash algorithm change +# 2015-07-28, xt +# version 21: fix problems with nicks with commas in them +# 2015-04-19, xt +# version 20: fix ignore of nicks in URLs +# 2015-04-18, xt +# version 19: new option ignore nicks in URLs +# 2015-03-03, xt +# version 18: iterate buffers looking for nicklists instead of servers +# 2015-02-23, holomorph +# version 17: fix coloring in non-channel buffers (#58) +# 2014-09-17, holomorph +# version 16: use weechat config facilities +# clean unused, minor linting, some simplification +# 2014-05-05, holomorph +# version 15: fix python2-specific re.search check +# 2013-01-29, nils_2 +# version 14: make script compatible with Python 3.x +# 2012-10-19, ldvx +# version 13: Iterate over every word to prevent incorrect colorization of +# nicks. Added option greedy_matching. +# 2012-04-28, ldvx +# version 12: added ignore_tags to avoid colorizing nicks if tags are present +# 2012-01-14, nesthib +# version 11: input_text_display hook and modifier to colorize nicks in input bar +# 2010-12-22, xt +# version 10: hook config option for updating blacklist +# 2010-12-20, xt +# version 0.9: hook new config option for weechat 0.3.4 +# 2010-11-01, nils_2 +# version 0.8: hook_modifier() added to communicate with rainbow_text +# 2010-10-01, xt +# version 0.7: changes to support non-irc-plugins +# 2010-07-29, xt +# version 0.6: compile regexp as per patch from Chris quigybo@hotmail.com +# 2010-07-19, xt +# version 0.5: fix bug with incorrect coloring of own nick +# 2010-06-02, xt +# version 0.4: update to reflect API changes +# 2010-03-26, xt +# version 0.3: fix error with exception +# 2010-03-24, xt +# version 0.2: use ignore_channels when populating to increase performance. +# 2010-02-03, xt +# version 0.1: initial (based on ruby script by dominikh) +# +# Known issues: nicks will not get colorized if they begin with a character +# such as ~ (which some irc networks do happen to accept) + +import weechat +import re +w = weechat + +SCRIPT_NAME = "colorize_nicks" +SCRIPT_AUTHOR = "xt " +SCRIPT_VERSION = "22" +SCRIPT_LICENSE = "GPL" +SCRIPT_DESC = "Use the weechat nick colors in the chat area" + +VALID_NICK = r'([@~&!%+])?([-a-zA-Z0-9\[\]\\`_^\{|\}]+)' +valid_nick_re = re.compile(VALID_NICK) +ignore_channels = [] +ignore_nicks = [] + +# Dict with every nick on every channel with its color as lookup value +colored_nicks = {} + +CONFIG_FILE_NAME = "colorize_nicks" + +# config file and options +colorize_config_file = "" +colorize_config_option = {} + +def colorize_config_init(): + ''' + Initialization of configuration file. + Sections: look. + ''' + global colorize_config_file, colorize_config_option + colorize_config_file = weechat.config_new(CONFIG_FILE_NAME, + "colorize_config_reload_cb", "") + if colorize_config_file == "": + return + + # section "look" + section_look = weechat.config_new_section( + colorize_config_file, "look", 0, 0, "", "", "", "", "", "", "", "", "", "") + if section_look == "": + weechat.config_free(colorize_config_file) + return + colorize_config_option["blacklist_channels"] = weechat.config_new_option( + colorize_config_file, section_look, "blacklist_channels", + "string", "Comma separated list of channels", "", 0, 0, + "", "", 0, "", "", "", "", "", "") + colorize_config_option["blacklist_nicks"] = weechat.config_new_option( + colorize_config_file, section_look, "blacklist_nicks", + "string", "Comma separated list of nicks", "", 0, 0, + "so,root", "so,root", 0, "", "", "", "", "", "") + colorize_config_option["min_nick_length"] = weechat.config_new_option( + colorize_config_file, section_look, "min_nick_length", + "integer", "Minimum length nick to colorize", "", + 2, 20, "", "", 0, "", "", "", "", "", "") + colorize_config_option["colorize_input"] = weechat.config_new_option( + colorize_config_file, section_look, "colorize_input", + "boolean", "Whether to colorize input", "", 0, + 0, "off", "off", 0, "", "", "", "", "", "") + colorize_config_option["ignore_tags"] = weechat.config_new_option( + colorize_config_file, section_look, "ignore_tags", + "string", "Comma separated list of tags to ignore; i.e. irc_join,irc_part,irc_quit", "", 0, 0, + "", "", 0, "", "", "", "", "", "") + colorize_config_option["greedy_matching"] = weechat.config_new_option( + colorize_config_file, section_look, "greedy_matching", + "boolean", "If off, then use lazy matching instead", "", 0, + 0, "on", "on", 0, "", "", "", "", "", "") + colorize_config_option["ignore_nicks_in_urls"] = weechat.config_new_option( + colorize_config_file, section_look, "ignore_nicks_in_urls", + "boolean", "If on, don't colorize nicks inside URLs", "", 0, + 0, "off", "off", 0, "", "", "", "", "", "") + +def colorize_config_read(): + ''' Read configuration file. ''' + global colorize_config_file + return weechat.config_read(colorize_config_file) + +def colorize_nick_color(nick, my_nick): + ''' Retrieve nick color from weechat. ''' + if nick == my_nick: + return w.color(w.config_string(w.config_get('weechat.color.chat_nick_self'))) + else: + return w.info_get('irc_nick_color', nick) + +def colorize_cb(data, modifier, modifier_data, line): + ''' Callback that does the colorizing, and returns new line if changed ''' + + global ignore_nicks, ignore_channels, colored_nicks + + + full_name = modifier_data.split(';')[1] + channel = '.'.join(full_name.split('.')[1:]) + + buffer = w.buffer_search('', full_name) + # Check if buffer has colorized nicks + if buffer not in colored_nicks: + return line + + if channel and channel in ignore_channels: + return line + + min_length = w.config_integer(colorize_config_option['min_nick_length']) + reset = w.color('reset') + + # Don't colorize if the ignored tag is present in message + tags_line = modifier_data.rsplit(';') + if len(tags_line) >= 3: + tags_line = tags_line[2].split(',') + for i in w.config_string(colorize_config_option['ignore_tags']).split(','): + if i in tags_line: + return line + + for words in valid_nick_re.findall(line): + nick = words[1] + # Check that nick is not ignored and longer than minimum length + if len(nick) < min_length or nick in ignore_nicks: + continue + + # Check that nick is in the dictionary colored_nicks + if nick in colored_nicks[buffer]: + nick_color = colored_nicks[buffer][nick] + + # Let's use greedy matching. Will check against every word in a line. + if w.config_boolean(colorize_config_option['greedy_matching']): + for word in line.split(): + if w.config_boolean(colorize_config_option['ignore_nicks_in_urls']) and \ + word.startswith(('http://', 'https://')): + continue + + if nick in word: + # Is there a nick that contains nick and has a greater lenght? + # If so let's save that nick into var biggest_nick + biggest_nick = "" + for i in colored_nicks[buffer]: + if nick in i and nick != i and len(i) > len(nick): + if i in word: + # If a nick with greater len is found, and that word + # also happens to be in word, then let's save this nick + biggest_nick = i + # If there's a nick with greater len, then let's skip this + # As we will have the chance to colorize when biggest_nick + # iterates being nick. + if len(biggest_nick) > 0 and biggest_nick in word: + pass + elif len(word) < len(biggest_nick) or len(biggest_nick) == 0: + new_word = word.replace(nick, '%s%s%s' % (nick_color, nick, reset)) + line = line.replace(word, new_word) + # Let's use lazy matching for nick + else: + nick_color = colored_nicks[buffer][nick] + # The two .? are in case somebody writes "nick:", "nick,", etc + # to address somebody + regex = r"(\A|\s).?(%s).?(\Z|\s)" % re.escape(nick) + match = re.search(regex, line) + if match is not None: + new_line = line[:match.start(2)] + nick_color+nick+reset + line[match.end(2):] + line = new_line + return line + +def colorize_input_cb(data, modifier, modifier_data, line): + ''' Callback that does the colorizing in input ''' + + global ignore_nicks, ignore_channels, colored_nicks + + min_length = w.config_integer(colorize_config_option['min_nick_length']) + + if not w.config_boolean(colorize_config_option['colorize_input']): + return line + + buffer = w.current_buffer() + # Check if buffer has colorized nicks + if buffer not in colored_nicks: + return line + + channel = w.buffer_get_string(buffer, 'name') + if channel and channel in ignore_channels: + return line + + reset = w.color('reset') + + for words in valid_nick_re.findall(line): + nick = words[1] + # Check that nick is not ignored and longer than minimum length + if len(nick) < min_length or nick in ignore_nicks: + continue + if nick in colored_nicks[buffer]: + nick_color = colored_nicks[buffer][nick] + line = line.replace(nick, '%s%s%s' % (nick_color, nick, reset)) + + return line + +def populate_nicks(*args): + ''' Fills entire dict with all nicks weechat can see and what color it has + assigned to it. ''' + global colored_nicks + + colored_nicks = {} + + buffers = w.infolist_get('buffer', '', '') + while w.infolist_next(buffers): + buffer_ptr = w.infolist_pointer(buffers, 'pointer') + my_nick = w.buffer_get_string(buffer_ptr, 'localvar_nick') + nicklist = w.infolist_get('nicklist', buffer_ptr, '') + while w.infolist_next(nicklist): + if buffer_ptr not in colored_nicks: + colored_nicks[buffer_ptr] = {} + + nick = w.infolist_string(nicklist, 'name') + nick_color = colorize_nick_color(nick, my_nick) + + colored_nicks[buffer_ptr][nick] = nick_color + + w.infolist_free(nicklist) + + w.infolist_free(buffers) + + return w.WEECHAT_RC_OK + +def add_nick(data, signal, type_data): + ''' Add nick to dict of colored nicks ''' + global colored_nicks + + # Nicks can have , in them in some protocols + splitted = type_data.split(',') + pointer = splitted[0] + nick = ",".join(splitted[1:]) + if pointer not in colored_nicks: + colored_nicks[pointer] = {} + + my_nick = w.buffer_get_string(pointer, 'localvar_nick') + nick_color = colorize_nick_color(nick, my_nick) + + colored_nicks[pointer][nick] = nick_color + + return w.WEECHAT_RC_OK + +def remove_nick(data, signal, type_data): + ''' Remove nick from dict with colored nicks ''' + global colored_nicks + + # Nicks can have , in them in some protocols + splitted = type_data.split(',') + pointer = splitted[0] + nick = ",".join(splitted[1:]) + + if pointer in colored_nicks and nick in colored_nicks[pointer]: + del colored_nicks[pointer][nick] + + return w.WEECHAT_RC_OK + +def update_blacklist(*args): + ''' Set the blacklist for channels and nicks. ''' + global ignore_channels, ignore_nicks + ignore_channels = w.config_string(colorize_config_option['blacklist_channels']).split(',') + ignore_nicks = w.config_string(colorize_config_option['blacklist_nicks']).split(',') + return w.WEECHAT_RC_OK + +if __name__ == "__main__": + if w.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, + SCRIPT_DESC, "", ""): + colorize_config_init() + colorize_config_read() + + # Run once to get data ready + update_blacklist() + populate_nicks() + + w.hook_signal('nicklist_nick_added', 'add_nick', '') + w.hook_signal('nicklist_nick_removed', 'remove_nick', '') + w.hook_modifier('weechat_print', 'colorize_cb', '') + # Hook config for changing colors + w.hook_config('weechat.color.chat_nick_colors', 'populate_nicks', '') + w.hook_config('weechat.look.nick_color_hash', 'populate_nicks', '') + # Hook for working togheter with other scripts (like colorize_lines) + w.hook_modifier('colorize_nicks', 'colorize_cb', '') + # Hook for modifying input + w.hook_modifier('250|input_text_display', 'colorize_input_cb', '') + # Hook for updating blacklist (this could be improved to use fnmatch) + weechat.hook_config('%s.look.blacklist*' % SCRIPT_NAME, 'update_blacklist', '') diff --git a/.weechat/script/plugins.xml.gz b/.weechat/script/plugins.xml.gz new file mode 100644 index 0000000..dceeed9 Binary files /dev/null and b/.weechat/script/plugins.xml.gz differ diff --git a/.weechat/weechat.conf b/.weechat/weechat.conf index 49fc4ac..ec3369c 100644 --- a/.weechat/weechat.conf +++ b/.weechat/weechat.conf @@ -143,7 +143,7 @@ chat_host = cyan chat_inactive_buffer = default chat_inactive_window = default chat_nick = lightcyan -chat_nick_colors = "cyan,magenta,green,brown,lightblue,default,lightcyan,lightmagenta,lightgreen,blue" +chat_nick_colors = "red,green,brown,blue,magenta,cyan,white,lightred,lightgreen,yellow,lightblue,lightmagenta,lightcyan" chat_nick_offline = default chat_nick_offline_highlight = default chat_nick_offline_highlight_bg = blue @@ -232,6 +232,20 @@ path = "%h/plugins" save_config_on_unload = on [bar] +buffers.color_bg = default +buffers.color_delim = default +buffers.color_fg = default +buffers.conditions = "" +buffers.filling_left_right = vertical +buffers.filling_top_bottom = columns_vertical +buffers.hidden = on +buffers.items = "buffers" +buffers.position = left +buffers.priority = 0 +buffers.separator = on +buffers.size = 0 +buffers.size_max = 0 +buffers.type = root input.color_bg = default input.color_delim = cyan input.color_fg = default @@ -246,13 +260,27 @@ input.separator = off input.size = 1 input.size_max = 0 input.type = window +isetbar.color_bg = default +isetbar.color_delim = cyan +isetbar.color_fg = default +isetbar.conditions = "" +isetbar.filling_left_right = vertical +isetbar.filling_top_bottom = horizontal +isetbar.hidden = on +isetbar.items = "isetbar_help" +isetbar.position = top +isetbar.priority = 0 +isetbar.separator = on +isetbar.size = 3 +isetbar.size_max = 3 +isetbar.type = window nicklist.color_bg = default nicklist.color_delim = cyan nicklist.color_fg = default nicklist.conditions = "${nicklist}" nicklist.filling_left_right = vertical nicklist.filling_top_bottom = columns_vertical -nicklist.hidden = off +nicklist.hidden = on nicklist.items = "buffer_nicklist" nicklist.position = right nicklist.priority = 200 @@ -294,6 +322,7 @@ title.type = window [notify] [filter] +irc_smart = on;*;irc_smart_filter;* [key] ctrl-? = "/input delete_previous_char" @@ -567,11 +596,17 @@ meta2-D = "/cursor move left" @chat:q = "hsignal:chat_quote_prefix_message;/cursor stop" [key_mouse] +@bar(buffers):ctrl-wheeldown = "hsignal:buffers_mouse" +@bar(buffers):ctrl-wheelup = "hsignal:buffers_mouse" @bar(input):button2 = "/input grab_mouse_area" @bar(nicklist):button1-gesture-down = "/bar scroll nicklist ${_window_number} +100%" @bar(nicklist):button1-gesture-down-long = "/bar scroll nicklist ${_window_number} e" @bar(nicklist):button1-gesture-up = "/bar scroll nicklist ${_window_number} -100%" @bar(nicklist):button1-gesture-up-long = "/bar scroll nicklist ${_window_number} b" +@chat(perl.iset):button1 = "hsignal:iset_mouse" +@chat(perl.iset):button2* = "hsignal:iset_mouse" +@chat(perl.iset):wheeldown = "/repeat 5 /iset **down" +@chat(perl.iset):wheelup = "/repeat 5 /iset **up" @chat(script.scripts):button1 = "/window ${_window_number};/script go ${_chat_line_y}" @chat(script.scripts):button2 = "/window ${_window_number};/script go ${_chat_line_y};/script installremove -q ${script_name_with_extension}" @chat(script.scripts):wheeldown = "/script down 5" @@ -581,6 +616,8 @@ meta2-D = "/cursor move left" @item(buffer_nicklist):button1-gesture-left-long = "/window ${_window_number};/kickban ${nick}" @item(buffer_nicklist):button2 = "/window ${_window_number};/whois ${nick}" @item(buffer_nicklist):button2-gesture-left = "/window ${_window_number};/ban ${nick}" +@item(buffers):button1* = "hsignal:buffers_mouse" +@item(buffers):button2* = "hsignal:buffers_mouse" @bar:wheeldown = "/bar scroll ${_bar_name} ${_window_number} +20%" @bar:wheelup = "/bar scroll ${_bar_name} ${_window_number} -20%" @chat:button1 = "/window ${_window_number}"