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.
4 use vars qw($VERSION %IRSSI);
9 contact=> 'bd@bc-bd.org',
11 description=> 'right aligned nicks depending on longest nick',
13 url=> 'https://bc-bd.org/svn/repos/irssi/nm',
18 # for irssi 0.8.4 by bd@bc-bd.org
20 # right aligned nicks depending on longest nick
22 # inspired by neatmsg.pl from kodgehopper <kodgehopper@netscape.net
23 # formats taken from www.irssi.de
24 # thanks to adrianel <adrinael@nuclearzone.org> for some hints
25 # thanks to Eric Wald <eswald@gmail.com> for the left alignment patch
26 # inspired by nickcolor.pl by Timo Sirainen and Ian Peters
27 # thanks to And1 <and1@meinungsverstaerker.de> for a small patch
28 # thanks to berber@tzi.de for the save/load patch
38 # for help on available commands
45 /set neat_colorize <ON|OFF>
47 * OFF : do not colorize nicks
49 /set neat_colors <string>
50 Use these colors when colorizing nicks, eg:
54 See the file formats.txt on an explanation of what colors are
57 /set neat_left_actions <ON|OFF>
58 * ON : print nicks left-aligned on actions
59 * OFF : print nicks right-aligned on actions
61 /set neat_left_messages <ON|OFF>
62 * ON : print nicks left-aligned on messages
63 * OFF : print nicks right-aligned on messages
65 /set neat_right_mode <ON|OFF>
66 * ON : print the mode of the nick e.g @%+ after the nick
67 * OFF : print it left of the nick
69 /set neat_maxlength <number>
70 * number : Maximum length of Nicks to display. Longer nicks are truncated.
71 * 0 : Do not truncate nicks.
73 /set neat_melength <number>
74 * number : number of spaces to substract from /me padding
76 /set neat_ignorechars <str>
77 * str : regular expression used to filter out unwanted characters in
78 nicks. this can be used to assign the same color for similar
79 nicks, e.g. foo and foo_:
81 /set neat_ignorechars [_]
83 /set neat_allow_shrinking <ON|OFF>
84 * ON : shrink padding when longest nick disappears
85 * OFF : do not shrink, only allow growing
97 # - added option to ignore certain characters from color hash building, see
98 # https://bc-bd.org/trac/irssi/ticket/22
99 # - added option to save and specify colors for nicks, see
100 # https://bc-bd.org/trac/irssi/ticket/23
101 # - added option to disallow shrinking, see
102 # https://bc-bd.org/trac/irssi/ticket/12
105 # - now also aligning own messages in queries
108 # - fxed off by one error in nick_to_color, patch by jrib, see
109 # https://bc-bd.org/trac/irssi/ticket/24
112 # - added support for alignment in queries, see
113 # https://bc-bd.org/trac/irssi/ticket/21
116 # - integrated left alignment patch from Eric Wald <eswald@gmail.com>, see
117 # https://bc-bd.org/trac/irssi/ticket/18
120 # - /me padding, see https://bc-bd.org/trac/irssi/ticket/17
123 # - integrate nick coloring support
126 # - moved neat_maxlength check to reformat() (thx to Jerome De Greef <jdegreef@brutele.be>)
129 # - by adrianel <adrinael@nuclearzone.org>
130 # * reformat after setup reload
131 # * maximum length of nicks
134 # - got lost somewhere
148 # Empty nicks, eg "<> message"
149 # This seems to be triggered by some themes. As of now there is no known
150 # fix other than changing themes, see
151 # https://bc-bd.org/trac/irssi/ticket/19
153 # Well, it's a feature: due to the lacking support of extendable themes
154 # from irssi it is not possible to just change some formats per window.
155 # This means that right now all windows are aligned with the same nick
156 # length, which can be somewhat annoying.
157 # If irssi supports extendable themes, I will include per-server indenting
158 # and a setting where you can specify servers you don't want to be indented
163 my ($longestNick, %saved_colors, @colors, $alignment, $sign, %commands);
168 my $max = Irssi::settings_get_int('neat_maxlength');
169 my $actsign = Irssi::settings_get_bool('neat_left_actions')? '': '-';
170 $sign = Irssi::settings_get_bool('neat_left_messages')? '': '-';
172 if ($max && $max < $longestNick) {
176 my $me = $longestNick - Irssi::settings_get_int('neat_melength');
177 $me = 0 if ($me < 0);
179 Irssi::command('^format own_action {ownaction $['.$actsign.$me.']0} $1');
180 Irssi::command('^format action_public {pubaction $['.$actsign.$me.']0}$1');
181 Irssi::command('^format action_private {pvtaction $['.$actsign.$me.']0}$1');
182 Irssi::command('^format action_private_query {pvtaction_query $['.$actsign.$me.']0} $2');
184 my $length = $sign . $longestNick;
185 if (Irssi::settings_get_bool('neat_right_mode') == 0) {
186 Irssi::command('^format own_msg {ownmsgnick $2 {ownnick $['.$length.']0}}$1');
187 Irssi::command('^format own_msg_channel {ownmsgnick $3 {ownnick $['.$length.']0}{msgchannel $1}}$2');
188 Irssi::command('^format pubmsg_me {pubmsgmenick $2 {menick $['.$length.']0}}$1');
189 Irssi::command('^format pubmsg_me_channel {pubmsgmenick $3 {menick $['.$length.']0}{msgchannel $1}}$2');
190 Irssi::command('^format pubmsg_hilight {pubmsghinick $0 $3 $['.$length.']1%n}$2');
191 Irssi::command('^format pubmsg_hilight_channel {pubmsghinick $0 $4 $['.$length.']1{msgchannel $2}}$3');
192 Irssi::command('^format pubmsg {pubmsgnick $2 {pubnick $['.$length.']0}}$1');
193 Irssi::command('^format pubmsg_channel {pubmsgnick $2 {pubnick $['.$length.']0}}$1');
195 Irssi::command('^format own_msg {ownmsgnick {ownnick $['.$length.']0$2}}$1');
196 Irssi::command('^format own_msg_channel {ownmsgnick {ownnick $['.$length.']0$3}{msgchannel $1}}$2');
197 Irssi::command('^format pubmsg_me {pubmsgmenick {menick $['.$length.']0}$2}$1');
198 Irssi::command('^format pubmsg_me_channel {pubmsgmenick {menick $['.$length.']0$3}{msgchannel $1}}$2');
199 Irssi::command('^format pubmsg_hilight {pubmsghinick $0 $0 $['.$length.']1$3%n}$2');
200 Irssi::command('^format pubmsg_hilight_channel {pubmsghinick $0 $['.$length.']1$4{msgchannel $2}}$3');
201 Irssi::command('^format pubmsg {pubmsgnick {pubnick $['.$length.']0$2}}$1');
202 Irssi::command('^format pubmsg_channel {pubmsgnick {pubnick $['.$length.']0$2}}$1');
206 Irssi::command('^format own_msg_private_query {ownprivmsgnick {ownprivnick $['.$length.']2}}$1');
207 Irssi::command('^format msg_private_query {privmsgnick $['.$length.']0}$2');
210 sub findLongestNick {
213 # get own nick length
215 my $len = length($_->{nick});
217 $longestNick = $len if ($len > $longestNick);
220 # find longest other nick
221 foreach (Irssi::channels()) {
222 foreach ($_->nicks()) {
223 my $len = length($_->{nick});
225 $longestNick = $len if ($len > $longestNick);
232 # a new nick was created
235 my ($channel, $nick) = @_;
237 my $len = length($nick->{nick});
239 if ($len > $longestNick) {
244 return if (exists($saved_colors{$nick->{nick}}));
246 $saved_colors{$nick->{nick}} = "%".nick_to_color($nick->{nick});
252 my ($channel, $nick, $old_nick) = @_;
254 # we only need to recalculate if this was the longest nick
255 if (length($old_nick) == $longestNick) {
256 my $len = length($nick->{nick});
258 # if the new nick is shorter we need to find the longest nick
259 # again, if it is longer, it is the new longest nick
260 if ($len < $longestNick) {
261 # only look for a new longest nick if we are allowed to
263 findLongestNick() if Irssi::settings_get_bool('neat_allow_shrinking');
271 $saved_colors{$nick->{nick}} = $saved_colors{$nick->{old_nick}};
272 delete $saved_colors{$nick->{old_nick}}
277 my ($channel, $nick) = @_;
279 my $thisLen = length($nick->{nick});
281 # we only need to recalculate if this was the longest nick and we are
283 if ($thisLen == $longestNick && Irssi::settings_get_bool('neat_allow_shrinking')) {
288 # we do not remove a known color for a gone nick, as they may return
291 # based on simple_hash from nickcolor.pl
292 sub nick_to_color($) {
296 my $ignore = Irssi::settings_get_str("neat_ignorechars");
297 $string =~ s/$ignore//g;
300 foreach my $char (split(//, $string)) {
301 $counter += ord $char;
304 return $colors[$counter % ($#colors + 1)];
308 Irssi::command('^format pubmsg {pubmsgnick $2 {pubnick '.$_[0].'$['.$sign.$longestNick.']0}}$1');
309 Irssi::command('^format pubmsg_channel {pubmsgnick $2 {pubnick '.$_[0].'$['.$sign.$longestNick.']0}}$1');
313 Irssi::command('^format pubmsg {pubmsgnick {pubnick '.$_[0].'$['.$sign.$longestNick.']0}$2}$1');
314 Irssi::command('^format pubmsg_channel {pubmsgnick {pubnick '.$_[0].'$['.$sign.$longestNick.']0}$2}$1');
318 my ($server, $msg, $nick, $address, $target) = @_;
320 &$alignment($saved_colors{$nick});
324 @colors = split(//, Irssi::settings_get_str('neat_colors'));
326 # check left or right alignment
327 if (Irssi::settings_get_bool('neat_right_mode') == 0) {
328 $alignment = \&color_left;
330 $alignment = \&color_right;
333 # check if we switched coloring on or off
334 my $new = Irssi::settings_get_bool('neat_colorize');
335 if ($new != $colorize) {
337 Irssi::signal_add('message public', 'sig_public');
339 if ($colorize >= 0) {
340 Irssi::signal_remove('message public', 'sig_public');
350 # make sure that every nick has an assigned color
351 sub assert_colors() {
352 foreach (Irssi::channels()) {
353 foreach ($_->nicks()) {
354 next if (exists($saved_colors{$_->{nick}}));
356 $saved_colors{$_->{nick}} = "%".nick_to_color($_->{nick});
361 # load colors from file
363 open(FID, "<".$ENV{HOME}."/.irssi/saved_colors") || return;
367 my ($k, $v) = split(/:/);
368 $saved_colors{$k} = $v;
374 # save colors to file
376 open(FID, ">".$ENV{HOME}."/.irssi/saved_colors");
378 print FID $_.":".$saved_colors{$_}."\n" foreach (keys(%saved_colors));
383 # log a line to a window item
385 my ($witem, @text) = @_;
387 $witem->print("nm.pl: ".$_) foreach(@text);
390 # show available colors
391 sub cmd_neatcolor_colors($) {
392 my ($witem, undef, undef) = @_;
394 neat_log($witem, "Available colors: ".join("", map { "%".$_.$_ } @colors));
397 # display the configured color for a nick
398 sub cmd_neatcolor_get() {
399 my ($witem, $nick, undef) = @_;
401 if (!exists($saved_colors{$nick})) {
402 neat_log($witem, "Error: no such nick '$nick'");
406 neat_log($witem, "Color for ".$saved_colors{$nick}.$nick);
410 sub cmd_neatcolor_help() {
411 my ($witem, $cmd, undef) = @_;
414 if (!exists($commands{$cmd})) {
415 neat_log($witem, "Error: no such command '$cmd'");
419 if (!exists($commands{$cmd}{verbose})) {
420 neat_log($witem, "No additional help for '$cmd' available");
424 neat_log($witem, ( "", "Help for ".uc($cmd), "" ) );
425 neat_log($witem, @{$commands{$cmd}{verbose}});
429 neat_log($witem, split(/\n/, $help));
430 neat_log($witem, "Available options for /neatcolor");
431 neat_log($witem, " ".$_.": ".$commands{$_}{text}) foreach(sort(keys(%commands)));
434 foreach (sort(keys(%commands))) {
435 push(@verbose, $_) if exists($commands{$_}{verbose});
438 neat_log($witem, "Verbose help available for: '".join(", ", @verbose)."'");
441 # list configured nicks
442 sub cmd_neatcolor_list() {
443 my ($witem, undef, undef) = @_;
445 neat_log($witem, "Configured nicks: ".join(", ", map { $saved_colors{$_}.$_ } sort(keys(%saved_colors))));
448 # reset a nick to its default color
449 sub cmd_neatcolor_reset() {
450 my ($witem, $nick, undef) = @_;
452 if (!exists($saved_colors{$nick})) {
453 neat_log($witem, "Error: no such nick '$nick'");
457 $saved_colors{$nick} = "%".nick_to_color($nick);
458 neat_log($witem, "Reset color for ".$saved_colors{$nick}.$nick);
461 # save configured colors to disk
462 sub cmd_neatcolor_save() {
463 my ($witem, undef, undef) = @_;
467 neat_log($witem, "color information saved");
470 # set a color for a nick
471 sub cmd_neatcolor_set() {
472 my ($witem, $nick, $color) = @_;
474 my @found = grep(/$color/, @colors);
476 neat_log($witem, "Error: trying to set unknown color '%$color$color%n'");
477 cmd_neatcolor_colors($witem);
481 if ($witem->{type} ne "CHANNEL" && $witem->{type} ne "QUERY") {
482 neat_log($witem, "Warning: not a Channel/Query, can not check nick");
484 my @nicks = grep(/^$nick$/i, map { $_->{nick} } ($witem->nicks()));
487 neat_log($witem, "Warning: could not find nick '$nick' here");
489 if ($nicks[0] ne $nick) {
490 neat_log($witem, "Warning: using '$nicks[0]' instead of '$nick'");
496 $saved_colors{$nick} = "%".$color;
497 neat_log($witem, "Set color for $saved_colors{$nick}$nick");
502 text => "show available colors",
506 "displays all available colors",
508 "You can restrict/define the list of available colors ".
509 "with the help of the neat_colors setting"
511 func => \&cmd_neatcolor_colors,
514 text => "retrieve color for a nick",
518 "displays color used for <nick>"
520 func => \&cmd_neatcolor_get,
523 text => "print this help message",
524 func => \&cmd_neatcolor_help,
527 text => "list configured nick/color pairs",
528 func => \&cmd_neatcolor_list,
531 text => "reset color to default",
535 "resets the color used for <nick> to its internal default"
537 func => \&cmd_neatcolor_reset,
540 text => "save color information to disk",
544 "saves color information to disk, so that it survives ".
547 "Color information will be automatically saved on /quit",
549 func => \&cmd_neatcolor_save,
552 text => "set a specific color for a nick",
554 "SET <nick> <color>",
556 "use <color> for <nick>",
558 "This command will perform a couple of sanity checks, ".
559 "when called from a CHANNEL/QUERY window",
562 " /neatcolor set bc-bd r",
564 "use /neatcolor COLORS to see available colors"
566 func => \&cmd_neatcolor_set,
570 # the main command callback that gets called for all neatcolor commands
571 sub cmd_neatcolor() {
572 my ($data, $server, $witem) = @_;
573 my ($cmd, $nick, $color) = split (/ /, $data);
577 # make sure we have a valid witem to print text to
578 $witem = Irssi::active_win() unless ($witem);
580 if (!exists($commands{$cmd})) {
581 neat_log($witem, "Error: unknown command '$cmd'");
582 &{$commands{"help"}{"func"}} if (exists($commands{"help"}));
586 &{$commands{$cmd}{"func"}}($witem, $nick, $color);
589 Irssi::settings_add_bool('misc', 'neat_left_messages', 0);
590 Irssi::settings_add_bool('misc', 'neat_left_actions', 0);
591 Irssi::settings_add_bool('misc', 'neat_right_mode', 1);
592 Irssi::settings_add_int('misc', 'neat_maxlength', 0);
593 Irssi::settings_add_int('misc', 'neat_melength', 2);
594 Irssi::settings_add_bool('misc', 'neat_colorize', 1);
595 Irssi::settings_add_str('misc', 'neat_colors', 'rRgGyYbBmMcC');
596 Irssi::settings_add_str('misc', 'neat_ignorechars', '');
597 Irssi::settings_add_bool('misc', 'neat_allow_shrinking', 1);
599 Irssi::command_bind('neatcolor', 'cmd_neatcolor');
601 Irssi::signal_add('nicklist new', 'sig_newNick');
602 Irssi::signal_add('nicklist changed', 'sig_changeNick');
603 Irssi::signal_add('nicklist remove', 'sig_removeNick');
605 Irssi::signal_add('setup changed', 'sig_setup');
606 Irssi::signal_add_last('setup reread', 'sig_setup');
614 # we need to add this signal _after_ the colors have been loaded, to make sure
615 # no race condition exists wrt color saving
616 Irssi::signal_add('gui exit', 'save_colors');