]> 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:

Merge branch 'windowlist-filter' into int
[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         => 'http://bc-bd.org/blog/irssi/'
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                 my $filter_level = Irssi::settings_get_int('chanact_filter');
261                 if ($match_windowlist) {
262                         # window matches windowlist so use
263                         # chanact_filter_windowlist_level to override
264                         # chanact_filter
265                         $filter_level = Irssi::settings_get_int('chanact_filter_windowlist_level');
266                 }
267                 # skip windows with data of level lower than the applicable
268                 # filter setting
269                 next if ($win->{data_level} < $filter_level);
270
271                 # (status) is an awfull long name, so make it short to 'S'
272                 # some people don't like it, so make it configurable
273                 if (Irssi::settings_get_bool('chanact_chop_status')
274                         && $name eq "(status)") {
275                         $name = "S";
276                 }
277
278                 # check if we should show the mode
279                 $mode = "";
280                 if ($type eq "CHANNEL") {
281                         my $server = $win->{active_server};
282                         !ref($server) && next;
283
284                         my $channel = $server->channel_find($name);
285                         !ref($channel) && next;
286
287                         my $nick = $channel->nick_find($server->{nick});
288                         !ref($nick) && next;
289
290                         if ($nick->{op}) {
291                                 $mode = "@";
292                         } elsif ($nick->{voice}) {
293                                 $mode = "+";
294                         } elsif ($nick->{halfop}) {
295                                 $mode = "%";
296                         }
297                 }
298
299                 # in case we have a specific hilightcolor use it
300                 if ($win->{hilight_color}) {
301                         $hilight = "{sb_act_hilight_color $win->{hilight_color} ";
302                 } else {
303                         $hilight = $show{$win->{data_level}};
304                 }
305
306                 if ($remove_prefix) {
307                         $name =~ s/^([&#+!=]?)$remove_prefix/$1/;
308                 }
309                 if ($abbrev) {
310                         if ($name =~ /^[&#+!=]/) {
311                                 $name = substr($name, 1, $abbrev + 1);
312                         } else {
313                                 $name = substr($name, 0, $abbrev);
314                         }
315                 }
316                 if ($remove_hash) {
317                         $name =~ s/^[&#+!=]//;
318                 }
319
320                 if (Irssi::settings_get_bool('chanact_show_alias') == 1 &&
321                                 $win->{name} =~ /^([a-zA-Z+]):(.+)$/) {
322                         $number = "$1";
323                         $display = Irssi::settings_get_str('chanact_display_alias');
324                 } else {
325                         $number = $win->{refnum};
326                         $display = Irssi::settings_get_str('chanact_display');
327                 }
328
329                 $actString .= expand($display,"C",$name,"N",$number,"M",$mode,"H",$hilight,"S","}{sb_background}").$separator;
330         }
331
332         # assemble the final string
333         if ($actString ne "") {
334                 # Remove the last separator
335                 $actString =~ s/$separator$//;
336
337                 if (Irssi::settings_get_int('chanact_filter')) {
338                         $actString = "{sb ".Irssi::settings_get_str('chanact_header').$actString."}";
339                 } else {
340                         $actString = "{sb ".$actString."}";
341                 }
342         }
343
344         # no remake needed any longer
345         $needRemake = 0;
346 }
347
348 # method called because of some events. here we dont remake the item but just
349 # remember that we have to remake it the next time we are called
350 sub chanactHasChanged()
351 {
352         # if needRemake is already set, no need to trigger a redraw as we will
353         # be redrawing the item anyway.
354         return if $needRemake;
355
356         $needRemake = 1;
357
358         Irssi::statusbar_items_redraw('chanact');
359 }
360
361 # function by veli@piipiip.net
362 # Remove alias
363 sub cmd_window_unalias {
364         my ($data, $server, $witem) = @_;
365         my $rn_start = Irssi::settings_get_int('chanact_renumber_start');
366
367         unless ($data =~ /^[a-zA-Z]$/ ||
368                         Irssi::active_win()->{name} =~ /^[a-zA-Z]$/) {
369                 Irssi::print("Usage: /window_unalias <char>");
370                 Irssi::print("or /window_alias in window that has an alias.");
371                 return;
372         }
373
374         if ($data eq '') { $data = Irssi::active_win()->{name}; }
375
376         if (my $oldwin = Irssi::window_find_name($data)) {
377                 $oldwin->set_name(undef);
378                 Irssi::print("Removed alias with the key '$data'.");
379
380                 if (Irssi::settings_get_bool('chanact_autorenumber') == 1 &&
381                                 $oldwin->{refnum} >= $rn_start) {
382                         my $old_refnum = $oldwin->{refnum};
383
384                         # Find the first available slot and move the window
385                         my $newnum = 1;
386                         while (Irssi::window_find_refnum($newnum) ne "") { $newnum++; }
387                         $oldwin->set_refnum($newnum);
388
389                         Irssi::print("and moved it to from $old_refnum to $newnum");
390                 }
391         }
392 }
393
394 # function by veli@piipiip.net
395 # Make an alias
396 sub cmd_window_alias {
397         my ($data, $server, $witem) = @_;
398         my $rn_start = Irssi::settings_get_int('chanact_renumber_start');
399
400         unless ($data =~ /^[a-zA-Z+]$/) {
401                 Irssi::print("Usage: /window_alias <char>");
402                 return;
403         }
404
405         cmd_window_unalias($data, $server, $witem);
406
407         my $window = $witem->window();
408         my $winnum = $window->{refnum};
409
410         if (Irssi::settings_get_bool('chanact_autorenumber') == 1 &&
411                         $window->{refnum} < $rn_start) {
412                 my $old_refnum = $window->{refnum};
413
414                 $winnum = $rn_start;
415
416                 # Find the first available slot and move the window
417                 while (Irssi::window_find_refnum($winnum) ne "") { $winnum++; }
418                 $window->set_refnum($winnum);
419
420                 Irssi::print("Moved the window from $old_refnum to $winnum");
421         }
422
423         my $winname = $witem->{name};
424         my $winserver = $window->{active_server}->{tag};
425         my $winhandle = "$winserver/$winname";
426         $window->set_name("$data:$winhandle");
427         $server->command("/bind meta-$data change_window $data:$winhandle");
428         Irssi::print("Window $winhandle is now accessible with meta-$data");
429 }
430
431 # function by veli@piipiip.net
432 # Makes the aliases if names have already been set
433 sub cmd_rebuild_aliases {
434         foreach (sort { $a->{refnum} <=> $b->{refnum} } Irssi::windows) {
435                 if ($_->{name} =~ /^[a-zA-Z]$/) {
436                         cmd_window_alias($_->{name}, $_->{active_server}, $_->{active});
437                 }
438         }
439 }
440
441 # function by veli@piipiip.net
442 # Change the binding if the window refnum changes.
443 sub refnum_changed {
444         my ($window, $oldref) = @_;
445         my $server = Irssi::active_server();
446
447         if ($window->{name} =~ /^[a-zA-Z]$/) {
448                 $server->command("/bind meta-".$window->{name}." change_window ".$window->{refnum});
449         }
450 }
451
452 $needRemake = 1;
453
454 # Window alias command
455 Irssi::command_bind('window_alias','cmd_window_alias');
456 Irssi::command_bind('window_unalias','cmd_window_unalias');
457 # Irssi::command_bind('window_alias_rebuild','cmd_rebuild_aliases');
458
459 # our config item
460 Irssi::settings_add_str('chanact', 'chanact_display', '$H$N:$M$C$S');
461 Irssi::settings_add_str('chanact', 'chanact_display_alias', '$H$N$M$S');
462 Irssi::settings_add_int('chanact', 'chanact_abbreviate_names', 0);
463 Irssi::settings_add_bool('chanact', 'chanact_show_alias', 1);
464 Irssi::settings_add_str('chanact', 'chanact_separator', " ");
465 Irssi::settings_add_bool('chanact', 'chanact_autorenumber', 0);
466 Irssi::settings_add_bool('chanact', 'chanact_remove_hash', 0);
467 Irssi::settings_add_str('chanact', 'chanact_remove_prefix', "");
468 Irssi::settings_add_int('chanact', 'chanact_renumber_start', 50);
469 Irssi::settings_add_str('chanact', 'chanact_header', "Act: ");
470 Irssi::settings_add_bool('chanact', 'chanact_chop_status', 1);
471 Irssi::settings_add_bool('chanact', 'chanact_sort_by_activity', 1);
472 Irssi::settings_add_int('chanact', 'chanact_filter', 0);
473 Irssi::settings_add_str('chanact', 'chanact_filter_windowlist', "");
474 Irssi::settings_add_int('chanact', 'chanact_filter_windowlist_level',
475         Irssi::settings_get_int('chanact_filter') < 4 ? 4 : 2);
476
477 # register the statusbar item
478 Irssi::statusbar_item_register('chanact', '$0', 'chanact');
479 # according to cras we shall not call this
480 # Irssi::statusbars_recreate_items();
481
482 # register all that nifty callbacks on special events
483 Irssi::signal_add_last('setup changed', 'chanactHasChanged');
484 Irssi::signal_add_last('window changed', 'chanactHasChanged');
485 Irssi::signal_add_last('window item changed', 'chanactHasChanged');
486 Irssi::signal_add_last('window hilight', 'chanactHasChanged');
487 Irssi::signal_add_last('window item hilight', 'chanactHasChanged');
488 Irssi::signal_add("window created", "chanactHasChanged");
489 Irssi::signal_add("window destroyed", "chanactHasChanged");
490 Irssi::signal_add("window name changed", "chanactHasChanged");
491 Irssi::signal_add("window activity", "chanactHasChanged");
492 Irssi::signal_add("print text", "chanactHasChanged");
493 Irssi::signal_add('nick mode changed', 'chanactHasChanged');
494
495 Irssi::signal_add_last('window refnum changed', 'refnum_changed');
496
497 ###############
498 ###
499 #
500 # Changelog
501 #
502 # 0.5.11
503 #       - added chanact_filter_windowlist, which is a space-separated list of
504 #         windows for which to use chanact_filter_windowlist_level instead of
505 #         chanact_filter. You can use @QUERIES to match all queries
506 #         (madduck@madduck.net).
507 #
508 # 0.5.10
509 #       - fixed irssi crash when using Irssi::print from within remake()
510 #       - added option to filter out some data levels, based on a patch by
511 #         Juergen Jung <juergen@Winterkaelte.de>, see
512 #         https://bc-bd.org/trac/irssi/ticket/15
513 #               + retired chanact_show_all in favour of chanact_filter
514 #
515 # 0.5.9
516 #       - changes by stefan voelkel
517 #               + sort channels by activity, see
518 #                 https://bc-bd.org/trac/irssi/ticket/5, based on a patch by jan
519 #                 krueger
520 #               + fixed chrash on /exec -interactive, see
521 #               https://bc-bd.org/trac/irssi/ticket/7
522 #
523 #       - changes by Jan 'jast' Krueger <jast@heapsort.de>, 2004-06-22
524 #               + updated documentation in script's comments
525 #
526 #       - changes by Ivo Timmermans <ivo@o2w.nl>
527 #               + honor actcolor /hilight setting if present
528 #
529 # 0.5.8
530 # - made aliases case-sensitive and include network in channel names by madduck
531 #
532 # 0.5.7
533 # - integrated remove patch by Christoph Berg <myon@debian.org>
534 #
535 # 0.5.6
536 # - fixed a bug (#1) reported by Wouter Coekaert
537 #
538 # 0.5.5
539 # - some speedups from David Leadbeater <dgl@dgl.cx>
540 #
541 #
542 # 0.5.4
543 # - added help for chanact_display_alias
544 #
545 # 0.5.3
546 # - added '+' to the available chars of aliase's
547 # - added chanact_display_alias to allow different display modes if the window
548 #   has an alias
549 #
550 # 0.5.2
551 # - removed unused chanact_show_name settings (thx to Qerub)
552 # - fixed $mode display
553 # - guarded reference operations to (hopefully) fix errors on server disconnect
554 #
555 # 0.5.1
556 # - small typo fixed
557 #
558 # 0.5.0
559 # - changed chanact_show_mode to chanact_display. reversed changes from
560 #   Qerub through that, but kept funcionality.
561 # - removed chanact_color_all since it is no longer needed
562 #
563 # 0.4.3
564 # - changes by Qerub
565 #   + added chanact_show_mode to show the mode just before the channel name
566 #   + added chanact_chop_status to be able to control the (status) chopping
567 #     [bd] minor implementation changes
568 # - moved Changelog to the end of the file since it is getting pretty big
569 #
570 # 0.4.2
571 # - changed back to old version numbering sheme
572 # - added '=' to Qrczak's chanact_abbreviate_names stuff :)
573 # - added chanact_header
574 #
575 # 0.41q
576 #       - changes by Qrczak
577 #               + added setting 'chanact_abbreviate_names'
578 #               + windows are sorted by refnum; I didn't understand the old
579 #                 logic and it broke sorting for numbers above 9
580 #
581 # 0.41
582 #       - minor updates
583 #               + fixed channel sort [veli]
584 #               + removed few typos and added some documentation [veli]
585 #
586 # 0.4
587 #       - merge with window_alias.pl
588 #               + added /window_alias from window_alias.pl by veli@piipiip.net
589 #               + added setting 'chanact_show_alias'
590 #               + added setting 'chanact_show_names'
591 #               + changed setting 'chanact_show_mode' to int
592 #               + added setting 'chanact_separator' [veli]
593 #               + added setting 'chanact_autorenumber' [veli]
594 #               + added setting 'chanact_renumber_start' [veli]
595 #               + added /window_unalias [veli]
596 #               + moved setting to their own group 'chanact' [veli]
597 #
598 # 0.3
599 #       - merge with chanlist.pl
600 #               + added setting 'chanact_show_mode'
601 #               + added setting 'chanact_show_all'
602 #
603 # 0.2
604 #       - added 'Act' to the item
605 #               - added setting 'chanact_color_all'
606 #               - finally found format for statusbar hilight
607 #
608 # 0.1
609 #       - Initial Release
610 #
611 ###
612 ################
613 #
614 # vim:noet