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

allow per-window level specifications
[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 #                               Alternatively, an entry can be postfixed with
169 #                               a colon (':') and the level to use for that
170 #                               window.
171 #                               The special string @QUERIES matches all queries.
172 #
173 # /set chanact_filter_windowlist_level <int>
174 #   like chanact_filter for windows in chanact_filter_windowlist, which do not
175 #   have a specific value. Defaults to chanact_filter<4 ? 4 : 2, making
176 #   chanact_filter_windowlist a list of windows never to show if
177 #   chanact_filter<4, and a list of windows to show when there is reasonable
178 #   activity if all channels would be hidden.
179 #
180 #########
181 # HINTS
182 #########
183 #
184 # If you have trouble with wrong colored entries your 'default.theme' might
185 # be too old. Try on a shell:
186 #
187 #       $ mv ~/.irssi/default.theme /tmp/
188 #
189 # And in irssi:
190 #       /reload
191 #       /save
192 #
193 ###
194 #################
195
196 my %show = (
197         0 => "{%n ",                    # NOTHING
198         1 => "{sb_act_text ",           # TEXT
199         2 => "{sb_act_msg ",            # MSG
200         3 => "{sb_act_hilight ",        # HILIGHT
201 );
202
203 my ($actString,$needRemake);
204
205 sub expand {
206   my ($string, %format) = @_;
207   my ($exp, $repl);
208   $string =~ s/\$$exp/$repl/g while (($exp, $repl) = each(%format));
209   return $string;
210 }
211
212 # method will get called every time the statusbar item will be displayed
213 # but we dont need to recreate the item every time so we first
214 # check if something has changed and only then we recreate the string
215 # this might just save some cycles
216 # FIXME implement $get_size_only check, and user $item->{min|max-size}
217 sub chanact {
218         my ($item, $get_size_only) = @_;
219
220         if ($needRemake) {
221                 remake();
222         }
223         
224         $item->default_handler($get_size_only, $actString, undef, 1);
225 }
226
227 sub get_filterlevel {
228         my $windows = shift;
229         my $kwregexp = '(?:' . join('|', map quotemeta, @_) . ')';
230         my $defaultlevel = Irssi::settings_get_int('chanact_filter_windowlist_level');
231         foreach my $win (@$windows) {
232                 return ($1 ? $1 : $defaultlevel) if $win =~ /^$kwregexp(?:\:(\d+))?$/;
233         }
234         return undef;
235 }
236
237 use Data::Dumper;
238
239 # this is the real creation method
240 sub remake() {
241         my ($afternumber,$finish,$hilight,$mode,$number,$display,@windows);
242         my $separator = Irssi::settings_get_str('chanact_separator'); 
243         my $abbrev = Irssi::settings_get_int('chanact_abbreviate_names');
244         my $remove_prefix = Irssi::settings_get_str('chanact_remove_prefix');
245         my $remove_hash = Irssi::settings_get_bool('chanact_remove_hash');
246         my @windowlist = split ' ', Irssi::settings_get_str('chanact_filter_windowlist');
247
248         if (Irssi::settings_get_bool('chanact_sort_by_activity')) {
249                 @windows = sort { ($b->{last_line} <=> $a->{last_line}) }
250                         Irssi::windows;
251         } else {
252                 @windows = sort { ($a->{refnum}) <=> ($b->{refnum}) }
253                         Irssi::windows;
254         }
255
256         $actString = "";
257         foreach my $win (@windows) {
258         
259                 # since irssi is single threaded this shouldn't happen
260                 !ref($win) && next;
261
262                 my $active = $win->{active};
263                 !ref($active) && next;
264
265                 my $name = $win->get_active_name;
266                 my $type = $active->{type};
267
268                 ## determine the filter_level to use to determine whether the
269                 ## activity on the current window is worth the bother
270                 #
271                 my @matchlist; push @matchlist, $name;
272                 # if this is a query, also try to match @QUERIES
273                 push @matchlist, '@QUERIES' if ($type eq 'QUERY');
274                 # get_filterlevel matches all items in @matchlist against the
275                 # @windowlist and returns the applicable filterlevel
276                 my $filter_level = get_filterlevel(\@windowlist, @matchlist);
277                 # if we don't have a match (undef), then use the
278                 # chanact_filter value
279                 $filter_level = Irssi::settings_get_int('chanact_filter') unless $filter_level;
280
281                 # now, skip windows with data of level lower than the
282                 # filter level
283                 next if ($win->{data_level} < $filter_level);
284
285                 # alright, the activity is important, let's show the window
286                 my $level = $win->{data_level};
287
288                 # (status) is an awfull long name, so make it short to 'S'
289                 # some people don't like it, so make it configurable
290                 if (Irssi::settings_get_bool('chanact_chop_status')
291                     && $name eq "(status)") {
292                         $name = "S";
293                 }
294         
295                 # check if we should show the mode
296                 $mode = "";
297                 if ($type eq "CHANNEL") {
298                         my $server = $win->{active_server};
299                         !ref($server) && next;
300
301                         my $channel = $server->channel_find($name);
302                         !ref($channel) && next;
303
304                         my $nick = $channel->nick_find($server->{nick});
305                         !ref($nick) && next;
306                         
307                         if ($nick->{op}) {
308                                 $mode = "@";
309                         } elsif ($nick->{voice}) {
310                                 $mode = "+";
311                         } elsif ($nick->{halfop}) {
312                                 $mode = "%";
313                         }
314                 }
315
316                 # in case we have a specific hilightcolor use it
317                 if ($win->{hilight_color}) {
318                         $hilight = "{sb_act_hilight_color $win->{hilight_color} ";
319                 } else {
320                         $hilight = $show{$win->{data_level}};
321                 }
322
323                 if ($remove_prefix) {
324                         $name =~ s/^([&#+!=]?)$remove_prefix/$1/;
325                 }
326                 if ($abbrev) {
327                         if ($name =~ /^[&#+!=]/) {
328                                 $name = substr($name, 1, $abbrev + 1);
329                         } else {
330                                 $name = substr($name, 0, $abbrev);
331                         }
332                 }
333                 if ($remove_hash) {
334                         $name =~ s/^[&#+!=]//;
335                 }
336
337                 if (Irssi::settings_get_bool('chanact_show_alias') == 1 && 
338                                 $win->{name} =~ /^([a-zA-Z+]):(.+)$/) {
339                         $number = "$1";
340                         $display = Irssi::settings_get_str('chanact_display_alias'); 
341                 } else {
342                         $number = $win->{refnum};
343                         $display = Irssi::settings_get_str('chanact_display'); 
344                 }
345
346                 $actString .= expand($display,"C",$name,"N",$number,"M",$mode,"H",$hilight,"S","}{sb_background}").$separator;
347         }
348
349         # assemble the final string
350         if ($actString ne "") {
351                 # Remove the last separator
352                 $actString =~ s/$separator$//;
353                 
354                 if (Irssi::settings_get_int('chanact_filter')) {
355                         $actString = "{sb ".Irssi::settings_get_str('chanact_header').$actString."}";
356                 } else {
357                         $actString = "{sb ".$actString."}";
358                 }
359         }
360
361         # no remake needed any longer
362         $needRemake = 0;
363 }
364
365 # method called because of some events. here we dont remake the item but just
366 # remember that we have to remake it the next time we are called
367 sub chanactHasChanged()
368 {
369         # if needRemake is already set, no need to trigger a redraw as we will
370         # be redrawing the item anyway.
371         return if $needRemake;
372
373         $needRemake = 1;
374
375         Irssi::statusbar_items_redraw('chanact');
376 }
377
378 # function by veli@piipiip.net
379 # Remove alias
380 sub cmd_window_unalias {
381         my ($data, $server, $witem) = @_;
382         my $rn_start = Irssi::settings_get_int('chanact_renumber_start');
383         
384         unless ($data =~ /^[a-zA-Z]$/ || 
385                         Irssi::active_win()->{name} =~ /^[a-zA-Z]$/) {
386                 Irssi::print("Usage: /window_unalias <char>");
387                 Irssi::print("or /window_alias in window that has an alias.");
388                 return;
389         }
390         
391         if ($data eq '') { $data = Irssi::active_win()->{name}; }
392
393         if (my $oldwin = Irssi::window_find_name($data)) {
394                 $oldwin->set_name(undef);
395                 Irssi::print("Removed alias with the key '$data'.");
396                 
397                 if (Irssi::settings_get_bool('chanact_autorenumber') == 1 && 
398                                 $oldwin->{refnum} >= $rn_start) {
399                         my $old_refnum = $oldwin->{refnum};
400                         
401                         # Find the first available slot and move the window
402                         my $newnum = 1;
403                         while (Irssi::window_find_refnum($newnum) ne "") { $newnum++; }
404                         $oldwin->set_refnum($newnum);
405                         
406                         Irssi::print("and moved it to from $old_refnum to $newnum");
407                 }
408         }
409 }
410
411 # function by veli@piipiip.net
412 # Make an alias
413 sub cmd_window_alias {
414         my ($data, $server, $witem) = @_;
415         my $rn_start = Irssi::settings_get_int('chanact_renumber_start');
416
417         unless ($data =~ /^[a-zA-Z+]$/) {
418                 Irssi::print("Usage: /window_alias <char>");
419                 return;
420         }
421
422         cmd_window_unalias($data, $server, $witem);
423         
424         my $window = $witem->window();
425         my $winnum = $window->{refnum};
426         
427         if (Irssi::settings_get_bool('chanact_autorenumber') == 1 &&
428                         $window->{refnum} < $rn_start) {
429                 my $old_refnum = $window->{refnum};
430
431                 $winnum = $rn_start;
432  
433                 # Find the first available slot and move the window
434                 while (Irssi::window_find_refnum($winnum) ne "") { $winnum++; }
435                 $window->set_refnum($winnum);
436                 
437                 Irssi::print("Moved the window from $old_refnum to $winnum");
438         }
439         
440         my $winname = $witem->{name};
441         my $winserver = $window->{active_server}->{tag};
442         my $winhandle = "$winserver/$winname";
443         $window->set_name("$data:$winhandle");
444         $server->command("/bind meta-$data change_window $data:$winhandle");
445         Irssi::print("Window $winhandle is now accessible with meta-$data");
446 }
447
448 # function by veli@piipiip.net
449 # Makes the aliases if names have already been set
450 sub cmd_rebuild_aliases {
451         foreach (sort { $a->{refnum} <=> $b->{refnum} } Irssi::windows) {
452                 if ($_->{name} =~ /^[a-zA-Z]$/) {
453                         cmd_window_alias($_->{name}, $_->{active_server}, $_->{active});
454                 }
455         }
456 }
457
458 # function by veli@piipiip.net
459 # Change the binding if the window refnum changes.
460 sub refnum_changed {
461         my ($window, $oldref) = @_;
462         my $server = Irssi::active_server();
463
464         if ($window->{name} =~ /^[a-zA-Z]$/) {
465                 $server->command("/bind meta-".$window->{name}." change_window ".$window->{refnum});
466         }
467 }
468
469 $needRemake = 1;
470
471 # Window alias command
472 Irssi::command_bind('window_alias','cmd_window_alias');
473 Irssi::command_bind('window_unalias','cmd_window_unalias');
474 # Irssi::command_bind('window_alias_rebuild','cmd_rebuild_aliases');
475
476 # our config item
477 Irssi::settings_add_str('chanact', 'chanact_display', '$H$N:$M$C$S');
478 Irssi::settings_add_str('chanact', 'chanact_display_alias', '$H$N$M$S');
479 Irssi::settings_add_int('chanact', 'chanact_abbreviate_names', 0);
480 Irssi::settings_add_bool('chanact', 'chanact_show_alias', 1);
481 Irssi::settings_add_str('chanact', 'chanact_separator', " ");
482 Irssi::settings_add_bool('chanact', 'chanact_autorenumber', 0);
483 Irssi::settings_add_bool('chanact', 'chanact_remove_hash', 0);
484 Irssi::settings_add_str('chanact', 'chanact_remove_prefix', "");
485 Irssi::settings_add_int('chanact', 'chanact_renumber_start', 50);
486 Irssi::settings_add_str('chanact', 'chanact_header', "Act: ");
487 Irssi::settings_add_bool('chanact', 'chanact_chop_status', 1);
488 Irssi::settings_add_bool('chanact', 'chanact_sort_by_activity', 1);
489 Irssi::settings_add_int('chanact', 'chanact_filter', 0);
490 Irssi::settings_add_str('chanact', 'chanact_filter_windowlist', "");
491 Irssi::settings_add_int('chanact', 'chanact_filter_windowlist_level',
492         Irssi::settings_get_int('chanact_filter') < 4 ? 4 : 2);
493
494 # register the statusbar item
495 Irssi::statusbar_item_register('chanact', '$0', 'chanact');
496 # according to cras we shall not call this
497 # Irssi::statusbars_recreate_items();
498
499 # register all that nifty callbacks on special events
500 Irssi::signal_add_last('setup changed', 'chanactHasChanged');
501 Irssi::signal_add_last('window changed', 'chanactHasChanged');
502 Irssi::signal_add_last('window item changed', 'chanactHasChanged');
503 Irssi::signal_add_last('window hilight', 'chanactHasChanged');
504 Irssi::signal_add_last('window item hilight', 'chanactHasChanged');
505 Irssi::signal_add("window created", "chanactHasChanged");
506 Irssi::signal_add("window destroyed", "chanactHasChanged");
507 Irssi::signal_add("window name changed", "chanactHasChanged");
508 Irssi::signal_add("window activity", "chanactHasChanged");
509 Irssi::signal_add("print text", "chanactHasChanged");
510 Irssi::signal_add('nick mode changed', 'chanactHasChanged');
511
512 Irssi::signal_add_last('window refnum changed', 'refnum_changed');
513
514 ###############
515 ###
516 #
517 # Changelog
518 #
519 # 0.5.11
520 #       - added chanact_filter_windowlist, which is a space-separated list of
521 #         windows for which to use chanact_filter_windowlist_level instead of
522 #         chanact_filter. Each window can also have a specific level
523 #         specified. You can use @QUERIES to match all queries
524 #         (madduck@madduck.net).
525 #
526 # 0.5.10
527 #       - fixed irssi crash when using Irssi::print from within remake()
528 #       - added option to filter out some data levels, based on a patch by
529 #         Juergen Jung <juergen@Winterkaelte.de>, see
530 #         https://bc-bd.org/trac/irssi/ticket/15
531 #               + retired chanact_show_all in favour of chanact_filter
532 #
533 # 0.5.9
534 #       - changes by stefan voelkel
535 #               + sort channels by activity, see
536 #                 https://bc-bd.org/trac/irssi/ticket/5, based on a patch by jan
537 #                 krueger
538 #               + fixed chrash on /exec -interactive, see
539 #               https://bc-bd.org/trac/irssi/ticket/7
540 #
541 #       - changes by Jan 'jast' Krueger <jast@heapsort.de>, 2004-06-22
542 #               + updated documentation in script's comments
543 #
544 #       - changes by Ivo Timmermans <ivo@o2w.nl>
545 #               + honor actcolor /hilight setting if present
546 #
547 # 0.5.8
548 # - made aliases case-sensitive and include network in channel names by madduck
549 #
550 # 0.5.7
551 # - integrated remove patch by Christoph Berg <myon@debian.org>
552 #
553 # 0.5.6
554 # - fixed a bug (#1) reported by Wouter Coekaert
555
556 # 0.5.5
557 # - some speedups from David Leadbeater <dgl@dgl.cx>
558
559 #
560 # 0.5.4
561 # - added help for chanact_display_alias
562 #
563 # 0.5.3
564 # - added '+' to the available chars of aliase's
565 # - added chanact_display_alias to allow different display modes if the window
566 #   has an alias
567 #
568 # 0.5.2
569 # - removed unused chanact_show_name settings (thx to Qerub)
570 # - fixed $mode display
571 # - guarded reference operations to (hopefully) fix errors on server disconnect
572
573 # 0.5.1
574 # - small typo fixed
575 #
576 # 0.5.0
577 # - changed chanact_show_mode to chanact_display. reversed changes from
578 #   Qerub through that, but kept funcionality.
579 # - removed chanact_color_all since it is no longer needed
580
581 # 0.4.3
582 # - changes by Qerub
583 #   + added chanact_show_mode to show the mode just before the channel name
584 #   + added chanact_chop_status to be able to control the (status) chopping
585 #     [bd] minor implementation changes
586 # - moved Changelog to the end of the file since it is getting pretty big
587 #
588 # 0.4.2
589 # - changed back to old version numbering sheme
590 # - added '=' to Qrczak's chanact_abbreviate_names stuff :)
591 # - added chanact_header
592 #
593 # 0.41q
594 #       - changes by Qrczak
595 #               + added setting 'chanact_abbreviate_names'
596 #               + windows are sorted by refnum; I didn't understand the old
597 #                 logic and it broke sorting for numbers above 9
598 #
599 # 0.41
600 #       - minor updates
601 #               + fixed channel sort [veli]
602 #               + removed few typos and added some documentation [veli]
603 #
604 # 0.4
605 #       - merge with window_alias.pl
606 #               + added /window_alias from window_alias.pl by veli@piipiip.net
607 #               + added setting 'chanact_show_alias'
608 #               + added setting 'chanact_show_names'
609 #               + changed setting 'chanact_show_mode' to int
610 #               + added setting 'chanact_separator' [veli]
611 #               + added setting 'chanact_autorenumber' [veli]
612 #               + added setting 'chanact_renumber_start' [veli]
613 #               + added /window_unalias [veli]
614 #               + moved setting to their own group 'chanact' [veli]
615 #
616 # 0.3
617 #       - merge with chanlist.pl
618 #               + added setting 'chanact_show_mode'
619 #               + added setting 'chanact_show_all'
620 #
621 # 0.2
622 #       - added 'Act' to the item
623 #               - added setting 'chanact_color_all'
624 #               - finally found format for statusbar hilight
625 #
626 # 0.1
627 #       - Initial Release
628 #
629 ###
630 ################