]> git.madduck.net Git - code/irssi/scripts-bc-bd.git/blob - chanact.pl

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

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