commit: 62d50f727a9929fbdc10281c7e19e0f2b944f641
parent: 1953df066dc916ca0797be4bbddf60c65be4d59b
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Sun, 29 Jul 2018 03:47:04 +0200
.weechat: New config
Diffstat:
28 files changed, 4683 insertions(+), 0 deletions(-)
diff --git a/.weechat/alias.conf b/.weechat/alias.conf
@@ -0,0 +1,48 @@
+#
+# weechat -- alias.conf
+#
+# WARNING: It is NOT recommended to edit this file by hand,
+# especially if WeeChat is running.
+#
+# Use /set or similar command to change settings in WeeChat.
+#
+# For more info, see: https://weechat.org/doc/quickstart
+#
+
+[cmd]
+AAWAY = "allserv /away"
+AME = "allchan /me"
+AMSG = "allchan /msg *"
+ANICK = "allserv /nick"
+BEEP = "print -beep"
+BYE = "quit"
+C = "buffer clear"
+CHAT = "dcc chat"
+CL = "buffer clear"
+CLOSE = "buffer close"
+EXIT = "quit"
+IG = "ignore"
+J = "join"
+K = "kick"
+KB = "kickban"
+LEAVE = "part"
+M = "msg"
+MSGBUF = "command -buffer $1 * /input send $2-"
+MUB = "unban *"
+N = "names"
+Q = "query"
+REDRAW = "window refresh"
+SAY = "msg *"
+SIGNOFF = "quit"
+T = "topic"
+UB = "unban"
+UMODE = "mode $nick"
+V = "command core version"
+W = "who"
+WC = "window merge"
+WI = "whois"
+WII = "whois $1 $1"
+WW = "whowas"
+
+[completion]
+MSGBUF = "%(buffers_plugins_names)"
diff --git a/.weechat/aspell.conf b/.weechat/aspell.conf
@@ -0,0 +1,33 @@
+#
+# weechat -- aspell.conf
+#
+# WARNING: It is NOT recommended to edit this file by hand,
+# especially if WeeChat is running.
+#
+# Use /set or similar command to change settings in WeeChat.
+#
+# For more info, see: https://weechat.org/doc/quickstart
+#
+
+[color]
+misspelled = lightred
+suggestion = default
+suggestion_delimiter_dict = cyan
+suggestion_delimiter_word = cyan
+
+[check]
+commands = "ame,amsg,away,command,cycle,kick,kickban,me,msg,notice,part,query,quit,topic"
+default_dict = ""
+during_search = off
+enabled = off
+real_time = off
+suggestions = -1
+word_min_length = 2
+
+[dict]
+
+[look]
+suggestion_delimiter_dict = " / "
+suggestion_delimiter_word = ","
+
+[option]
diff --git a/.weechat/autosort.conf b/.weechat/autosort.conf
@@ -0,0 +1,22 @@
+#
+# weechat -- autosort.conf
+#
+# WARNING: It is NOT recommended to edit this file by hand,
+# especially if WeeChat is running.
+#
+# Use /set or similar command to change settings in WeeChat.
+#
+# For more info, see: https://weechat.org/doc/quickstart
+#
+
+[sorting]
+case_sensitive = off
+replacements = ""
+rules = ""
+signal_delay = 5
+signals = "buffer_opened buffer_merged buffer_unmerged buffer_renamed"
+sort_on_config_change = on
+
+[v3]
+helpers = "{"core_first": "${if:${buffer.full_name}!=core.weechat}", "irc_first": "${if:${buffer.plugin.name}!=irc}", "irc_last": "${if:${buffer.plugin.name}==irc}", "irc_raw_first": "${if:${buffer.full_name}!=irc.irc_raw}", "irc_raw_last": "${if:${buffer.full_name}==irc.irc_raw}", "hashless_name": "${info:autosort_replace,#,,${buffer.name}}"}"
+rules = "["${core_first}", "${irc_last}", "${buffer.plugin.name}", "${irc_raw_first}", "${if:${plugin}==irc?${server}}", "${if:${plugin}==irc?${info:autosort_order,${type},server,*,channel,private}}", "${if:${plugin}==irc?${hashless_name}}", "${buffer.full_name}"]"
diff --git a/.weechat/buflist.conf b/.weechat/buflist.conf
@@ -0,0 +1,39 @@
+#
+# weechat -- buflist.conf
+#
+# WARNING: It is NOT recommended to edit this file by hand,
+# especially if WeeChat is running.
+#
+# Use /set or similar command to change settings in WeeChat.
+#
+# For more info, see: https://weechat.org/doc/quickstart
+#
+
+[look]
+add_newline = on
+auto_scroll = 50
+display_conditions = "${buffer.hidden}==0"
+enabled = on
+mouse_jump_visited_buffer = off
+mouse_move_buffer = on
+mouse_wheel = on
+nick_prefix = on
+nick_prefix_empty = on
+signals_refresh = ""
+sort = "number,-active"
+
+[format]
+buffer = "${format_number}${indent}${format_nick_prefix}${color_hotlist}${format_name}"
+buffer_current = "${color:,7}${format_buffer}"
+hotlist = " ${color:green}(${hotlist}${color:green})"
+hotlist_highlight = "${color:magenta}"
+hotlist_low = "${color:white}"
+hotlist_message = "${color:7}"
+hotlist_none = "${color:default}"
+hotlist_private = "${color:green}"
+hotlist_separator = "${color:default},"
+indent = " "
+lag = " ${color:green}[${color:brown}${lag}${color:green}]"
+name = "${name}"
+nick_prefix = "${color_nick_prefix}${nick_prefix}"
+number = "${color:green}${number}${if:${number_displayed}?.: }"
diff --git a/.weechat/charset.conf b/.weechat/charset.conf
@@ -0,0 +1,18 @@
+#
+# weechat -- charset.conf
+#
+# WARNING: It is NOT recommended to edit this file by hand,
+# especially if WeeChat is running.
+#
+# Use /set or similar command to change settings in WeeChat.
+#
+# For more info, see: https://weechat.org/doc/quickstart
+#
+
+[default]
+decode = "iso-8859-1"
+encode = ""
+
+[decode]
+
+[encode]
diff --git a/.weechat/colorize_nicks.conf b/.weechat/colorize_nicks.conf
@@ -0,0 +1,20 @@
+#
+# weechat -- colorize_nicks.conf
+#
+# WARNING: It is NOT recommended to edit this file by hand,
+# especially if WeeChat is running.
+#
+# Use /set or similar command to change settings in WeeChat.
+#
+# For more info, see: https://weechat.org/doc/quickstart
+#
+
+[look]
+blacklist_channels = ""
+blacklist_nicks = "so,root"
+colorize_input = off
+greedy_matching = on
+ignore_nicks_in_urls = off
+ignore_tags = ""
+match_limit = 20
+min_nick_length = 2
diff --git a/.weechat/exec.conf b/.weechat/exec.conf
@@ -0,0 +1,18 @@
+#
+# weechat -- exec.conf
+#
+# WARNING: It is NOT recommended to edit this file by hand,
+# especially if WeeChat is running.
+#
+# Use /set or similar command to change settings in WeeChat.
+#
+# For more info, see: https://weechat.org/doc/quickstart
+#
+
+[command]
+default_options = ""
+purge_delay = 0
+
+[color]
+flag_finished = lightred
+flag_running = lightgreen
diff --git a/.weechat/fifo.conf b/.weechat/fifo.conf
@@ -0,0 +1,14 @@
+#
+# weechat -- fifo.conf
+#
+# WARNING: It is NOT recommended to edit this file by hand,
+# especially if WeeChat is running.
+#
+# Use /set or similar command to change settings in WeeChat.
+#
+# For more info, see: https://weechat.org/doc/quickstart
+#
+
+[file]
+enabled = on
+path = "%h/weechat_fifo"
diff --git a/.weechat/fset.conf b/.weechat/fset.conf
@@ -0,0 +1,95 @@
+#
+# weechat -- fset.conf
+#
+# WARNING: It is NOT recommended to edit this file by hand,
+# especially if WeeChat is running.
+#
+# Use /set or similar command to change settings in WeeChat.
+#
+# For more info, see: https://weechat.org/doc/quickstart
+#
+
+[look]
+auto_unmark = off
+condition_catch_set = "${count} >= 1"
+export_help_default = on
+format_number = 1
+marked_string = "*"
+scroll_horizontal = 10
+show_plugins_desc = off
+sort = "~name"
+unmarked_string = " "
+use_color_value = off
+use_keys = on
+use_mute = off
+
+[format]
+export_help = "# ${description2}"
+export_option = "/set ${name} ${quoted_value}"
+export_option_null = "/unset ${name}"
+option1 = ""
+option2 = "${marked} ${name} ${type} ${value2}${newline} ${empty_name} ${_default_value}${color:darkgray} -- ${min}..${max}${newline} ${empty_name} ${description}"
+
+[color]
+default_value = default
+default_value_selected = white
+description = default
+description_selected = white
+file = default
+file_changed = brown
+file_changed_selected = yellow
+file_selected = white
+help_default_value = white
+help_description = default
+help_name = white
+help_quotes = darkgray
+help_values = default
+index = cyan
+index_selected = lightcyan
+line_marked_bg1 = default
+line_marked_bg2 = default
+line_selected_bg1 = blue
+line_selected_bg2 = red
+marked = brown
+marked_selected = yellow
+max = default
+max_selected = white
+min = default
+min_selected = white
+name = default
+name_changed = brown
+name_changed_selected = yellow
+name_selected = white
+option = default
+option_changed = brown
+option_changed_selected = yellow
+option_selected = white
+parent_name = default
+parent_name_selected = white
+parent_value = cyan
+parent_value_selected = lightcyan
+quotes = darkgray
+quotes_changed = default
+quotes_changed_selected = white
+quotes_selected = default
+section = default
+section_changed = brown
+section_changed_selected = yellow
+section_selected = white
+string_values = default
+string_values_selected = white
+title_count_options = cyan
+title_current_option = lightcyan
+title_filter = yellow
+title_marked_options = lightgreen
+title_sort = white
+type = green
+type_selected = lightgreen
+unmarked = default
+unmarked_selected = white
+value = cyan
+value_changed = brown
+value_changed_selected = yellow
+value_selected = lightcyan
+value_undef = magenta
+value_undef_selected = lightmagenta
diff --git a/.weechat/irc.conf b/.weechat/irc.conf
@@ -0,0 +1,231 @@
+#
+# weechat -- irc.conf
+#
+# WARNING: It is NOT recommended to edit this file by hand,
+# especially if WeeChat is running.
+#
+# Use /set or similar command to change settings in WeeChat.
+#
+# For more info, see: https://weechat.org/doc/quickstart
+#
+
+[look]
+buffer_open_before_autojoin = on
+buffer_open_before_join = off
+buffer_switch_autojoin = on
+buffer_switch_join = on
+color_nicks_in_names = on
+color_nicks_in_nicklist = on
+color_nicks_in_server_messages = on
+color_pv_nick_like_channel = on
+ctcp_time_format = "%a, %d %b %Y %T %z"
+display_away = local
+display_ctcp_blocked = on
+display_ctcp_reply = on
+display_ctcp_unknown = on
+display_host_join = on
+display_host_join_local = on
+display_host_quit = on
+display_join_message = "329,332,333,366"
+display_old_topic = on
+display_pv_away_once = on
+display_pv_back = on
+highlight_channel = "$nick"
+highlight_pv = "$nick"
+highlight_server = "$nick"
+highlight_tags_restrict = "irc_privmsg,irc_notice"
+item_channel_modes_hide_args = "k"
+item_display_server = buffer_plugin
+item_nick_modes = on
+item_nick_prefix = on
+join_auto_add_chantype = off
+msgbuffer_fallback = current
+new_channel_position = none
+new_pv_position = none
+nick_completion_smart = speakers
+nick_mode = prefix
+nick_mode_empty = off
+nicks_hide_password = "nickserv"
+notice_as_pv = auto
+notice_welcome_redirect = on
+notice_welcome_tags = ""
+notify_tags_ison = "notify_message"
+notify_tags_whois = "notify_message"
+part_closes_buffer = off
+pv_buffer = independent
+pv_tags = "notify_private"
+raw_messages = 256
+server_buffer = merge_with_core
+smart_filter = on
+smart_filter_delay = 5
+smart_filter_join = on
+smart_filter_join_unmask = 30
+smart_filter_mode = "+"
+smart_filter_nick = on
+smart_filter_quit = on
+temporary_servers = off
+topic_strip_colors = off
+
+[color]
+input_nick = lightcyan
+item_channel_modes = default
+item_lag_counting = default
+item_lag_finished = yellow
+item_nick_modes = default
+message_join = green
+message_quit = red
+mirc_remap = "1,-1:darkgray"
+nick_prefixes = "y:lightred;q:lightred;a:lightcyan;o:lightgreen;h:lightmagenta;v:yellow;*:lightblue"
+notice = green
+reason_quit = default
+topic_current = default
+topic_new = white
+topic_old = default
+
+[network]
+autoreconnect_delay_growing = 2
+autoreconnect_delay_max = 600
+ban_mask_default = "*!$ident@$host"
+channel_encode = off
+colors_receive = on
+colors_send = on
+lag_check = 60
+lag_max = 1800
+lag_min_show = 500
+lag_reconnect = 300
+lag_refresh_interval = 1
+notify_check_ison = 1
+notify_check_whois = 5
+sasl_fail_unavailable = on
+send_unknown_commands = off
+whois_double_nick = off
+
+[msgbuffer]
+
+[ctcp]
+
+[ignore]
+
+[server_default]
+addresses = ""
+anti_flood_prio_high = 2
+anti_flood_prio_low = 2
+autoconnect = off
+autojoin = ""
+autoreconnect = on
+autoreconnect_delay = 10
+autorejoin = off
+autorejoin_delay = 30
+away_check = 0
+away_check_max_nicks = 25
+capabilities = ""
+command = ""
+command_delay = 0
+connection_timeout = 60
+ipv6 = on
+local_hostname = ""
+msg_kick = ""
+msg_part = "WeeChat ${info:version}"
+msg_quit = "WeeChat ${info:version}"
+nicks = "lanodan,lanodan_"
+nicks_alternate = on
+notify = ""
+password = ""
+proxy = ""
+realname = ""
+sasl_fail = continue
+sasl_key = ""
+sasl_mechanism = plain
+sasl_password = ""
+sasl_timeout = 15
+sasl_username = ""
+ssl = off
+ssl_cert = ""
+ssl_dhkey_size = 2048
+ssl_fingerprint = ""
+ssl_priorities = "NORMAL:-VERS-SSL3.0"
+ssl_verify = on
+usermode = ""
+username = "lanodan"
+
+[server]
+freenode.addresses = "chat.freenode.net/+6697"
+freenode.proxy
+freenode.ipv6
+freenode.ssl = on
+freenode.ssl_cert
+freenode.ssl_priorities
+freenode.ssl_dhkey_size
+freenode.ssl_fingerprint
+freenode.ssl_verify
+freenode.password
+freenode.capabilities
+freenode.sasl_mechanism
+freenode.sasl_username = "lanodan"
+freenode.sasl_password = "${sec.data.freenode}"
+freenode.sasl_key
+freenode.sasl_timeout
+freenode.sasl_fail
+freenode.autoconnect
+freenode.autoreconnect
+freenode.autoreconnect_delay
+freenode.nicks
+freenode.nicks_alternate
+freenode.username
+freenode.realname
+freenode.local_hostname
+freenode.usermode
+freenode.command
+freenode.command_delay
+freenode.autojoin
+freenode.autorejoin
+freenode.autorejoin_delay
+freenode.connection_timeout
+freenode.anti_flood_prio_high
+freenode.anti_flood_prio_low
+freenode.away_check
+freenode.away_check_max_nicks
+freenode.msg_kick
+freenode.msg_part
+freenode.msg_quit
+freenode.notify
+geeknode.addresses = "irc.geeknode.org/+6697"
+geeknode.proxy
+geeknode.ipv6
+geeknode.ssl = on
+geeknode.ssl_cert
+geeknode.ssl_priorities
+geeknode.ssl_dhkey_size
+geeknode.ssl_fingerprint
+geeknode.ssl_verify
+geeknode.password
+geeknode.capabilities
+geeknode.sasl_mechanism
+geeknode.sasl_username
+geeknode.sasl_password
+geeknode.sasl_key
+geeknode.sasl_timeout
+geeknode.sasl_fail
+geeknode.autoconnect
+geeknode.autoreconnect
+geeknode.autoreconnect_delay
+geeknode.nicks
+geeknode.nicks_alternate
+geeknode.username
+geeknode.realname
+geeknode.local_hostname
+geeknode.usermode
+geeknode.command
+geeknode.command_delay
+geeknode.autojoin
+geeknode.autorejoin
+geeknode.autorejoin_delay
+geeknode.connection_timeout
+geeknode.anti_flood_prio_high
+geeknode.anti_flood_prio_low
+geeknode.away_check
+geeknode.away_check_max_nicks
+geeknode.msg_kick
+geeknode.msg_part
+geeknode.msg_quit
+geeknode.notify
diff --git a/.weechat/logger.conf b/.weechat/logger.conf
@@ -0,0 +1,33 @@
+#
+# weechat -- logger.conf
+#
+# WARNING: It is NOT recommended to edit this file by hand,
+# especially if WeeChat is running.
+#
+# Use /set or similar command to change settings in WeeChat.
+#
+# For more info, see: https://weechat.org/doc/quickstart
+#
+
+[look]
+backlog = 20
+
+[color]
+backlog_end = default
+backlog_line = default
+
+[file]
+auto_log = on
+flush_delay = 120
+info_lines = off
+mask = "$plugin.$name.weechatlog"
+name_lower_case = on
+nick_prefix = ""
+nick_suffix = ""
+path = "%h/logs/"
+replacement_char = "_"
+time_format = "%Y-%m-%d %H:%M:%S"
+
+[level]
+
+[mask]
diff --git a/.weechat/perl/autoload/highmon.pl b/.weechat/perl/autoload/highmon.pl
@@ -0,0 +1 @@
+../highmon.pl+
\ No newline at end of file
diff --git a/.weechat/perl/highmon.pl b/.weechat/perl/highmon.pl
@@ -0,0 +1,1139 @@
+#
+# highmon.pl - Highlight Monitoring for weechat 0.3.0
+# Version 2.5
+#
+# Add 'Highlight Monitor' buffer/bar to log all highlights in one spot
+#
+# Usage:
+# /highmon [help] | [monitor [channel [server]]] | [clean default|orphan|all] | clearbar
+# Command wrapper for highmon commands
+#
+# /highmon clean default|orphan|all will clean the config section of default 'on' entries,
+# channels you are no longer joined, or both
+#
+# /highmon clearbar will clear the contents of highmon's bar output
+#
+# /highmon monitor [channel] [server] is used to toggle a highlight monitoring on and off, this
+# can be used in the channel buffer for the channel you wish to toggle, or be given
+# with arguments e.g. /highmon monitor #weechat freenode
+#
+# /set plugins.var.perl.highmon.alignment
+# The config setting "alignment" can be changed to;
+# "channel", "schannel", "nchannel", "channel,nick", "schannel,nick", "nchannel,nick"
+# to change how the monitor appears
+# The 'channel' value will show: "#weechat"
+# The 'schannel' value will show: "6"
+# The 'nchannel' value will show: "6:#weechat"
+#
+# /set plugins.var.perl.highmon.short_names
+# Setting this to 'on' will trim the network name from highmon, ala buffers.pl
+#
+# /set plugins.var.perl.highmon.merge_private
+# Setting this to 'on' will merge private messages to highmon's display
+#
+# /set plugins.var.perl.highmon.color_buf
+# This turns colored buffer names on or off, you can also set a single fixed color by using a weechat color name.
+# This *must* be a valid color name, or weechat will likely do unexpected things :)
+#
+# /set plugins.var.perl.highmon.hotlist_show
+# Setting this to 'on' will let the highmon buffer appear in hotlists
+# (status bar/buffer.pl)
+#
+# /set plugins.var.perl.highmon.away_only
+# Setting this to 'on' will only put messages in the highmon buffer when
+# you set your status to away
+#
+# /set plugins.var.perl.highmon.logging
+# Toggles logging status for highmon buffer (default: off)
+#
+# /set plugins.var.perl.highmon.output
+# Changes where output method of highmon; takes either "bar" or "buffer" (default; buffer)
+# /set plugins.var.perl.highmon.bar_lines
+# Changes the amount of lines the output bar will hold.
+# (Only appears once output has been set to bar, defaults to 10)
+# /set plugins.var.perl.highmon.bar_scrolldown
+# Toggles the bar scrolling at the bottom when new highlights are received
+# (Only appears once output has been set to bar, defaults to off)
+#
+# /set plugins.var.perl.highmon.nick_prefix
+# /set plugins.var.perl.highmon.nick_suffix
+# Sets the prefix and suffix chars in the highmon buffer
+# (Defaults to <> if nothing set, and blank if there is)
+#
+# servername.#channel
+# servername is the internal name for the server (set when you use /server add)
+# #channel is the channel name, (where # is whatever channel type that channel happens to be)
+#
+# Optional, set up tweaks; Hide the status and input lines on highmon
+#
+# /set weechat.bar.status.conditions "${window.buffer.full_name} != perl.highmon"
+# /set weechat.bar.input.conditions "${window.buffer.full_name} != perl.highmon"
+#
+
+# Bugs and feature requests at: https://github.com/KenjiE20/highmon
+
+# History:
+# 2014-08-16, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.5: -add: clearbar command to clear bar output
+# -add: firstrun output prompt to check the help text for set up hints as they were being missed
+# and update hint for conditions to use eval
+# -change: Make all outputs use the date callback for more accurate timestamps (thanks Germainz)
+# 2013-12-04, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.4: -add: Support for eval style colour codes in time format used for bar output
+# 2013-10-22, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.3.3.2: -fix: Typo in fix command
+# 2013-10-10, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.3.3.1: -fix: Typo in closed buffer warning
+# 2013-10-07, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.3.3: -add: Warning and fixer for accidental buffer closes
+# 2013-01-15, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.3.2: -fix: Let bar output use the string set in weechat's config option
+# -add: github info
+# 2012-04-15, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.3.1: -fix: Colour tags in bar timestamp string
+# 2012-02-28, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.3: -feature: Added merge_private option to display private messages (default: off)
+# -fix: Channel name colours now show correctly when set to on
+# 2011-08-07, Sitaktif <romainchossart_at_gmail.com>:
+# v2.2.1: -feature: Add "bar_scrolldown" option to have the bar display the latest hl at anytime
+# -fix: Set up bar-specific config at startup if 'output' is already configured as 'bar'
+# 2010-12-22, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.2: -change: Use API instead of config to find channel colours, ready for 0.3.4 and 256 colours
+# 2010-12-13, idl0r & KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.1.3: -fix: perl errors caused by bar line counter
+# -fix: Add command list to inbuilt help
+# 2010-09-30, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.1.2: -fix: logging config was not correctly toggling back on (thanks to sleo for noticing)
+# -version sync w/ chanmon
+# 2010-08-27, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.1: -feature: Add 'nchannel' option to alignment to display buffer and name
+# 2010-04-25, KenjiE20 <longbow@longbowslair.co.uk>:
+# v2.0: Release as version 2.0
+# 2010-04-24, KenjiE20 <longbow@longbowslair.co.uk>:
+# v1.9: Rewrite for v2.0
+# Bring feature set in line with chanmon 2.0
+# -code change: Made more subs to shrink the code down in places
+# -fix: Stop highmon attempting to double load/hook
+# -fix: Add version dependant check for away status
+# 2010-01-25, KenjiE20 <longbow@longbowslair.co.uk>:
+# v1.7: -fixture: Let highmon be aware of nick_prefix/suffix
+# and allow custom prefix/suffix for chanmon buffer
+# (Defaults to <> if nothing set, and blank if there is)
+# (Thanks to m4v for these)
+# 2009-09-07, KenjiE20 <longbow@longbowslair.co.uk>:
+# v1.6: -feature: colored buffer names
+# -change: version sync with chanmon
+# 2009-09-05, KenjiE20 <longbow@longbowslair.co.uk>:
+# v1.2: -fix: disable buffer highlight
+# 2009-09-02, KenjiE20 <longbow@longbowslair.co.uk>:
+# v.1.1.1 -change: Stop unsightly text block on '/help'
+# 2009-08-10, KenjiE20 <longbow@longbowslair.co.uk>:
+# v1.1: In-client help added
+# 2009-08-02, KenjiE20 <longbow@longbowslair.co.uk>:
+# v1.0: Initial Public Release
+
+# Copyright (c) 2009 by KenjiE20 <longbow@longbowslair.co.uk>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+@bar_lines = ();
+@bar_lines_time = ();
+# Replicate info earlier for in-client help
+
+$highmonhelp = weechat::color("bold")."/highmon [help] | [monitor [channel [server]]] | [clean default|orphan|all] | clearbar".weechat::color("-bold")."
+ Command wrapper for highmon commands
+
+".weechat::color("bold")."/highmon clean default|orphan|all".weechat::color("-bold")." will clean the config section of default 'on' entries, channels you are no longer joined, or both
+
+".weechat::color("bold")."/highmon clearbar".weechat::color("-bold")." will clear the contents of highmon's bar output
+
+".weechat::color("bold")."/highmon monitor [channel] [server]".weechat::color("-bold")." is used to toggle a highlight monitoring on and off, this can be used in the channel buffer for the channel you wish to toggle, or be given with arguments e.g. /highmon monitor #weechat freenode
+
+".weechat::color("bold")."/set plugins.var.perl.highmon.alignment".weechat::color("-bold")."
+ The config setting \"alignment\" can be changed to;
+ \"channel\", \"schannel\", \"nchannel\", \"channel,nick\", \"schannel,nick\", \"nchannel,nick\"
+ to change how the monitor appears
+ The 'channel' value will show: \"#weechat\"
+ The 'schannel' value will show: \"6\"
+ The 'nchannel' value will show: \"6:#weechat\"
+
+".weechat::color("bold")."/set plugins.var.perl.highmon.short_names".weechat::color("-bold")."
+ Setting this to 'on' will trim the network name from highmon, ala buffers.pl
+
+".weechat::color("bold")."/set plugins.var.perl.highmon.merge_private".weechat::color("-bold")."
+ Setting this to 'on' will merge private messages to highmon's display
+
+".weechat::color("bold")."/set plugins.var.perl.highmon.color_buf".weechat::color("-bold")."
+ This turns colored buffer names on or off, you can also set a single fixed color by using a weechat color name.
+ This ".weechat::color("bold")."must".weechat::color("-bold")." be a valid color name, or weechat will likely do unexpected things :)
+
+".weechat::color("bold")."/set plugins.var.perl.highmon.hotlist_show".weechat::color("-bold")."
+Setting this to 'on' will let the highmon buffer appear in hotlists (status bar/buffer.pl)
+
+".weechat::color("bold")."/set plugins.var.perl.highmon.away_only".weechat::color("-bold")."
+Setting this to 'on' will only put messages in the highmon buffer when you set your status to away
+
+".weechat::color("bold")."/set plugins.var.perl.highmon.logging".weechat::color("-bold")."
+ Toggles logging status for highmon buffer (default: off)
+
+".weechat::color("bold")."/set plugins.var.perl.highmon.output".weechat::color("-bold")."
+ Changes where output method of highmon; takes either \"bar\" or \"buffer\" (default; buffer)
+".weechat::color("bold")."/set plugins.var.perl.highmon.bar_lines".weechat::color("-bold")."
+ Changes the amount of lines the output bar will hold.
+ (Only appears once output has been set to bar, defaults to 10)
+".weechat::color("bold")."/set plugins.var.perl.highmon.bar_scrolldown".weechat::color("-bold")."
+ Toggles the bar scrolling at the bottom when new highlights are received
+ (Only appears once output has been set to bar, defaults to off)
+
+".weechat::color("bold")."/set plugins.var.perl.highmon.nick_prefix".weechat::color("-bold")."
+".weechat::color("bold")."/set plugins.var.perl.highmon.nick_suffix".weechat::color("-bold")."
+ Sets the prefix and suffix chars in the highmon buffer
+ (Defaults to <> if nothing set, and blank if there is)
+
+".weechat::color("bold")."servername.#channel".weechat::color("-bold")."
+ servername is the internal name for the server (set when you use /server add)
+ #channel is the channel name, (where # is whatever channel type that channel happens to be)
+
+".weechat::color("bold")."Optional, set up tweaks;".weechat::color("-bold")." Hide the status and input lines on highmon
+
+".weechat::color("bold")."/set weechat.bar.status.conditions \"\${window.buffer.full_name} != perl.highmon\"".weechat::color("-bold")."
+".weechat::color("bold")."/set weechat.bar.input.conditions \"\${window.buffer.full_name} != perl.highmon\"".weechat::color("-bold");
+# Print verbose help
+sub print_help
+{
+ weechat::print("", "\t".weechat::color("bold")."Highmon Help".weechat::color("-bold")."\n\n");
+ weechat::print("", "\t".$highmonhelp);
+ return weechat::WEECHAT_RC_OK;
+}
+
+# Bar item build
+sub highmon_bar_build
+{
+ # Get max lines
+ $max_lines = weechat::config_get_plugin("bar_lines");
+ $max_lines = $max_lines ? $max_lines : 10;
+ $str = '';
+ $align_num = 0;
+ $count = 0;
+ # Keep lines within max
+ while ($#bar_lines > $max_lines)
+ {
+ shift(@bar_lines);
+ shift(@bar_lines_time);
+ }
+ # So long as we have some lines, build a string
+ if (@bar_lines)
+ {
+ # Build loop
+ $sep = " ".weechat::config_string(weechat::config_get("weechat.look.prefix_suffix"))." ";
+ foreach(@bar_lines)
+ {
+ # Find max align needed
+ $prefix_num = (index(weechat::string_remove_color($_, ""), $sep));
+ $align_num = $prefix_num if ($prefix_num > $align_num);
+ }
+ foreach(@bar_lines)
+ {
+ # Get align for this line
+ $prefix_num = (index(weechat::string_remove_color($_, ""), $sep));
+
+ # Make string
+ $str = $str.$bar_lines_time[$count]." ".(" " x ($align_num - $prefix_num)).$_."\n";
+ # Increment count for sync with time list
+ $count++;
+ }
+ }
+ return $str;
+}
+
+# Make a new bar
+sub highmon_bar_open
+{
+ # Make the bar item
+ weechat::bar_item_new("highmon", "highmon_bar_build", "");
+
+ $highmon_bar = weechat::bar_new ("highmon", "off", 100, "root", "", "bottom", "vertical", "vertical", 0, 0, "default", "cyan", "default", "on", "highmon");
+
+ return weechat::WEECHAT_RC_OK;
+}
+# Close bar
+sub highmon_bar_close
+{
+ # Find if bar exists
+ $highmon_bar = weechat::bar_search("highmon");
+ # If is does, close it
+ if ($highmon_bar ne "")
+ {
+ weechat::bar_remove($highmon_bar);
+ }
+
+ # Find if bar item exists
+ $highmon_bar_item = weechat::bar_item_search("highmon_bar");
+ # If is does, close it
+ if ($highmon_bar_item ne "")
+ {
+ weechat::bar_remove($highmon_bar_item);
+ }
+
+ @bar_lines = ();
+ return weechat::WEECHAT_RC_OK;
+}
+
+# Make a new buffer
+sub highmon_buffer_open
+{
+ # Search for pre-existing buffer
+ $highmon_buffer = weechat::buffer_search("perl", "highmon");
+
+ # Make a new buffer
+ if ($highmon_buffer eq "")
+ {
+ $highmon_buffer = weechat::buffer_new("highmon", "highmon_buffer_input", "", "highmon_buffer_close", "");
+ }
+
+ # Turn off notify, highlights
+ if ($highmon_buffer ne "")
+ {
+ if (weechat::config_get_plugin("hotlist_show" eq "off"))
+ {
+ weechat::buffer_set($highmon_buffer, "notify", "0");
+ }
+ weechat::buffer_set($highmon_buffer, "highlight_words", "-");
+ weechat::buffer_set($highmon_buffer, "title", "Highlight Monitor");
+ # Set no_log
+ if (weechat::config_get_plugin("logging") eq "off")
+ {
+ weechat::buffer_set($highmon_buffer, "localvar_set_no_log", "1");
+ }
+ }
+ return weechat::WEECHAT_RC_OK;
+}
+# Buffer input has no action
+sub highmon_buffer_input
+{
+ return weechat::WEECHAT_RC_OK;
+}
+# Close up
+sub highmon_buffer_close
+{
+ $highmon_buffer = "";
+ # If user hasn't changed output style warn user
+ if (weechat::config_get_plugin("output") eq "buffer")
+ {
+ weechat::print("", "\tHighmon buffer has been closed but output is still set to buffer, unusual results may occur. To recreate the buffer use ".weechat::color("bold")."/highmon fix".weechat::color("-bold"));
+ }
+ return weechat::WEECHAT_RC_OK;
+}
+
+# Highmon command wrapper
+sub highmon_command_cb
+{
+ $data = $_[0];
+ $buffer = $_[1];
+ $args = $_[2];
+ my $cmd = '';
+ my $arg = '';
+
+ if ($args ne "")
+ {
+ # Split argument up
+ @arg_array = split(/ /,$args);
+ # Take first as command
+ $cmd = shift(@arg_array);
+ # Rebuild string to pass to subs
+ if (@arg_array)
+ {
+ $arg = join(" ", @arg_array);
+ }
+ }
+
+ # Help command
+ if ($cmd eq "" || $cmd eq "help")
+ {
+ print_help();
+ }
+ # /monitor command
+ elsif ($cmd eq "monitor")
+ {
+ highmon_toggle($data, $buffer, $arg);
+ }
+ # /highclean command
+ elsif ($cmd eq "clean")
+ {
+ highmon_config_clean($data, $buffer, $arg);
+ }
+ # clearbar command
+ elsif ($cmd eq "clearbar")
+ {
+ if (weechat::config_get_plugin("output") eq "bar")
+ {
+ @bar_lines = ();
+ weechat::bar_item_update("highmon");
+ }
+ }
+ # Fix closed buffer
+ elsif ($cmd eq "fix")
+ {
+ if (weechat::config_get_plugin("output") eq "buffer" && $highmon_buffer eq "")
+ {
+ highmon_buffer_open();
+ }
+ }
+ return weechat::WEECHAT_RC_OK;
+}
+
+# Clean up config entries
+sub highmon_config_clean
+{
+ $data = $_[0];
+ $buffer = $_[1];
+ $args = $_[2];
+
+ # Don't do anything if bad option given
+ if ($args ne "default" && $args ne "orphan" && $args ne "all")
+ {
+ weechat::print("", "\thighmon.pl: Unknown option");
+ return weechat::WEECHAT_RC_OK;
+ }
+
+ @chans = ();
+ # Load an infolist of highmon options
+ $infolist = weechat::infolist_get("option", "", "*highmon*");
+ while (weechat::infolist_next($infolist))
+ {
+ $name = weechat::infolist_string($infolist, "option_name");
+ $name =~ s/perl\.highmon\.(\w*)\.([#&\+!])(.*)/$1.$2$3/;
+ if ($name =~ /^(.*)\.([#&\+!])(.*)$/)
+ {
+ $action = 0;
+ # Clean up all 'on's
+ if ($args eq "default" || $args eq "all")
+ {
+ # If value in config is "on"
+ if (weechat::config_get_plugin($name) eq "on")
+ {
+ # Unset and if successful flag as changed
+ $rc = weechat::config_unset_plugin($name);
+ if ($rc eq weechat::WEECHAT_CONFIG_OPTION_UNSET_OK_REMOVED)
+ {
+ $action = 1;
+ }
+ }
+ }
+ # Clean non joined
+ if ($args eq "orphan" || $args eq "all")
+ {
+ # If we can't find the buffer for this entry
+ if (weechat::buffer_search("irc", $name) eq "")
+ {
+ # Unset and if successful flag as changed
+ $rc = weechat::config_unset_plugin($name);
+ if ($rc eq weechat::WEECHAT_CONFIG_OPTION_UNSET_OK_REMOVED)
+ {
+ $action = 1;
+ }
+ }
+ }
+ # Add changed entry names to list
+ push (@chans, $name) if ($action);
+ }
+ }
+ weechat::infolist_free($infolist);
+ # If channels were cleaned from config
+ if (@chans)
+ {
+ # If only one entry
+ if (@chans == 1)
+ {
+ $str = "\thighmon.pl: Cleaned ".@chans." entry from the config:";
+ }
+ else
+ {
+ $str = "\thighmon.pl: Cleaned ".@chans." entries from the config:";
+ }
+ # Build a list of channels
+ foreach(@chans)
+ {
+ $str = $str." ".$_;
+ }
+ # Print what happened
+ weechat::print("",$str);
+ }
+ # Config seemed to be clean
+ else
+ {
+ weechat::print("", "\thighmon.pl: No entries removed");
+ }
+ return weechat::WEECHAT_RC_OK;
+}
+
+# Check config elements
+sub highmon_config_init
+{
+ # First run default
+ if (!(weechat::config_is_set_plugin ("first_run")))
+ {
+ if (weechat::config_get_plugin("first_run") ne "true")
+ {
+ weechat::print("", "\tThis appears to be the first time highmon has been run. For help and common set up hints see /highmon help");
+ weechat::config_set_plugin("first_run", "true");
+ }
+ }
+ # Alignment default
+ if (!(weechat::config_is_set_plugin ("alignment")))
+ {
+ weechat::config_set_plugin("alignment", "channel");
+ }
+ if (weechat::config_get_plugin("alignment") eq "")
+ {
+ weechat::config_set_plugin("alignment", "none");
+ }
+
+ # Short name default
+ if (!(weechat::config_is_set_plugin ("short_names")))
+ {
+ weechat::config_set_plugin("short_names", "off");
+ }
+
+ # Coloured names default
+ if (!(weechat::config_is_set_plugin ("color_buf")))
+ {
+ weechat::config_set_plugin("color_buf", "on");
+ }
+
+ # Hotlist show default
+ if (!(weechat::config_is_set_plugin ("hotlist_show")))
+ {
+ weechat::config_set_plugin("hotlist_show", "off");
+ }
+
+ # Away only default
+ if (!(weechat::config_is_set_plugin ("away_only")))
+ {
+ weechat::config_set_plugin("away_only", "off");
+ }
+
+ # highmon log default
+ if (!(weechat::config_is_set_plugin ("logging")))
+ {
+ weechat::config_set_plugin("logging", "off");
+ }
+
+ # Output default
+ if (!(weechat::config_is_set_plugin ("output")))
+ {
+ weechat::config_set_plugin("output", "buffer");
+ }
+
+ # Private message merging
+ if (!(weechat::config_is_set_plugin ("merge_private")))
+ {
+ weechat::config_set_plugin("merge_private", "off");
+ }
+
+ # Set bar config in case output was set to "bar" before even changing the setting
+ if (weechat::config_get_plugin("output") eq "bar")
+ {
+ # Output bar lines default
+ if (!(weechat::config_is_set_plugin ("bar_lines")))
+ {
+ weechat::config_set_plugin("bar_lines", "10");
+ }
+ if (!(weechat::config_is_set_plugin ("bar_scrolldown")))
+ {
+ weechat::config_set_plugin("bar_scrolldown", "off");
+ }
+ }
+
+ # Check for exisiting prefix/suffix chars, and setup accordingly
+ $prefix = weechat::config_get("irc.look.nick_prefix");
+ $prefix = weechat::config_string($prefix);
+ $suffix = weechat::config_get("irc.look.nick_suffix");
+ $suffix = weechat::config_string($suffix);
+
+ if (!(weechat::config_is_set_plugin("nick_prefix")))
+ {
+ if ($prefix eq "" && $suffix eq "")
+ {
+ weechat::config_set_plugin("nick_prefix", "<");
+ }
+ else
+ {
+ weechat::config_set_plugin("nick_prefix", "");
+ }
+ }
+
+ if (!(weechat::config_is_set_plugin("nick_suffix")))
+ {
+ if ($prefix eq "" && $suffix eq "")
+ {
+ weechat::config_set_plugin("nick_suffix", ">");
+ }
+ else
+ {
+ weechat::config_set_plugin("nick_suffix", "");
+ }
+ }
+}
+
+# Get config updates
+sub highmon_config_cb
+{
+ $point = $_[0];
+ $name = $_[1];
+ $value = $_[2];
+
+ $name =~ s/^plugins\.var\.perl\.highmon\.//;
+
+ # Set logging on buffer
+ if ($name eq "logging")
+ {
+ # Search for pre-existing buffer
+ $highmon_buffer = weechat::buffer_search("perl", "highmon");
+ if ($value eq "off")
+ {
+ weechat::buffer_set($highmon_buffer, "localvar_set_no_log", "1");
+ }
+ else
+ {
+ weechat::buffer_set($highmon_buffer, "localvar_del_no_log", "");
+ }
+ }
+ # Output changer
+ elsif ($name eq "output")
+ {
+ if ($value eq "bar")
+ {
+ # Search for pre-existing buffer
+ $highmon_buffer = weechat::buffer_search("perl", "highmon");
+ # Close if it exists
+ if ($highmon_buffer ne "")
+ {
+ weechat::buffer_close($highmon_buffer)
+ }
+
+ # Output bar lines default
+ if (!(weechat::config_is_set_plugin ("bar_lines")))
+ {
+ weechat::config_set_plugin("bar_lines", "10");
+ }
+ if (!(weechat::config_is_set_plugin ("bar_scrolldown")))
+ {
+ weechat::config_set_plugin("bar_scrolldown", "off");
+ }
+ # Make a bar if doesn't exist
+ highmon_bar_open();
+ }
+ elsif ($value eq "buffer")
+ {
+ # If a bar exists, close it
+ highmon_bar_close();
+ # Open buffer
+ highmon_buffer_open();
+ }
+
+ }
+ # Change if hotlist config changes
+ elsif ($name eq "hotlist_show")
+ {
+ # Search for pre-existing buffer
+ $highmon_buffer = weechat::buffer_search("perl", "highmon");
+ if ($value eq "off" && $highmon_buffer)
+ {
+ weechat::buffer_set($highmon_buffer, "notify", "0");
+ }
+ elsif ($value ne "off" && $highmon_buffer)
+ {
+ weechat::buffer_set($highmon_buffer, "notify", "3");
+ }
+ }
+ elsif ($name eq "weechat.look.prefix_suffix")
+ {
+ if (weechat::config_get_plugin("output") eq "bar")
+ {
+ @bar_lines = ();
+ weechat::print("", "\thighmon: weechat.look.prefix_suffix changed, clearing highmon bar");
+ weechat::bar_item_update("highmon");
+ }
+ }
+ return weechat::WEECHAT_RC_OK;
+}
+
+# Set up weechat hooks / commands
+sub highmon_hook
+{
+ weechat::hook_print("", "", "", 0, "highmon_new_message", "");
+ weechat::hook_command("highclean", "Highmon config clean up", "default|orphan|all", " default: Cleans all config entries with the default \"on\" value\n orphan: Cleans all config entries for channels you aren't currently joined\n all: Does both defaults and orphan", "default|orphan|all", "highmon_config_clean", "");
+
+ weechat::hook_command("highmon", "Highmon help", "[help] | [monitor [channel [server]]] | [clean default|orphan|all] | clearbar", " help: Print help on config options for highmon\n monitor: Toggles monitoring for a channel\n clean: Highmon config clean up (/highclean)\nclearbar: Clear Highmon bar", "help || monitor %(irc_channels) %(irc_servers) || clean default|orphan|all || clearbar", "highmon_command_cb", "");
+
+ weechat::hook_config("plugins.var.perl.highmon.*", "highmon_config_cb", "");
+ weechat::hook_config("weechat.look.prefix_suffix", "highmon_config_cb", "");
+}
+
+# Main body, Callback for hook_print
+sub highmon_new_message
+{
+ my $net = "";
+ my $chan = "";
+ my $nick = "";
+ my $outstr = "";
+ my $window_displayed = "";
+ my $dyncheck = "0";
+
+# DEBUG point
+# $string = "\t"."0: ".$_[0]." 1: ".$_[1]." 2: ".$_[2]." 3: ".$_[3]." 4: ".$_[4]." 5: ".$_[5]." 6: ".$_[6]." 7: ".$_[7];
+# weechat::print("", "\t".$string);
+
+ $cb_datap = $_[0];
+ $cb_bufferp = $_[1];
+ $cb_date = $_[2];
+ $cb_tags = $_[3];
+ $cb_disp = $_[4];
+ $cb_high = $_[5];
+ $cb_prefix = $_[6];
+ $cb_msg = $_[7];
+
+ # Only work on highlighted messages or private message when enabled
+ if ($cb_high == "1" || (weechat::config_get_plugin("merge_private") eq "on" && $cb_tags =~ /notify_private/))
+ {
+ # Pre bug #29618 (0.3.3) away detect
+ if (weechat::info_get("version_number", "") <= 197120)
+ {
+ $away = '';
+ # Get infolist for this server
+ $infolist = weechat::infolist_get("irc_server", "", weechat::buffer_get_string($cb_bufferp, "localvar_server"));
+ while (weechat::infolist_next($infolist))
+ {
+ # Get away message is is_away is on
+ $away = weechat::infolist_string($infolist, "away_message") if (weechat::infolist_integer($infolist, "is_away"));
+ }
+ weechat::infolist_free($infolist);
+ }
+ # Post bug #29618 fix
+ else
+ {
+ $away = weechat::buffer_get_string($cb_bufferp, "localvar_away");
+ }
+ if (weechat::config_get_plugin("away_only") ne "on" || ($away ne ""))
+ {
+ # Check buffer name is an IRC channel
+ $bufname = weechat::buffer_get_string($cb_bufferp, 'name');
+ if ($bufname =~ /(.*)\.([#&\+!])(.*)/)
+ {
+ # Are we running on this channel
+ if (weechat::config_get_plugin($bufname) ne "off" && $cb_disp eq "1")
+ {
+ # Format nick
+ # Line isn't action or topic notify
+ if (!($cb_tags =~ /irc_action/) && !($cb_tags =~ /irc_topic/))
+ {
+ # Strip nick colour
+ $uncolnick = weechat::string_remove_color($cb_prefix, "");
+ # Format nick
+ $nick = " ".weechat::config_get_plugin("nick_prefix").weechat::color("chat_highlight").$uncolnick.weechat::color("reset").weechat::config_get_plugin("nick_suffix");
+ }
+ # Topic line
+ elsif ($cb_tags =~ /irc_topic/)
+ {
+ $nick = " ".$cb_prefix.weechat::color("reset");
+ }
+ # Action line
+ else
+ {
+ $uncolnick = weechat::string_remove_color($cb_prefix, "");
+ $nick = weechat::color("chat_highlight").$uncolnick.weechat::color("reset");
+ }
+ # Send to output
+ highmon_print ($cb_msg, $cb_bufferp, $nick, $cb_date, $cb_tags);
+ }
+ }
+ # Or is private message
+ elsif (weechat::config_get_plugin("merge_private") eq "on" && $cb_tags =~ /notify_private/)
+ {
+ # Strip nick colour
+ $uncolnick = weechat::buffer_get_string($cb_bufferp, 'short_name');
+ # Format nick
+ $nick = " ".weechat::config_get_plugin("nick_prefix").weechat::color("chat_highlight").$uncolnick.weechat::color("reset").weechat::config_get_plugin("nick_suffix");
+ #Send to output
+ highmon_print ($cb_msg, $cb_bufferp, $nick, $cb_date, $cb_tags);
+ }
+ }
+ }
+ return weechat::WEECHAT_RC_OK;
+}
+
+# Output formatter and printer takes (msg bufpointer nick)
+sub highmon_print
+{
+ $cb_msg = $_[0];
+ my $cb_bufferp = $_[1] if ($_[1]);
+ my $nick = $_[2] if ($_[2]);
+ my $cb_date = $_[3] if ($_[3]);
+ my $cb_tags = $_[4] if ($_[4]);
+
+ #Normal channel message
+ if ($cb_bufferp && $nick)
+ {
+ # Format buffer name
+ $bufname = format_buffer_name($cb_bufferp);
+
+ # If alignment is #channel | nick msg
+ if (weechat::config_get_plugin("alignment") eq "channel")
+ {
+ $nick =~ s/\s(.*)/$1/;
+ # Build string
+ $outstr = $bufname."\t".$nick." ".$cb_msg;
+ }
+ # or if it is channel number | nick msg
+ elsif (weechat::config_get_plugin("alignment") eq "schannel")
+ {
+ $nick =~ s/\s(.*)/$1/;
+ # Use channel number instead
+ $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').weechat::color("reset");
+ # Build string
+ $outstr = $bufname."\t".$nick." ".$cb_msg;
+ }
+ # or if it is number:#channel | nick msg
+ elsif (weechat::config_get_plugin("alignment") eq "nchannel")
+ {
+ $nick =~ s/\s(.*)/$1/;
+ # Place channel number in front of formatted name
+ $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').":".weechat::color("reset").$bufname;
+ # Build string
+ $outstr = $bufname."\t".$nick." ".$cb_msg;
+ }
+ # or if it is #channel nick | msg
+ elsif (weechat::config_get_plugin("alignment") eq "channel,nick")
+ {
+ # Build string
+ $outstr = $bufname.":".$nick."\t".$cb_msg;
+ }
+ # or if it is channel number nick | msg
+ elsif (weechat::config_get_plugin("alignment") eq "schannel,nick")
+ {
+ # Use channel number instead
+ $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').weechat::color("reset");
+ # Build string
+ $outstr = $bufname.":".$nick."\t".$cb_msg;
+ }
+ # or if it is number:#channel nick | msg
+ elsif (weechat::config_get_plugin("alignment") eq "nchannel,nick")
+ {
+ # Place channel number in front of formatted name
+ $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').":".weechat::color("reset").$bufname;
+ # Build string
+ $outstr = $bufname.":".$nick."\t".$cb_msg;
+ }
+ # or finally | #channel nick msg
+ else
+ {
+ # Build string
+ $outstr = "\t".$bufname.":".$nick." ".$cb_msg;
+ }
+ }
+ # highmon channel toggle message
+ elsif ($cb_bufferp && !$nick)
+ {
+ # Format buffer name
+ $bufname = format_buffer_name($cb_bufferp);
+
+ # If alignment is #channel * | *
+ if (weechat::config_get_plugin("alignment") =~ /channel/)
+ {
+ # If it's actually channel number * | *
+ if (weechat::config_get_plugin("alignment") =~ /schannel/)
+ {
+ # Use channel number instead
+ $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').weechat::color("reset");
+ }
+ # Or if it's actually number:#channel * | *
+ if (weechat::config_get_plugin("alignment") =~ /nchannel/)
+ {
+ # Place channel number in front of formatted name
+ $bufname = weechat::color("chat_prefix_buffer").weechat::buffer_get_integer($cb_bufferp, 'number').":".weechat::color("reset").$bufname;
+ }
+ $outstr = $bufname."\t".$cb_msg;
+ }
+ # or if alignment is | *
+ else
+ {
+ $outstr = $bufname.": ".$cb_msg;
+ }
+ }
+ # highmon dynmon
+ elsif (!$cb_bufferp && !$nick)
+ {
+ $outstr = "\t".$cb_msg;
+ }
+
+ # Send string to buffer
+ if (weechat::config_get_plugin("output") eq "buffer")
+ {
+ # Search for and confirm buffer
+ $highmon_buffer = weechat::buffer_search("perl", "highmon");
+ # Print
+ if ($cb_date)
+ {
+ weechat::print_date_tags($highmon_buffer, $cb_date, $cb_tags, $outstr);
+ }
+ else
+ {
+ weechat::print($highmon_buffer, $outstr);
+ }
+ }
+ elsif (weechat::config_get_plugin("output") eq "bar")
+ {
+ # Add time string
+ use POSIX qw(strftime);
+ if ($cb_date)
+ {
+ $time = strftime(weechat::config_string(weechat::config_get("weechat.look.buffer_time_format")), localtime($cb_date));
+ }
+ else
+ {
+ $time = strftime(weechat::config_string(weechat::config_get("weechat.look.buffer_time_format")), localtime);
+ }
+ # Colourise
+ if ($time =~ /\$\{(?:color:)?[\w,]+\}/) # Coloured string
+ {
+ while ($time =~ /\$\{(?:color:)?([\w,]+)\}/)
+ {
+ $color = weechat::color($1);
+ $time =~ s/\$\{(?:color:)?[\w,]+\}/$color/;
+ }
+ $time .= weechat::color("reset");
+ }
+ else # Default string
+ {
+ $colour = weechat::color(weechat::config_string(weechat::config_get("weechat.color.chat_time_delimiters")));
+ $reset = weechat::color("reset");
+ $time =~ s/(\d*)(.)(\d*)/$1$colour$2$reset$3/g;
+ }
+ # Push updates to bar lists
+ push (@bar_lines_time, $time);
+
+ # Change tab char
+ $delim = " ".weechat::color(weechat::config_string(weechat::config_get("weechat.color.chat_delimiters"))).weechat::config_string(weechat::config_get("weechat.look.prefix_suffix")).weechat::color("reset")." ";
+ $outstr =~ s/\t/$delim/;
+
+ push (@bar_lines, $outstr);
+ # Trigger update
+ weechat::bar_item_update("highmon");
+
+ if (weechat::config_get_plugin("bar_scrolldown") eq "on")
+ {
+ weechat::command("", "/bar scroll highmon * ye")
+ }
+ }
+}
+
+# Start the output display
+sub highmon_start
+{
+ if (weechat::config_get_plugin("output") eq "buffer")
+ {
+ highmon_buffer_open();
+ }
+ elsif (weechat::config_get_plugin("output") eq "bar")
+ {
+ highmon_bar_open();
+ }
+}
+
+# Takes two optional args (channel server), toggles monitoring on/off
+sub highmon_toggle
+{
+ $data = $_[0];
+ $buffer = $_[1];
+ $args = $_[2];
+
+ # Check if we've been told what channel to act on
+ if ($args ne "")
+ {
+ # Split argument up
+ @arg_array = split(/ /,$args);
+ # Check if a server was given
+ if ($arg_array[1])
+ {
+ # Find matching
+ $bufp = weechat::buffer_search("irc", $arg_array[1].".".$arg_array[0]);
+ }
+ else
+ {
+ $found_chans = 0;
+ # Loop through defined servers
+ $infolist = weechat::infolist_get("buffer", "", "");
+ while (weechat::infolist_next($infolist))
+ {
+ # Only interesting in IRC buffers
+ if (weechat::infolist_string($infolist, "plugin_name") eq "irc")
+ {
+ # Find buffers that maych
+ $sname = weechat::infolist_string($infolist, "short_name");
+ if ($sname eq $arg_array[0])
+ {
+ $found_chans++;
+ $bufp = weechat::infolist_pointer($infolist, "pointer");
+ }
+ }
+ }
+ weechat::infolist_free($infolist);
+ # If the infolist found more than one channel, halt as we need to know which one
+ if ($found_chans > 1)
+ {
+ weechat::print("", "Channel name is not unique, please define server");
+ return weechat::WEECHAT_RC_OK;
+ }
+ }
+ # Something didn't return right
+ if ($bufp eq "")
+ {
+ weechat::print("", "Could not find buffer");
+ return weechat::WEECHAT_RC_OK;
+ }
+ }
+ else
+ {
+ # Get pointer from where we are
+ $bufp = weechat::current_buffer();
+ }
+ # Get buffer name
+ $bufname = weechat::buffer_get_string($bufp, 'name');
+ # Test if buffer is an IRC channel
+ if ($bufname =~ /(.*)\.([#&\+!])(.*)/)
+ {
+ if (weechat::config_get_plugin($bufname) eq "off")
+ {
+ # If currently off, set on
+ weechat::config_set_plugin($bufname, "on");
+
+ # Send to output formatter
+ highmon_print("Highlight Monitoring Enabled", $bufp);
+ return weechat::WEECHAT_RC_OK;
+ }
+ elsif (weechat::config_get_plugin($bufname) eq "on" || weechat::config_get_plugin($bufname) eq "")
+ {
+ # If currently on, set off
+ weechat::config_set_plugin($bufname, "off");
+
+ # Send to output formatter
+ highmon_print("Highlight Monitoring Disabled", $bufp);
+ return weechat::WEECHAT_RC_OK;
+ }
+ }
+}
+
+# Takes a buffer pointer and returns a formatted name
+sub format_buffer_name
+{
+ $cb_bufferp = $_[0];
+ $bufname = weechat::buffer_get_string($cb_bufferp, 'name');
+
+ # Set colour from buffer name
+ if (weechat::config_get_plugin("color_buf") eq "on")
+ {
+ # Determine what colour to use
+ $color = weechat::info_get("irc_nick_color", $bufname);
+ if (!$color)
+ {
+ $color = 0;
+ @char_array = split(//,$bufname);
+ foreach $char (@char_array)
+ {
+ $color += ord($char);
+ }
+ $color %= 10;
+ $color = sprintf "weechat.color.chat_nick_color%02d", $color+1;
+ $color = weechat::config_get($color);
+ $color = weechat::config_string($color);
+ $color = weechat::color($color);
+ }
+
+ # Private message just show network
+ if (weechat::config_get_plugin("merge_private") eq "on" && weechat::buffer_get_string($cb_bufferp, "localvar_type") eq "private")
+ {
+ $bufname = weechat::buffer_get_string($cb_bufferp, "localvar_server");
+ }
+ # Format name to short or 'nicename'
+ elsif (weechat::config_get_plugin("short_names") eq "on")
+ {
+ $bufname = weechat::buffer_get_string($cb_bufferp, 'short_name');
+ }
+ else
+ {
+ $bufname =~ s/(.*)\.([#&\+!])(.*)/$1$2$3/;
+ }
+
+ # Build a coloured string
+ $bufname = $color.$bufname.weechat::color("reset");
+ }
+ # User set colour name
+ elsif (weechat::config_get_plugin("color_buf") ne "off")
+ {
+ # Private message just show network
+ if (weechat::config_get_plugin("merge_private") eq "on" && weechat::buffer_get_string($cb_bufferp, "localvar_type") eq "private")
+ {
+ $bufname = weechat::buffer_get_string($cb_bufferp, "localvar_server");
+ }
+ # Format name to short or 'nicename'
+ elsif (weechat::config_get_plugin("short_names") eq "on")
+ {
+ $bufname = weechat::buffer_get_string($cb_bufferp, 'short_name');
+ }
+ else
+ {
+ $bufname =~ s/(.*)\.([#&\+!])(.*)/$1$2$3/;
+ }
+
+ $color = weechat::config_get_plugin("color_buf");
+ $bufname = weechat::color($color).$bufname.weechat::color("reset");
+ }
+ # Stick with default colour
+ else
+ {
+ # Private message just show network
+ if (weechat::config_get_plugin("merge_private") eq "on" && weechat::buffer_get_string($cb_bufferp, "localvar_type") eq "private")
+ {
+ $bufname = weechat::buffer_get_string($cb_bufferp, "localvar_server");
+ }
+ # Format name to short or 'nicename'
+ elsif (weechat::config_get_plugin("short_names") eq "on")
+ {
+ $bufname = weechat::buffer_get_string($cb_bufferp, 'short_name');
+ }
+ else
+ {
+ $bufname =~ s/(.*)\.([#&\+!])(.*)/$1$2$3/;
+ }
+ }
+
+ return $bufname;
+}
+
+# Check result of register, and attempt to behave in a sane manner
+if (!weechat::register("highmon", "KenjiE20", "2.5", "GPL3", "Highlight Monitor", "", ""))
+{
+ # Double load
+ weechat::print ("", "\tHighmon is already loaded");
+ return weechat::WEECHAT_RC_OK;
+}
+else
+{
+ # Start everything
+ highmon_hook();
+ highmon_config_init();
+ highmon_start();
+}
diff --git a/.weechat/plugins.conf b/.weechat/plugins.conf
@@ -0,0 +1,56 @@
+#
+# weechat -- plugins.conf
+#
+# WARNING: It is NOT recommended to edit this file by hand,
+# especially if WeeChat is running.
+#
+# Use /set or similar command to change settings in WeeChat.
+#
+# For more info, see: https://weechat.org/doc/quickstart
+#
+
+[var]
+perl.check_license = "off"
+perl.highmon.alignment = "channel"
+perl.highmon.away_only = "off"
+perl.highmon.color_buf = "on"
+perl.highmon.first_run = "true"
+perl.highmon.hotlist_show = "off"
+perl.highmon.logging = "off"
+perl.highmon.merge_private = "off"
+perl.highmon.nick_prefix = "<"
+perl.highmon.nick_suffix = ">"
+perl.highmon.output = "buffer"
+perl.highmon.short_names = "off"
+python.buffer_autoclose.age_limit = "30"
+python.buffer_autoclose.ignore = ""
+python.buffer_autoclose.interval = "1"
+python.check_license = "off"
+python.go.auto_jump = "off"
+python.go.buffer_number = "on"
+python.go.color_name = "black,cyan"
+python.go.color_name_highlight = "red,cyan"
+python.go.color_name_highlight_selected = "red,brown"
+python.go.color_name_selected = "black,brown"
+python.go.color_number = "yellow,magenta"
+python.go.color_number_selected = "yellow,red"
+python.go.fuzzy_search = "off"
+python.go.message = "Go to: "
+python.go.short_name = "off"
+python.go.sort = "number,beginning"
+python.go.use_core_instead_weechat = "off"
+
+[desc]
+python.go.auto_jump = "automatically jump to buffer when it is uniquely selected (default: "off")"
+python.go.buffer_number = "display buffer number (default: "on")"
+python.go.color_name = "color for buffer name (not selected) (default: "black,cyan")"
+python.go.color_name_highlight = "color for highlight in buffer name (not selected) (default: "red,cyan")"
+python.go.color_name_highlight_selected = "color for highlight in a selected buffer name (default: "red,brown")"
+python.go.color_name_selected = "color for a selected buffer name (default: "black,brown")"
+python.go.color_number = "color for buffer number (not selected) (default: "yellow,magenta")"
+python.go.color_number_selected = "color for selected buffer number (default: "yellow,red")"
+python.go.fuzzy_search = "search buffer matches using approximation (default: "off")"
+python.go.message = "message to display before list of buffers (default: "Go to: ")"
+python.go.short_name = "display and search in short names instead of buffer name (default: "off")"
+python.go.sort = "comma-separated list of keys to sort buffers (the order is important, sorts are performed in the given order): name = sort by name (or short name), (default: "number,beginning")"
+python.go.use_core_instead_weechat = "use name "core" instead of "weechat" for core buffer (default: "off")"
diff --git a/.weechat/python/autoload/autosort.py b/.weechat/python/autoload/autosort.py
@@ -0,0 +1 @@
+../autosort.py+
\ No newline at end of file
diff --git a/.weechat/python/autoload/buffer_autoclose.py b/.weechat/python/autoload/buffer_autoclose.py
@@ -0,0 +1 @@
+../buffer_autoclose.py+
\ No newline at end of file
diff --git a/.weechat/python/autoload/colorize_nicks.py b/.weechat/python/autoload/colorize_nicks.py
@@ -0,0 +1 @@
+../colorize_nicks.py+
\ No newline at end of file
diff --git a/.weechat/python/autoload/go.py b/.weechat/python/autoload/go.py
@@ -0,0 +1 @@
+../go.py+
\ No newline at end of file
diff --git a/.weechat/python/autosort.py b/.weechat/python/autosort.py
@@ -0,0 +1,923 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2013-2017 Maarten de Vries <maarten@de-vri.es>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# Autosort automatically keeps your buffers sorted and grouped by server.
+# You can define your own sorting rules. See /help autosort for more details.
+#
+# https://github.com/de-vri-es/weechat-autosort
+#
+
+#
+# Changelog:
+# 3.3:
+# * Fix the /autosort debug command for unicode.
+# * Update the default rules to work better with Slack.
+# 3.2:
+# * Fix python3 compatiblity.
+# 3.1:
+# * Use colors to format the help text.
+# 3.0:
+# * Switch to evaluated expressions for sorting.
+# * Add `/autosort debug` command.
+# * Add ${info:autosort_replace,from,to,text} to replace substrings in sort rules.
+# * Add ${info:autosort_order,value,first,second,third} to ease writing sort rules.
+# * Make tab completion context aware.
+# 2.8:
+# * Fix compatibility with python 3 regarding unicode handling.
+# 2.7:
+# * Fix sorting of buffers with spaces in their name.
+# 2.6:
+# * Ignore case in rules when doing case insensitive sorting.
+# 2.5:
+# * Fix handling unicode buffer names.
+# * Add hint to set irc.look.server_buffer to independent and buffers.look.indenting to on.
+# 2.4:
+# * Make script python3 compatible.
+# 2.3:
+# * Fix sorting items without score last (regressed in 2.2).
+# 2.2:
+# * Add configuration option for signals that trigger a sort.
+# * Add command to manually trigger a sort (/autosort sort).
+# * Add replacement patterns to apply before sorting.
+# 2.1:
+# * Fix some minor style issues.
+# 2.0:
+# * Allow for custom sort rules.
+#
+
+
+import json
+import math
+import re
+import sys
+import time
+import weechat
+
+SCRIPT_NAME = 'autosort'
+SCRIPT_AUTHOR = 'Maarten de Vries <maarten@de-vri.es>'
+SCRIPT_VERSION = '3.3'
+SCRIPT_LICENSE = 'GPL3'
+SCRIPT_DESC = 'Flexible automatic (or manual) buffer sorting based on eval expressions.'
+
+
+config = None
+hooks = []
+timer = None
+
+# Make sure that unicode, bytes and str are always available in python2 and 3.
+# For python 2, str == bytes
+# For python 3, str == unicode
+if sys.version_info[0] >= 3:
+ unicode = str
+
+def ensure_str(input):
+ '''
+ Make sure the given type if the correct string type for the current python version.
+ That means bytes for python2 and unicode for python3.
+ '''
+ if not isinstance(input, str):
+ if isinstance(input, bytes):
+ return input.encode('utf-8')
+ if isinstance(input, unicode):
+ return input.decode('utf-8')
+ return input
+
+
+if hasattr(time, 'perf_counter'):
+ perf_counter = time.perf_counter
+else:
+ perf_counter = time.clock
+
+def casefold(string):
+ if hasattr(string, 'casefold'): return string.casefold()
+ # Fall back to lowercasing for python2.
+ return string.lower()
+
+def list_swap(values, a, b):
+ values[a], values[b] = values[b], values[a]
+
+def list_move(values, old_index, new_index):
+ values.insert(new_index, values.pop(old_index))
+
+def list_find(collection, value):
+ for i, elem in enumerate(collection):
+ if elem == value: return i
+ return None
+
+class HumanReadableError(Exception):
+ pass
+
+def parse_int(arg, arg_name = 'argument'):
+ ''' Parse an integer and provide a more human readable error. '''
+ arg = arg.strip()
+ try:
+ return int(arg)
+ except ValueError:
+ raise HumanReadableError('Invalid {0}: expected integer, got "{1}".'.format(arg_name, arg))
+
+def decode_rules(blob):
+ parsed = json.loads(blob)
+ if not isinstance(parsed, list):
+ log('Malformed rules, expected a JSON encoded list of strings, but got a {0}. No rules have been loaded. Please fix the setting manually.'.format(type(parsed)))
+ return []
+
+ for i, entry in enumerate(parsed):
+ if not isinstance(entry, (str, unicode)):
+ log('Rule #{0} is not a string but a {1}. No rules have been loaded. Please fix the setting manually.'.format(i, type(entry)))
+ return []
+
+ return parsed
+
+def decode_helpers(blob):
+ parsed = json.loads(blob)
+ if not isinstance(parsed, dict):
+ log('Malformed helpers, expected a JSON encoded dictonary but got a {0}. No helpers have been loaded. Please fix the setting manually.'.format(type(parsed)))
+ return {}
+
+ for key, value in parsed.items():
+ if not isinstance(value, (str, unicode)):
+ log('Helper "{0}" is not a string but a {1}. No helpers have been loaded. Please fix seting manually.'.format(key, type(value)))
+ return {}
+ return parsed
+
+class Config:
+ ''' The autosort configuration. '''
+
+ default_rules = json.dumps([
+ '${core_first}',
+ '${irc_last}',
+ '${buffer.plugin.name}',
+ '${irc_raw_first}',
+ '${if:${plugin}==irc?${server}}',
+ '${if:${plugin}==irc?${info:autosort_order,${type},server,*,channel,private}}',
+ '${if:${plugin}==irc?${hashless_name}}',
+ '${buffer.full_name}',
+ ])
+
+ default_helpers = json.dumps({
+ 'core_first': '${if:${buffer.full_name}!=core.weechat}',
+ 'irc_first': '${if:${buffer.plugin.name}!=irc}',
+ 'irc_last': '${if:${buffer.plugin.name}==irc}',
+ 'irc_raw_first': '${if:${buffer.full_name}!=irc.irc_raw}',
+ 'irc_raw_last': '${if:${buffer.full_name}==irc.irc_raw}',
+ 'hashless_name': '${info:autosort_replace,#,,${buffer.name}}',
+ })
+
+ default_signal_delay = 5
+
+ default_signals = 'buffer_opened buffer_merged buffer_unmerged buffer_renamed'
+
+ def __init__(self, filename):
+ ''' Initialize the configuration. '''
+
+ self.filename = filename
+ self.config_file = weechat.config_new(self.filename, '', '')
+ self.sorting_section = None
+ self.v3_section = None
+
+ self.case_sensitive = False
+ self.rules = []
+ self.helpers = {}
+ self.signals = []
+ self.signal_delay = Config.default_signal_delay,
+ self.sort_on_config = True
+
+ self.__case_sensitive = None
+ self.__rules = None
+ self.__helpers = None
+ self.__signals = None
+ self.__signal_delay = None
+ self.__sort_on_config = None
+
+ if not self.config_file:
+ log('Failed to initialize configuration file "{0}".'.format(self.filename))
+ return
+
+ self.sorting_section = weechat.config_new_section(self.config_file, 'sorting', False, False, '', '', '', '', '', '', '', '', '', '')
+ self.v3_section = weechat.config_new_section(self.config_file, 'v3', False, False, '', '', '', '', '', '', '', '', '', '')
+
+ if not self.sorting_section:
+ log('Failed to initialize section "sorting" of configuration file.')
+ weechat.config_free(self.config_file)
+ return
+
+ self.__case_sensitive = weechat.config_new_option(
+ self.config_file, self.sorting_section,
+ 'case_sensitive', 'boolean',
+ 'If this option is on, sorting is case sensitive.',
+ '', 0, 0, 'off', 'off', 0,
+ '', '', '', '', '', ''
+ )
+
+ weechat.config_new_option(
+ self.config_file, self.sorting_section,
+ 'rules', 'string',
+ 'Sort rules used by autosort v2.x and below. Not used by autosort anymore.',
+ '', 0, 0, '', '', 0,
+ '', '', '', '', '', ''
+ )
+
+ weechat.config_new_option(
+ self.config_file, self.sorting_section,
+ 'replacements', 'string',
+ 'Replacement patterns used by autosort v2.x and below. Not used by autosort anymore.',
+ '', 0, 0, '', '', 0,
+ '', '', '', '', '', ''
+ )
+
+ self.__rules = weechat.config_new_option(
+ self.config_file, self.v3_section,
+ 'rules', 'string',
+ 'An ordered list of sorting rules encoded as JSON. See /help autosort for commands to manipulate these rules.',
+ '', 0, 0, Config.default_rules, Config.default_rules, 0,
+ '', '', '', '', '', ''
+ )
+
+ self.__helpers = weechat.config_new_option(
+ self.config_file, self.v3_section,
+ 'helpers', 'string',
+ 'A dictionary helper variables to use in the sorting rules, encoded as JSON. See /help autosort for commands to manipulate these helpers.',
+ '', 0, 0, Config.default_helpers, Config.default_helpers, 0,
+ '', '', '', '', '', ''
+ )
+
+ self.__signals = weechat.config_new_option(
+ self.config_file, self.sorting_section,
+ 'signals', 'string',
+ 'A space separated list of signals that will cause autosort to resort your buffer list.',
+ '', 0, 0, Config.default_signals, Config.default_signals, 0,
+ '', '', '', '', '', ''
+ )
+
+ self.__signal_delay = weechat.config_new_option(
+ self.config_file, self.sorting_section,
+ 'signal_delay', 'integer',
+ 'Delay in milliseconds to wait after a signal before sorting the buffer list. This prevents triggering many times if multiple signals arrive in a short time. It can also be needed to wait for buffer localvars to be available.',
+ '', 0, 1000, str(Config.default_signal_delay), str(Config.default_signal_delay), 0,
+ '', '', '', '', '', ''
+ )
+
+ self.__sort_on_config = weechat.config_new_option(
+ self.config_file, self.sorting_section,
+ 'sort_on_config_change', 'boolean',
+ 'Decides if the buffer list should be sorted when autosort configuration changes.',
+ '', 0, 0, 'on', 'on', 0,
+ '', '', '', '', '', ''
+ )
+
+ if weechat.config_read(self.config_file) != weechat.WEECHAT_RC_OK:
+ log('Failed to load configuration file.')
+
+ if weechat.config_write(self.config_file) != weechat.WEECHAT_RC_OK:
+ log('Failed to write configuration file.')
+
+ self.reload()
+
+ def reload(self):
+ ''' Load configuration variables. '''
+
+ self.case_sensitive = weechat.config_boolean(self.__case_sensitive)
+
+ rules_blob = weechat.config_string(self.__rules)
+ helpers_blob = weechat.config_string(self.__helpers)
+ signals_blob = weechat.config_string(self.__signals)
+
+ self.rules = decode_rules(rules_blob)
+ self.helpers = decode_helpers(helpers_blob)
+ self.signals = signals_blob.split()
+ self.signal_delay = weechat.config_integer(self.__signal_delay)
+ self.sort_on_config = weechat.config_boolean(self.__sort_on_config)
+
+ def save_rules(self, run_callback = True):
+ ''' Save the current rules to the configuration. '''
+ weechat.config_option_set(self.__rules, json.dumps(self.rules), run_callback)
+
+ def save_helpers(self, run_callback = True):
+ ''' Save the current helpers to the configuration. '''
+ weechat.config_option_set(self.__helpers, json.dumps(self.helpers), run_callback)
+
+
+def pad(sequence, length, padding = None):
+ ''' Pad a list until is has a certain length. '''
+ return sequence + [padding] * max(0, (length - len(sequence)))
+
+
+def log(message, buffer = 'NULL'):
+ weechat.prnt(buffer, 'autosort: {0}'.format(message))
+
+
+def get_buffers():
+ ''' Get a list of all the buffers in weechat. '''
+ hdata = weechat.hdata_get('buffer')
+ buffer = weechat.hdata_get_list(hdata, "gui_buffers");
+
+ result = []
+ while buffer:
+ number = weechat.hdata_integer(hdata, buffer, 'number')
+ result.append((number, buffer))
+ buffer = weechat.hdata_pointer(hdata, buffer, 'next_buffer')
+ return hdata, result
+
+class MergedBuffers(list):
+ """ A list of merged buffers, possibly of size 1. """
+ def __init__(self, number):
+ super(MergedBuffers, self).__init__()
+ self.number = number
+
+def merge_buffer_list(buffers):
+ '''
+ Group merged buffers together.
+ The output is a list of MergedBuffers.
+ '''
+ if not buffers: return []
+ result = {}
+ for number, buffer in buffers:
+ if number not in result: result[number] = MergedBuffers(number)
+ result[number].append(buffer)
+ return result.values()
+
+def sort_buffers(hdata, buffers, rules, helpers, case_sensitive):
+ for merged in buffers:
+ for buffer in merged:
+ name = weechat.hdata_string(hdata, buffer, 'name')
+
+ return sorted(buffers, key=merged_sort_key(rules, helpers, case_sensitive))
+
+def buffer_sort_key(rules, helpers, case_sensitive):
+ ''' Create a sort key function for a list of lists of merged buffers. '''
+ def key(buffer):
+ extra_vars = {}
+ for helper_name, helper in sorted(helpers.items()):
+ expanded = weechat.string_eval_expression(helper, {"buffer": buffer}, {}, {})
+ extra_vars[helper_name] = expanded if case_sensitive else casefold(expanded)
+ result = []
+ for rule in rules:
+ expanded = weechat.string_eval_expression(rule, {"buffer": buffer}, extra_vars, {})
+ result.append(expanded if case_sensitive else casefold(expanded))
+ return result
+
+ return key
+
+def merged_sort_key(rules, helpers, case_sensitive):
+ buffer_key = buffer_sort_key(rules, helpers, case_sensitive)
+ def key(merged):
+ best = None
+ for buffer in merged:
+ this = buffer_key(buffer)
+ if best is None or this < best: best = this
+ return best
+ return key
+
+def apply_buffer_order(buffers):
+ ''' Sort the buffers in weechat according to the given order. '''
+ for i, buffer in enumerate(buffers):
+ weechat.buffer_set(buffer[0], "number", str(i + 1))
+
+def split_args(args, expected, optional = 0):
+ ''' Split an argument string in the desired number of arguments. '''
+ split = args.split(' ', expected - 1)
+ if (len(split) < expected):
+ raise HumanReadableError('Expected at least {0} arguments, got {1}.'.format(expected, len(split)))
+ return split[:-1] + pad(split[-1].split(' ', optional), optional + 1, '')
+
+def do_sort():
+ hdata, buffers = get_buffers()
+ buffers = merge_buffer_list(buffers)
+ buffers = sort_buffers(hdata, buffers, config.rules, config.helpers, config.case_sensitive)
+ apply_buffer_order(buffers)
+
+def command_sort(buffer, command, args):
+ ''' Sort the buffers and print a confirmation. '''
+ start = perf_counter()
+ do_sort()
+ elapsed = perf_counter() - start
+ log("Finished sorting buffers in {0:.4f} seconds.".format(elapsed))
+ return weechat.WEECHAT_RC_OK
+
+def command_debug(buffer, command, args):
+ hdata, buffers = get_buffers()
+ buffers = merge_buffer_list(buffers)
+
+ # Show evaluation results.
+ log('Individual evaluation results:')
+ start = perf_counter()
+ key = buffer_sort_key(config.rules, config.helpers, config.case_sensitive)
+ results = []
+ for merged in buffers:
+ for buffer in merged:
+ fullname = weechat.hdata_string(hdata, buffer, 'full_name')
+ results.append((fullname, key(buffer)))
+ elapsed = perf_counter() - start
+
+ for fullname, result in results:
+ fullname = ensure_str(fullname)
+ result = [ensure_str(x) for x in result]
+ log('{0}: {1}'.format(fullname, result))
+ log('Computing evalutaion results took {0:.4f} seconds.'.format(elapsed))
+
+ return weechat.WEECHAT_RC_OK
+
+def command_rule_list(buffer, command, args):
+ ''' Show the list of sorting rules. '''
+ output = 'Sorting rules:\n'
+ for i, rule in enumerate(config.rules):
+ output += ' {0}: {1}\n'.format(i, rule)
+ if not len(config.rules):
+ output += ' No sorting rules configured.\n'
+ log(output )
+
+ return weechat.WEECHAT_RC_OK
+
+
+def command_rule_add(buffer, command, args):
+ ''' Add a rule to the rule list. '''
+ config.rules.append(args)
+ config.save_rules()
+ command_rule_list(buffer, command, '')
+
+ return weechat.WEECHAT_RC_OK
+
+
+def command_rule_insert(buffer, command, args):
+ ''' Insert a rule at the desired position in the rule list. '''
+ index, rule = split_args(args, 2)
+ index = parse_int(index, 'index')
+
+ config.rules.insert(index, rule)
+ config.save_rules()
+ command_rule_list(buffer, command, '')
+ return weechat.WEECHAT_RC_OK
+
+
+def command_rule_update(buffer, command, args):
+ ''' Update a rule in the rule list. '''
+ index, rule = split_args(args, 2)
+ index = parse_int(index, 'index')
+
+ config.rules[index] = rule
+ config.save_rules()
+ command_rule_list(buffer, command, '')
+ return weechat.WEECHAT_RC_OK
+
+
+def command_rule_delete(buffer, command, args):
+ ''' Delete a rule from the rule list. '''
+ index = args.strip()
+ index = parse_int(index, 'index')
+
+ config.rules.pop(index)
+ config.save_rules()
+ command_rule_list(buffer, command, '')
+ return weechat.WEECHAT_RC_OK
+
+
+def command_rule_move(buffer, command, args):
+ ''' Move a rule to a new position. '''
+ index_a, index_b = split_args(args, 2)
+ index_a = parse_int(index_a, 'index')
+ index_b = parse_int(index_b, 'index')
+
+ list_move(config.rules, index_a, index_b)
+ config.save_rules()
+ command_rule_list(buffer, command, '')
+ return weechat.WEECHAT_RC_OK
+
+
+def command_rule_swap(buffer, command, args):
+ ''' Swap two rules. '''
+ index_a, index_b = split_args(args, 2)
+ index_a = parse_int(index_a, 'index')
+ index_b = parse_int(index_b, 'index')
+
+ list_swap(config.rules, index_a, index_b)
+ config.save_rules()
+ command_rule_list(buffer, command, '')
+ return weechat.WEECHAT_RC_OK
+
+
+def command_helper_list(buffer, command, args):
+ ''' Show the list of helpers. '''
+ output = 'Helper variables:\n'
+
+ width = max(map(lambda x: len(x) if len(x) <= 30 else 0, config.helpers.keys()))
+
+ for name, expression in sorted(config.helpers.items()):
+ output += ' {0:>{width}}: {1}\n'.format(name, expression, width=width)
+ if not len(config.helpers):
+ output += ' No helper variables configured.'
+ log(output)
+
+ return weechat.WEECHAT_RC_OK
+
+
+def command_helper_set(buffer, command, args):
+ ''' Add/update a helper to the helper list. '''
+ name, expression = split_args(args, 2)
+
+ config.helpers[name] = expression
+ config.save_helpers()
+ command_helper_list(buffer, command, '')
+
+ return weechat.WEECHAT_RC_OK
+
+def command_helper_delete(buffer, command, args):
+ ''' Delete a helper from the helper list. '''
+ name = args.strip()
+
+ del config.helpers[name]
+ config.save_helpers()
+ command_helper_list(buffer, command, '')
+ return weechat.WEECHAT_RC_OK
+
+
+def command_helper_rename(buffer, command, args):
+ ''' Rename a helper to a new position. '''
+ old_name, new_name = split_args(args, 2)
+
+ try:
+ config.helpers[new_name] = config.helpers[old_name]
+ del config.helpers[old_name]
+ except KeyError:
+ raise HumanReadableError('No such helper: {0}'.format(old_name))
+ config.save_helpers()
+ command_helper_list(buffer, command, '')
+ return weechat.WEECHAT_RC_OK
+
+
+def command_helper_swap(buffer, command, args):
+ ''' Swap two helpers. '''
+ a, b = split_args(args, 2)
+ try:
+ config.helpers[b], config.helpers[a] = config.helpers[a], config.helpers[b]
+ except KeyError as e:
+ raise HumanReadableError('No such helper: {0}'.format(e.args[0]))
+
+ config.helpers.swap(index_a, index_b)
+ config.save_helpers()
+ command_helper_list(buffer, command, '')
+ return weechat.WEECHAT_RC_OK
+
+def call_command(buffer, command, args, subcommands):
+ ''' Call a subccommand from a dictionary. '''
+ subcommand, tail = pad(args.split(' ', 1), 2, '')
+ subcommand = subcommand.strip()
+ if (subcommand == ''):
+ child = subcommands.get(' ')
+ else:
+ command = command + [subcommand]
+ child = subcommands.get(subcommand)
+
+ if isinstance(child, dict):
+ return call_command(buffer, command, tail, child)
+ elif callable(child):
+ return child(buffer, command, tail)
+
+ log('{0}: command not found'.format(' '.join(command)))
+ return weechat.WEECHAT_RC_ERROR
+
+def on_signal(*args, **kwargs):
+ global timer
+ ''' Called whenever the buffer list changes. '''
+ if timer is not None:
+ weechat.unhook(timer)
+ timer = None
+ weechat.hook_timer(config.signal_delay, 0, 1, "on_timeout", "")
+ return weechat.WEECHAT_RC_OK
+
+def on_timeout(pointer, remaining_calls):
+ global timer
+ timer = None
+ do_sort()
+ return weechat.WEECHAT_RC_OK
+
+def apply_config():
+ # Unhook all signals and hook the new ones.
+ for hook in hooks:
+ weechat.unhook(hook)
+ for signal in config.signals:
+ hooks.append(weechat.hook_signal(signal, 'on_signal', ''))
+
+ if config.sort_on_config:
+ do_sort()
+
+def on_config_changed(*args, **kwargs):
+ ''' Called whenever the configuration changes. '''
+ config.reload()
+ apply_config()
+
+ return weechat.WEECHAT_RC_OK
+
+def parse_arg(args):
+ if not args: return None, None
+
+ result = ''
+ escaped = False
+ for i, c in enumerate(args):
+ if not escaped:
+ if c == '\\':
+ escaped = True
+ continue
+ elif c == ',':
+ return result, args[i+1:]
+ result += c
+ escaped = False
+ return result, None
+
+def parse_args(args, max = None):
+ result = []
+ i = 0
+ while max is None or i < max:
+ arg, args = parse_arg(args)
+ if arg is None: break
+ result.append(arg)
+ i += 1
+ return result, args
+
+def on_info_replace(pointer, name, arguments):
+ arguments, rest = parse_args(arguments, 3)
+ if rest or len(arguments) < 3:
+ log('usage: ${{info:{0},old,new,text}}'.format(name))
+ return ''
+ old, new, text = arguments
+
+ return text.replace(old, new)
+
+def on_info_order(pointer, name, arguments):
+ arguments, rest = parse_args(arguments)
+ if len(arguments) < 1:
+ log('usage: ${{info:{0},value,first,second,third,...}}'.format(name))
+ return ''
+
+ value = arguments[0]
+ keys = arguments[1:]
+ if not keys: return '0'
+
+ # Find the value in the keys (or '*' if we can't find it)
+ result = list_find(keys, value)
+ if result is None: result = list_find(keys, '*')
+ if result is None: result = len(keys)
+
+ # Pad result with leading zero to make sure string sorting works.
+ width = int(math.log10(len(keys))) + 1
+ return '{0:0{1}}'.format(result, width)
+
+
+def on_autosort_command(data, buffer, args):
+ ''' Called when the autosort command is invoked. '''
+ try:
+ return call_command(buffer, ['/autosort'], args, {
+ ' ': command_sort,
+ 'sort': command_sort,
+ 'debug': command_debug,
+
+ 'rules': {
+ ' ': command_rule_list,
+ 'list': command_rule_list,
+ 'add': command_rule_add,
+ 'insert': command_rule_insert,
+ 'update': command_rule_update,
+ 'delete': command_rule_delete,
+ 'move': command_rule_move,
+ 'swap': command_rule_swap,
+ },
+ 'helpers': {
+ ' ': command_helper_list,
+ 'list': command_helper_list,
+ 'set': command_helper_set,
+ 'delete': command_helper_delete,
+ 'rename': command_helper_rename,
+ 'swap': command_helper_swap,
+ },
+ })
+ except HumanReadableError as e:
+ log(e)
+ return weechat.WEECHAT_RC_ERROR
+
+def add_completions(completion, words):
+ for word in words:
+ weechat.hook_completion_list_add(completion, word, 0, weechat.WEECHAT_LIST_POS_END)
+
+def autosort_complete_rules(words, completion):
+ if len(words) == 0:
+ add_completions(completion, ['add', 'delete', 'insert', 'list', 'move', 'swap', 'update'])
+ if len(words) == 1 and words[0] in ('delete', 'insert', 'move', 'swap', 'update'):
+ add_completions(completion, map(str, range(len(config.rules))))
+ if len(words) == 2 and words[0] in ('move', 'swap'):
+ add_completions(completion, map(str, range(len(config.rules))))
+ if len(words) == 2 and words[0] in ('update'):
+ try:
+ add_completions(completion, [config.rules[int(words[1])]])
+ except KeyError: pass
+ except ValueError: pass
+ else:
+ add_completions(completion, [''])
+ return weechat.WEECHAT_RC_OK
+
+def autosort_complete_helpers(words, completion):
+ if len(words) == 0:
+ add_completions(completion, ['delete', 'list', 'rename', 'set', 'swap'])
+ elif len(words) == 1 and words[0] in ('delete', 'rename', 'set', 'swap'):
+ add_completions(completion, sorted(config.helpers.keys()))
+ elif len(words) == 2 and words[0] == 'swap':
+ add_completions(completion, sorted(config.helpers.keys()))
+ elif len(words) == 2 and words[0] == 'rename':
+ add_completions(completion, sorted(config.helpers.keys()))
+ elif len(words) == 2 and words[0] == 'set':
+ try:
+ add_completions(completion, [config.helpers[words[1]]])
+ except KeyError: pass
+ return weechat.WEECHAT_RC_OK
+
+def on_autosort_complete(data, name, buffer, completion):
+ cmdline = weechat.buffer_get_string(buffer, "input")
+ cursor = weechat.buffer_get_integer(buffer, "input_pos")
+ prefix = cmdline[:cursor]
+ words = prefix.split()[1:]
+
+ # If the current word isn't finished yet,
+ # ignore it for coming up with completion suggestions.
+ if prefix[-1] != ' ': words = words[:-1]
+
+ if len(words) == 0:
+ add_completions(completion, ['debug', 'helpers', 'rules', 'sort'])
+ elif words[0] == 'rules':
+ return autosort_complete_rules(words[1:], completion)
+ elif words[0] == 'helpers':
+ return autosort_complete_helpers(words[1:], completion)
+ return weechat.WEECHAT_RC_OK
+
+command_description = r'''{*white}# General commands{reset}
+
+{*white}/autosort {brown}sort{reset}
+Manually trigger the buffer sorting.
+
+{*white}/autosort {brown}debug{reset}
+Show the evaluation results of the sort rules for each buffer.
+
+
+{*white}# Sorting rule commands{reset}
+
+{*white}/autosort{brown} rules list{reset}
+Print the list of sort rules.
+
+{*white}/autosort {brown}rules add {cyan}<expression>{reset}
+Add a new rule at the end of the list.
+
+{*white}/autosort {brown}rules insert {cyan}<index> <expression>{reset}
+Insert a new rule at the given index in the list.
+
+{*white}/autosort {brown}rules update {cyan}<index> <expression>{reset}
+Update a rule in the list with a new expression.
+
+{*white}/autosort {brown}rules delete {cyan}<index>
+Delete a rule from the list.
+
+{*white}/autosort {brown}rules move {cyan}<index_from> <index_to>{reset}
+Move a rule from one position in the list to another.
+
+{*white}/autosort {brown}rules swap {cyan}<index_a> <index_b>{reset}
+Swap two rules in the list
+
+
+{*white}# Helper variable commands{reset}
+
+{*white}/autosort {brown}helpers list
+Print the list of helper variables.
+
+{*white}/autosort {brown}helpers set {cyan}<name> <expression>
+Add or update a helper variable with the given name.
+
+{*white}/autosort {brown}helpers delete {cyan}<name>
+Delete a helper variable.
+
+{*white}/autosort {brown}helpers rename {cyan}<old_name> <new_name>
+Rename a helper variable.
+
+{*white}/autosort {brown}helpers swap {cyan}<name_a> <name_b>
+Swap the expressions of two helper variables in the list.
+
+
+{*white}# Description
+Autosort is a weechat script to automatically keep your buffers sorted. The sort
+order can be customized by defining your own sort rules, but the default should
+be sane enough for most people. It can also group IRC channel/private buffers
+under their server buffer if you like.
+
+{*white}# Sort rules{reset}
+Autosort evaluates a list of eval expressions (see {*default}/help eval{reset}) and sorts the
+buffers based on evaluated result. Earlier rules will be considered first. Only
+if earlier rules produced identical results is the result of the next rule
+considered for sorting purposes.
+
+You can debug your sort rules with the `{*default}/autosort debug{reset}` command, which will
+print the evaluation results of each rule for each buffer.
+
+{*brown}NOTE:{reset} The sort rules for version 3 are not compatible with version 2 or vice
+versa. You will have to manually port your old rules to version 3 if you have any.
+
+{*white}# Helper variables{reset}
+You may define helper variables for the main sort rules to keep your rules
+readable. They can be used in the main sort rules as variables. For example,
+a helper variable named `{cyan}foo{reset}` can be accessed in a main rule with the
+string `{cyan}${{foo}}{reset}`.
+
+{*white}# Replacing substrings{reset}
+There is no default method for replacing text inside eval expressions. However,
+autosort adds a `replace` info hook that can be used inside eval expressions:
+ {cyan}${{info:autosort_replace,from,to,text}}{reset}
+
+For example, to strip all hashes from a buffer name, you could write:
+ {cyan}${{info:autosort_replace,#,,${{buffer.name}}}}{reset}
+
+You can escape commas and backslashes inside the arguments by prefixing them with
+a backslash.
+
+{*white}# Automatic or manual sorting{reset}
+By default, autosort will automatically sort your buffer list whenever a buffer
+is opened, merged, unmerged or renamed. This should keep your buffers sorted in
+almost all situations. However, you may wish to change the list of signals that
+cause your buffer list to be sorted. Simply edit the `{cyan}autosort.sorting.signals{reset}`
+option to add or remove any signal you like.
+
+If you remove all signals you can still sort your buffers manually with the
+`{*default}/autosort sort{reset}` command. To prevent all automatic sorting, the option
+`{cyan}autosort.sorting.sort_on_config_change{reset}` should also be disabled.
+
+{*white}# Recommended settings
+For the best visual effect, consider setting the following options:
+ {*white}/set {cyan}irc.look.server_buffer{reset} {brown}independent{reset}
+ {*white}/set {cyan}buffers.look.indenting{reset} {brown}on{reset}
+
+The first setting allows server buffers to be sorted independently, which is
+needed to create a hierarchical tree view of the server and channel buffers.
+The second one indents channel and private buffers in the buffer list of the
+`{*default}buffers.pl{reset}` script.
+
+If you are using the {*default}buflist{reset} plugin you can (ab)use Unicode to draw a tree
+structure with the following setting (modify to suit your need):
+ {*white}/set {cyan}buflist.format.indent {brown}"${{color:237}}${{if:${{buffer.next_buffer.local_variables.type}}=~^(channel|private)$?├─:└─}}"{reset}
+'''
+
+command_completion = '%(plugin_autosort) %(plugin_autosort) %(plugin_autosort) %(plugin_autosort) %(plugin_autosort)'
+
+info_replace_description = 'Replace all occurences of `from` with `to` in the string `text`.'
+info_replace_arguments = 'from,to,text'
+
+info_order_description = (
+ 'Get a zero padded index of a value in a list of possible values.'
+ 'If the value is not found, the index for `*` is returned.'
+ 'If there is no `*` in the list, the highest index + 1 is returned.'
+)
+info_order_arguments = 'value,first,second,third,...'
+
+
+if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, "", ""):
+ config = Config('autosort')
+
+ colors = {
+ 'default': weechat.color('default'),
+ 'reset': weechat.color('reset'),
+ 'black': weechat.color('black'),
+ 'red': weechat.color('red'),
+ 'green': weechat.color('green'),
+ 'brown': weechat.color('brown'),
+ 'yellow': weechat.color('yellow'),
+ 'blue': weechat.color('blue'),
+ 'magenta': weechat.color('magenta'),
+ 'cyan': weechat.color('cyan'),
+ 'white': weechat.color('white'),
+ '*default': weechat.color('*default'),
+ '*black': weechat.color('*black'),
+ '*red': weechat.color('*red'),
+ '*green': weechat.color('*green'),
+ '*brown': weechat.color('*brown'),
+ '*yellow': weechat.color('*yellow'),
+ '*blue': weechat.color('*blue'),
+ '*magenta': weechat.color('*magenta'),
+ '*cyan': weechat.color('*cyan'),
+ '*white': weechat.color('*white'),
+ }
+
+ weechat.hook_config('autosort.*', 'on_config_changed', '')
+ weechat.hook_completion('plugin_autosort', '', 'on_autosort_complete', '')
+ weechat.hook_command('autosort', command_description.format(**colors), '', '', command_completion, 'on_autosort_command', '')
+ weechat.hook_info('autosort_replace', info_replace_description, info_replace_arguments, 'on_info_replace', '')
+ weechat.hook_info('autosort_order', info_order_description, info_order_arguments, 'on_info_order', '')
+
+ apply_config()
diff --git a/.weechat/python/buffer_autoclose.py b/.weechat/python/buffer_autoclose.py
@@ -0,0 +1,137 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2009 by xt <xt@bash.no>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# (this script requires WeeChat 0.3.0 or newer)
+#
+# History:
+# 2018-04-10, Sébastien Helleu <flashcode@flashtux.org>
+# version 0.5: fix infolist_time for WeeChat >= 2.2 (WeeChat returns a long
+# integer instead of a string)
+# 2016-02-05, ixti
+# version 0.4: Add Python3 support
+# 2009-12-15, xt
+# version 0.3: moved around some control structures to not be as noisy
+# 2009-12-02, xt
+# version 0.2: bugfix, more printing
+# 2009-12-01, xt <xt@bash.no>
+# version 0.1: initial release
+
+import weechat as w
+import time
+
+SCRIPT_NAME = "buffer_autoclose"
+SCRIPT_AUTHOR = "xt <xt@bash.no>"
+SCRIPT_VERSION = "0.5"
+SCRIPT_LICENSE = "GPL3"
+SCRIPT_DESC = "Automatically close inactive private message buffers"
+
+settings = {
+ 'interval': '1', # How often in minutes to check
+ 'age_limit': '30', # How old in minutes before auto close
+ 'ignore': '', # Buffers to ignore (use full name: server.buffer_name)
+}
+
+if w.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE,
+ SCRIPT_DESC, "", ""):
+ for option, default_value in settings.items():
+ if not w.config_is_set_plugin(option):
+ w.config_set_plugin(option, default_value)
+ w.hook_timer(\
+ int(w.config_get_plugin('interval')) * 1000 * 60,
+ 0,
+ 0,
+ "close_time_cb",
+ '')
+
+
+def get_all_buffers():
+ '''Returns list with pointers of all open buffers.'''
+ buffers = []
+ infolist = w.infolist_get('buffer', '', '')
+ while w.infolist_next(infolist):
+ buffer_type = w.buffer_get_string(w.infolist_pointer(infolist, 'pointer'), 'localvar_type')
+ if buffer_type == 'private': # we only close private message buffers for now
+ buffers.append(w.infolist_pointer(infolist, 'pointer'))
+ w.infolist_free(infolist)
+ return buffers
+
+def get_last_line_date(buffer):
+ date = '1970-01-01 01:00:00'
+ infolist = w.infolist_get('buffer_lines', buffer, '')
+ while w.infolist_prev(infolist):
+ date = w.infolist_time(infolist, 'date')
+ # since WeeChat 2.2, infolist_time returns a long integer instead of
+ # a string
+ if not isinstance(date, str):
+ date = time.strftime('%F %T', time.localtime(int(date)))
+ if date != '1970-01-01 01:00:00':
+ # Some lines like "Day changed to" message doesn't have date
+ # set so loop until we find a message that does
+ break
+ w.infolist_free(infolist)
+ return date
+
+def is_in_hotlist(buffer):
+ ''' Returns true if buffer is in hotlist, false if not'''
+
+ hotlist = w.infolist_get('hotlist', '', '')
+ found = False
+ while w.infolist_next(hotlist):
+ thebuffer = w.infolist_pointer(hotlist, 'buffer_pointer')
+ if thebuffer == buffer:
+ found = True
+ name = w.buffer_get_string(thebuffer, 'short_name')
+ break
+
+ w.infolist_free(hotlist)
+ return found
+
+def close_time_cb(buffer, args):
+ ''' Callback for check for inactivity and close '''
+
+ for buffer in get_all_buffers():
+ name = w.buffer_get_string(buffer, 'name')
+
+
+ date = get_last_line_date(buffer)
+ date = time.mktime(time.strptime(date, '%Y-%m-%d %H:%M:%S'))
+ now = time.time()
+ seconds_old = now - date
+ if seconds_old > int(w.config_get_plugin('age_limit'))*60:
+ if is_in_hotlist(buffer):
+ #w.prnt('', '%s: Not closing buffer: %s: it is in hotlist' %(SCRIPT_NAME, name))
+ continue
+ if name in w.config_get_plugin('ignore').split(','):
+ #w.prnt('', '%s: Not closing buffer: %s: it is in ignore list' %(SCRIPT_NAME, name))
+ continue
+ if buffer == w.current_buffer():
+ # Never close current buffer
+ #w.prnt('', '%s: Not closing buffer: %s: it is in currently active' %(SCRIPT_NAME, name))
+ continue
+ if len(w.buffer_get_string(buffer, 'input')):
+ # Don't close buffers with text on input line
+ #w.prnt('', '%s: Not closing buffer: %s: it has input' %(SCRIPT_NAME, name))
+ continue
+
+ w.prnt('', '%s: Closing buffer: %s' %(SCRIPT_NAME, name))
+ w.command(buffer, '/buffer close')
+ #else:
+ # w.prnt('', '%s: Not closing buffer: %s: it is too new: %s' %(SCRIPT_NAME, name, seconds_old))
+
+ return w.WEECHAT_RC_OK
diff --git a/.weechat/python/colorize_nicks.py b/.weechat/python/colorize_nicks.py
@@ -0,0 +1,400 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2010 by xt <xt@bash.no>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# This script colors nicks in IRC channels in the actual message
+# not just in the prefix section.
+#
+#
+# History:
+# 2018-04-06: Joey Pabalinas <joeypabalinas@gmail.com>
+# version 26: fix freezes with too many nicks in one line
+# 2018-03-18: nils_2
+# version 25: fix unable to run function colorize_config_reload_cb()
+# 2017-06-20: lbeziaud <louis.beziaud@ens-rennes.fr>
+# version 24: colorize utf8 nicks
+# 2017-03-01, arza <arza@arza.us>
+# version 23: don't colorize nicklist group names
+# 2016-05-01, Simmo Saan <simmo.saan@gmail.com>
+# version 22: invalidate cached colors on hash algorithm change
+# 2015-07-28, xt
+# version 21: fix problems with nicks with commas in them
+# 2015-04-19, xt
+# version 20: fix ignore of nicks in URLs
+# 2015-04-18, xt
+# version 19: new option ignore nicks in URLs
+# 2015-03-03, xt
+# version 18: iterate buffers looking for nicklists instead of servers
+# 2015-02-23, holomorph
+# version 17: fix coloring in non-channel buffers (#58)
+# 2014-09-17, holomorph
+# version 16: use weechat config facilities
+# clean unused, minor linting, some simplification
+# 2014-05-05, holomorph
+# version 15: fix python2-specific re.search check
+# 2013-01-29, nils_2
+# version 14: make script compatible with Python 3.x
+# 2012-10-19, ldvx
+# version 13: Iterate over every word to prevent incorrect colorization of
+# nicks. Added option greedy_matching.
+# 2012-04-28, ldvx
+# version 12: added ignore_tags to avoid colorizing nicks if tags are present
+# 2012-01-14, nesthib
+# version 11: input_text_display hook and modifier to colorize nicks in input bar
+# 2010-12-22, xt
+# version 10: hook config option for updating blacklist
+# 2010-12-20, xt
+# version 0.9: hook new config option for weechat 0.3.4
+# 2010-11-01, nils_2
+# version 0.8: hook_modifier() added to communicate with rainbow_text
+# 2010-10-01, xt
+# version 0.7: changes to support non-irc-plugins
+# 2010-07-29, xt
+# version 0.6: compile regexp as per patch from Chris quigybo@hotmail.com
+# 2010-07-19, xt
+# version 0.5: fix bug with incorrect coloring of own nick
+# 2010-06-02, xt
+# version 0.4: update to reflect API changes
+# 2010-03-26, xt
+# version 0.3: fix error with exception
+# 2010-03-24, xt
+# version 0.2: use ignore_channels when populating to increase performance.
+# 2010-02-03, xt
+# version 0.1: initial (based on ruby script by dominikh)
+#
+# Known issues: nicks will not get colorized if they begin with a character
+# such as ~ (which some irc networks do happen to accept)
+
+import weechat
+import re
+w = weechat
+
+SCRIPT_NAME = "colorize_nicks"
+SCRIPT_AUTHOR = "xt <xt@bash.no>"
+SCRIPT_VERSION = "26"
+SCRIPT_LICENSE = "GPL"
+SCRIPT_DESC = "Use the weechat nick colors in the chat area"
+
+# Based on the recommendations in RFC 7613. A valid nick is composed
+# of anything but " ,*?.!@".
+VALID_NICK = r'([@~&!%+-])?([^\s,\*?\.!@]+)'
+valid_nick_re = re.compile(VALID_NICK)
+ignore_channels = []
+ignore_nicks = []
+
+# Dict with every nick on every channel with its color as lookup value
+colored_nicks = {}
+
+CONFIG_FILE_NAME = "colorize_nicks"
+
+# config file and options
+colorize_config_file = ""
+colorize_config_option = {}
+
+def colorize_config_init():
+ '''
+ Initialization of configuration file.
+ Sections: look.
+ '''
+ global colorize_config_file, colorize_config_option
+ colorize_config_file = weechat.config_new(CONFIG_FILE_NAME,
+ "", "")
+ if colorize_config_file == "":
+ return
+
+ # section "look"
+ section_look = weechat.config_new_section(
+ colorize_config_file, "look", 0, 0, "", "", "", "", "", "", "", "", "", "")
+ if section_look == "":
+ weechat.config_free(colorize_config_file)
+ return
+ colorize_config_option["blacklist_channels"] = weechat.config_new_option(
+ colorize_config_file, section_look, "blacklist_channels",
+ "string", "Comma separated list of channels", "", 0, 0,
+ "", "", 0, "", "", "", "", "", "")
+ colorize_config_option["blacklist_nicks"] = weechat.config_new_option(
+ colorize_config_file, section_look, "blacklist_nicks",
+ "string", "Comma separated list of nicks", "", 0, 0,
+ "so,root", "so,root", 0, "", "", "", "", "", "")
+ colorize_config_option["min_nick_length"] = weechat.config_new_option(
+ colorize_config_file, section_look, "min_nick_length",
+ "integer", "Minimum length nick to colorize", "",
+ 2, 20, "", "", 0, "", "", "", "", "", "")
+ colorize_config_option["colorize_input"] = weechat.config_new_option(
+ colorize_config_file, section_look, "colorize_input",
+ "boolean", "Whether to colorize input", "", 0,
+ 0, "off", "off", 0, "", "", "", "", "", "")
+ colorize_config_option["ignore_tags"] = weechat.config_new_option(
+ colorize_config_file, section_look, "ignore_tags",
+ "string", "Comma separated list of tags to ignore; i.e. irc_join,irc_part,irc_quit", "", 0, 0,
+ "", "", 0, "", "", "", "", "", "")
+ colorize_config_option["greedy_matching"] = weechat.config_new_option(
+ colorize_config_file, section_look, "greedy_matching",
+ "boolean", "If off, then use lazy matching instead", "", 0,
+ 0, "on", "on", 0, "", "", "", "", "", "")
+ colorize_config_option["match_limit"] = weechat.config_new_option(
+ colorize_config_file, section_look, "match_limit",
+ "integer", "Fall back to lazy matching if greedy matches exceeds this number", "",
+ 20, 1000, "", "", 0, "", "", "", "", "", "")
+ colorize_config_option["ignore_nicks_in_urls"] = weechat.config_new_option(
+ colorize_config_file, section_look, "ignore_nicks_in_urls",
+ "boolean", "If on, don't colorize nicks inside URLs", "", 0,
+ 0, "off", "off", 0, "", "", "", "", "", "")
+
+def colorize_config_read():
+ ''' Read configuration file. '''
+ global colorize_config_file
+ return weechat.config_read(colorize_config_file)
+
+def colorize_nick_color(nick, my_nick):
+ ''' Retrieve nick color from weechat. '''
+ if nick == my_nick:
+ return w.color(w.config_string(w.config_get('weechat.color.chat_nick_self')))
+ else:
+ return w.info_get('irc_nick_color', nick)
+
+def colorize_cb(data, modifier, modifier_data, line):
+ ''' Callback that does the colorizing, and returns new line if changed '''
+
+ global ignore_nicks, ignore_channels, colored_nicks
+
+
+ full_name = modifier_data.split(';')[1]
+ channel = '.'.join(full_name.split('.')[1:])
+
+ buffer = w.buffer_search('', full_name)
+ # Check if buffer has colorized nicks
+ if buffer not in colored_nicks:
+ return line
+
+ if channel and channel in ignore_channels:
+ return line
+
+ min_length = w.config_integer(colorize_config_option['min_nick_length'])
+ reset = w.color('reset')
+
+ # Don't colorize if the ignored tag is present in message
+ tags_line = modifier_data.rsplit(';')
+ if len(tags_line) >= 3:
+ tags_line = tags_line[2].split(',')
+ for i in w.config_string(colorize_config_option['ignore_tags']).split(','):
+ if i in tags_line:
+ return line
+
+ for words in valid_nick_re.findall(line):
+ nick = words[1]
+ # Check that nick is not ignored and longer than minimum length
+ if len(nick) < min_length or nick in ignore_nicks:
+ continue
+
+ # If the matched word is not a known nick, we try to match the
+ # word without its first or last character (if not a letter).
+ # This is necessary as "foo:" is a valid nick, which could be
+ # adressed as "foo::".
+ if nick not in colored_nicks[buffer]:
+ if not nick[-1].isalpha() and not nick[0].isalpha():
+ if nick[1:-1] in colored_nicks[buffer]:
+ nick = nick[1:-1]
+ elif not nick[0].isalpha():
+ if nick[1:] in colored_nicks[buffer]:
+ nick = nick[1:]
+ elif not nick[-1].isalpha():
+ if nick[:-1] in colored_nicks[buffer]:
+ nick = nick[:-1]
+
+ # Check that nick is in the dictionary colored_nicks
+ if nick in colored_nicks[buffer]:
+ nick_color = colored_nicks[buffer][nick]
+
+ try:
+ # Let's use greedy matching. Will check against every word in a line.
+ if w.config_boolean(colorize_config_option['greedy_matching']):
+ cnt = 0
+ limit = w.config_integer(colorize_config_option['match_limit'])
+
+ for word in line.split():
+ cnt += 1
+ assert cnt < limit
+ # if cnt > limit:
+ # raise RuntimeError('Exceeded colorize_nicks.look.match_limit.');
+
+ if w.config_boolean(colorize_config_option['ignore_nicks_in_urls']) and \
+ word.startswith(('http://', 'https://')):
+ continue
+
+ if nick in word:
+ # Is there a nick that contains nick and has a greater lenght?
+ # If so let's save that nick into var biggest_nick
+ biggest_nick = ""
+ for i in colored_nicks[buffer]:
+ cnt += 1
+ assert cnt < limit
+
+ if nick in i and nick != i and len(i) > len(nick):
+ if i in word:
+ # If a nick with greater len is found, and that word
+ # also happens to be in word, then let's save this nick
+ biggest_nick = i
+ # If there's a nick with greater len, then let's skip this
+ # As we will have the chance to colorize when biggest_nick
+ # iterates being nick.
+ if len(biggest_nick) > 0 and biggest_nick in word:
+ pass
+ elif len(word) < len(biggest_nick) or len(biggest_nick) == 0:
+ new_word = word.replace(nick, '%s%s%s' % (nick_color, nick, reset))
+ line = line.replace(word, new_word)
+
+ # Switch to lazy matching
+ else:
+ raise AssertionError
+
+ except AssertionError:
+ # Let's use lazy matching for nick
+ nick_color = colored_nicks[buffer][nick]
+ # The two .? are in case somebody writes "nick:", "nick,", etc
+ # to address somebody
+ regex = r"(\A|\s).?(%s).?(\Z|\s)" % re.escape(nick)
+ match = re.search(regex, line)
+ if match is not None:
+ new_line = line[:match.start(2)] + nick_color+nick+reset + line[match.end(2):]
+ line = new_line
+
+ return line
+
+def colorize_input_cb(data, modifier, modifier_data, line):
+ ''' Callback that does the colorizing in input '''
+
+ global ignore_nicks, ignore_channels, colored_nicks
+
+ min_length = w.config_integer(colorize_config_option['min_nick_length'])
+
+ if not w.config_boolean(colorize_config_option['colorize_input']):
+ return line
+
+ buffer = w.current_buffer()
+ # Check if buffer has colorized nicks
+ if buffer not in colored_nicks:
+ return line
+
+ channel = w.buffer_get_string(buffer, 'name')
+ if channel and channel in ignore_channels:
+ return line
+
+ reset = w.color('reset')
+
+ for words in valid_nick_re.findall(line):
+ nick = words[1]
+ # Check that nick is not ignored and longer than minimum length
+ if len(nick) < min_length or nick in ignore_nicks:
+ continue
+ if nick in colored_nicks[buffer]:
+ nick_color = colored_nicks[buffer][nick]
+ line = line.replace(nick, '%s%s%s' % (nick_color, nick, reset))
+
+ return line
+
+def populate_nicks(*args):
+ ''' Fills entire dict with all nicks weechat can see and what color it has
+ assigned to it. '''
+ global colored_nicks
+
+ colored_nicks = {}
+
+ buffers = w.infolist_get('buffer', '', '')
+ while w.infolist_next(buffers):
+ buffer_ptr = w.infolist_pointer(buffers, 'pointer')
+ my_nick = w.buffer_get_string(buffer_ptr, 'localvar_nick')
+ nicklist = w.infolist_get('nicklist', buffer_ptr, '')
+ while w.infolist_next(nicklist):
+ if buffer_ptr not in colored_nicks:
+ colored_nicks[buffer_ptr] = {}
+
+ if w.infolist_string(nicklist, 'type') != 'nick':
+ continue
+
+ nick = w.infolist_string(nicklist, 'name')
+ nick_color = colorize_nick_color(nick, my_nick)
+
+ colored_nicks[buffer_ptr][nick] = nick_color
+
+ w.infolist_free(nicklist)
+
+ w.infolist_free(buffers)
+
+ return w.WEECHAT_RC_OK
+
+def add_nick(data, signal, type_data):
+ ''' Add nick to dict of colored nicks '''
+ global colored_nicks
+
+ # Nicks can have , in them in some protocols
+ splitted = type_data.split(',')
+ pointer = splitted[0]
+ nick = ",".join(splitted[1:])
+ if pointer not in colored_nicks:
+ colored_nicks[pointer] = {}
+
+ my_nick = w.buffer_get_string(pointer, 'localvar_nick')
+ nick_color = colorize_nick_color(nick, my_nick)
+
+ colored_nicks[pointer][nick] = nick_color
+
+ return w.WEECHAT_RC_OK
+
+def remove_nick(data, signal, type_data):
+ ''' Remove nick from dict with colored nicks '''
+ global colored_nicks
+
+ # Nicks can have , in them in some protocols
+ splitted = type_data.split(',')
+ pointer = splitted[0]
+ nick = ",".join(splitted[1:])
+
+ if pointer in colored_nicks and nick in colored_nicks[pointer]:
+ del colored_nicks[pointer][nick]
+
+ return w.WEECHAT_RC_OK
+
+def update_blacklist(*args):
+ ''' Set the blacklist for channels and nicks. '''
+ global ignore_channels, ignore_nicks
+ ignore_channels = w.config_string(colorize_config_option['blacklist_channels']).split(',')
+ ignore_nicks = w.config_string(colorize_config_option['blacklist_nicks']).split(',')
+ return w.WEECHAT_RC_OK
+
+if __name__ == "__main__":
+ if w.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE,
+ SCRIPT_DESC, "", ""):
+ colorize_config_init()
+ colorize_config_read()
+
+ # Run once to get data ready
+ update_blacklist()
+ populate_nicks()
+
+ w.hook_signal('nicklist_nick_added', 'add_nick', '')
+ w.hook_signal('nicklist_nick_removed', 'remove_nick', '')
+ w.hook_modifier('weechat_print', 'colorize_cb', '')
+ # Hook config for changing colors
+ w.hook_config('weechat.color.chat_nick_colors', 'populate_nicks', '')
+ w.hook_config('weechat.look.nick_color_hash', 'populate_nicks', '')
+ # Hook for working togheter with other scripts (like colorize_lines)
+ w.hook_modifier('colorize_nicks', 'colorize_cb', '')
+ # Hook for modifying input
+ w.hook_modifier('250|input_text_display', 'colorize_input_cb', '')
+ # Hook for updating blacklist (this could be improved to use fnmatch)
+ weechat.hook_config('%s.look.blacklist*' % SCRIPT_NAME, 'update_blacklist', '')
diff --git a/.weechat/python/go.py b/.weechat/python/go.py
@@ -0,0 +1,561 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2009-2014 Sébastien Helleu <flashcode@flashtux.org>
+# Copyright (C) 2010 m4v <lambdae2@gmail.com>
+# Copyright (C) 2011 stfn <stfnmd@googlemail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# History:
+#
+# 2017-04-01, Sébastien Helleu <flashcode@flashtux.org>:
+# version 2.5: add option "buffer_number"
+# 2017-03-02, Sébastien Helleu <flashcode@flashtux.org>:
+# version 2.4: fix syntax and indentation error
+# 2017-02-25, Simmo Saan <simmo.saan@gmail.com>
+# version 2.3: fix fuzzy search breaking buffer number search display
+# 2016-01-28, ylambda <ylambda@koalabeast.com>
+# version 2.2: add option "fuzzy_search"
+# 2015-11-12, nils_2 <weechatter@arcor.de>
+# version 2.1: fix problem with buffer short_name "weechat", using option
+# "use_core_instead_weechat", see:
+# https://github.com/weechat/weechat/issues/574
+# 2014-05-12, Sébastien Helleu <flashcode@flashtux.org>:
+# version 2.0: add help on options, replace option "sort_by_activity" by
+# "sort" (add sort by name and first match at beginning of
+# name and by number), PEP8 compliance
+# 2012-11-26, Nei <anti.teamidiot.de>
+# version 1.9: add auto_jump option to automatically go to buffer when it
+# is uniquely selected
+# 2012-09-17, Sébastien Helleu <flashcode@flashtux.org>:
+# version 1.8: fix jump to non-active merged buffers (jump with buffer name
+# instead of number)
+# 2012-01-03 nils_2 <weechatter@arcor.de>
+# version 1.7: add option "use_core_instead_weechat"
+# 2012-01-03, Sébastien Helleu <flashcode@flashtux.org>:
+# version 1.6: make script compatible with Python 3.x
+# 2011-08-24, stfn <stfnmd@googlemail.com>:
+# version 1.5: /go with name argument jumps directly to buffer
+# Remember cursor position in buffer input
+# 2011-05-31, Elián Hanisch <lambdae2@gmail.com>:
+# version 1.4: Sort list of buffers by activity.
+# 2011-04-25, Sébastien Helleu <flashcode@flashtux.org>:
+# version 1.3: add info "go_running" (used by script input_lock.rb)
+# 2010-11-01, Sébastien Helleu <flashcode@flashtux.org>:
+# version 1.2: use high priority for hooks to prevent conflict with other
+# plugins/scripts (WeeChat >= 0.3.4 only)
+# 2010-03-25, Elián Hanisch <lambdae2@gmail.com>:
+# version 1.1: use a space to match the end of a string
+# 2009-11-16, Sébastien Helleu <flashcode@flashtux.org>:
+# version 1.0: add new option to display short names
+# 2009-06-15, Sébastien Helleu <flashcode@flashtux.org>:
+# version 0.9: fix typo in /help go with command /key
+# 2009-05-16, Sébastien Helleu <flashcode@flashtux.org>:
+# version 0.8: search buffer by number, fix bug when window is split
+# 2009-05-03, Sébastien Helleu <flashcode@flashtux.org>:
+# version 0.7: eat tab key (do not complete input, just move buffer
+# pointer)
+# 2009-05-02, Sébastien Helleu <flashcode@flashtux.org>:
+# version 0.6: sync with last API changes
+# 2009-03-22, Sébastien Helleu <flashcode@flashtux.org>:
+# version 0.5: update modifier signal name for input text display,
+# fix arguments for function string_remove_color
+# 2009-02-18, Sébastien Helleu <flashcode@flashtux.org>:
+# version 0.4: do not hook command and init options if register failed
+# 2009-02-08, Sébastien Helleu <flashcode@flashtux.org>:
+# version 0.3: case insensitive search for buffers names
+# 2009-02-08, Sébastien Helleu <flashcode@flashtux.org>:
+# version 0.2: add help about Tab key
+# 2009-02-08, Sébastien Helleu <flashcode@flashtux.org>:
+# version 0.1: initial release
+#
+
+"""
+Quick jump to buffers.
+(this script requires WeeChat 0.3.0 or newer)
+"""
+
+from __future__ import print_function
+
+SCRIPT_NAME = 'go'
+SCRIPT_AUTHOR = 'Sébastien Helleu <flashcode@flashtux.org>'
+SCRIPT_VERSION = '2.5'
+SCRIPT_LICENSE = 'GPL3'
+SCRIPT_DESC = 'Quick jump to buffers'
+
+SCRIPT_COMMAND = 'go'
+
+IMPORT_OK = True
+
+try:
+ import weechat
+except ImportError:
+ print('This script must be run under WeeChat.')
+ print('Get WeeChat now at: http://www.weechat.org/')
+ IMPORT_OK = False
+
+import re
+
+# script options
+SETTINGS = {
+ 'color_number': (
+ 'yellow,magenta',
+ 'color for buffer number (not selected)'),
+ 'color_number_selected': (
+ 'yellow,red',
+ 'color for selected buffer number'),
+ 'color_name': (
+ 'black,cyan',
+ 'color for buffer name (not selected)'),
+ 'color_name_selected': (
+ 'black,brown',
+ 'color for a selected buffer name'),
+ 'color_name_highlight': (
+ 'red,cyan',
+ 'color for highlight in buffer name (not selected)'),
+ 'color_name_highlight_selected': (
+ 'red,brown',
+ 'color for highlight in a selected buffer name'),
+ 'message': (
+ 'Go to: ',
+ 'message to display before list of buffers'),
+ 'short_name': (
+ 'off',
+ 'display and search in short names instead of buffer name'),
+ 'sort': (
+ 'number,beginning',
+ 'comma-separated list of keys to sort buffers '
+ '(the order is important, sorts are performed in the given order): '
+ 'name = sort by name (or short name), ',
+ 'hotlist = sort by hotlist order, '
+ 'number = first match a buffer number before digits in name, '
+ 'beginning = first match at beginning of names (or short names); '
+ 'the default sort of buffers is by numbers'),
+ 'use_core_instead_weechat': (
+ 'off',
+ 'use name "core" instead of "weechat" for core buffer'),
+ 'auto_jump': (
+ 'off',
+ 'automatically jump to buffer when it is uniquely selected'),
+ 'fuzzy_search': (
+ 'off',
+ 'search buffer matches using approximation'),
+ 'buffer_number': (
+ 'on',
+ 'display buffer number'),
+}
+
+# hooks management
+HOOK_COMMAND_RUN = {
+ 'input': ('/input *', 'go_command_run_input'),
+ 'buffer': ('/buffer *', 'go_command_run_buffer'),
+ 'window': ('/window *', 'go_command_run_window'),
+}
+hooks = {}
+
+# input before command /go (we'll restore it later)
+saved_input = ''
+saved_input_pos = 0
+
+# last user input (if changed, we'll update list of matching buffers)
+old_input = None
+
+# matching buffers
+buffers = []
+buffers_pos = 0
+
+
+def go_option_enabled(option):
+ """Checks if a boolean script option is enabled or not."""
+ return weechat.config_string_to_boolean(weechat.config_get_plugin(option))
+
+
+def go_info_running(data, info_name, arguments):
+ """Returns "1" if go is running, otherwise "0"."""
+ return '1' if 'modifier' in hooks else '0'
+
+
+def go_unhook_one(hook):
+ """Unhook something hooked by this script."""
+ global hooks
+ if hook in hooks:
+ weechat.unhook(hooks[hook])
+ del hooks[hook]
+
+
+def go_unhook_all():
+ """Unhook all."""
+ go_unhook_one('modifier')
+ for hook in HOOK_COMMAND_RUN:
+ go_unhook_one(hook)
+
+
+def go_hook_all():
+ """Hook command_run and modifier."""
+ global hooks
+ priority = ''
+ version = weechat.info_get('version_number', '') or 0
+ # use high priority for hook to prevent conflict with other plugins/scripts
+ # (WeeChat >= 0.3.4 only)
+ if int(version) >= 0x00030400:
+ priority = '2000|'
+ for hook, value in HOOK_COMMAND_RUN.items():
+ if hook not in hooks:
+ hooks[hook] = weechat.hook_command_run(
+ '%s%s' % (priority, value[0]),
+ value[1], '')
+ if 'modifier' not in hooks:
+ hooks['modifier'] = weechat.hook_modifier(
+ 'input_text_display_with_cursor', 'go_input_modifier', '')
+
+
+def go_start(buf):
+ """Start go on buffer."""
+ global saved_input, saved_input_pos, old_input, buffers_pos
+ go_hook_all()
+ saved_input = weechat.buffer_get_string(buf, 'input')
+ saved_input_pos = weechat.buffer_get_integer(buf, 'input_pos')
+ weechat.buffer_set(buf, 'input', '')
+ old_input = None
+ buffers_pos = 0
+
+
+def go_end(buf):
+ """End go on buffer."""
+ global saved_input, saved_input_pos, old_input
+ go_unhook_all()
+ weechat.buffer_set(buf, 'input', saved_input)
+ weechat.buffer_set(buf, 'input_pos', str(saved_input_pos))
+ old_input = None
+
+
+def go_match_beginning(buf, string):
+ """Check if a string matches the beginning of buffer name/short name."""
+ if not string:
+ return False
+ esc_str = re.escape(string)
+ if re.search(r'^#?' + esc_str, buf['name']) \
+ or re.search(r'^#?' + esc_str, buf['short_name']):
+ return True
+ return False
+
+
+def go_match_fuzzy(name, string):
+ """Check if string matches name using approximation."""
+ if not string:
+ return False
+
+ name_len = len(name)
+ string_len = len(string)
+
+ if string_len > name_len:
+ return False
+ if name_len == string_len:
+ return name == string
+
+ # Attempt to match all chars somewhere in name
+ prev_index = -1
+ for i, char in enumerate(string):
+ index = name.find(char, prev_index+1)
+ if index == -1:
+ return False
+ prev_index = index
+ return True
+
+
+def go_now(buf, args):
+ """Go to buffer specified by args."""
+ listbuf = go_matching_buffers(args)
+ if not listbuf:
+ return
+
+ # prefer buffer that matches at beginning (if option is enabled)
+ if 'beginning' in weechat.config_get_plugin('sort').split(','):
+ for index in range(len(listbuf)):
+ if go_match_beginning(listbuf[index], args):
+ weechat.command(buf,
+ '/buffer ' + str(listbuf[index]['full_name']))
+ return
+
+ # jump to first buffer in matching buffers by default
+ weechat.command(buf, '/buffer ' + str(listbuf[0]['full_name']))
+
+
+def go_cmd(data, buf, args):
+ """Command "/go": just hook what we need."""
+ global hooks
+ if args:
+ go_now(buf, args)
+ elif 'modifier' in hooks:
+ go_end(buf)
+ else:
+ go_start(buf)
+ return weechat.WEECHAT_RC_OK
+
+
+def go_matching_buffers(strinput):
+ """Return a list with buffers matching user input."""
+ global buffers_pos
+ listbuf = []
+ if len(strinput) == 0:
+ buffers_pos = 0
+ strinput = strinput.lower()
+ infolist = weechat.infolist_get('buffer', '', '')
+ while weechat.infolist_next(infolist):
+ short_name = weechat.infolist_string(infolist, 'short_name')
+ if go_option_enabled('short_name'):
+ name = weechat.infolist_string(infolist, 'short_name')
+ else:
+ name = weechat.infolist_string(infolist, 'name')
+ if name == 'weechat' \
+ and go_option_enabled('use_core_instead_weechat') \
+ and weechat.infolist_string(infolist, 'plugin_name') == 'core':
+ name = 'core'
+ number = weechat.infolist_integer(infolist, 'number')
+ full_name = weechat.infolist_string(infolist, 'full_name')
+ if not full_name:
+ full_name = '%s.%s' % (
+ weechat.infolist_string(infolist, 'plugin_name'),
+ weechat.infolist_string(infolist, 'name'))
+ pointer = weechat.infolist_pointer(infolist, 'pointer')
+ matching = name.lower().find(strinput) >= 0
+ if not matching and strinput[-1] == ' ':
+ matching = name.lower().endswith(strinput.strip())
+ if not matching and go_option_enabled('fuzzy_search'):
+ matching = go_match_fuzzy(name.lower(), strinput)
+ if not matching and strinput.isdigit():
+ matching = str(number).startswith(strinput)
+ if len(strinput) == 0 or matching:
+ listbuf.append({
+ 'number': number,
+ 'short_name': short_name,
+ 'name': name,
+ 'full_name': full_name,
+ 'pointer': pointer,
+ })
+ weechat.infolist_free(infolist)
+
+ # sort buffers
+ hotlist = []
+ infolist = weechat.infolist_get('hotlist', '', '')
+ while weechat.infolist_next(infolist):
+ hotlist.append(
+ weechat.infolist_pointer(infolist, 'buffer_pointer'))
+ weechat.infolist_free(infolist)
+ last_index_hotlist = len(hotlist)
+
+ def _sort_name(buf):
+ """Sort buffers by name (or short name)."""
+ return buf['name']
+
+ def _sort_hotlist(buf):
+ """Sort buffers by hotlist order."""
+ try:
+ return hotlist.index(buf['pointer'])
+ except ValueError:
+ # not in hotlist, always last.
+ return last_index_hotlist
+
+ def _sort_match_number(buf):
+ """Sort buffers by match on number."""
+ return 0 if str(buf['number']) == strinput else 1
+
+ def _sort_match_beginning(buf):
+ """Sort buffers by match at beginning."""
+ return 0 if go_match_beginning(buf, strinput) else 1
+
+ funcs = {
+ 'name': _sort_name,
+ 'hotlist': _sort_hotlist,
+ 'number': _sort_match_number,
+ 'beginning': _sort_match_beginning,
+ }
+
+ for key in weechat.config_get_plugin('sort').split(','):
+ if key in funcs:
+ listbuf = sorted(listbuf, key=funcs[key])
+
+ if not strinput:
+ index = [i for i, buf in enumerate(listbuf)
+ if buf['pointer'] == weechat.current_buffer()]
+ if index:
+ buffers_pos = index[0]
+
+ return listbuf
+
+
+def go_buffers_to_string(listbuf, pos, strinput):
+ """Return string built with list of buffers found (matching user input)."""
+ string = ''
+ strinput = strinput.lower()
+ for i in range(len(listbuf)):
+ selected = '_selected' if i == pos else ''
+ buffer_name = listbuf[i]['name']
+ index = buffer_name.lower().find(strinput)
+ if index >= 0:
+ index2 = index + len(strinput)
+ name = '%s%s%s%s%s' % (
+ buffer_name[:index],
+ weechat.color(weechat.config_get_plugin(
+ 'color_name_highlight' + selected)),
+ buffer_name[index:index2],
+ weechat.color(weechat.config_get_plugin(
+ 'color_name' + selected)),
+ buffer_name[index2:])
+ elif go_option_enabled("fuzzy_search") and \
+ go_match_fuzzy(buffer_name.lower(), strinput):
+ name = ""
+ prev_index = -1
+ for char in strinput.lower():
+ index = buffer_name.lower().find(char, prev_index+1)
+ if prev_index < 0:
+ name += buffer_name[:index]
+ name += weechat.color(weechat.config_get_plugin(
+ 'color_name_highlight' + selected))
+ if prev_index >= 0 and index > prev_index+1:
+ name += weechat.color(weechat.config_get_plugin(
+ 'color_name' + selected))
+ name += buffer_name[prev_index+1:index]
+ name += weechat.color(weechat.config_get_plugin(
+ 'color_name_highlight' + selected))
+ name += buffer_name[index]
+ prev_index = index
+
+ name += weechat.color(weechat.config_get_plugin(
+ 'color_name' + selected))
+ name += buffer_name[prev_index+1:]
+ else:
+ name = buffer_name
+ string += ' '
+ if go_option_enabled('buffer_number'):
+ string += '%s%s' % (
+ weechat.color(weechat.config_get_plugin(
+ 'color_number' + selected)),
+ str(listbuf[i]['number']))
+ string += '%s%s%s' % (
+ weechat.color(weechat.config_get_plugin(
+ 'color_name' + selected)),
+ name,
+ weechat.color('reset'))
+ return ' ' + string if string else ''
+
+
+def go_input_modifier(data, modifier, modifier_data, string):
+ """This modifier is called when input text item is built by WeeChat.
+
+ This is commonly called after changes in input or cursor move: it builds
+ a new input with prefix ("Go to:"), and suffix (list of buffers found).
+ """
+ global old_input, buffers, buffers_pos
+ if modifier_data != weechat.current_buffer():
+ return ''
+ names = ''
+ new_input = weechat.string_remove_color(string, '')
+ new_input = new_input.lstrip()
+ if old_input is None or new_input != old_input:
+ old_buffers = buffers
+ buffers = go_matching_buffers(new_input)
+ if buffers != old_buffers and len(new_input) > 0:
+ if len(buffers) == 1 and go_option_enabled('auto_jump'):
+ weechat.command(modifier_data, '/wait 1ms /input return')
+ buffers_pos = 0
+ old_input = new_input
+ names = go_buffers_to_string(buffers, buffers_pos, new_input.strip())
+ return weechat.config_get_plugin('message') + string + names
+
+
+def go_command_run_input(data, buf, command):
+ """Function called when a command "/input xxx" is run."""
+ global buffers, buffers_pos
+ if command == '/input search_text' or command.find('/input jump') == 0:
+ # search text or jump to another buffer is forbidden now
+ return weechat.WEECHAT_RC_OK_EAT
+ elif command == '/input complete_next':
+ # choose next buffer in list
+ buffers_pos += 1
+ if buffers_pos >= len(buffers):
+ buffers_pos = 0
+ weechat.hook_signal_send('input_text_changed',
+ weechat.WEECHAT_HOOK_SIGNAL_STRING, '')
+ return weechat.WEECHAT_RC_OK_EAT
+ elif command == '/input complete_previous':
+ # choose previous buffer in list
+ buffers_pos -= 1
+ if buffers_pos < 0:
+ buffers_pos = len(buffers) - 1
+ weechat.hook_signal_send('input_text_changed',
+ weechat.WEECHAT_HOOK_SIGNAL_STRING, '')
+ return weechat.WEECHAT_RC_OK_EAT
+ elif command == '/input return':
+ # switch to selected buffer (if any)
+ go_end(buf)
+ if len(buffers) > 0:
+ weechat.command(
+ buf, '/buffer ' + str(buffers[buffers_pos]['full_name']))
+ return weechat.WEECHAT_RC_OK_EAT
+ return weechat.WEECHAT_RC_OK
+
+
+def go_command_run_buffer(data, buf, command):
+ """Function called when a command "/buffer xxx" is run."""
+ return weechat.WEECHAT_RC_OK_EAT
+
+
+def go_command_run_window(data, buf, command):
+ """Function called when a command "/window xxx" is run."""
+ return weechat.WEECHAT_RC_OK_EAT
+
+
+def go_unload_script():
+ """Function called when script is unloaded."""
+ go_unhook_all()
+ return weechat.WEECHAT_RC_OK
+
+
+def go_main():
+ """Entry point."""
+ if not weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION,
+ SCRIPT_LICENSE, SCRIPT_DESC,
+ 'go_unload_script', ''):
+ return
+ weechat.hook_command(
+ SCRIPT_COMMAND,
+ 'Quick jump to buffers', '[name]',
+ 'name: directly jump to buffer by name (without argument, list is '
+ 'displayed)\n\n'
+ 'You can bind command to a key, for example:\n'
+ ' /key bind meta-g /go\n\n'
+ 'You can use completion key (commonly Tab and shift-Tab) to select '
+ 'next/previous buffer in list.',
+ '%(buffers_names)',
+ 'go_cmd', '')
+
+ # set default settings
+ version = weechat.info_get('version_number', '') or 0
+ for option, value in SETTINGS.items():
+ if not weechat.config_is_set_plugin(option):
+ weechat.config_set_plugin(option, value[0])
+ if int(version) >= 0x00030500:
+ weechat.config_set_desc_plugin(
+ option, '%s (default: "%s")' % (value[1], value[0]))
+ weechat.hook_info('go_running',
+ 'Return "1" if go is running, otherwise "0"',
+ '',
+ 'go_info_running', '')
+
+
+if __name__ == "__main__" and IMPORT_OK:
+ go_main()
diff --git a/.weechat/relay.conf b/.weechat/relay.conf
@@ -0,0 +1,48 @@
+#
+# weechat -- relay.conf
+#
+# WARNING: It is NOT recommended to edit this file by hand,
+# especially if WeeChat is running.
+#
+# Use /set or similar command to change settings in WeeChat.
+#
+# For more info, see: https://weechat.org/doc/quickstart
+#
+
+[look]
+auto_open_buffer = on
+raw_messages = 256
+
+[color]
+client = cyan
+status_active = lightblue
+status_auth_failed = lightred
+status_connecting = yellow
+status_disconnected = lightred
+status_waiting_auth = brown
+text = default
+text_bg = default
+text_selected = white
+
+[network]
+allow_empty_password = off
+allowed_ips = ""
+bind_address = ""
+clients_purge_delay = 0
+compression_level = 6
+ipv6 = on
+max_clients = 5
+password = ""
+ssl_cert_key = "%h/ssl/relay.pem"
+ssl_priorities = "NORMAL:-VERS-SSL3.0"
+websocket_allowed_origins = ""
+
+[irc]
+backlog_max_minutes = 1440
+backlog_max_number = 256
+backlog_since_last_disconnect = on
+backlog_since_last_message = off
+backlog_tags = "irc_privmsg"
+backlog_time_format = "[%H:%M] "
+
+[port]
diff --git a/.weechat/script.conf b/.weechat/script.conf
@@ -0,0 +1,56 @@
+#
+# weechat -- script.conf
+#
+# WARNING: It is NOT recommended to edit this file by hand,
+# especially if WeeChat is running.
+#
+# Use /set or similar command to change settings in WeeChat.
+#
+# For more info, see: https://weechat.org/doc/quickstart
+#
+
+[look]
+columns = "%s %n %V %v %u | %d | %t"
+diff_color = on
+diff_command = "auto"
+display_source = on
+quiet_actions = on
+sort = "p,n"
+translate_description = on
+use_keys = on
+
+[color]
+status_autoloaded = cyan
+status_held = white
+status_installed = lightcyan
+status_obsolete = lightmagenta
+status_popular = yellow
+status_running = lightgreen
+status_unknown = lightred
+text = default
+text_bg = default
+text_bg_selected = red
+text_date = default
+text_date_selected = white
+text_delimiters = default
+text_description = default
+text_description_selected = white
+text_extension = default
+text_extension_selected = white
+text_name = cyan
+text_name_selected = lightcyan
+text_selected = white
+text_tags = brown
+text_tags_selected = yellow
+text_version = magenta
+text_version_loaded = default
+text_version_loaded_selected = white
+text_version_selected = lightmagenta
+
+[scripts]
+autoload = on
+cache_expire = 1440
+download_timeout = 30
+hold = ""
+path = "%h/script"
+url = "https://weechat.org/files/plugins.xml.gz"
diff --git a/.weechat/sec.conf b/.weechat/sec.conf
@@ -0,0 +1,20 @@
+#
+# weechat -- sec.conf
+#
+# WARNING: It is NOT recommended to edit this file by hand,
+# especially if WeeChat is running.
+#
+# Use /set or similar command to change settings in WeeChat.
+#
+# For more info, see: https://weechat.org/doc/quickstart
+#
+
+[crypt]
+cipher = aes256
+hash_algo = sha256
+passphrase_file = ""
+salt = on
+
+[data]
+__passphrase__ = on
+freenode = "083E5D2B43DDD37A80DF63FE3C63D955AB03868BBC9C6B9CEFE24F30F67A002B1CC5B4B690F823B5167F47720A451ED8C840A3771903194810CB4D5109456560C17150C8A295809124F3DB"
diff --git a/.weechat/trigger.conf b/.weechat/trigger.conf
@@ -0,0 +1,67 @@
+#
+# weechat -- trigger.conf
+#
+# WARNING: It is NOT recommended to edit this file by hand,
+# especially if WeeChat is running.
+#
+# Use /set or similar command to change settings in WeeChat.
+#
+# For more info, see: https://weechat.org/doc/quickstart
+#
+
+[look]
+enabled = on
+monitor_strip_colors = off
+
+[color]
+flag_command = lightgreen
+flag_conditions = yellow
+flag_post_action = lightblue
+flag_regex = lightcyan
+flag_return_code = lightmagenta
+regex = white
+replace = cyan
+trigger = green
+trigger_disabled = red
+
+[trigger]
+beep.arguments = ""
+beep.command = "/print -beep"
+beep.conditions = "${tg_displayed} && (${tg_highlight} || ${tg_msg_pv})"
+beep.enabled = on
+beep.hook = print
+beep.post_action = none
+beep.regex = ""
+beep.return_code = ok
+cmd_pass.arguments = "5000|input_text_display;5000|history_add;5000|irc_command_auth"
+cmd_pass.command = ""
+cmd_pass.conditions = ""
+cmd_pass.enabled = on
+cmd_pass.hook = modifier
+cmd_pass.post_action = none
+cmd_pass.regex = "==^((/(msg|m|quote) +nickserv +(id|identify|ghost +[^ ]+|release +[^ ]+|regain +[^ ]+|recover +[^ ]+) +)|/oper +[^ ]+ +|/quote +pass +|/set +[^ ]*password[^ ]* +|/secure +(passphrase|decrypt|set +[^ ]+) +)(.*)==${re:1}${hide:*,${re:+}}"
+cmd_pass.return_code = ok
+cmd_pass_register.arguments = "5000|input_text_display;5000|history_add;5000|irc_command_auth"
+cmd_pass_register.command = ""
+cmd_pass_register.conditions = ""
+cmd_pass_register.enabled = on
+cmd_pass_register.hook = modifier
+cmd_pass_register.post_action = none
+cmd_pass_register.regex = "==^(/(msg|m|quote) +nickserv +register +)([^ ]+)(.*)==${re:1}${hide:*,${re:3}}${re:4}"
+cmd_pass_register.return_code = ok
+msg_auth.arguments = "5000|irc_message_auth"
+msg_auth.command = ""
+msg_auth.conditions = ""
+msg_auth.enabled = on
+msg_auth.hook = modifier
+msg_auth.post_action = none
+msg_auth.regex = "==^(.*(id|identify|register|ghost +[^ ]+|release +[^ ]+|regain +[^ ]+|recover +[^ ]+) +)(.*)==${re:1}${hide:*,${re:+}}"
+msg_auth.return_code = ok
+server_pass.arguments = "5000|input_text_display;5000|history_add"
+server_pass.command = ""
+server_pass.conditions = ""
+server_pass.enabled = on
+server_pass.hook = modifier
+server_pass.post_action = none
+server_pass.regex = "==^(/(server|connect) .*-(sasl_)?password=)([^ ]+)(.*)==${re:1}${hide:*,${re:4}}${re:5}"
+server_pass.return_code = ok
diff --git a/.weechat/weechat.conf b/.weechat/weechat.conf
@@ -0,0 +1,649 @@
+#
+# weechat -- weechat.conf
+#
+# WARNING: It is NOT recommended to edit this file by hand,
+# especially if WeeChat is running.
+#
+# Use /set or similar command to change settings in WeeChat.
+#
+# For more info, see: https://weechat.org/doc/quickstart
+#
+
+[debug]
+
+[startup]
+command_after_plugins = ""
+command_before_plugins = ""
+display_logo = on
+display_version = on
+sys_rlimit = ""
+
+[look]
+align_end_of_lines = message
+align_multiline_words = on
+bar_more_down = "▼▼"
+bar_more_left = "◀◀"
+bar_more_right = "▶▶"
+bar_more_up = "▲▲"
+bare_display_exit_on_input = on
+bare_display_time_format = "%H:%M"
+buffer_auto_renumber = on
+buffer_notify_default = message
+buffer_position = end
+buffer_search_case_sensitive = off
+buffer_search_force_default = off
+buffer_search_regex = off
+buffer_search_where = prefix_message
+buffer_time_format = "%H:%M:%S"
+color_basic_force_bold = off
+color_inactive_buffer = on
+color_inactive_message = on
+color_inactive_prefix = on
+color_inactive_prefix_buffer = on
+color_inactive_time = off
+color_inactive_window = on
+color_nick_offline = off
+color_pairs_auto_reset = 5
+color_real_white = off
+command_chars = ""
+command_incomplete = off
+confirm_quit = off
+confirm_upgrade = off
+day_change = on
+day_change_message_1date = "-- %a, %d %b %Y --"
+day_change_message_2dates = "-- %%a, %%d %%b %%Y (%a, %d %b %Y) --"
+eat_newline_glitch = off
+emphasized_attributes = ""
+highlight = ""
+highlight_regex = ""
+highlight_tags = ""
+hotlist_add_conditions = "${away} || ${buffer.num_displayed} == 0"
+hotlist_buffer_separator = ", "
+hotlist_count_max = 2
+hotlist_count_min_msg = 2
+hotlist_names_count = 3
+hotlist_names_length = 0
+hotlist_names_level = 12
+hotlist_names_merged_buffers = off
+hotlist_prefix = "H: "
+hotlist_remove = merged
+hotlist_short_names = on
+hotlist_sort = group_time_asc
+hotlist_suffix = ""
+hotlist_unique_numbers = on
+input_cursor_scroll = 20
+input_share = none
+input_share_overwrite = off
+input_undo_max = 32
+item_away_message = on
+item_buffer_filter = "*"
+item_buffer_zoom = "!"
+item_mouse_status = "M"
+item_time_format = "%H:%M"
+jump_current_to_previous_buffer = on
+jump_previous_buffer_when_closing = on
+jump_smart_back_to_buffer = on
+key_bind_safe = on
+key_grab_delay = 800
+mouse = on
+mouse_timer_delay = 100
+nick_color_force = ""
+nick_color_hash = djb2
+nick_color_stop_chars = "_|["
+nick_prefix = ""
+nick_suffix = ">"
+paste_auto_add_newline = on
+paste_bracketed = on
+paste_bracketed_timer_delay = 10
+paste_max_lines = 1
+prefix_action = "⚡"
+prefix_align = none
+prefix_align_max = 0
+prefix_align_min = 0
+prefix_align_more = "+"
+prefix_align_more_after = on
+prefix_buffer_align = right
+prefix_buffer_align_max = 0
+prefix_buffer_align_more = "+"
+prefix_buffer_align_more_after = on
+prefix_error = "⚠"
+prefix_join = "-->"
+prefix_network = "ℹ "
+prefix_quit = "<--"
+prefix_same_nick = "⤷"
+prefix_suffix = "|"
+quote_nick_prefix = "<"
+quote_nick_suffix = ">"
+quote_time_format = "%H:%M:%S"
+read_marker = line
+read_marker_always_show = off
+read_marker_string = "- "
+save_config_on_exit = on
+save_config_with_fsync = off
+save_layout_on_exit = none
+scroll_amount = 3
+scroll_bottom_after_switch = off
+scroll_page_percent = 100
+search_text_not_found_alert = on
+separator_horizontal = "-"
+separator_vertical = ""
+tab_width = 1
+time_format = "%a, %d %b %Y %T"
+window_auto_zoom = off
+window_separator_horizontal = on
+window_separator_vertical = on
+window_title = "WeeChat ${info:version}"
+word_chars_highlight = "!\u00A0,-,_,|,alnum"
+word_chars_input = "!\u00A0,-,_,|,alnum"
+
+[palette]
+
+[color]
+bar_more = lightmagenta
+chat = default
+chat_bg = default
+chat_buffer = white
+chat_channel = white
+chat_day_change = cyan
+chat_delimiters = green
+chat_highlight = 7
+chat_highlight_bg = magenta
+chat_host = cyan
+chat_inactive_buffer = default
+chat_inactive_window = default
+chat_nick = lightcyan
+chat_nick_colors = "1,2,3,4,5,6"
+chat_nick_offline = default
+chat_nick_offline_highlight = default
+chat_nick_offline_highlight_bg = blue
+chat_nick_other = cyan
+chat_nick_prefix = green
+chat_nick_self = white
+chat_nick_suffix = green
+chat_prefix_action = white
+chat_prefix_buffer = brown
+chat_prefix_buffer_inactive_buffer = default
+chat_prefix_error = yellow
+chat_prefix_join = lightgreen
+chat_prefix_more = lightmagenta
+chat_prefix_network = magenta
+chat_prefix_quit = lightred
+chat_prefix_suffix = green
+chat_read_marker = magenta
+chat_read_marker_bg = default
+chat_server = brown
+chat_tags = red
+chat_text_found = yellow
+chat_text_found_bg = lightmagenta
+chat_time = default
+chat_time_delimiters = brown
+chat_value = cyan
+chat_value_null = blue
+emphasized = yellow
+emphasized_bg = magenta
+input_actions = lightgreen
+input_text_not_found = red
+item_away = yellow
+nicklist_away = cyan
+nicklist_group = green
+separator = blue
+status_count_highlight = magenta
+status_count_msg = brown
+status_count_other = default
+status_count_private = green
+status_data_highlight = lightmagenta
+status_data_msg = yellow
+status_data_other = default
+status_data_private = lightgreen
+status_filter = green
+status_more = yellow
+status_mouse = green
+status_name = white
+status_name_ssl = lightgreen
+status_nicklist_count = default
+status_number = yellow
+status_time = default
+
+[completion]
+base_word_until_cursor = on
+command_inline = on
+default_template = "%(nicks)|%(irc_channels)"
+nick_add_space = on
+nick_case_sensitive = off
+nick_completer = ":"
+nick_first_only = off
+nick_ignore_chars = "[]`_-^"
+partial_completion_alert = on
+partial_completion_command = off
+partial_completion_command_arg = off
+partial_completion_count = on
+partial_completion_other = off
+
+[history]
+display_default = 5
+max_buffer_lines_minutes = 0
+max_buffer_lines_number = 4096
+max_commands = 100
+max_visited_buffers = 50
+
+[proxy]
+
+[network]
+connection_timeout = 60
+gnutls_ca_file = "/etc/ssl/certs/ca-certificates.crt"
+gnutls_handshake_timeout = 30
+proxy_curl = ""
+
+[plugin]
+autoload = "*"
+debug = off
+extension = ".so,.dll"
+path = "%h/plugins"
+save_config_on_unload = on
+
+[bar]
+buflist.color_bg = default
+buflist.color_delim = default
+buflist.color_fg = default
+buflist.conditions = ""
+buflist.filling_left_right = vertical
+buflist.filling_top_bottom = columns_vertical
+buflist.hidden = off
+buflist.items = "buflist"
+buflist.position = left
+buflist.priority = 0
+buflist.separator = on
+buflist.size = 0
+buflist.size_max = 0
+buflist.type = root
+fset.color_bg = default
+fset.color_delim = cyan
+fset.color_fg = default
+fset.conditions = "${buffer.full_name} == fset.fset"
+fset.filling_left_right = vertical
+fset.filling_top_bottom = horizontal
+fset.hidden = off
+fset.items = "fset"
+fset.position = top
+fset.priority = 0
+fset.separator = on
+fset.size = 3
+fset.size_max = 3
+fset.type = window
+input.color_bg = default
+input.color_delim = cyan
+input.color_fg = default
+input.conditions = ""
+input.filling_left_right = vertical
+input.filling_top_bottom = horizontal
+input.hidden = off
+input.items = "[input_prompt]+(away),[input_search],[input_paste],input_text,aspell_suggest"
+input.position = bottom
+input.priority = 1000
+input.separator = off
+input.size = 1
+input.size_max = 0
+input.type = window
+nicklist.color_bg = default
+nicklist.color_delim = cyan
+nicklist.color_fg = default
+nicklist.conditions = "${nicklist}"
+nicklist.filling_left_right = vertical
+nicklist.filling_top_bottom = columns_vertical
+nicklist.hidden = off
+nicklist.items = "buffer_nicklist"
+nicklist.position = right
+nicklist.priority = 200
+nicklist.separator = on
+nicklist.size = 0
+nicklist.size_max = 0
+nicklist.type = window
+status.color_bg = 0
+status.color_delim = cyan
+status.color_fg = default
+status.conditions = ""
+status.filling_left_right = vertical
+status.filling_top_bottom = horizontal
+status.hidden = off
+status.items = "buffer_number+:+buffer_name+(buffer_modes)+{buffer_nicklist_count}+[lag]+[aspell_dict]+scroll+[hotlist]"
+status.position = bottom
+status.priority = 500
+status.separator = off
+status.size = 1
+status.size_max = 0
+status.type = window
+title.color_bg = 0
+title.color_delim = cyan
+title.color_fg = default
+title.conditions = ""
+title.filling_left_right = vertical
+title.filling_top_bottom = horizontal
+title.hidden = off
+title.items = "buffer_title"
+title.position = top
+title.priority = 500
+title.separator = off
+title.size = 1
+title.size_max = 0
+title.type = window
+
+[layout]
+
+[notify]
+
+[filter]
+
+[key]
+ctrl-? = "/input delete_previous_char"
+ctrl-A = "/input move_beginning_of_line"
+ctrl-B = "/input move_previous_char"
+ctrl-C_ = "/input insert \x1F"
+ctrl-Cb = "/input insert \x02"
+ctrl-Cc = "/input insert \x03"
+ctrl-Ci = "/input insert \x1D"
+ctrl-Co = "/input insert \x0F"
+ctrl-Cv = "/input insert \x16"
+ctrl-D = "/input delete_next_char"
+ctrl-E = "/input move_end_of_line"
+ctrl-F = "/input move_next_char"
+ctrl-H = "/input delete_previous_char"
+ctrl-I = "/input complete_next"
+ctrl-J = "/input return"
+ctrl-K = "/input delete_end_of_line"
+ctrl-L = "/window refresh"
+ctrl-M = "/input return"
+ctrl-N = "/buffer +1"
+ctrl-P = "/buffer -1"
+ctrl-R = "/input search_text_here"
+ctrl-Sctrl-U = "/input set_unread"
+ctrl-T = "/input transpose_chars"
+ctrl-U = "/input delete_beginning_of_line"
+ctrl-W = "/input delete_previous_word"
+ctrl-X = "/input switch_active_buffer"
+ctrl-Y = "/input clipboard_paste"
+meta-meta-OP = "/bar scroll buflist * b"
+meta-meta-OQ = "/bar scroll buflist * e"
+meta-meta2-1~ = "/window scroll_top"
+meta-meta2-23~ = "/bar scroll nicklist * b"
+meta-meta2-24~ = "/bar scroll nicklist * e"
+meta-meta2-4~ = "/window scroll_bottom"
+meta-meta2-5~ = "/window scroll_up"
+meta-meta2-6~ = "/window scroll_down"
+meta-meta2-7~ = "/window scroll_top"
+meta-meta2-8~ = "/window scroll_bottom"
+meta-meta2-A = "/buffer -1"
+meta-meta2-B = "/buffer +1"
+meta-meta2-C = "/buffer +1"
+meta-meta2-D = "/buffer -1"
+meta-- = "/filter toggle @"
+meta-/ = "/input jump_last_buffer_displayed"
+meta-0 = "/buffer *10"
+meta-1 = "/buffer *1"
+meta-2 = "/buffer *2"
+meta-3 = "/buffer *3"
+meta-4 = "/buffer *4"
+meta-5 = "/buffer *5"
+meta-6 = "/buffer *6"
+meta-7 = "/buffer *7"
+meta-8 = "/buffer *8"
+meta-9 = "/buffer *9"
+meta-< = "/input jump_previously_visited_buffer"
+meta-= = "/filter toggle"
+meta-> = "/input jump_next_visited_buffer"
+meta-OA = "/input history_global_previous"
+meta-OB = "/input history_global_next"
+meta-OC = "/input move_next_word"
+meta-OD = "/input move_previous_word"
+meta-OF = "/input move_end_of_line"
+meta-OH = "/input move_beginning_of_line"
+meta-OP = "/bar scroll buflist * -100%"
+meta-OQ = "/bar scroll buflist * +100%"
+meta-Oa = "/input history_global_previous"
+meta-Ob = "/input history_global_next"
+meta-Oc = "/input move_next_word"
+meta-Od = "/input move_previous_word"
+meta2-15~ = "/buffer -1"
+meta2-17~ = "/buffer +1"
+meta2-18~ = "/window -1"
+meta2-19~ = "/window +1"
+meta2-1;3A = "/buffer -1"
+meta2-1;3B = "/buffer +1"
+meta2-1;3C = "/buffer +1"
+meta2-1;3D = "/buffer -1"
+meta2-1;3F = "/window scroll_bottom"
+meta2-1;3H = "/window scroll_top"
+meta2-1;5A = "/input history_global_previous"
+meta2-1;5B = "/input history_global_next"
+meta2-1;5C = "/input move_next_word"
+meta2-1;5D = "/input move_previous_word"
+meta2-1~ = "/input move_beginning_of_line"
+meta2-200~ = "/input paste_start"
+meta2-201~ = "/input paste_stop"
+meta2-20~ = "/bar scroll title * -30%"
+meta2-21~ = "/bar scroll title * +30%"
+meta2-23;3~ = "/bar scroll nicklist * b"
+meta2-23~ = "/bar scroll nicklist * -100%"
+meta2-24;3~ = "/bar scroll nicklist * e"
+meta2-24~ = "/bar scroll nicklist * +100%"
+meta2-3~ = "/input delete_next_char"
+meta2-4~ = "/input move_end_of_line"
+meta2-5;3~ = "/window scroll_up"
+meta2-5~ = "/window page_up"
+meta2-6;3~ = "/window scroll_down"
+meta2-6~ = "/window page_down"
+meta2-7~ = "/input move_beginning_of_line"
+meta2-8~ = "/input move_end_of_line"
+meta2-A = "/input history_previous"
+meta2-B = "/input history_next"
+meta2-C = "/input move_next_char"
+meta2-D = "/input move_previous_char"
+meta2-F = "/input move_end_of_line"
+meta2-G = "/window page_down"
+meta2-H = "/input move_beginning_of_line"
+meta2-I = "/window page_up"
+meta2-Z = "/input complete_previous"
+meta2-[E = "/buffer -1"
+meta-_ = "/input redo"
+meta-a = "/input jump_smart"
+meta-b = "/window bare"
+meta-d = "/input delete_next_word"
+meta-f = "/input move_next_word"
+meta-g = "/go"
+meta-h = "/input hotlist_clear"
+meta-jmeta-f = "/buffer -"
+meta-jmeta-l = "/buffer +"
+meta-jmeta-r = "/server raw"
+meta-jmeta-s = "/server jump"
+meta-j01 = "/buffer *1"
+meta-j02 = "/buffer *2"
+meta-j03 = "/buffer *3"
+meta-j04 = "/buffer *4"
+meta-j05 = "/buffer *5"
+meta-j06 = "/buffer *6"
+meta-j07 = "/buffer *7"
+meta-j08 = "/buffer *8"
+meta-j09 = "/buffer *9"
+meta-j10 = "/buffer *10"
+meta-j11 = "/buffer *11"
+meta-j12 = "/buffer *12"
+meta-j13 = "/buffer *13"
+meta-j14 = "/buffer *14"
+meta-j15 = "/buffer *15"
+meta-j16 = "/buffer *16"
+meta-j17 = "/buffer *17"
+meta-j18 = "/buffer *18"
+meta-j19 = "/buffer *19"
+meta-j20 = "/buffer *20"
+meta-j21 = "/buffer *21"
+meta-j22 = "/buffer *22"
+meta-j23 = "/buffer *23"
+meta-j24 = "/buffer *24"
+meta-j25 = "/buffer *25"
+meta-j26 = "/buffer *26"
+meta-j27 = "/buffer *27"
+meta-j28 = "/buffer *28"
+meta-j29 = "/buffer *29"
+meta-j30 = "/buffer *30"
+meta-j31 = "/buffer *31"
+meta-j32 = "/buffer *32"
+meta-j33 = "/buffer *33"
+meta-j34 = "/buffer *34"
+meta-j35 = "/buffer *35"
+meta-j36 = "/buffer *36"
+meta-j37 = "/buffer *37"
+meta-j38 = "/buffer *38"
+meta-j39 = "/buffer *39"
+meta-j40 = "/buffer *40"
+meta-j41 = "/buffer *41"
+meta-j42 = "/buffer *42"
+meta-j43 = "/buffer *43"
+meta-j44 = "/buffer *44"
+meta-j45 = "/buffer *45"
+meta-j46 = "/buffer *46"
+meta-j47 = "/buffer *47"
+meta-j48 = "/buffer *48"
+meta-j49 = "/buffer *49"
+meta-j50 = "/buffer *50"
+meta-j51 = "/buffer *51"
+meta-j52 = "/buffer *52"
+meta-j53 = "/buffer *53"
+meta-j54 = "/buffer *54"
+meta-j55 = "/buffer *55"
+meta-j56 = "/buffer *56"
+meta-j57 = "/buffer *57"
+meta-j58 = "/buffer *58"
+meta-j59 = "/buffer *59"
+meta-j60 = "/buffer *60"
+meta-j61 = "/buffer *61"
+meta-j62 = "/buffer *62"
+meta-j63 = "/buffer *63"
+meta-j64 = "/buffer *64"
+meta-j65 = "/buffer *65"
+meta-j66 = "/buffer *66"
+meta-j67 = "/buffer *67"
+meta-j68 = "/buffer *68"
+meta-j69 = "/buffer *69"
+meta-j70 = "/buffer *70"
+meta-j71 = "/buffer *71"
+meta-j72 = "/buffer *72"
+meta-j73 = "/buffer *73"
+meta-j74 = "/buffer *74"
+meta-j75 = "/buffer *75"
+meta-j76 = "/buffer *76"
+meta-j77 = "/buffer *77"
+meta-j78 = "/buffer *78"
+meta-j79 = "/buffer *79"
+meta-j80 = "/buffer *80"
+meta-j81 = "/buffer *81"
+meta-j82 = "/buffer *82"
+meta-j83 = "/buffer *83"
+meta-j84 = "/buffer *84"
+meta-j85 = "/buffer *85"
+meta-j86 = "/buffer *86"
+meta-j87 = "/buffer *87"
+meta-j88 = "/buffer *88"
+meta-j89 = "/buffer *89"
+meta-j90 = "/buffer *90"
+meta-j91 = "/buffer *91"
+meta-j92 = "/buffer *92"
+meta-j93 = "/buffer *93"
+meta-j94 = "/buffer *94"
+meta-j95 = "/buffer *95"
+meta-j96 = "/buffer *96"
+meta-j97 = "/buffer *97"
+meta-j98 = "/buffer *98"
+meta-j99 = "/buffer *99"
+meta-k = "/input grab_key_command"
+meta-m = "/mute mouse toggle"
+meta-n = "/window scroll_next_highlight"
+meta-p = "/window scroll_previous_highlight"
+meta-r = "/input delete_line"
+meta-s = "/mute aspell toggle"
+meta-u = "/window scroll_unread"
+meta-wmeta-meta2-A = "/window up"
+meta-wmeta-meta2-B = "/window down"
+meta-wmeta-meta2-C = "/window right"
+meta-wmeta-meta2-D = "/window left"
+meta-wmeta2-1;3A = "/window up"
+meta-wmeta2-1;3B = "/window down"
+meta-wmeta2-1;3C = "/window right"
+meta-wmeta2-1;3D = "/window left"
+meta-wmeta-b = "/window balance"
+meta-wmeta-s = "/window swap"
+meta-x = "/input zoom_merged_buffer"
+meta-z = "/window zoom"
+ctrl-_ = "/input undo"
+
+[key_search]
+ctrl-I = "/input search_switch_where"
+ctrl-J = "/input search_stop_here"
+ctrl-M = "/input search_stop_here"
+ctrl-Q = "/input search_stop"
+ctrl-R = "/input search_switch_regex"
+meta2-A = "/input search_previous"
+meta2-B = "/input search_next"
+meta-c = "/input search_switch_case"
+
+[key_cursor]
+ctrl-J = "/cursor stop"
+ctrl-M = "/cursor stop"
+meta-meta2-A = "/cursor move area_up"
+meta-meta2-B = "/cursor move area_down"
+meta-meta2-C = "/cursor move area_right"
+meta-meta2-D = "/cursor move area_left"
+meta2-1;3A = "/cursor move area_up"
+meta2-1;3B = "/cursor move area_down"
+meta2-1;3C = "/cursor move area_right"
+meta2-1;3D = "/cursor move area_left"
+meta2-A = "/cursor move up"
+meta2-B = "/cursor move down"
+meta2-C = "/cursor move right"
+meta2-D = "/cursor move left"
+@item(buffer_nicklist):K = "/window ${_window_number};/kickban ${nick}"
+@item(buffer_nicklist):b = "/window ${_window_number};/ban ${nick}"
+@item(buffer_nicklist):k = "/window ${_window_number};/kick ${nick}"
+@item(buffer_nicklist):q = "/window ${_window_number};/query ${nick};/cursor stop"
+@item(buffer_nicklist):w = "/window ${_window_number};/whois ${nick}"
+@chat:Q = "hsignal:chat_quote_time_prefix_message;/cursor stop"
+@chat:m = "hsignal:chat_quote_message;/cursor stop"
+@chat:q = "hsignal:chat_quote_prefix_message;/cursor stop"
+
+[key_mouse]
+@bar(buflist):ctrl-wheeldown = "hsignal:buflist_mouse"
+@bar(buflist):ctrl-wheelup = "hsignal:buflist_mouse"
+@bar(input):button2 = "/input grab_mouse_area"
+@bar(nicklist):button1-gesture-down = "/bar scroll nicklist ${_window_number} +100%"
+@bar(nicklist):button1-gesture-down-long = "/bar scroll nicklist ${_window_number} e"
+@bar(nicklist):button1-gesture-up = "/bar scroll nicklist ${_window_number} -100%"
+@bar(nicklist):button1-gesture-up-long = "/bar scroll nicklist ${_window_number} b"
+@chat(fset.fset):button1 = "/window ${_window_number};/fset -go ${_chat_line_y}"
+@chat(fset.fset):button2* = "hsignal:fset_mouse"
+@chat(fset.fset):wheeldown = "/fset -down 5"
+@chat(fset.fset):wheelup = "/fset -up 5"
+@chat(script.scripts):button1 = "/window ${_window_number};/script go ${_chat_line_y}"
+@chat(script.scripts):button2 = "/window ${_window_number};/script go ${_chat_line_y};/script installremove -q ${script_name_with_extension}"
+@chat(script.scripts):wheeldown = "/script down 5"
+@chat(script.scripts):wheelup = "/script up 5"
+@item(buffer_nicklist):button1 = "/window ${_window_number};/query ${nick}"
+@item(buffer_nicklist):button1-gesture-left = "/window ${_window_number};/kick ${nick}"
+@item(buffer_nicklist):button1-gesture-left-long = "/window ${_window_number};/kickban ${nick}"
+@item(buffer_nicklist):button2 = "/window ${_window_number};/whois ${nick}"
+@item(buffer_nicklist):button2-gesture-left = "/window ${_window_number};/ban ${nick}"
+@item(buflist):button1* = "hsignal:buflist_mouse"
+@item(buflist):button2* = "hsignal:buflist_mouse"
+@item(buflist2):button1* = "hsignal:buflist_mouse"
+@item(buflist2):button2* = "hsignal:buflist_mouse"
+@item(buflist3):button1* = "hsignal:buflist_mouse"
+@item(buflist3):button2* = "hsignal:buflist_mouse"
+@bar:wheeldown = "/bar scroll ${_bar_name} ${_window_number} +20%"
+@bar:wheelup = "/bar scroll ${_bar_name} ${_window_number} -20%"
+@chat:button1 = "/window ${_window_number}"
+@chat:button1-gesture-left = "/window ${_window_number};/buffer -1"
+@chat:button1-gesture-left-long = "/window ${_window_number};/buffer 1"
+@chat:button1-gesture-right = "/window ${_window_number};/buffer +1"
+@chat:button1-gesture-right-long = "/window ${_window_number};/input jump_last_buffer"
+@chat:ctrl-wheeldown = "/window scroll_horiz -window ${_window_number} +10%"
+@chat:ctrl-wheelup = "/window scroll_horiz -window ${_window_number} -10%"
+@chat:wheeldown = "/window scroll_down -window ${_window_number}"
+@chat:wheelup = "/window scroll_up -window ${_window_number}"
+@*:button3 = "/cursor go ${_x},${_y}"
diff --git a/.weechat/xfer.conf b/.weechat/xfer.conf
@@ -0,0 +1,46 @@
+#
+# weechat -- xfer.conf
+#
+# WARNING: It is NOT recommended to edit this file by hand,
+# especially if WeeChat is running.
+#
+# Use /set or similar command to change settings in WeeChat.
+#
+# For more info, see: https://weechat.org/doc/quickstart
+#
+
+[look]
+auto_open_buffer = on
+progress_bar_size = 20
+pv_tags = "notify_private"
+
+[color]
+status_aborted = lightred
+status_active = lightblue
+status_connecting = yellow
+status_done = lightgreen
+status_failed = lightred
+status_waiting = lightcyan
+text = default
+text_bg = default
+text_selected = white
+
+[network]
+blocksize = 65536
+fast_send = on
+own_ip = ""
+port_range = ""
+speed_limit = 0
+timeout = 300
+
+[file]
+auto_accept_chats = off
+auto_accept_files = off
+auto_accept_nicks = ""
+auto_check_crc32 = off
+auto_rename = on
+auto_resume = on
+convert_spaces = on
+download_path = "%h/xfer"
+upload_path = "~"
+use_nick_in_filename = on