-
Notifications
You must be signed in to change notification settings - Fork 234
/
chansort_configurable.pl
271 lines (256 loc) · 10.3 KB
/
chansort_configurable.pl
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
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');