summaryrefslogtreecommitdiffstats
path: root/scripts/chansort_configurable.pl
blob: c02c53b18d5b3e0a84e5135aef1a97dff03c2497 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
use strict;
use warnings;
use Irssi;
use File::Spec::Functions qw(catdir catfile);

our $VERSION = '1.1';
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). E.g. creating the file 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 {
#         # Provide a default sorter with some sane defaults
#         exists($a->{chatnet}) <=> exists($b->{chatnet})
#         ||
#         # "CHANNEL" will sort before "QUERY"
#         $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:
#
#    sub {
#        # This sorts the status window before anything else
#        exists($a->{chatnet}) <=> exists($b->{chatnet})
#        ||
#        # "CHANNEL" will sort before "QUERY"
#        $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
#        )
#    };
#
# 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.

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};

        push @windows => {
            # Extract these to the top-level for easy extraction
            refnum       => $window->{refnum},
            (exists $active->{server}
             # This is for everything except the (status) window
             ? (
                 name    => $active->{name},
                 type    => $active->{type},
                 chatnet => $active->{server}->{chatnet},
             )
             : ()),
            # 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 {
        (
            $sort_callback
            ? ($sort_callback->())
            : (
                # Provide a default sorter with some sane defaults
                exists($a->{chatnet}) <=> exists($b->{chatnet})
                ||
                # "CHANNEL" will sort before "QUERY"
                $a->{type} cmp $b->{type}
                ||
                # Cluster chatnets alphabetically
                $a->{chatnet} cmp $b->{chatnet}
                ||
                # Put & channels like &bitlbee before normal channels
                ($b->{name} =~ /^&/) <=> ($a->{name} =~ /^&/)
                ||
                # Default to sorting alphabetically
                $a->{name} cmp $b->{name}
            )
        )
    } @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');