/var/www/www.irssi.org-old/scripts/html/chanact.pl
1 use Irssi 20020101.0001 ();
2 use strict;
3 use Irssi::TextUI;
4
5 use vars qw($VERSION %IRSSI);
6
7 $VERSION = "0.5.10";
8 %IRSSI = (
9 authors => 'BC-bd, Veli',
10 contact => 'bd@bc-bd.org, veli@piipiip.net',
11 name => 'chanact',
12 description => 'Adds new powerful and customizable [Act: ...] item (chanelnames,modes,alias). Lets you give alias characters to windows so that you can select those with meta-<char>',
13 license => 'GNU GPLv2 or later',
14 url => 'https://bc-bd.org/svn/repos/irssi/chanact'
15 );
16
17 # Adds new powerful and customizable [Act: ...] item (chanelnames,modes,alias).
18 # Lets you give alias characters to windows so that you can select those with
19 # meta-<char>.
20 #
21 # for irssi 0.8.2 by bd@bc-bd.org
22 #
23 # inspired by chanlist.pl by 'cumol@hammerhart.de'
24 #
25 #########
26 # Contributors
27 #########
28 #
29 # veli@piipiip.net /window_alias code
30 # qrczak@knm.org.pl chanact_abbreviate_names
31 # qerub@home.se Extra chanact_show_mode and chanact_chop_status
32 # madduck@madduck.net Better channel aliasing (case-sensitive, cross-network)
33 # Jan 'jast' Krueger <jast@heapsort.de>, 2004-06-22
34 # Ivo Timmermans <ivo@o2w.nl> win->{hilight} patch
35 #
36 #########
37 # USAGE
38 ###
39 #
40 # copy the script to ~/.irssi/scripts/
41 #
42 # In irssi:
43 #
44 # /script load chanact
45 # /statusbar window add -after act chanact
46 #
47 # If you want the item to appear on another position read the help
48 # for /statusbar.
49 # To remove the [Act: 1,2,3] item type:
50 #
51 # /statusbar window remove act
52 #
53 # To see all chanact options type:
54 #
55 # / set chanact_
56 #
57 # After these steps you have your new statusbar item and you can start giving
58 # aliases to your windows. Go to the window you want to give the alias to
59 # and say:
60 #
61 # /window_alias <alias char>
62 #
63 # You can also remove the aliases with:
64 #
65 # /window_unalias <alias char>
66 #
67 # or in aliased window:
68 #
69 # /window_unalias
70 #
71 # To see a list of your windows use:
72 #
73 # /window list
74 #
75 #########
76 # OPTIONS
77 #########
78 #
79 # /set chanact_chop_status <ON|OFF>
80 # * ON : shorten (Status) to S
81 # * OFF : don't do it
82 #
83 # /set chanact_show_mode <ON|OFF>
84 # * ON : show channel modes
85 # * OFF : don't show channel modes
86 #
87 # /set chanact_sort_by_activity <ON|OFF>
88 # * ON : sorts the list by last activity
89 # * OFF : sorts the list by window number
90 #
91 # /set chanact_display <string>
92 # * string : Format String for one Channel. The following $'s are expanded:
93 # $C : Channel
94 # $N : Number of the Window
95 # $M : Mode in that channel
96 # $H : Start highlightning
97 # $S : Stop highlightning
98 # * example:
99 #
100 # /set chanact_display $H$N:$M.$S$C
101 #
102 # will give you on #irssi.de if you have voice
103 #
104 # [3:+.#irssi.de]
105 #
106 # with '3:+.' highlighted and the channel name printed in regular color
107 #
108 # /set chanact_display_alias <string>
109 # as 'chanact_display' but is used if the window has an alias and
110 # 'chanact_show_alias' is set to on.
111 #
112 # /set chanact_show_names <ON|OFF>
113 # * ON : show the channelnames after the number/alias
114 # * OFF : don't show the names
115 #
116 # /set chanact_abbreviate_names <int>
117 # * 0 : don't abbreviate
118 # * <int> : strip channel name prefix character and leave only
119 # that many characters of the proper name
120 #
121 # /set chanact_show_alias <ON|OFF>
122 # * ON : show the aliase instead of the refnum
123 # * OFF : shot the refnum
124 #
125 # /set chanact_header <str>
126 # * <str> : Characters to be displayed at the start of the item.
127 # Defaults to: "Act: "
128 #
129 # /set chanact_separator <str>
130 # * <str> : Charater to use between the channel entries
131 #
132 # /set chanact_autorenumber <ON|OFF>
133 # * ON : Move the window automatically to first available slot
134 # starting from "chanact_renumber_start" when assigning
135 # an alias to window. Also moves the window back to a
136 # first available slot from refnum 1 when the window
137 # loses it's alias.
138 # * OFF : Don't move the windows automatically
139 #
140 # /set chanact_renumber_start <int>
141 # * <int> : Move the window to first available slot after this
142 # num when "chanact_autorenumber" is ON.
143 #
144 # /set chanact_remove_hash <ON|OFF>
145 # * ON : Remove &#+!= from channel names
146 # * OFF : Don't touch channel names
147 #
148 # /set chanact_remove_prefix <string>
149 # * <string> : Regular expression used to remove from the
150 # beginning of the channel name.
151 # * example :
152 # To shorten a lot of debian channels:
153 #
154 # /set chanact_remove_prefix deb(ian.(devel-)?)?
155 #
156 # /set chanact_filter <int>
157 # * 0 : show all channels
158 # * 1 : hide channels without activity
159 # * 2 : hide channels with only join/part/etc messages
160 # * 3 : hide channels with text messages
161 # * 4 : hide all channels (now why would you want to do that)
162 #
163 #########
164 # HINTS
165 #########
166 #
167 # If you have trouble with wrong colored entries your 'default.theme' might
168 # be too old. Try on a shell:
169 #
170 # $ mv ~/.irssi/default.theme /tmp/
171 #
172 # And in irssi:
173 # /reload
174 # /save
175 #
176 ###
177 #################
178
179 my %show = (
180 0 => "{%n ", # NOTHING
181 1 => "{sb_act_text ", # TEXT
182 2 => "{sb_act_msg ", # MSG
183 3 => "{sb_act_hilight ", # HILIGHT
184 );
185
186 my ($actString,$needRemake);
187
188 sub expand {
189 my ($string, %format) = @_;
190 my ($exp, $repl);
191 $string =~ s/\$$exp/$repl/g while (($exp, $repl) = each(%format));
192 return $string;
193 }
194
195 # method will get called every time the statusbar item will be displayed
196 # but we dont need to recreate the item every time so we first
197 # check if something has changed and only then we recreate the string
198 # this might just save some cycles
199 # FIXME implement $get_size_only check, and user $item->{min|max-size}
200 sub chanact {
201 my ($item, $get_size_only) = @_;
202
203 if ($needRemake) {
204 remake();
205 }
206
207 $item->default_handler($get_size_only, $actString, undef, 1);
208 }
209
210 # this is the real creation method
211 sub remake() {
212 my ($afternumber,$finish,$hilight,$mode,$number,$display,@windows);
213 my $separator = Irssi::settings_get_str('chanact_separator');
214 my $abbrev = Irssi::settings_get_int('chanact_abbreviate_names');
215 my $remove_prefix = Irssi::settings_get_str('chanact_remove_prefix');
216 my $remove_hash = Irssi::settings_get_bool('chanact_remove_hash');
217
218 if (Irssi::settings_get_bool('chanact_sort_by_activity')) {
219 @windows = sort { ($b->{last_line} <=> $a->{last_line}) }
220 Irssi::windows;
221 } else {
222 @windows = sort { ($a->{refnum}) <=> ($b->{refnum}) }
223 Irssi::windows;
224 }
225
226 $actString = "";
227 foreach my $win (@windows) {
228
229 # since irssi is single threaded this shouldn't happen
230 !ref($win) && next;
231
232 my $active = $win->{active};
233 !ref($active) && next;
234
235 my $name = $win->get_active_name;
236
237 # (status) is an awfull long name, so make it short to 'S'
238 # some people don't like it, so make it configurable
239 if (Irssi::settings_get_bool('chanact_chop_status')
240 && $name eq "(status)") {
241 $name = "S";
242 }
243
244 # check if we should show the mode
245 $mode = "";
246 if ($active->{type} eq "CHANNEL") {
247 my $server = $win->{active_server};
248 !ref($server) && next;
249
250 my $channel = $server->channel_find($name);
251 !ref($channel) && next;
252
253 my $nick = $channel->nick_find($server->{nick});
254 !ref($nick) && next;
255
256 if ($nick->{op}) {
257 $mode = "@";
258 } elsif ($nick->{voice}) {
259 $mode = "+";
260 } elsif ($nick->{halfop}) {
261 $mode = "%";
262 }
263 }
264
265 next if (Irssi::settings_get_int('chanact_filter') > $win->{data_level});
266
267 # in case we have a specific hilightcolor use it
268 if ($win->{hilight_color}) {
269 $hilight = "{sb_act_hilight_color $win->{hilight_color} ";
270 } else {
271 $hilight = $show{$win->{data_level}};
272 }
273
274 if ($remove_prefix) {
275 $name =~ s/^([&#+!=]?)$remove_prefix/$1/;
276 }
277 if ($abbrev) {
278 if ($name =~ /^[&#+!=]/) {
279 $name = substr($name, 1, $abbrev + 1);
280 } else {
281 $name = substr($name, 0, $abbrev);
282 }
283 }
284 if ($remove_hash) {
285 $name =~ s/^[&#+!=]//;
286 }
287
288 if (Irssi::settings_get_bool('chanact_show_alias') == 1 &&
289 $win->{name} =~ /^([a-zA-Z+]):(.+)$/) {
290 $number = "$1";
291 $display = Irssi::settings_get_str('chanact_display_alias');
292 } else {
293 $number = $win->{refnum};
294 $display = Irssi::settings_get_str('chanact_display');
295 }
296
297 $actString .= expand($display,"C",$name,"N",$number,"M",$mode,"H",$hilight,"S","}{sb_background}").$separator;
298 }
299
300 # assemble the final string
301 if ($actString ne "") {
302 # Remove the last separator
303 $actString =~ s/$separator$//;
304
305 if (Irssi::settings_get_int('chanact_filter')) {
306 $actString = "{sb ".Irssi::settings_get_str('chanact_header').$actString."}";
307 } else {
308 $actString = "{sb ".$actString."}";
309 }
310 }
311
312 # no remake needed any longer
313 $needRemake = 0;
314 }
315
316 # method called because of some events. here we dont remake the item but just
317 # remember that we have to remake it the next time we are called
318 sub chanactHasChanged()
319 {
320 # if needRemake is already set, no need to trigger a redraw as we will
321 # be redrawing the item anyway.
322 return if $needRemake;
323
324 $needRemake = 1;
325
326 Irssi::statusbar_items_redraw('chanact');
327 }
328
329 # function by veli@piipiip.net
330 # Remove alias
331 sub cmd_window_unalias {
332 my ($data, $server, $witem) = @_;
333 my $rn_start = Irssi::settings_get_int('chanact_renumber_start');
334
335 unless ($data =~ /^[a-zA-Z]$/ ||
336 Irssi::active_win()->{name} =~ /^[a-zA-Z]$/) {
337 Irssi::print("Usage: /window_unalias <char>");
338 Irssi::print("or /window_alias in window that has an alias.");
339 return;
340 }
341
342 if ($data eq '') { $data = Irssi::active_win()->{name}; }
343
344 if (my $oldwin = Irssi::window_find_name($data)) {
345 $oldwin->set_name(undef);
346 Irssi::print("Removed alias with the key '$data'.");
347
348 if (Irssi::settings_get_bool('chanact_autorenumber') == 1 &&
349 $oldwin->{refnum} >= $rn_start) {
350 my $old_refnum = $oldwin->{refnum};
351
352 # Find the first available slot and move the window
353 my $newnum = 1;
354 while (Irssi::window_find_refnum($newnum) ne "") { $newnum++; }
355 $oldwin->set_refnum($newnum);
356
357 Irssi::print("and moved it to from $old_refnum to $newnum");
358 }
359 }
360 }
361
362 # function by veli@piipiip.net
363 # Make an alias
364 sub cmd_window_alias {
365 my ($data, $server, $witem) = @_;
366 my $rn_start = Irssi::settings_get_int('chanact_renumber_start');
367
368 unless ($data =~ /^[a-zA-Z+]$/) {
369 Irssi::print("Usage: /window_alias <char>");
370 return;
371 }
372
373 cmd_window_unalias($data, $server, $witem);
374
375 my $window = $witem->window();
376 my $winnum = $window->{refnum};
377
378 if (Irssi::settings_get_bool('chanact_autorenumber') == 1 &&
379 $window->{refnum} < $rn_start) {
380 my $old_refnum = $window->{refnum};
381
382 $winnum = $rn_start;
383
384 # Find the first available slot and move the window
385 while (Irssi::window_find_refnum($winnum) ne "") { $winnum++; }
386 $window->set_refnum($winnum);
387
388 Irssi::print("Moved the window from $old_refnum to $winnum");
389 }
390
391 my $winname = $witem->{name};
392 my $winserver = $window->{active_server}->{tag};
393 my $winhandle = "$winserver/$winname";
394 $window->set_name("$data:$winhandle");
395 $server->command("/bind meta-$data change_window $data:$winhandle");
396 Irssi::print("Window $winhandle is now accessible with meta-$data");
397 }
398
399 # function by veli@piipiip.net
400 # Makes the aliases if names have already been set
401 sub cmd_rebuild_aliases {
402 foreach (sort { $a->{refnum} <=> $b->{refnum} } Irssi::windows) {
403 if ($_->{name} =~ /^[a-zA-Z]$/) {
404 cmd_window_alias($_->{name}, $_->{active_server}, $_->{active});
405 }
406 }
407 }
408
409 # function by veli@piipiip.net
410 # Change the binding if the window refnum changes.
411 sub refnum_changed {
412 my ($window, $oldref) = @_;
413 my $server = Irssi::active_server();
414
415 if ($window->{name} =~ /^[a-zA-Z]$/) {
416 $server->command("/bind meta-".$window->{name}." change_window ".$window->{refnum});
417 }
418 }
419
420 $needRemake = 1;
421
422 # Window alias command
423 Irssi::command_bind('window_alias','cmd_window_alias');
424 Irssi::command_bind('window_unalias','cmd_window_unalias');
425 # Irssi::command_bind('window_alias_rebuild','cmd_rebuild_aliases');
426
427 # our config item
428 Irssi::settings_add_str('chanact', 'chanact_display', '$H$N:$M$C$S');
429 Irssi::settings_add_str('chanact', 'chanact_display_alias', '$H$N$M$S');
430 Irssi::settings_add_int('chanact', 'chanact_abbreviate_names', 0);
431 Irssi::settings_add_bool('chanact', 'chanact_show_alias', 1);
432 Irssi::settings_add_str('chanact', 'chanact_separator', " ");
433 Irssi::settings_add_bool('chanact', 'chanact_autorenumber', 0);
434 Irssi::settings_add_bool('chanact', 'chanact_remove_hash', 0);
435 Irssi::settings_add_str('chanact', 'chanact_remove_prefix', "");
436 Irssi::settings_add_int('chanact', 'chanact_renumber_start', 50);
437 Irssi::settings_add_str('chanact', 'chanact_header', "Act: ");
438 Irssi::settings_add_bool('chanact', 'chanact_chop_status', 1);
439 Irssi::settings_add_bool('chanact', 'chanact_sort_by_activity', 1);
440 Irssi::settings_add_int('chanact', 'chanact_filter', 0);
441
442 # register the statusbar item
443 Irssi::statusbar_item_register('chanact', '$0', 'chanact');
444 # according to cras we shall not call this
445 # Irssi::statusbars_recreate_items();
446
447 # register all that nifty callbacks on special events
448 Irssi::signal_add_last('setup changed', 'chanactHasChanged');
449 Irssi::signal_add_last('window changed', 'chanactHasChanged');
450 Irssi::signal_add_last('window item changed', 'chanactHasChanged');
451 Irssi::signal_add_last('window hilight', 'chanactHasChanged');
452 Irssi::signal_add_last('window item hilight', 'chanactHasChanged');
453 Irssi::signal_add("window created", "chanactHasChanged");
454 Irssi::signal_add("window destroyed", "chanactHasChanged");
455 Irssi::signal_add("window name changed", "chanactHasChanged");
456 Irssi::signal_add("window activity", "chanactHasChanged");
457 Irssi::signal_add("print text", "chanactHasChanged");
458 Irssi::signal_add('nick mode changed', 'chanactHasChanged');
459
460 Irssi::signal_add_last('window refnum changed', 'refnum_changed');
461
462 ###############
463 ###
464 #
465 # Changelog
466 #
467 # 0.5.10
468 # - fixed irssi crash when using Irssi::print from within remake()
469 # - added option to filter out some data levels, based on a patch by
470 # Juergen Jung <juergen@Winterkaelte.de>, see
471 # https://bc-bd.org/trac/irssi/ticket/15
472 # + retired chanact_show_all in favour of chanact_filter
473 #
474 # 0.5.9
475 # - changes by stefan voelkel
476 # + sort channels by activity, see
477 # https://bc-bd.org/trac/irssi/ticket/5, based on a patch by jan
478 # krueger
479 # + fixed chrash on /exec -interactive, see
480 # https://bc-bd.org/trac/irssi/ticket/7
481 #
482 # - changes by Jan 'jast' Krueger <jast@heapsort.de>, 2004-06-22
483 # + updated documentation in script's comments
484 #
485 # - changes by Ivo Timmermans <ivo@o2w.nl>
486 # + honor actcolor /hilight setting if present
487 #
488 # 0.5.8
489 # - made aliases case-sensitive and include network in channel names by madduck
490 #
491 # 0.5.7
492 # - integrated remove patch by Christoph Berg <myon@debian.org>
493 #
494 # 0.5.6
495 # - fixed a bug (#1) reported by Wouter Coekaert
496 #
497 # 0.5.5
498 # - some speedups from David Leadbeater <dgl@dgl.cx>
499 #
500 #
501 # 0.5.4
502 # - added help for chanact_display_alias
503 #
504 # 0.5.3
505 # - added '+' to the available chars of aliase's
506 # - added chanact_display_alias to allow different display modes if the window
507 # has an alias
508 #
509 # 0.5.2
510 # - removed unused chanact_show_name settings (thx to Qerub)
511 # - fixed $mode display
512 # - guarded reference operations to (hopefully) fix errors on server disconnect
513 #
514 # 0.5.1
515 # - small typo fixed
516 #
517 # 0.5.0
518 # - changed chanact_show_mode to chanact_display. reversed changes from
519 # Qerub through that, but kept funcionality.
520 # - removed chanact_color_all since it is no longer needed
521 #
522 # 0.4.3
523 # - changes by Qerub
524 # + added chanact_show_mode to show the mode just before the channel name
525 # + added chanact_chop_status to be able to control the (status) chopping
526 # [bd] minor implementation changes
527 # - moved Changelog to the end of the file since it is getting pretty big
528 #
529 # 0.4.2
530 # - changed back to old version numbering sheme
531 # - added '=' to Qrczak's chanact_abbreviate_names stuff :)
532 # - added chanact_header
533 #
534 # 0.41q
535 # - changes by Qrczak
536 # + added setting 'chanact_abbreviate_names'
537 # + windows are sorted by refnum; I didn't understand the old
538 # logic and it broke sorting for numbers above 9
539 #
540 # 0.41
541 # - minor updates
542 # + fixed channel sort [veli]
543 # + removed few typos and added some documentation [veli]
544 #
545 # 0.4
546 # - merge with window_alias.pl
547 # + added /window_alias from window_alias.pl by veli@piipiip.net
548 # + added setting 'chanact_show_alias'
549 # + added setting 'chanact_show_names'
550 # + changed setting 'chanact_show_mode' to int
551 # + added setting 'chanact_separator' [veli]
552 # + added setting 'chanact_autorenumber' [veli]
553 # + added setting 'chanact_renumber_start' [veli]
554 # + added /window_unalias [veli]
555 # + moved setting to their own group 'chanact' [veli]
556 #
557 # 0.3
558 # - merge with chanlist.pl
559 # + added setting 'chanact_show_mode'
560 # + added setting 'chanact_show_all'
561 #
562 # 0.2
563 # - added 'Act' to the item
564 # - added setting 'chanact_color_all'
565 # - finally found format for statusbar hilight
566 #
567 # 0.1
568 # - Initial Release
569 #
570 ###
571 ################