Mercurial > dotfiles.old
changeset 202:1bb19c7b3298
Replace irssi with weechat
author | zegervdv <zegervdv@me.com> |
---|---|
date | Wed, 19 Nov 2014 19:24:17 +0100 |
parents | 6de3103d47f4 |
children | 2c77dbb93f11 |
files | irssi/config irssi/pbrisbin.theme irssi/scripts/adv_windowlist.pl irssi/scripts/autorun/adv_windowlist.pl irssi/scripts/autorun/cap_sasl.pl irssi/scripts/autorun/hilightwin.pl irssi/scripts/autorun/nicklist.pl irssi/scripts/autorun/nm.pl irssi/scripts/autorun/queryresume.pl irssi/scripts/autorun/trackbar.pl irssi/scripts/bitlbee_typing_notice.pl irssi/scripts/cap_sasl.pl irssi/scripts/hilightwin.pl irssi/scripts/nicklist.pl irssi/scripts/nm.pl irssi/scripts/queryresume.pl irssi/scripts/trackbar.pl weechat/buffers.conf weechat/perl/autoload/buffers.pl weechat/perl/autoload/iset.pl weechat/perl/buffers.pl weechat/perl/iset.pl weechat/weechat.conf |
diffstat | 23 files changed, 7458 insertions(+), 5083 deletions(-) [+] |
line wrap: on
line diff
--- a/irssi/config Wed Nov 19 19:08:21 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,219 +0,0 @@ -# vim:ft=config - -servers = ( - { - address = "irc.freenode.net"; - chatnet = "freenode"; - port = "6697"; - use_ssl = "yes"; - ssl_verify = "yes"; - ssl_capath = "/etc/ssl/certs/"; - autoconnect = "yes"; - }, - - { address = "localhost"; chatnet = "bitlbee"; autoconnect = "yes"; } -); - -chatnets = { - freenode = { type = "IRC"; nick = "zegervdv"; }; - bitlbee = { type = "IRC"; }; -}; - -channels = ( - { name = "#vim"; chatnet = "freenode"; autojoin = "yes"; }, - { name = "#raspberrypi"; chatnet = "freenode"; autojoin = "yes"; }, - { name = "#archlinux-arm"; chatnet = "freenode"; autojoin = "yes"; } -); - -aliases = { - J = "join"; - LEAVE = "part"; - E = "exec - runz"; - EO = "exec - -o runz"; - EXIT = "quit"; - LL = "lastlog"; - W = "window"; - M = "mark"; - WC = "window close"; - WK = "window kill"; - WN = "window new hide"; - WA = "window goto active"; - RUN = "SCRIPT LOAD"; - Q = "QUERY"; -}; - -statusbar = { - items = { - time = "{sb $Z} "; - window = ":: {sb [$winref] $tag $itemname} "; - window_empty = ":: {sb [$winref] $tag $itemname} "; - - prompt = "{prompt}"; - prompt_empty = "{prompt}"; - }; - - default = { - window = { - type = "window"; - placement = "top"; - visible = "active"; - items = { window = { }; window_empty = { }; typing_notice = { }; }; - }; - - window_inact = { - type = "window"; - placement = "top"; - visible = "inactive"; - items = { window = { }; window_empty = { }; }; - }; - - prompt = { - type = "root"; - placement = "bottom"; - position = "100"; - visible = "always"; - - items = { - time = { }; - user = { }; - prompt = { priority = "-1"; }; - prompt_empty = { priority = "-1"; }; - - input = { priority = "10"; }; - }; - }; - - topic = { - type = "root"; - placement = "bottom"; - position = "1"; - visible = "always"; - items = { topic = { }; topic_empty = { }; }; - }; - - awl_0 = { - items = { - barstart = { priority = "100"; }; - awl_0 = { }; - barend = { priority = "100"; alignment = "right"; }; - }; - }; - }; -}; - -settings = { - core = { - real_name = "Zeger Van de Vannet"; - user_name = "zegervdv"; - nick = "zegervdv"; - awaylog_file = "/dev/null"; - recode_autodetect_utf8 = "yes"; - recode_fallback = "CP1252"; - }; - - "fe-text" = { actlist_sort = "refnum"; }; - - "fe-common/core" = { - emphasis = "OFF"; - theme = "pbrisbin"; - beep_msg_level = "NOTICE MSGS HILIGHT"; - bell_beeps = "no"; - hilight_nick_matches = "no"; - autolog_path = "~/.irssi/logs/$tag/$0.log"; - autolog = "yes"; - }; - - "perl/core/scripts" = { - neat_maxlength = "13"; - awl_display_key = "%w$N.$H$C$S "; - awl_position = "0"; - awl_sbar_maxlength = "no"; - awl_maxlines = "3"; - screen_away_message = "away"; - hilightwin_showprivmsg = "no"; - bitlbee_send_typing = "yes"; - lt_in_queries = "yes"; - neat_left_actions = "no"; - awl_shared_sbar = "OFF"; - }; -}; - -ignores = ( - { level = "JOINS PARTS QUITS NICKS"; }, - { level = "MODES"; channels = ( "&bitlbee", "&facebook" ); } -); - -hilights = ( - { text = "zegervdv"; nick = "no"; word = "yes"; fullword = "yes"; }, - { text = "@zegervdv"; nick = "no"; word = "yes"; fullword = "yes"; } -); - -logs = { }; -windows = { - 1 = { immortal = "yes"; name = "(status)"; level = "ALL"; }; - 2 = { name = "hilight"; sticky = "yes"; }; - 3 = { - items = ( - { - type = "CHANNEL"; - chat_type = "IRC"; - name = "&bitlbee"; - tag = "bitlbee"; - } - ); - }; - 4 = { - items = ( - { - type = "CHANNEL"; - chat_type = "IRC"; - name = "#twitter_zegervdv"; - tag = "bitlbee"; - } - ); - }; - 5 = { - items = ( - { - type = "CHANNEL"; - chat_type = "IRC"; - name = "&facebook"; - tag = "bitlbee"; - } - ); - }; - 6 = { - items = ( - { - type = "CHANNEL"; - chat_type = "IRC"; - name = "#vim"; - tag = "freenode"; - } - ); - }; - 7 = { - items = ( - { - type = "CHANNEL"; - chat_type = "IRC"; - name = "#raspberrypi"; - tag = "freenode"; - } - ); - }; - 8 = { - items = ( - { - type = "CHANNEL"; - chat_type = "IRC"; - name = "#archlinux-arm"; - tag = "freenode"; - } - ); - }; -}; -mainwindows = { - 1 = { first_line = "11"; lines = "44"; }; - 2 = { first_line = "1"; lines = "10"; }; -};
--- a/irssi/pbrisbin.theme Wed Nov 19 19:08:21 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,174 +0,0 @@ -## -## pbrisbin's irssi theme. -## - -default_color = "-1"; -info_eol = "false"; -replaces = { "[]=" = "%K$*%n"; }; - -# Only overrides are shown, defaults are commented. -abstracts = { - ## - ## Generic - ## - line_start = "%c::%n "; - timestamp = "%K$0-%n"; - hilight = "%W$*%W"; - - #error = "%R$*%n"; - #channel = "%_$*%_"; - #nick = "%_$*%_"; - #nickhost = "[$*]"; - #server = "%_$*%_"; - #comment = "[$*]"; - #reason = "{comment $*}"; - #mode = "{comment $*}"; - - # channel specific messages - #channick_hilight = "%C$*%n"; - #chanhost_hilight = "{nickhost %c$*%n}"; - #channick = "%c$*%n"; - #chanhost = "{nickhost $*}"; - #channelhilight = "%c$*%n"; - #ban = "%c$*%n"; - - ## - ## Messages - ## - msgnick = "$0$1-%c:%n %|"; - - #ownmsgnick = "{msgnick $0 $1-}"; - #ownnick = "%W$*%n"; - #pubmsgnick = "{msgnick $0 $1-}"; - #pubnick = "%N$*%n"; - #pubmsgmenick = "{msgnick $0 $1-}"; - #menick = "%Y$*%n"; - #pubmsghinick = "{msgnick $1 $0$2-%n}"; - #msgchannel = "%K:%c$*%n"; - #privmsg = "[%R$0%K(%r$1-%K)%n] "; - #ownprivmsg = "[%r$0%K(%R$1-%K)%n] "; - #ownprivmsgnick = "{msgnick $*}"; - #ownprivnick = "%W$*%n"; - #privmsgnick = "{msgnick %R$*%n}"; - - ## - ## Action - ## - action_core = "%M$*"; - action = "{action_core $*}"; - pvtaction = "{action_core $*}"; - ownaction_target = "{action_core $*}"; - - #ownaction = "{action $*}"; - pubaction = "{action $*} "; - # fix neatlength inconsistency, sigh - #pvtaction_query = "{action $*}"; - - ## - ## whois - ## - #whois = "%# $[8]0 : $1-"; - - ## - ## Notices - ## - #ownnotice = "[%r$0%K(%R$1-%K)]%n "; - #notice = "%K-%M$*%K-%n "; - #pubnotice_channel = "%K:%m$*"; - #pvtnotice_host = "%K(%m$*%K)"; - #servernotice = "%g!$*%n "; - - ## - ## CTCP - ## - #ownctcp = "[%r$0%K(%R$1-%K)] "; - #ctcp = "%g$*%n"; - - ## - ## Wallops - ## - #wallop = "%W$*%n: "; - #wallop_nick = "%n$*"; - #wallop_action = "%W * $*%n "; - - ## - ## Netsplits - ## - #netsplit = "%R$*%n"; - #netjoin = "%C$*%n"; - - ## - ## Names - ## - #names_prefix = ""; - #names_nick = "[%_$0%_$1-] "; - #names_nick_op = "{names_nick $*}"; - #names_nick_halfop = "{names_nick $*}"; - #names_nick_voice = "{names_nick $*}"; - #names_users = "[%g$*%n]"; - #names_channel = "%G$*%n"; - - ## - ## DCC - ## - #dcc = "%g$*%n"; - #dccfile = "%_$*%_"; - #dccownmsg = "[%r$0%K($1-%K)%n] "; - #dccownnick = "%R$*%n"; - #dccownquerynick = "%W$*%n"; - #dccownaction = "{action $*}"; - #dccownaction_target = "{action_core $0}%K:%c$1%n "; - #dccmsg = "[%G$1-%K(%g$0%K)%n] "; - #dccquerynick = "%G$*%n"; - #dccaction = "%W (*dcc*) $*%n %|"; - - ## - ## Statusbar - ## - sb_background = "%n%0"; - sbstart = " "; - sbend = " "; - prompt = " %c:%n "; - sb = "%W$*"; - sbmode = ""; - sbaway = " (%Gaway%n)"; - - #sb_prompt_bg = "%n"; - #sb_info_bg = "%8"; - #sbstart = ""; - #sbend = " "; - #topicsbstart = "{sbstart $*}"; - #topicsbend = "{sbend $*}"; - #prompt = "[$*] "; - #sb = " %c[%n$*%c]%n"; - #sbmode = "(%c+%n$*)"; - #sbaway = " (%GzZzZ%n)"; - #sbservertag = ":$0 (change with ^X)"; - #sbnickmode = "$0"; - #sb_act_sep = "%c$*"; - #sb_act_text = "%c$*"; - #sb_act_msg = "%W$*"; - #sb_act_hilight = "%M$*"; - #sb_act_hilight_color = "$0$1-%n"; -}; - -formats = { - "fe-common/core" = { - own_msg = "{ownmsgnick {ownnick $[-13]0$2}}$1"; - own_msg_channel = "{ownmsgnick {ownnick $[-13]0$3}{msgchannel $1}}$2"; - own_msg_private_query = "{ownprivmsgnick {ownprivnick $[-13]2}}$1"; - pubmsg_me = "{pubmsgmenick {menick $[-13]0}$2}$1"; - pubmsg_me_channel = "{pubmsgmenick {menick $[-13]0$3}{msgchannel $1}}$2"; - pubmsg_hilight = "{pubmsghinick $0 $0 $[-13]1$3%n}$2"; - pubmsg_hilight_channel = "{pubmsghinick $0 $[-13]1$4{msgchannel $2}}$3"; - pubmsg = "{pubmsgnick {pubnick $[-13]0$2}}$1"; - pubmsg_channel = "{pubmsgnick {pubnick $[-13]0$2}}$1"; - msg_private_query = "{privmsgnick $[-13]0}$2"; - }; - "fe-common/irc" = { - own_action = "{ownaction $[-11]0} $1"; - action_private = "{pvtaction $[-11]0}$1"; - action_private_query = "{pvtaction_query $[-11]0} $2"; - action_public = "{pubaction $[-11]0}$1"; - }; -};
--- a/irssi/scripts/adv_windowlist.pl Wed Nov 19 19:08:21 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2478 +0,0 @@ -use strict; # use warnings; - -# {{{ debug - -#BEGIN { -# open STDERR, '>', '/home/ailin/wlstatwarnings'; -#}; - -# FIXME COULD SOMEONE PLEASE TELL ME HOW TO SHUT UP -# -# ... -# Variable "*" will not stay shared at (eval *) line *. -# Variable "*" will not stay shared at (eval *) line *. -# ... -# Can't locate package Irssi::Nick for @Irssi::Irc::Nick::ISA at (eval *) line *. -# ... -# -# THANKS - -# }}} - -# if you don't know how to operate folds, type zn - -# {{{ header - -use Irssi (); # which is the minimum required version of Irssi ? -use Irssi::TextUI; - -use vars qw($VERSION %IRSSI); - -$VERSION = '0.6ca'; -%IRSSI = ( - original_authors => q(BC-bd, Veli, Timo Sirainen, ). - q(Wouter Coekaerts, Jean-Yves Lefort), # (decadix) - original_contact => q([email protected], [email protected], [email protected], ). - q([email protected], [email protected]), - authors => q(Nei), - contact => q(Nei @ [email protected]), - url => "http://anti.teamidiot.de/", - name => q(awl), - description => q(Adds a permanent advanced window list on the right or ). - q(in a statusbar.), - description2 => q(Based on chanact.pl which was apparently based on ). - q(lightbar.c and nicklist.pl with various other ideas ). - q(from random scripts.), - license => q(GNU GPLv2 or later), -); - -# }}} - -# {{{ *** D O C U M E N T A T I O N *** - -# adapted by Nei - -############### -# {{{ original comment -# ########### -# # Adds new powerful and customizable [Act: ...] item (chanelnames,modes,alias). -# # Lets you give alias characters to windows so that you can select those with -# # meta-<char>. -# # -# # for irssi 0.8.2 by [email protected] -# # -# # inspired by chanlist.pl by '[email protected]' -# # -# ######### -# # {{{ Contributors -# ######### -# # -# # [email protected] /window_alias code -# # [email protected] chanact_abbreviate_names -# # [email protected] Extra chanact_show_mode and chanact_chop_status -# # }}} -# }}} -# -# {{{ FURTHER THANKS TO -# ############ -# # buu, fxn, Somni, Khisanth, integral, tybalt89 for much support in any aspect perl -# # and the channel in general ( #perl @ freenode ) and especially the ir_* functions -# # -# # Valentin 'senneth' Batz ( [email protected] ) for the pointer to grep.pl, continuous support -# # and help in digging up ir_strip_codes -# # -# # OnetrixNET technology networks for the debian environment -# # -# # Monkey-Pirate.com / Spaceman Spiff for the webspace -# # -# }}} - -###### -# {{{ M A I N P R O B L E M -##### -# -# It is impossible to place the awl on a statusbar together with other items, -# because I do not know how to calculate the size that it is going to get -# granted, and therefore I cannot do the linebreaks properly. -# This is what is missing to make a nice script out of awl. -# If you have any ideas, please contact me ASAP :). -# }}} -###### - -###### -# {{{ UTF-8 PROBLEM -##### -# -# Please help me find a solution to this: -# this be your statusbar, it is using up the maximum term size -# [[1=1]#abc [2=2]#defghi] -# -# now consider this example:i -# "ascii" characters are marked with ., utf-8 characters with * -# [[1=1]#... [2=2]#...***] -# -# you should think that this is how it would be displayed? WRONG! -# [[1=1]#... [2=2]#...*** ] -# -# this is what Irssi does.. I believe my length calculating code to be correct, -# however, I'd love to be proven wrong (or receive any other fix, too, of -# course!) -# }}} -###### - -######### -# {{{ USAGE -### -# -# copy the script to ~/.irssi/scripts/ -# -# In irssi: -# -# /script load awl -# -# -# Hint: to get rid of the old [Act:] display -# /statusbar window remove act -# -# to get it back: -# /statusbar window add -after lag -priority 10 act -# }}} -########## -# {{{ OPTIONS -######## -# -# {{{ /set awl_display_nokey <string> -# /set awl_display_key <string> -# /set awl_display_nokey_active <string> -# /set awl_display_key_active <string> -# * string : Format String for one window. The following $'s are expanded: -# $C : Name -# $N : Number of the Window -# $Q : meta-Keymap -# $H : Start highlighting -# $S : Stop highlighting -# /+++++++++++++++++++++++++++++++++, -# | **** I M P O R T A N T : **** | -# | | -# | don't forget to use $S if you | -# | used $H before! | -# | | -# '+++++++++++++++++++++++++++++++++/ -# XXX NOTE ON *_active: there is a BUG somewhere in the length -# XXX calculation. currently it's best to NOT remove $H/$S from those -# XXX settings if you use it in the non-active settings. -# }}} -# {{{ /set awl_separator <string> -# * string : Charater to use between the channel entries -# you'll need to escape " " space and "$" like this: -# "/set awl_separator \ " -# "/set awl_separator \$" -# and {}% like this: -# "/set awl_separator %{" -# "/set awl_separator %}" -# "/set awl_separator %%" -# (reason being, that the separator is used inside a {format }) -# }}} -# {{{ /set awl_prefer_name <ON|OFF> -# * this setting decides whether awl will use the active_name (OFF) or the -# window name as the name/caption in awl_display_*. -# That way you can rename windows using /window name myownname. -# }}} -# {{{ /set awl_hide_data <num> -# * num : hide the window if its data_level is below num -# set it to 0 to basically disable this feature, -# 1 if you don't want windows without activity to be shown -# 2 to show only those windows with channel text or hilight -# 3 to show only windows with hilight -# }}} -# {{{ /set awl_maxlines <num> -# * num : number of lines to use for the window list (0 to disable, negative -# lock) -# }}} -# {{{ /set awl_columns <num> -# * num : number of columns to use in screen mode (0 for unlimited) -# }}} -# {{{ /set awl_block <num> -# * num : width of a column in screen mode (negative values = block display) -# /+++++++++++++++++++++++++++++++++, -# | ****** W A R N I N G ! ****** | -# | | -# | If your block display looks | -# | DISTORTED, you need to add the | -# | following line to your .theme | -# | file under | -# | abstracts = { : | -# | | -# | sb_act_none = "%n$*"; | -# | | -# '+++++++++++++++++++++++++++++++++/ -#.02:08:26. < shi> Irssi::current_theme()->get_format <.. can this be used? -# }}} -# {{{ /set awl_sbar_maxlength <ON|OFF> -# * if you enable the maxlength setting, the block width will be used as a -# maximum length for the non-block statusbar mode too. -# }}} -# {{{ /set awl_height_adjust <num> -# * num : how many lines to leave empty in screen mode -# }}} -# {{{ /set awl_sort <-data_level|-last_line|refnum> -# * you can change the window sort order with this variable -# -data_level : sort windows with hilight first -# -last_line : sort windows in order of activity -# refnum : sort windows by window number -# }}} -# {{{ /set awl_placement <top|bottom> -# /set awl_position <num> -# * these settings correspond to /statusbar because awl will create -# statusbars for you -# (see /help statusbar to learn more) -# }}} -# {{{ /set awl_all_disable <ON|OFF> -# * if you set awl_all_disable to ON, awl will also remove the -# last statusbar it created if it is empty. -# As you might guess, this only makes sense with awl_hide_data > 0 ;) -# }}} -# {{{ /set awl_automode <sbar|screen|emulate_lightbar> -# * this setting defines whether the window list is shown in statusbars or -# whether the screen hack is used (from nicklist.pl) -# }}} -# }}} -########## -# {{{ COMMANDS -######## -# {{{ /awl paste <ON|OFF|TOGGLE> -# * enables or disables the screen hack windowlist. This is useful when you -# want to mark & copy text that you want to paste somewhere (hence the -# name). (ON means AWL disabled!) -# This is nicely bound to a function key for example. -# }}} -# {{{ /awl redraw -# * redraws the screen hack windowlist. There are many occasions where the -# screen hack windowlist can get destroyed so you can use this command to -# fix it. -# }}} -# }}} -### -# {{{ WISHES -#### -# -# if you fiddle with my mess, provide me with your fixes so I can benefit as well -# -# Nei =^.^= ( [email protected] ) -# }}} - -# }}} - -# {{{ modules - -#use Class::Classless; -#use Term::Info; - -# }}} - -# {{{ global variables - -my $replaces = '[=]'; # AARGH!!! (chars that are always surrounded by weird - # colour codes by Irssi) - -my $actString = []; # statusbar texts -my $currentLines = 0; -my $resetNeeded; # layout/screen has changed, redo everything -my $needRemake; # "normal" changes -#my $callcount = 0; -sub GLOB_QUEUE_TIMER () { 100 } -my $globTime = undef; # timer to limit remake() calls - - -my $SCREEN_MODE; -my $DISABLE_SCREEN_TEMP; -my $currentColumns = 0; -my $screenResizing; -my ($screenHeight, $screenWidth); -my $screenansi = bless { - NAME => 'Screen::ANSI', - PARENTS => [], - METHODS => { - dcs => sub { "\033P" }, - st => sub { "\033\\"}, - } -}, 'Class::Classless::X'; -#my $terminfo = new Term::Info 'xterm'; # xterm here, make this modular -# {{{{{{{{{{{{{{{ -my $terminfo = bless { # xterm here, make this modular - NAME => 'Term::Info::xterm', - PARENTS => [], - METHODS => { - # civis=\E[?25l, - civis => sub { "\033[?25l" }, - # sc=\E7, - sc => sub { "\0337" }, - # cup=\E[%i%p1%d;%p2%dH, - cup => sub { shift;shift; "\033[" . ($_[0] + 1) . ';' . ($_[1] + 1) . 'H' }, - # el=\E[K, - el => sub { "\033[K" }, - # rc=\E8, - rc => sub { "\0338" }, - # cnorm=\E[?25h, - cnorm => sub { "\033[?25h" }, - # setab=\E[4%p1%dm, - setab => sub { shift;shift; "\033[4" . $_[0] . 'm' }, - # setaf=\E[3%p1%dm, - setaf => sub { shift;shift; "\033[3" . $_[0] . 'm' }, - # bold=\E[1m, - bold => sub { "\033[1m" }, - # blink=\E[5m, - blink => sub { "\033[5m" }, - # rev=\E[7m, - rev => sub { "\033[7m" }, - # op=\E[39;49m, - op => sub { "\033[39;49m" }, - } -}, 'Class::Classless::X'; -# }}}}}}}}}}}}}}} - - -sub setc () { - $IRSSI{'name'} -} -sub set ($) { - setc . '_' . shift -} - -# }}} - - -# {{{ sbar mode - -my %statusbars; # currently active statusbars - -# maybe I should just tie the array ? -sub add_statusbar { - for (@_) { - # add subs - for my $l ($_) { { - no strict 'refs'; # :P - *{set$l} = sub { awl($l, @_) }; - }; } - Irssi::command('statusbar ' . (set$_) . ' reset'); - Irssi::command('statusbar ' . (set$_) . ' enable'); - if (lc Irssi::settings_get_str(set 'placement') eq 'top') { - Irssi::command('statusbar ' . (set$_) . ' placement top'); - } - if ((my $x = int Irssi::settings_get_int(set 'position')) != 0) { - Irssi::command('statusbar ' . (set$_) . ' position ' . $x); - } - Irssi::command('statusbar ' . (set$_) . ' add -priority 100 -alignment left barstart'); - Irssi::command('statusbar ' . (set$_) . ' add ' . (set$_)); - Irssi::command('statusbar ' . (set$_) . ' add -priority 100 -alignment right barend'); - Irssi::command('statusbar ' . (set$_) . ' disable'); - Irssi::statusbar_item_register(set$_, '$0', set$_); - $statusbars{$_} = {}; - } -} - -sub remove_statusbar { - for (@_) { - Irssi::command('statusbar ' . (set$_) . ' reset'); - Irssi::statusbar_item_unregister(set$_); # XXX does this actually work ? - # DO NOT REMOVE the sub before you have unregistered it :)) - for my $l ($_) { { - no strict 'refs'; - undef &{set$l}; - }; } - delete $statusbars{$_}; - } -} - -sub syncLines { - my $temp = $currentLines; - $currentLines = @$actString; - #Irssi::print("current lines: $temp new lines: $currentLines"); - my $currMaxLines = Irssi::settings_get_int(set 'maxlines'); - if ($currMaxLines > 0 and @$actString > $currMaxLines) { - $currentLines = $currMaxLines; - } - elsif ($currMaxLines < 0) { - $currentLines = abs($currMaxLines); - } - return if ($temp == $currentLines); - if ($currentLines > $temp) { - for ($temp .. ($currentLines - 1)) { - add_statusbar($_); - Irssi::command('statusbar ' . (set$_) . ' enable'); - } - } - else { - for ($_ = ($temp - 1); $_ >= $currentLines; $_--) { - Irssi::command('statusbar ' . (set$_) . ' disable'); - remove_statusbar($_); - } - } -} - -# FIXME implement $get_size_only check, and user $item->{min|max-size} ?? -sub awl { - my ($line, $item, $get_size_only) = @_; - - if ($needRemake) { - $needRemake = undef; - remake(); - } - - my $text = $actString->[$line]; # DO NOT set the actual $actString->[$line] to '' here or - $text = '' unless defined $text; # you'll screw up the statusbar counter ($currentLines) - $item->default_handler($get_size_only, $text, '', 1); -} - -# remove old statusbars -my %killBar; -sub get_old_status { - my ($textDest, $cont, $cont_stripped) = @_; - if ($textDest->{'level'} == 524288 and $textDest->{'target'} eq '' - and !defined($textDest->{'server'}) - ) { - my $name = quotemeta(set ''); - if ($cont_stripped =~ m/^$name(\d+)\s/) { $killBar{$1} = {}; } - Irssi::signal_stop(); - } -} -sub killOldStatus { - %killBar = (); - Irssi::signal_add_first('print text' => 'get_old_status'); - Irssi::command('statusbar'); - Irssi::signal_remove('print text' => 'get_old_status'); - remove_statusbar(keys %killBar); -} -#killOldStatus(); - -# end sbar mode }}} - - -# {{{ keymaps - -my %keymap; - -sub get_keymap { - my ($textDest, undef, $cont_stripped) = @_; - if ($textDest->{'level'} == 524288 and $textDest->{'target'} eq '' - and !defined($textDest->{'server'}) - ) { - if ($cont_stripped =~ m/((?:meta-)+)(.)\s+change_window (\d+)/) { - my ($level, $key, $window) = ($1, $2, $3); - my $numlevel = ($level =~ y/-//) - 1; - $keymap{$window} = ('-' x $numlevel) . "$key"; - } - Irssi::signal_stop(); - } -} - -sub update_keymap { - %keymap = (); - Irssi::signal_remove('command bind' => 'watch_keymap'); - Irssi::signal_add_first('print text' => 'get_keymap'); - Irssi::command('bind'); # stolen from grep - Irssi::signal_remove('print text' => 'get_keymap'); - Irssi::signal_add('command bind' => 'watch_keymap'); - Irssi::timeout_add_once(100, 'eventChanged', undef); -} - -# watch keymap changes -sub watch_keymap { - Irssi::timeout_add_once(1000, 'update_keymap', undef); -} - -update_keymap(); - -# end keymaps }}} - -# {{{ format handling - -# a bad way do do expansions but who cares -sub expand { - my ($string, %format) = @_; - my ($exp, $repl); - $string =~ s/\$$exp/$repl/g while (($exp, $repl) = each(%format)); - return $string; -} - -my %strip_table = ( - # fe-common::core::formats.c:format_expand_styles - # delete format_backs format_fores bold_fores other stuff - (map { $_ => '' } (split //, '04261537' . 'kbgcrmyw' . 'KBGCRMYW' . 'U9_8:|FnN>#[')), - # escape - (map { $_ => $_ } (split //, '{}%')), -); -sub ir_strip_codes { # strip %codes - my $o = shift; - $o =~ s/(%(.))/exists $strip_table{$2} ? $strip_table{$2} : $1/gex; - $o -} - -sub ir_parse_special { - my $o; my $i = shift; - #if ($_[0]) { # for the future?!? - # eval { - # $o = $_[0]->parse_special($i); - # }; - # unless ($@) { - # return $o; - # } - #} - my $win = shift || Irssi::active_win(); - my $server = Irssi::active_server(); - if (ref $win and ref $win->{'active'}) { - $o = $win->{'active'}->parse_special($i); - } - elsif (ref $win and ref $win->{'active_server'}) { - $o = $win->{'active_server'}->parse_special($i); - } - elsif (ref $server) { - $o = $server->parse_special($i); - } - else { - $o = Irssi::parse_special($i); - } - $o -} -sub ir_parse_special_protected { - my $o; my $i = shift; - $i =~ s/ - ( \\. ) | # skip over escapes (maybe) - ( \$[^% $\]+ ) # catch special variables - / - if ($1) { $1 } - elsif ($2) { my $i2 = $2; ir_fe(ir_parse_special($i2, @_)) } - else { $& } - /gex; - $i -} - - -sub sb_ctfe { # Irssi::current_theme->format_expand wrapper - Irssi::current_theme->format_expand( - shift, - ( - Irssi::EXPAND_FLAG_IGNORE_REPLACES - | - ($_[0]?0:Irssi::EXPAND_FLAG_IGNORE_EMPTY) - ) - ) -} -sub sb_expand { # expand {format }s (and apply parse_special for $vars) - ir_parse_special( - sb_ctfe(shift) - ) -} -sub sb_strip { - ir_strip_codes( - sb_expand(shift) - ); # does this get us the actual length of that s*ty bar :P ? -} -sub sb_length { - # unicode cludge, d*mn broken Irssi - # screw it, this will fail from broken joining anyway (and cause warnings) - my $term_type = 'term_type'; - if (Irssi::version > 20040819) { # this is probably wrong, but I don't know - # when the setting name got changed - $term_type = 'term_charset'; - } - #if (lc Irssi::settings_get_str($term_type) eq '8bit' - # or Irssi::settings_get_str($term_type) =~ /^iso/i - #) { - # length(sb_strip(shift)) - #} - #else { - my $temp = sb_strip(shift); - # try to get the displayed width - my $length; - eval { - require Text::CharWidth; - $length = Text::CharWidth::mbswidth($temp); - }; - unless ($@) { - return $length; - } - else { - if (lc Irssi::settings_get_str($term_type) eq 'utf-8') { - # try to switch on utf8 - eval { - no warnings; - require Encode; - #$temp = Encode::decode_utf8($temp); # thanks for the hint, but I have my - # # reasons for _utf8_on - Encode::_utf8_on($temp); - }; - } - # there is nothing more I can do - length($temp) - } - #} -} - -# !!! G*DD*MN Irssi is adding an additional layer of backslashitis per { } layer -# !!! AND I still don't know what I need to escape. -# !!! and NOONE else seems to know or care either. -# !!! f*ck open source. I mean it. -# XXX any Irssi::print debug statement leads to SEGFAULT - why ? - -# major parts of the idea by buu (#perl @ freenode) -# thanks to fxn and Somni for debugging -# while ($_[0] =~ /(.)/g) { -# my $c = $1; # XXX sooo... goto kills $1 -# if ($q eq '%') { goto ESC; } - -## <freenode:#perl:tybalt89> s/%(.)|(\{)|(\})|(\\|\$)/$1?$1:$2?($level++,$2):$3?($level>$min_level&&$level--,$3):'\\'x(2**$level-1).$4/ge; # untested... -sub ir_escape { - my $min_level = $_[1] || 0; my $level = $min_level; - my $o = shift; - $o =~ s/ - ( %. ) | # $1 - ( \{ ) | # $2 - ( \} ) | # $3 - ( \\ ) | # $4 - ( \$(?=[^\\]) ) | # $5 - ( \$ ) # $6 - / - if ($1) { $1 } # %. escape - elsif ($2) { $level++; $2 } # { nesting start - elsif ($3) { if ($level > $min_level) { $level--; } $3 } # } nesting end - elsif ($4) { '\\'x(2**$level) } # \ needs \\escaping - elsif ($5) { '\\'x(2**$level-1) . '$' . '\\'x(2**$level-1) } # and $ needs even more because of "parse_special" - else { '\\'x(2**$level-1) . '$' } # $ needs \$ escaping - /gex; - $o -} -#sub ir_escape { -# my $min_level = $_[1] || 0; my $level = $min_level; -# my $o = shift; -# $o =~ s/ -# ( %. ) | # $1 -# ( \{ ) | # $2 -# ( \} ) | # $3 -# ( \\ | \$ ) # $4 -# / -# if ($1) { $1 } # %. escape -# elsif ($2) { $level++; $2 } # { nesting start -# elsif ($3) { if ($level > $min_level) { $level--; } $3 } # } nesting end -# else { '\\'x(2**($level-1)-1) . $4 } # \ or $ needs \\escaping -# /gex; -# $o -#} - -sub ir_fe { # try to fix format stuff - my $x = shift; - # XXX why do I have to use two/four % here instead of one/two ?? - # answer: you screwed up in ir_escape - $x =~ s/([%{}])/%$1/g; - #$x =~ s/(\\|\$|[ ])/\\$1/g; # XXX HOW CAN I HANDLE THE SPACES CORRECTLY XXX - $x =~ s/(\\|\$)/\\$1/g; - #$x =~ s/(\$(?=.))|(\$)/$1?"\\\$\\":"\\\$"/ge; # I think this should be here - # # (logic), but it doesn't work - # # that way :P - #$x =~ s/\\/\\\\/g; # that's right, escape escapes - $x -} -sub ir_ve { # escapes special vars but leave colours alone - my $x = shift; - #$x =~ s/([%{}])/%$1/g; - $x =~ s/(\\|\$|[ ])/\\$1/g; - $x -} - -my %ansi_table; -{ - my ($i, $j, $k) = (0, 0, 0); - %ansi_table = ( - # fe-common::core::formats.c:format_expand_styles - # do format_backs - (map { $_ => $terminfo->setab($i++) } (split //, '01234567' )), - # do format_fores - (map { $_ => $terminfo->setaf($j++) } (split //, 'krgybmcw' )), - # do bold_fores - (map { $_ => $terminfo->bold() . - $terminfo->setaf($k++) } (split //, 'KRGYBMCW')), - # reset - #(map { $_ => $terminfo->op() } (split //, 'nN')), - (map { $_ => $terminfo->op() } (split //, 'n')), - (map { $_ => "\033[0m" } (split //, 'N')), # XXX quick and DIRTY - # flash/bright - F => $terminfo->blink(), - # reverse - 8 => $terminfo->rev(), - # bold - (map { $_ => $terminfo->bold() } (split //, '9_')), - # delete other stuff - (map { $_ => '' } (split //, ':|>#[')), - # escape - (map { $_ => $_ } (split //, '{}%')), - ) -} -sub formats_to_ansi_basic { - my $o = shift; - $o =~ s/(%(.))/exists $ansi_table{$2} ? $ansi_table{$2} : $1/gex; - $o -} - -sub lc1459 ($) { my $x = shift; $x =~ y/A-Z][\^/a-z}{|~/; $x } -Irssi::settings_add_str(setc, 'banned_channels', ''); -Irssi::settings_add_bool(setc, 'banned_channels_on', 0); -my %banned_channels = map { lc1459($_) => undef } -split ' ', Irssi::settings_get_str('banned_channels'); -Irssi::settings_add_str(setc, 'fancy_abbrev', 'fancy'); - -# }}} - -# {{{ main - -sub remake () { - #$callcount++; - #my $xx = $callcount; Irssi::print("starting remake [ $xx ]"); - my ($hilight, $number, $display); - my $separator = '{sb_act_sep ' . Irssi::settings_get_str(set 'separator') . - '}'; - my $custSort = Irssi::settings_get_str(set 'sort'); - my $custSortDir = 1; - if ($custSort =~ /^[-!](.*)/) { - $custSortDir = -1; - $custSort = $1; - } - - my @wins = - sort { - ( - ( (int($a->{$custSort}) <=> int($b->{$custSort})) * $custSortDir ) - || - ($a->{'refnum'} <=> $b->{'refnum'}) - ) - } Irssi::windows; - my $block = Irssi::settings_get_int(set 'block'); - my $columns = $currentColumns; - my $oldActString = $actString if $SCREEN_MODE; - $actString = $SCREEN_MODE ? [' A W L'] : []; - my $line = $SCREEN_MODE ? 1 : 0; - my $width = $SCREEN_MODE - ? - $screenWidth - abs($block)*$columns + 1 - : - ([Irssi::windows]->[0]{'width'} - sb_length('{sb x}')); - my $height = $screenHeight - abs(Irssi::settings_get_int(set - 'height_adjust')); - my ($numPad, $keyPad) = (0, 0); - my %abbrevList; - if ($SCREEN_MODE or Irssi::settings_get_bool(set 'sbar_maxlength') - or ($block < 0) - ) { - %abbrevList = (); - if (Irssi::settings_get_str('fancy_abbrev') !~ /^(no|off|head)/i) { - my @nameList = map { ref $_ ? $_->get_active_name : '' } @wins; - for (my $i = 0; $i < @nameList - 1; ++$i) { - my ($x, $y) = ($nameList[$i], $nameList[$i + 1]); - for ($x, $y) { s/^[+#!=]// } - my $res = Algorithm::LCSS::LCSS($x, $y); - if (defined $res) { - #Irssi::print("common pattern $x $y : $res"); - #Irssi::print("found at $nameList[$i] ".index($nameList[$i], - # $res)); - $abbrevList{$nameList[$i]} = int (index($nameList[$i], $res) + - (length($res) / 2)); - #Irssi::print("found at ".$nameList[$i+1]." ".index($nameList[$i+1], - # $res)); - $abbrevList{$nameList[$i+1]} = int (index($nameList[$i+1], $res) + - (length($res) / 2)); - } - } - } - if ($SCREEN_MODE or ($block < 0)) { - $numPad = length((sort { length($b) <=> length($a) } keys %keymap)[0]); - $keyPad = length((sort { length($b) <=> length($a) } values %keymap)[0]); - } - } - if ($SCREEN_MODE) { - print STDERR $screenansi->dcs(). - $terminfo->civis(). - $terminfo->sc(). - $screenansi->st(); - if (@$oldActString < 1) { - print STDERR $screenansi->dcs(). - $terminfo->cup(0, $width). - $actString->[0]. - $terminfo->el(). - $screenansi->st(); - } - } - foreach my $win (@wins) { - unless ($SCREEN_MODE) { - $actString->[$line] = '' unless defined $actString->[$line] - or Irssi::settings_get_bool(set 'all_disable'); - } - - # all stolen from chanact, what does this code do and why do we need it ? - !ref($win) && next; - - my $name = $win->get_active_name; - $name = '*' if (Irssi::settings_get_bool('banned_channels_on') and exists - $banned_channels{lc1459($name)}); - $name = $win->{'name'} if $name ne '*' and $win->{'name'} ne '' - and Irssi::settings_get_bool(set 'prefer_name'); - my $active = $win->{'active'}; - my $colour = $win->{'hilight_color'}; - if (!defined $colour) { $colour = ''; } - - if ($win->{'data_level'} < Irssi::settings_get_int(set 'hide_data')) { - next; } # for Geert - if ($win->{'data_level'} == 0) { $hilight = '{sb_act_none '; } - elsif ($win->{'data_level'} == 1) { $hilight = '{sb_act_text '; } - elsif ($win->{'data_level'} == 2) { $hilight = '{sb_act_msg '; } - elsif ($colour ne '') { $hilight = "{sb_act_hilight_color $colour "; } - elsif ($win->{'data_level'} == 3) { $hilight = '{sb_act_hilight '; } - else { $hilight = '{sb_act_special '; } - - $number = $win->{'refnum'}; - my @display = ('display_nokey'); - if (defined $keymap{$number} and $keymap{$number} ne '') { - unshift @display, map { (my $cpy = $_) =~ s/_no/_/; $cpy } @display; - } - if (Irssi::active_win->{'refnum'} == $number) { - unshift @display, map { my $cpy = $_; $cpy .= '_active'; $cpy } @display; - } - #Irssi::print("win $number [@display]: " . join '.', split //, join '<<', map { - # Irssi::settings_get_str(set $_) } @display); - $display = (grep { $_ } - map { Irssi::settings_get_str(set $_) } - @display)[0]; - #Irssi::print("win $number : " . join '.', split //, $display); - - if ($SCREEN_MODE or Irssi::settings_get_bool(set 'sbar_maxlength') - or ($block < 0) - ) { - my $baseLength = sb_length(ir_escape(ir_ve(ir_parse_special_protected(sb_ctfe( - '{sb_background}' . expand($display, - C => ir_fe('x'), - N => $number . (' 'x($numPad - length($number))), - Q => ir_fe((' 'x($keyPad - length($keymap{$number}))) . $keymap{$number}), - H => $hilight, - S => '}{sb_background}' - ), 1), $win)))) - 1; - my $diff = abs($block) - (length($name) + $baseLength); - if ($diff < 0) { # too long - if (abs($diff) >= length($name)) { $name = '' } # forget it - elsif (abs($diff) + 1 >= length($name)) { $name = substr($name, - 0, 1); } - else { - my $middle = exists $abbrevList{$name} ? - (($abbrevList{$name} + (2*(length($name) / 2)))/3) : - ((Irssi::settings_get_str('fancy_abbrev') =~ /^head/i) ? - length($name) : - (length($name) / 2)); - my $cut = int($middle - (abs($diff) / 2) + .55); - $cut = 1 if $cut < 1; - $cut = length($name) - abs($diff) - 1 if $cut > (length($name) - - abs($diff) - 1); - $name = substr($name, 0, $cut) . '~' . substr($name, $cut + - abs($diff) + 1); - } - } - elsif ($SCREEN_MODE or ($block < 0)) { - $name .= (' ' x $diff); - } - } - - my $add = ir_ve(ir_parse_special_protected(sb_ctfe('{sb_background}' . expand($display, - C => ir_fe($name), - N => $number . (' 'x($numPad - length($number))), - Q => ir_fe((' 'x($keyPad - length($keymap{$number}))) . $keymap{$number}), - H => $hilight, - S => '}{sb_background}' - ), 1), $win)); - if ($SCREEN_MODE) { - $actString->[$line] = $add; - if ((!defined $oldActString->[$line] - or $oldActString->[$line] ne $actString->[$line]) - and - $line <= ($columns * $height) - ) { - print STDERR $screenansi->dcs(). - $terminfo->cup(($line-1) % $height+1, $width + ( - abs($block) * int(($line-1) / $height))). - formats_to_ansi_basic(sb_expand(ir_escape($actString->[$line]))). - #$terminfo->el(). - $screenansi->st(); - } - $line++; - } - else { - #$temp =~ s/\{\S+?(?:\s(.*?))?\}/$1/g; - #$temp =~ s/\\\\\\\\/\\/g; # XXX I'm actually guessing here, someone point me - # # XXX to docs please - $actString->[$line] = '' unless defined $actString->[$line]; - - # XXX how can I check whether the content still fits in the bar? this would - # XXX allow awlstatus to reside on a statusbar together with other items... - if (sb_length(ir_escape($actString->[$line] . $add)) >= $width) { - # XXX doesn't correctly handle utf-8 multibyte ... help !!? - $actString->[$line] .= ' ' x ($width - sb_length(ir_escape( - $actString->[$line]))); - $line++; - } - $actString->[$line] .= $add . $separator; - # XXX if I use these prints, output layout gets screwed up... why ? - #Irssi::print("line $line: ".$actString->[$line]); - #Irssi::print("temp $line: ".$temp); - } - } - - if ($SCREEN_MODE) { - while ($line <= ($columns * $height)) { - print STDERR $screenansi->dcs(). - $terminfo->cup(($line-1) % $height+1, $width + ( - abs($block) * int(($line-1) / $height))). - $terminfo->el(). - $screenansi->st(); - $line++; - } - print STDERR $screenansi->dcs(). - $terminfo->rc(). - $terminfo->cnorm(). - $screenansi->st(); - } - else { - # XXX the Irssi::print statements lead to the MOST WEIRD results - # e.g.: the loop gets executed TWICE for p > 0 ?!? - for (my $p = 0; $p < @$actString; $p++) { # wrap each line in {sb }, escape it - my $x = $actString->[$p]; # properly, etc. - $x =~ s/\Q$separator\E([ ]*)$/$1/; - #Irssi::print("[$p]".'current:'.join'.',split//,sb_strip(ir_escape($x,0))); - #Irssi::print("assumed length before:".sb_length(ir_escape($x,0))); - $x = "{sb $x}"; - #Irssi::print("[$p]".'new:'.join'.',split//,sb_expand(ir_escape($x,0))); - #Irssi::print("[$p]".'new:'.join'.',split//,ir_escape($x,0)); - #Irssi::print("assumed length after:".sb_length(ir_escape($x,0))); - $x = ir_escape($x); - #Irssi::print("[$p]".'REALnew:'.join'.',split//,sb_strip($x)); - $actString->[$p] = $x; - # XXX any Irssi::print debug statement leads to SEGFAULT (sometimes) - why ? - } - } - #Irssi::print("remake [ $xx ] finished"); -} - -sub awlHasChanged () { - $globTime = undef; - my $temp = ($SCREEN_MODE ? - "\\\n" . Irssi::settings_get_int(set 'block'). - Irssi::settings_get_int(set 'height_adjust') - : "!\n" . Irssi::settings_get_str(set 'placement'). - Irssi::settings_get_int(set 'position')). - Irssi::settings_get_str(set 'automode'); - if ($temp ne $resetNeeded) { wlreset(); return; } - #Irssi::print("awl has changed, calls to remake so far: $callcount"); - $needRemake = 1; - - #remake(); - if ( - ($SCREEN_MODE and !$DISABLE_SCREEN_TEMP) - or - ($needRemake and Irssi::settings_get_bool(set 'all_disable')) - or - (!Irssi::settings_get_bool(set 'all_disable') and $currentLines < 1) - ) { - $needRemake = undef; - remake(); - } - - unless ($SCREEN_MODE) { - # XXX Irssi crashes if I try to do this without timer, why ? What's the minimum - # XXX delay I need to use in the timer ? - Irssi::timeout_add_once(100, 'syncLines', undef); - - for (keys %statusbars) { - Irssi::statusbar_items_redraw(set$_); - } - } - else { - Irssi::timeout_add_once(100, 'syncColumns', undef); - } -} - -sub eventChanged () { # Implement a change queue/blocker -.-) - if (defined $globTime) { - Irssi::timeout_remove($globTime); - } # delay the update further - $globTime = Irssi::timeout_add_once(GLOB_QUEUE_TIMER, 'awlHasChanged', undef); -} - -# }}} - - -# {{{ screen mode - -sub screenFullRedraw { - my ($window) = @_; - if (!ref $window or $window->{'refnum'} == Irssi::active_win->{'refnum'}) { - $actString = []; - eventChanged(); - } -} - -sub screenSize { # from nicklist.pl - $screenResizing = 1; - # fit screen - system 'screen -x '.$ENV{'STY'}.' -X fit'; - # get size - my ($row, $col) = split ' ', `stty size`; - # set screen width - $screenWidth = $col-1; - $screenHeight = $row-1; - - # on some recent systems, "screen -X fit; screen -X width -w 50" doesn't work, needs a sleep in between the 2 commands - # so we wait a second before setting the width - Irssi::timeout_add_once(100, sub { - my ($new_irssi_width) = @_; - $new_irssi_width -= abs(Irssi::settings_get_int(set - 'block'))*$currentColumns - 1; - system 'screen -x '.$ENV{'STY'}.' -X width -w ' . $new_irssi_width; - # and then we wait another second for the resizing, and then redraw. - Irssi::timeout_add_once(10,sub {$screenResizing = 0; screenFullRedraw()}, []); - }, $screenWidth); -} - -sub screenOff { - my ($unloadMode) = @_; - Irssi::signal_remove('gui print text finished' => 'screenFullRedraw'); - Irssi::signal_remove('gui page scrolled' => 'screenFullRedraw'); - Irssi::signal_remove('window changed' => 'screenFullRedraw'); - Irssi::signal_remove('window changed automatic' => 'screenFullRedraw'); - if ($unloadMode) { - Irssi::signal_remove('terminal resized' => 'resizeTerm'); - } - system 'screen -x '.$ENV{'STY'}.' -X fit'; -} - -sub syncColumns { - return if (@$actString == 0); - my $temp = $currentColumns; - #Irssi::print("current columns $temp"); - my $height = $screenHeight - abs(Irssi::settings_get_int(set - 'height_adjust')); - $currentColumns = int(($#$actString-1) / $height) + 1; - #Irssi::print("objects in actstring:".scalar(@$actString).", screen height:". - # $height); - my $currMaxColumns = Irssi::settings_get_int(set 'columns'); - if ($currMaxColumns > 0 and $currentColumns > $currMaxColumns) { - $currentColumns = $currMaxColumns; - } - elsif ($currMaxColumns < 0) { - $currentColumns = abs($currMaxColumns); - } - return if ($temp == $currentColumns); - screenSize(); -} - -#$needRemake = 1; -sub resizeTerm () { - if ($SCREEN_MODE and !$screenResizing) { - $screenResizing = 1; - Irssi::timeout_add_once(10, 'screenSize', undef); - } - Irssi::timeout_add_once(100, 'eventChanged', undef); -} - -# }}} - - -# {{{ settings add - -Irssi::settings_add_str(setc, set 'display_nokey', '[$N]$H$C$S'); -Irssi::settings_add_str(setc, set 'display_key', '[$Q=$N]$H$C$S'); -Irssi::settings_add_str(setc, set 'display_nokey_active', ''); -Irssi::settings_add_str(setc, set 'display_key_active', ''); -Irssi::settings_add_str(setc, set 'separator', "\\ "); -Irssi::settings_add_bool(setc, set 'prefer_name', 0); -Irssi::settings_add_int(setc, set 'hide_data', 0); -Irssi::settings_add_int(setc, set 'maxlines', 9); -Irssi::settings_add_int(setc, set 'columns', 1); -Irssi::settings_add_int(setc, set 'block', 20); -Irssi::settings_add_bool(setc, set 'sbar_maxlength', 0); -Irssi::settings_add_int(setc, set 'height_adjust', 2); -Irssi::settings_add_str(setc, set 'sort', 'refnum'); -Irssi::settings_add_str(setc, set 'placement', 'bottom'); -Irssi::settings_add_int(setc, set 'position', 0); -Irssi::settings_add_bool(setc, set 'all_disable', 0); -Irssi::settings_add_str(setc, set 'automode', 'sbar'); - -# }}} - - -# {{{ init - -sub wlreset { - $actString = []; - $currentLines = 0; # 1; # mhmmmm .. we actually enable one line down there so - # let's try this. - #update_keymap(); - killOldStatus(); - # Register statusbar - #add_statusbar(0); - #Irssi::command('statusbar wl0 enable'); - my $was_screen_mode = $SCREEN_MODE; - if ($SCREEN_MODE = (Irssi::settings_get_str(set 'automode') =~ /screen/i) - and - !$was_screen_mode - ) { - if (!defined $ENV{'STY'}) { - Irssi::print('Screen mode can only be used in GNU screen but no '. - 'screen was found.', MSGLEVEL_CLIENTERROR); - $SCREEN_MODE = undef; - } - else { - Irssi::signal_add_last('gui print text finished' => 'screenFullRedraw'); - Irssi::signal_add_last('gui page scrolled' => 'screenFullRedraw'); - Irssi::signal_add('window changed' => 'screenFullRedraw'); - Irssi::signal_add('window changed automatic' => 'screenFullRedraw'); - } - } - elsif ($was_screen_mode and !$SCREEN_MODE) { - screenOff(); - } - $resetNeeded = ($SCREEN_MODE ? - "\\\n" . Irssi::settings_get_int(set 'block'). - Irssi::settings_get_int(set 'height_adjust') - : "!\n" . Irssi::settings_get_str(set 'placement'). - Irssi::settings_get_int(set 'position')). - Irssi::settings_get_str(set 'automode'); - resizeTerm(); -} - -wlreset(); - -# }}} - - -# {{{ unload/deinit - -my $Unload; -sub unload ($$$) { - $Unload = 1; - # pretend we didn't do anything ASAP - Irssi::timeout_add_once(10, sub { $Unload = undef; }, undef); -} -# last try to catch a sigsegv -Irssi::signal_add_first('gui exit' => sub { $Unload = undef; }); -sub UNLOAD { - # this might well crash Irssi... try /eval /script unload someotherscript ; - # /quit (= SEGFAULT !) - if ($Unload) { - $actString = ['']; # syncLines(); # XXX Irssi crashes when trying to disable - killOldStatus(); # XXX all statusbars ? - if ($SCREEN_MODE) { - screenOff('unload mode'); - } - } -} - -# }}} - - -# {{{ signals - -sub addPrintTextHook { # update on print text - return if $_[0]->{'level'} == 262144 and $_[0]->{'target'} eq '' - and !defined($_[0]->{'server'}); - if (Irssi::settings_get_str(set 'sort') =~ /^[-!]?last_line$/) { - Irssi::timeout_add_once(100, 'eventChanged', undef); - } -} - -#sub _x { my ($x, $y) = @_; ($x, sub { Irssi::print('-->signal '.$x); eval "$y();"; }) } -#sub _x { @_ } -Irssi::signal_add_first( - 'command script unload' => 'unload' -); -Irssi::signal_add_last({ - 'setup changed' => 'eventChanged', - 'print text' => 'addPrintTextHook', - 'terminal resized' => 'resizeTerm', - 'setup reread' => 'wlreset', - 'window hilight' => 'eventChanged', -}); -Irssi::signal_add({ - 'window created' => 'eventChanged', - 'window destroyed' => 'eventChanged', - 'window name changed' => 'eventChanged', - 'window refnum changed' => 'eventChanged', - 'window changed' => 'eventChanged', - 'window changed automatic' => 'eventChanged', -}); - -#Irssi::signal_add('nick mode changed', 'chanactHasChanged'); # relicts - -# }}} - -# {{{ commands - - -sub runsub { - my ($cmd) = @_; - sub { - my ($data, $server, $item) = @_; - Irssi::command_runsub($cmd, $data, $server, $item); - }; -} -Irssi::command_bind( setc() => runsub(setc()) ); -Irssi::command_bind( setc() . ' paste' => runsub(setc() . ' paste') ); -Irssi::command_bind( - setc() . ' paste on' => sub { - return unless $SCREEN_MODE; - my $was_disabled = $DISABLE_SCREEN_TEMP; - $DISABLE_SCREEN_TEMP = 1; - Irssi::print('Paste mode is now ON, '.uc(setc()).' is temporarily '. - 'disabled.'); - if (!$was_disabled) { - $screenResizing = 1; - screenOff(); - } - } -); -Irssi::command_bind( - setc() . ' paste off' => sub { - return unless $SCREEN_MODE; - my $was_disabled = $DISABLE_SCREEN_TEMP; - $DISABLE_SCREEN_TEMP = undef; - Irssi::print('Paste mode is now OFF, '.uc(setc()).' is enabled.'); - if ($was_disabled) { - $SCREEN_MODE = undef; - $screenResizing = 0; - wlreset(); - } - } -); -Irssi::command_bind( - setc() . ' paste toggle' => sub { - if ($DISABLE_SCREEN_TEMP) { - Irssi::command(setc() . ' paste off'); - } - else { - Irssi::command(setc() . ' paste on'); - } - } -); -Irssi::command_bind( - setc() . ' redraw' => sub { - return unless $SCREEN_MODE; - screenFullRedraw(); - } -); - - -# }}} - -# {{{ Algorithm::LCSS module -{ - package Algorithm::Diff; - # Skip to first "=head" line for documentation. - use strict; - - use integer; # see below in _replaceNextLargerWith() for mod to make - # if you don't use this - - # McIlroy-Hunt diff algorithm - # Adapted from the Smalltalk code of Mario I. Wolczko, <[email protected]> - # by Ned Konz, [email protected] - # Updates by Tye McQueen, http://perlmonks.org/?node=tye - - # Create a hash that maps each element of $aCollection to the set of - # positions it occupies in $aCollection, restricted to the elements - # within the range of indexes specified by $start and $end. - # The fourth parameter is a subroutine reference that will be called to - # generate a string to use as a key. - # Additional parameters, if any, will be passed to this subroutine. - # - # my $hashRef = _withPositionsOfInInterval( \@array, $start, $end, $keyGen ); - - sub _withPositionsOfInInterval - { - my $aCollection = shift; # array ref - my $start = shift; - my $end = shift; - my $keyGen = shift; - my %d; - my $index; - for ( $index = $start ; $index <= $end ; $index++ ) - { - my $element = $aCollection->[$index]; - my $key = &$keyGen( $element, @_ ); - if ( exists( $d{$key} ) ) - { - unshift ( @{ $d{$key} }, $index ); - } - else - { - $d{$key} = [$index]; - } - } - return wantarray ? %d : \%d; - } - - # Find the place at which aValue would normally be inserted into the - # array. If that place is already occupied by aValue, do nothing, and - # return undef. If the place does not exist (i.e., it is off the end of - # the array), add it to the end, otherwise replace the element at that - # point with aValue. It is assumed that the array's values are numeric. - # This is where the bulk (75%) of the time is spent in this module, so - # try to make it fast! - - sub _replaceNextLargerWith - { - my ( $array, $aValue, $high ) = @_; - $high ||= $#$array; - - # off the end? - if ( $high == -1 || $aValue > $array->[-1] ) - { - push ( @$array, $aValue ); - return $high + 1; - } - - # binary search for insertion point... - my $low = 0; - my $index; - my $found; - while ( $low <= $high ) - { - $index = ( $high + $low ) / 2; - - # $index = int(( $high + $low ) / 2); # without 'use integer' - $found = $array->[$index]; - - if ( $aValue == $found ) - { - return undef; - } - elsif ( $aValue > $found ) - { - $low = $index + 1; - } - else - { - $high = $index - 1; - } - } - - # now insertion point is in $low. - $array->[$low] = $aValue; # overwrite next larger - return $low; - } - - # This method computes the longest common subsequence in $a and $b. - - # Result is array or ref, whose contents is such that - # $a->[ $i ] == $b->[ $result[ $i ] ] - # foreach $i in ( 0 .. $#result ) if $result[ $i ] is defined. - - # An additional argument may be passed; this is a hash or key generating - # function that should return a string that uniquely identifies the given - # element. It should be the case that if the key is the same, the elements - # will compare the same. If this parameter is undef or missing, the key - # will be the element as a string. - - # By default, comparisons will use "eq" and elements will be turned into keys - # using the default stringizing operator '""'. - - # Additional parameters, if any, will be passed to the key generation - # routine. - - sub _longestCommonSubsequence - { - my $a = shift; # array ref or hash ref - my $b = shift; # array ref or hash ref - my $counting = shift; # scalar - my $keyGen = shift; # code ref - my $compare; # code ref - - if ( ref($a) eq 'HASH' ) - { # prepared hash must be in $b - my $tmp = $b; - $b = $a; - $a = $tmp; - } - - # Check for bogus (non-ref) argument values - if ( !ref($a) || !ref($b) ) - { - my @callerInfo = caller(1); - die 'error: must pass array or hash references to ' . $callerInfo[3]; - } - - # set up code refs - # Note that these are optimized. - if ( !defined($keyGen) ) # optimize for strings - { - $keyGen = sub { $_[0] }; - $compare = sub { my ( $a, $b ) = @_; $a eq $b }; - } - else - { - $compare = sub { - my $a = shift; - my $b = shift; - &$keyGen( $a, @_ ) eq &$keyGen( $b, @_ ); - }; - } - - my ( $aStart, $aFinish, $matchVector ) = ( 0, $#$a, [] ); - my ( $prunedCount, $bMatches ) = ( 0, {} ); - - if ( ref($b) eq 'HASH' ) # was $bMatches prepared for us? - { - $bMatches = $b; - } - else - { - my ( $bStart, $bFinish ) = ( 0, $#$b ); - - # First we prune off any common elements at the beginning - while ( $aStart <= $aFinish - and $bStart <= $bFinish - and &$compare( $a->[$aStart], $b->[$bStart], @_ ) ) - { - $matchVector->[ $aStart++ ] = $bStart++; - $prunedCount++; - } - - # now the end - while ( $aStart <= $aFinish - and $bStart <= $bFinish - and &$compare( $a->[$aFinish], $b->[$bFinish], @_ ) ) - { - $matchVector->[ $aFinish-- ] = $bFinish--; - $prunedCount++; - } - - # Now compute the equivalence classes of positions of elements - $bMatches = - _withPositionsOfInInterval( $b, $bStart, $bFinish, $keyGen, @_ ); - } - my $thresh = []; - my $links = []; - - my ( $i, $ai, $j, $k ); - for ( $i = $aStart ; $i <= $aFinish ; $i++ ) - { - $ai = &$keyGen( $a->[$i], @_ ); - if ( exists( $bMatches->{$ai} ) ) - { - $k = 0; - for $j ( @{ $bMatches->{$ai} } ) - { - - # optimization: most of the time this will be true - if ( $k and $thresh->[$k] > $j and $thresh->[ $k - 1 ] < $j ) - { - $thresh->[$k] = $j; - } - else - { - $k = _replaceNextLargerWith( $thresh, $j, $k ); - } - - # oddly, it's faster to always test this (CPU cache?). - if ( defined($k) ) - { - $links->[$k] = - [ ( $k ? $links->[ $k - 1 ] : undef ), $i, $j ]; - } - } - } - } - - if (@$thresh) - { - return $prunedCount + @$thresh if $counting; - for ( my $link = $links->[$#$thresh] ; $link ; $link = $link->[0] ) - { - $matchVector->[ $link->[1] ] = $link->[2]; - } - } - elsif ($counting) - { - return $prunedCount; - } - - return wantarray ? @$matchVector : $matchVector; - } - - sub traverse_sequences - { - my $a = shift; # array ref - my $b = shift; # array ref - my $callbacks = shift || {}; - my $keyGen = shift; - my $matchCallback = $callbacks->{'MATCH'} || sub { }; - my $discardACallback = $callbacks->{'DISCARD_A'} || sub { }; - my $finishedACallback = $callbacks->{'A_FINISHED'}; - my $discardBCallback = $callbacks->{'DISCARD_B'} || sub { }; - my $finishedBCallback = $callbacks->{'B_FINISHED'}; - my $matchVector = _longestCommonSubsequence( $a, $b, 0, $keyGen, @_ ); - - # Process all the lines in @$matchVector - my $lastA = $#$a; - my $lastB = $#$b; - my $bi = 0; - my $ai; - - for ( $ai = 0 ; $ai <= $#$matchVector ; $ai++ ) - { - my $bLine = $matchVector->[$ai]; - if ( defined($bLine) ) # matched - { - &$discardBCallback( $ai, $bi++, @_ ) while $bi < $bLine; - &$matchCallback( $ai, $bi++, @_ ); - } - else - { - &$discardACallback( $ai, $bi, @_ ); - } - } - - # The last entry (if any) processed was a match. - # $ai and $bi point just past the last matching lines in their sequences. - - while ( $ai <= $lastA or $bi <= $lastB ) - { - - # last A? - if ( $ai == $lastA + 1 and $bi <= $lastB ) - { - if ( defined($finishedACallback) ) - { - &$finishedACallback( $lastA, @_ ); - $finishedACallback = undef; - } - else - { - &$discardBCallback( $ai, $bi++, @_ ) while $bi <= $lastB; - } - } - - # last B? - if ( $bi == $lastB + 1 and $ai <= $lastA ) - { - if ( defined($finishedBCallback) ) - { - &$finishedBCallback( $lastB, @_ ); - $finishedBCallback = undef; - } - else - { - &$discardACallback( $ai++, $bi, @_ ) while $ai <= $lastA; - } - } - - &$discardACallback( $ai++, $bi, @_ ) if $ai <= $lastA; - &$discardBCallback( $ai, $bi++, @_ ) if $bi <= $lastB; - } - - return 1; - } - - sub traverse_balanced - { - my $a = shift; # array ref - my $b = shift; # array ref - my $callbacks = shift || {}; - my $keyGen = shift; - my $matchCallback = $callbacks->{'MATCH'} || sub { }; - my $discardACallback = $callbacks->{'DISCARD_A'} || sub { }; - my $discardBCallback = $callbacks->{'DISCARD_B'} || sub { }; - my $changeCallback = $callbacks->{'CHANGE'}; - my $matchVector = _longestCommonSubsequence( $a, $b, 0, $keyGen, @_ ); - - # Process all the lines in match vector - my $lastA = $#$a; - my $lastB = $#$b; - my $bi = 0; - my $ai = 0; - my $ma = -1; - my $mb; - - while (1) - { - - # Find next match indices $ma and $mb - do { - $ma++; - } while( - $ma <= $#$matchVector - && !defined $matchVector->[$ma] - ); - - last if $ma > $#$matchVector; # end of matchVector? - $mb = $matchVector->[$ma]; - - # Proceed with discard a/b or change events until - # next match - while ( $ai < $ma || $bi < $mb ) - { - - if ( $ai < $ma && $bi < $mb ) - { - - # Change - if ( defined $changeCallback ) - { - &$changeCallback( $ai++, $bi++, @_ ); - } - else - { - &$discardACallback( $ai++, $bi, @_ ); - &$discardBCallback( $ai, $bi++, @_ ); - } - } - elsif ( $ai < $ma ) - { - &$discardACallback( $ai++, $bi, @_ ); - } - else - { - - # $bi < $mb - &$discardBCallback( $ai, $bi++, @_ ); - } - } - - # Match - &$matchCallback( $ai++, $bi++, @_ ); - } - - while ( $ai <= $lastA || $bi <= $lastB ) - { - if ( $ai <= $lastA && $bi <= $lastB ) - { - - # Change - if ( defined $changeCallback ) - { - &$changeCallback( $ai++, $bi++, @_ ); - } - else - { - &$discardACallback( $ai++, $bi, @_ ); - &$discardBCallback( $ai, $bi++, @_ ); - } - } - elsif ( $ai <= $lastA ) - { - &$discardACallback( $ai++, $bi, @_ ); - } - else - { - - # $bi <= $lastB - &$discardBCallback( $ai, $bi++, @_ ); - } - } - - return 1; - } - - sub prepare - { - my $a = shift; # array ref - my $keyGen = shift; # code ref - - # set up code ref - $keyGen = sub { $_[0] } unless defined($keyGen); - - return scalar _withPositionsOfInInterval( $a, 0, $#$a, $keyGen, @_ ); - } - - sub LCS - { - my $a = shift; # array ref - my $b = shift; # array ref or hash ref - my $matchVector = _longestCommonSubsequence( $a, $b, 0, @_ ); - my @retval; - my $i; - for ( $i = 0 ; $i <= $#$matchVector ; $i++ ) - { - if ( defined( $matchVector->[$i] ) ) - { - push ( @retval, $a->[$i] ); - } - } - return wantarray ? @retval : \@retval; - } - - sub LCS_length - { - my $a = shift; # array ref - my $b = shift; # array ref or hash ref - return _longestCommonSubsequence( $a, $b, 1, @_ ); - } - - sub LCSidx - { - my $a= shift @_; - my $b= shift @_; - my $match= _longestCommonSubsequence( $a, $b, 0, @_ ); - my @am= grep defined $match->[$_], 0..$#$match; - my @bm= @{$match}[@am]; - return \@am, \@bm; - } - - sub compact_diff - { - my $a= shift @_; - my $b= shift @_; - my( $am, $bm )= LCSidx( $a, $b, @_ ); - my @cdiff; - my( $ai, $bi )= ( 0, 0 ); - push @cdiff, $ai, $bi; - while( 1 ) { - while( @$am && $ai == $am->[0] && $bi == $bm->[0] ) { - shift @$am; - shift @$bm; - ++$ai, ++$bi; - } - push @cdiff, $ai, $bi; - last if ! @$am; - $ai = $am->[0]; - $bi = $bm->[0]; - push @cdiff, $ai, $bi; - } - push @cdiff, 0+@$a, 0+@$b - if $ai < @$a || $bi < @$b; - return wantarray ? @cdiff : \@cdiff; - } - - sub diff - { - my $a = shift; # array ref - my $b = shift; # array ref - my $retval = []; - my $hunk = []; - my $discard = sub { - push @$hunk, [ '-', $_[0], $a->[ $_[0] ] ]; - }; - my $add = sub { - push @$hunk, [ '+', $_[1], $b->[ $_[1] ] ]; - }; - my $match = sub { - push @$retval, $hunk - if 0 < @$hunk; - $hunk = [] - }; - traverse_sequences( $a, $b, - { MATCH => $match, DISCARD_A => $discard, DISCARD_B => $add }, @_ ); - &$match(); - return wantarray ? @$retval : $retval; - } - - sub sdiff - { - my $a = shift; # array ref - my $b = shift; # array ref - my $retval = []; - my $discard = sub { push ( @$retval, [ '-', $a->[ $_[0] ], "" ] ) }; - my $add = sub { push ( @$retval, [ '+', "", $b->[ $_[1] ] ] ) }; - my $change = sub { - push ( @$retval, [ 'c', $a->[ $_[0] ], $b->[ $_[1] ] ] ); - }; - my $match = sub { - push ( @$retval, [ 'u', $a->[ $_[0] ], $b->[ $_[1] ] ] ); - }; - traverse_balanced( - $a, - $b, - { - MATCH => $match, - DISCARD_A => $discard, - DISCARD_B => $add, - CHANGE => $change, - }, - @_ - ); - return wantarray ? @$retval : $retval; - } - - ######################################## - my $Root= __PACKAGE__; - package Algorithm::Diff::_impl; - use strict; - - sub _Idx() { 0 } # $me->[_Idx]: Ref to array of hunk indices - # 1 # $me->[1]: Ref to first sequence - # 2 # $me->[2]: Ref to second sequence - sub _End() { 3 } # $me->[_End]: Diff between forward and reverse pos - sub _Same() { 4 } # $me->[_Same]: 1 if pos 1 contains unchanged items - sub _Base() { 5 } # $me->[_Base]: Added to range's min and max - sub _Pos() { 6 } # $me->[_Pos]: Which hunk is currently selected - sub _Off() { 7 } # $me->[_Off]: Offset into _Idx for current position - sub _Min() { -2 } # Added to _Off to get min instead of max+1 - - sub Die - { - require Carp; - Carp::confess( @_ ); - } - - sub _ChkPos - { - my( $me )= @_; - return if $me->[_Pos]; - my $meth= ( caller(1) )[3]; - Die( "Called $meth on 'reset' object" ); - } - - sub _ChkSeq - { - my( $me, $seq )= @_; - return $seq + $me->[_Off] - if 1 == $seq || 2 == $seq; - my $meth= ( caller(1) )[3]; - Die( "$meth: Invalid sequence number ($seq); must be 1 or 2" ); - } - - sub getObjPkg - { - my( $us )= @_; - return ref $us if ref $us; - return $us . "::_obj"; - } - - sub new - { - my( $us, $seq1, $seq2, $opts ) = @_; - my @args; - for( $opts->{keyGen} ) { - push @args, $_ if $_; - } - for( $opts->{keyGenArgs} ) { - push @args, @$_ if $_; - } - my $cdif= Algorithm::Diff::compact_diff( $seq1, $seq2, @args ); - my $same= 1; - if( 0 == $cdif->[2] && 0 == $cdif->[3] ) { - $same= 0; - splice @$cdif, 0, 2; - } - my @obj= ( $cdif, $seq1, $seq2 ); - $obj[_End] = (1+@$cdif)/2; - $obj[_Same] = $same; - $obj[_Base] = 0; - my $me = bless \@obj, $us->getObjPkg(); - $me->Reset( 0 ); - return $me; - } - - sub Reset - { - my( $me, $pos )= @_; - $pos= int( $pos || 0 ); - $pos += $me->[_End] - if $pos < 0; - $pos= 0 - if $pos < 0 || $me->[_End] <= $pos; - $me->[_Pos]= $pos || !1; - $me->[_Off]= 2*$pos - 1; - return $me; - } - - sub Base - { - my( $me, $base )= @_; - my $oldBase= $me->[_Base]; - $me->[_Base]= 0+$base if defined $base; - return $oldBase; - } - - sub Copy - { - my( $me, $pos, $base )= @_; - my @obj= @$me; - my $you= bless \@obj, ref($me); - $you->Reset( $pos ) if defined $pos; - $you->Base( $base ); - return $you; - } - - sub Next { - my( $me, $steps )= @_; - $steps= 1 if ! defined $steps; - if( $steps ) { - my $pos= $me->[_Pos]; - my $new= $pos + $steps; - $new= 0 if $pos && $new < 0; - $me->Reset( $new ) - } - return $me->[_Pos]; - } - - sub Prev { - my( $me, $steps )= @_; - $steps= 1 if ! defined $steps; - my $pos= $me->Next(-$steps); - $pos -= $me->[_End] if $pos; - return $pos; - } - - sub Diff { - my( $me )= @_; - $me->_ChkPos(); - return 0 if $me->[_Same] == ( 1 & $me->[_Pos] ); - my $ret= 0; - my $off= $me->[_Off]; - for my $seq ( 1, 2 ) { - $ret |= $seq - if $me->[_Idx][ $off + $seq + _Min ] - < $me->[_Idx][ $off + $seq ]; - } - return $ret; - } - - sub Min { - my( $me, $seq, $base )= @_; - $me->_ChkPos(); - my $off= $me->_ChkSeq($seq); - $base= $me->[_Base] if !defined $base; - return $base + $me->[_Idx][ $off + _Min ]; - } - - sub Max { - my( $me, $seq, $base )= @_; - $me->_ChkPos(); - my $off= $me->_ChkSeq($seq); - $base= $me->[_Base] if !defined $base; - return $base + $me->[_Idx][ $off ] -1; - } - - sub Range { - my( $me, $seq, $base )= @_; - $me->_ChkPos(); - my $off = $me->_ChkSeq($seq); - if( !wantarray ) { - return $me->[_Idx][ $off ] - - $me->[_Idx][ $off + _Min ]; - } - $base= $me->[_Base] if !defined $base; - return ( $base + $me->[_Idx][ $off + _Min ] ) - .. ( $base + $me->[_Idx][ $off ] - 1 ); - } - - sub Items { - my( $me, $seq )= @_; - $me->_ChkPos(); - my $off = $me->_ChkSeq($seq); - if( !wantarray ) { - return $me->[_Idx][ $off ] - - $me->[_Idx][ $off + _Min ]; - } - return - @{$me->[$seq]}[ - $me->[_Idx][ $off + _Min ] - .. ( $me->[_Idx][ $off ] - 1 ) - ]; - } - - sub Same { - my( $me )= @_; - $me->_ChkPos(); - return wantarray ? () : 0 - if $me->[_Same] != ( 1 & $me->[_Pos] ); - return $me->Items(1); - } - - my %getName; - %getName= ( - same => \&Same, - diff => \&Diff, - base => \&Base, - min => \&Min, - max => \&Max, - range=> \&Range, - items=> \&Items, # same thing - ); - - sub Get - { - my $me= shift @_; - $me->_ChkPos(); - my @value; - for my $arg ( @_ ) { - for my $word ( split ' ', $arg ) { - my $meth; - if( $word !~ /^(-?\d+)?([a-zA-Z]+)([12])?$/ - || not $meth= $getName{ lc $2 } - ) { - Die( $Root, ", Get: Invalid request ($word)" ); - } - my( $base, $name, $seq )= ( $1, $2, $3 ); - push @value, scalar( - 4 == length($name) - ? $meth->( $me ) - : $meth->( $me, $seq, $base ) - ); - } - } - if( wantarray ) { - return @value; - } elsif( 1 == @value ) { - return $value[0]; - } - Die( 0+@value, " values requested from ", - $Root, "'s Get in scalar context" ); - } - - - my $Obj= getObjPkg($Root); - no strict 'refs'; - - for my $meth ( qw( new getObjPkg ) ) { - *{$Root."::".$meth} = \&{$meth}; - *{$Obj ."::".$meth} = \&{$meth}; - } - for my $meth ( qw( - Next Prev Reset Copy Base Diff - Same Items Range Min Max Get - _ChkPos _ChkSeq - ) ) { - *{$Obj."::".$meth} = \&{$meth}; - } - -}; -{ - package Algorithm::LCSS; - - use strict; - { - no strict 'refs'; - *traverse_sequences = \&Algorithm::Diff::traverse_sequences; - } - - sub _tokenize { [split //, $_[0]] } - - sub CSS { - my $is_array = ref $_[0] eq 'ARRAY' ? 1 : 0; - my ( $seq1, $seq2, @match, $from_match ); - my $i = 0; - if ( $is_array ) { - $seq1 = $_[0]; - $seq2 = $_[1]; - traverse_sequences( $seq1, $seq2, { - MATCH => sub { push @{$match[$i]}, $seq1->[$_[0]]; $from_match = 1 }, - DISCARD_A => sub { do{$i++; $from_match = 0} if $from_match }, - DISCARD_B => sub { do{$i++; $from_match = 0} if $from_match }, - }); - } - else { - $seq1 = _tokenize($_[0]); - $seq2 = _tokenize($_[1]); - traverse_sequences( $seq1, $seq2, { - MATCH => sub { $match[$i] .= $seq1->[$_[0]]; $from_match = 1 }, - DISCARD_A => sub { do{$i++; $from_match = 0} if $from_match }, - DISCARD_B => sub { do{$i++; $from_match = 0} if $from_match }, - }); - } - return \@match; - } - - sub CSS_Sorted { - my $match = CSS(@_); - if ( ref $_[0] eq 'ARRAY' ) { - @$match = map{$_->[0]}sort{$b->[1]<=>$a->[1]}map{[$_,scalar(@$_)]}@$match - } - else { - @$match = map{$_->[0]}sort{$b->[1]<=>$a->[1]}map{[$_,length($_)]}@$match - } - return $match; - } - - sub LCSS { - my $is_array = ref $_[0] eq 'ARRAY' ? 1 : 0; - my $css = CSS(@_); - my $index; - my $length = 0; - if ( $is_array ) { - for( my $i = 0; $i < @$css; $i++ ) { - next unless @{$css->[$i]}>$length; - $index = $i; - $length = @{$css->[$i]}; - } - } - else { - for( my $i = 0; $i < @$css; $i++ ) { - next unless length($css->[$i])>$length; - $index = $i; - $length = length($css->[$i]); - } - } - return $css->[$index]; - } - -}; -# }}} -#{{{ Class::Classless module -{ - package Class::Classless; - use strict; - use vars qw(@ISA); - use Carp; - - @ISA = (); - - ########################################################################### - - @Class::Classless::X::ISA = (); - - ########################################################################### - ########################################################################### - - sub Class::Classless::X::AUTOLOAD { - # This's the big dispatcher. - - my $it = shift @_; - my $m = ($Class::Classless::X::AUTOLOAD =~ m/([^:]+)$/s ) - ? $1 : $Class::Classless::X::AUTOLOAD; - - croak "Can't call Class::Classless methods (like $m) without an object" - unless ref $it; # sanity, basically. - - my $prevstate; - $prevstate = ${shift @_} - if scalar(@_) && defined($_[0]) && - ref($_[0]) eq 'Class::Classless::CALLSTATE::SHIMMY' - ; # A shim! we were called via $callstate->NEXT - - my $no_fail = $prevstate ? $prevstate->[3] : undef; - my $i = $prevstate ? ($prevstate->[1] + 1) : 0; - # where to start scanning - my $lineage; - - # Get the linearization of the ISA tree - if($prevstate) { - $lineage = $prevstate->[2]; - } elsif(defined $it->{'ISA_CACHE'} and ref $it->{'ISA_CACHE'} ){ - $lineage = $it->{'ISA_CACHE'}; - } else { - $lineage = [ &Class::Classless::X::ISA_TREE($it) ]; - } - - # Was: - #my @lineage = - # $prevstate ? @{$prevstate->[2]} - # : &Class::Classless::X::ISA_TREE($it); - # # Get the linearization of the ISA tree - # # ISA-memoization happens in the ISA_TREE function. - - for(; $i < @$lineage; ++$i) { - - if( !defined($no_fail) and exists($lineage->[$i]{'NO_FAIL'}) ) { - $no_fail = ($lineage->[$i]{'NO_FAIL'} || 0); - # so the first NO_FAIL sets it - } - - if( ref($lineage->[$i]{'METHODS'} || 0) # sanity - && exists($lineage->[$i]{'METHODS'}{$m}) - ){ - # We found what we were after. Now see what to do with it. - my $v = $lineage->[$i]{'METHODS'}{$m}; - return $v unless defined $v and ref $v; - - if(ref($v) eq 'CODE') { # normal case, I expect! - # Used to have copying of the arglist here. - # But it was apparently useless, so I deleted it - unshift @_, - $it, # $_[0] -- target object - # a NEW callstate - bless([$m, $i, $lineage, $no_fail, $prevstate ? 1 : 0], - 'Class::Classless::CALLSTATE' - ), # $_[1] -- the callstate - ; - goto &{ $v }; # yes, magic goto! bimskalabim! - } - return @$v if ref($v) eq '_deref_array'; - return $$v if ref($v) eq '_deref_scalar'; - return $v; # fallthru - } - } - - if($m eq 'DESTROY') { # mitigate DESTROY-lookup failure at global destruction - # should be impossible - } else { - if($no_fail || 0) { - return; - } - croak "Can't find ", $prevstate ? 'NEXT method' : 'method', - " $m in ", $it->{'NAME'} || $it, - " or any ancestors\n"; - } - } - - ########################################################################### - ########################################################################### - - sub Class::Classless::X::DESTROY { - # noop - } - - ########################################################################### - sub Class::Classless::X::ISA_TREE { - # The linearizer! - # Returns the search path for $_[0], starting with $_[0] - # Possibly memoized. - - # I stopped being able to understand this algorithm about five - # minutes after I wrote it. - use strict; - - my $set_cache = 0; # flag to set the cache on the way out - - if(exists($_[0]{'ISA_CACHE'})) { - return @{$_[0]{'ISA_CACHE'}} - if defined $_[0]{'ISA_CACHE'} - and ref $_[0]{'ISA_CACHE'}; - - # Otherwise, if exists but is not a ref, it's a signal that it should - # be replaced at the earliest, with a listref - $set_cache = 1; - } - - my $has_mi = 0; # set to 0 on the first node we see with 2 parents! - # First, just figure out what's in the tree. - my %last_child = ($_[0] => 1); # as if already seen - - # if $last_child{$x} == $y, that means: - # 1) incidentally, we've passed the node $x before. - # 2) $x is the last child of $y, - # so that means that $y can be pushed to the stack only after - # we've pushed $x to the stack. - - my @tree_nodes; - { - my $current; - my @in_stack = ($_[0]); - while(@in_stack) { - next unless - defined($current = shift @in_stack) - && ref($current) # sanity - && ref($current->{'PARENTS'} || 0) # sanity - ; - - push @tree_nodes, $current; - - $has_mi = 1 if @{$current->{'PARENTS'}} > 1; - unshift - @in_stack, - map { - if(exists $last_child{$_}) { # seen before! - $last_child{$_} = $current; - (); # seen -- don't re-explore - } else { # first time seen - $last_child{$_} = $current; - $_; # first time seen -- explore now - } - } - @{$current->{'PARENTS'}} - ; - } - - # If there was no MI, then that first scan was sufficient. - unless($has_mi) { - $_[0]{'ISA_CACHE'} = \@tree_nodes if $set_cache; - return @tree_nodes; - } - - # Otherwise, toss this list and rescan, consulting %last_child - } - - # $last_child{$parent} holds the last (or only) child of $parent - # in this tree. When walking the tree this time, only that - # child is authorized to put its parent on the @in_stack. - # And that's the only way a node can get added to @in_stack, - # except for $_[0] (the start node) being there at the beginning. - - # Now, walk again, but this time exploring parents the LAST - # time seen in the tree, not the first. - - my @out; - { - my $current; - my @in_stack = ($_[0]); - while(@in_stack) { - next unless defined($current = shift @in_stack) && ref($current); - push @out, $current; # finally. - unshift - @in_stack, - grep( - ( - defined($_) # sanity - && ref($_) # sanity - && $last_child{$_} eq $current, - ), - # I'm lastborn (or onlyborn) of this parent - # so it's OK to explore now - @{$current->{'PARENTS'}} - ) - if ref($current->{'PARENTS'} || 0) # sanity - ; - } - - unless(scalar(@out) == scalar(keys(%last_child))) { - # the counts should be equal - my %good_ones; - @good_ones{@out} = (); - croak - "ISA tree for " . - ($_[0]{'NAME'} || $_[0]) . - " is apparently cyclic, probably involving the nodes " . - nodelist( grep { ref($_) && !exists $good_ones{$_} } - values(%last_child) ) - . "\n"; - } - } - #print "Contents of out: ", nodelist(@out), "\n"; - - $_[0]{'ISA_CACHE'} = \@out if $set_cache; - return @out; - } - - ########################################################################### - - sub Class::Classless::X::can { # NOT like UNIVERSAL::can ... - # return 1 if $it is capable of the method given -- otherwise 0 - my($it, $m) = @_[0,1]; - return undef unless ref $it; - - croak "undef is not a valid method name" unless defined($m); - croak "null-string is not a valid method name" unless length($m); - - foreach my $o (&Class::Classless::X::ISA_TREE($it)) { - return 1 - if ref($o->{'METHODS'} || 0) # sanity - && exists $o->{'METHODS'}{$m}; - } - - return 0; - } - - - ########################################################################### - - sub Class::Classless::X::isa { # Like UNIVERSAL::isa - # Returns true for $X->isa($Y) iff $Y is $X or is an ancestor of $X. - - return unless ref($_[0]) && ref($_[1]); - return scalar(grep {$_ eq $_[1]} &Class::Classless::X::ISA_TREE($_[0])); - } - - ########################################################################### - - sub nodelist { join ', ', map { "" . ($_->{'NAME'} || $_) . ""} @_ } - - ########################################################################### - ########################################################################### - ########################################################################### - # Methods for the CALLSTATE class. - # Basically, CALLSTATE objects represent the state of the dispatcher, - # frozen at the moment when the method call was dispatched to the - # appropriate sub. - # In the grand scheme of things, this needn't be a class -- I could - # have just made the callstate data-object be a hash with documented - # keys, or a closure that responded to only certain parameters, - # etc. But I like it this way. And I like being able to say simply - # $cs->NEXT - # Yes, these are a bit cryptically written, but it's behoovy for - # them to be very very efficient. - - @Class::Classless::ISA = (); - sub Class::Classless::CALLSTATE::found_name { $_[0][0] } - # the method name called and found - sub Class::Classless::CALLSTATE::found_depth { $_[0][1] } - # my depth in the lineage - sub Class::Classless::CALLSTATE::lineage { @{$_[0][2]} } - # my lineage - sub Class::Classless::CALLSTATE::target { $_[0][2][ 0 ] } - # the object that's the target -- same as $_[0] for the method called - sub Class::Classless::CALLSTATE::home { $_[0][2][ $_[0][1] ] } - # the object I was found in - sub Class::Classless::CALLSTATE::sub_found { - $_[0][2][ $_[0][1] ]{'METHODS'}{ $_[0][0] } - } # the routine called - - sub Class::Classless::CALLSTATE::no_fail { $_[0][3] } - sub Class::Classless::CALLSTATE::set_no_fail_true { $_[0][3] = 1 } - sub Class::Classless::CALLSTATE::set_fail_false { $_[0][3] = 0 } - sub Class::Classless::CALLSTATE::set_fail_undef { $_[0][3] = undef } - - sub Class::Classless::CALLSTATE::via_next { $_[0][4] } - - sub Class::Classless::CALLSTATE::NEXT { - #croak "NEXT needs at least one argument: \$cs->NEXT('method'...)" - # unless @_ > 1; - # no longer true. - my $cs = shift @_; - my $m = shift @_; # which may be (or come out) undef... - $m = $cs->[0] unless defined $m; # the method name called and found - - ($cs->[2][0])->$m( - bless( \$cs, 'Class::Classless::CALLSTATE::SHIMMY' ), - @_ - ); - } - - ########################################################################### -}; -#}}} - -############### -### -# -# {{{ *** C h a n g e l o g *** -# -# 0.6ca -# - add screen support (from nicklist.pl) -# - rename to adv_windowlist.pl (advanced window list) since it isn't just a -# window list status bar (wlstat) anymore -# - names can now have a max length and window names can be used -# - fixed a bug with block display in screen mode and statusbar mode -# - added space handling to ir_fe and removed it again -# - now handling formats on my own -# - added warning about missing sb_act_none abstract leading to -# - display*active settings -# - added warning about the bug in awl_display_(no)key_active settings -# -# 0.5d -# - add setting to also hide the last statusbar if empty (awl_all_disable) -# - reverted to old utf8 code to also calculate broken utf8 length correctly -# - simplified dealing with statusbars in wlreset -# - added a little tweak for the renamed term_type somewhere after Irssi 0.8.9 -# - fixed bug in handling channel #$$ -# - typo on line 200 spotted by f0rked -# - reset background colour at the beginning of an entry -# -# 0.4d -# - fixed order of disabling statusbars -# - several attempts at special chars, without any real success -# and much more weird new bugs caused by this -# - setting to specify sort order -# - reduced timeout values -# - added awl_hide_data for Geert Hauwaerts ( [email protected] ) :) -# - make it so the dynamic sub is actually deleted -# - fix a bug with removing of the last separator -# - take into consideration parse_special -# -# 0.3b -# - automatically kill old statusbars -# - reset on /reload -# - position/placement settings -# -# 0.2 -# - automated retrieval of key bindings (thanks grep.pl authors) -# - improved removing of statusbars -# - got rid of status chop -# -# 0.1 -# - rewritten to suit my needs -# - based on chanact 0.5.5 -# }}} -# vim: se fdm=marker tw=80 :
--- a/irssi/scripts/autorun/adv_windowlist.pl Wed Nov 19 19:08:21 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -../adv_windowlist.pl \ No newline at end of file
--- a/irssi/scripts/autorun/cap_sasl.pl Wed Nov 19 19:08:21 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -../cap_sasl.pl \ No newline at end of file
--- a/irssi/scripts/autorun/hilightwin.pl Wed Nov 19 19:08:21 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -../hilightwin.pl \ No newline at end of file
--- a/irssi/scripts/autorun/nicklist.pl Wed Nov 19 19:08:21 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -../nicklist.pl \ No newline at end of file
--- a/irssi/scripts/autorun/nm.pl Wed Nov 19 19:08:21 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -../nm.pl \ No newline at end of file
--- a/irssi/scripts/autorun/queryresume.pl Wed Nov 19 19:08:21 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -../queryresume.pl \ No newline at end of file
--- a/irssi/scripts/autorun/trackbar.pl Wed Nov 19 19:08:21 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -../trackbar.pl \ No newline at end of file
--- a/irssi/scripts/bitlbee_typing_notice.pl Wed Nov 19 19:08:21 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,319 +0,0 @@ -# INSTALLATION -# [&bitlbee] set typing_notice true -# <@root> typing_notice = `true' -# AND -# /statusbar window add typing_notice -# -# SETTINGS -# [bitlbee] -# bitlbee_send_typing = ON -# -> send typing messages to buddies -# bitlbee_typing_allwin = OFF -# -> show typing notifications in all windows -# -# -# Changelog: -# -# 2010-08-09 (version 1.7.1) -# * Multiple control channels supported by checking chanmodes -# -# 2010-07-27 (version 1.7) -# * Using new server detection for latest BitlBee support -# -# 2010-07-26 (version 1.6.3) -# * Removed checking if nicks exists in &bitlbee channel, this because BitlBee -# can be used without control channel from this date -# -# 2007-03-03 (version 1.6.2) -# * Fix: timers weren't deleted correctly. This resulted in huge mem usage. -# -# 2006-11-02 (version 1.6.1) -# * Sending typing works again. -# -# 2006-10-27 (version 1.6) -# * 'channel sync' re-implemented. -# * bitlbee_send_typing was a string setting, It's a boolean now, like it should. -# -# 2006-10-24 (version 1.5) -# * Sending notices to online users only. ( removed this again at 2010-07-26, see above ) -# * Using the new get_channel function; -# -# 2005-12-15 (version 1.42): -# * Fixed small bug with typing notices disappearing under certain circumstances -# in channels -# * Fixed bug that caused outgoing notifications not to work -# * root cares not about our typing status. -# -# 2005-12-04 (version 1.41): -# * Implemented stale states in statusbar (shows "(stale)" for OSCAR connections) -# * Introduced bitlbee_typing_allwin (default OFF). Set this to ON to make -# typing notifications visible in all windows. -# -# 2005-12-03 (version 1.4): -# * Major code cleanups and rewrites for bitlbee 1.0 with the updated typing -# scheme. TYPING 0, TYPING 1, and TYPING 2 are now supported from the server. -# * Stale states (where user has typed in text but has stopped typing) are now -# recognized. -# * Bug where user thinks you are still typing if you close the window after -# typing something and then erasing it quickly.. fixed. -# * If a user signs off while they are still typing, the notification is removed -# This update by Matt "f0rked" Sparks -# -# 2005-08-26: -# Some fixes for AIM, Thanks to Dracula. -# -# 2005-08-16: -# AIM supported, for sending notices, using CTCP TYPING 0. (Use the AIM patch from Hanji http://get.bitlbee.org/patches/) -# -# 2004-10-31: -# Sends typing notice to the bitlbee server when typing a message in irssi. bitlbee > 0.92 -# -# 2004-06-11: -# shows [typing: ] in &bitlbee with multiple users. -# -use strict; -use Irssi::TextUI; -use Data::Dumper; - -use vars qw($VERSION %IRSSI); - -$VERSION = '1.7.1'; -%IRSSI = ( - authors => 'Tijmen "timing" Ruizendaal, Matt "f0rked" Sparks', - contact => '[email protected], [email protected]', - name => 'BitlBee_typing_notice', - description => '1. Adds an item to the status bar wich shows [typing] when someone is typing a message on the supported IM-networks 2. Sends typing notices to the supported IM networks (the other way arround). (For bitlbee 3.0+)', - license => 'GPLv2', - url => 'http://the-timing.nl/stuff/irssi-bitlbee, http://f0rked.com', - changed => '2010-08-09', -); - -my $bitlbee_server; # server object -my @control_channels; # mostly: &bitlbee, &facebook etc. -init(); - -sub init { # if script is loaded after connect - my @servers = Irssi::servers(); - foreach my $server(@servers) { - if( $server->isupport('NETWORK') eq 'BitlBee' ){ - $bitlbee_server = $server; - my @channels = $server->channels(); - foreach my $channel(@channels) { - if( $channel->{mode} =~ /C/ ){ - push @control_channels, $channel->{name} unless (grep $_ eq $channel->{name}, @control_channels); - } - } - } - } -} -# if connect after script is loaded -Irssi::signal_add_last('event 005' => sub { - my( $server ) = @_; - if( $server->isupport('NETWORK') eq 'BitlBee' ){ - $bitlbee_server = $server; - } -}); -# if new control channel is synced after script is loaded -Irssi::signal_add_last('channel sync' => sub { - my( $channel ) = @_; - if( $channel->{mode} =~ /C/ && $channel->{server}->{tag} eq $bitlbee_server->{tag} ){ - push @control_channels, $channel->{name} unless (grep $_ eq $channel->{name}, @control_channels); - } -}); - -# How often to check if we are typing, or on msn, -# how long to keep the typing notice up, or check -# if the other user is still typing... -my $KEEP_TYPING_TIMEOUT = 1; -my $STOP_TYPING_TIMEOUT = 7; - -my %timer_tag; - -my %typing; -my %tag; -my $line; -my %out_typing; -my $lastkey; -my $keylog_active = 1; -my $command_char = Irssi::settings_get_str('cmdchars'); # mostly: / -my $to_char = Irssi::settings_get_str("completion_char"); # mostly: : - -sub event_ctcp_msg { - my ($server, $msg, $from, $address) = @_; - return if $server->{tag} ne $bitlbee_server->{tag}; - if ( my($type) = $msg =~ "TYPING ([0-9])" ){ - Irssi::signal_stop(); - if( $type == 0 ){ - unset_typing($from); - } elsif( $type == 1 ){ - $typing{$from}=1; - if( $address !~ /\@login\.oscar\.aol\.com/ and $address !~ /\@YAHOO/ and $address !~ /\@login\.icq\.com/ ){ - Irssi::timeout_remove($tag{$from}); - delete($tag{$from}); - $tag{$from}=Irssi::timeout_add_once($STOP_TYPING_TIMEOUT*1000,"unset_typing",$from); - } - redraw($from); - } elsif( $type == 2 ){ - stale_typing($from); - } - } -} - -sub unset_typing { - my($from,$no_redraw)=@_; - delete $typing{$from} if $typing{$from}; - Irssi::timeout_remove($tag{$from}); - delete($tag{$from}); - redraw($from) if !$no_redraw; -} - -sub stale_typing { - my($from)=@_; - $typing{$from}=2; - redraw($from); -} - -sub redraw { - my($from)=@_; - my $window = Irssi::active_win(); - my $name = $window->get_active_name(); - - # only redraw if current window equals to the typing person, is a control channel or if allwin is set - if( $from eq $name || (grep $_ eq $name, @control_channels) || Irssi::settings_get_bool("bitlbee_typing_allwin") ){ - Irssi::statusbar_items_redraw('typing_notice'); - } -} - -sub event_msg { - my ($server,$data,$from,$address,$target) = @_; - return if $server->{tag} ne $bitlbee_server->{tag}; - my $channel=Irssi::active_win()->get_active_name(); - unset_typing $from, "no redraw"; - unset_typing $channel; -} - -sub event_quit { - my $server = shift; - return if $server->{tag} ne $bitlbee_server->{tag}; - my $nick = shift; - unset_typing $nick; -} - -sub typing_notice { - my ($item, $get_size_only) = @_; - my $window = Irssi::active_win(); - my $channel = $window->get_active_name(); - - if (exists($typing{$channel})) { - my $append=$typing{$channel}==2 ? " (stale)" : ""; - $item->default_handler($get_size_only, "{sb typing$append}", 0, 1); - } else { - $item->default_handler($get_size_only, "", 0, 1); - Irssi::timeout_remove($tag{$channel}); - delete($tag{$channel}); - } - # we check for correct windows again, because the statusbar item is redrawn after window change too. - if( (grep $_ eq $channel, @control_channels) || Irssi::settings_get_bool("bitlbee_typing_allwin")) { - foreach my $key (keys(%typing)) { - $line .= " ".$key; - if ($typing{$key}==2) { $line .= " (stale)"; } - } - if ($line ne "") { - $item->default_handler($get_size_only, "{sb typing:$line}", 0, 1); - $line = ""; - } - } -} - -sub window_change { - Irssi::statusbar_items_redraw('typing_notice'); - my $win = !Irssi::active_win() ? undef : Irssi::active_win()->{active}; - if (ref $win && ($win->{server}->{tag} eq $bitlbee_server->{tag})) { - if (!$keylog_active) { - $keylog_active = 1; - Irssi::signal_add_last('gui key pressed', 'key_pressed'); - } - } else { - if ($keylog_active) { - $keylog_active = 0; - Irssi::signal_remove('gui key pressed', 'key_pressed'); - } - } -} - -sub key_pressed { - return if !Irssi::settings_get_bool("bitlbee_send_typing"); - my $key = shift; - if ($key != 9 && $key != 10 && $lastkey != 27 && $key != 27 - && $lastkey != 91 && $key != 126 && $key != 127) - { - my $server = Irssi::active_server(); - my $window = Irssi::active_win(); - my $nick = $window->get_active_name(); - - if ($server->{tag} eq $bitlbee_server->{tag} && $nick ne "(status)" && $nick ne "root") { - if( grep $_ eq $nick, @control_channels ){ # send typing if in control channel - my $input = Irssi::parse_special("\$L"); - my ($first_word) = split(/ /,$input); - if ($input !~ /^$command_char.*/ && $first_word =~ s/$to_char$//){ - send_typing($first_word); - } - } else { # or any other channels / query - my $input = Irssi::parse_special("\$L"); - if ($input !~ /^$command_char.*/ && length($input) > 0){ - send_typing($nick); - } - } - } - } - $lastkey = $key; -} - -sub out_empty { - my ($a) = @_; - my($nick,$tag)=@{$a}; - delete($out_typing{$nick}); - Irssi::timeout_remove($timer_tag{$nick}); - delete($timer_tag{$nick}); - $bitlbee_server->command("^CTCP $nick TYPING 0"); -} - -sub send_typing { - my $nick = shift; - if (!exists($out_typing{$nick}) || time - $out_typing{$nick} > $KEEP_TYPING_TIMEOUT) { - $bitlbee_server->command("^CTCP $nick TYPING 1"); - $out_typing{$nick} = time; - ### Reset 'stop-typing' timer - Irssi::timeout_remove($timer_tag{$nick}); - delete($timer_tag{$nick}); - - ### create new timer - $timer_tag{$nick} = Irssi::timeout_add_once($STOP_TYPING_TIMEOUT*1000, 'out_empty', ["$nick", $bitlbee_server->{tag}]); - } -} - -#README: Delete the old bitlbee_send_typing string from ~/.irssi/config. A boolean is better. - -sub db_typing { - print "Detected channels: "; - print Dumper(@control_channels); - print "Detected server tag: ".$bitlbee_server->{tag}; - print "Tag: ".Dumper(%tag); - print "Timer Tag: ".Dumper(%timer_tag); - print "Typing: ".Dumper(%typing); - print "Out Typing: ".Dumper(%out_typing); -} - -Irssi::command_bind('db_typing','db_typing'); - -Irssi::settings_add_bool("bitlbee","bitlbee_send_typing",1); -Irssi::settings_add_bool("bitlbee","bitlbee_typing_allwin",0); - -Irssi::signal_add("ctcp msg", "event_ctcp_msg"); -Irssi::signal_add("message private", "event_msg"); -Irssi::signal_add("message public", "event_msg"); -Irssi::signal_add("message quit", "event_quit"); -Irssi::signal_add_last('window changed', 'window_change'); -Irssi::signal_add_last('gui key pressed', 'key_pressed'); -Irssi::statusbar_item_register('typing_notice', undef, 'typing_notice'); -Irssi::statusbars_recreate_items();
--- a/irssi/scripts/cap_sasl.pl Wed Nov 19 19:08:21 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,272 +0,0 @@ -use strict; -use Irssi; -use vars qw($VERSION %IRSSI); -# $Id$ - -use MIME::Base64; - -$VERSION = "1.1"; - -%IRSSI = ( - authors => 'Michael Tharp and Jilles Tjoelker', - contact => '[email protected]', - name => 'cap_sasl.pl', - description => 'Implements PLAIN SASL authentication mechanism for use with charybdis ircds, and enables CAP MULTI-PREFIX', - license => 'GNU General Public License', - url => 'http://sasl.charybdis.be/', -); - -my %sasl_auth = (); -my %mech = (); - -sub timeout; - -sub server_connected { - my $server = shift; - $server->send_raw_now("CAP LS"); -} - -sub event_cap { - my ($server, $args, $nick, $address) = @_; - my ($subcmd, $caps, $tosend); - - $tosend = ''; - if ($args =~ /^\S+ (\S+) :(.*)$/) { - $subcmd = uc $1; - $caps = ' '.$2.' '; - if ($subcmd eq 'LS') { - $tosend .= ' multi-prefix' if $caps =~ / multi-prefix /i; - $tosend .= ' sasl' if $caps =~ / sasl /i && defined($sasl_auth{$server->{tag}}); - $tosend =~ s/^ //; - $server->print('', "CLICAP: supported by server:$caps"); - if (!$server->{connected}) { - if ($tosend eq '') { - $server->send_raw_now("CAP END"); - } else { - $server->print('', "CLICAP: requesting: $tosend"); - $server->send_raw_now("CAP REQ :$tosend"); - } - } - Irssi::signal_stop(); - } elsif ($subcmd eq 'ACK') { - $server->print('', "CLICAP: now enabled:$caps"); - if ($caps =~ / sasl /i) { - $sasl_auth{$server->{tag}}{buffer} = ''; - if($mech{$sasl_auth{$server->{tag}}{mech}}) { - $server->send_raw_now("AUTHENTICATE " . $sasl_auth{$server->{tag}}{mech}); - Irssi::timeout_add_once(5000, \&timeout, $server->{tag}); - }else{ - $server->print('', 'SASL: attempted to start unknown mechanism "' . $sasl_auth{$server->{tag}}{mech} . '"'); - } - } - elsif (!$server->{connected}) { - $server->send_raw_now("CAP END"); - } - Irssi::signal_stop(); - } elsif ($subcmd eq 'NAK') { - $server->print('', "CLICAP: refused:$caps"); - if (!$server->{connected}) { - $server->send_raw_now("CAP END"); - } - Irssi::signal_stop(); - } elsif ($subcmd eq 'LIST') { - $server->print('', "CLICAP: currently enabled:$caps"); - Irssi::signal_stop(); - } - } -} - -sub event_authenticate { - my ($server, $args, $nick, $address) = @_; - my $sasl = $sasl_auth{$server->{tag}}; - return unless $sasl && $mech{$sasl->{mech}}; - - $sasl->{buffer} .= $args; - return if length($args) == 400; - - my $data = $sasl->{buffer} eq '+' ? '' : decode_base64($sasl->{buffer}); - my $out = $mech{$sasl->{mech}}($sasl, $data); - $out = '' unless defined $out; - $out = $out eq '' ? '+' : encode_base64($out, ''); - - while(length $out >= 400) { - my $subout = substr($out, 0, 400, ''); - $server->send_raw_now("AUTHENTICATE $subout"); - } - if(length $out) { - $server->send_raw_now("AUTHENTICATE $out"); - }else{ # Last piece was exactly 400 bytes, we have to send some padding to indicate we're done - $server->send_raw_now("AUTHENTICATE +"); - } - - $sasl->{buffer} = ''; - Irssi::signal_stop(); -} - -sub event_saslend { - my ($server, $args, $nick, $address) = @_; - - my $data = $args; - $data =~ s/^\S+ :?//; - # need this to see it, ?? -- jilles - $server->print('', $data); - if (!$server->{connected}) { - $server->send_raw_now("CAP END"); - } -} - -sub timeout { - my $tag = shift; - my $server = Irssi::server_find_tag($tag); - if(!$server->{connected}) { - $server->print('', "SASL: authentication timed out"); - $server->send_raw_now("CAP END"); - } -} - -sub cmd_sasl { - my ($data, $server, $item) = @_; - - if ($data ne '') { - Irssi::command_runsub ('sasl', $data, $server, $item); - } else { - cmd_sasl_show(@_); - } -} - -sub cmd_sasl_set { - my ($data, $server, $item) = @_; - - if (my($net, $u, $p, $m) = $data =~ /^(\S+) (\S+) (\S+) (\S+)$/) { - if($mech{uc $m}) { - $sasl_auth{$net}{user} = $u; - $sasl_auth{$net}{password} = $p; - $sasl_auth{$net}{mech} = uc $m; - Irssi::print("SASL: added $net: [$m] $sasl_auth{$net}{user} *"); - }else{ - Irssi::print("SASL: unknown mechanism $m"); - } - } elsif ($data =~ /^(\S+)$/) { - $net = $1; - if (defined($sasl_auth{$net})) { - delete $sasl_auth{$net}; - Irssi::print("SASL: deleted $net"); - } else { - Irssi::print("SASL: no entry for $net"); - } - } else { - Irssi::print("SASL: usage: /sasl set <net> <user> <password or keyfile> <mechanism>"); - } -} - -sub cmd_sasl_show { - #my ($data, $server, $item) = @_; - my $net; - my $count = 0; - - foreach $net (keys %sasl_auth) { - Irssi::print("SASL: $net: [$sasl_auth{$net}{mech}] $sasl_auth{$net}{user} *"); - $count++; - } - Irssi::print("SASL: no networks defined") if !$count; -} - -sub cmd_sasl_save { - #my ($data, $server, $item) = @_; - my $file = Irssi::get_irssi_dir()."/sasl.auth"; - open FILE, "> $file" or return; - foreach my $net (keys %sasl_auth) { - printf FILE ("%s\t%s\t%s\t%s\n", $net, $sasl_auth{$net}{user}, $sasl_auth{$net}{password}, $sasl_auth{$net}{mech}); - } - close FILE; - Irssi::print("SASL: auth saved to $file"); -} - -sub cmd_sasl_load { - #my ($data, $server, $item) = @_; - my $file = Irssi::get_irssi_dir()."/sasl.auth"; - - open FILE, "< $file" or return; - %sasl_auth = (); - while (<FILE>) { - chomp; - my ($net, $u, $p, $m) = split (/\t/, $_, 4); - $m ||= "PLAIN"; - if($mech{uc $m}) { - $sasl_auth{$net}{user} = $u; - $sasl_auth{$net}{password} = $p; - $sasl_auth{$net}{mech} = uc $m; - }else{ - Irssi::print("SASL: unknown mechanism $m"); - } - } - close FILE; - Irssi::print("SASL: auth loaded from $file"); -} - -sub cmd_sasl_mechanisms { - Irssi::print("SASL: mechanisms supported: " . join(" ", keys %mech)); -} - -Irssi::signal_add_first('server connected', \&server_connected); -Irssi::signal_add('event cap', \&event_cap); -Irssi::signal_add('event authenticate', \&event_authenticate); -Irssi::signal_add('event 903', 'event_saslend'); -Irssi::signal_add('event 904', 'event_saslend'); -Irssi::signal_add('event 905', 'event_saslend'); -Irssi::signal_add('event 906', 'event_saslend'); -Irssi::signal_add('event 907', 'event_saslend'); - -Irssi::command_bind('sasl', \&cmd_sasl); -Irssi::command_bind('sasl load', \&cmd_sasl_load); -Irssi::command_bind('sasl save', \&cmd_sasl_save); -Irssi::command_bind('sasl set', \&cmd_sasl_set); -Irssi::command_bind('sasl show', \&cmd_sasl_show); -Irssi::command_bind('sasl mechanisms', \&cmd_sasl_mechanisms); - -$mech{PLAIN} = sub { - my($sasl, $data) = @_; - my $u = $sasl->{user}; - my $p = $sasl->{password}; - - join("\0", $u, $u, $p); -}; - -eval { - use Crypt::OpenSSL::Bignum; - use Crypt::DH; - use Crypt::Blowfish; - use Math::BigInt; - sub bin2bi { return Crypt::OpenSSL::Bignum->new_from_bin(shift)->to_decimal } # binary to BigInt - sub bi2bin { return Crypt::OpenSSL::Bignum->new_from_decimal((shift)->bstr)->to_bin } # BigInt to binary - $mech{'DH-BLOWFISH'} = sub { - my($sasl, $data) = @_; - my $u = $sasl->{user}; - my $pass = $sasl->{password}; - - # Generate private key and compute secret key - my($p, $g, $y) = unpack("(n/a*)3", $data); - my $dh = Crypt::DH->new(p => bin2bi($p), g => bin2bi($g)); - $dh->generate_keys; - - my $secret = bi2bin($dh->compute_secret(bin2bi($y))); - my $pubkey = bi2bin($dh->pub_key); - - # Pad the password to the nearest multiple of blocksize and encrypt - $pass .= "\0"; - $pass .= chr(rand(256)) while length($pass) % 8; - - my $cipher = Crypt::Blowfish->new($secret); - my $crypted = ''; - while(length $pass) { - my $clear = substr($pass, 0, 8, ''); - $crypted .= $cipher->encrypt($clear); - } - - pack("n/a*Z*a*", $pubkey, $u, $crypted); - }; -}; - -cmd_sasl_load(); - -# vim: ts=4
--- a/irssi/scripts/hilightwin.pl Wed Nov 19 19:08:21 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -# -# Print hilighted messages & private messages to window named "hilight" for -# irssi 0.7.99 by Timo Sirainen -# -# Modded a tiny bit by znx to stop private messages entering the hilighted -# window (can be toggled) and to put up a timestamp. -# - -use Irssi; -use POSIX; -use vars qw($VERSION %IRSSI); - -$VERSION = "0.02"; -%IRSSI = ( - authors => "Timo \'cras\' Sirainen, Mark \'znx\' Sangster", - contact => "tss\@iki.fi, znxster\@gmail.com", - name => "hilightwin", - description => "Print hilighted messages to window named \"hilight\"", - license => "Public Domain", - url => "http://irssi.org/", - changed => "Sun May 25 18:59:57 BST 2008" -); - -sub sig_printtext { - my ($dest, $text, $stripped) = @_; - - my $opt = MSGLEVEL_HILIGHT; - - if(Irssi::settings_get_bool('hilightwin_showprivmsg')) { - $opt = MSGLEVEL_HILIGHT|MSGLEVEL_MSGS; - } - - if( - ($dest->{level} & ($opt)) && - ($dest->{level} & MSGLEVEL_NOHILIGHT) == 0 - ) { - $window = Irssi::window_find_name('hilight'); - - if ($dest->{level} & MSGLEVEL_PUBLIC) { - $text = $dest->{target}.": ".$text; - } - $text = strftime( - Irssi::settings_get_str('timestamp_format')." ", - localtime - ).$text; - $window->print($text, MSGLEVEL_NEVER) if ($window); - } -} - -$window = Irssi::window_find_name('hilight'); -Irssi::print("Create a window named 'hilight'") if (!$window); - -Irssi::settings_add_bool('hilightwin','hilightwin_showprivmsg',1); - -Irssi::signal_add('print text', 'sig_printtext'); - -# vim:set ts=4 sw=4 et:
--- a/irssi/scripts/nicklist.pl Wed Nov 19 19:08:21 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,611 +0,0 @@ -# for documentation: see http://wouter.coekaerts.be/site/irssi/nicklist - -use Irssi; -use strict; -use IO::Handle; # for (auto)flush -use Fcntl; # for sysopen -use vars qw($VERSION %IRSSI); -$VERSION = '0.4.6'; -%IRSSI = ( - authors => 'Wouter Coekaerts', - contact => '[email protected]', - name => 'nicklist', - description => 'draws a nicklist to another terminal, or at the right of your irssi in the same terminal', - license => 'GPLv2', - url => 'http://wouter.coekaerts.be/irssi', - changed => '29/06/2004' -); - -sub cmd_help { - print ( <<EOF -Commands: -NICKLIST HELP -NICKLIST SCROLL <nr of lines> -NICKLIST SCREEN -NICKLIST FIFO -NICKLIST OFF -NICKLIST UPDATE - -For help see: http://wouter.coekaerts.be/site/irssi/nicklist - -in short: - -1. FIFO MODE -- in irssi: /NICKLIST FIFO (only the first time, to create the fifo) -- in a shell, in a window where you want the nicklist: cat ~/.irssi/nicklistfifo -- back in irssi: - /SET nicklist_heigth <height of nicklist> - /SET nicklist_width <width of nicklist> - /NICKLIST FIFO - -2. SCREEN MODE -- start irssi inside screen ("screen irssi") -- /NICKLIST SCREEN -EOF - ); -} - -my $prev_lines = 0; # number of lines in previous written nicklist -my $scroll_pos = 0; # scrolling position -my $cursor_line; # line the cursor is currently on -my ($OFF, $SCREEN, $FIFO) = (0,1,2); # modes -my $mode = $OFF; # current mode -my $need_redraw = 0; # nicklist needs redrawing -my $screen_resizing = 0; # terminal is being resized -my $active_channel; # (REC) - -my @nicklist=(); # array of hashes, containing the internal nicklist of the active channel - # nick => realnick - # mode => - my ($MODE_OP, $MODE_HALFOP, $MODE_VOICE, $MODE_NORMAL) = (0,1,2,3); - # status => - my ($STATUS_NORMAL, $STATUS_JOINING, $STATUS_PARTING, $STATUS_QUITING, $STATUS_KICKED, $STATUS_SPLIT) = (0,1,2,3,4,5); - # text => text to be printed - # cmp => text used to compare (sort) nicks - - -# 'cached' settings -my ($screen_prefix, $irssi_width, @prefix_mode, @prefix_status, $height, $nicklist_width); - -sub read_settings { - ($screen_prefix = Irssi::settings_get_str('nicklist_screen_prefix')) =~ s/\\e/\033/g; - - ($prefix_mode[$MODE_OP] = Irssi::settings_get_str('nicklist_prefix_mode_op')) =~ s/\\e/\033/g; - ($prefix_mode[$MODE_HALFOP] = Irssi::settings_get_str('nicklist_prefix_mode_halfop')) =~ s/\\e/\033/g; - ($prefix_mode[$MODE_VOICE] = Irssi::settings_get_str('nicklist_prefix_mode_voice')) =~ s/\\e/\033/g; - ($prefix_mode[$MODE_NORMAL] = Irssi::settings_get_str('nicklist_prefix_mode_normal')) =~ s/\\e/\033/g; - - if ($mode != $SCREEN) { - $height = Irssi::settings_get_int('nicklist_height'); - } - my $new_nicklist_width = Irssi::settings_get_int('nicklist_width'); - if ($new_nicklist_width != $nicklist_width && $mode == $SCREEN) { - sig_terminal_resized(); - } - $nicklist_width = $new_nicklist_width; -} - -sub update { - read_settings(); - make_nicklist(); -} - -################## -##### OUTPUT ##### -################## - -### off ### - -sub cmd_off { - if ($mode == $SCREEN) { - screen_stop(); - } elsif ($mode == $FIFO) { - fifo_stop(); - } -} - -### fifo ### - -sub cmd_fifo_start { - read_settings(); - my $path = Irssi::settings_get_str('nicklist_fifo_path'); - unless (-p $path) { # not a pipe - if (-e _) { # but a something else - die "$0: $path exists and is not a pipe, please remove it\n"; - } else { - require POSIX; - POSIX::mkfifo($path, 0666) or die "can\'t mkfifo $path: $!"; - Irssi::print("Fifo created. Start reading it (\"cat $path\") and try again."); - return; - } - } - if (!sysopen(FIFO, $path, O_WRONLY | O_NONBLOCK)) { # or die "can't write $path: $!"; - Irssi::print("Couldn\'t write to the fifo ($!). Please start reading the fifo (\"cat $path\") and try again."); - return; - } - FIFO->autoflush(1); - print FIFO "\033[2J\033[1;1H"; # erase screen & jump to 0,0 - $cursor_line = 0; - if ($mode == $SCREEN) { - screen_stop(); - } - $mode = $FIFO; - make_nicklist(); -} - -sub fifo_stop { - close FIFO; - $mode = $OFF; - Irssi::print("Fifo closed."); -} - -### screen ### - -sub cmd_screen_start { - if (!defined($ENV{'STY'})) { - Irssi::print 'screen not detected, screen mode only works inside screen'; - return; - } - read_settings(); - if ($mode == $SCREEN) {return;} - if ($mode == $FIFO) { - fifo_stop(); - } - $mode = $SCREEN; - Irssi::signal_add_last('gui print text finished', \&sig_gui_print_text_finished); - Irssi::signal_add_last('gui page scrolled', \&sig_page_scrolled); - Irssi::signal_add('terminal resized', \&sig_terminal_resized); - screen_size(); - make_nicklist(); -} - -sub screen_stop { - $mode = $OFF; - Irssi::signal_remove('gui print text finished', \&sig_gui_print_text_finished); - Irssi::signal_remove('gui page scrolled', \&sig_page_scrolled); - Irssi::signal_remove('terminal resized', \&sig_terminal_resized); - system 'screen -x '.$ENV{'STY'}.' -X fit'; -} - -sub screen_size { - if ($mode != $SCREEN) { - return; - } - $screen_resizing = 1; - # fit screen - system 'screen -x '.$ENV{'STY'}.' -X fit'; - # get size (from perldoc -q size) - my ($winsize, $row, $col, $xpixel, $ypixel); - eval 'use Term::ReadKey; ($col, $row, $xpixel, $ypixel) = GetTerminalSize'; - # require Term::ReadKey 'GetTerminalSize'; - # ($col, $row, $xpixel, $ypixel) = Term::ReadKey::GetTerminalSize; - #}; - if ($@) { # no Term::ReadKey, try the ugly way - eval { - require 'sys/ioctl.ph'; - # without this reloading doesn't work. workaround for some unknown bug - do 'asm/ioctls.ph'; - }; - - # ugly way not working, let's try something uglier, the dg-hack(tm) (constant for linux only?) - if($@) { no strict 'refs'; *TIOCGWINSZ = sub { return 0x5413 } } - - unless (defined &TIOCGWINSZ) { - die "Term::ReadKey not found, and ioctl 'workaround' failed. Install the Term::ReadKey perl module to use screen mode.\n"; - } - open(TTY, "+</dev/tty") or die "No tty: $!"; - unless (ioctl(TTY, &TIOCGWINSZ, $winsize='')) { - die "Term::ReadKey not found, and ioctl 'workaround' failed ($!). Install the Term::ReadKey perl module to use screen mode.\n"; - } - close(TTY); - ($row, $col, $xpixel, $ypixel) = unpack('S4', $winsize); - } - - # set screen width - $irssi_width = $col-$nicklist_width-1; - $height = $row-1; - - # on some recent systems, "screen -X fit; screen -X width -w 50" doesn't work, needs a sleep in between the 2 commands - # so we wait a second before setting the width - Irssi::timeout_add_once(1000, sub { - my ($new_irssi_width) = @_; - system 'screen -x '.$ENV{'STY'}.' -X width -w ' . $new_irssi_width; - # and then we wait another second for the resizing, and then redraw. - Irssi::timeout_add_once(1000,sub {$screen_resizing = 0; redraw()}, []); - }, $irssi_width); -} - -sub sig_terminal_resized { - if ($screen_resizing) { - return; - } - $screen_resizing = 1; - Irssi::timeout_add_once(1000,\&screen_size,[]); -} - - -### both ### - -sub nicklist_write_start { - if ($mode == $SCREEN) { - print STDERR "\033P\033[s\033\\"; # save cursor - } -} - -sub nicklist_write_end { - if ($mode == $SCREEN) { - print STDERR "\033P\033[u\033\\"; # restore cursor - } -} - -sub nicklist_write_line { - my ($line, $data) = @_; - if ($mode == $SCREEN) { - print STDERR "\033P\033[" . ($line+1) . ';'. ($irssi_width+1) .'H'. $screen_prefix . $data . "\033\\"; - } elsif ($mode == $FIFO) { - $data = "\033[m$data"; # reset color - if ($line == $cursor_line+1) { - $data = "\n$data"; # next line - } elsif ($line == $cursor_line) { - $data = "\033[1G".$data; # back to beginning of line - } else { - $data = "\033[".($line+1).";0H".$data; # jump - } - $cursor_line=$line; - print(FIFO $data) or fifo_stop(); - } -} - -# recalc the text of the nicklist item -sub calc_text { - my ($nick) = @_; - my $tmp = $nicklist_width-3; - (my $text = $nick->{'nick'}) =~ s/^(.{$tmp})..+$/$1\033[34m~\033[m/; - $nick->{'text'} = $prefix_mode[$nick->{'mode'}] . $text . (' ' x ($nicklist_width-length($nick->{'nick'})-1)); - $nick->{'cmp'} = $nick->{'mode'}.lc($nick->{'nick'}); -} - -# redraw the given nick (nr) if it is visible -sub redraw_nick_nr { - my ($nr) = @_; - my $line = $nr - $scroll_pos; - if ($line >= 0 && $line < $height) { - nicklist_write_line($line, $nicklist[$nr]->{'text'}); - } -} - -# nick was inserted, redraw area if necessary -sub draw_insert_nick_nr { - my ($nr) = @_; - my $line = $nr - $scroll_pos; - if ($line < 0) { # nick is inserted above visible area - $scroll_pos++; # 'scroll' down :) - } elsif ($line < $height) { # line is visible - if ($mode == $SCREEN) { - need_redraw(); - } elsif ($mode == $FIFO) { - my $data = "\033[m\033[L". $nicklist[$nr]->{'text'}; # reset color & insert line & write nick - if ($line == $cursor_line) { - $data = "\033[1G".$data; # back to beginning of line - } else { - $data = "\033[".($line+1).";1H".$data; # jump - } - $cursor_line=$line; - print(FIFO $data) or fifo_stop(); - if ($prev_lines < $height) { - $prev_lines++; # the nicklist has one line more - } - } - } -} - -sub draw_remove_nick_nr { - my ($nr) = @_; - my $line = $nr - $scroll_pos; - if ($line < 0) { # nick removed above visible area - $scroll_pos--; # 'scroll' up :) - } elsif ($line < $height) { # line is visible - if ($mode == $SCREEN) { - need_redraw(); - } elsif ($mode == $FIFO) { - #my $data = "\033[m\033[L[i$line]". $nicklist[$nr]->{'text'}; # reset color & insert line & write nick - my $data = "\033[M"; # delete line - if ($line != $cursor_line) { - $data = "\033[".($line+1)."d".$data; # jump - } - $cursor_line=$line; - print(FIFO $data) or fifo_stop(); - if (@nicklist-$scroll_pos >= $height) { - redraw_nick_nr($scroll_pos+$height-1); - } - } - } -} - -# redraw the whole nicklist -sub redraw { - $need_redraw = 0; - #make_nicklist(); - nicklist_write_start(); - my $line = 0; - ### draw nicklist ### - for (my $i=$scroll_pos;$line < $height && $i < @nicklist; $i++) { - nicklist_write_line($line++, $nicklist[$i]->{'text'}); - } - - ### clean up other lines ### - my $real_lines = $line; - while($line < $prev_lines) { - nicklist_write_line($line++,' ' x $nicklist_width); - } - $prev_lines = $real_lines; - nicklist_write_end(); -} - -# redraw (with little delay to avoid redrawing to much) -sub need_redraw { - if(!$need_redraw) { - $need_redraw = 1; - Irssi::timeout_add_once(10,\&redraw,[]); - } -} - -sub sig_page_scrolled { - $prev_lines = $height; # we'll need to redraw everything if he scrolled up - need_redraw; -} - -# redraw (with delay) if the window is visible (only in screen mode) -sub sig_gui_print_text_finished { - if ($need_redraw) { # there's already a redraw 'queued' - return; - } - my $window = @_[0]; - if ($window->{'refnum'} == Irssi::active_win->{'refnum'} || Irssi::settings_get_str('nicklist_screen_split_windows') eq '*') { - need_redraw; - return; - } - foreach my $win (split(/[ ,]/, Irssi::settings_get_str('nicklist_screen_split_windows'))) { - if ($window->{'refnum'} == $win || $window->{'name'} eq $win) { - need_redraw; - return; - } - } -} - -#################### -##### NICKLIST ##### -#################### - -# returns the position of the given nick(as string) in the (internal) nicklist -sub find_nick { - my ($nick) = @_; - for (my $i=0;$i < @nicklist; $i++) { - if ($nicklist[$i]->{'nick'} eq $nick) { - return $i; - } - } - return -1; -} - -# find position where nick should be inserted into the list -sub find_insert_pos { - my ($cmp)= @_; - for (my $i=0;$i < @nicklist; $i++) { - if ($nicklist[$i]->{'cmp'} gt $cmp) { - return $i; - } - } - return scalar(@nicklist); #last -} - -# make the (internal) nicklist (@nicklist) -sub make_nicklist { - @nicklist = (); - $scroll_pos = 0; - - ### get & check channel ### - my $channel = Irssi::active_win->{active}; - - if (!$channel || (ref($channel) ne 'Irssi::Irc::Channel' && ref($channel) ne 'Irssi::Silc::Channel' && ref($channel) ne 'Irssi::Xmpp::Channel') || $channel->{'type'} ne 'CHANNEL' || ($channel->{chat_type} ne 'SILC' && !$channel->{'names_got'}) ) { - $active_channel = undef; - # no nicklist - } else { - $active_channel = $channel; - ### make nicklist ### - my $thisnick; - foreach my $nick (sort {(($a->{'op'}?'1':$a->{'halfop'}?'2':$a->{'voice'}?'3':'4').lc($a->{'nick'})) - cmp (($b->{'op'}?'1':$b->{'halfop'}?'2':$b->{'voice'}?'3':'4').lc($b->{'nick'}))} $channel->nicks()) { - $thisnick = {'nick' => $nick->{'nick'}, 'mode' => ($nick->{'op'}?$MODE_OP:$nick->{'halfop'}?$MODE_HALFOP:$nick->{'voice'}?$MODE_VOICE:$MODE_NORMAL)}; - calc_text($thisnick); - push @nicklist, $thisnick; - } - } - need_redraw(); -} - -# insert nick(as hash) into nicklist -# pre: cmp has to be calculated -sub insert_nick { - my ($nick) = @_; - my $nr = find_insert_pos($nick->{'cmp'}); - splice @nicklist, $nr, 0, $nick; - draw_insert_nick_nr($nr); -} - -# remove nick(as nr) from nicklist -sub remove_nick { - my ($nr) = @_; - splice @nicklist, $nr, 1; - draw_remove_nick_nr($nr); -} - -################### -##### ACTIONS ##### -################### - -# scroll the nicklist, arg = number of lines to scroll, positive = down, negative = up -sub cmd_scroll { - if (!$active_channel) { # not a channel active - return; - } - my @nicks=Irssi::active_win->{active}->nicks; - my $nick_count = scalar(@nicks)+0; - my $channel = Irssi::active_win->{active}; - if (!$channel || $channel->{type} ne 'CHANNEL' || !$channel->{names_got} || $nick_count <= Irssi::settings_get_int('nicklist_height')) { - return; - } - $scroll_pos += @_[0]; - - if ($scroll_pos > $nick_count - $height) { - $scroll_pos = $nick_count - $height; - } - if ($scroll_pos <= 0) { - $scroll_pos = 0; - } - need_redraw(); -} - -sub is_active_channel { - my ($server,$channel) = @_; # (channel as string) - return ($server && $server->{'tag'} eq $active_channel->{'server'}->{'tag'} && $server->channel_find($channel) && $active_channel && $server->channel_find($channel)->{'name'} eq $active_channel->{'name'}); -} - -sub sig_channel_wholist { # this is actualy a little late, when the names are received would be better - my ($channel) = @_; - if (Irssi::active_win->{'active'} && Irssi::active_win->{'active'}->{'name'} eq $channel->{'name'}) { # the channel joined is active - make_nicklist - } -} - -sub sig_join { - my ($server,$channel,$nick,$address) = @_; - if (!is_active_channel($server,$channel)) { - return; - } - my $newnick = {'nick' => $nick, 'mode' => $MODE_NORMAL}; - calc_text($newnick); - insert_nick($newnick); -} - -sub sig_kick { - my ($server, $channel, $nick, $kicker, $address, $reason) = @_; - if (!is_active_channel($server,$channel)) { - return; - } - my $nr = find_nick($nick); - if ($nr == -1) { - Irssi::print("nicklist warning: $nick was kicked from $channel, but not found in nicklist"); - } else { - remove_nick($nr); - } -} - -sub sig_part { - my ($server,$channel,$nick,$address, $reason) = @_; - if (!is_active_channel($server,$channel)) { - return; - } - my $nr = find_nick($nick); - if ($nr == -1) { - Irssi::print("nicklist warning: $nick has parted $channel, but was not found in nicklist"); - } else { - remove_nick($nr); - } - -} - -sub sig_quit { - my ($server,$nick,$address, $reason) = @_; - if ($server->{'tag'} ne $active_channel->{'server'}->{'tag'}) { - return; - } - my $nr = find_nick($nick); - if ($nr != -1) { - remove_nick($nr); - } -} - -sub sig_nick { - my ($server, $newnick, $oldnick, $address) = @_; - if ($server->{'tag'} ne $active_channel->{'server'}->{'tag'}) { - return; - } - my $nr = find_nick($oldnick); - if ($nr != -1) { # if nick was found (nickchange is in current channel) - my $nick = $nicklist[$nr]; - remove_nick($nr); - $nick->{'nick'} = $newnick; - calc_text($nick); - insert_nick($nick); - } -} - -sub sig_mode { - my ($channel, $nick, $setby, $mode, $type) = @_; # (nick and channel as rec) - if ($channel->{'server'}->{'tag'} ne $active_channel->{'server'}->{'tag'} || $channel->{'name'} ne $active_channel->{'name'}) { - return; - } - my $nr = find_nick($nick->{'nick'}); - if ($nr == -1) { - Irssi::print("nicklist warning: $nick->{'nick'} had mode set on $channel->{'name'}, but was not found in nicklist"); - } else { - my $nicklist_item = $nicklist[$nr]; - remove_nick($nr); - $nicklist_item->{'mode'} = ($nick->{'op'}?$MODE_OP:$nick->{'halfop'}?$MODE_HALFOP:$nick->{'voice'}?$MODE_VOICE:$MODE_NORMAL); - calc_text($nicklist_item); - insert_nick($nicklist_item); - } -} - -##### command binds ##### -Irssi::command_bind 'nicklist' => sub { - my ( $data, $server, $item ) = @_; - $data =~ s/\s+$//g; - Irssi::command_runsub ('nicklist', $data, $server, $item ) ; -}; -Irssi::signal_add_first 'default command nicklist' => sub { - # gets triggered if called with unknown subcommand - cmd_help(); -}; -Irssi::command_bind('nicklist update',\&update); -Irssi::command_bind('nicklist help',\&cmd_help); -Irssi::command_bind('nicklist scroll',\&cmd_scroll); -Irssi::command_bind('nicklist fifo',\&cmd_fifo_start); -Irssi::command_bind('nicklist screen',\&cmd_screen_start); -Irssi::command_bind('nicklist screensize',\&screen_size); -Irssi::command_bind('nicklist off',\&cmd_off); - -##### signals ##### -Irssi::signal_add_last('window item changed', \&make_nicklist); -Irssi::signal_add_last('window changed', \&make_nicklist); -Irssi::signal_add_last('channel wholist', \&sig_channel_wholist); -Irssi::signal_add_first('message join', \&sig_join); # first, to be before ignores -Irssi::signal_add_first('message part', \&sig_part); -Irssi::signal_add_first('message kick', \&sig_kick); -Irssi::signal_add_first('message quit', \&sig_quit); -Irssi::signal_add_first('message nick', \&sig_nick); -Irssi::signal_add_first('message own_nick', \&sig_nick); -Irssi::signal_add_first('nick mode changed', \&sig_mode); - -Irssi::signal_add('setup changed', \&read_settings); - -##### settings ##### -Irssi::settings_add_str('nicklist', 'nicklist_screen_prefix', '\e[m '); -Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_op', '\e[32m@\e[39m'); -Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_halfop', '\e[34m%\e[39m'); -Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_voice', '\e[33m+\e[39m'); -Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_normal', ' '); - -Irssi::settings_add_int('nicklist', 'nicklist_width',11); -Irssi::settings_add_int('nicklist', 'nicklist_height',24); -Irssi::settings_add_str('nicklist', 'nicklist_fifo_path', Irssi::get_irssi_dir . '/nicklistfifo'); -Irssi::settings_add_str('nicklist', 'nicklist_screen_split_windows', ''); -Irssi::settings_add_str('nicklist', 'nicklist_automode', ''); - -read_settings(); -if (uc(Irssi::settings_get_str('nicklist_automode')) eq 'SCREEN') { - cmd_screen_start(); -} elsif (uc(Irssi::settings_get_str('nicklist_automode')) eq 'FIFO') { - cmd_fifo_start(); -}
--- a/irssi/scripts/nm.pl Wed Nov 19 19:08:21 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,693 +0,0 @@ -use Irssi; -use strict; - -use vars qw($VERSION %IRSSI); - -$VERSION="0.3.10"; -%IRSSI = ( - authors=> 'BC-bd', - contact=> '[email protected]', - name=> 'nm', - description=> 'right aligned nicks depending on longest nick', - license=> 'GPL v2', - url=> 'http://bc-bd.org/blog/irssi/', -); - -# $Id: 9cb009e8b7e6f5ce60294334faf88715ef01413e $ -# nm.pl -# for irssi 0.8.4 by [email protected] -# -# right aligned nicks depending on longest nick -# -# inspired by neatmsg.pl from kodgehopper <[email protected] -# formats taken from www.irssi.de -# thanks to adrianel <[email protected]> for some hints -# thanks to Eric Wald <[email protected]> for the left alignment patch -# inspired by nickcolor.pl by Timo Sirainen and Ian Peters -# thanks to And1 <[email protected]> for a small patch -# thanks to [email protected] for the save/load patch -# thanks to Dennis Heimbert <[email protected]> for a bug report/patch -# thanks to Roy Sigurd Karlsbakk <[email protected]> for an autosave patch -# -######### -# USAGE -### -# -# use -# -# /neatcolor help -# -# for help on available commands -# -######### -# OPTIONS -######### - -my $help = " -/set neat_colorize <ON|OFF> - * ON : colorize nicks - * OFF : do not colorize nicks - -/set neat_colors <string> - Use these colors when colorizing nicks, eg: - - /set neat_colors yYrR - - See the file formats.txt on an explanation of what colors are - available. - -/set neat_left_actions <ON|OFF> - * ON : print nicks left-aligned on actions - * OFF : print nicks right-aligned on actions - -/set neat_left_messages <ON|OFF> - * ON : print nicks left-aligned on messages - * OFF : print nicks right-aligned on messages - -/set neat_right_mode <ON|OFF> - * ON : print the mode of the nick e.g @%+ after the nick - * OFF : print it left of the nick - -/set neat_maxlength <number> - * number : Maximum length of Nicks to display. Longer nicks are truncated. - * 0 : Do not truncate nicks. - -/set neat_melength <number> - * number : number of spaces to substract from /me padding - -/set neat_ignorechars <str> - * str : regular expression used to filter out unwanted characters in - nicks. this can be used to assign the same color for similar - nicks, e.g. foo and foo_: - - /set neat_ignorechars [_] - -/set neat_allow_shrinking <ON|OFF> - * ON : shrink padding when longest nick disappears - * OFF : do not shrink, only allow growing - -/set neat_autosave <number> - * number : autosave after <number> seconds, defaults to 60. Set to 0 to - disable. -"; - -# -### -################ -### -# -# Changelog -# -# Version 0.3.11 -# - added autosave, idea from Roy Sigurd Karlsbakk -# -# Version 0.3.10 -# - fix losing of saved color when changing nick shares more than one channel -# with you -# -# Version 0.3.9 -# - fix longest nick calculation for nicks shorter than the current longest -# nick -# - updated url -# -# Version 0.3.8 -# - fixed error in the nickchange tracking code, reported by Kevin Ballard -# - added --all switch to reset command -# - skip broken lines in saved_colors -# -# Version 0.3.7 -# - fixed crash when calling /neatcolor without parameters -# - fixed url -# -# Version 0.3.6 -# - added option to ignore certain characters from color hash building, see -# https://bc-bd.org/trac/irssi/ticket/22 -# - added option to save and specify colors for nicks, see -# https://bc-bd.org/trac/irssi/ticket/23 -# - added option to disallow shrinking, see -# https://bc-bd.org/trac/irssi/ticket/12 -# -# Version 0.3.5 -# - now also aligning own messages in queries -# -# Version 0.3.4 -# - fxed off by one error in nick_to_color, patch by jrib, see -# https://bc-bd.org/trac/irssi/ticket/24 -# -# Version 0.3.3 -# - added support for alignment in queries, see -# https://bc-bd.org/trac/irssi/ticket/21 -# -# Version 0.3.2 -# - integrated left alignment patch from Eric Wald <[email protected]>, see -# https://bc-bd.org/trac/irssi/ticket/18 -# -# Version 0.3.1 -# - /me padding, see https://bc-bd.org/trac/irssi/ticket/17 -# -# Version 0.3.0 -# - integrate nick coloring support -# -# Version 0.2.1 -# - moved neat_maxlength check to reformat() (thx to Jerome De Greef <[email protected]>) -# -# Version 0.2.0 -# - by adrianel <[email protected]> -# * reformat after setup reload -# * maximum length of nicks -# -# Version 0.1.0 -# - got lost somewhere -# -# Version 0.0.2 -# - ugly typo fixed -# -# Version 0.0.1 -# - initial release -# -### -################ -### -# -# BUGS -# -# Empty nicks, eg "<> message" -# This seems to be triggered by some themes. As of now there is no known -# fix other than changing themes, see -# https://bc-bd.org/trac/irssi/ticket/19 -# -# Well, it's a feature: due to the lacking support of extendable themes -# from irssi it is not possible to just change some formats per window. -# This means that right now all windows are aligned with the same nick -# length, which can be somewhat annoying. -# If irssi supports extendable themes, I will include per-server indenting -# and a setting where you can specify servers you don't want to be indented -# -### -################ - -my ($longestNick, %saved_colors, @colors, $alignment, $sign, %commands,); -my ($pending_save); - -my $colorize = -1; - -sub reformat() { - my $max = Irssi::settings_get_int('neat_maxlength'); - my $actsign = Irssi::settings_get_bool('neat_left_actions')? '': '-'; - $sign = Irssi::settings_get_bool('neat_left_messages')? '': '-'; - - if ($max && $max < $longestNick) { - $longestNick = $max; - } - - my $me = $longestNick - Irssi::settings_get_int('neat_melength'); - $me = 0 if ($me < 0); - - Irssi::command('^format own_action {ownaction $['.$actsign.$me.']0} $1'); - Irssi::command('^format action_public {pubaction $['.$actsign.$me.']0}$1'); - Irssi::command('^format action_private {pvtaction $['.$actsign.$me.']0}$1'); - Irssi::command('^format action_private_query {pvtaction_query $['.$actsign.$me.']0} $2'); - - my $length = $sign . $longestNick; - if (Irssi::settings_get_bool('neat_right_mode') == 0) { - Irssi::command('^format own_msg {ownmsgnick $2 {ownnick $['.$length.']0}}$1'); - Irssi::command('^format own_msg_channel {ownmsgnick $3 {ownnick $['.$length.']0}{msgchannel $1}}$2'); - Irssi::command('^format pubmsg_me {pubmsgmenick $2 {menick $['.$length.']0}}$1'); - Irssi::command('^format pubmsg_me_channel {pubmsgmenick $3 {menick $['.$length.']0}{msgchannel $1}}$2'); - Irssi::command('^format pubmsg_hilight {pubmsghinick $0 $3 $['.$length.']1%n}$2'); - Irssi::command('^format pubmsg_hilight_channel {pubmsghinick $0 $4 $['.$length.']1{msgchannel $2}}$3'); - Irssi::command('^format pubmsg {pubmsgnick $2 {pubnick $['.$length.']0}}$1'); - Irssi::command('^format pubmsg_channel {pubmsgnick $2 {pubnick $['.$length.']0}}$1'); - } else { - Irssi::command('^format own_msg {ownmsgnick {ownnick $['.$length.']0$2}}$1'); - Irssi::command('^format own_msg_channel {ownmsgnick {ownnick $['.$length.']0$3}{msgchannel $1}}$2'); - Irssi::command('^format pubmsg_me {pubmsgmenick {menick $['.$length.']0}$2}$1'); - Irssi::command('^format pubmsg_me_channel {pubmsgmenick {menick $['.$length.']0$3}{msgchannel $1}}$2'); - Irssi::command('^format pubmsg_hilight {pubmsghinick $0 $0 $['.$length.']1$3%n}$2'); - Irssi::command('^format pubmsg_hilight_channel {pubmsghinick $0 $['.$length.']1$4{msgchannel $2}}$3'); - Irssi::command('^format pubmsg {pubmsgnick {pubnick $['.$length.']0$2}}$1'); - Irssi::command('^format pubmsg_channel {pubmsgnick {pubnick $['.$length.']0$2}}$1'); - } - - # format queries - Irssi::command('^format own_msg_private_query {ownprivmsgnick {ownprivnick $['.$length.']2}}$1'); - Irssi::command('^format msg_private_query {privmsgnick $['.$length.']0}$2'); -}; - -sub findLongestNick { - $longestNick = 0; - - # get own nick length - map { - my $len = length($_->{nick}); - - $longestNick = $len if ($len > $longestNick); - } Irssi::servers(); - - # find longest other nick - foreach (Irssi::channels()) { - foreach ($_->nicks()) { - my $len = length($_->{nick}); - - $longestNick = $len if ($len > $longestNick); - } - } - - reformat(); -} - -sub delayed_save -{ - # skip if we have already a save pending. we don't reset the timeout - # here, else you could end up with changes never being automatically - # saved if they happen more often than <neat_autosave> seconds - return if $pending_save; - - return unless Irssi::settings_get_int('neat_autosave'); - - Irssi::timeout_add_once(Irssi::settings_get_int('neat_autosave') * 1000, - \&save_colors, undef); -} - -# a new nick was created -sub sig_newNick -{ - my ($channel, $nick) = @_; - - my $len = length($nick->{nick}); - - if ($len > $longestNick) { - $longestNick = $len; - reformat(); - } - - return if (exists($saved_colors{$nick->{nick}})); - - $saved_colors{$nick->{nick}} = "%".nick_to_color($nick->{nick}); - delayed_save(); -} - -# something changed -sub sig_changeNick -{ - my ($channel, $nick, $old_nick) = @_; - - # if no saved color exists, we already handled this nickchange. irssi - # generates one signal per channel the nick is in, so if you share more - # than one channel with this nick, you'd lose the coloring. - return unless exists($saved_colors{$old_nick}); - - # we need to update the saved colorors hash independent of nick lenght - $saved_colors{$nick->{nick}} = $saved_colors{$old_nick}; - delete $saved_colors{$old_nick}; - delayed_save(); - - my $new = length($nick->{nick}); - - # in case the new nick is longer than the old one, simply remember this - # as the new longest nick and reformat. - # - # if the new nick is as long as the known longest nick nothing has to be - # done - # - # if the new nick is shorter than the current longest one and if the - # user allows us to shrink, find new longest nick and reformat. - if ($new > $longestNick) { - $longestNick = $new; - } elsif ($new == $longestNick) { - return; - } else { - return unless Irssi::settings_get_bool('neat_allow_shrinking'); - findLongestNick(); - } - - reformat(); -} - -sub sig_removeNick -{ - my ($channel, $nick) = @_; - - my $thisLen = length($nick->{nick}); - - # we only need to recalculate if this was the longest nick and we are - # allowed to shrink - if ($thisLen == $longestNick && Irssi::settings_get_bool('neat_allow_shrinking')) { - findLongestNick(); - reformat(); - } - - # we do not remove a known color for a gone nick, as they may return -} - -# based on simple_hash from nickcolor.pl -sub nick_to_color($) { - my ($string) = @_; - chomp $string; - - my $ignore = Irssi::settings_get_str("neat_ignorechars"); - $string =~ s/$ignore//g; - - my $counter; - foreach my $char (split(//, $string)) { - $counter += ord $char; - } - - return $colors[$counter % ($#colors + 1)]; -} - -sub color_left($) { - Irssi::command('^format pubmsg {pubmsgnick $2 {pubnick '.$_[0].'$['.$sign.$longestNick.']0}}$1'); - Irssi::command('^format pubmsg_channel {pubmsgnick $2 {pubnick '.$_[0].'$['.$sign.$longestNick.']0}}$1'); -} - -sub color_right($) { - Irssi::command('^format pubmsg {pubmsgnick {pubnick '.$_[0].'$['.$sign.$longestNick.']0}$2}$1'); - Irssi::command('^format pubmsg_channel {pubmsgnick {pubnick '.$_[0].'$['.$sign.$longestNick.']0}$2}$1'); -} - -sub sig_public { - my ($server, $msg, $nick, $address, $target) = @_; - - &$alignment($saved_colors{$nick}); -} - -sub sig_setup { - @colors = split(//, Irssi::settings_get_str('neat_colors')); - - # check left or right alignment - if (Irssi::settings_get_bool('neat_right_mode') == 0) { - $alignment = \&color_left; - } else { - $alignment = \&color_right; - } - - # check if we switched coloring on or off - my $new = Irssi::settings_get_bool('neat_colorize'); - if ($new != $colorize) { - if ($new) { - Irssi::signal_add('message public', 'sig_public'); - } else { - if ($colorize >= 0) { - Irssi::signal_remove('message public', 'sig_public'); - } - } - } - $colorize = $new; - - reformat(); - &$alignment('%w'); -} - -# make sure that every nick has an assigned color -sub assert_colors() { - foreach (Irssi::channels()) { - foreach ($_->nicks()) { - next if (exists($saved_colors{$_->{nick}})); - - $saved_colors{$_->{nick}} = "%".nick_to_color($_->{nick}); - delayed_save(); - } - } -} - -# load colors from file -sub load_colors() { - open(FID, "<".$ENV{HOME}."/.irssi/saved_colors") || return; - - while (<FID>) { - chomp; - my ($k, $v) = split(/:/); - - # skip broken lines, those may have been introduced by nm.pl - # version 0.3.7 and earlier - if ($k eq '' || $v eq '') { - neat_log(Irssi::active_win(), "Warning, broken line in saved_colors file, skipping '$k:$v'"); - next; - } - - $saved_colors{$k} = $v; - } - - close(FID); -} - -# save colors to file -sub save_colors() { - open(FID, ">".$ENV{HOME}."/.irssi/saved_colors"); - - print FID $_.":".$saved_colors{$_}."\n" foreach (keys(%saved_colors)); - - close(FID); - - # clear possible pending save. - Irssi::timeout_remove($pending_save) if $pending_save; - $pending_save = undef; -} - -# log a line to a window item -sub neat_log($@) { - my ($witem, @text) = @_; - - $witem->print("nm.pl: ".$_) foreach(@text); -} - -# show available colors -sub cmd_neatcolor_colors($) { - my ($witem, undef, undef) = @_; - - neat_log($witem, "Available colors: ".join("", map { "%".$_.$_ } @colors)); -} - -# display the configured color for a nick -sub cmd_neatcolor_get() { - my ($witem, $nick, undef) = @_; - - if (!exists($saved_colors{$nick})) { - neat_log($witem, "Error: no such nick '$nick'"); - return; - } - - neat_log($witem, "Color for ".$saved_colors{$nick}.$nick); -} - -# display help -sub cmd_neatcolor_help() { - my ($witem, $cmd, undef) = @_; - - if ($cmd) { - if (!exists($commands{$cmd})) { - neat_log($witem, "Error: no such command '$cmd'"); - return; - } - - if (!exists($commands{$cmd}{verbose})) { - neat_log($witem, "No additional help for '$cmd' available"); - return; - } - - neat_log($witem, ( "", "Help for ".uc($cmd), "" ) ); - neat_log($witem, @{$commands{$cmd}{verbose}}); - return; - } - - neat_log($witem, split(/\n/, $help)); - neat_log($witem, "Available options for /neatcolor"); - neat_log($witem, " ".$_.": ".$commands{$_}{text}) foreach(sort(keys(%commands))); - - my @verbose; - foreach (sort(keys(%commands))) { - push(@verbose, $_) if exists($commands{$_}{verbose}); - } - - neat_log($witem, "Verbose help available for: '".join(", ", @verbose)."'"); -} - -# list configured nicks -sub cmd_neatcolor_list() { - my ($witem, undef, undef) = @_; - - neat_log($witem, "Configured nicks: ".join(", ", map { $saved_colors{$_}.$_ } sort(keys(%saved_colors)))); -} - -# reset a nick to its default color -sub cmd_neatcolor_reset() { - my ($witem, $nick, undef) = @_; - - if ($nick eq '--all') { - %saved_colors = (); - assert_colors(); - neat_log($witem, "Reset all colors"); - return; - } - - if (!exists($saved_colors{$nick})) { - neat_log($witem, "Error: no such nick '$nick'"); - return; - } - - $saved_colors{$nick} = "%".nick_to_color($nick); - delayed_save(); - neat_log($witem, "Reset color for ".$saved_colors{$nick}.$nick); -} - -# save configured colors to disk -sub cmd_neatcolor_save() { - my ($witem, undef, undef) = @_; - - save_colors(); - - neat_log($witem, "color information saved"); -} - -# set a color for a nick -sub cmd_neatcolor_set() { - my ($witem, $nick, $color) = @_; - - my @found = grep(/$color/, @colors); - if ($#found) { - neat_log($witem, "Error: trying to set unknown color '%$color$color%n'"); - cmd_neatcolor_colors($witem); - return; - } - - if ($witem->{type} ne "CHANNEL" && $witem->{type} ne "QUERY") { - neat_log($witem, "Warning: not a Channel/Query, can not check nick!"); - neat_log($witem, "Remember, nicks are case sensitive to nm.pl"); - } else { - my @nicks = grep(/^$nick$/i, map { $_->{nick} } ($witem->nicks())); - - if ($#nicks < 0) { - neat_log($witem, "Warning: could not find nick '$nick' here"); - } else { - if ($nicks[0] ne $nick) { - neat_log($witem, "Warning: using '$nicks[0]' instead of '$nick'"); - $nick = $nicks[0]; - } - } - } - - $saved_colors{$nick} = "%".$color; - delayed_save(); - neat_log($witem, "Set color for $saved_colors{$nick}$nick"); -} - -%commands = ( - colors => { - text => "show available colors", - verbose => [ - "COLORS", - "", - "displays all available colors", - "", - "You can restrict/define the list of available colors ". - "with the help of the neat_colors setting" - ], - func => \&cmd_neatcolor_colors, - }, - get => { - text => "retrieve color for a nick", - verbose => [ - "GET <nick>", - "", - "displays color used for <nick>" - ], - func => \&cmd_neatcolor_get, - }, - help => { - text => "print this help message", - func => \&cmd_neatcolor_help, - }, - list => { - text => "list configured nick/color pairs", - func => \&cmd_neatcolor_list, - }, - reset => { - text => "reset color to default", - verbose => [ - "RESET --all|<nick>", - "", - "resets the color used for all nicks or for <nick> to ", - "its internal default", - ], - func => \&cmd_neatcolor_reset, - }, - save => { - text => "save color information to disk", - verbose => [ - "SAVE", - "", - "saves color information to disk, so that it survives ". - "an irssi restart.", - "", - "Color information will be automatically saved on /quit", - ], - func => \&cmd_neatcolor_save, - }, - set => { - text => "set a specific color for a nick", - verbose => [ - "SET <nick> <color>", - "", - "use <color> for <nick>", - "", - "This command will perform a couple of sanity checks, ". - "when called from a CHANNEL/QUERY window", - "", - "EXAMPLE:", - " /neatcolor set bc-bd r", - "", - "use /neatcolor COLORS to see available colors" - ], - func => \&cmd_neatcolor_set, - }, -); - -# the main command callback that gets called for all neatcolor commands -sub cmd_neatcolor() { - my ($data, $server, $witem) = @_; - my ($cmd, $nick, $color) = split (/ /, $data); - - $cmd = lc($cmd); - - # make sure we have a valid witem to print text to - $witem = Irssi::active_win() unless ($witem); - - if (!exists($commands{$cmd})) { - neat_log($witem, "Error: unknown command '$cmd'"); - &{$commands{"help"}{"func"}}($witem) if (exists($commands{"help"})); - return; - } - - &{$commands{$cmd}{"func"}}($witem, $nick, $color); -} - -Irssi::settings_add_bool('misc', 'neat_left_messages', 0); -Irssi::settings_add_bool('misc', 'neat_left_actions', 0); -Irssi::settings_add_bool('misc', 'neat_right_mode', 1); -Irssi::settings_add_int('misc', 'neat_maxlength', 0); -Irssi::settings_add_int('misc', 'neat_melength', 2); -Irssi::settings_add_bool('misc', 'neat_colorize', 1); -Irssi::settings_add_str('misc', 'neat_colors', 'rRgGyYbBmMcC'); -Irssi::settings_add_str('misc', 'neat_ignorechars', ''); -Irssi::settings_add_bool('misc', 'neat_allow_shrinking', 1); -Irssi::settings_add_int('misc', 'neat_autosave', 60); - -Irssi::command_bind('neatcolor', 'cmd_neatcolor'); - -Irssi::signal_add('nicklist new', 'sig_newNick'); -Irssi::signal_add('nicklist changed', 'sig_changeNick'); -Irssi::signal_add('nicklist remove', 'sig_removeNick'); - -Irssi::signal_add('setup changed', 'sig_setup'); -Irssi::signal_add_last('setup reread', 'sig_setup'); - -findLongestNick(); -sig_setup; - -load_colors(); -assert_colors(); - -# we need to add this signal _after_ the colors have been loaded, to make sure -# no race condition exists wrt color saving -Irssi::signal_add('gui exit', 'save_colors');
--- a/irssi/scripts/queryresume.pl Wed Nov 19 19:08:21 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -# QueryResume by Stefan Tomanek <[email protected]> -# -use strict; - -use vars qw($VERSION %IRSSI); -$VERSION = '2003021201'; -%IRSSI = ( - authors => 'Stefan \'tommie\' Tomanek', - contact => '[email protected]', - name => 'QueryResume', - description => 'restores the last lines of a query on re-creation', - license => 'GPLv2', - modules => 'Date::Format File::Glob', - changed => $VERSION, -); - -use Irssi 20020324; -use Date::Format; -use File::Glob ':glob'; - -sub draw_box ($$$$) { - my ($title, $text, $footer, $colour) = @_; - my $box = ''; - $box .= '%R,--[%n%9%U'.$title.'%U%9%R]%n'."\n"; - foreach (split(/\n/, $text)) { - $box .= '%R|%n '.$_."\n"; - } - $box .= '%R`--<%n'.$footer.'%R>->%n'; - $box =~ s/%.//g unless $colour; - return $box; -} - -sub sig_window_item_new ($$) { - my ($win, $witem) = @_; - return unless (ref $witem && $witem->{type} eq 'QUERY'); - my @data; - my $filename = Irssi::settings_get_str('autolog_path'); - my $servertag = $witem->{server}->{tag}; - my $name = lc $witem->{name}; - $filename =~ s/(\$tag|\$1)/$servertag/g; - $filename =~ s/\$0/$name/g; - my @lt = localtime(time); - my $zone; - $filename = strftime($filename, @lt, $zone); - $filename =~ s/(\[|\])/\\$1/g; - local *F; - open(F, "<".bsd_glob($filename)); - my $lines = Irssi::settings_get_int('queryresume_lines'); - foreach (<F>) { - unless (/^--- Log/) { - push(@data, $_); - shift(@data) if (@data > $lines); - } - } - my $text; - $text .= $_ foreach @data; - $text =~ s/%/%%/g; - $witem->print(draw_box('QueryResume', $text, $filename, 1), MSGLEVEL_CLIENTCRAP) if $text; -} - -Irssi::settings_add_int($IRSSI{name}, 'queryresume_lines', 10); - -Irssi::signal_add('window item new', 'sig_window_item_new'); -
--- a/irssi/scripts/trackbar.pl Wed Nov 19 19:08:21 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,189 +0,0 @@ -# trackbar.pl -# -# This little script will do just one thing: it will draw a line each time you -# switch away from a window. This way, you always know just upto where you've -# been reading that window :) It also removes the previous drawn line, so you -# don't see double lines. -# -# Usage: -# -# The script works right out of the box, but if you want you can change -# the working by /set'ing the following variables: -# -# trackbar_string The characters to repeat to draw the bar -# trackbar_style The style for the bar, %r is red for example -# See formats.txt that came with irssi -# -# /mark is a command that will redraw the line at the bottom. However! This -# requires irssi version after 20021228. otherwise you'll get the error -# redraw: unknown command, and your screen is all goofed up :) -# -# /upgrade & buf.pl notice: This version tries to remove the trackbars before -# the upgrade is done, so buf.pl does not restore them, as they are not removeable -# afterwards by trackbar. Unfortiounatly, to make this work, trackbar and buf.pl -# need to be loaded in a specific order. Please experiment to see which order works -# for you (strangely, it differs from configuration to configuration, something I will -# try to fix in a next version) -# -# Authors: -# - Main maintainer & author: Peter 'kinlo' Leurs -# - Many thanks to Timo 'cras' Sirainen for placing me on my way -# - on-upgrade-remove-line patch by Uwe Dudenhoeffer -# -# Version history: -# 1.4: - Changed our's by my's so the irssi script header is valid -# - Removed utf-8 support. In theory, the script should work w/o any -# problems for utf-8, just set trackbar_string to a valid utf-8 character -# and everything *should* work. However, this script is being plagued by -# irssi internal bugs. The function Irssi::settings_get_str does NOT handle -# unicode strings properly, hence you will notice problems when setting the bar -# to a unicode char. For changing your bar to utf-8 symbols, read the line sub. -# 1.3: - Upgrade now removes the trackbars. -# - Some code cleanups, other defaults -# - /mark sets the line to the bottom -# 1.2: - Support for utf-8 -# - How the bar looks can now be configured with trackbar_string -# and trackbar_style -# 1.1: - Fixed bug when closing window -# 1.0: - Initial release -# -# -# Call for help! -# -# There is a trackbar version 2.0 that properly handles resizes and immediate config change -# activation. However, there is/are some bug(s) in irssi's main buffer/window code that causes -# irssi to 'forget' lines, which is ofcourse completly unaccepteable. I haven't found the time -# nor do I know the irssi's internals enough to find and fix this bug, if you want to help, please -# contact me, I'll give you a copy of the 2.0 version that will immediatly show you the problems. -# -# Known bugs: -# - if you /clear a window, it will be uncleared when returning to the window -# - UTF-8 characters in the trackbar_string doesnt work. This is an irssi bug. -# - if you resize your irssi (in xterm or so) the bar is not resized -# - changing the trackbar style is only visible after returning to a window -# however, changing style/resize takes in effect after you left the window. -# -# Whishlist/todo: -# - instead of drawing a line, just invert timestamp or something, -# to save a line (but I don't think this is possible with current irssi) -# - some pageup keybinding possibility, to scroll up upto the trackbar -# - <@coekie> kinlo: if i switch to another window, in another split window, i -# want the trackbar to go down in the previouswindow in that splitwindow :) -# - < bob_2> anyway to clear the line once the window is read? -# - < elho> kinlo: wishlist item: a string that gets prepended to the repeating pattern -# - < elho> an option to still have the timestamp in front of the bar -# - < elho> oh and an option to not draw it in the status window :P -# -# BTW: when you have feature requests, mailing a patch that works is the fastest way -# to get it added :p - -use strict; -use 5.6.1; -use Irssi; -use Irssi::TextUI; - -my $VERSION = "1.4"; - -my %IRSSI = ( - authors => "Peter 'kinlo' Leurs", - contact => "peter\@pfoe.be", - name => "trackbar", - description => "Shows a bar where you've last read a window", - license => "GPLv2", - url => "http://www.pfoe.be/~peter/trackbar/", - changed => "Thu Feb 20 16:18:08 2003", -); - -my %config; - -Irssi::settings_add_str('trackbar', 'trackbar_string' => '-'); -$config{'trackbar_string'} = Irssi::settings_get_str('trackbar_string'); - -Irssi::settings_add_str('trackbar', 'trackbar_style' => '%K'); -$config{'trackbar_style'} = Irssi::settings_get_str('trackbar_style'); - -Irssi::signal_add( - 'setup changed' => sub { - $config{'trackbar_string'} = Irssi::settings_get_str('trackbar_string'); - $config{'trackbar_style'} = Irssi::settings_get_str('trackbar_style'); - if ($config{'trackbar_style'} =~ /(?<!%)[^%]|%%|%$/) { - Irssi::print( - "trackbar: %RWarning!%n 'trackbar_style' seems to contain " - . "printable characters. Only use format codes (read " - . "formats.txt).", MSGLEVEL_CLIENTERROR); - } - } -); - -Irssi::signal_add( - 'window changed' => sub { - my (undef, $oldwindow) = @_; - - if ($oldwindow) { - my $line = $oldwindow->view()->get_bookmark('trackbar'); - $oldwindow->view()->remove_line($line) if defined $line; - $oldwindow->print(line($oldwindow->{'width'}), MSGLEVEL_NEVER); - $oldwindow->view()->set_bookmark_bottom('trackbar'); - } - } -); - -sub line { - my $width = shift; - my $string = $config{'trackbar_string'}; - $string = '-' unless defined $string; - - # There is a bug in irssi's utf-8 handling on config file settings, as you - # can reproduce/see yourself by the following code sniplet: - # - # my $quake = pack 'U*', 8364; # EUR symbol - # Irssi::settings_add_str 'temp', 'temp_foo' => $quake; - # Irssi::print length $quake; - # # prints 1 - # Irssi::print length Irssi::settings_get_str 'temp_foo'; - # # prints 3 - # - # - # Trackbar used to have a workaround, but on recent versions of perl/irssi - # it does no longer work. Therefore, if you want your trackbar to contain - # unicode characters, uncomment the line below for a nice full line, or set - # the string to whatever char you want. - - # $string = pack('U*', 0x2500); - - - my $length = length $string; - - if ($length == 0) { - $string = '-'; - $length = 1; - } - - my $times = $width / $length; - $times = int(1 + $times) if $times != int($times); - $string =~ s/%/%%/g; - return $config{'trackbar_style'} . substr($string x $times, 0, $width); -} - -# Remove trackbars on upgrade - but this doesn't really work if the scripts are not loaded in the correct order... watch out! - -Irssi::signal_add_first( 'session save' => sub { - for my $window (Irssi::windows) { - next unless defined $window; - my $line = $window->view()->get_bookmark('trackbar'); - $window->view()->remove_line($line) if defined $line; - } - } -); - -sub cmd_mark { - my $window = Irssi::active_win(); -# return unless defined $window; - my $line = $window->view()->get_bookmark('trackbar'); - $window->view()->remove_line($line) if defined $line; - $window->print(line($window->{'width'}), MSGLEVEL_NEVER); - $window->view()->set_bookmark_bottom('trackbar'); - Irssi::command("redraw"); -} - -Irssi::command_bind('mark', 'cmd_mark');
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat/buffers.conf Wed Nov 19 19:24:17 2014 +0100 @@ -0,0 +1,71 @@ +# +# buffers.conf -- weechat v1.0.1 +# + +[color] +current_bg = default +current_fg = cyan +default_bg = default +default_fg = gray +hotlist_highlight_bg = default +hotlist_highlight_fg = magenta +hotlist_low_bg = default +hotlist_low_fg = white +hotlist_message_bg = default +hotlist_message_fg = green +hotlist_private_bg = default +hotlist_private_fg = red +none_channel_bg = default +none_channel_fg = darkgray +number = default +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 = 0 +detach_buffer_immediately = "" +detach_display_window_number = off +detach_displayed_buffers = on +detach_free_content = off +detach_query = off +hide_merged_buffers = all +hotlist_counter = off +immune_detach_buffers = "" +indenting = on +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 = off +sort = number +suffix_bufname = " " +toggle_bar = on +whitelist_buffers = ""
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat/perl/autoload/buffers.pl Wed Nov 19 19:24:17 2014 +0100 @@ -0,0 +1,1785 @@ +# +# Copyright (C) 2008-2014 Sebastien Helleu <[email protected]> +# Copyright (C) 2011-2013 Nils G <[email protected]> +# +# 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 <http://www.gnu.org/licenses/>. +# +# +# Display sidebar with list of buffers. +# +# History: +# +# 2014-08-29, Patrick Steinhardt <[email protected]>: +# v4.9: add support for specifying custom buffer names +# 2014-07-19, Sebastien Helleu <[email protected]>: +# v4.8: add support of ctrl + mouse wheel to jump to previous/next buffer, +# new option "mouse_wheel" +# 2014-06-22, Sebastien Helleu <[email protected]>: +# v4.7: fix typos in options +# 2014-04-05, Sebastien Helleu <[email protected]>: +# v4.6: add support of hidden buffers (WeeChat >= 0.4.4) +# 2014-01-01, Sebastien Helleu <[email protected]>: +# v4.5: add option "mouse_move_buffer" +# 2013-12-11, Sebastien Helleu <[email protected]>: +# 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 <[email protected]>: +# 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 <anti.teamidiot.de>: +# v3.7: call menu on right mouse if menu script is loaded. +# 2012-10-06, nils_2 <[email protected]>: +# v3.6: add new option "hotlist_counter" (idea by torque). +# 2012-06-02, nils_2 <[email protected]>: +# v3.5: add values "server|channel|private|all|keepserver|none" to option "hide_merged_buffers" (suggested by dominikh). +# 2012-05-25, nils_2 <[email protected]>: +# v3.4: add new option "show_lag". +# 2012-04-07, Sebastien Helleu <[email protected]>: +# v3.3: fix truncation of wide chars in buffer name (option name_size_max) (bug #36034) +# 2012-03-15, nils_2 <[email protected]>: +# 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 <[email protected]>: +# v3.1: fix reload of config file +# 2012-01-29, nils_2 <[email protected]>: +# v3.0: fix: buffers did not update directly during window_switch (reported by FiXato) +# 2012-01-29, nils_2 <[email protected]>: +# v2.9: add options "name_size_max" and "name_crop_suffix" +# 2012-01-08, nils_2 <[email protected]>: +# 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 <[email protected]>: +# v2.7: fix regex lookup in whitelist buffers list +# 2011-12-04, nils_2 <[email protected]>: +# 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 <[email protected]>: +# v2.5: add new options "show_number_char" and "color_number_char", +# add help-description for options +# 2011-08-24, Sebastien Helleu <[email protected]>: +# v2.4: add mouse support +# 2011-06-06, nils_2 <[email protected]>: +# v2.3: added: missed option "color_whitelist_default" +# 2011-03-23, Sebastien Helleu <[email protected]>: +# v2.2: fix color of nick prefix with WeeChat >= 0.3.5 +# 2011-02-13, nils_2 <[email protected]>: +# v2.1: add options "color_whitelist_*" +# 2010-10-05, Sebastien Helleu <[email protected]>: +# v2.0: add options "sort" and "show_number" +# 2010-04-12, Sebastien Helleu <[email protected]>: +# v1.9: replace call to log() by length() to align buffer numbers +# 2010-04-02, Sebastien Helleu <[email protected]>: +# v1.8: fix bug with background color and option indenting_number +# 2010-04-02, Helios <[email protected]>: +# v1.7: add indenting_number option +# 2010-02-25, m4v <[email protected]>: +# v1.6: add option to hide empty prefixes +# 2010-02-12, Sebastien Helleu <[email protected]>: +# v1.5: add optional nick prefix for buffers like IRC channels +# 2009-09-30, Sebastien Helleu <[email protected]>: +# v1.4: remove spaces for indenting when bar position is top/bottom +# 2009-06-14, Sebastien Helleu <[email protected]>: +# v1.3: add option "hide_merged_buffers" +# 2009-06-14, Sebastien Helleu <[email protected]>: +# v1.2: improve display with merged buffers +# 2009-05-02, Sebastien Helleu <[email protected]>: +# v1.1: sync with last API changes +# 2009-02-21, Sebastien Helleu <[email protected]>: +# v1.0: remove timer used to update bar item first time (not needed any more) +# 2009-02-17, Sebastien Helleu <[email protected]>: +# v0.9: fix bug with indenting of private buffers +# 2009-01-04, Sebastien Helleu <[email protected]>: +# v0.8: update syntax for command /set (comments) +# 2008-10-20, Jiri Golembiovsky <[email protected]>: +# v0.7: add indenting option +# 2008-10-01, Sebastien Helleu <[email protected]>: +# v0.6: add default color for buffers, and color for current active buffer +# 2008-09-18, Sebastien Helleu <[email protected]>: +# v0.5: fix color for "low" level entry in hotlist +# 2008-09-18, Sebastien Helleu <[email protected]>: +# v0.4: rename option "show_category" to "short_names", +# remove option "color_slash" +# 2008-09-15, Sebastien Helleu <[email protected]>: +# v0.3: fix bug with priority in hotlist (var not defined) +# 2008-09-02, Sebastien Helleu <[email protected]>: +# 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 <[email protected]>: +# 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 = "4.9"; + +my $BUFFERS_CONFIG_FILE_NAME = "buffers"; +my $buffers_config_file; +my $cmd_buffers_whitelist= "buffers_whitelist"; +my $cmd_buffers_detach = "buffers_detach"; + +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 <flashcode\@flashtux.org>", + $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", "", "", "" + ], + "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. A query and ". + "highlight message will attach buffer again. Allows \"*\" wildcard. ". + "Ex: \"BitlBee,freenode.*\"", + "", 0, 0, "", "", 0, + "", "", "buffers_signal_config_detach_buffer_immediately", "", "", "" + ], + "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 + + 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"}} < 2) ); # 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){ + $name = encode("UTF-8", substr(decode("UTF-8", $name), 0, weechat::config_integer($options{"name_size_max"}))); + } + 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 + { + my $indent = ""; + $indent = ((" " x length($buffer->{"number"}))." ") if (($position eq "left") || ($position eq "right")); + $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 .= " "; + } + 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 .= " "; + }else + { + $str .= ( (" " x ( $max_number_digits - length($buffer->{"number"}) ))." " ); + } + } + } + } + + $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 + { + $str .= encode("UTF-8", substr(decode("UTF-8", $name), 0, weechat::config_integer($options{"name_size_max"}))); + $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; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat/perl/autoload/iset.pl Wed Nov 19 19:24:17 2014 +0100 @@ -0,0 +1,1462 @@ +# +# Copyright (C) 2008-2014 Sebastien Helleu <[email protected]> +# Copyright (C) 2010-2014 Nils Görs <[email protected]> +# +# 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 <http://www.gnu.org/licenses/>. +# +# Set WeeChat and plugins options interactively. +# +# History: +# +# 2014-09-30, arza <[email protected]>: +# version 3.6: fix current line counter when options aren't found +# 2014-06-03, nils_2 <[email protected]>: +# version 3.5: add new option "use_mute" +# 2014-01-30, stfn <[email protected]>: +# version 3.4: add new options "color_value_diff" and "color_value_diff_selected" +# 2014-01-16, luz <[email protected]>: +# version 3.3: fix bug with column alignment in iset buffer when option +# name contains unicode characters +# 2013-08-03, Sebastien Helleu <[email protected]>: +# version 3.2: allow "q" as input in iset buffer to close it +# 2013-07-14, Sebastien Helleu <[email protected]>: +# 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 <[email protected]>: +# version 3.0: simpler title, fix refresh on unset +# 2012-12-16, nils_2 <[email protected]>: +# version 2.9: fix focus window with iset buffer on mouse click +# 2012-08-25, nils_2 <[email protected]>: +# version 2.8: most important key and mouse bindings for iset buffer added to title-bar (idea The-Compiler) +# 2012-07-31, nils_2 <[email protected]>: +# 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 <[email protected]>: +# version 2.6: switch to iset buffer (if existing) when command /iset is called with arguments +# 2012-03-17, Sebastien Helleu <[email protected]>: +# version 2.5: fix check of sections when creating config file +# 2012-03-09, Sebastien Helleu <[email protected]>: +# version 2.4: fix reload of config file +# 2012-02-02, nils_2 <[email protected]>: +# 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 <[email protected]>: +# version 2.1: use own config file (iset.conf), fix own help color (used immediately) +# 2011-10-16, nils_2 <[email protected]>: +# 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 <[email protected]>: +# version 1.9: add mouse support, fix iset buffer, fix errors on first load under FreeBSD +# 2011-07-21, nils_2 <[email protected]>: +# 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 <[email protected]>: +# 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 <[email protected]>: +# 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 <[email protected]>: +# version 1.5: use new help format for command arguments +# 2011-02-03, nils_2 <[email protected]>: +# version 1.4: fixed: restore value filter after /upgrade using buffer local variable. +# 2011-01-14, nils_2 <[email protected]>: +# version 1.3: added function to search for values (option value_search_char). +# code optimization. +# 2010-12-26, Sebastien Helleu <[email protected]>: +# 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 <[email protected]>: +# version 1.1.1: fix bugs with cursor position +# 2010-11-20, nils_2 <[email protected]>: +# version 1.1: cursor position set to value +# 2010-08-03, Sebastien Helleu <[email protected]>: +# version 1.0: move misplaced call to infolist_free() +# 2010-02-02, rettub <[email protected]>: +# version 0.9: turn all the help stuff off if option 'show_help_bar' is 'off', +# new key binding <alt>-<v> to toggle help_bar and help stuff on/off +# 2010-01-30, nils_2 <[email protected]>: +# version 0.8: fix error when option does not exist +# 2010-01-24, Sebastien Helleu <[email protected]>: +# version 0.7: display iset bar only on iset buffer +# 2010-01-22, nils_2 <[email protected]> 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 <[email protected]>: +# version 0.5: fix bug with iset buffer after /upgrade +# 2009-05-02, Sebastien Helleu <[email protected]>: +# version 0.4: sync with last API changes +# 2009-01-04, Sebastien Helleu <[email protected]>: +# version 0.3: open iset buffer when /iset command is executed +# 2009-01-04, Sebastien Helleu <[email protected]>: +# 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 <[email protected]>: +# version 0.1: first official version +# 2008-04-19, Sebastien Helleu <[email protected]>: +# script creation + +use strict; + +my $PRGNAME = "iset"; +my $VERSION = "3.6"; +my $DESCR = "Interactive Set for configuration options"; +my $AUTHOR = "Sebastien Helleu <flashcode\@flashtux.org>"; +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_types = (); +my @options_values = (); +my @options_default_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 +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 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]); + 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); + } + } + 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_types = (); + @options_values = (); + @options_default_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"); + 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 $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}{"type"} = $type; + $options_internal{$name}{"value"} = $value; + $options_internal{$name}{"default_value"} = $default_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}{"type"} = $type; + $options_internal{$name}{"value"} = $value; + $options_internal{$name}{"default_value"} = $default_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_types, $options_internal{$name}{"type"}); + push(@options_values, $options_internal{$name}{"value"}); + push(@options_default_values, $options_internal{$name}{"default_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_types = (); + @options_values = (); + @options_default_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"); + 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"); + if ($search_mode) + { + if ( grep /\Q$var_value/,lc($value) ) + { + $options_internal{$name}{"type"} = $type; + $options_internal{$name}{"value"} = $value; + $options_internal{$name}{"default_value"} = $default_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}{"type"} = $type; + $options_internal{$name}{"value"} = $value; + $options_internal{$name}{"default_value"} = $default_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_types, $options_internal{$name}{"type"}); + push(@options_values, $options_internal{$name}{"value"}); + push(@options_default_values, $options_internal{$name}{"default_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 = ""; + if ($options_is_null[$y]) + { + $color3 = weechat::color(weechat::config_color($options_iset{"color_value_undef"})); + } + 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"})); + } + 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]; + $value = "(undef)" if ($options_is_null[$y]); + 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_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 + my $infolist = weechat::infolist_get("option", "", $option_name); + if ($infolist) + { + weechat::infolist_next($infolist); + if (weechat::infolist_fields($infolist)) + { + $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"); + 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); + } + } + 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; + 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 + } + } + 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 = "null"; + } + else + { + $quote = "\"" if ($options_types[$current_line] eq "string"); + } + my $set_command = "/set"; + $set_command = "/mute " . $set_command if (weechat::config_boolean($options_iset{"use_mute"}) == 1); + + weechat::buffer_set($iset_buffer, "input", $set_command." ".$options_names[$current_line]." ".$quote.$value.$quote); + weechat::command($iset_buffer, "/input move_beginning_of_line"); + weechat::command($iset_buffer, "/input move_next_word"); + weechat::command($iset_buffer, "/input move_next_word"); + weechat::command($iset_buffer, "/input move_next_word") if (weechat::config_boolean($options_iset{"use_mute"}) == 1); + weechat::command($iset_buffer, "/input move_next_char"); + weechat::command($iset_buffer, "/input move_next_char") if ($quote ne ""); + } + } + 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]}); + + 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", "f <file> || s <section> || [=][=]<text>", + "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". + "\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 options for file 'weechat'\n". + " /iset f weechat\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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat/perl/buffers.pl Wed Nov 19 19:24:17 2014 +0100 @@ -0,0 +1,1785 @@ +# +# Copyright (C) 2008-2014 Sebastien Helleu <[email protected]> +# Copyright (C) 2011-2013 Nils G <[email protected]> +# +# 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 <http://www.gnu.org/licenses/>. +# +# +# Display sidebar with list of buffers. +# +# History: +# +# 2014-08-29, Patrick Steinhardt <[email protected]>: +# v4.9: add support for specifying custom buffer names +# 2014-07-19, Sebastien Helleu <[email protected]>: +# v4.8: add support of ctrl + mouse wheel to jump to previous/next buffer, +# new option "mouse_wheel" +# 2014-06-22, Sebastien Helleu <[email protected]>: +# v4.7: fix typos in options +# 2014-04-05, Sebastien Helleu <[email protected]>: +# v4.6: add support of hidden buffers (WeeChat >= 0.4.4) +# 2014-01-01, Sebastien Helleu <[email protected]>: +# v4.5: add option "mouse_move_buffer" +# 2013-12-11, Sebastien Helleu <[email protected]>: +# 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 <[email protected]>: +# 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 <anti.teamidiot.de>: +# v3.7: call menu on right mouse if menu script is loaded. +# 2012-10-06, nils_2 <[email protected]>: +# v3.6: add new option "hotlist_counter" (idea by torque). +# 2012-06-02, nils_2 <[email protected]>: +# v3.5: add values "server|channel|private|all|keepserver|none" to option "hide_merged_buffers" (suggested by dominikh). +# 2012-05-25, nils_2 <[email protected]>: +# v3.4: add new option "show_lag". +# 2012-04-07, Sebastien Helleu <[email protected]>: +# v3.3: fix truncation of wide chars in buffer name (option name_size_max) (bug #36034) +# 2012-03-15, nils_2 <[email protected]>: +# 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 <[email protected]>: +# v3.1: fix reload of config file +# 2012-01-29, nils_2 <[email protected]>: +# v3.0: fix: buffers did not update directly during window_switch (reported by FiXato) +# 2012-01-29, nils_2 <[email protected]>: +# v2.9: add options "name_size_max" and "name_crop_suffix" +# 2012-01-08, nils_2 <[email protected]>: +# 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 <[email protected]>: +# v2.7: fix regex lookup in whitelist buffers list +# 2011-12-04, nils_2 <[email protected]>: +# 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 <[email protected]>: +# v2.5: add new options "show_number_char" and "color_number_char", +# add help-description for options +# 2011-08-24, Sebastien Helleu <[email protected]>: +# v2.4: add mouse support +# 2011-06-06, nils_2 <[email protected]>: +# v2.3: added: missed option "color_whitelist_default" +# 2011-03-23, Sebastien Helleu <[email protected]>: +# v2.2: fix color of nick prefix with WeeChat >= 0.3.5 +# 2011-02-13, nils_2 <[email protected]>: +# v2.1: add options "color_whitelist_*" +# 2010-10-05, Sebastien Helleu <[email protected]>: +# v2.0: add options "sort" and "show_number" +# 2010-04-12, Sebastien Helleu <[email protected]>: +# v1.9: replace call to log() by length() to align buffer numbers +# 2010-04-02, Sebastien Helleu <[email protected]>: +# v1.8: fix bug with background color and option indenting_number +# 2010-04-02, Helios <[email protected]>: +# v1.7: add indenting_number option +# 2010-02-25, m4v <[email protected]>: +# v1.6: add option to hide empty prefixes +# 2010-02-12, Sebastien Helleu <[email protected]>: +# v1.5: add optional nick prefix for buffers like IRC channels +# 2009-09-30, Sebastien Helleu <[email protected]>: +# v1.4: remove spaces for indenting when bar position is top/bottom +# 2009-06-14, Sebastien Helleu <[email protected]>: +# v1.3: add option "hide_merged_buffers" +# 2009-06-14, Sebastien Helleu <[email protected]>: +# v1.2: improve display with merged buffers +# 2009-05-02, Sebastien Helleu <[email protected]>: +# v1.1: sync with last API changes +# 2009-02-21, Sebastien Helleu <[email protected]>: +# v1.0: remove timer used to update bar item first time (not needed any more) +# 2009-02-17, Sebastien Helleu <[email protected]>: +# v0.9: fix bug with indenting of private buffers +# 2009-01-04, Sebastien Helleu <[email protected]>: +# v0.8: update syntax for command /set (comments) +# 2008-10-20, Jiri Golembiovsky <[email protected]>: +# v0.7: add indenting option +# 2008-10-01, Sebastien Helleu <[email protected]>: +# v0.6: add default color for buffers, and color for current active buffer +# 2008-09-18, Sebastien Helleu <[email protected]>: +# v0.5: fix color for "low" level entry in hotlist +# 2008-09-18, Sebastien Helleu <[email protected]>: +# v0.4: rename option "show_category" to "short_names", +# remove option "color_slash" +# 2008-09-15, Sebastien Helleu <[email protected]>: +# v0.3: fix bug with priority in hotlist (var not defined) +# 2008-09-02, Sebastien Helleu <[email protected]>: +# 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 <[email protected]>: +# 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 = "4.9"; + +my $BUFFERS_CONFIG_FILE_NAME = "buffers"; +my $buffers_config_file; +my $cmd_buffers_whitelist= "buffers_whitelist"; +my $cmd_buffers_detach = "buffers_detach"; + +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 <flashcode\@flashtux.org>", + $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", "", "", "" + ], + "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. A query and ". + "highlight message will attach buffer again. Allows \"*\" wildcard. ". + "Ex: \"BitlBee,freenode.*\"", + "", 0, 0, "", "", 0, + "", "", "buffers_signal_config_detach_buffer_immediately", "", "", "" + ], + "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 + + 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"}} < 2) ); # 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){ + $name = encode("UTF-8", substr(decode("UTF-8", $name), 0, weechat::config_integer($options{"name_size_max"}))); + } + 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 + { + my $indent = ""; + $indent = ((" " x length($buffer->{"number"}))." ") if (($position eq "left") || ($position eq "right")); + $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 .= " "; + } + 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 .= " "; + }else + { + $str .= ( (" " x ( $max_number_digits - length($buffer->{"number"}) ))." " ); + } + } + } + } + + $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 + { + $str .= encode("UTF-8", substr(decode("UTF-8", $name), 0, weechat::config_integer($options{"name_size_max"}))); + $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; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat/perl/iset.pl Wed Nov 19 19:24:17 2014 +0100 @@ -0,0 +1,1462 @@ +# +# Copyright (C) 2008-2014 Sebastien Helleu <[email protected]> +# Copyright (C) 2010-2014 Nils Görs <[email protected]> +# +# 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 <http://www.gnu.org/licenses/>. +# +# Set WeeChat and plugins options interactively. +# +# History: +# +# 2014-09-30, arza <[email protected]>: +# version 3.6: fix current line counter when options aren't found +# 2014-06-03, nils_2 <[email protected]>: +# version 3.5: add new option "use_mute" +# 2014-01-30, stfn <[email protected]>: +# version 3.4: add new options "color_value_diff" and "color_value_diff_selected" +# 2014-01-16, luz <[email protected]>: +# version 3.3: fix bug with column alignment in iset buffer when option +# name contains unicode characters +# 2013-08-03, Sebastien Helleu <[email protected]>: +# version 3.2: allow "q" as input in iset buffer to close it +# 2013-07-14, Sebastien Helleu <[email protected]>: +# 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 <[email protected]>: +# version 3.0: simpler title, fix refresh on unset +# 2012-12-16, nils_2 <[email protected]>: +# version 2.9: fix focus window with iset buffer on mouse click +# 2012-08-25, nils_2 <[email protected]>: +# version 2.8: most important key and mouse bindings for iset buffer added to title-bar (idea The-Compiler) +# 2012-07-31, nils_2 <[email protected]>: +# 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 <[email protected]>: +# version 2.6: switch to iset buffer (if existing) when command /iset is called with arguments +# 2012-03-17, Sebastien Helleu <[email protected]>: +# version 2.5: fix check of sections when creating config file +# 2012-03-09, Sebastien Helleu <[email protected]>: +# version 2.4: fix reload of config file +# 2012-02-02, nils_2 <[email protected]>: +# 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 <[email protected]>: +# version 2.1: use own config file (iset.conf), fix own help color (used immediately) +# 2011-10-16, nils_2 <[email protected]>: +# 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 <[email protected]>: +# version 1.9: add mouse support, fix iset buffer, fix errors on first load under FreeBSD +# 2011-07-21, nils_2 <[email protected]>: +# 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 <[email protected]>: +# 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 <[email protected]>: +# 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 <[email protected]>: +# version 1.5: use new help format for command arguments +# 2011-02-03, nils_2 <[email protected]>: +# version 1.4: fixed: restore value filter after /upgrade using buffer local variable. +# 2011-01-14, nils_2 <[email protected]>: +# version 1.3: added function to search for values (option value_search_char). +# code optimization. +# 2010-12-26, Sebastien Helleu <[email protected]>: +# 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 <[email protected]>: +# version 1.1.1: fix bugs with cursor position +# 2010-11-20, nils_2 <[email protected]>: +# version 1.1: cursor position set to value +# 2010-08-03, Sebastien Helleu <[email protected]>: +# version 1.0: move misplaced call to infolist_free() +# 2010-02-02, rettub <[email protected]>: +# version 0.9: turn all the help stuff off if option 'show_help_bar' is 'off', +# new key binding <alt>-<v> to toggle help_bar and help stuff on/off +# 2010-01-30, nils_2 <[email protected]>: +# version 0.8: fix error when option does not exist +# 2010-01-24, Sebastien Helleu <[email protected]>: +# version 0.7: display iset bar only on iset buffer +# 2010-01-22, nils_2 <[email protected]> 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 <[email protected]>: +# version 0.5: fix bug with iset buffer after /upgrade +# 2009-05-02, Sebastien Helleu <[email protected]>: +# version 0.4: sync with last API changes +# 2009-01-04, Sebastien Helleu <[email protected]>: +# version 0.3: open iset buffer when /iset command is executed +# 2009-01-04, Sebastien Helleu <[email protected]>: +# 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 <[email protected]>: +# version 0.1: first official version +# 2008-04-19, Sebastien Helleu <[email protected]>: +# script creation + +use strict; + +my $PRGNAME = "iset"; +my $VERSION = "3.6"; +my $DESCR = "Interactive Set for configuration options"; +my $AUTHOR = "Sebastien Helleu <flashcode\@flashtux.org>"; +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_types = (); +my @options_values = (); +my @options_default_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 +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 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]); + 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); + } + } + 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_types = (); + @options_values = (); + @options_default_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"); + 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 $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}{"type"} = $type; + $options_internal{$name}{"value"} = $value; + $options_internal{$name}{"default_value"} = $default_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}{"type"} = $type; + $options_internal{$name}{"value"} = $value; + $options_internal{$name}{"default_value"} = $default_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_types, $options_internal{$name}{"type"}); + push(@options_values, $options_internal{$name}{"value"}); + push(@options_default_values, $options_internal{$name}{"default_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_types = (); + @options_values = (); + @options_default_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"); + 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"); + if ($search_mode) + { + if ( grep /\Q$var_value/,lc($value) ) + { + $options_internal{$name}{"type"} = $type; + $options_internal{$name}{"value"} = $value; + $options_internal{$name}{"default_value"} = $default_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}{"type"} = $type; + $options_internal{$name}{"value"} = $value; + $options_internal{$name}{"default_value"} = $default_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_types, $options_internal{$name}{"type"}); + push(@options_values, $options_internal{$name}{"value"}); + push(@options_default_values, $options_internal{$name}{"default_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 = ""; + if ($options_is_null[$y]) + { + $color3 = weechat::color(weechat::config_color($options_iset{"color_value_undef"})); + } + 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"})); + } + 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]; + $value = "(undef)" if ($options_is_null[$y]); + 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_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 + my $infolist = weechat::infolist_get("option", "", $option_name); + if ($infolist) + { + weechat::infolist_next($infolist); + if (weechat::infolist_fields($infolist)) + { + $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"); + 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); + } + } + 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; + 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 + } + } + 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 = "null"; + } + else + { + $quote = "\"" if ($options_types[$current_line] eq "string"); + } + my $set_command = "/set"; + $set_command = "/mute " . $set_command if (weechat::config_boolean($options_iset{"use_mute"}) == 1); + + weechat::buffer_set($iset_buffer, "input", $set_command." ".$options_names[$current_line]." ".$quote.$value.$quote); + weechat::command($iset_buffer, "/input move_beginning_of_line"); + weechat::command($iset_buffer, "/input move_next_word"); + weechat::command($iset_buffer, "/input move_next_word"); + weechat::command($iset_buffer, "/input move_next_word") if (weechat::config_boolean($options_iset{"use_mute"}) == 1); + weechat::command($iset_buffer, "/input move_next_char"); + weechat::command($iset_buffer, "/input move_next_char") if ($quote ne ""); + } + } + 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]}); + + 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", "f <file> || s <section> || [=][=]<text>", + "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". + "\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 options for file 'weechat'\n". + " /iset f weechat\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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat/weechat.conf Wed Nov 19 19:24:17 2014 +0100 @@ -0,0 +1,893 @@ +# +# weechat.conf -- weechat v1.0.1 +# + +[debug] + +[startup] +command_after_plugins = "" +command_before_plugins = "" +display_logo = on +display_version = on +sys_rlimit = "" + +[look] +align_end_of_lines = message +bar_more_down = "▼" +bar_more_left = "◀" +bar_more_right = "▶" +bar_more_up = "▲" +bare_display_exit_on_input = on +bare_display_time_format = "%H:%M" +buffer_auto_renumber = on +buffer_notify_default = all +buffer_position = end +buffer_search_case_sensitive = off +buffer_search_force_default = off +buffer_search_regex = off +buffer_search_where = message +buffer_time_format = " " +color_basic_force_bold = off +color_inactive_buffer = off +color_inactive_message = off +color_inactive_prefix = on +color_inactive_prefix_buffer = on +color_inactive_time = off +color_inactive_window = off +color_nick_offline = off +color_pairs_auto_reset = 5 +color_real_white = off +command_chars = "" +confirm_quit = off +day_change = on +day_change_message_1date = "-- %a, %d %b %Y --" +day_change_message_2dates = "-- %%a, %%d %%b %%Y (%a, %d %b %Y) --" +eat_newline_glitch = off +emphasized_attributes = "" +highlight = "zeger,zegervdv" +highlight_regex = "" +highlight_tags = "" +hotlist_add_conditions = "${away} || ${buffer.num_displayed} == 0" +hotlist_buffer_separator = ", " +hotlist_count_max = 2 +hotlist_count_min_msg = 2 +hotlist_names_count = 3 +hotlist_names_length = 0 +hotlist_names_level = 12 +hotlist_names_merged_buffers = off +hotlist_prefix = "H: " +hotlist_remove = merged +hotlist_short_names = on +hotlist_sort = group_time_asc +hotlist_suffix = "" +hotlist_unique_numbers = on +input_cursor_scroll = 20 +input_share = none +input_share_overwrite = off +input_undo_max = 32 +item_buffer_filter = "⚑" +item_buffer_zoom = "!" +item_time_format = "%H:%M" +jump_current_to_previous_buffer = on +jump_previous_buffer_when_closing = on +jump_smart_back_to_buffer = on +key_bind_safe = on +mouse = off +mouse_timer_delay = 100 +nick_prefix = "" +nick_suffix = "" +paste_bracketed = off +paste_bracketed_timer_delay = 10 +paste_max_lines = 1 +prefix_action = "⚡" +prefix_align = right +prefix_align_max = 10 +prefix_align_min = 10 +prefix_align_more = " " +prefix_align_more_after = on +prefix_buffer_align = right +prefix_buffer_align_max = 0 +prefix_buffer_align_more = "+" +prefix_buffer_align_more_after = on +prefix_error = "⚠ " +prefix_join = "◥" +prefix_network = "ℹ " +prefix_quit = "◣" +prefix_same_nick = "" +prefix_suffix = "│" +read_marker = line +read_marker_always_show = off +read_marker_string = "" +save_config_on_exit = on +save_layout_on_exit = none +scroll_amount = 3 +scroll_bottom_after_switch = off +scroll_page_percent = 100 +search_text_not_found_alert = on +separator_horizontal = "" +separator_vertical = "" +tab_width = 1 +time_format = "%a, %d %b %Y %T" +window_auto_zoom = off +window_separator_horizontal = on +window_separator_vertical = on +window_title = "WeeChat" + +[palette] +100 = "" +101 = "" +102 = "" +103 = "" +104 = "" +105 = "" +106 = "" +107 = "" +108 = "" +109 = "" +110 = "" +111 = "" +112 = "" +113 = "" +114 = "" +115 = "" +116 = "" +117 = "" +118 = "" +119 = "" +120 = "" +121 = "" +122 = "" +123 = "" +124 = "" +125 = "" +126 = "" +127 = "" +128 = "" +129 = "" +130 = "" +131 = "" +132 = "" +133 = "" +134 = "" +135 = "" +136 = "" +137 = "" +138 = "" +139 = "" +140 = "" +141 = "" +142 = "" +143 = "" +144 = "" +145 = "" +146 = "" +147 = "" +148 = "" +149 = "" +150 = "" +151 = "" +152 = "" +153 = "" +154 = "" +155 = "" +156 = "" +157 = "" +158 = "" +159 = "" +160 = "" +161 = "" +162 = "" +163 = "" +164 = "" +165 = "" +166 = "" +167 = "" +168 = "" +169 = "" +17 = "" +170 = "" +171 = "" +172 = "" +173 = "" +174 = "" +175 = "" +176 = "" +177 = "" +178 = "" +179 = "" +18 = "" +180 = "" +181 = "" +182 = "" +183 = "" +184 = "" +185 = "" +186 = "" +187 = "" +188 = "" +189 = "" +19 = "" +190 = "" +191 = "" +192 = "" +193 = "" +194 = "" +195 = "" +196 = "" +197 = "" +198 = "" +199 = "" +20 = "" +200 = "" +201 = "" +202 = "" +203 = "" +204 = "" +205 = "" +206 = "" +207 = "" +208 = "" +209 = "" +21 = "" +210 = "" +211 = "" +212 = "" +213 = "" +214 = "" +215 = "" +216 = "" +217 = "" +218 = "" +219 = "" +22 = "" +220 = "" +221 = "" +222 = "" +223 = "" +224 = "" +225 = "" +226 = "" +227 = "" +228 = "" +229 = "" +23 = "" +230 = "" +231 = "" +232 = "" +233 = "" +234 = "" +235 = "" +236 = "" +237 = "" +238 = "" +239 = "" +24 = "" +240 = "" +241 = "" +242 = "" +243 = "" +244 = "" +245 = "" +246 = "" +247 = "" +248 = "" +249 = "" +25 = "" +250 = "" +251 = "" +252 = "" +253 = "" +254 = "" +255 = "" +256 = "" +26 = "" +27 = "" +28 = "" +29 = "" +30 = "" +31 = "" +32 = "" +33 = "" +34 = "" +35 = "" +36 = "" +37 = "" +38 = "" +39 = "" +40 = "" +41 = "" +42 = "" +43 = "" +44 = "" +45 = "" +46 = "" +47 = "" +48 = "" +49 = "" +50 = "" +51 = "" +52 = "" +53 = "" +54 = "" +55 = "" +56 = "" +57 = "" +58 = "" +59 = "" +60 = "" +61 = "" +62 = "" +63 = "" +64 = "" +65 = "" +66 = "" +67 = "" +68 = "" +69 = "" +70 = "" +71 = "" +72 = "" +73 = "" +74 = "" +75 = "" +76 = "" +77 = "" +78 = "" +79 = "" +80 = "" +81 = "" +82 = "" +83 = "" +84 = "" +85 = "" +86 = "" +87 = "" +88 = "" +89 = "" +90 = "" +91 = "" +92 = "" +93 = "" +94 = "" +95 = "" +96 = "" +97 = "" +98 = "" +99 = "" + +[color] +bar_more = lightmagenta +chat = default +chat_bg = default +chat_buffer = white +chat_channel = gray +chat_day_change = cyan +chat_delimiters = default +chat_highlight = default +chat_highlight_bg = default +chat_host = cyan +chat_inactive_buffer = darkgray +chat_inactive_window = darkgray +chat_nick = lightcyan +chat_nick_colors = "darkgray,red,lightred,green,lightgreen,blue,lightblue,brown,cyan,lightcyan,magenta" +chat_nick_offline = darkgray +chat_nick_offline_highlight = default +chat_nick_offline_highlight_bg = darkgray +chat_nick_other = cyan +chat_nick_prefix = green +chat_nick_self = darkgray +chat_nick_suffix = green +chat_prefix_action = white +chat_prefix_buffer = brown +chat_prefix_buffer_inactive_buffer = darkgray +chat_prefix_error = yellow +chat_prefix_join = darkgray +chat_prefix_more = lightmagenta +chat_prefix_network = magenta +chat_prefix_quit = gray +chat_prefix_suffix = gray +chat_read_marker = gray +chat_read_marker_bg = default +chat_server = brown +chat_tags = red +chat_text_found = yellow +chat_text_found_bg = lightmagenta +chat_time = gray +chat_time_delimiters = gray +chat_value = cyan +emphasized = yellow +emphasized_bg = magenta +input_actions = lightgreen +input_text_not_found = red +nicklist_away = cyan +nicklist_group = green +nicklist_offline = blue +separator = gray +status_count_highlight = magenta +status_count_msg = brown +status_count_other = default +status_count_private = green +status_data_highlight = lightmagenta +status_data_msg = yellow +status_data_other = default +status_data_private = lightgreen +status_filter = green +status_more = yellow +status_name = darkgray +status_name_ssl = lightgreen +status_nicklist_count = default +status_number = yellow +status_time = default + +[completion] +base_word_until_cursor = on +default_template = "%(nicks)|%(irc_channels)" +nick_add_space = on +nick_completer = ":" +nick_first_only = off +nick_ignore_chars = "[]`_-^" +partial_completion_alert = on +partial_completion_command = off +partial_completion_command_arg = off +partial_completion_count = on +partial_completion_other = off + +[history] +display_default = 5 +max_buffer_lines_minutes = 0 +max_buffer_lines_number = 4096 +max_commands = 100 +max_visited_buffers = 50 + +[proxy] + +[network] +connection_timeout = 60 +gnutls_ca_file = "/usr/share/curl/ca-bundle.crt" +gnutls_handshake_timeout = 30 +proxy_curl = "" + +[plugin] +autoload = "*" +debug = off +extension = ".so,.dll" +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 = horizontal +buffers.hidden = on +buffers.items = "buffers" +buffers.position = top +buffers.priority = 0 +buffers.separator = off +buffers.size = 0 +buffers.size_max = 0 +buffers.type = root +input.color_bg = default +input.color_delim = red +input.color_fg = default +input.conditions = "active" +input.filling_left_right = vertical +input.filling_top_bottom = horizontal +input.hidden = off +input.items = "+ » +,input_text" +input.position = bottom +input.priority = 1000 +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 = darkgray +nicklist.conditions = "${active}" +nicklist.filling_left_right = vertical +nicklist.filling_top_bottom = columns_vertical +nicklist.hidden = on +nicklist.items = "buffer_nicklist" +nicklist.position = right +nicklist.priority = 200 +nicklist.separator = on +nicklist.size = 0 +nicklist.size_max = 0 +nicklist.type = window +rootinput.color_bg = default +rootinput.color_delim = red +rootinput.color_fg = default +rootinput.conditions = "" +rootinput.filling_left_right = vertical +rootinput.filling_top_bottom = horizontal +rootinput.hidden = on +rootinput.items = "+ » +,input_text" +rootinput.position = bottom +rootinput.priority = 0 +rootinput.separator = off +rootinput.size = 1 +rootinput.size_max = 0 +rootinput.type = root +spacer.color_bg = default +spacer.color_delim = gray +spacer.color_fg = gray +spacer.conditions = "inactive" +spacer.filling_left_right = vertical +spacer.filling_top_bottom = horizontal +spacer.hidden = off +spacer.items = "+ +irc_channel+ (+buffer_plugin+)" +spacer.position = bottom +spacer.priority = 1100 +spacer.separator = off +spacer.size = 0 +spacer.size_max = 0 +spacer.type = window +spacer2.color_bg = default +spacer2.color_delim = default +spacer2.color_fg = default +spacer2.conditions = "" +spacer2.filling_left_right = vertical +spacer2.filling_top_bottom = horizontal +spacer2.hidden = off +spacer2.items = "+ +" +spacer2.position = top +spacer2.priority = 0 +spacer2.separator = off +spacer2.size = 0 +spacer2.size_max = 0 +spacer2.type = window +status.color_bg = default +status.color_delim = cyan +status.color_fg = default +status.conditions = "" +status.filling_left_right = vertical +status.filling_top_bottom = horizontal +status.hidden = off +status.items = "\n" +status.position = bottom +status.priority = 500 +status.separator = off +status.size = 1 +status.size_max = 0 +status.type = window +title.color_bg = default +title.color_delim = white +title.color_fg = blue +title.conditions = "" +title.filling_left_right = vertical +title.filling_top_bottom = horizontal +title.hidden = on +title.items = "buffer_title" +title.position = top +title.priority = 500 +title.separator = off +title.size = 1 +title.size_max = 0 +title.type = window + +[layout] +_zoom.window = "1;0;0;0;irc;freenode.##hackernews" + +[notify] + +[filter] +joinquit = off;*;irc_join,irc_part,irc_quit;* +modes = on;*;irc_324,irc_mode;* +irc_smart = on;*;irc_smart_filter;* + +[key] +ctrl-? = "/input delete_previous_char" +ctrl-A = "/input move_beginning_of_line" +ctrl-B = "/input move_previous_char" +ctrl-C = "/window splith" +ctrl-Cb = "/input insert \x02" +ctrl-Cc = "/input insert \x03" +ctrl-Ci = "/input insert \x1D" +ctrl-Co = "/input insert \x0F" +ctrl-Cr = "/input insert \x12" +ctrl-Cu = "/input insert \x15" +ctrl-D = "/input delete_next_char" +ctrl-E = "/input move_end_of_line" +ctrl-F = "/input move_next_char" +ctrl-H = "/window left" +ctrl-I = "/input complete_next" +ctrl-J = "/window down" +ctrl-K = "/window up" +ctrl-L = "/window right" +ctrl-M = "/input return" +ctrl-N = "/buffer +1" +ctrl-P = "/buffer -1" +ctrl-R = "/input search_text" +ctrl-Sctrl-U = "/input set_unread" +ctrl-T = "/input transpose_chars" +ctrl-U = "/input delete_beginning_of_line" +ctrl-W = "/input delete_previous_word" +ctrl-X = "/input switch_active_buffer" +ctrl-Y = "/input clipboard_paste" +meta-meta2-1~ = "/window scroll_top" +meta-meta2-23~ = "/bar scroll nicklist * b" +meta-meta2-24~ = "/bar scroll nicklist * e" +meta-meta2-4~ = "/window scroll_bottom" +meta-meta2-5~ = "/window scroll_up" +meta-meta2-6~ = "/window scroll_down" +meta-meta2-7~ = "/window scroll_top" +meta-meta2-8~ = "/window scroll_bottom" +meta-meta2-A = "/buffer -1" +meta-meta2-B = "/buffer +1" +meta-meta2-C = "/buffer +1" +meta-meta2-D = "/buffer -1" +meta-/ = "/input jump_last_buffer_displayed" +meta-0 = "/buffer *10" +meta-1 = "/buffer *1" +meta-2 = "/buffer *2" +meta-3 = "/buffer *3" +meta-4 = "/buffer *4" +meta-5 = "/buffer *5" +meta-6 = "/buffer *6" +meta-7 = "/buffer *7" +meta-8 = "/buffer *8" +meta-9 = "/buffer *9" +meta-< = "/input jump_previously_visited_buffer" +meta-= = "/filter toggle" +meta-> = "/input jump_next_visited_buffer" +meta-OA = "/input history_global_previous" +meta-OB = "/input history_global_next" +meta-OC = "/input move_next_word" +meta-OD = "/input move_previous_word" +meta-OF = "/input move_end_of_line" +meta-OH = "/input move_beginning_of_line" +meta-Oa = "/input history_global_previous" +meta-Ob = "/input history_global_next" +meta-Oc = "/input move_next_word" +meta-Od = "/input move_previous_word" +meta2-15~ = "/buffer -1" +meta2-17~ = "/buffer +1" +meta2-18~ = "/window -1" +meta2-19~ = "/window +1" +meta2-1;3A = "/buffer -1" +meta2-1;3B = "/buffer +1" +meta2-1;3C = "/buffer +1" +meta2-1;3D = "/buffer -1" +meta2-1;5A = "/input history_global_previous" +meta2-1;5B = "/input history_global_next" +meta2-1;5C = "/input move_next_word" +meta2-1;5D = "/input move_previous_word" +meta2-1~ = "/input move_beginning_of_line" +meta2-200~ = "/input paste_start" +meta2-201~ = "/input paste_stop" +meta2-20~ = "/bar scroll title * -30%" +meta2-21~ = "/bar scroll title * +30%" +meta2-23~ = "/bar scroll nicklist * -100%" +meta2-24~ = "/bar scroll nicklist * +100%" +meta2-3~ = "/input delete_next_char" +meta2-4~ = "/input move_end_of_line" +meta2-5;3~ = "/window scroll_up" +meta2-5~ = "/window page_up" +meta2-6;3~ = "/window scroll_down" +meta2-6~ = "/window page_down" +meta2-7~ = "/input move_beginning_of_line" +meta2-8~ = "/input move_end_of_line" +meta2-A = "/input history_previous" +meta2-B = "/input history_next" +meta2-C = "/input move_next_char" +meta2-D = "/input move_previous_char" +meta2-F = "/input move_end_of_line" +meta2-G = "/window page_down" +meta2-H = "/input move_beginning_of_line" +meta2-I = "/window page_up" +meta2-Z = "/input complete_previous" +meta2-[E = "/buffer -1" +meta-_ = "/input redo" +meta-a = "/input jump_smart" +meta-b = "/input move_previous_word" +meta-d = "/input delete_next_word" +meta-f = "/input move_next_word" +meta-h = "/input hotlist_clear" +meta-jmeta-l = "/input jump_last_buffer" +meta-jmeta-r = "/server raw" +meta-jmeta-s = "/server jump" +meta-j01 = "/buffer 1" +meta-j02 = "/buffer 2" +meta-j03 = "/buffer 3" +meta-j04 = "/buffer 4" +meta-j05 = "/buffer 5" +meta-j06 = "/buffer 6" +meta-j07 = "/buffer 7" +meta-j08 = "/buffer 8" +meta-j09 = "/buffer 9" +meta-j10 = "/buffer 10" +meta-j11 = "/buffer 11" +meta-j12 = "/buffer 12" +meta-j13 = "/buffer 13" +meta-j14 = "/buffer 14" +meta-j15 = "/buffer 15" +meta-j16 = "/buffer 16" +meta-j17 = "/buffer 17" +meta-j18 = "/buffer 18" +meta-j19 = "/buffer 19" +meta-j20 = "/buffer 20" +meta-j21 = "/buffer 21" +meta-j22 = "/buffer 22" +meta-j23 = "/buffer 23" +meta-j24 = "/buffer 24" +meta-j25 = "/buffer 25" +meta-j26 = "/buffer 26" +meta-j27 = "/buffer 27" +meta-j28 = "/buffer 28" +meta-j29 = "/buffer 29" +meta-j30 = "/buffer 30" +meta-j31 = "/buffer 31" +meta-j32 = "/buffer 32" +meta-j33 = "/buffer 33" +meta-j34 = "/buffer 34" +meta-j35 = "/buffer 35" +meta-j36 = "/buffer 36" +meta-j37 = "/buffer 37" +meta-j38 = "/buffer 38" +meta-j39 = "/buffer 39" +meta-j40 = "/buffer 40" +meta-j41 = "/buffer 41" +meta-j42 = "/buffer 42" +meta-j43 = "/buffer 43" +meta-j44 = "/buffer 44" +meta-j45 = "/buffer 45" +meta-j46 = "/buffer 46" +meta-j47 = "/buffer 47" +meta-j48 = "/buffer 48" +meta-j49 = "/buffer 49" +meta-j50 = "/buffer 50" +meta-j51 = "/buffer 51" +meta-j52 = "/buffer 52" +meta-j53 = "/buffer 53" +meta-j54 = "/buffer 54" +meta-j55 = "/buffer 55" +meta-j56 = "/buffer 56" +meta-j57 = "/buffer 57" +meta-j58 = "/buffer 58" +meta-j59 = "/buffer 59" +meta-j60 = "/buffer 60" +meta-j61 = "/buffer 61" +meta-j62 = "/buffer 62" +meta-j63 = "/buffer 63" +meta-j64 = "/buffer 64" +meta-j65 = "/buffer 65" +meta-j66 = "/buffer 66" +meta-j67 = "/buffer 67" +meta-j68 = "/buffer 68" +meta-j69 = "/buffer 69" +meta-j70 = "/buffer 70" +meta-j71 = "/buffer 71" +meta-j72 = "/buffer 72" +meta-j73 = "/buffer 73" +meta-j74 = "/buffer 74" +meta-j75 = "/buffer 75" +meta-j76 = "/buffer 76" +meta-j77 = "/buffer 77" +meta-j78 = "/buffer 78" +meta-j79 = "/buffer 79" +meta-j80 = "/buffer 80" +meta-j81 = "/buffer 81" +meta-j82 = "/buffer 82" +meta-j83 = "/buffer 83" +meta-j84 = "/buffer 84" +meta-j85 = "/buffer 85" +meta-j86 = "/buffer 86" +meta-j87 = "/buffer 87" +meta-j88 = "/buffer 88" +meta-j89 = "/buffer 89" +meta-j90 = "/buffer 90" +meta-j91 = "/buffer 91" +meta-j92 = "/buffer 92" +meta-j93 = "/buffer 93" +meta-j94 = "/buffer 94" +meta-j95 = "/buffer 95" +meta-j96 = "/buffer 96" +meta-j97 = "/buffer 97" +meta-j98 = "/buffer 98" +meta-j99 = "/buffer 99" +meta-k = "/input grab_key_command" +meta-m = "/mute mouse toggle" +meta-n = "/window scroll_next_highlight" +meta-p = "/window scroll_previous_highlight" +meta-r = "/input delete_line" +meta-s = "/mute aspell toggle" +meta-u = "/window scroll_unread" +meta-wmeta-meta2-A = "/window up" +meta-wmeta-meta2-B = "/window down" +meta-wmeta-meta2-C = "/window right" +meta-wmeta-meta2-D = "/window left" +meta-wmeta2-1;3A = "/window up" +meta-wmeta2-1;3B = "/window down" +meta-wmeta2-1;3C = "/window right" +meta-wmeta2-1;3D = "/window left" +meta-wmeta-b = "/window balance" +meta-wmeta-s = "/window swap" +meta-x = "/input zoom_merged_buffer" +meta-z = "/window zoom" +ctrl-_ = "/input undo" + +[key_search] +ctrl-I = "/input search_switch_where" +ctrl-J = "/input search_stop" +ctrl-M = "/input search_stop" +ctrl-R = "/input search_switch_regex" +meta2-A = "/input search_previous" +meta2-B = "/input search_next" +meta-c = "/input search_switch_case" + +[key_cursor] +ctrl-J = "/cursor stop" +ctrl-M = "/cursor stop" +meta-meta2-A = "/cursor move area_up" +meta-meta2-B = "/cursor move area_down" +meta-meta2-C = "/cursor move area_right" +meta-meta2-D = "/cursor move area_left" +meta2-1;3A = "/cursor move area_up" +meta2-1;3B = "/cursor move area_down" +meta2-1;3C = "/cursor move area_right" +meta2-1;3D = "/cursor move area_left" +meta2-A = "/cursor move up" +meta2-B = "/cursor move down" +meta2-C = "/cursor move right" +meta2-D = "/cursor move left" +@item(buffer_nicklist):K = "/window ${_window_number};/kickban ${nick}" +@item(buffer_nicklist):b = "/window ${_window_number};/ban ${nick}" +@item(buffer_nicklist):k = "/window ${_window_number};/kick ${nick}" +@item(buffer_nicklist):q = "/window ${_window_number};/query ${nick};/cursor stop" +@item(buffer_nicklist):w = "/window ${_window_number};/whois ${nick}" +@chat:Q = "hsignal:chat_quote_time_prefix_message;/cursor stop" +@chat:m = "hsignal:chat_quote_message;/cursor stop" +@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" +@chat(script.scripts):wheelup = "/script up 5" +@item(buffer_nicklist):button1 = "/window ${_window_number};/query ${nick}" +@item(buffer_nicklist):button1-gesture-left = "/window ${_window_number};/kick ${nick}" +@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}" +@chat:button1-gesture-left = "/window ${_window_number};/buffer -1" +@chat:button1-gesture-left-long = "/window ${_window_number};/buffer 1" +@chat:button1-gesture-right = "/window ${_window_number};/buffer +1" +@chat:button1-gesture-right-long = "/window ${_window_number};/input jump_last_buffer" +@chat:ctrl-wheeldown = "/window scroll_horiz -window ${_window_number} +10%" +@chat:ctrl-wheelup = "/window scroll_horiz -window ${_window_number} -10%" +@chat:wheeldown = "/window scroll_down -window ${_window_number}" +@chat:wheelup = "/window scroll_up -window ${_window_number}" +@*:button3 = "/cursor go ${_x},${_y}"