use strict; use warnings; our $VERSION = '0.4.1'; # ed9cb119fc4b3d1 our %IRSSI = ( authors => 'Nei', contact => 'Nei @ [email protected]', url => "http://anti.teamidiot.de/", name => 'colorize_nicks', description => 'Colourise mention of nicks in the message body.', license => 'GNU GPLv2 or later', ); # inspired by mrwright's nickcolor.pl and xt's colorize_nicks.pl # # you need nickcolor_expando or another nickcolor script providing the # get_nick_color2 function # Usage # ===== # should start working once loaded # Options # ======= # /set colorize_nicks_skip_formats # * how many forms (blocks of irssi format codes or non-letters) to # skip at the beginning of line before starting to colourise nicks # (you usually want to skip the speaker's nick itself and the # timestamp) # # /set colorize_nicks_ignore_list # * list of nicks (words) that should never be coloured # # /set colorize_nicks_repeat_formats # * repeat the format stack from the beginning of line, enable when # using per-line colours and colorize_nicks breaks it # Commands # ======== # you can use this alias: # # /alias nocolorize set colorize_nicks_ignore_list $colorize_nicks_ignore_list # # /nocolorize # * quickly add nick to the bad word list of nicks that should not be # colourised no warnings 'redefine'; use Irssi; my $irssi_mumbo = qr/\cD[`-i]|\cD[&-@\xff]./; my $nickchar = qr/[\]\[[:alnum:]\\|`^{}_-]/; my $nick_pat = qr/($nickchar+)/; my @ignore_list; my $colourer_script; sub _find_colourer { my $colourer; unless ($colourer_script && ($colourer = "Irssi::Script::$colourer_script"->can('get_nick_color2'))) { for my $script (sort map { s/::$//r } keys %Irssi::Script::) { if ($colourer = "Irssi::Script::$script"->can('get_nick_color2')) { $colourer_script = $script; last; } } } $colourer } sub _get_chanref { my ($dest) = @_; return unless $dest->{level} & MSGLEVEL_PUBLIC; return unless defined $dest->{target}; return unless ref $dest->{server}; $dest->{server}->channel_find($dest->{target}) } sub _colourise_nicks { my ($dest, $chanref, $colourer, @nicks) = @_; my %nicks = map { $_->[0] => $colourer->($dest->{server}{tag}, $chanref->{name}, $_->[1], 1) } grep { defined } map { if (my $nr = $chanref->nick_find($_)) { [ $_ => $nr->{nick} ] } } keys %{ +{ map { $_ => undef } @nicks } }; delete @nicks{ @ignore_list }; my $nick_re = join '|', map { quotemeta } sort { length $b <=> length $a } grep { length $nicks{$_} } keys %nicks; (\%nicks, $nick_re) } sub _colourise_form { my ( $text, $skip, $nicks, $nick_re ) = @_; return if $skip < 0; my $repeat = Irssi::settings_get_bool('colorize_nicks_repeat_formats'); my @forms = split /((?:$irssi_mumbo|\s|[.,*@%+&!#$()=~'";:?\/><]+(?=$irssi_mumbo|\s))+)/, $text, -1; my $ret = ''; my $fmtstack = ''; while (@forms) { my ($t, $form) = splice @forms, 0, 2; if ($skip > 0) { --$skip; $ret .= $t; $ret .= $form if defined $form; if ($repeat) { $fmtstack .= join '', $form =~ /$irssi_mumbo/g if defined $form; $fmtstack =~ s/\cDe//g; } } elsif (length $nick_re && $t =~ s/((?:^|\s)\W{0,3}?)(?<!$nickchar|')($nick_re)(?!$nickchar)/$1$nicks->{$2}$2\cDg$fmtstack/g) { $ret .= "$t\cDg$fmtstack"; $ret .= $form if defined $form; $fmtstack .= join '', $form =~ /$irssi_mumbo/g if defined $form; $fmtstack =~ s/\cDe//g; } else { $ret .= $t; $ret .= $form if defined $form; } } $ret } # TXT_OWN_MSG, server->nick, msg, nickmode # TXT_OWN_MSG_CHANNEL, server->nick, target, msg, nickmode # TXT_PUBMSG_HILIGHT, color, printnick, msg, nickmode # TXT_PUBMSG_HILIGHT_CHANNEL, color, printnick, target, msg, nickmode # for_me ? TXT_PUBMSG_ME : TXT_PUBMSG, printnick, msg, nickmode # for_me ? TXT_PUBMSG_ME_CHANNEL : TXT_PUBMSG_CHANNEL, printnick, target, msg, nickmode sub prt_format_issue { my ( $theme, $module, $dest, $format, @args ) = @_; my $chanref = _get_chanref($dest); return unless $chanref; my $colourer = _find_colourer(); return unless $colourer; my $arg = 1; $arg++ if $format =~ /_channel/; $arg++ if $format =~ /_hilight/; return unless @args > $arg; utf8::decode($args[$arg]); my $text = $args[$arg]; my $stripped = Irssi::strip_codes($text); utf8::decode($stripped); my ($nicks, $nick_re) = _colourise_nicks($dest, $chanref, $colourer, $stripped =~ /$nick_pat/g); return unless $nicks; $args[$arg] = _colourise_form($text, 0, $nicks, $nick_re); Irssi::signal_continue($theme, $module, $dest, $format, @args) if defined $args[$arg] && $args[$arg] ne $text; } sub prt_text_issue { my ( $dest, $text, $stripped ) = @_; my $chanref = _get_chanref($dest); return unless $chanref; my $colourer = _find_colourer(); return unless $colourer; utf8::decode($text); utf8::decode($stripped); my ($nicks, $nick_re) = _colourise_nicks($dest, $chanref, $colourer, $stripped =~ /$nick_pat/g); return unless $nicks; my $skip = Irssi::settings_get_int('colorize_nicks_skip_formats'); my $ret = _colourise_form($text, $skip, $nicks, $nick_re); Irssi::signal_continue($dest, $ret, $stripped) if defined $ret && $ret ne $text; } sub setup_changed { @ignore_list = split /\s+|,/, Irssi::settings_get_str('colorize_nicks_ignore_list'); } sub init { setup_changed(); } if ((Irssi::parse_special('$abiversion')||0) >= 28) { Irssi::signal_add( 'print format' => 'prt_format_issue' ); } else { Irssi::signal_add( 'print text' => 'prt_text_issue' ); Irssi::settings_add_int('colorize_nicks', 'colorize_nicks_skip_formats' => 2); } Irssi::signal_add_last('setup changed' => 'setup_changed'); Irssi::settings_add_str('colorize_nicks', 'colorize_nicks_ignore_list' => ''); Irssi::settings_add_bool('colorize_nicks', 'colorize_nicks_repeat_formats' => 0); init();