diff options
| author | dx | 2015-11-23 14:18:41 -0300 |
|---|---|---|
| committer | dx | 2015-11-23 14:18:41 -0300 |
| commit | 8d9d995b69ba2b436d4bd63061d8189a6844a9a8 (patch) | |
| tree | 0a8e939a47dbd15d9a8c04b61e21c1e33d6da738 /scripts/dim_nicks.pl | |
| parent | 2605878778636421276fe85cd9a2045d125546bd (diff) | |
| parent | 6dec1974e3ac2e71c26e842887a4b8fe2ec9082c (diff) | |
| download | scripts.irssi.org-8d9d995b69ba2b436d4bd63061d8189a6844a9a8.tar.bz2 | |
Merge pull request #173 from irssi/nei-scripts
FORCEFULLY ADD ALL THE SCRIPTS FROM NEI'S WEBSITE
Diffstat (limited to 'scripts/dim_nicks.pl')
| -rw-r--r-- | scripts/dim_nicks.pl | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/scripts/dim_nicks.pl b/scripts/dim_nicks.pl new file mode 100644 index 0000000..5c19633 --- /dev/null +++ b/scripts/dim_nicks.pl @@ -0,0 +1,392 @@ +use strict; +use warnings; + +our $VERSION = '0.4.6'; # 373036720cc131b +our %IRSSI = ( + authors => 'Nei', + contact => 'Nei @ anti@conference.jabber.teamidiot.de', + url => "http://anti.teamidiot.de/", + name => 'dim_nicks', + description => 'Dims nicks that are not in channel anymore.', + license => 'GNU GPLv2 or later', + ); + +# Usage +# ===== +# Once loaded, this script will record the nicks of each new +# message. If the user leaves the room, the messages will be rewritten +# with the nick in another colour/style. +# +# Depending on your theme, tweaking the forms settings may be +# necessary. With the default irssi theme, this script should just +# work. + +# Options +# ======= +# /set dim_nicks_color <colour> +# * the colour code to use for dimming the nick, or a string of format +# codes with the special token $* in place of the nick (e.g. %I$*%I +# for italic) +# +# /set dim_nicks_history_lines <num> +# * only this many lines of messages are remembered/rewritten (per +# window) +# +# /set dim_nicks_forms_skip <num> +# /set dim_nicks_forms_search_max <num> +# * these two settings limit the range where to search for the +# nick. +# It sets how many forms (blocks of irssi format codes or +# non-letters) to skip at the beginning of line before starting to +# search for the nick, and from then on how many forms to search +# before stopping. +# You should set this to the appropriate values to avoid (a) dimming +# your timestamp (b) dimming message content instead of the nick. +# To check your settings, you can use the command +# /script exec Irssi::Script::dim_nicks::debug_forms + + +no warnings 'redefine'; +use constant IN_IRSSI => __PACKAGE__ ne 'main' || $ENV{IRSSI_MOCK}; +use Irssi 20140701; +use Irssi::TextUI; +use Encode; + + +sub setc () { + $IRSSI{name} +} + +sub set ($) { + setc . '_' . $_[0] +} + +my $history_lines = 100; +my $skip_forms = 1; +my $search_forms_max = 5; +my $color_letter = 'K'; + +my (%nick_reg, %chan_reg, %history, %history_st, %lost_nicks, %lost_nicks_backup); + +my ($dest, $chanref, $nickref); + +sub clear_ref { + $dest = undef; + $chanref = undef; + $nickref = undef; +} + +sub msg_line_tag { + my ($srv, $msg, $nick, $addr, $targ) = @_; + $chanref = $srv->channel_find($targ); + $nickref = ref $chanref ? $chanref->nick_find($nick) : undef; +} + +sub msg_line_clear { + clear_ref(); +} + +my @color_code; + +sub color_to_code { + my $win = Irssi::active_win; + my $view = $win->view; + if (-1 == index $color_letter, '$*') { + $color_letter = "%$color_letter\$*"; + } + $win->print_after(undef, MSGLEVEL_NEVER, "$color_letter "); + my $lp = $win->last_line_insert; + my $color_code = $lp->get_text(1); + $color_code =~ s/ $//; + $view->remove_line($lp); + @color_code = split /\$\*/, $color_code, 2; +} + +sub setup_changed { + $history_lines = Irssi::settings_get_int( set 'history_lines' ); + $skip_forms = Irssi::settings_get_int( set 'forms_skip' ); + $search_forms_max = Irssi::settings_get_int( set 'forms_search_max' ); + my $new_color = Irssi::settings_get_str( set 'color' ); + if ($new_color ne $color_letter) { + $color_letter = $new_color; + color_to_code(); + } +} + +sub init_dim_nicks { + setup_changed(); +} + +sub prt_text_issue { + ($dest) = @_; + clear_ref() unless defined $dest->{target}; + clear_ref() unless $dest->{level} & MSGLEVEL_PUBLIC; +} + +sub expire_hist { + for my $ch (keys %history_st) { + if (@{$history_st{$ch}} > 2 * $history_lines) { + my @del = splice @{$history_st{$ch}}, 0, $history_lines; + delete @history{ @del }; + } + } +} + +sub prt_text_ref { + return unless $nickref; + my ($win) = @_; + my $view = $win->view; + my $line_id = $view->{buffer}{_irssi} .','. $view->{buffer}{cur_line}{_irssi}; + $chan_reg{ $chanref->{_irssi} } = $chanref; + $nick_reg{ $nickref->{_irssi} } = $nickref; + if (exists $history{ $line_id }) { + } + $history{ $line_id } = [ $win->{_irssi}, $chanref->{_irssi}, $nickref->{_irssi}, $nickref->{nick} ]; + push @{$history_st{ $chanref->{_irssi} }}, $line_id; + expire_hist(); + my @lost_forever = grep { $view->{buffer}{first_line}{info}{time} > $lost_nicks{ $chanref->{_irssi} }{ $_ } } + keys %{$lost_nicks{ $chanref->{_irssi} }}; + delete @{$lost_nicks{ $chanref->{_irssi} }}{ @lost_forever }; + delete @{$lost_nicks_backup{ $chanref->{_irssi} }}{ @lost_forever }; + clear_ref(); +} + +sub win_del { + my ($win) = @_; + for my $ch (keys %history_st) { + @{$history_st{$ch}} = grep { exists $history{ $_ } && + $history{ $_ }[0] != $win->{_irssi} } @{$history_st{$ch}}; + } + my @del = grep { $history{ $_ }[0] == $win->{_irssi} } keys %history; + delete @history{ @del }; +} + +sub _alter_lines { + my ($chan, $check_lr, $ad) = @_; + my $win = $chan->window; + return unless ref $win; + my $view = $win->view; + my $count = $history_lines; + my $buffer_id = $view->{buffer}{_irssi} .','; + my $lp = $view->{buffer}{cur_line}; + my %check_lr = map { $_ => undef } @$check_lr; + my $redraw; + my $bottom = $view->{bottom}; + while ($lp && $count) { + my $line_id = $buffer_id . $lp->{_irssi}; + if (exists $check_lr{ $line_id }) { + $lp = _alter_line($buffer_id, $line_id, $win, $view, $lp, $chan->{_irssi}, $ad); + unless ($lp) { + last; + } + $redraw = 1; + } + } continue { + --$count; + $lp = $lp->prev; + } + if ($redraw) { + $win->command('^scrollback end') if $bottom && !$win->view->{bottom}; + $view->redraw; + } +} + +my $irssi_mumbo = qr/\cD[`-i]|\cD[&-@\xff]./; +my $irssi_mumbo_no_partial = qr/(?<!\cD)(?<!\cD[&-@\xff])/; +my $irssi_skip_form_re = qr/((?:$irssi_mumbo|[.,*@%+&!#$()=~'";:?\/><]+(?=$irssi_mumbo|\s))+|\s+)/; + +sub debug_forms { + my $win = Irssi::active_win; + my $view = $win->view; + my $lp = $view->{buffer}{cur_line}; + my $count = $history_lines; + my $buffer_id = $view->{buffer}{_irssi} .','; + while ($lp && $count) { + my $line_id = $buffer_id . $lp->{_irssi}; + # $history{ $line_id } = [ $win->{_irssi}, $chanref->{_irssi}, $nickref->{_irssi}, $nickref->{nick} ]; + if (exists $history{ $line_id }) { + my $line_nick = $history{ $line_id }[3]; + my $text = $lp->get_text(1); + pos $text = 0; + my $from = 0; + for (my $i = 0; $i < $skip_forms; ++$i) { + last unless + scalar $text =~ /$irssi_skip_form_re/g; + $from = pos $text; + } + my $to = $from; + for (my $i = 0; $i < $search_forms_max; ++$i) { + last unless + scalar $text =~ /$irssi_skip_form_re/g; + $to = pos $text; + } + my $pre = substr $text, 0, $from; + my $search = substr $text, $from, $to-$from; + my $post = substr $text, $to; + unless ($to > $from) { + } else { + my @nick_reg; + unshift @nick_reg, quotemeta substr $line_nick, 0, $_ for 1 .. length $line_nick; + no warnings 'uninitialized'; + for my $nick_reg (@nick_reg) { + last if $search + =~ s/(\Q$color_code[0]\E\s*)?((?:$irssi_mumbo)+)?$irssi_mumbo_no_partial($nick_reg)((?:$irssi_mumbo)+)?(\s*\Q$color_code[0]\E)?/<match>$1$2<nick>$3<\/nick>$4$5<\/match>/; + last if $search + =~ s/(?:\Q$color_code[0]\E)?(?:(?:$irssi_mumbo)+?)?$irssi_mumbo_no_partial($nick_reg)(?:(?:$irssi_mumbo)+?)?(?:\Q$color_code[1]\E)?/<nick>$1<\/nick>/; + } + } + my $msg = "$pre<search>$search</search>$post"; + #$msg =~ s/([^[:print:]])/sprintf '\\x%02x', ord $1/ge; + $msg =~ s/\cDe/%|/g; $msg =~ s/%/%%/g; + $win->print(setc." form debug: [$msg]", MSGLEVEL_CLIENTCRAP); + return; + } + } continue { + --$count; + $lp = $lp->prev; + } + $win->print(setc." form debug: no usable line found", MSGLEVEL_CLIENTCRAP); +} + +sub _alter_line { + my ($buffer_id, $lrp, $win, $view, $lp, $cid, $ad) = @_; + my $line_nick = $history{ $lrp }[3]; + my $text = $lp->get_text(1); + pos $text = 0; + my $from = 0; + for (my $i = 0; $i < $skip_forms; ++$i) { + last unless + scalar $text =~ /$irssi_skip_form_re/g; + $from = pos $text; + } + my $to = $from; + for (my $i = 0; $i < $search_forms_max; ++$i) { + last unless + scalar $text =~ /$irssi_skip_form_re/g; + $to = pos $text; + } + return $lp unless $to > $from; + my @nick_reg; + unshift @nick_reg, quotemeta substr $line_nick, 0, $_ for 1 .. length $line_nick; + { no warnings 'uninitialized'; + if ($ad) { + if (exists $lost_nicks_backup{ $cid }{ $line_nick }) { + my ($fs, $fc, $bc, $bs) = @{$lost_nicks_backup{ $cid }{ $line_nick }}; + my $sen = length $bs ? $color_code[0] : ''; + for my $nick_reg (@nick_reg) { + last if + (substr $text, $from, $to-$from) + =~ s/(?:\Q$color_code[0]\E)?(?:(?:$irssi_mumbo)+?)?$irssi_mumbo_no_partial($nick_reg)(?:(?:$irssi_mumbo)+?)?(?:\Q$color_code[1]\E)?/$fc$1$bc$sen/; + } + } + } + else { + for my $nick_reg (@nick_reg) { + if ( + (substr $text, $from, $to-$from) + =~ s/(\Q$color_code[0]\E\s*)?((?:$irssi_mumbo)+)?$irssi_mumbo_no_partial($nick_reg)((?:$irssi_mumbo)+)?(\s*\Q$color_code[0]\E)?/$1$2$color_code[0]$3$color_code[1]$4$5/) { + $lost_nicks_backup{ $cid }{ $line_nick } = [ $1, $2, $4, $5 ]; + last; + } + } + } } + $win->gui_printtext_after($lp->prev, $lp->{info}{level} | MSGLEVEL_NEVER, "$text\n", $lp->{info}{time}); + my $ll = $win->last_line_insert; + my $line_id = $buffer_id . $ll->{_irssi}; + if (exists $history{ $line_id }) { + } + grep { $_ eq $lrp and $_ = $line_id } @{$history_st{ $cid }}; + $history{ $line_id } = delete $history{ $lrp }; + $view->remove_line($lp); + $ll; +} + +sub nick_add { + my ($chan, $nick) = @_; + if (delete $lost_nicks{ $chan->{_irssi} }{ $nick->{nick} }) { + my @check_lr = grep { $history{ $_ }[1] == $chan->{_irssi} && + $history{ $_ }[2] eq $nick->{nick} } keys %history; + if (@check_lr) { + $nick_reg{ $nick->{_irssi} } = $nick; + for my $li (@check_lr) { + $history{ $li }[2] = $nick->{_irssi}; + } + _alter_lines($chan, \@check_lr, 1); + } + } + delete $lost_nicks_backup{ $chan->{_irssi} }{ $nick->{nick} }; +} + +sub nick_del { + my ($chan, $nick) = @_; + my @check_lr = grep { $history{ $_ }[2] eq $nick->{_irssi} } keys %history; + for my $li (@check_lr) { + $history{ $li }[2] = $nick->{nick}; + } + if (@check_lr) { + $lost_nicks{ $chan->{_irssi} }{ $nick->{nick} } = time; + _alter_lines($chan, \@check_lr, 0); + } + delete $nick_reg{ $nick->{_irssi} }; +} + +sub nick_change { + my ($chan, $nick, $oldnick) = @_; + nick_add($chan, $nick); +} + +sub chan_del { + my ($chan) = @_; + if (my $del = delete $history_st{ $chan->{_irssi} }) { + delete @history{ @$del }; + } + delete $chan_reg{ $chan->{_irssi} }; + delete $lost_nicks{$chan->{_irssi}}; + delete $lost_nicks_backup{$chan->{_irssi}}; +} + +Irssi::settings_add_int( setc, set 'history_lines', $history_lines); +Irssi::signal_add_last({ + 'setup changed' => 'setup_changed', +}); +Irssi::signal_add({ + 'print text' => 'prt_text_issue', + 'gui print text finished' => 'prt_text_ref', + 'nicklist new' => 'nick_add', + 'nicklist changed' => 'nick_change', + 'nicklist remove' => 'nick_del', + 'window destroyed' => 'win_del', + 'message public' => 'msg_line_tag', + 'message own_public' => 'msg_line_clear', + 'channel destroyed' => 'chan_del', +}); + +sub dumphist { + my $win = Irssi::active_win; + my $view = $win->view; + my $buffer_id = $view->{buffer}{_irssi} .','; + for (my $lp = $view->{buffer}{first_line}; $lp; $lp = $lp->next) { + my $line_id = $buffer_id . $lp->{_irssi}; + if (exists $history{ $line_id }) { + my $k = $history{ $line_id }; + if (exists $chan_reg{ $k->[1] }) { + } + if (exists $nick_reg{ $k->[2] }) { + } + if (exists $lost_nicks{ $k->[1] } && exists $lost_nicks{ $k->[1] }{ $k->[2] }) { + } + } + } +} +Irssi::settings_add_str( setc, set 'color', $color_letter); +Irssi::settings_add_int( setc, set 'forms_skip', $skip_forms); +Irssi::settings_add_int( setc, set 'forms_search_max', $search_forms_max); + +init_dim_nicks(); + +{ package Irssi::Nick } + +# Changelog +# ========= +# 0.4.6 +# - fix crash on some lines reported by pierrot |
