From 1b930379b616a121714bc62fce5a202e52409ceb Mon Sep 17 00:00:00 2001 From: Stefan Huber Date: Tue, 6 Nov 2012 14:12:00 +0100 Subject: [PATCH] renames, add irssi scripts --- {conky => dotfiles/conky}/showmounts.sh | 0 dotfiles/irssi/config | 313 +++ dotfiles/irssi/config-sthu | 380 +++ dotfiles/irssi/default.theme | 294 ++ dotfiles/irssi/envy.theme | 514 ++++ dotfiles/irssi/scripts/adv_windowlist.pl | 2478 +++++++++++++++++ .../irssi/scripts/autorun/adv_windowlist.pl | 1 + dotfiles/irssi/scripts/autorun/hilightwin.pl | 1 + dotfiles/irssi/scripts/autorun/niq.pl | 1 + dotfiles/irssi/scripts/autorun/nm.pl | 1 + dotfiles/irssi/scripts/autorun/postpone.pl | 1 + dotfiles/irssi/scripts/autorun/screen_away.pl | 1 + dotfiles/irssi/scripts/autorun/topic-diff.pl | 1 + dotfiles/irssi/scripts/autorun/trackbar.pl | 1 + dotfiles/irssi/scripts/autorun/usercount.pl | 1 + .../irssi/scripts/autorun/xchatnickcolor.pl | 1 + dotfiles/irssi/scripts/beep_beep.pl | 51 + dotfiles/irssi/scripts/cap_sasl.pl | 272 ++ dotfiles/irssi/scripts/hilightwin.pl | 57 + dotfiles/irssi/scripts/nicklist.pl | 611 ++++ dotfiles/irssi/scripts/niq.pl | 295 ++ dotfiles/irssi/scripts/nm.pl | 662 +++++ dotfiles/irssi/scripts/notify.pl | 77 + dotfiles/irssi/scripts/postpone.pl | 117 + dotfiles/irssi/scripts/screen_away.pl | 243 ++ dotfiles/irssi/scripts/scriptassist.pl | 1160 ++++++++ dotfiles/irssi/scripts/topic-diff.pl | 86 + dotfiles/irssi/scripts/trackbar.pl | 228 ++ dotfiles/irssi/scripts/usercount.pl | 172 ++ dotfiles/irssi/scripts/xchatnickcolor.pl | 157 ++ .../kde-autostart}/displayrootwindow.sh | 0 31 files changed, 8177 insertions(+) rename {conky => dotfiles/conky}/showmounts.sh (100%) create mode 100644 dotfiles/irssi/config create mode 100644 dotfiles/irssi/config-sthu create mode 100644 dotfiles/irssi/default.theme create mode 100644 dotfiles/irssi/envy.theme create mode 100644 dotfiles/irssi/scripts/adv_windowlist.pl create mode 120000 dotfiles/irssi/scripts/autorun/adv_windowlist.pl create mode 120000 dotfiles/irssi/scripts/autorun/hilightwin.pl create mode 120000 dotfiles/irssi/scripts/autorun/niq.pl create mode 120000 dotfiles/irssi/scripts/autorun/nm.pl create mode 120000 dotfiles/irssi/scripts/autorun/postpone.pl create mode 120000 dotfiles/irssi/scripts/autorun/screen_away.pl create mode 120000 dotfiles/irssi/scripts/autorun/topic-diff.pl create mode 120000 dotfiles/irssi/scripts/autorun/trackbar.pl create mode 120000 dotfiles/irssi/scripts/autorun/usercount.pl create mode 120000 dotfiles/irssi/scripts/autorun/xchatnickcolor.pl create mode 100644 dotfiles/irssi/scripts/beep_beep.pl create mode 100644 dotfiles/irssi/scripts/cap_sasl.pl create mode 100644 dotfiles/irssi/scripts/hilightwin.pl create mode 100644 dotfiles/irssi/scripts/nicklist.pl create mode 100644 dotfiles/irssi/scripts/niq.pl create mode 100644 dotfiles/irssi/scripts/nm.pl create mode 100644 dotfiles/irssi/scripts/notify.pl create mode 100644 dotfiles/irssi/scripts/postpone.pl create mode 100644 dotfiles/irssi/scripts/screen_away.pl create mode 100644 dotfiles/irssi/scripts/scriptassist.pl create mode 100644 dotfiles/irssi/scripts/topic-diff.pl create mode 100644 dotfiles/irssi/scripts/trackbar.pl create mode 100644 dotfiles/irssi/scripts/usercount.pl create mode 100644 dotfiles/irssi/scripts/xchatnickcolor.pl rename {kde-autostart => dotfiles/kde-autostart}/displayrootwindow.sh (100%) diff --git a/conky/showmounts.sh b/dotfiles/conky/showmounts.sh similarity index 100% rename from conky/showmounts.sh rename to dotfiles/conky/showmounts.sh diff --git a/dotfiles/irssi/config b/dotfiles/irssi/config new file mode 100644 index 0000000..0ff6c4a --- /dev/null +++ b/dotfiles/irssi/config @@ -0,0 +1,313 @@ +servers = ( + { address = "irc.stealth.net"; chatnet = "IRCnet"; port = "6668"; }, + { address = "irc.efnet.org"; chatnet = "EFNet"; port = "6667"; }, + { + address = "irc.undernet.org"; + chatnet = "Undernet"; + port = "6667"; + }, + { address = "irc.dal.net"; chatnet = "DALnet"; port = "6667"; }, + { + address = "irc.quakenet.org"; + chatnet = "QuakeNet"; + port = "6667"; + }, + { address = "silc.silcnet.org"; chatnet = "SILC"; port = "706"; }, + { + address = "irc.freenode.net"; + chatnet = "freenode"; + port = "7000"; + use_ssl = "yes"; + ssl_verify = "yes"; + ssl_capath = "/etc/ssl/certs"; + family = "inet"; + autoconnect = "yes"; + }, + { + address = "irc.oftc.net"; + chatnet = "OFTC"; + port = "6697"; + use_ssl = "yes"; + ssl_verify = "yes"; + ssl_capath = "/etc/ssl/certs"; + family = "inet"; + autoconnect = "no"; + } +); + +chatnets = { + IRCnet = { + type = "IRC"; + max_kicks = "4"; + max_msgs = "5"; + max_whois = "4"; + max_query_chans = "5"; + }; + EFNet = { + type = "IRC"; + max_kicks = "4"; + max_msgs = "3"; + max_whois = "1"; + }; + Undernet = { + type = "IRC"; + max_kicks = "1"; + max_msgs = "3"; + max_whois = "30"; + }; + DALnet = { + type = "IRC"; + max_kicks = "4"; + max_msgs = "3"; + max_whois = "30"; + }; + QuakeNet = { + type = "IRC"; + max_kicks = "1"; + max_msgs = "3"; + max_whois = "30"; + }; + SILC = { type = "SILC"; }; + freenode = { + type = "IRC"; + #autosendcmd = "/msg nickserv identify PASSWORD; /window goto nickserv; /wait 2000; /wc"; + }; + OFTC = { type = "IRC"; }; +}; + +channels = ( + { name = "#myfavchannel"; chatnet = "freenode"; autojoin = "yes"; } +); + +aliases = { + J = "join"; + WJOIN = "join -window"; + WQUERY = "query -window"; + LEAVE = "part"; + BYE = "quit"; + EXIT = "quit"; + SIGNOFF = "quit"; + DESCRIBE = "action"; + DATE = "time"; + HOST = "userhost"; + LAST = "lastlog"; + SAY = "msg *"; + WI = "whois"; + WII = "whois $0 $0"; + WW = "whowas"; + W = "who"; + N = "names"; + M = "msg"; + T = "topic"; + C = "clear"; + CL = "clear"; + K = "kick"; + KB = "kickban"; + KN = "knockout"; + BANS = "ban"; + B = "ban"; + MUB = "unban *"; + UB = "unban"; + IG = "ignore"; + UNIG = "unignore"; + SB = "scrollback"; + UMODE = "mode $N"; + WC = "window close"; + WN = "window new hide"; + SV = "say Irssi $J ($V) - http://irssi.org/"; + GOTO = "sb goto"; + CHAT = "dcc chat"; + RUN = "SCRIPT LOAD"; + CALC = "exec - if which bc &>/dev/null\\; then echo '$*' | bc | awk '{print \"$*=\"$$1}'\\; else echo bc was not found\\; fi"; + SBAR = "STATUSBAR"; + INVITELIST = "mode $C +I"; + Q = "QUERY"; + "MANUAL-WINDOWS" = "set use_status_window off;set autocreate_windows off;set autocreate_query_level none;set autoclose_windows off;set reuse_unused_windows on;save"; + EXEMPTLIST = "mode $C +e"; + ATAG = "WINDOW SERVER"; +}; + +statusbar = { + # formats: + # when using {templates}, the template is shown only if it's argument isn't + # empty unless no argument is given. for example {sb} is printed always, + # but {sb $T} is printed only if $T isn't empty. + + items = { + # start/end text in statusbars + barstart = "{sbstart}"; + barend = "{sbend}"; + + topicbarstart = "{topicsbstart}"; + topicbarend = "{topicsbend}"; + + # treated "normally", you could change the time/user name to whatever + time = "{sb $Z}"; + user = "{sb {sbnickmode $cumode}$N{sbmode $usermode}{sbaway $A}}"; + + # treated specially .. window is printed with non-empty windows, + # window_empty is printed with empty windows + window = "{sb $winref:$tag/$itemname{sbmode $M}}"; + window_empty = "{sb $winref{sbservertag $tag}}"; + prompt = "{prompt $[.15]itemname}"; + prompt_empty = "{prompt $winname}"; + topic = " $topic"; + topic_empty = " Irssi v$J - http://www.irssi.org"; + + # all of these treated specially, they're only displayed when needed + lag = "{sb Lag: $0-}"; + act = "{sb Act: $0-}"; + more = "-- more --"; + }; + + # there's two type of statusbars. root statusbars are either at the top + # of the screen or at the bottom of the screen. window statusbars are at + # the top/bottom of each split window in screen. + default = { + # the "default statusbar" to be displayed at the bottom of the window. + # contains all the normal items. + window = { + disabled = "no"; + + # window, root + type = "window"; + # top, bottom + placement = "bottom"; + # number + position = "1"; + # active, inactive, always + visible = "active"; + + # list of items in statusbar in the display order + items = { + barstart = { priority = "100"; }; + time = { }; + user = { }; + window = { }; + window_empty = { }; + lag = { priority = "-1"; }; + act = { priority = "10"; }; + more = { priority = "-1"; alignment = "right"; }; + barend = { priority = "100"; alignment = "right"; }; + usercount = { }; + }; + }; + + # statusbar to use in inactive split windows + window_inact = { + type = "window"; + placement = "bottom"; + position = "1"; + visible = "inactive"; + items = { + barstart = { priority = "100"; }; + window = { }; + window_empty = { }; + more = { priority = "-1"; alignment = "right"; }; + barend = { priority = "100"; alignment = "right"; }; + }; + }; + + # we treat input line as yet another statusbar :) It's possible to + # add other items before or after the input line item. + prompt = { + type = "root"; + placement = "bottom"; + # we want to be at the bottom always + position = "100"; + visible = "always"; + items = { + prompt = { priority = "-1"; }; + prompt_empty = { priority = "-1"; }; + # treated specially, this is the real input line. + input = { priority = "10"; }; + }; + }; + + # topicbar + topic = { + type = "root"; + placement = "top"; + position = "1"; + visible = "always"; + items = { + topicbarstart = { priority = "100"; }; + topic = { }; + topic_empty = { }; + topicbarend = { priority = "100"; alignment = "right"; }; + }; + }; + awl_0 = { + items = { + barstart = { priority = "100"; }; + awl_0 = { }; + barend = { priority = "100"; alignment = "right"; }; + }; + }; + }; +}; +settings = { + core = { + real_name = "Firsname Lastname"; + user_name = "XXX"; + nick = "XXX"; + log_timestamp = "%F %H:%M "; + resolve_prefer_ipv6 = "yes"; + timestamp_format = "%R"; + }; + "fe-text" = { actlist_sort = "refnum"; }; + "fe-common/core" = { + beep_when_away = "yes"; + theme = "envy"; + beep_msg_level = "MSGS DCC DCCMSGS HILIGHT"; + bell_beeps = "yes"; + beep_when_window_active = "yes"; + autolog = "yes"; + autolog_path = "~/.irssi/logs/$tag/$0.%Y-%m.log"; + term_charset = "UTF-8"; + show_names_on_join = "yes"; + show_nickmode = "yes"; + use_status_window = "yes"; + use_msgs_window = "no"; + activity_hide_level = "JOINS QUITS PARTS NICKS MODES"; + emphasis_multiword = "yes"; + hilight_level = "PUBLIC DCCMSGS"; + }; + "perl/core/scripts" = { + nicklist_width = "10"; + nicklist_height = "20"; + nicklist_automode = "screen"; + screen_away_active = "yes"; + screen_away_nick = ""; + #beep_cmd = "/usr/bin/ogg123 --quiet /usr/share/sounds/KDE-Im-Irc-Event.ogg &"; + neat_maxlength = "12"; + screen_away_message = "Currently away"; + }; +}; +hilights = ( { text = "NICK XXX"; nick = "yes"; word = "yes"; } ); +logs = { }; +windows = { + 1 = { + immortal = "yes"; + name = "(status)"; + level = "ALL"; + sticky = "yes"; + parent = "3"; + }; + 2 = { name = "hilight"; sticky = "yes"; }; + 3 = { + items = ( + { + type = "CHANNEL"; + chat_type = "IRC"; + name = "#myfavchannel"; + tag = "freenode"; + } + ); + sticky = "yes"; + }; +}; +mainwindows = { + 3 = { first_line = "8"; lines = "61"; }; + 2 = { first_line = "1"; lines = "7"; }; +}; diff --git a/dotfiles/irssi/config-sthu b/dotfiles/irssi/config-sthu new file mode 100644 index 0000000..a58955e --- /dev/null +++ b/dotfiles/irssi/config-sthu @@ -0,0 +1,380 @@ +servers = ( + { address = "irc.stealth.net"; chatnet = "IRCnet"; port = "6668"; }, + { address = "irc.efnet.org"; chatnet = "EFNet"; port = "6667"; }, + { + address = "irc.undernet.org"; + chatnet = "Undernet"; + port = "6667"; + }, + { address = "irc.dal.net"; chatnet = "DALnet"; port = "6667"; }, + { + address = "irc.quakenet.org"; + chatnet = "QuakeNet"; + port = "6667"; + }, + { address = "silc.silcnet.org"; chatnet = "SILC"; port = "706"; }, + { + address = "irc.freenode.net"; + chatnet = "freenode"; + port = "7000"; + use_ssl = "yes"; + ssl_verify = "yes"; + ssl_capath = "/etc/ssl/certs"; + family = "inet"; + autoconnect = "yes"; + }, + { + address = "irc.oftc.net"; + chatnet = "OFTC"; + port = "6697"; + use_ssl = "yes"; + ssl_verify = "yes"; + ssl_capath = "/etc/ssl/certs"; + family = "inet"; + autoconnect = "yes"; + }, + { + address = "testing.bitlbee.org"; + chatnet = "bitlbee"; + port = "6668"; + use_ssl = "yes"; + ssl_verify = "no"; + family = "inet"; + autoconnect = "yes"; + } +); + +chatnets = { + IRCnet = { + type = "IRC"; + max_kicks = "4"; + max_msgs = "5"; + max_whois = "4"; + max_query_chans = "5"; + }; + EFNet = { + type = "IRC"; + max_kicks = "4"; + max_msgs = "3"; + max_whois = "1"; + }; + Undernet = { + type = "IRC"; + max_kicks = "1"; + max_msgs = "3"; + max_whois = "30"; + }; + DALnet = { + type = "IRC"; + max_kicks = "4"; + max_msgs = "3"; + max_whois = "30"; + }; + QuakeNet = { + type = "IRC"; + max_kicks = "1"; + max_msgs = "3"; + max_whois = "30"; + }; + SILC = { type = "SILC"; }; + freenode = { + type = "IRC"; + #autosendcmd = "/msg nickserv identify QPFR6YdanYOkZvYcLsLO; /window goto nickserv; /wait 2000; /wc"; + autosendcmd = "/msg nickserv identify Naihu2udaqua5Ule; /window goto nickserv; /wait 2000; /wc"; + }; + OFTC = { + type = "IRC"; + #autosendcmd = "/msg nickserv identify aLeno8CY4m5Z4HQWlA7iR+BpIkghGu7H6QxDWHHh; /wait 2000; /window goto nickserv; /wc"; + autosendcmd = "/msg nickserv identify kiesah8ter5Vooth; /wait 2000; /window goto nickserv; /wc"; + }; + bitlbee = { + type = "IRC"; + autosendcmd = "/msg nickserv identify 2ciCuvKX; /wait 2000; /window goto nickserv; /wc"; + }; +}; + +channels = ( + { name = "#irssi"; chatnet = "ircnet"; autojoin = "No"; }, + { name = "silc"; chatnet = "silc"; autojoin = "No"; }, + { name = "#compgeo"; chatnet = "OFTC"; autojoin = "yes"; }, + { name = "#wavelab"; chatnet = "freenode"; autojoin = "yes"; }, + { name = "#chaossbg"; chatnet = "freenode"; autojoin = "yes"; }, + { + name = "#gentoo-anfaenger"; + chatnet = "freenode"; + autojoin = "No"; + }, + { name = "#gentoo.de"; chatnet = "freenode"; autojoin = "No"; } +); + +aliases = { + J = "join"; + WJOIN = "join -window"; + WQUERY = "query -window"; + LEAVE = "part"; + BYE = "quit"; + EXIT = "quit"; + SIGNOFF = "quit"; + DESCRIBE = "action"; + DATE = "time"; + HOST = "userhost"; + LAST = "lastlog"; + SAY = "msg *"; + WI = "whois"; + WII = "whois $0 $0"; + WW = "whowas"; + W = "who"; + N = "names"; + M = "msg"; + T = "topic"; + C = "clear"; + CL = "clear"; + K = "kick"; + KB = "kickban"; + KN = "knockout"; + BANS = "ban"; + B = "ban"; + MUB = "unban *"; + UB = "unban"; + IG = "ignore"; + UNIG = "unignore"; + SB = "scrollback"; + UMODE = "mode $N"; + WC = "window close"; + WN = "window new hide"; + SV = "say Irssi $J ($V) - http://irssi.org/"; + GOTO = "sb goto"; + CHAT = "dcc chat"; + RUN = "SCRIPT LOAD"; + CALC = "exec - if which bc &>/dev/null\\; then echo '$*' | bc | awk '{print \"$*=\"$$1}'\\; else echo bc was not found\\; fi"; + SBAR = "STATUSBAR"; + INVITELIST = "mode $C +I"; + Q = "QUERY"; + "MANUAL-WINDOWS" = "set use_status_window off;set autocreate_windows off;set autocreate_query_level none;set autoclose_windows off;set reuse_unused_windows on;save"; + EXEMPTLIST = "mode $C +e"; + ATAG = "WINDOW SERVER"; +}; + +statusbar = { + # formats: + # when using {templates}, the template is shown only if it's argument isn't + # empty unless no argument is given. for example {sb} is printed always, + # but {sb $T} is printed only if $T isn't empty. + + items = { + # start/end text in statusbars + barstart = "{sbstart}"; + barend = "{sbend}"; + + topicbarstart = "{topicsbstart}"; + topicbarend = "{topicsbend}"; + + # treated "normally", you could change the time/user name to whatever + time = "{sb $Z}"; + user = "{sb {sbnickmode $cumode}$N{sbmode $usermode}{sbaway $A}}"; + + # treated specially .. window is printed with non-empty windows, + # window_empty is printed with empty windows + window = "{sb $winref:$tag/$itemname{sbmode $M}}"; + window_empty = "{sb $winref{sbservertag $tag}}"; + prompt = "{prompt $[.15]itemname}"; + prompt_empty = "{prompt $winname}"; + topic = " $topic"; + topic_empty = " Irssi v$J - http://www.irssi.org"; + + # all of these treated specially, they're only displayed when needed + lag = "{sb Lag: $0-}"; + act = "{sb Act: $0-}"; + more = "-- more --"; + }; + + # there's two type of statusbars. root statusbars are either at the top + # of the screen or at the bottom of the screen. window statusbars are at + # the top/bottom of each split window in screen. + default = { + # the "default statusbar" to be displayed at the bottom of the window. + # contains all the normal items. + window = { + disabled = "no"; + + # window, root + type = "window"; + # top, bottom + placement = "bottom"; + # number + position = "1"; + # active, inactive, always + visible = "active"; + + # list of items in statusbar in the display order + items = { + barstart = { priority = "100"; }; + time = { }; + user = { }; + window = { }; + window_empty = { }; + lag = { priority = "-1"; }; + act = { priority = "10"; }; + more = { priority = "-1"; alignment = "right"; }; + barend = { priority = "100"; alignment = "right"; }; + usercount = { }; + }; + }; + + # statusbar to use in inactive split windows + window_inact = { + type = "window"; + placement = "bottom"; + position = "1"; + visible = "inactive"; + items = { + barstart = { priority = "100"; }; + window = { }; + window_empty = { }; + more = { priority = "-1"; alignment = "right"; }; + barend = { priority = "100"; alignment = "right"; }; + }; + }; + + # we treat input line as yet another statusbar :) It's possible to + # add other items before or after the input line item. + prompt = { + type = "root"; + placement = "bottom"; + # we want to be at the bottom always + position = "100"; + visible = "always"; + items = { + prompt = { priority = "-1"; }; + prompt_empty = { priority = "-1"; }; + # treated specially, this is the real input line. + input = { priority = "10"; }; + }; + }; + + # topicbar + topic = { + type = "root"; + placement = "top"; + position = "1"; + visible = "always"; + items = { + topicbarstart = { priority = "100"; }; + topic = { }; + topic_empty = { }; + topicbarend = { priority = "100"; alignment = "right"; }; + }; + }; + awl_0 = { + items = { + barstart = { priority = "100"; }; + awl_0 = { }; + barend = { priority = "100"; alignment = "right"; }; + }; + }; + }; +}; +settings = { + core = { + real_name = "Stefan Huber"; + user_name = "shuber"; + nick = "shuber"; + log_timestamp = "%F %H:%M "; + resolve_prefer_ipv6 = "yes"; + timestamp_format = "%R"; + }; + "fe-text" = { actlist_sort = "refnum"; }; + "fe-common/core" = { + beep_when_away = "yes"; + theme = "envy"; + beep_msg_level = "MSGS DCC DCCMSGS HILIGHT"; + bell_beeps = "yes"; + beep_when_window_active = "yes"; + autolog = "yes"; + autolog_path = "~/.irssi/logs/$tag/$0.%Y-%m.log"; + term_charset = "UTF-8"; + show_names_on_join = "yes"; + show_nickmode = "yes"; + use_status_window = "yes"; + use_msgs_window = "no"; + activity_hide_level = "JOINS QUITS PARTS NICKS MODES"; + emphasis_multiword = "yes"; + hilight_level = "PUBLIC DCCMSGS"; + }; + "perl/core/scripts" = { + nicklist_width = "10"; + nicklist_height = "20"; + nicklist_automode = "screen"; + screen_away_active = "yes"; + screen_away_nick = ""; + beep_cmd = "/usr/bin/ogg123 --quiet /usr/share/sounds/KDE-Im-Irc-Event.ogg &"; + neat_maxlength = "12"; + screen_away_message = "Currently away"; + }; +}; +hilights = ( + { text = "shuber"; nick = "yes"; word = "yes"; }, + { text = "shuber2"; nick = "yes"; word = "yes"; } +); +logs = { }; +windows = { + 1 = { + immortal = "yes"; + name = "(status)"; + level = "ALL"; + sticky = "yes"; + }; + 2 = { name = "hilight"; sticky = "yes"; }; + 3 = { + items = ( + { + type = "CHANNEL"; + chat_type = "IRC"; + name = "&bitlbee"; + tag = "bitlbee"; + } + ); + sticky = "yes"; + parent = "1"; + }; + 4 = { + items = ( + { + type = "CHANNEL"; + chat_type = "IRC"; + name = "#wavelab"; + tag = "freenode"; + } + ); + sticky = "yes"; + parent = "1"; + }; + 5 = { + items = ( + { + type = "CHANNEL"; + chat_type = "IRC"; + name = "#compgeo"; + tag = "OFTC"; + } + ); + sticky = "yes"; + parent = "1"; + }; + 6 = { + items = ( + { + type = "CHANNEL"; + chat_type = "IRC"; + name = "#chaossbg"; + tag = "freenode"; + } + ); + sticky = "yes"; + parent = "1"; + }; +}; +mainwindows = { + 1 = { first_line = "4"; lines = "26"; }; + 2 = { first_line = "1"; lines = "3"; }; +}; diff --git a/dotfiles/irssi/default.theme b/dotfiles/irssi/default.theme new file mode 100644 index 0000000..98af18b --- /dev/null +++ b/dotfiles/irssi/default.theme @@ -0,0 +1,294 @@ +# When testing changes, the easiest way to reload the theme is with /RELOAD. +# This reloads the configuration file too, so if you did any changes remember +# to /SAVE it first. Remember also that /SAVE overwrites the theme file with +# old data so keep backups :) + +# TEMPLATES: + +# The real text formats that irssi uses are the ones you can find with +# /FORMAT command. Back in the old days all the colors and texts were mixed +# up in those formats, and it was really hard to change the colors since you +# might have had to change them in tens of different places. So, then came +# this templating system. + +# Now the /FORMATs don't have any colors in them, and they also have very +# little other styling. Most of the stuff you need to change is in this +# theme file. If you can't change something here, you can always go back +# to change the /FORMATs directly, they're also saved in these .theme files. + +# So .. the templates. They're those {blahblah} parts you see all over the +# /FORMATs and here. Their usage is simply {name parameter1 parameter2}. +# When irssi sees this kind of text, it goes to find "name" from abstracts +# block below and sets "parameter1" into $0 and "parameter2" into $1 (you +# can have more parameters of course). Templates can have subtemplates. +# Here's a small example: +# /FORMAT format hello {colorify {underline world}} +# abstracts = { colorify = "%G$0-%n"; underline = "%U$0-%U"; } +# When irssi expands the templates in "format", the final string would be: +# hello %G%Uworld%U%n +# ie. underlined bright green "world" text. +# and why "$0-", why not "$0"? $0 would only mean the first parameter, +# $0- means all the parameters. With {underline hello world} you'd really +# want to underline both of the words, not just the hello (and world would +# actually be removed entirely). + +# COLORS: + +# You can find definitions for the color format codes in docs/formats.txt. + +# There's one difference here though. %n format. Normally it means the +# default color of the terminal (white mostly), but here it means the +# "reset color back to the one it was in higher template". For example +# if there was /FORMAT test %g{foo}bar, and foo = "%Y$0%n", irssi would +# print yellow "foo" (as set with %Y) but "bar" would be green, which was +# set at the beginning before the {foo} template. If there wasn't the %g +# at start, the normal behaviour of %n would occur. If you _really_ want +# to use the terminal's default color, use %N. + +############################################################################# + +# default foreground color (%N) - -1 is the "default terminal color" +default_color = "-1"; + +# print timestamp/servertag at the end of line, not at beginning +info_eol = "false"; + +# these characters are automatically replaced with specified color +# (dark grey by default) +replaces = { "[]=" = "%K$*%n"; }; + +abstracts = { + ## + ## generic + ## + + # text to insert at the beginning of each non-message line + line_start = "%B-%W!%B-%n "; + + # timestamp styling, nothing by default + timestamp = "$*"; + + # any kind of text that needs hilighting, default is to bold + hilight = "%_$*%_"; + + # any kind of error message, default is bright red + error = "%R$*%n"; + + # channel name is printed + channel = "%_$*%_"; + + # nick is printed + nick = "%_$*%_"; + + # nick host is printed + nickhost = "[$*]"; + + # server name is printed + server = "%_$*%_"; + + # some kind of comment is printed + comment = "[$*]"; + + # reason for something is printed (part, quit, kick, ..) + reason = "{comment $*}"; + + # mode change is printed ([+o nick]) + mode = "{comment $*}"; + + ## + ## channel specific messages + ## + + # highlighted nick/host is printed (joins) + channick_hilight = "%C$*%n"; + chanhost_hilight = "{nickhost %c$*%n}"; + + # nick/host is printed (parts, quits, etc.) + channick = "%c$*%n"; + chanhost = "{nickhost $*}"; + + # highlighted channel name is printed + channelhilight = "%c$*%n"; + + # ban/ban exception/invite list mask is printed + ban = "%c$*%n"; + + ## + ## messages + ## + + # the basic styling of how to print message, $0 = nick mode, $1 = nick + msgnick = "%K<%n$0$1-%K>%n %|"; + + # message from you is printed. "msgownnick" specifies the styling of the + # nick ($0 part in msgnick) and "ownmsgnick" specifies the styling of the + # whole line. + + # Example1: You want the message text to be green: + # ownmsgnick = "{msgnick $0 $1-}%g"; + # Example2.1: You want < and > chars to be yellow: + # ownmsgnick = "%Y{msgnick $0 $1-%Y}%n"; + # (you'll also have to remove <> from replaces list above) + # Example2.2: But you still want to keep <> grey for other messages: + # pubmsgnick = "%K{msgnick $0 $1-%K}%n"; + # pubmsgmenick = "%K{msgnick $0 $1-%K}%n"; + # pubmsghinick = "%K{msgnick $1 $0$2-%n%K}%n"; + # ownprivmsgnick = "%K{msgnick $*%K}%n"; + # privmsgnick = "%K{msgnick %R$*%K}%n"; + + # $0 = nick mode, $1 = nick + ownmsgnick = "{msgnick $0 $1-}"; + ownnick = "%W$*%n"; + + # public message in channel, $0 = nick mode, $1 = nick + pubmsgnick = "{msgnick $0 $1-}"; + pubnick = "%N$*%n"; + + # public message in channel meant for me, $0 = nick mode, $1 = nick + pubmsgmenick = "{msgnick $0 $1-}"; + menick = "%Y$*%n"; + + # public highlighted message in channel + # $0 = highlight color, $1 = nick mode, $2 = nick + pubmsghinick = "{msgnick $1 $0$2-%n}"; + + # channel name is printed with message + msgchannel = "%K:%c$*%n"; + + # private message, $0 = nick, $1 = host + privmsg = "[%R$0%K(%r$1-%K)%n] "; + + # private message from you, $0 = "msg", $1 = target nick + ownprivmsg = "[%r$0%K(%R$1-%K)%n] "; + + # own private message in query + ownprivmsgnick = "{msgnick $*}"; + ownprivnick = "%W$*%n"; + + # private message in query + privmsgnick = "{msgnick %R$*%n}"; + + ## + ## Actions (/ME stuff) + ## + + # used internally by this theme + action_core = "%W * $*%n"; + + # generic one that's used by most actions + action = "{action_core $*} "; + + # own action, both private/public + ownaction = "{action $*}"; + + # own action with target, both private/public + ownaction_target = "{action_core $0}%K:%c$1%n "; + + # private action sent by others + pvtaction = "%W (*) $*%n "; + pvtaction_query = "{action $*}"; + + # public action sent by others + pubaction = "{action $*}"; + + + ## + ## other IRC events + ## + + # 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 "; + + # CTCPs + 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 list + 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 = "%_$*%_"; + + # DCC chat, own msg/action + dccownmsg = "[%r$0%K($1-%K)%n] "; + dccownnick = "%R$*%n"; + dccownquerynick = "%W$*%n"; + dccownaction = "{action $*}"; + dccownaction_target = "{action_core $0}%K:%c$1%n "; + + # DCC chat, others + dccmsg = "[%G$1-%K(%g$0%K)%n] "; + dccquerynick = "%G$*%n"; + dccaction = "%W (*dcc*) $*%n %|"; + + ## + ## statusbar + ## + + # default background for all statusbars. You can also give + # the default foreground color for statusbar items. + sb_background = "%4%w"; + + # default backround for "default" statusbar group + #sb_default_bg = "%4"; + # background for prompt / input line + sb_prompt_bg = "%n"; + # background for info statusbar + sb_info_bg = "%8"; + # background for topicbar (same default) + #sb_topic_bg = "%4"; + + # text at the beginning of statusbars. sb-item already puts + # space there,so we don't use anything by default. + sbstart = ""; + # text at the end of statusbars. Use space so that it's never + # used for anything. + sbend = " "; + + topicsbstart = "{sbstart $*}"; + topicsbend = "{sbend $*}"; + + prompt = "[$*] "; + + sb = " %c[%n$*%c]%n"; + sbmode = "(%c+%n$*)"; + sbaway = " (%GzZzZ%n)"; + sbservertag = ":$0 (change with ^X)"; + sbnickmode = "$0"; + + # activity in statusbar + + # ',' separator + sb_act_sep = "%c$*"; + # normal text + sb_act_text = "%c$*"; + # public message + sb_act_msg = "%W$*"; + # hilight + sb_act_hilight = "%M$*"; + # hilight with specified color, $0 = color, $1 = text + sb_act_hilight_color = "$0$1-%n"; +}; diff --git a/dotfiles/irssi/envy.theme b/dotfiles/irssi/envy.theme new file mode 100644 index 0000000..9472c70 --- /dev/null +++ b/dotfiles/irssi/envy.theme @@ -0,0 +1,514 @@ +# ___ ___ ___ ___ +# /\ \ /\__\ /\__\ |\__\ +# /::\ \ /::| | /:/ / |:| | +# /:/\:\ \ /:|:| | /:/ / |:| | +# /::\~\:\ \ /:/|:| |__ /:/__/ ___ |:|__|__ +# /:/\:\ \:\__\ /:/ |:| /\__\ |:| | /\__\ /::::\__\ +# \:\~\:\ \/__/ \/__|:|/:/ / |:| |/:/ / /:/~~/~ +# \:\ \:\__\ |:/:/ / |:|__/:/ / /:/ / +# \:\ \/__/ |::/ / \::::/__/ \/__/ +# \:\__\ /:/ / ~~~~ +# \/__/ \/__/ v. 3.6 +# +# theme by rolle (rolle @ QuakeNet, rolle_ @ Ircnet) +# http://rollemaa.org/ +# +# you can find the most recent version here: +# http://rolle.tux.fi + +default_color = "-1"; +# Timestamp/servertag loppuun, ei alkuun +info_eol = "false"; +replaces = { "[]=" = "$*"; }; + +abstracts = { + line_start = "%K"; + timestamp = "%K$*%n"; + hilight = "$*"; + error = "$*"; + channel = "$*"; + nick = "$*"; + nickhost = "$*"; + server = "$*"; + comment = "$*"; + reason = "{comment $*}"; + mode = "{comment $*}"; + channick_hilight = "$*"; + chanhost_hilight = "{nickhost $*}"; + channick = "$*"; + chanhost = "{nickhost $*}"; + channelhilight = "$*"; + ban = "$*"; + # Kaikissa alemmissa: $0 = mode, $1 = nick + msgnick = "$0$1- %|"; + ownmsgnick = "{msgnick %K<$0 %G$1-%K>}%n"; + ownnick = "$*"; + pubmsgnick = "{msgnick %K<$0 %W$1-%K>}%n"; + pubnick = "$*"; + pubmsgmenick = "{msgnick %K<$0 %P$1-%K>}%P"; + menick = "%P$*%n"; + # $0 = hilightin väri, $1 = mode, $2 = nick + pubmsghinick = "{msgnick %K<$1 %P$2-%K>%P}"; + msgchannel = ":$*"; + # $0 = nick, $1 = hosti + privmsg = "[$0($1-)] "; + # $0 = "msg", $1 = target nick + ownprivmsg = "[$0($1-)] "; + ownprivmsgnick = "{msgnick $*}"; + ownprivnick = "%K<%G$*%K>%n"; + privmsgnick = "%K<%B$*%K>%n "; + action_core = " %r>%y>%g> %c$0-"; + action = "{action_core $*} "; + ownaction = "{action $*}"; + ownaction_target = "{action_core $*}:$1 "; + pvtaction = " (>>>) $* "; + pvtaction_query = "{action $*}"; + pubaction = "{action $*}"; + ownnotice = "[$0($1-)] "; + notice = "%g$*%K -> %G"; + whois = "%# $[8]0 : $1-"; + pubnotice_channel = ":$*"; + pvtnotice_host = "($*)"; + servernotice = "%r!$* %n"; + ownctcp = "[$0($1-)] "; + ctcp = "$*"; + wallop = "$*: "; + wallop_nick = "$*"; + wallop_action = " * $* "; + netsplit = "$*"; + netjoin = "%K::%g:%K $*"; + names_prefix = "%K"; + names_nick = "%K[$0$1-] "; + names_nick_op = "%K{names_nick $*}"; + names_nick_halfop = "%K{names_nick $*}"; + names_nick_voice = "%K{names_nick $*}"; + names_users = "%K[$*]"; + names_channel = "%K$*"; + dcc = "$*"; + dccfile = "$*"; + dccownmsg = "[$0($1-)] "; + dccownnick = "$*"; + dccownquerynick = "$*"; + dccownaction = "{action $*}"; + dccownaction_target = "{action_core $0}:$1 "; + dccmsg = "[$1-($0)] "; + dccquerynick = "$*"; + dccaction = " (*dcc*) $* %|"; + sb_background = ""; + sb_window_bg = "%n%2"; + sb_default_bg = ""; + sb_prompt_bg = "%0"; + sb_info_bg = ""; + sb_topic_bg = "%G"; + sbstart = ""; + sbend = " "; + topicsbstart = "{sbstart $*}"; + topicsbend = "{sbend $*}"; + prompt = "%R!%G$*%K: "; + sb = " %w/%W$*%w/%n"; + sbmode = ""; + sbaway = "%r>%n"; + sbservertag = "%W$0%n"; + sbnickmode = ""; + sb_act_sep = "%w$*%n"; + sb_act_text = "%G$*%n"; + sb_act_msg = "%G$*%n"; + sb_act_hilight = "%r($*)%n"; + sb_act_hilight_color = "%r$0$1-%n"; +}; +formats = { + "fe-common/core" = { + query_start = "%K:%K:%g:%K %gStarting query%K in {server $1} with {nick $0}"; + join = "%K::%g:%K {channick_hilight $0} [{chanhost_hilight $1}] has %gjoined%K {channel $2}"; + part = "%r:%K:: {channick $0} [{chanhost $1}] has %rleft%K {channel $2}"; + quit = "%r:%K:: {channick $0} [{chanhost $1}] has %rquit%k ({reason $2})"; + quit_once = "%r:%K:: {channick $0} [{chanhost $1}] has %rquit%K ({reason $2})"; + nick_changed = "%K:%y:%K: {channick_hilight $0} is %ynow known as%K {channick_hilight $1}"; + # own_msg = "{ownmsgnick $2 {ownnick $[-10]0}}$1"; + # own_msg_channel = "{ownmsgnick $3 {ownnick $[-10]0}{msgchannel $1}}$2"; + # pubmsg_me = "{pubmsgmenick $2 {menick $[-10]0}}$1"; + # pubmsg_me_channel = "{pubmsgmenick $3 {menick $[-10]0}{msgchannel $1}}$2"; + # pubmsg_hilight = "{pubmsghinick $0 $3 $[-10]1}$2"; + # pubmsg_hilight_channel = "{pubmsghinick $0 $4 $[-10]1{msgchannel $2}}$3"; + # pubmsg = "{pubmsgnick $2 {pubnick \0030$0}}$1"; + # pubmsg_channel = "{pubmsgnick $3 {pubnick $[-10]0}{msgchannel $1}}$2"; + # line_start = "{line_start}"; + # line_start_irssi = "{line_start}{hilight Irssi} %W|%n "; + line_start_irssi = "{line_start}"; + timestamp = "%K{timestamp $Z} "; + # servertag = "$[-11]0 %W|%n "; + servertag = ""; + daychange = "Day changed to %%d %%b %%Y %n"; + talking_with = "%r:%y:%g:%K You are now talking with {nick $0}"; + refnum_too_low = "%r:%K:: Window number must be greater than 1"; + error_server_sticky = "%r:%K:: Window's server is %rsticky%K and it cannot be changed without -unsticky option"; + set_server_sticky = "%K::%g:%K Window's server %gset sticky%K"; + unset_server_sticky = "%K::%g:%K Window's server isn't sticky anymore"; + window_name_not_unique = "%r:%K:: Window names must be unique"; + window_level = "%K::%g:%K Window level is now $0"; + windowlist_header = "Ref Name Active item Server Level"; + windowlist_line = "$[3]0 %|$[20]1 $[15]2 $[15]3 $4"; + windowlist_footer = ""; + windows_layout_saved = "%K::%g:%K Layout of windows is now %gremembered%K next time you start irssi"; + windows_layout_reset = "%K::%g:%K Layout of windows %greset%K to defaults"; + window_info_header = ""; + window_info_footer = ""; + window_info_refnum = "Window : {hilight #$0}"; + window_info_refnum_sticky = "Window : {hilight #$0 (sticky)}"; + window_info_name = "Name : $0"; + window_info_history = "History : $0"; + window_info_size = "Size : $0x$1"; + window_info_level = "Level : $0"; + window_info_server = "Server : $0"; + window_info_server_sticky = "Server : $0 (sticky)"; + window_info_theme = "Theme : $0$1"; + window_info_bound_items_header = "Bounds : {hilight Name Server tag}"; + window_info_bound_item = " : $[!30]0 $[!15]1 $2"; + window_info_bound_items_footer = ""; + window_info_items_header = "Items : {hilight Name Server tag}"; + window_info_item = " $[7]0: $[!30]1 $2"; + window_info_items_footer = ""; + looking_up = "%K::%g:%K %gLooking up%K {server $0}"; + connecting = "%K::%g:%K %gConnecting%K to {server $0} [$1] port {hilight $2}"; + connection_established = "%K::%g:%K Connection to {server $0} %gestablished%K"; + cant_connect = "%r:%K:: %rUnable to connect%K server {server $0} port {hilight $1} {reason $2}"; + connection_lost = "%r:%K:: %rConnection lost%K to {server $0}"; + lag_disconnected = "%r:%K:: %rNo PONG reply%K from server {server $0} in $1 seconds, disconnecting"; + disconnected = "%r:%K:: %rDisconnected%K from {server $0} {reason $1}"; + server_quit = "%r:%K:: %rDisconnecting%K from server {server $0}: {reason $1}"; + server_changed = "%K:%y:%K: %yChanged%K to {hilight $2} server {server $1}"; + unknown_server_tag = "%r:%K:: %rUnknown%K server tag {server $0}"; + no_connected_servers = "%r:%K:: %rNot connected%K to any servers"; + server_list = "{server $0}: $1:$2 ($3)"; + server_lookup_list = "{server $0}: $1:$2 ($3) (connecting...)"; + server_reconnect_list = "{server $0}: $1:$2 ($3) ($5 left before reconnecting)"; + server_reconnect_removed = "%K::%g:%K %gRemoved reconnection%K to server {server $0} port {hilight $1}"; + server_reconnect_not_found = "%r:%K:: Reconnection tag {server $0} %rnot found%K"; + setupserver_added = "%K::%g:%K Server {server $0} %gsaved%K"; + setupserver_removed = "%K::%g:%K Server {server $0} %gremoved%K"; + setupserver_not_found = "%r:%K:: Server {server $0} %rnot found%K"; + your_nick = "%r:%y:%g:%K Your nickname is {nick $0}"; + kick = "%r:%K:: {channick $0} was %rkicked%K from {channel $1} by {nick $2} ({reason $3})"; + invite = "%K:%y:%K: {channick_hilight $0} %yinvites%K you to {channel $1}"; + not_invited = "You have not been invited to a channel!"; + new_topic = "%K:%y:%K: {channick_hilight $0} %ychanged the topic%K of {channel $1} to: {hilight $2}"; + topic_unset = "%K:%y:%K: {channick_hilight $0} %yunset the topic%K on {channel $1}"; + your_nick_changed = "%K:%y:%K: You're %ynow known as%K {channick_hilight $1}"; + talking_in = "%r:%y:%g:%K You are now talking in {channel $0}"; + not_in_channels = "%r:%y:%g:%K You are not on any channels"; + current_channel = "%r:%y:%g:%K Current channel {channel $0}"; + names = "{names_users Users {names_channel $0}} {comment $1 total}"; + names_prefix = "{names_prefix $0}"; + names_nick_op = "{names_nick_op $0 $1}"; + names_nick_halfop = "{names_nick_halfop $0 $1}"; + names_nick_voice = "{names_nick_voice $0 $1}"; + names_nick = "{names_nick $0 $1}"; + endofnames = "%r:%y:%g:%K {channel $0}: Total of {hilight $1} nicks {comment {hilight $2} ops, {hilight $3} halfops, {hilight $4} voices, {hilight $5} normal}"; + chanlist_header = "%r:%y:%g:%K You are on the following channels:"; + chanlist_line = "{channel $[-9]0} %|+$1 ($2): $3"; + chansetup_not_found = "Channel {channel $0} not found"; + chansetup_added = "Channel {channel $0} saved"; + chansetup_removed = "Channel {channel $0} removed"; + chansetup_header = "Channel Network Password Settings"; + chansetup_line = "{channel $[15]0} %|$[10]1 $[10]2 $3"; + chansetup_footer = ""; + channel_move_notify = "{channel $0} is already joined in window $1, use \"/WINDOW ITEM MOVE $0\" to move it to this window"; + # own_msg_private = "{ownprivmsg msg $0}$1"; + # own_msg_private_query = "{ownprivmsgnick {ownprivnick $[-9]2}}$1"; + # msg_private = "{privmsg $0 $1}$2"; + # msg_private_query = "{privmsgnick $[-9]0}$2"; + no_msgs_got = "%r:%y:%g:%K You have not received a message from anyone yet"; + no_msgs_sent = "%r:%y:%g:%K You have not sent a message to anyone yet"; + query_stop = "%r:%y:%g:%K Closing query with {nick $0}"; + no_query = "%r:%y:%g:%K No query with {nick $0}"; + query_server_changed = "%K:%y:%K: Query with {nick $0} %ychanged%K to server {server $1}"; + query_move_notify = "%r:%y:%g:%K Query with {nick $0} is already created to window $1, use \"/WINDOW ITEM MOVE $0\" to move it to this window"; + hilight_header = "%r:%y:%g:%K Highlights:"; + hilight_line = "$[-4]0 $1 $2 $3$4$5"; + hilight_footer = ""; + hilight_not_found = "%r:%K:: Highlight %rnot found%K: $0"; + hilight_removed = "%K::%g:%K Highlight %gremoved%K: $0"; + alias_added = "%K::%g:%K Alias $0 %gadded%K"; + alias_removed = "%K::%g:%K Alias $0 %gremoved%K"; + alias_not_found = "%r:%K:: %rNo such%K alias: $0"; + aliaslist_header = "%r:%y:%g:%K Aliases:"; + aliaslist_line = "$[10]0 $1"; + aliaslist_footer = ""; + log_opened = "%K::%g:%K Log file {hilight $0} %gopened%K"; + log_closed = "%K::%g:%K Log file {hilight $0} %gclosed%K"; + log_create_failed = "%r:%K:: %rCouldn't create%K log file {hilight $0}: $1"; + log_locked = "%r:%K:: Log file {hilight $0} is %rlocked%K, probably by another running Irssi"; + log_not_open = "%r:%K:: Log file {hilight $0} %rnot open%K"; + log_started = "%K::%g:%K %gStarted%K logging to file {hilight $0}"; + log_stopped = "%r:%K:: %rStopped%K logging to file {hilight $0}"; + log_list_header = "%r:%y:%g:%K Logs:"; + log_list = "$0 $1: $2 $3$4"; + log_list_footer = ""; + windowlog_file = "%K::%g:%K Window LOGFILE set to $0"; + windowlog_file_logging = "%r:%K:: %rCan't change%K window's logfile while log is on"; + no_away_msgs = "%r:%K:: %rNo new%K messages in awaylog"; + away_msgs = "%K::%g:%K {hilight $1} %gnew messages%K in awaylog:"; + module_header = "Module Type Submodules"; + module_line = "$[!20]0 $[7]1 $2"; + module_footer = ""; + module_already_loaded = "%r:%K:: Module {hilight $0/$1} already loaded"; + module_not_loaded = "%r:%K:: Module {hilight $0/$1} %ris not loaded%K"; + module_load_error = "%r:%K:: %rError%K loading module {hilight $0/$1}: $2"; + module_invalid = "%r:%K:: {hilight $0/$1} isn't Irssi module"; + module_loaded = "%K::%g:%K %gLoaded%K module {hilight $0/$1}"; + module_unloaded = "%r:%K:: %rUnloaded%K module {hilight $0/$1}"; + command_unknown = "%r:%K:: %rUnknown%K command: $0"; + command_ambiguous = "%r:%K:: %rAmbiguous%K command: $0"; + option_unknown = "%r:%K:: %rUnknown%K option: $0"; + option_ambiguous = "%r:%K:: %rAmbiguous%K option: $0"; + option_missing_arg = "%r:%K:: %rMissing%K required argument for: $0"; + not_enough_params = "%r:%K:: %rNot enough%K parameters given"; + not_connected = "%r:%K:: %rNot connected%K to server"; + not_joined = "%r:%K:: %rNot joined%K to any channel"; + chan_not_found = "%r:%K:: %rNot joined%K to such channel"; + chan_not_synced = "%r:%K:: Channel %rnot fully synchronized%K yet, try again after a while"; + illegal_proto = "%r:%K:: Command isn't designed for the chat protocol of the active server"; + not_good_idea = "%r:%K:: Doing this is %rnot a good idea%K. Add -YES if you really mean it"; + theme_saved = "%K::%g:%K Theme %gsaved%K to $0"; + theme_save_failed = "%r:%K:: %rError%K saving theme to $0: $1"; + theme_not_found = "%r:%K:: Theme {hilight $0} %rnot found%K"; + theme_changed = "%K:%y:%K: %yUsing%K now theme {hilight $0} ($1)"; + window_theme = "%K::%g:%K %gUsing%K theme {hilight $0} in this window"; + window_theme_default = "%r:%K:: %rNo theme is set%K for this window"; + window_theme_changed = "%K:%y:%K: %yUsing%K now theme {hilight $0} ($1) in this window"; + window_theme_removed = "%K::%g:%K %gRemoved%K theme from this window"; + format_title = "%:[{hilight $0}] - [{hilight $1}]%:"; + format_subtitle = "[{hilight $0}]"; + format_item = "$0 = $1"; + ignored = "%K::%g:%K %gIgnoring%K {hilight $1} from {nick $0}"; + unignored = "%K::%g:%K %gUnignored%K {nick $0}"; + ignore_not_found = "%K::%g:%K {nick $0} %gis not%K being ignored"; + ignore_no_ignores = "%r:%y:%g:%K There are no ignores"; + ignore_header = "%r:%y:%g:%K Ignorance List:"; + ignore_line = "$[-4]0 $1: $2 $3 $4"; + ignore_footer = ""; + unknown_chat_protocol = "%r:%K:: %rUnknown%K chat protocol: $0"; + unknown_chatnet = "%r:%K:: %rUnknown%K chat network: $0 (create it with /IRCNET ADD)"; + not_toggle = "%r:%K:: Value must be either ON, OFF or TOGGLE"; + perl_error = "%r:%K:: Perl %rerror%K: $0"; + bind_key = "$[!20]0 $1 $2"; + bind_unknown_id = "%r:%K:: %rUnknown%K bind action: $0"; + config_saved = "%K::%g:%K %gSaved%K configuration to file $0"; + config_reloaded = "%K::%g:%K %gReloaded%K configuration"; + config_modified = "%r:%y:%g:%K Configuration file was modified since irssi was last started - do you want to overwrite the possible changes?"; + glib_error = "{error GLib $0} $1"; + overwrite_config = "%r:%y:%g:%K Overwrite config (%gy%K/%rN%K)?"; + set_title = "[{hilight $0}]"; + set_item = "$0 = $1"; + set_unknown = "%r:%K:: %rUnknown%K setting $0"; + set_not_boolean = "%r:%K:: Setting {hilight $0} isn't boolean, use /SET"; + translation_not_found = "%r:%K:: %rError%K opening translation table file $0: $1"; + translation_file_error = "%r:%K:: %rError%K parsing translation table file $0"; + pubmsg = "{pubmsgnick {pubnick $[-7]0$2}}$1"; + own_msg = "{ownmsgnick {ownnick $[-7]0$2}}$1"; + own_msg_channel = "{ownmsgnick {ownnick $[-7]0$3}{msgchannel $1}}$2"; + own_msg_private_query = "{ownprivmsgnick {ownprivnick $[-7]2}}$1"; + pubmsg_me = "{pubmsgmenick {menick $[-7]0}$2}$1"; + pubmsg_me_channel = "{pubmsgmenick {menick $[-7]0$3}{msgchannel $1}}$2"; + pubmsg_hilight = "{pubmsghinick $0 $0 $[-7]1$3%n}$2"; + pubmsg_hilight_channel = "{pubmsghinick $0 $[-7]1$4{msgchannel $2}}$3"; + pubmsg_channel = "{pubmsgnick {pubnick $[-7]0$2}}$1"; + msg_private_query = "{privmsgnick $[-7]0}$2"; + }; + "fe-common/irc/dcc" = { + dcc_list_header = "{line_start_irssi}{dcc DCC connections:}"; + dcc_list_footer = "{line_start_irssi}{dcc ];}"; + # own_dcc = "{dccownmsg dcc {dccownnick $1}}$2"; + # own_dcc_action = "{dccownaction_target $0 $1}$2"; + # own_dcc_action_query = "{dccownaction $0}$2"; + # own_dcc_ctcp = "{ownctcp ctcp $0}$1 $2"; + # dcc_msg = "{dccmsg dcc $0}$1"; + # action_dcc = "{dccaction $0}$1"; + # action_dcc_query = "{dccaction $0}$1"; + # own_dcc_query = "{ownmsgnick {dccownquerynick $0}}$2"; + # dcc_msg_query = "{privmsgnick $0}$1"; + dcc_ctcp = "%K::%g:%K {dcc >>> DCC CTCP {hilight $1} %greceived%K from {hilight $0}: $2}"; + dcc_chat = "%K::%g:%K {dcc DCC CHAT from {nick $0} [$1 port $2]}"; + dcc_chat_channel = "%K::%g:%K {dcc DCC CHAT from {nick $0} [$1 port $2] %grequested%K in channel {channel $3}}"; + dcc_chat_not_found = "%K::%g:%K {dcc No DCC CHAT %gconnection open%K to {nick $0}}"; + dcc_chat_connected = "%K::%g:%K {dcc DCC CHAT connection with {nick $0} [$1 port $2] %gestablished%K}"; + dcc_chat_disconnected = "%r:%K:: {dcc DCC %rlost chat%K to {nick $0}}"; + dcc_send = "%K::%g:%K {dcc DCC SEND from {nick $0} [$1 port $2]: $3 [$4 bytes]}"; + dcc_send_channel = "%K::%g:%K {dcc DCC SEND from {nick $0} [$1 port $2]: $3 [$4 bytes] %grequested%K in channel {channel $5}}"; + dcc_send_exists = "%r:%K:: {dcc DCC %ralready sending%K file {dccfile $0} for {nick $1}}"; + dcc_send_not_found = "%r:%K:: {dcc DCC %rnot sending%K file {dccfile $1} to {nick $0}}"; + dcc_send_file_open_error = "%r:%K:: {dcc DCC %rcan't open%K file {dccfile $0}: $1}"; + dcc_send_connected = "%K::%g:%K {dcc DCC %gsending%K file {dccfile $0} for {nick $1} [$2 port $3]}"; + dcc_send_complete = "%K::%g:%K {dcc DCC %gsent%K file {dccfile $0} [{hilight $1}kB] for {nick $2} in {hilight $3} secs [{hilight $4kB/s}]}"; + dcc_send_aborted = "%r:%K:: {dcc DCC %raborted%K sending file {dccfile $0} for {nick $1}}"; + dcc_get_not_found = "%r:%K:: {dcc DCC no file offered by {nick $0}}"; + dcc_get_connected = "%K::%g:%K {dcc DCC %greceiving%K file {dccfile $0} from {nick $1} [$2 port $3]}"; + dcc_get_complete = "%K::%g:%K {dcc DCC %greceived%K file {dccfile $0} [$1kB] from {nick $2} in {hilight $3} secs [$4kB/s]}"; + dcc_get_aborted = "%r:%K:: {dcc DCC %raborted%K receiving file {dccfile $0} from {nick $1}}"; + dcc_unknown_ctcp = "%r:%K:: {dcc DCC unknown ctcp {hilight $0} from {nick $1} [$2]}"; + dcc_unknown_reply = "%r:%K:: {dcc DCC unknown reply {hilight $0} from {nick $1} [$2]}"; + dcc_unknown_type = "%r:%K:: {dcc DCC unknown type {hilight $0}}"; + dcc_invalid_ctcp = "%r:%K:: {dcc DCC received CTCP {hilight $0} with %rinvalid%K parameters from {nick $1}}"; + dcc_connect_error = "%r:%K:: {dcc DCC %rcan't connect%K to {hilight $0} port {hilight $1}}"; + dcc_cant_create = "%r:%K:: {dcc DCC %rcan't create%K file {dccfile $0}}"; + dcc_rejected = "%r:%K:: {dcc DCC $0 was %rrejected%K by {nick $1} [{hilight $2}]}"; + dcc_request_send = "%K::%g:%K {dcc DCC $0 %grequest sent%K to {nick $1}: $2"; + dcc_close = "{dcc DCC $0 close for {nick $1} [{hilight $2}]}"; + dcc_lowport = "{dcc Warning: Port sent with DCC request is a lowport ({hilight $0, $1}) - this isn't normal. It is possible the address/port is faked (or maybe someone is just trying to bypass firewall)}"; + dcc_list_line_chat = "%WChat ->%n {dcc $0 $1}"; + dcc_list_line_file = "%WFile ->%n {dcc $0 $1 : $2k of $3k ($4%%) - $5kB/s - $6}"; + }; + "fe-text" = { + lastlog_too_long = "%r:%y:%g:%K /LASTLOG would print $0 lines. If you really want to print all these lines use -force option."; + lastlog_count = "{hilight Lastlog}: $0 lines"; + lastlog_start = "{hilight Lastlog}:"; + lastlog_end = "{hilight End of Lastlog}"; + refnum_not_found = "%r:%K::%K Window number $0 %rnot found%K"; + window_too_small = "%r:%K::%K %rNot enough room%K to resize this window"; + cant_hide_last = "%r:%K::%K You %rcan't hide%K the last window"; + cant_hide_sticky_windows = "%r:%K::%K You %rcan't hide%K sticky windows (use /WINDOW STICK OFF)"; + cant_show_sticky_windows = "%r:%K::%K You %rcan't show%K sticky windows (use /WINDOW STICK OFF)"; + window_not_sticky = "%r:%K::%K Window %ris not%K sticky"; + window_set_sticky = "%K::%g:%K Window %gset%K sticky"; + window_unset_sticky = "%K::%g:%K Window %gis not%K sticky anymore"; + window_info_sticky = "Sticky : $0"; + window_scroll = "%K::%g:%K Window scroll mode is now $0"; + window_scroll_unknown = "%r:%K:: %rUnknown%K scroll mode $0, must be ON, OFF or DEFAULT"; + }; + "fe-common/irc" = { + netsplit = "%r:%K:: %r{netsplit netsplit}%K %|{server $0} <-> {server $1} %rquits%K: $2"; + netsplit_more = "%r:%K:: %r{netsplit netsplit}%K %|{server $0} <-> {server $1} %rquits:%K $2 (+$3 more, use /NETSPLIT to show all of them)"; + netsplit_join = "%K::%g:%K %g{netjoin netsplit}%K - %|%gjoins:%K $0"; + netsplit_join_more = "%%K::%g:%K %g{netjoin netsplit}%K - %|over, %gjoins:%K $0 (+$1 more)"; + no_netsplits = "%r:%y:%g:%K There are no netsplits"; + netsplits_header = "Nick Channel Server Splitted server"; + netsplits_line = "$[9]0 $[10]1 $[20]2 $3"; + netsplits_footer = ""; + ircnet_added = "%K::%g:%K Ircnet $0 %gsaved%K"; + ircnet_removed = "%K::%g:%K Ircnet $0 %gremoved%K"; + ircnet_not_found = "%r:%K:: Ircnet $0 %rnot found%K"; + ircnet_header = "%r:%y:%g:%K Ircnets:"; + ircnet_line = "$0: $1"; + ircnet_footer = ""; + setupserver_header = "Server Port Network Settings"; + setupserver_line = "%|$[!20]0 $[5]1 $[10]2 $3"; + setupserver_footer = ""; + joinerror_toomany = "%r:%K:: Join %rfails%K: {channel $0} (You have joined to too many channels)"; + joinerror_full = "%r:%K:: Join %rfails%K: {channel $0} (Channel is full)"; + joinerror_invite = "%r:%K:: Join %rfails%K: {channel $0} (You must be invited)"; + joinerror_banned = "%r:%K:: Join %rfails%K: {channel $0} (You are banned)"; + joinerror_bad_key = "%r:%K:: Join %rfails%K: {channel $0} (Wrong channel key)"; + joinerror_bad_mask = "%r:%K:: Join %rfails%K: {channel $0} (Bad channel mask)"; + joinerror_unavail = "%r:%K:: Join %rfails%K: {channel $0} (Channel is temporarily unavailable)"; + joinerror_duplicate = "%r:%K:: Channel {channel $0} already exists - %rcannot create%K it"; + channel_rejoin = "%r:%K:: Channel {channel $0} is temporarily %runavailable%K. Setting up a rejoin, to not rejoin, use /rmrejoins."; + inviting = "%K::%g:%K %gInviting%K {nick $0} to {channel $1}"; + channel_created = "%r:%y:%g:%K Channel {channel $0} created %_$1%_"; + url = "%r:%y:%g:%K Home page for {channelhilight $0}: $1"; + topic = "%r:%y:%g:%K Topic for {channel $0}: %_$1%_"; + no_topic = "%r:%y:%g:%K No topic set for %_$0%_"; + topic_info = "%r:%y:%g:%K Topic set by {channick_hilight $0} {mode $1}"; + chanmode_change = "%K:%y:%K: %ymode%K/{channel $0} [{mode $1}] by {nick $2}"; + server_chanmode_change = "%K::%g: {netsplit ServerMode}%K/{channelhilight $0}: {mode $1} by {nick $2}"; + channel_mode = "%K:%y:%K: %ymode%K/{channelhilight $0} [{mode $1}]"; + bantype = "%K:%y:%K: Ban type %ychanged%K to {channel $0}"; + no_bans = "%r:%y:%g:%K No bans in channel {channel $0}"; + banlist = "$0 - {channel $1}: ban {ban $2}"; + banlist_long = "$0 - {channel $1}: ban {ban $2} {comment by {nick $3}, $4 secs ago}"; + ebanlist = "{channel $0}: ban exception {ban $1}"; + ebanlist_long = "{channel $0}: ban exception {ban $1} {comment by {nick $2}, $3 secs ago}"; + no_invitelist = "%r:%y:%g:%K Invite list is empty in channel {channel $0}"; + invitelist = "{channel $0}: invite {ban $1}"; + no_such_channel = "%r:%K::%K {channel $0}: %rNo such%K channel"; + channel_change = "%K:%y:%K: %ymode%K/{channel $0} [{mode $1}]"; + channel_synced = "%r:%y:%g:%K Join to {channel $0} was synced in {hilight $1} secs"; + usermode_change = "%K:%y:%K: %ymode%K/{channel $0} [{mode $0}] by {channick_hilight $1}"; + user_mode = "%r:%y:%g:%K Your user mode is {mode $0}"; + away = "%K::%g:%K You have been %gmarked%K as being away"; + unaway = "%K::%g:%K You are %gno longer marked%K as being away"; + nick_away = "%r:%K::%K {nick $0} is %raway%K: $1"; + no_such_nick = "%r:%K::%K {nick $0}: %rNo such%K nick/channel"; + nick_in_use = "%r:%K::%K Nick {nick $0} is %ralready in use%K"; + nick_unavailable = "%r:%K::%K Nick {nick $0} is temporarily %runavailable%K"; + your_nick_owned = "%r:%K::%K Your nick is %rowned%K by {nick $3} {comment $1@$2}"; + whois = "%K:%K:%g:%K %g%U{nick $0}%U%K ({nickhost $1@$2})%:%r:%y:%g:%K ircname: $3"; + whowas = "%r:%y:%g:%K {nick $0} {nickhost $1@$2}%:%r:%y:%g:%K {whois ircname $3}"; + whois_idle = "%r:%y:%g:%K Idle: %|since $1 days $2 hours $3 mins $4 secs"; + whois_idle_signon = "%r:%y:%g:%K Idle: %|since $1 days $2 hours $3 mins $4 secs {comment Signed on: $5}"; + whois_server = "%r:%y:%g:%K Server: %|$1 {comment $2}"; + whois_oper = "%r:%y:%g:%K Info: %|{hilight $1}"; + whois_registered = "%r:%y:%g:%K Info: %|has registered this nick"; + whois_help = "%r:%y:%g:%K Info: %|available for help"; + whois_modes = "%r:%y:%g:%K Modes: %|{mode $1}"; + whois_realhost = "%r:%y:%g:%K Hostname: %|{hilight $1-}"; + whois_usermode = "%r:%y:%g:%K Usermode: %|{mode $1}"; + whois_channels = "%r:%y:%g:%K Channels: %|{channel $1}"; + whois_away = "%r:%y:%g:%K Away: %|$1"; + whois_special = "%r:%y:%g:%K Info: %|$1"; + whois_extra = "%r:%y:%g:%K Info: %|$1"; + end_of_whois = "%r:%K::%K %rEnd%K of WHOIS%K"; + end_of_whowas = "%r:%y:%g:%K End of WHOWAS"; + whois_not_found = "%r:%K::%K There is %rno such%K nick {channick_hilight $0}"; + who = "{channelhilight $[-10]0} %|{nick $[!9]1} $[!3]2 $[!2]3 $4@$5 {comment {hilight $6}}"; + end_of_who = "%r:%y:%g:%K End of /WHO list"; + own_notice = "{ownnotice notice $0}$1"; + # own_action = "{nick $[-11]0}%n $1"; + # own_action_target = "{ownaction_target $0 $2}$1"; + own_ctcp = "{ownctcp ctcp $0}$1 $2"; + notice_server = "{servernotice $0}$1"; + notice_public = "{notice $0{pubnotice_channel $1}}$2"; + notice_private = "{notice $0{pvtnotice_host $1}}$2"; + # action_private = "{pvtaction $0}$2"; + # action_private_query = "{pvtaction_query $0}$2"; + # action_public = " {nick $[-11]0}%n $1"; + # action_public_channel = "{pubaction $0{msgchannel $1}}$2"; + ctcp_reply = "%K::%g:%K %gCTCP%K {hilight $0} reply from {channick_hilight $1}: $2"; + ctcp_reply_channel = "%K::%g:%K %gCTCP {hilight $0} reply%K from {channick_hilight $1} in channel {channel $3}: $2"; + ctcp_ping_reply = "%K::%g:%K %gCTCP {hilight PING} reply%K from {channick_hilight $0}: $1.$[-3.0]2 seconds"; + ctcp_requested = "%K::%g:%K %K{ctcp {hilight $0} {comment $1} %grequested%K {hilight $2} from {nick $3}}"; + ctcp_requested_unknown = ""; + online = "%r:%y:%g:%K Users online: {hilight $0}"; + pong = "%K::%g:%K PONG %greceived%K from $0: $1"; + wallops = "{wallop WALLOP {wallop_nick $0}} $1"; + action_wallops = "{wallop WALLOP {wallop_action $0}} $1"; + kill = "%r:%K:: You were %r{error killed}%K by {nick $0} {nickhost $1} {reason $2} {comment Path: $3}"; + kill_server = "%r:%K:: You were %r{error killed}%K by {server $0} {reason $1} {comment Path: $2}"; + error = "%r:%K:: %r{error ERROR}%K $0"; + unknown_mode = "%r:%K:: %rUnknown%K mode character $0"; + not_chanop = "%r:%K:: You're %rnot channel operator%K in {channel $0}"; + silenced = "%K::%g:%K %gSilenced%K {nick $0}"; + unsilenced = "%K::%g:%K %gUnsilenced%K {nick $0}"; + silence_line = "{nick $0}: silence {ban $1}"; + ask_oper_pass = "%r:%y:%g:%K Operator password:"; + own_action = "{ownaction $[-5]0} $1"; + action_private = "{pvtaction $[-5]0}$1"; + action_private_query = "{pvtaction_query $[-5]0} $2"; + action_public = "{pubaction $[-5]0}$1"; + }; + "fe-common/perl" = { + script_not_found = "%r:%K:: Script {hilight $0} %rnot found%K"; + script_not_loaded = "%r:%K:: Script {hilight $0} %ris not%K loaded"; + script_loaded = "%K::%g:%K %gLoaded%K script {hilight $0}"; + script_unloaded = "%r:%K:: %rUnloaded%K script {hilight $0}"; + no_scripts_loaded = "%r:%y:%g:%K No scripts are loaded"; + script_list_header = "%r:%y:%g:%K Loaded scripts:"; + script_list_line = "$[!15]0 $1"; + script_list_footer = ""; + script_error = "{error %r:%K:: %rError%K in script {hilight $0}:}"; + }; + # "fe-common/irc/notifylist" = { + # notify_join = "{nick $0} [$1@$2] [{hilight $3}] has joined to $4"; + # notify_part = "{nick $0} has left $4"; + # notify_away = "{nick $0} [$5] [$1@$2] [{hilight $3}] is now away: $4"; + # notify_unaway = "{nick $0} [$4] [$1@$2] [{hilight $3}] is now unaway"; + # notify_unidle = "{nick $0} [$5] [$1@$2] [{hilight $3}] just stopped idling"; + # notify_online = "On $0: {hilight $1}"; + # notify_offline = "Offline: $0"; + # notify_list = "$0: $1 $2 $3"; + # notify_list_empty = "The notify list is empty"; + # }; + "Irssi::Script::xchatnickcolor" = { + pubmsg_hilight = "{pubmsghinick $0 $0 $[-7]1$3%n}$2"; + }; +}; + diff --git a/dotfiles/irssi/scripts/adv_windowlist.pl b/dotfiles/irssi/scripts/adv_windowlist.pl new file mode 100644 index 0000000..780ab35 --- /dev/null +++ b/dotfiles/irssi/scripts/adv_windowlist.pl @@ -0,0 +1,2478 @@ +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(bd@bc-bd.org, veli@piipiip.net, tss@iki.fi, ). + q(wouter@coekaerts.be, jylefort@brutele.be), + authors => q(Nei), + contact => q(Nei @ anti@conference.jabber.teamidiot.de), + 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-. +# # +# # for irssi 0.8.2 by bd@bc-bd.org +# # +# # inspired by chanlist.pl by 'cumol@hammerhart.de' +# # +# ######### +# # {{{ Contributors +# ######### +# # +# # veli@piipiip.net /window_alias code +# # qrczak@knm.org.pl chanact_abbreviate_names +# # qerub@home.se 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 ( vb@g-23.org ) 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 +# /set awl_display_key +# /set awl_display_nokey_active +# /set awl_display_key_active +# * 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 : 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 +# * 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 : 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 : number of lines to use for the window list (0 to disable, negative +# lock) +# }}} +# {{{ /set awl_columns +# * num : number of columns to use in screen mode (0 for unlimited) +# }}} +# {{{ /set awl_block +# * 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 +# * 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 : 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 +# /set awl_position +# * these settings correspond to /statusbar because awl will create +# statusbars for you +# (see /help statusbar to learn more) +# }}} +# {{{ /set awl_all_disable +# * 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 +# * this setting defines whether the window list is shown in statusbars or +# whether the screen hack is used (from nicklist.pl) +# }}} +# }}} +########## +# {{{ COMMANDS +######## +# {{{ /awl paste +# * 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 =^.^= ( anti@conference.jabber.teamidiot.de ) +# }}} + +# }}} + +# {{{ 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; } + +## 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, + # by Ned Konz, perl@bike-nomad.com + # 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 ( geert@irssi.org ) :) +# - 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 : diff --git a/dotfiles/irssi/scripts/autorun/adv_windowlist.pl b/dotfiles/irssi/scripts/autorun/adv_windowlist.pl new file mode 120000 index 0000000..d210a5c --- /dev/null +++ b/dotfiles/irssi/scripts/autorun/adv_windowlist.pl @@ -0,0 +1 @@ +../adv_windowlist.pl \ No newline at end of file diff --git a/dotfiles/irssi/scripts/autorun/hilightwin.pl b/dotfiles/irssi/scripts/autorun/hilightwin.pl new file mode 120000 index 0000000..fb9568b --- /dev/null +++ b/dotfiles/irssi/scripts/autorun/hilightwin.pl @@ -0,0 +1 @@ +../hilightwin.pl \ No newline at end of file diff --git a/dotfiles/irssi/scripts/autorun/niq.pl b/dotfiles/irssi/scripts/autorun/niq.pl new file mode 120000 index 0000000..6fbb467 --- /dev/null +++ b/dotfiles/irssi/scripts/autorun/niq.pl @@ -0,0 +1 @@ +../niq.pl \ No newline at end of file diff --git a/dotfiles/irssi/scripts/autorun/nm.pl b/dotfiles/irssi/scripts/autorun/nm.pl new file mode 120000 index 0000000..e486d46 --- /dev/null +++ b/dotfiles/irssi/scripts/autorun/nm.pl @@ -0,0 +1 @@ +../nm.pl \ No newline at end of file diff --git a/dotfiles/irssi/scripts/autorun/postpone.pl b/dotfiles/irssi/scripts/autorun/postpone.pl new file mode 120000 index 0000000..08aff6a --- /dev/null +++ b/dotfiles/irssi/scripts/autorun/postpone.pl @@ -0,0 +1 @@ +../postpone.pl \ No newline at end of file diff --git a/dotfiles/irssi/scripts/autorun/screen_away.pl b/dotfiles/irssi/scripts/autorun/screen_away.pl new file mode 120000 index 0000000..baa7b36 --- /dev/null +++ b/dotfiles/irssi/scripts/autorun/screen_away.pl @@ -0,0 +1 @@ +../screen_away.pl \ No newline at end of file diff --git a/dotfiles/irssi/scripts/autorun/topic-diff.pl b/dotfiles/irssi/scripts/autorun/topic-diff.pl new file mode 120000 index 0000000..707981e --- /dev/null +++ b/dotfiles/irssi/scripts/autorun/topic-diff.pl @@ -0,0 +1 @@ +../topic-diff.pl \ No newline at end of file diff --git a/dotfiles/irssi/scripts/autorun/trackbar.pl b/dotfiles/irssi/scripts/autorun/trackbar.pl new file mode 120000 index 0000000..8c5a483 --- /dev/null +++ b/dotfiles/irssi/scripts/autorun/trackbar.pl @@ -0,0 +1 @@ +../trackbar.pl \ No newline at end of file diff --git a/dotfiles/irssi/scripts/autorun/usercount.pl b/dotfiles/irssi/scripts/autorun/usercount.pl new file mode 120000 index 0000000..1afd2ea --- /dev/null +++ b/dotfiles/irssi/scripts/autorun/usercount.pl @@ -0,0 +1 @@ +../usercount.pl \ No newline at end of file diff --git a/dotfiles/irssi/scripts/autorun/xchatnickcolor.pl b/dotfiles/irssi/scripts/autorun/xchatnickcolor.pl new file mode 120000 index 0000000..e1798b9 --- /dev/null +++ b/dotfiles/irssi/scripts/autorun/xchatnickcolor.pl @@ -0,0 +1 @@ +../xchatnickcolor.pl \ No newline at end of file diff --git a/dotfiles/irssi/scripts/beep_beep.pl b/dotfiles/irssi/scripts/beep_beep.pl new file mode 100644 index 0000000..139b95a --- /dev/null +++ b/dotfiles/irssi/scripts/beep_beep.pl @@ -0,0 +1,51 @@ +#!/usr/bin/irssi +# +# irssi beep replace script (tested with irssi v0.8.8.CVS (20030126-1726)) +# (C) 2002-2004 Ge0rG@IRCnet (Georg Lukas ) +# inspired and tested by Macrotron@IRCnet (macrotron@president.eu.org) + +# added beep_flood to irssi settings: beep_cmd will be run not more often +# then every $beep_flood milliseconds + +# fixed memory leak with timeout_add (made irssi waste 80mb and more after a day of IRC) +# added > /dev/null, thx to Luis Oliveira +# fixed timeout handling bug, thx to frizop@charter.net + +$VERSION = "0.10"; +%IRSSI = ( + authors => "Georg Lukas", + contact => "georg\@op-co.de", + name => "beep_beep", + description => "runs arbitrary command instead of system beep, includes flood protection", + license => "Public Domain", + url => "http://op-co.de/irssi/", +); + +use Irssi; + +my $might_beep = 1, $to_tag; + +sub beep_overflow_timeout() { + $might_beep = 1; + Irssi::timeout_remove($to_tag); +} + +sub beep_beep() { + my $beep_cmd = Irssi::settings_get_str("beep_cmd"); + if ($beep_cmd) { + if ($might_beep) { + my $beep_flood = Irssi::settings_get_int('beep_flood'); + $beep_flood = 1000 if $beep_flood < 0; + Irssi::timeout_remove($to_tag); + $to_tag = Irssi::timeout_add($beep_flood, 'beep_overflow_timeout', undef); + system($beep_cmd); + $might_beep = 0; + } + Irssi::signal_stop(); + } +} + +Irssi::settings_add_str("lookandfeel", "beep_cmd", "ogg123 --quiet /usr/share/sounds/KDE-Im-Irc-Event.ogg &"); +Irssi::settings_add_int("lookandfeel", "beep_flood", 1000); +Irssi::signal_add("beep", "beep_beep"); + diff --git a/dotfiles/irssi/scripts/cap_sasl.pl b/dotfiles/irssi/scripts/cap_sasl.pl new file mode 100644 index 0000000..1de3aca --- /dev/null +++ b/dotfiles/irssi/scripts/cap_sasl.pl @@ -0,0 +1,272 @@ +use strict; +use Irssi; +use vars qw($VERSION %IRSSI); +# $Id$ + +use MIME::Base64; + +$VERSION = "1.1"; + +%IRSSI = ( + authors => 'Michael Tharp and Jilles Tjoelker', + contact => 'gxti@partiallystapled.com', + 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 "); + } +} + +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 () { + 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 diff --git a/dotfiles/irssi/scripts/hilightwin.pl b/dotfiles/irssi/scripts/hilightwin.pl new file mode 100644 index 0000000..f7af8a7 --- /dev/null +++ b/dotfiles/irssi/scripts/hilightwin.pl @@ -0,0 +1,57 @@ +# +# 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: diff --git a/dotfiles/irssi/scripts/nicklist.pl b/dotfiles/irssi/scripts/nicklist.pl new file mode 100644 index 0000000..0dbe4fb --- /dev/null +++ b/dotfiles/irssi/scripts/nicklist.pl @@ -0,0 +1,611 @@ +# 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 => 'coekie@irssi.org', + 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 ( < +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 + /SET nicklist_width + /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, "+{'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') || $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(); +} diff --git a/dotfiles/irssi/scripts/niq.pl b/dotfiles/irssi/scripts/niq.pl new file mode 100644 index 0000000..479ffcc --- /dev/null +++ b/dotfiles/irssi/scripts/niq.pl @@ -0,0 +1,295 @@ +# BitchX TAB complete style +# for irssi 0.7.99 by bd@bc-bd.org +# +# signal handling learned from dictcomplete by Timo Sirainen +# +# thx go out to fuchs, darix, dg, peder and all on #irssi who helped +# +######### +# USAGE +### +# +# In a channel window type "ab" to see a list of nicks starting +# with "ab". +# If you now press again, irssi will default to its own nick +# completion method. +# If you enter more characters you can use again to see a list +# of the matching nicks, or to complete the nick if there is only +# one matching. +# +# The last completion is saved so if you press "" with an empty +# input line, you get the last completed nick. +# +# Now there is a statusbar item where you can see the completing +# nicks instead of in the channel window. There are two ways to +# use it: +# +# 1) Inside another statusbar +# +# /set niq_show_in_statusbar ON +# /statusbar window add -before more niq +# +# 2) In an own statusbar +# +# /statusbar niq enable +# /statusbar niq add niq +# /statusbar niq disable +# /set niq_show_in_statusbar ON +# /set niq_own_statusbar ON +# +# You can also hide the bar when not completing nicks by using +# +# /set niq_hide_on_inactive ON +# +######### +# OPTIONS +######### +# +# /set niq_show_in_statusbar +# * ON : show the completing nicks in a statusbar item +# * OFF : show the nicks in the channel window +# +# /set niq_own_statusbar +# * ON : use an own statusbar for the nicks +# * OFF : just use an item +# +# /set niq_hide_on_inactive +# * ON : hide the own statusbar on inactivity +# * OFF : dont hide it +# +# /set niq_color_char +# * ON : colors the next unlikely character +# * OFF : boring no colors +# +### +################ +### +# Changelog +# +# Version 0.5.7 +# - use configured completion_char instead of a colon +# - removed old, unused code +# - fixed url +# - fixed documentation leading to emtpy statusbar +# - removed warning about a problem with irssi version 0.8.4 +# +# Version 0.5.6 +# - work around an use problem +# +# Version 0.5.5 +# - fixed completion for nicks starting with special chars +# +# Version 0.5.4 +# - removed unneeded sort() of colored nicks +# - moved colored nick generation to where it is needed +# - the statusbar only worked with colorized nicks (duh!) +# +# Version 0.5.3 +# - stop nickcompleting if last char is the completion_char +# which is in most cases ':' +# +# Version 0.5.2 +# - fixed vanishing statusbar. it wrongly was reset on any +# privmsg. +# +# Version 0.5.1 +# - changed statusbar to be off by default since most people +# dont use the latest fixed version. +# +# Version 0.5 +# - added own statusbar option +# - added color char option +# +# Version 0.4 +# - added an niq statusbar +# +# Version 0.3 +# - added default to irssi method on +# +# Version 0.2 +# - added lastcomp support +# +# Version 0.1 +# - initial release +### +################ + +use Irssi; +use Irssi::TextUI; +use strict; + +use vars qw($VERSION %IRSSI); + +$VERSION="0.5.7"; +%IRSSI = ( + authors=> 'BC-bd', + contact=> 'bd@bc-bd.org', + name=> 'niq', + description=> 'BitchX like Nickcompletion at line start plus statusbar', + license=> 'GPL v2', + url=> 'https://bc-bd.org/cgi-bin/gitweb.cgi?p=irssi.git;a=summary', +); + +my($lastword,$lastcomp,$niqString); + +$lastcomp = ""; +$lastword = ""; + +# build our nick with completion_char, add to complist and stop the signal +sub buildNickAndStop { + my ($complist,$nick) = @_; + my $push = $nick.Irssi::settings_get_str('completion_char'); + + $lastcomp = $nick; + $lastword = ""; + push (@{$complist}, $push); + + if (Irssi::settings_get_bool('niq_show_in_statusbar') == 1) { + drawStatusbar(""); + } + + Irssi::signal_stop(); +} + +# the signal handler +sub sig_complete { + my ($complist, $window, $word, $linestart, $want_space) = @_; + + # still allow channel- #, /set n, etc completion. + if ($linestart ne "") { + return; + } + + # also back out if nothing has been entered and lastcomp is "" + if ($word eq "") { + if ($lastcomp ne "") { + buildNickAndStop($complist,$lastcomp); + return; + } else { + return; + } + } + if (rindex($word,Irssi::settings_get_str('completion_char')) == length($word) -1) { + chop($word); + buildNickAndStop($complist,$word,0); + return; + } + + my $channel = $window->{active}; + + # the completion is ok if this is a channel + if ($channel->{type} ne "CHANNEL") + { + return; + } + + my (@nicks); + + # get the matching nicks but quote this l33t special chars like ^ + my $shortestNick = 999; + my $quoted = quotemeta $word; + foreach my $n ($channel->nicks()) { + if ($n->{nick} =~ /^$quoted/i && $window->{active_server}->{nick} ne $n->{nick}) { + push(@nicks,$n->{nick}); + if (length($n->{nick}) < $shortestNick) { + $shortestNick = length($n->{nick}); + } + } + } + + @nicks = sort(@nicks); + + # if theres only one nick return it. + if (scalar @nicks eq 1) + { + buildNickAndStop($complist,$nicks[0]); + } elsif (scalar @nicks gt 1) { + # check if this is or + if ($lastword eq $word) { + # so default to the irssi method + sort(@nicks); + for (@nicks) { + $_ .= Irssi::settings_get_str ('completion_char'); + } + + push (@{$complist}, @nicks); + + # but delete lastword to be ready for the next + $lastword = ""; + + if (Irssi::settings_get_bool('niq_show_in_statusbar') == 1) { + drawStatusbar(""); + } + + return; + } else { + # only so just print + + # build string w/o colored nicks + if (Irssi::settings_get_bool('niq_color_char') == 1) { + $niqString = ""; + foreach my $n (@nicks) { + my $coloredNick = $n; + $coloredNick =~ s/($quoted)(.)(.*)/$1%_$2%_$3/i; + $niqString .= "$coloredNick "; + } + } else { + $niqString = join(" ",@nicks); + } + + if (Irssi::settings_get_bool('niq_show_in_statusbar') == 1) { + drawStatusbar($niqString); + } else { + $window->print($niqString); + } + + Irssi::signal_stop(); + + # remember last word + $lastword = $word; + + return; + } + } +} + +sub emptyBar() { + $lastword = ""; + + drawStatusbar(""); +} + +sub drawStatusbar() { + my ($word) = @_; + + if (Irssi::settings_get_bool('niq_own_statusbar') == 1) { + if (Irssi::settings_get_bool('niq_hide_on_inactive') == 1) { + if ($word eq "") { + Irssi::command("statusbar niq disable"); + } else { + Irssi::command("statusbar niq enable"); + } + } + } + + $niqString = "{sb $word}"; + Irssi::statusbar_items_redraw('niq'); +} + +sub niqStatusbar() { + my ($item, $get_size_only) = @_; + + $item->default_handler($get_size_only, $niqString, undef, 1); +} + +Irssi::signal_add_first('complete word', 'sig_complete'); +Irssi::signal_add_last('window changed', 'emptyBar'); +Irssi::signal_add('message own_public', 'emptyBar'); + +Irssi::statusbar_item_register('niq', '$0', 'niqStatusbar'); +Irssi::statusbars_recreate_items(); + +Irssi::settings_add_bool('misc', 'niq_show_in_statusbar', 0); +Irssi::settings_add_bool('misc', 'niq_own_statusbar', 0); +Irssi::settings_add_bool('misc', 'niq_hide_on_inactive', 1); +Irssi::settings_add_bool('misc', 'niq_color_char', 1); diff --git a/dotfiles/irssi/scripts/nm.pl b/dotfiles/irssi/scripts/nm.pl new file mode 100644 index 0000000..b9b2955 --- /dev/null +++ b/dotfiles/irssi/scripts/nm.pl @@ -0,0 +1,662 @@ +use Irssi; +use strict; + +use vars qw($VERSION %IRSSI); + +$VERSION="0.3.10"; +%IRSSI = ( + authors=> 'BC-bd', + contact=> 'bd@bc-bd.org', + 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 bd@bc-bd.org +# +# right aligned nicks depending on longest nick +# +# inspired by neatmsg.pl from kodgehopper for some hints +# thanks to Eric Wald for the left alignment patch +# inspired by nickcolor.pl by Timo Sirainen and Ian Peters +# thanks to And1 for a small patch +# thanks to berber@tzi.de for the save/load patch +# thanks to Dennis Heimbert for a bug report/patch +# +######### +# USAGE +### +# +# use +# +# /neatcolor help +# +# for help on available commands +# +######### +# OPTIONS +######### + +my $help = " +/set neat_colorize + * ON : colorize nicks + * OFF : do not colorize nicks + +/set neat_colors + 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 : print nicks left-aligned on actions + * OFF : print nicks right-aligned on actions + +/set neat_left_messages + * ON : print nicks left-aligned on messages + * OFF : print nicks right-aligned on messages + +/set neat_right_mode + * ON : print the mode of the nick e.g @%+ after the nick + * OFF : print it left of the nick + +/set neat_maxlength + * number : Maximum length of Nicks to display. Longer nicks are truncated. + * 0 : Do not truncate nicks. + +/set neat_melength + * number : number of spaces to substract from /me padding + +/set neat_ignorechars + * 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 : shrink padding when longest nick disappears + * OFF : do not shrink, only allow growing + +"; + +# +### +################ +### +# +# Changelog +# +# 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 , 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 ) +# +# Version 0.2.0 +# - by adrianel +# * 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 $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(); +} + +# 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}); +} + +# 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}; + + 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}); + } + } +} + +# load colors from file +sub load_colors() { + open(FID, "<".$ENV{HOME}."/.irssi/saved_colors") || return; + + while () { + 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); +} + +# 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); + 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; + 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 ", + "", + "displays color used for " + ], + 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|", + "", + "resets the color used for all nicks or for 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 ", + "", + "use for ", + "", + "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::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'); diff --git a/dotfiles/irssi/scripts/notify.pl b/dotfiles/irssi/scripts/notify.pl new file mode 100644 index 0000000..1178307 --- /dev/null +++ b/dotfiles/irssi/scripts/notify.pl @@ -0,0 +1,77 @@ +## +## Put me in ~/.irssi/scripts, and then execute the following in irssi: +## +## /load perl +## /script load notify +## + +use strict; +use Irssi; +use vars qw($VERSION %IRSSI); +use HTML::Entities; + +$VERSION = "0.01"; +%IRSSI = ( + authors => 'Luke Macken, Paul W. Frields', + contact => 'lewk@csh.rit.edu, stickster@gmail.com', + name => 'notify.pl', + description => 'Use libnotify to alert user to hilighted messages', + license => 'GNU General Public License', + url => 'http://lewk.org/log/code/irssi-notify', +); + +Irssi::settings_add_str('notify', 'notify_icon', 'gtk-dialog-info'); +Irssi::settings_add_str('notify', 'notify_time', '5000'); + +sub sanitize { + my ($text) = @_; + encode_entities($text); + return $text; +} + +sub notify { + my ($server, $summary, $message) = @_; + + # Make the message entity-safe + $summary = sanitize($summary); + $message = sanitize($message); + + my $cmd = "EXEC - notify-send" . + " -i " . Irssi::settings_get_str('notify_icon') . + " -t " . Irssi::settings_get_str('notify_time') . + " -- '" . $summary . "'" . + " '" . $message . "'"; + + $server->command($cmd); +} + +sub print_text_notify { + my ($dest, $text, $stripped) = @_; + my $server = $dest->{server}; + + return if (!$server || !($dest->{level} & MSGLEVEL_HILIGHT)); + my $sender = $stripped; + $sender =~ s/^\<.([^\>]+)\>.+/\1/ ; + $stripped =~ s/^\<.[^\>]+\>.// ; + my $summary = $dest->{target} . ": " . $sender; + notify($server, $summary, $stripped); +} + +sub message_private_notify { + my ($server, $msg, $nick, $address) = @_; + + return if (!$server); + notify($server, "Private message from ".$nick, $msg); +} + +sub dcc_request_notify { + my ($dcc, $sendaddr) = @_; + my $server = $dcc->{server}; + + return if (!$dcc); + notify($server, "DCC ".$dcc->{type}." request", $dcc->{nick}); +} + +Irssi::signal_add('print text', 'print_text_notify'); +Irssi::signal_add('message private', 'message_private_notify'); +Irssi::signal_add('dcc request', 'dcc_request_notify'); diff --git a/dotfiles/irssi/scripts/postpone.pl b/dotfiles/irssi/scripts/postpone.pl new file mode 100644 index 0000000..72e0a90 --- /dev/null +++ b/dotfiles/irssi/scripts/postpone.pl @@ -0,0 +1,117 @@ +# by Stefan 'tommie' Tomanek +# +# + +use strict; + +use vars qw($VERSION %IRSSI); +$VERSION = "20030208"; +%IRSSI = ( + authors => "Stefan 'tommie' Tomanek", + contact => "stefan\@pico.ruhr.de", + name => "postpone", + description => "Postpones messages sent to a splitted user and resends them when the nick rejoins", + license => "GPLv2", + changed => "$VERSION", + commands => "postpone" +); + +use Irssi 20020324; +use vars qw(%messages); + +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 show_help() { + my $help="Postpone $VERSION +/postpone help + Display this help +/postpone flush + Flush postponed messages to +/postpone list + List postponed messages +"; + my $text = ''; + foreach (split(/\n/, $help)) { + $_ =~ s/^\/(.*)$/%9\/$1%9/; + $text .= $_."\n"; + } + print CLIENTCRAP &draw_box("Postpone", $text, "help", 1); +} + + +sub event_send_text ($$$) { + my ($line, $server, $witem) = @_; + return unless ($witem && $witem->{type} eq "CHANNEL"); + if ($line =~ /^(\w+?): (.*)$/) { + my ($target, $msg) = ($1,$2); + if ($witem->nick_find($target)) { + # Just leave me alone + return; + } else { + $witem->print("%B>>%n %U".$target."%U is not here, message has been postponed: \"".$line."\"", MSGLEVEL_CLIENTCRAP); + push @{$messages{$server->{tag}}{$witem->{name}}{$target}}, $line; + Irssi::signal_stop(); + } + } +} + +sub event_message_join ($$$$) { + my ($server, $channel, $nick, $address) = @_; + return unless (defined $messages{$server->{tag}}); + return unless (defined $messages{$server->{tag}}{$channel}); + return unless (defined $messages{$server->{tag}}{$channel}{$nick}); + return unless (scalar(@{$messages{$server->{tag}}{$channel}{$nick}}) > 0); + my $chan = $server->channel_find($channel); + $chan->print("%B>>%n Sending postponed messages for ".$nick, MSGLEVEL_CLIENTCRAP); + while (scalar(@{$messages{$server->{tag}}{$channel}{$nick}}) > 0) { + my $msg = pop @{$messages{$server->{tag}}{$channel}{$nick}}; + $server->command('MSG '.$channel.' '.$msg); + } + +} + +sub cmd_postpone ($$$) { + my ($args, $server, $witem) = @_; + my @arg = split(/ /, $args); + if (scalar(@arg) < 1) { + #foo + } elsif ($arg[0] eq 'flush' && defined $arg[1]) { + return unless ($witem && $witem->{type} eq "CHANNEL"); + while (scalar(@{$messages{$server->{tag}}{$witem->{name}}{$arg[1]}}) > 0) { + my $msg = pop @{$messages{$server->{tag}}{$witem->{name}}{$arg[1]}}; + $server->command('MSG '.$witem->{name}.' '.$msg); + } + } elsif ($arg[0] eq 'list') { + my $text; + foreach (keys %messages) { + $text .= $_."\n"; + foreach my $channel (keys %{$messages{$_}}) { + $text .= " %U".$channel."%U \n"; + foreach my $nick (sort keys %{$messages{$_}{$channel}}) { + $text .= ' |'.$_."\n" foreach @{$messages{$_}{$channel}{$nick}}; + } + } + } + print CLIENTCRAP &draw_box('Postpone', $text, 'messages', 1); + } elsif ($arg[0] eq 'help') { + show_help(); + } +} + +Irssi::command_bind('postpone', \&cmd_postpone); + +Irssi::signal_add('send text', \&event_send_text); +Irssi::signal_add('message join', \&event_message_join); + +print CLIENTCRAP "%B>>%n Postpone ".$VERSION." loaded: /postpone help for help"; + diff --git a/dotfiles/irssi/scripts/screen_away.pl b/dotfiles/irssi/scripts/screen_away.pl new file mode 100644 index 0000000..86e3087 --- /dev/null +++ b/dotfiles/irssi/scripts/screen_away.pl @@ -0,0 +1,243 @@ +use Irssi; +use strict; +use FileHandle; + +use vars qw($VERSION %IRSSI); + +$VERSION = "0.9.7.1"; +%IRSSI = ( + authors => 'Andreas \'ads\' Scherbaum ', + name => 'screen_away', + description => 'set (un)away, if screen is attached/detached', + license => 'GPL v2', + url => 'none', +); + +# screen_away irssi module +# +# written by Andreas 'ads' Scherbaum +# +# changes: +# 07.02.2004 fix error with away mode +# thanks to Michael Schiansky for reporting and fixing this one +# 07.08.2004 new function for changing nick on away +# 24.08.2004 fixing bug where the away nick was not storedcorrectly +# thanks for Harald Wurpts for help debugging this one +# 17.09.2004 rewrote init part to use $ENV{'STY'} +# 05.12.2004 add patch for remember away state +# thanks to Jilles Tjoelker +# change "chatnet" to "tag" +# 18.05.2007 fix '-one' for SILC networks +# +# +# usage: +# +# put this script into your autorun directory and/or load it with +# /SCRIPT LOAD +# +# there are 5 settings available: +# +# /set screen_away_active ON/OFF/TOGGLE +# /set screen_away_repeat +# /set screen_away_message +# /set screen_away_window +# /set screen_away_nick +# +# active means, that you will be only set away/unaway, if this +# flag is set, default is ON +# repeat is the number of seconds, after the script will check the +# screen status again, default is 5 seconds +# message is the away message sent to the server, default: not here ... +# window is a window number or name, if set, the script will switch +# to this window, if it sets you away, default is '1' +# nick is the new nick, if the script goes away +# will only be used it not empty +# +# normal you should be able to rename the script to something other +# than 'screen_away' (as example, if you dont like the name) by simple +# changing the 'name' parameter in the %IRSSI hash at the top of this script + + +# variables +my $timer_name = undef; +my $away_status = 0; +my %old_nicks = (); +my %away = (); + +# Register formats +Irssi::theme_register( +[ + 'screen_away_crap', + '{line_start}{hilight ' . $IRSSI{'name'} . ':} $0' +]); + +# if we are running +my $screen_away_used = 0; + +# try to find out, if we are running in a screen +# (see, if $ENV{STY} is set +if (!defined($ENV{STY})) { + # just return, we will never be called again + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'screen_away_crap', + "could not open status file for parent process (pid: " . getppid() . "): $!"); + return; +} + +my ($socket_name, $socket_path); + +# search for socket +# normal we could search the socket file, ... if we know the path +# but so we have to call one time the screen executable +# disable locale +# the quotes around C force perl 5.005_03 to use the shell +# thanks to Jilles Tjoelker for pointing this out +my $socket = `LC_ALL="C" screen -ls`; + + + +my $running_in_screen = 0; +# locale doesnt seems to be an problem (yet) +if ($socket !~ /^No Sockets found/s) { + # ok, should have only one socket + $socket_name = $ENV{'STY'}; + $socket_path = $socket; + $socket_path =~ s/^.+\d+ Sockets? in ([^\n]+)\.\n.+$/$1/s; + if (length($socket_path) != length($socket)) { + # only activate, if string length is different + # (to make sure, we really got a dir name) + $screen_away_used = 1; + } else { + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'screen_away_crap', + "error reading screen informations from:"); + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'screen_away_crap', + "$socket"); + return; + } +} + +# last check +if ($screen_away_used == 0) { + # we will never be called again + return; +} + +# build complete socket name +$socket = $socket_path . "/" . $socket_name; + +# register config variables +Irssi::settings_add_bool('misc', $IRSSI{'name'} . '_active', 1); +Irssi::settings_add_int('misc', $IRSSI{'name'} . '_repeat', 5); +Irssi::settings_add_str('misc', $IRSSI{'name'} . '_message', "not here ..."); +Irssi::settings_add_str('misc', $IRSSI{'name'} . '_window', "1"); +Irssi::settings_add_str('misc', $IRSSI{'name'} . '_nick', ""); + +# init process +screen_away(); + +# screen_away() +# +# check, set or reset the away status +# +# parameter: +# none +# return: +# 0 (OK) +sub screen_away { + my ($away, @screen, $screen); + + # only run, if activated + if (Irssi::settings_get_bool($IRSSI{'name'} . '_active') == 1) { + if ($away_status == 0) { + # display init message at first time + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'screen_away_crap', + "activating $IRSSI{'name'} (interval: " . Irssi::settings_get_int($IRSSI{'name'} . '_repeat') . " seconds)"); + } + # get actual screen status + my @screen = stat($socket); + # 00100 is the mode for "user has execute permissions", see stat.h + if (($screen[2] & 00100) == 0) { + # no execute permissions, Detached + $away = 1; + } else { + # execute permissions, Attached + $away = 2; + } + + # check if status has changed + if ($away == 1 and $away_status != 1) { + # set away + if (length(Irssi::settings_get_str($IRSSI{'name'} . '_window')) > 0) { + # if length of window is greater then 0, make this window active + Irssi::command('window goto ' . Irssi::settings_get_str($IRSSI{'name'} . '_window')); + } + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'screen_away_crap', + "Set away"); + my $message = Irssi::settings_get_str($IRSSI{'name'} . '_message'); + if (length($message) == 0) { + # we have to set a message or we wouldnt go away + $message = "not here ..."; + } + my ($server); + foreach $server (Irssi::servers()) { + if (!$server->{usermode_away}) { + # user isnt yet away + $away{$server->{'tag'}} = 0; + $server->command("AWAY " . (($server->{chat_type} ne 'SILC') ? "-one " : "") . "$message") if (!$server->{usermode_away}); + if (length(Irssi::settings_get_str($IRSSI{'name'} . '_nick')) > 0) { + # only change, if actual nick isnt already the away nick + if (Irssi::settings_get_str($IRSSI{'name'} . '_nick') ne $server->{nick}) { + # keep old nick + $old_nicks{$server->{'tag'}} = $server->{nick}; + # set new nick + $server->command("NICK " . Irssi::settings_get_str($IRSSI{'name'} . '_nick')); + } + } + } else { + # user is already away, remember this + $away{$server->{'tag'}} = 1; + } + } + $away_status = $away; + } elsif ($away == 2 and $away_status != 2) { + # unset away + Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'screen_away_crap', + "Reset away"); + my ($server); + foreach $server (Irssi::servers()) { + if ($away{$server->{'tag'}} == 1) { + # user was already away, dont reset away + $away{$server->{'tag'}} = 0; + next; + } + $server->command("AWAY" . (($server->{chat_type} ne 'SILC') ? " -one" : "")) if ($server->{usermode_away}); + if (defined($old_nicks{$server->{'tag'}}) and length($old_nicks{$server->{'tag'}}) > 0) { + # set old nick + $server->command("NICK " . $old_nicks{$server->{'tag'}}); + $old_nicks{$server->{'tag'}} = ""; + } + } + $away_status = $away; + } + } + # but everytimes install a new timer + register_screen_away_timer(); + return 0; +} + +# register_screen_away_timer() +# +# remove old timer and install a new one +# +# parameter: +# none +# return: +# none +sub register_screen_away_timer { + if (defined($timer_name)) { + # remove old timer, if defined + Irssi::timeout_remove($timer_name); + } + # add new timer with new timeout (maybe the timeout has been changed) + $timer_name = Irssi::timeout_add(Irssi::settings_get_int($IRSSI{'name'} . '_repeat') * 1000, 'screen_away', ''); +} + diff --git a/dotfiles/irssi/scripts/scriptassist.pl b/dotfiles/irssi/scripts/scriptassist.pl new file mode 100644 index 0000000..8b63139 --- /dev/null +++ b/dotfiles/irssi/scripts/scriptassist.pl @@ -0,0 +1,1160 @@ +# by Stefan "tommie" Tomanek +# +# scriptassist.pl + + +use strict; + +use vars qw($VERSION %IRSSI); +$VERSION = '2003020803'; +%IRSSI = ( + authors => 'Stefan \'tommie\' Tomanek', + contact => 'stefan@pico.ruhr.de', + name => 'scriptassist', + description => 'keeps your scripts on the cutting edge', + license => 'GPLv2', + url => 'http://irssi.org/scripts/', + changed => $VERSION, + modules => 'Data::Dumper LWP::UserAgent (GnuPG)', + commands => "scriptassist" +); + +use vars qw($forked %remote_db $have_gpg); + +use Irssi 20020324; +use Data::Dumper; +use LWP::UserAgent; +use POSIX; + +# GnuPG is not always needed +use vars qw($have_gpg @complist); +$have_gpg = 0; +eval "use GnuPG qw(:algo :trust);"; +$have_gpg = 1 if not ($@); + +sub show_help() { + my $help = "scriptassist $VERSION +/scriptassist check + Check all loaded scripts for new available versions +/scriptassist update + Update the selected or all script to the newest version +/scriptassist search + Search the script database +/scriptassist info + Display information about +/scriptassist ratings + Retrieve the average ratings of the the scripts +/scriptassist top + Retrieve the first top rated scripts +/scriptassist new + Display the newest scripts +/scriptassist rate