comparison irssi/scripts/nm.pl @ 148:4e92ca6c779a

add irssi conf
author zegervdv <zegervdv@me.com>
date Sat, 18 Oct 2014 10:06:58 +0200
parents
children
comparison
equal deleted inserted replaced
147:0d420021bd5d 148:4e92ca6c779a
1 use Irssi;
2 use strict;
3
4 use vars qw($VERSION %IRSSI);
5
6 $VERSION="0.3.10";
7 %IRSSI = (
8 authors=> 'BC-bd',
9 contact=> '[email protected]',
10 name=> 'nm',
11 description=> 'right aligned nicks depending on longest nick',
12 license=> 'GPL v2',
13 url=> 'http://bc-bd.org/blog/irssi/',
14 );
15
16 # $Id: 9cb009e8b7e6f5ce60294334faf88715ef01413e $
17 # nm.pl
18 # for irssi 0.8.4 by [email protected]
19 #
20 # right aligned nicks depending on longest nick
21 #
22 # inspired by neatmsg.pl from kodgehopper <[email protected]
23 # formats taken from www.irssi.de
24 # thanks to adrianel <[email protected]> for some hints
25 # thanks to Eric Wald <[email protected]> for the left alignment patch
26 # inspired by nickcolor.pl by Timo Sirainen and Ian Peters
27 # thanks to And1 <[email protected]> for a small patch
28 # thanks to [email protected] for the save/load patch
29 # thanks to Dennis Heimbert <[email protected]> for a bug report/patch
30 # thanks to Roy Sigurd Karlsbakk <[email protected]> for an autosave patch
31 #
32 #########
33 # USAGE
34 ###
35 #
36 # use
37 #
38 # /neatcolor help
39 #
40 # for help on available commands
41 #
42 #########
43 # OPTIONS
44 #########
45
46 my $help = "
47 /set neat_colorize <ON|OFF>
48 * ON : colorize nicks
49 * OFF : do not colorize nicks
50
51 /set neat_colors <string>
52 Use these colors when colorizing nicks, eg:
53
54 /set neat_colors yYrR
55
56 See the file formats.txt on an explanation of what colors are
57 available.
58
59 /set neat_left_actions <ON|OFF>
60 * ON : print nicks left-aligned on actions
61 * OFF : print nicks right-aligned on actions
62
63 /set neat_left_messages <ON|OFF>
64 * ON : print nicks left-aligned on messages
65 * OFF : print nicks right-aligned on messages
66
67 /set neat_right_mode <ON|OFF>
68 * ON : print the mode of the nick e.g @%+ after the nick
69 * OFF : print it left of the nick
70
71 /set neat_maxlength <number>
72 * number : Maximum length of Nicks to display. Longer nicks are truncated.
73 * 0 : Do not truncate nicks.
74
75 /set neat_melength <number>
76 * number : number of spaces to substract from /me padding
77
78 /set neat_ignorechars <str>
79 * str : regular expression used to filter out unwanted characters in
80 nicks. this can be used to assign the same color for similar
81 nicks, e.g. foo and foo_:
82
83 /set neat_ignorechars [_]
84
85 /set neat_allow_shrinking <ON|OFF>
86 * ON : shrink padding when longest nick disappears
87 * OFF : do not shrink, only allow growing
88
89 /set neat_autosave <number>
90 * number : autosave after <number> seconds, defaults to 60. Set to 0 to
91 disable.
92 ";
93
94 #
95 ###
96 ################
97 ###
98 #
99 # Changelog
100 #
101 # Version 0.3.11
102 # - added autosave, idea from Roy Sigurd Karlsbakk
103 #
104 # Version 0.3.10
105 # - fix losing of saved color when changing nick shares more than one channel
106 # with you
107 #
108 # Version 0.3.9
109 # - fix longest nick calculation for nicks shorter than the current longest
110 # nick
111 # - updated url
112 #
113 # Version 0.3.8
114 # - fixed error in the nickchange tracking code, reported by Kevin Ballard
115 # - added --all switch to reset command
116 # - skip broken lines in saved_colors
117 #
118 # Version 0.3.7
119 # - fixed crash when calling /neatcolor without parameters
120 # - fixed url
121 #
122 # Version 0.3.6
123 # - added option to ignore certain characters from color hash building, see
124 # https://bc-bd.org/trac/irssi/ticket/22
125 # - added option to save and specify colors for nicks, see
126 # https://bc-bd.org/trac/irssi/ticket/23
127 # - added option to disallow shrinking, see
128 # https://bc-bd.org/trac/irssi/ticket/12
129 #
130 # Version 0.3.5
131 # - now also aligning own messages in queries
132 #
133 # Version 0.3.4
134 # - fxed off by one error in nick_to_color, patch by jrib, see
135 # https://bc-bd.org/trac/irssi/ticket/24
136 #
137 # Version 0.3.3
138 # - added support for alignment in queries, see
139 # https://bc-bd.org/trac/irssi/ticket/21
140 #
141 # Version 0.3.2
142 # - integrated left alignment patch from Eric Wald <[email protected]>, see
143 # https://bc-bd.org/trac/irssi/ticket/18
144 #
145 # Version 0.3.1
146 # - /me padding, see https://bc-bd.org/trac/irssi/ticket/17
147 #
148 # Version 0.3.0
149 # - integrate nick coloring support
150 #
151 # Version 0.2.1
152 # - moved neat_maxlength check to reformat() (thx to Jerome De Greef <[email protected]>)
153 #
154 # Version 0.2.0
155 # - by adrianel <[email protected]>
156 # * reformat after setup reload
157 # * maximum length of nicks
158 #
159 # Version 0.1.0
160 # - got lost somewhere
161 #
162 # Version 0.0.2
163 # - ugly typo fixed
164 #
165 # Version 0.0.1
166 # - initial release
167 #
168 ###
169 ################
170 ###
171 #
172 # BUGS
173 #
174 # Empty nicks, eg "<> message"
175 # This seems to be triggered by some themes. As of now there is no known
176 # fix other than changing themes, see
177 # https://bc-bd.org/trac/irssi/ticket/19
178 #
179 # Well, it's a feature: due to the lacking support of extendable themes
180 # from irssi it is not possible to just change some formats per window.
181 # This means that right now all windows are aligned with the same nick
182 # length, which can be somewhat annoying.
183 # If irssi supports extendable themes, I will include per-server indenting
184 # and a setting where you can specify servers you don't want to be indented
185 #
186 ###
187 ################
188
189 my ($longestNick, %saved_colors, @colors, $alignment, $sign, %commands,);
190 my ($pending_save);
191
192 my $colorize = -1;
193
194 sub reformat() {
195 my $max = Irssi::settings_get_int('neat_maxlength');
196 my $actsign = Irssi::settings_get_bool('neat_left_actions')? '': '-';
197 $sign = Irssi::settings_get_bool('neat_left_messages')? '': '-';
198
199 if ($max && $max < $longestNick) {
200 $longestNick = $max;
201 }
202
203 my $me = $longestNick - Irssi::settings_get_int('neat_melength');
204 $me = 0 if ($me < 0);
205
206 Irssi::command('^format own_action {ownaction $['.$actsign.$me.']0} $1');
207 Irssi::command('^format action_public {pubaction $['.$actsign.$me.']0}$1');
208 Irssi::command('^format action_private {pvtaction $['.$actsign.$me.']0}$1');
209 Irssi::command('^format action_private_query {pvtaction_query $['.$actsign.$me.']0} $2');
210
211 my $length = $sign . $longestNick;
212 if (Irssi::settings_get_bool('neat_right_mode') == 0) {
213 Irssi::command('^format own_msg {ownmsgnick $2 {ownnick $['.$length.']0}}$1');
214 Irssi::command('^format own_msg_channel {ownmsgnick $3 {ownnick $['.$length.']0}{msgchannel $1}}$2');
215 Irssi::command('^format pubmsg_me {pubmsgmenick $2 {menick $['.$length.']0}}$1');
216 Irssi::command('^format pubmsg_me_channel {pubmsgmenick $3 {menick $['.$length.']0}{msgchannel $1}}$2');
217 Irssi::command('^format pubmsg_hilight {pubmsghinick $0 $3 $['.$length.']1%n}$2');
218 Irssi::command('^format pubmsg_hilight_channel {pubmsghinick $0 $4 $['.$length.']1{msgchannel $2}}$3');
219 Irssi::command('^format pubmsg {pubmsgnick $2 {pubnick $['.$length.']0}}$1');
220 Irssi::command('^format pubmsg_channel {pubmsgnick $2 {pubnick $['.$length.']0}}$1');
221 } else {
222 Irssi::command('^format own_msg {ownmsgnick {ownnick $['.$length.']0$2}}$1');
223 Irssi::command('^format own_msg_channel {ownmsgnick {ownnick $['.$length.']0$3}{msgchannel $1}}$2');
224 Irssi::command('^format pubmsg_me {pubmsgmenick {menick $['.$length.']0}$2}$1');
225 Irssi::command('^format pubmsg_me_channel {pubmsgmenick {menick $['.$length.']0$3}{msgchannel $1}}$2');
226 Irssi::command('^format pubmsg_hilight {pubmsghinick $0 $0 $['.$length.']1$3%n}$2');
227 Irssi::command('^format pubmsg_hilight_channel {pubmsghinick $0 $['.$length.']1$4{msgchannel $2}}$3');
228 Irssi::command('^format pubmsg {pubmsgnick {pubnick $['.$length.']0$2}}$1');
229 Irssi::command('^format pubmsg_channel {pubmsgnick {pubnick $['.$length.']0$2}}$1');
230 }
231
232 # format queries
233 Irssi::command('^format own_msg_private_query {ownprivmsgnick {ownprivnick $['.$length.']2}}$1');
234 Irssi::command('^format msg_private_query {privmsgnick $['.$length.']0}$2');
235 };
236
237 sub findLongestNick {
238 $longestNick = 0;
239
240 # get own nick length
241 map {
242 my $len = length($_->{nick});
243
244 $longestNick = $len if ($len > $longestNick);
245 } Irssi::servers();
246
247 # find longest other nick
248 foreach (Irssi::channels()) {
249 foreach ($_->nicks()) {
250 my $len = length($_->{nick});
251
252 $longestNick = $len if ($len > $longestNick);
253 }
254 }
255
256 reformat();
257 }
258
259 sub delayed_save
260 {
261 # skip if we have already a save pending. we don't reset the timeout
262 # here, else you could end up with changes never being automatically
263 # saved if they happen more often than <neat_autosave> seconds
264 return if $pending_save;
265
266 return unless Irssi::settings_get_int('neat_autosave');
267
268 Irssi::timeout_add_once(Irssi::settings_get_int('neat_autosave') * 1000,
269 \&save_colors, undef);
270 }
271
272 # a new nick was created
273 sub sig_newNick
274 {
275 my ($channel, $nick) = @_;
276
277 my $len = length($nick->{nick});
278
279 if ($len > $longestNick) {
280 $longestNick = $len;
281 reformat();
282 }
283
284 return if (exists($saved_colors{$nick->{nick}}));
285
286 $saved_colors{$nick->{nick}} = "%".nick_to_color($nick->{nick});
287 delayed_save();
288 }
289
290 # something changed
291 sub sig_changeNick
292 {
293 my ($channel, $nick, $old_nick) = @_;
294
295 # if no saved color exists, we already handled this nickchange. irssi
296 # generates one signal per channel the nick is in, so if you share more
297 # than one channel with this nick, you'd lose the coloring.
298 return unless exists($saved_colors{$old_nick});
299
300 # we need to update the saved colorors hash independent of nick lenght
301 $saved_colors{$nick->{nick}} = $saved_colors{$old_nick};
302 delete $saved_colors{$old_nick};
303 delayed_save();
304
305 my $new = length($nick->{nick});
306
307 # in case the new nick is longer than the old one, simply remember this
308 # as the new longest nick and reformat.
309 #
310 # if the new nick is as long as the known longest nick nothing has to be
311 # done
312 #
313 # if the new nick is shorter than the current longest one and if the
314 # user allows us to shrink, find new longest nick and reformat.
315 if ($new > $longestNick) {
316 $longestNick = $new;
317 } elsif ($new == $longestNick) {
318 return;
319 } else {
320 return unless Irssi::settings_get_bool('neat_allow_shrinking');
321 findLongestNick();
322 }
323
324 reformat();
325 }
326
327 sub sig_removeNick
328 {
329 my ($channel, $nick) = @_;
330
331 my $thisLen = length($nick->{nick});
332
333 # we only need to recalculate if this was the longest nick and we are
334 # allowed to shrink
335 if ($thisLen == $longestNick && Irssi::settings_get_bool('neat_allow_shrinking')) {
336 findLongestNick();
337 reformat();
338 }
339
340 # we do not remove a known color for a gone nick, as they may return
341 }
342
343 # based on simple_hash from nickcolor.pl
344 sub nick_to_color($) {
345 my ($string) = @_;
346 chomp $string;
347
348 my $ignore = Irssi::settings_get_str("neat_ignorechars");
349 $string =~ s/$ignore//g;
350
351 my $counter;
352 foreach my $char (split(//, $string)) {
353 $counter += ord $char;
354 }
355
356 return $colors[$counter % ($#colors + 1)];
357 }
358
359 sub color_left($) {
360 Irssi::command('^format pubmsg {pubmsgnick $2 {pubnick '.$_[0].'$['.$sign.$longestNick.']0}}$1');
361 Irssi::command('^format pubmsg_channel {pubmsgnick $2 {pubnick '.$_[0].'$['.$sign.$longestNick.']0}}$1');
362 }
363
364 sub color_right($) {
365 Irssi::command('^format pubmsg {pubmsgnick {pubnick '.$_[0].'$['.$sign.$longestNick.']0}$2}$1');
366 Irssi::command('^format pubmsg_channel {pubmsgnick {pubnick '.$_[0].'$['.$sign.$longestNick.']0}$2}$1');
367 }
368
369 sub sig_public {
370 my ($server, $msg, $nick, $address, $target) = @_;
371
372 &$alignment($saved_colors{$nick});
373 }
374
375 sub sig_setup {
376 @colors = split(//, Irssi::settings_get_str('neat_colors'));
377
378 # check left or right alignment
379 if (Irssi::settings_get_bool('neat_right_mode') == 0) {
380 $alignment = \&color_left;
381 } else {
382 $alignment = \&color_right;
383 }
384
385 # check if we switched coloring on or off
386 my $new = Irssi::settings_get_bool('neat_colorize');
387 if ($new != $colorize) {
388 if ($new) {
389 Irssi::signal_add('message public', 'sig_public');
390 } else {
391 if ($colorize >= 0) {
392 Irssi::signal_remove('message public', 'sig_public');
393 }
394 }
395 }
396 $colorize = $new;
397
398 reformat();
399 &$alignment('%w');
400 }
401
402 # make sure that every nick has an assigned color
403 sub assert_colors() {
404 foreach (Irssi::channels()) {
405 foreach ($_->nicks()) {
406 next if (exists($saved_colors{$_->{nick}}));
407
408 $saved_colors{$_->{nick}} = "%".nick_to_color($_->{nick});
409 delayed_save();
410 }
411 }
412 }
413
414 # load colors from file
415 sub load_colors() {
416 open(FID, "<".$ENV{HOME}."/.irssi/saved_colors") || return;
417
418 while (<FID>) {
419 chomp;
420 my ($k, $v) = split(/:/);
421
422 # skip broken lines, those may have been introduced by nm.pl
423 # version 0.3.7 and earlier
424 if ($k eq '' || $v eq '') {
425 neat_log(Irssi::active_win(), "Warning, broken line in saved_colors file, skipping '$k:$v'");
426 next;
427 }
428
429 $saved_colors{$k} = $v;
430 }
431
432 close(FID);
433 }
434
435 # save colors to file
436 sub save_colors() {
437 open(FID, ">".$ENV{HOME}."/.irssi/saved_colors");
438
439 print FID $_.":".$saved_colors{$_}."\n" foreach (keys(%saved_colors));
440
441 close(FID);
442
443 # clear possible pending save.
444 Irssi::timeout_remove($pending_save) if $pending_save;
445 $pending_save = undef;
446 }
447
448 # log a line to a window item
449 sub neat_log($@) {
450 my ($witem, @text) = @_;
451
452 $witem->print("nm.pl: ".$_) foreach(@text);
453 }
454
455 # show available colors
456 sub cmd_neatcolor_colors($) {
457 my ($witem, undef, undef) = @_;
458
459 neat_log($witem, "Available colors: ".join("", map { "%".$_.$_ } @colors));
460 }
461
462 # display the configured color for a nick
463 sub cmd_neatcolor_get() {
464 my ($witem, $nick, undef) = @_;
465
466 if (!exists($saved_colors{$nick})) {
467 neat_log($witem, "Error: no such nick '$nick'");
468 return;
469 }
470
471 neat_log($witem, "Color for ".$saved_colors{$nick}.$nick);
472 }
473
474 # display help
475 sub cmd_neatcolor_help() {
476 my ($witem, $cmd, undef) = @_;
477
478 if ($cmd) {
479 if (!exists($commands{$cmd})) {
480 neat_log($witem, "Error: no such command '$cmd'");
481 return;
482 }
483
484 if (!exists($commands{$cmd}{verbose})) {
485 neat_log($witem, "No additional help for '$cmd' available");
486 return;
487 }
488
489 neat_log($witem, ( "", "Help for ".uc($cmd), "" ) );
490 neat_log($witem, @{$commands{$cmd}{verbose}});
491 return;
492 }
493
494 neat_log($witem, split(/\n/, $help));
495 neat_log($witem, "Available options for /neatcolor");
496 neat_log($witem, " ".$_.": ".$commands{$_}{text}) foreach(sort(keys(%commands)));
497
498 my @verbose;
499 foreach (sort(keys(%commands))) {
500 push(@verbose, $_) if exists($commands{$_}{verbose});
501 }
502
503 neat_log($witem, "Verbose help available for: '".join(", ", @verbose)."'");
504 }
505
506 # list configured nicks
507 sub cmd_neatcolor_list() {
508 my ($witem, undef, undef) = @_;
509
510 neat_log($witem, "Configured nicks: ".join(", ", map { $saved_colors{$_}.$_ } sort(keys(%saved_colors))));
511 }
512
513 # reset a nick to its default color
514 sub cmd_neatcolor_reset() {
515 my ($witem, $nick, undef) = @_;
516
517 if ($nick eq '--all') {
518 %saved_colors = ();
519 assert_colors();
520 neat_log($witem, "Reset all colors");
521 return;
522 }
523
524 if (!exists($saved_colors{$nick})) {
525 neat_log($witem, "Error: no such nick '$nick'");
526 return;
527 }
528
529 $saved_colors{$nick} = "%".nick_to_color($nick);
530 delayed_save();
531 neat_log($witem, "Reset color for ".$saved_colors{$nick}.$nick);
532 }
533
534 # save configured colors to disk
535 sub cmd_neatcolor_save() {
536 my ($witem, undef, undef) = @_;
537
538 save_colors();
539
540 neat_log($witem, "color information saved");
541 }
542
543 # set a color for a nick
544 sub cmd_neatcolor_set() {
545 my ($witem, $nick, $color) = @_;
546
547 my @found = grep(/$color/, @colors);
548 if ($#found) {
549 neat_log($witem, "Error: trying to set unknown color '%$color$color%n'");
550 cmd_neatcolor_colors($witem);
551 return;
552 }
553
554 if ($witem->{type} ne "CHANNEL" && $witem->{type} ne "QUERY") {
555 neat_log($witem, "Warning: not a Channel/Query, can not check nick!");
556 neat_log($witem, "Remember, nicks are case sensitive to nm.pl");
557 } else {
558 my @nicks = grep(/^$nick$/i, map { $_->{nick} } ($witem->nicks()));
559
560 if ($#nicks < 0) {
561 neat_log($witem, "Warning: could not find nick '$nick' here");
562 } else {
563 if ($nicks[0] ne $nick) {
564 neat_log($witem, "Warning: using '$nicks[0]' instead of '$nick'");
565 $nick = $nicks[0];
566 }
567 }
568 }
569
570 $saved_colors{$nick} = "%".$color;
571 delayed_save();
572 neat_log($witem, "Set color for $saved_colors{$nick}$nick");
573 }
574
575 %commands = (
576 colors => {
577 text => "show available colors",
578 verbose => [
579 "COLORS",
580 "",
581 "displays all available colors",
582 "",
583 "You can restrict/define the list of available colors ".
584 "with the help of the neat_colors setting"
585 ],
586 func => \&cmd_neatcolor_colors,
587 },
588 get => {
589 text => "retrieve color for a nick",
590 verbose => [
591 "GET <nick>",
592 "",
593 "displays color used for <nick>"
594 ],
595 func => \&cmd_neatcolor_get,
596 },
597 help => {
598 text => "print this help message",
599 func => \&cmd_neatcolor_help,
600 },
601 list => {
602 text => "list configured nick/color pairs",
603 func => \&cmd_neatcolor_list,
604 },
605 reset => {
606 text => "reset color to default",
607 verbose => [
608 "RESET --all|<nick>",
609 "",
610 "resets the color used for all nicks or for <nick> to ",
611 "its internal default",
612 ],
613 func => \&cmd_neatcolor_reset,
614 },
615 save => {
616 text => "save color information to disk",
617 verbose => [
618 "SAVE",
619 "",
620 "saves color information to disk, so that it survives ".
621 "an irssi restart.",
622 "",
623 "Color information will be automatically saved on /quit",
624 ],
625 func => \&cmd_neatcolor_save,
626 },
627 set => {
628 text => "set a specific color for a nick",
629 verbose => [
630 "SET <nick> <color>",
631 "",
632 "use <color> for <nick>",
633 "",
634 "This command will perform a couple of sanity checks, ".
635 "when called from a CHANNEL/QUERY window",
636 "",
637 "EXAMPLE:",
638 " /neatcolor set bc-bd r",
639 "",
640 "use /neatcolor COLORS to see available colors"
641 ],
642 func => \&cmd_neatcolor_set,
643 },
644 );
645
646 # the main command callback that gets called for all neatcolor commands
647 sub cmd_neatcolor() {
648 my ($data, $server, $witem) = @_;
649 my ($cmd, $nick, $color) = split (/ /, $data);
650
651 $cmd = lc($cmd);
652
653 # make sure we have a valid witem to print text to
654 $witem = Irssi::active_win() unless ($witem);
655
656 if (!exists($commands{$cmd})) {
657 neat_log($witem, "Error: unknown command '$cmd'");
658 &{$commands{"help"}{"func"}}($witem) if (exists($commands{"help"}));
659 return;
660 }
661
662 &{$commands{$cmd}{"func"}}($witem, $nick, $color);
663 }
664
665 Irssi::settings_add_bool('misc', 'neat_left_messages', 0);
666 Irssi::settings_add_bool('misc', 'neat_left_actions', 0);
667 Irssi::settings_add_bool('misc', 'neat_right_mode', 1);
668 Irssi::settings_add_int('misc', 'neat_maxlength', 0);
669 Irssi::settings_add_int('misc', 'neat_melength', 2);
670 Irssi::settings_add_bool('misc', 'neat_colorize', 1);
671 Irssi::settings_add_str('misc', 'neat_colors', 'rRgGyYbBmMcC');
672 Irssi::settings_add_str('misc', 'neat_ignorechars', '');
673 Irssi::settings_add_bool('misc', 'neat_allow_shrinking', 1);
674 Irssi::settings_add_int('misc', 'neat_autosave', 60);
675
676 Irssi::command_bind('neatcolor', 'cmd_neatcolor');
677
678 Irssi::signal_add('nicklist new', 'sig_newNick');
679 Irssi::signal_add('nicklist changed', 'sig_changeNick');
680 Irssi::signal_add('nicklist remove', 'sig_removeNick');
681
682 Irssi::signal_add('setup changed', 'sig_setup');
683 Irssi::signal_add_last('setup reread', 'sig_setup');
684
685 findLongestNick();
686 sig_setup;
687
688 load_colors();
689 assert_colors();
690
691 # we need to add this signal _after_ the colors have been loaded, to make sure
692 # no race condition exists wrt color saving
693 Irssi::signal_add('gui exit', 'save_colors');