Permalink
Switch branches/tags
Nothing to show
Find file Copy path
41d5525 May 4, 2016
2 contributors

Users who have contributed to this file

@avar @avarbkng
272 lines (256 sloc) 10.3 KB
use strict;
use warnings;
use Irssi;
use File::Spec::Functions qw(catdir catfile);
our $VERSION = '1.2';
our %IRSSI = (
authors => 'Ævar Arnfjörð Bjarmason',
contact => 'avarab@gmail.com',
name => 'chansort_configurable',
description => "Sort channels & query windows in a configurable way, based on Peder Stray's chansort.pl",
license => 'GPL',
url => 'http://scripts.irssi.org & https://github.com/avar/dotfiles/blob/master/.irssi/scripts/chansort_configurable.pl',
);
# HOWTO:
#
# /load chansort_configurable.pl
# /set chansort_configurable_autosort ON
#
# This is a plugin that allows you to sort your windows in any
# arbitrary way using a callback you provide. I originally forked this
# from chansort.pl on https://scripts.irssi.org which is a similar
# plugin that just sorts the windows in a pre-determined order.
#
# By default this plugin will sort things in a pre-determined order,
# but you can create a
# ~/.irssi/scripts/chansort_configurable_callback.pl file with a
# subroutine that we'll call inside sort() (so the $a and $b sort
# variables are available).
#
# The values of $a and $b are going to be hashes like:
#
# {
# refnum => Int, # e.g. 1, 50, ...
# type => Str, # e.g. "SERVER", "CHANNEL"
# chatnet => Str, # e.g. "freenode", "oftc", ...
# name => Str, # e.g. "(status)", "#irssi", "", ...
# window => Object, # The Irssi::Window object
# }
#
# The "window" object contains the refnum/type/chatnet/name data
# somewhere, but we've extracted it for convenience since depending on
# the state & type of the window the values can be anywhere in
# window.active.*, window.active.server.*, window.active_server.* or
# window.*
#
# Note that you can return "0" to just keep the existing order the
# windows are in now. We guarantee that the the sort is stable,
# i.e. if you return 0 from the comparison of $a and $b we'll leave
# the windows in the order they're already in. In other words, the
# window objects passed to your sort() routine will be pre-sorted in
# "refnum" order.
#
# Below we have examples of how you might create the
# ~/.irssi/scripts/chansort_configurable_callback.pl
# file. E.g. creating it as:
#
# use strict;
# use warnings;
#
# sub {
# rand() <=> rand()
# };
#
# Would sort your windows in a random order. This would be somewhat
# more useful:
#
# use strict;
# use warnings;
#
# my $n = -9001;
# my %hardcoded_positioning = (
# freenode => {
# '#irssi' => $n++, # 2
# '#freenode' => $n++, # 3
# },
# );
#
# sub {
# # We sort the "(status) window first before anything else
# ($b->{name} eq "(status)") <=> ($a->{name} eq "(status)")
# ||
# # We want "CHANNEL" at the beginning and "QUERY" at the end
# # regardless of chatnet.
# $a->{type} cmp $b->{type}
# ||
# # Cluster chatnets alphabetically
# $a->{chatnet} cmp $b->{chatnet}
# ||
# # Put & channels like &bitlbee before normal channels
# ($b->{name} =~ /^&/) <=> ($a->{name} =~ /^&/)
# ||
# # Allow for hardcoding the positioning of channels
# # within a network
# ($hardcoded_positioning{$a->{chatnet}}->{$a->{name}} || 0) <=> ($hardcoded_positioning{$b->{chatnet}}->{$b->{name}} || 0)
# ||
# # Default to sorting alphabetically
# $a->{name} cmp $b->{name}
# };
#
# The above sorter will sort channels before queries, and networks
# alphabetically, but will make the #irssi channel be the first
# channel on the freenode network.
#
# I actually prefer to have my CHANNEL windows sorted in a particular
# order, but have the QUERY windows accumulate at the end of the list
# so I can page backwards through the window list through my most
# recent QUERY chats, so this is a modification of the above that does
# that:
#
# use strict;
# use warnings;
#
# # See above for how this might be defined.
# my %hardcoded_positioning;
#
# sub {
# # We sort the "(status) window first before anything else
# ($b->{name} eq "(status)") <=> ($a->{name} eq "(status)")
# ||
# # We want "CHANNEL" at the beginning and "QUERY" at the end
# # regardless of chatnet.
# $a->{type} cmp $b->{type}
# ||
# # For the rest of this I want channels to be ordered by chatnet
# # and have hardcoded positions or an alphabetical sort, but for
# # QUERY I don't want any further sorting, I just want a stable
# # sort, this is so I can page back from the back of the list to
# # find my most recent queries.
# (
# ($a->{type} eq 'CHANNEL' and $b->{type} eq 'CHANNEL')
# ?
# (
# # Cluster chatnets alphabetically
# $a->{chatnet} cmp $b->{chatnet}
# ||
# # Put & channels like &bitlbee before normal channels
# ($b->{name} =~ /^&/) <=> ($a->{name} =~ /^&/)
# ||
# # Allow for hardcoding the positioning of channels
# # within a network
# ($hardcoded_positioning{$a->{chatnet}}->{$a->{name}} || 0) <=> ($hardcoded_positioning{$b->{chatnet}}->{$b->{name}} || 0)
# ||
# # Default to sorting alphabetically
# $a->{name} cmp $b->{name}
# )
# : 0
# )
# };
#
# The last example here is the default sorter you'll get if you don't
# create your own by creating the
# ~/.irssi/scripts/chansort_configurable_callback.pl file. Obviously
# the use of %hardcoded_positioning here is a no-op, but you could
# copy the example to your own file and fill it up to hardcode the
# sorting of certain channels.
my $sort_callback_file = catfile(catdir(Irssi::get_irssi_dir(), 'scripts'), 'chansort_configurable_callback.pl');
my $sort_callback = do $sort_callback_file;
sub cmd_chansort_configurable {
my @windows;
for my $window (Irssi::windows()) {
my $active = $window->{active};
my $active_server = $window->{active_server};
push @windows => {
# We extract some values to the top-level for ease of use,
# i.e. you don't have to go and unpack values from
# window.active.*, window.active.server.*,
# window.active_server.* or window.* which are often
# logically the same sort of thing, e.g. the name of the
# window.
refnum => $window->{refnum},
# We have a window.active for windows that are not
# type=SERVER and *connected* to a server, but if we're
# disconnected or have some otherwise disowned window we
# might also not have window.active, but will have
# window.active_server.
(
type => ($active->{type} || $active_server->{type}),
# Sometimes window.active.server.chatnet won't be
# there, but window.active_server.chatnet is always
# there, and these seem to be a reference to the same
# object.
chatnet => ($active_server->{chatnet}),
# If we have a window.active.name it'll be
# e.g. "#irssi", but otherwise we'll have
# e.g. window.name as "(status)" or just "".
name => ($active->{name} || $window->{name}),
),
# The raw window object with all the details.
window => $window,
};
}
# Because Irssi::windows() doesn't return these in the existing
# order they're in we first have to sort them by their existing
# order to make sure that we have a stable sort.
@windows = sort { $a->{refnum} <=> $b->{refnum} } @windows;
@windows = sort {
# Dummy lexical just so I can copy/paste the default sort
# example here and it'll compile.
my %hardcoded_positioning;
(
$sort_callback
? ($sort_callback->())
: (
# We sort the "(status) window first before anything
# else
($b->{name} eq "(status)") <=> ($a->{name} eq "(status)")
||
# We want "CHANNEL" at the beginning and "QUERY" at
# the end regardless of chatnet.
$a->{type} cmp $b->{type}
||
# For the rest of this I want channels to be ordered
# by chatnet and have hardcoded positions or an
# alphabetical sort, but for QUERY I don't want any
# further sorting, I just want a stable sort, this is
# so I can page back from the back of the list to find
# my most recent queries.
(
($a->{type} eq 'CHANNEL' and $b->{type} eq 'CHANNEL')
?
(
# Cluster chatnets alphabetically
$a->{chatnet} cmp $b->{chatnet}
||
# Put & channels like &bitlbee before normal
# channels
($b->{name} =~ /^&/) <=> ($a->{name} =~ /^&/)
||
# Allow for hardcoding the positioning of
# channels within a network
($hardcoded_positioning{$a->{chatnet}}->{$a->{name}} || 0) <=> ($hardcoded_positioning{$b->{chatnet}}->{$b->{name}} || 0)
||
# Default to sorting alphabetically
$a->{name} cmp $b->{name}
)
: 0
)
)
)
} @windows;
my $i = 0;
for my $window (@windows) {
$i++;
$window->{window}->command("WINDOW MOVE $i");
}
return;
}
sub sig_chansort_configurable_trigger {
return unless Irssi::settings_get_bool('chansort_configurable_autosort');
cmd_chansort_configurable();
}
Irssi::command_bind('chansort_configurable', 'cmd_chansort_configurable');
Irssi::settings_add_bool('chansort_configurable', 'chansort_configurable_autosort', 0);
Irssi::signal_add_last('window item name changed', 'sig_chansort_configurable_trigger');
Irssi::signal_add_last('channel created', 'sig_chansort_configurable_trigger');
Irssi::signal_add_last('query created', 'sig_chansort_configurable_trigger');