From 6353236f1e13aa522325f742d64da5fa7067ec44 Mon Sep 17 00:00:00 2001 From: NeodarZ Date: Tue, 28 Feb 2017 14:12:19 +0100 Subject: Add my fucking weechat theme --- weechat/python/autosort.py | 865 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 865 insertions(+) create mode 100755 weechat/python/autosort.py (limited to 'weechat/python/autosort.py') diff --git a/weechat/python/autosort.py b/weechat/python/autosort.py new file mode 100755 index 0000000..7b53b77 --- /dev/null +++ b/weechat/python/autosort.py @@ -0,0 +1,865 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013-2014 Maarten de Vries +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# +# Autosort automatically keeps your buffers sorted and grouped by server. +# You can define your own sorting rules. See /help autosort for more details. +# +# http://github.com/de-vri.es/weechat-autosort +# + +# +# Changelog: +# 2.6: +# * Ignore case in rules when doing case insensitive sorting. +# 2.5: +# * Fix handling unicode buffer names. +# * Add hint to set irc.look.server_buffer to independent and buffers.look.indenting to on. +# 2.4: +# * Make script python3 compatible. +# 2.3: +# * Fix sorting items without score last (regressed in 2.2). +# 2.2: +# * Add configuration option for signals that trigger a sort. +# * Add command to manually trigger a sort (/autosort sort). +# * Add replacement patterns to apply before sorting. +# 2.1: +# * Fix some minor style issues. +# 2.0: +# * Allow for custom sort rules. +# + + +import weechat +import re +import json + +SCRIPT_NAME = 'autosort' +SCRIPT_AUTHOR = 'Maarten de Vries ' +SCRIPT_VERSION = '2.6' +SCRIPT_LICENSE = 'GPL3' +SCRIPT_DESC = 'Automatically or manually keep your buffers sorted and grouped by server.' + + +config = None +hooks = [] + +class HumanReadableError(Exception): + pass + + +def parse_int(arg, arg_name = 'argument'): + ''' Parse an integer and provide a more human readable error. ''' + arg = arg.strip() + try: + return int(arg) + except ValueError: + raise HumanReadableError('Invalid {0}: expected integer, got "{1}".'.format(arg_name, arg)) + + +class Pattern: + ''' A simple glob-like pattern for matching buffer names. ''' + + def __init__(self, pattern, case_sensitive): + ''' Construct a pattern from a string. ''' + escaped = False + char_class = 0 + chars = '' + regex = '' + for c in pattern: + if escaped and char_class: + escaped = False + chars += re.escape(c) + elif escaped: + escaped = False + regex += re.escape(c) + elif c == '\\': + escaped = True + elif c == '*' and not char_class: + regex += '[^.]*' + elif c == '?' and not char_class: + regex += '[^.]' + elif c == '[' and not char_class: + char_class = 1 + chars = '' + elif c == '^' and char_class and not chars: + chars += '^' + elif c == ']' and char_class and chars not in ('', '^'): + char_class = False + regex += '[' + chars + ']' + elif c == '-' and char_class: + chars += '-' + elif char_class: + chars += re.escape(c) + else: + regex += re.escape(c) + + if char_class: + raise ValueError("unmatched opening '['") + if escaped: + raise ValueError("unexpected trailing '\\'") + + if case_sensitive: + self.regex = re.compile('^' + regex + '$') + else: + self.regex = re.compile('^' + regex + '$', flags = re.IGNORECASE) + self.pattern = pattern + + def match(self, input): + ''' Match the pattern against a string. ''' + return self.regex.match(input) + + +class FriendlyList(object): + ''' A list with human readable errors. ''' + + def __init__(self): + self.__data = [] + + def raw(self): + return self.__data + + def append(self, value): + ''' Add a rule to the list. ''' + self.__data.append(value) + + def insert(self, index, value): + ''' Add a rule to the list. ''' + if not 0 <= index <= len(self): raise HumanReadableError('Index out of range: expected an integer in the range [0, {0}], got {1}.'.format(len(self), index)) + self.__data.insert(index, value) + + def pop(self, index): + ''' Remove a rule from the list and return it. ''' + if not 0 <= index < len(self): raise HumanReadableError('Index out of range: expected an integer in the range [0, {0}), got {1}.'.format(len(self), index)) + return self.__data.pop(index) + + def move(self, index_a, index_b): + ''' Move a rule to a new position in the list. ''' + self.insert(index_b, self.pop(index_a)) + + def swap(self, index_a, index_b): + ''' Swap two elements in the list. ''' + self[index_a], self[index_b] = self[index_b], self[index_a] + + def __len__(self): + return len(self.__data) + + def __getitem__(self, index): + if not 0 <= index < len(self): raise HumanReadableError('Index out of range: expected an integer in the range [0, {0}), got {1}.'.format(len(self), index)) + return self.__data[index] + + def __setitem__(self, index, value): + if not 0 <= index < len(self): raise HumanReadableError('Index out of range: expected an integer in the range [0, {0}), got {1}.'.format(len(self), index)) + self.__data[index] = value + + def __iter__(self): + return iter(self.__data) + + +class RuleList(FriendlyList): + ''' A list of rules to test buffer names against. ''' + rule_regex = re.compile(r'^(.*)=\s*([+-]?[^=]*)$') + + def __init__(self, rules): + ''' Construct a RuleList from a list of rules. ''' + super(RuleList, self).__init__() + for rule in rules: self.append(rule) + + def get_score(self, name): + ''' Get the sort score of a partial name according to a rule list. ''' + for rule in self: + if rule[0].match(name): return rule[1] + return 999999999 + + def encode(self): + ''' Encode the rules for storage. ''' + return json.dumps(list(map(lambda x: (x[0].pattern, x[1]), self))) + + @staticmethod + def decode(blob, case_sensitive): + ''' Parse rules from a string blob. ''' + result = [] + + try: + decoded = json.loads(blob) + except ValueError: + log('Invalid rules: expected JSON encoded list of pairs, got "{0}".'.format(blob)) + return [], 0 + + for rule in decoded: + # Rules must be a pattern,score pair. + if len(rule) != 2: + log('Invalid rule: expected (pattern, score), got "{0}". Rule ignored.'.format(rule)) + continue + + # Rules must have a valid pattern. + try: + pattern = Pattern(rule[0], case_sensitive) + except ValueError as e: + log('Invalid pattern: {0} in "{1}". Rule ignored.'.format(e, rule[0])) + continue + + # Rules must have a valid score. + try: + score = int(rule[1]) + except ValueError as e: + log('Invalid score: expected an integer, got "{0}". Rule ignored.'.format(score)) + continue + + result.append((pattern, score)) + + return RuleList(result) + + @staticmethod + def parse_rule(arg, case_sensitive): + ''' Parse a rule argument. ''' + arg = arg.strip() + match = RuleList.rule_regex.match(arg) + if not match: + raise HumanReadableError('Invalid rule: expected " = ", got "{0}".'.format(arg)) + + pattern = match.group(1).strip() + try: + pattern = Pattern(pattern, case_sensitive) + except ValueError as e: + raise HumanReadableError('Invalid pattern: {0} in "{1}".'.format(e, pattern)) + + score = parse_int(match.group(2), 'score') + return (pattern, score) + + +def decode_replacements(blob): + ''' Decode a replacement list encoded as JSON. ''' + result = FriendlyList() + try: + decoded = json.loads(blob) + except ValueError: + log('Invalid replacement list: expected JSON encoded list of pairs, got "{0}".'.format(blob)) + return [], 0 + + for replacement in decoded: + # Replacements must be a (string, string) pair. + if len(replacement) != 2: + log('Invalid replacement pattern: expected (pattern, replacement), got "{0}". Replacement ignored.'.format(rule)) + continue + result.append(replacement) + + return result + + +def encode_replacements(replacements): + ''' Encode a list of replacement patterns as JSON. ''' + return json.dumps(replacements.raw()) + + +class Config: + ''' The autosort configuration. ''' + + default_rules = json.dumps([ + ('core', 0), + ('irc', 2), + ('*', 1), + + ('irc.irc_raw', 0), + ('irc.server', 1), + ]) + + default_replacements = '[]' + default_signals = 'buffer_opened buffer_merged buffer_unmerged buffer_renamed' + + def __init__(self, filename): + ''' Initialize the configuration. ''' + + self.filename = filename + self.config_file = weechat.config_new(self.filename, '', '') + self.sorting_section = None + + self.case_sensitive = False + self.group_irc = True + self.rules = [] + self.replacements = [] + self.signals = [] + self.sort_on_config = True + + self.__case_sensitive = None + self.__group_irc = None + self.__rules = None + self.__replacements = None + self.__signals = None + self.__sort_on_config = None + + if not self.config_file: + log('Failed to initialize configuration file "{0}".'.format(self.filename)) + return + + self.sorting_section = weechat.config_new_section(self.config_file, 'sorting', False, False, '', '', '', '', '', '', '', '', '', '') + + if not self.sorting_section: + log('Failed to initialize section "sorting" of configuration file.') + weechat.config_free(self.config_file) + return + + self.__case_sensitive = weechat.config_new_option( + self.config_file, self.sorting_section, + 'case_sensitive', 'boolean', + 'If this option is on, sorting is case sensitive.', + '', 0, 0, 'off', 'off', 0, + '', '', '', '', '', '' + ) + + self.__group_irc = weechat.config_new_option( + self.config_file, self.sorting_section, + 'group_irc', 'boolean', + 'If this option is on, the script pretends that IRC channel/private buffers are renamed to "irc.server.{network}.{channel}" rather than "irc.{network}.{channel}".' + + 'This ensures that these buffers are grouped with their respective server buffer.', + '', 0, 0, 'on', 'on', 0, + '', '', '', '', '', '' + ) + + self.__rules = weechat.config_new_option( + self.config_file, self.sorting_section, + 'rules', 'string', + 'An ordered list of sorting rules encoded as JSON. See /help autosort for commands to manipulate these rules.', + '', 0, 0, Config.default_rules, Config.default_rules, 0, + '', '', '', '', '', '' + ) + + self.__replacements = weechat.config_new_option( + self.config_file, self.sorting_section, + 'replacements', 'string', + 'An ordered list of replacement patterns to use on buffer name components, encoded as JSON. See /help autosort for commands to manipulate these replacements.', + '', 0, 0, Config.default_replacements, Config.default_replacements, 0, + '', '', '', '', '', '' + ) + + self.__signals = weechat.config_new_option( + self.config_file, self.sorting_section, + 'signals', 'string', + 'The signals that will cause autosort to resort your buffer list. Seperate signals with spaces.', + '', 0, 0, Config.default_signals, Config.default_signals, 0, + '', '', '', '', '', '' + ) + + self.__sort_on_config = weechat.config_new_option( + self.config_file, self.sorting_section, + 'sort_on_config_change', 'boolean', + 'Decides if the buffer list should be sorted when autosort configuration changes.', + '', 0, 0, 'on', 'on', 0, + '', '', '', '', '', '' + ) + + if weechat.config_read(self.config_file) != weechat.WEECHAT_RC_OK: + log('Failed to load configuration file.') + + if weechat.config_write(self.config_file) != weechat.WEECHAT_RC_OK: + log('Failed to write configuration file.') + + self.reload() + + def reload(self): + ''' Load configuration variables. ''' + + self.case_sensitive = weechat.config_boolean(self.__case_sensitive) + self.group_irc = weechat.config_boolean(self.__group_irc) + + rules_blob = weechat.config_string(self.__rules) + replacements_blob = weechat.config_string(self.__replacements) + signals_blob = weechat.config_string(self.__signals) + + self.rules = RuleList.decode(rules_blob, self.case_sensitive) + self.replacements = decode_replacements(replacements_blob) + self.signals = signals_blob.split() + self.sort_on_config = weechat.config_boolean(self.__sort_on_config) + + def save_rules(self, run_callback = True): + ''' Save the current rules to the configuration. ''' + weechat.config_option_set(self.__rules, RuleList.encode(self.rules), run_callback) + + def save_replacements(self, run_callback = True): + ''' Save the current replacement patterns to the configuration. ''' + weechat.config_option_set(self.__replacements, encode_replacements(self.replacements), run_callback) + + +def pad(sequence, length, padding = None): + ''' Pad a list until is has a certain length. ''' + return sequence + [padding] * max(0, (length - len(sequence))) + + +def log(message, buffer = 'NULL'): + weechat.prnt(buffer, 'autosort: {0}'.format(message)) + + +def get_buffers(): + ''' Get a list of all the buffers in weechat. ''' + buffers = [] + + buffer_list = weechat.infolist_get('buffer', '', '') + + while weechat.infolist_next(buffer_list): + name = weechat.infolist_string (buffer_list, 'full_name') + number = weechat.infolist_integer(buffer_list, 'number') + + # Buffer is merged with one we already have in the list, skip it. + if number <= len(buffers): + continue + buffers.append(name) + + weechat.infolist_free(buffer_list) + return buffers + + +def preprocess(buffer, config): + ''' + Preprocess a buffers names. + ''' + if not config.case_sensitive: + buffer = buffer.lower() + + for replacement in config.replacements: + buffer = buffer.replace(replacement[0], replacement[1]) + + buffer = buffer.split('.') + if config.group_irc and len(buffer) >= 2 and buffer[0] == 'irc' and buffer[1] not in ('server', 'irc_raw'): + buffer.insert(1, 'server') + + return buffer + + +def buffer_sort_key(rules): + ''' Create a sort key function for a buffer list from a rule list. ''' + def key(buffer): + result = [] + name = '' + for word in preprocess(buffer.decode('utf-8'), config): + name += ('.' if name else '') + word + result.append((rules.get_score(name), word)) + return result + + return key + + +def apply_buffer_order(buffers): + ''' Sort the buffers in weechat according to the order in the input list. ''' + for i, buffer in enumerate(buffers): + weechat.command('', '/buffer swap {0} {1}'.format(buffer, 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 command_sort(buffer, command, args): + ''' Sort the buffers and print a confirmation. ''' + on_buffers_changed() + log("Finished sorting buffers.", buffer) + return weechat.WEECHAT_RC_OK + + +def command_rule_list(buffer, command, args): + ''' Show the list of sorting rules. ''' + output = 'Sorting rules:\n' + for i, rule in enumerate(config.rules): + output += ' {0}: {1} = {2}\n'.format(i, rule[0].pattern, rule[1]) + if not len(config.rules): + output += ' No sorting rules configured.\n' + log(output, buffer) + + return weechat.WEECHAT_RC_OK + + +def command_rule_add(buffer, command, args): + ''' Add a rule to the rule list. ''' + rule = RuleList.parse_rule(args, config.case_sensitive) + + config.rules.append(rule) + config.save_rules() + command_rule_list(buffer, command, '') + + return weechat.WEECHAT_RC_OK + + +def command_rule_insert(buffer, command, args): + ''' Insert a rule at the desired position in the rule list. ''' + index, rule = split_args(args, 2) + index = parse_int(index, 'index') + rule = RuleList.parse_rule(rule, config.case_sensitive) + + config.rules.insert(index, rule) + config.save_rules() + command_rule_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_rule_update(buffer, command, args): + ''' Update a rule in the rule list. ''' + index, rule = split_args(args, 2) + index = parse_int(index, 'index') + rule = RuleList.parse_rule(rule, config.case_sensitive) + + config.rules[index] = rule + config.save_rules() + command_rule_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_rule_delete(buffer, command, args): + ''' Delete a rule from the rule list. ''' + index = args.strip() + index = parse_int(index, 'index') + + config.rules.pop(index) + config.save_rules() + command_rule_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_rule_move(buffer, command, args): + ''' Move a rule to a new position. ''' + index_a, index_b = split_args(args, 2) + index_a = parse_int(index_a, 'index') + index_b = parse_int(index_b, 'index') + + config.rules.move(index_a, index_b) + config.save_rules() + command_rule_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_rule_swap(buffer, command, args): + ''' Swap two rules. ''' + index_a, index_b = split_args(args, 2) + index_a = parse_int(index_a, 'index') + index_b = parse_int(index_b, 'index') + + config.rules.swap(index_a, index_b) + config.save_rules() + command_rule_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_replacement_list(buffer, command, args): + ''' Show the list of sorting rules. ''' + output = 'Replacement patterns:\n' + for i, pattern in enumerate(config.replacements): + output += ' {0}: {1} -> {2}\n'.format(i, pattern[0], pattern[1]) + if not len(config.replacements): + output += ' No replacement patterns configured.' + log(output, buffer) + + return weechat.WEECHAT_RC_OK + + +def command_replacement_add(buffer, command, args): + ''' Add a rule to the rule list. ''' + pattern, replacement = split_args(args, 1, 1) + + config.replacements.append((pattern, replacement)) + config.save_replacements() + command_replacement_list(buffer, command, '') + + return weechat.WEECHAT_RC_OK + + +def command_replacement_insert(buffer, command, args): + ''' Insert a rule at the desired position in the rule list. ''' + index, pattern, replacement = split_args(args, 2, 1) + index = parse_int(index, 'index') + + config.replacements.insert(index, (pattern, replacement)) + config.save_replacements() + command_replacement_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_replacement_update(buffer, command, args): + ''' Update a rule in the rule list. ''' + index, pattern, replacement = split_args(args, 2, 1) + index = parse_int(index, 'index') + + config.replacements[index] = (pattern, replacement) + config.save_replacements() + command_replacement_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_replacement_delete(buffer, command, args): + ''' Delete a rule from the rule list. ''' + index = args.strip() + index = parse_int(index, 'index') + + config.replacements.pop(index) + config.save_replacements() + command_replacement_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_replacement_move(buffer, command, args): + ''' Move a rule to a new position. ''' + index_a, index_b = split_args(args, 2) + index_a = parse_int(index_a, 'index') + index_b = parse_int(index_b, 'index') + + config.replacements.move(index_a, index_b) + config.save_replacements() + command_replacement_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_replacement_swap(buffer, command, args): + ''' Swap two rules. ''' + index_a, index_b = split_args(args, 2) + index_a = parse_int(index_a, 'index') + index_b = parse_int(index_b, 'index') + + config.replacements.swap(index_a, index_b) + config.save_replacements() + command_replacement_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + + + +def call_command(buffer, command, args, subcommands): + ''' Call a subccommand from a dictionary. ''' + subcommand, tail = pad(args.split(' ', 1), 2, '') + subcommand = subcommand.strip() + if (subcommand == ''): + child = subcommands.get(' ') + else: + command = command + [subcommand] + child = subcommands.get(subcommand) + + if isinstance(child, dict): + return call_command(buffer, command, tail, child) + elif callable(child): + return child(buffer, command, tail) + + log('{0}: command not found'.format(' '.join(command))) + return weechat.WEECHAT_RC_ERROR + + +def on_buffers_changed(*args, **kwargs): + ''' Called whenever the buffer list changes. ''' + buffers = get_buffers() + buffers.sort(key=buffer_sort_key(config.rules)) + apply_buffer_order(buffers) + return weechat.WEECHAT_RC_OK + + +def on_config_changed(*args, **kwargs): + ''' Called whenever the configuration changes. ''' + config.reload() + + # Unhook all signals and hook the new ones. + for hook in hooks: + weechat.unhook(hook) + for signal in config.signals: + hooks.append(weechat.hook_signal(signal, 'on_buffers_changed', '')) + + if config.sort_on_config: + on_buffers_changed() + + return weechat.WEECHAT_RC_OK + + +def on_autosort_command(data, buffer, args): + ''' Called when the autosort command is invoked. ''' + try: + return call_command(buffer, ['/autosort'], args, { + ' ': command_sort, + 'sort': command_sort, + + 'rules': { + ' ': command_rule_list, + 'list': command_rule_list, + 'add': command_rule_add, + 'insert': command_rule_insert, + 'update': command_rule_update, + 'delete': command_rule_delete, + 'move': command_rule_move, + 'swap': command_rule_swap, + }, + 'replacements': { + ' ': command_replacement_list, + 'list': command_replacement_list, + 'add': command_replacement_add, + 'insert': command_replacement_insert, + 'update': command_replacement_update, + 'delete': command_replacement_delete, + 'move': command_replacement_move, + 'swap': command_replacement_swap, + }, + 'sort': on_buffers_changed, + }) + except HumanReadableError as e: + log(e, buffer) + return weechat.WEECHAT_RC_ERROR + + +command_description = r''' +NOTE: For the best effect, you may want to consider setting the option irc.look.server_buffer to independent and buffers.look.indenting to on. + +# Commands + +## Miscellaneous +/autosort sort +Manually trigger the buffer sorting. + + +## Sorting rules + +/autosort rules list +Print the list of sort rules. + +/autosort rules add = +Add a new rule at the end of the list. + +/autosort rules insert = +Insert a new rule at the given index in the list. + +/autosort rules update = +Update a rule in the list with a new pattern and score. + +/autosort rules delete +Delete a rule from the list. + +/autosort rules move +Move a rule from one position in the list to another. + +/autosort rules swap +Swap two rules in the list + + +## Replacement patterns + +/autosort replacements list +Print the list of replacement patterns. + +/autosort replacements add +Add a new replacement pattern at the end of the list. + +/autosort replacements insert +Insert a new replacement pattern at the given index in the list. + +/autosort replacements update +Update a replacement pattern in the list. + +/autosort replacements delete +Delete a replacement pattern from the list. + +/autosort replacements move +Move a replacement pattern from one position in the list to another. + +/autosort replacements swap +Swap two replacement pattern in the list + + +# Introduction +Autosort is a weechat script to automatically keep your buffers sorted. +The sort order can be customized by defining your own sort rules, +but the default should be sane enough for most people. +It can also group IRC channel/private buffers under their server buffer if you like. + +Autosort first turns buffer names into a list of their components by splitting on them on the period character. +For example, the buffer name "irc.server.freenode" is turned into ['irc', 'server', 'freenode']. +The list of buffers is then lexicographically sorted. + +To facilitate custom sort orders, it is possible to assign a score to each component individually before the sorting is done. +Any name component that did not get a score assigned will be sorted after those that did receive a score. +Components are always sorted on their score first and on their name second. +Lower scores are sorted first. + +## Automatic or manual sorting +By default, autosort will automatically sort your buffer list whenever a buffer is opened, merged, unmerged or renamed. +This should keep your buffers sorted in almost all situations. +However, you may wish to change the list of signals that cause your buffer list to be sorted. +Simply edit the "autosort.sorting.signals" option to add or remove any signal you like. +If you remove all signals you can still sort your buffers manually with the "/autosort sort" command. +To prevent all automatic sorting, "autosort.sorting.sort_on_config_change" should also be set to off. + +## Grouping IRC buffers +In weechat, IRC channel/private buffers are named "irc..<#channel>", +and IRC server buffers are named "irc.server.". +This does not work very well with lexicographical sorting if you want all buffers for one network grouped together. +That is why autosort comes with the "autosort.sorting.group_irc" option, +which secretly pretends IRC channel/private buffers are called "irc.server..<#channel>". +The buffers are not actually renamed, autosort simply pretends they are for sorting purposes. + +## Replacement patterns +Sometimes you may want to ignore some characters for sorting purposes. +On Freenode for example, you may wish to ignore the difference between channels starting with a double or a single hash sign. +To do so, simply add a replacement pattern that replaces ## with # with the following command: +/autosort replacements add ## # + +Replacement patterns do not support wildcards or special characters at the moment. + +## Sort rules +You can assign scores to name components by defining sort rules. +The first rule that matches a component decides the score. +Further rules are not examined. +Sort rules use the following syntax: + = + +You can use the "/autosort rules" command to show and manipulate the list of sort rules. + + +Allowed special characters in the glob patterns are: + +Pattern | Meaning +--------|-------- +* | Matches a sequence of any characters except for periods. +? | Matches a single character, but not a period. +[a-z] | Matches a single character in the given regex-like character class. +[^ab] | A negated regex-like character class. +\* | A backslash escapes the next characters and removes its special meaning. +\\ | A literal backslash. + + +## Example +As an example, consider the following rule list: +0: core = 0 +1: irc = 2 +2: * = 1 + +3: irc.server.*.#* = 1 +4: irc.server.*.* = 0 + +Rule 0 ensures the core buffer is always sorted first. +Rule 1 sorts IRC buffers last and rule 2 puts all remaining buffers in between the two. + +Rule 3 and 4 would make no sense with the group_irc option off. +With the option on though, these rules will sort private buffers before regular channel buffers. +Rule 3 matches channel buffers and assigns them a higher score, +while rule 4 matches the buffers that remain and assigns them a lower score. +The same effect could also be achieved with a single rule: +irc.server.*.[^#]* = 0 +''' + +command_completion = 'sort||rules list|add|insert|update|delete|move|swap||replacements list|add|insert|update|delete|move|swap' + + +if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, "", ""): + config = Config('autosort') + + weechat.hook_config('autosort.*', 'on_config_changed', '') + weechat.hook_command('autosort', command_description, '', '', command_completion, 'on_autosort_command', 'NULL') + on_config_changed() -- cgit v1.2.1