diff options
| author | ailin-nemui | 2015-11-16 19:32:11 -0300 | 
|---|---|---|
| committer | dequis | 2015-11-16 19:34:05 -0300 | 
| commit | 2bc8e3368c0b842f1fe6fad069915a4bb90b1fa2 (patch) | |
| tree | cafd9a0ee1dace65772f70f6147598227c38a35b /scripts/nm2.pl | |
| parent | b8965d1651f89ebcd395de3309c1255542ad4c78 (diff) | |
| download | scripts.irssi.org-2bc8e3368c0b842f1fe6fad069915a4bb90b1fa2.tar.bz2 | |
Add all of nei's scripts from nei's website
Diffstat (limited to 'scripts/nm2.pl')
| -rw-r--r-- | scripts/nm2.pl | 560 | 
1 files changed, 560 insertions, 0 deletions
| diff --git a/scripts/nm2.pl b/scripts/nm2.pl new file mode 100644 index 0000000..08ec53d --- /dev/null +++ b/scripts/nm2.pl @@ -0,0 +1,560 @@ +use Irssi; +use strict; +use v5.14; +use List::Util qw(min max); +use Hash::Util qw(lock_keys); + +our $VERSION = '2.0-dev'; # cb10e88bcd58d0c +our %IRSSI = ( +    authors	=> 'Nei', +    contact	=> 'Nei @ anti@conference.jabber.teamidiot.de', +    url		=> "http://anti.teamidiot.de/", +    name	=> 'nm2', +    description => 'right aligned nicks depending on longest nick', +    license	=> 'GPL v2', +); + +# based on bc-bd's original nm.pl +# +# use a ** nickcolor_expando ** script for nick colors! +# +# why is there no right_mode? you can do that in your theme! + +# Options +# ======= +# /set neat_dynamic <ON|OFF> +# * whether the width should be dynamically chosen on each incoming +#   message +# +# /set neat_shrink <ON|OFF> +# * whether shrinking of the width is allowed, or only growing +# +# /set neat_staircase_shrink <ON|OFF> +# * whether shrinking should be done one character at a time +# +# The following styles decide if the nick is left/right aligned and +# where the colour/mode goes, they're a bit complex... +# put the desired indicator(s) between the appropriate "," and the +# default format of the public messages or actions will be rewritten +# appropriately. +# This can be used to align the nick left or right, before or after +# the nick brackets and before or between the nickmode (by using the +# pad on the correct place). To change the mode from left of the nick +# to right of the nick, you need to modify the abstracts in your theme +# however. +# By placing the colour at the end, you can even colour the message +# text in the nick colour, however it might be broken if there are +# other colour codes used inside the message or by scripts. +# +# /format neat_style      , , , , , , , , +#                        î î î î î î î î î +# p: pad                 | | | | | | | | `before message +# c: colour              | | | | | | | `-after msgchannel +# t: truncate indicator  | | | | | | `-before msgchannel +#                        | | | | | `-after nick +#                        | | | | `-before nick +#                        | | | `-after mode +#                        | | `-before mode +#                        | `-before msgnick +#                        `-none +# +# /format neat_action_style  , , , , +#                           î î î î î +# p: pad                    | | | | `-before message +# c: colour                 | | | `-after nick +# t: truncate indicator     | | `-before nick +#                           | `-before action +#                           `-none +# +# /format neat_pad_char <char> +# * the character(s) used for padding +# +# /format neat_truncate_char +# * the format or character to indicate that nick was truncated +# +# /format neat_notruncate_char +# * the format or character to indicate that nick NOT was truncated +# +# /format neat_customize_modes @@ | ++ |  ? +# * a |-separated mapping of mode prefixes and their rendition, can be +#   used to replace or colourise them +# +# /set neat_color_hinick <ON|OFF> +# * whether to use colours in hilighted messages +# +# /set neat_color_menick <ON|OFF> +# * whether to use colours in hilight_nick_matches +# +# /set neat_truncate_nick <ON|OFF> +# * whether to truncate overlong nicks +# +# /set neat_custom_modes <ON|OFF> +# * whether to enable the use of neat_customize_modes format +# +# /set neat_maxlength <number> +# * number : (maximum) length to use for nick padding +# +# /set neat_melength <number> +# * number : width to substract from maxlength for /me padding +# +# /set neat_history <number> +# * number : number of formatted lines to remember for dynamic mode +# + +my @action_protos = qw(irc silc xmpp); +my (%histories, %S, @style, @astyle, %format_ok, %cmmap); + +my $align_expando = ''; +my $trunc_expando = ''; +my $cumode_expando = ''; + +my $format_re = qr/ %(?=[}%{]) +		    | %[04261537kbgcrmywKBGCRMYWU9_8I:|FnN>#pP[] +		    | %[Zz][[:xdigit:]]{6} +		    | %[Xx](?i:0[a-f]|[1-6][0-9a-z]|7[a-x]) /x; + +sub update_expando { +    my ($mode, $server, $target, $nick, $space) = @_; +    my $t_add; +    my $nl = length $nick; +    my $pad_len = max(0, $space - $nl); +    if ($S{truncate_nick}) { +	if (($mode >= 4 && $S{trunc_in_anick}) +		|| ($mode < 4 && $S{trunc_in_nick})) { +	    $t_add = $S{tnolen}; +	} +	if ($nl + $t_add > $space) { +	    $trunc_expando = format_expand($S{tyes_char}); +	    $t_add = $S{tyeslen} if defined $t_add; +	} +	else { +	    $trunc_expando = format_expand($S{tno_char}); +	} +	$pad_len = max(0, $pad_len - $t_add) if $t_add; +    } +    else { +	$trunc_expando = ''; +    } +    if ($pad_len) { +	my @subs = split /($format_re)/, $S{pad_char} x $pad_len; +	$align_expando = ''; +	my $clen = 0; +	while (@subs) { +	    my ($tx, $fmt) = splice @subs, 0, 2; +	    my $txlen = length $tx // 0; +	    $align_expando .= substr $tx, 0, ($pad_len - $clen) if defined $tx; +	    $clen += $txlen; +	    $align_expando .= $fmt if defined $fmt; +	    last if $clen >= $pad_len; +	} +	$align_expando = format_expand($align_expando.'%n'); +    } +    else { +	$align_expando = ''; +    } +    return $t_add; +} + +sub prnt_clear_levels { +    my ($dest) = @_; +    clear_ref() if $dest->{level} +	& (MSGLEVEL_PUBLIC|MSGLEVEL_MSGS|MSGLEVEL_ACTIONS|MSGLEVEL_DCCMSGS|MSGLEVEL_NOTICES); +} + +sub clear_ref { +    $trunc_expando = $align_expando = $cumode_expando = ''; +} + +sub expando_nickalign { $align_expando } +sub expando_nicktrunc { $trunc_expando } +sub expando_nickcumode { $cumode_expando } + +Irssi::expando_create('nickalign', \&expando_nickalign, { +    'message public'	     => 'none', +    'message own_public'     => 'none', +    'message private'	     => 'none', +    'message own_private'    => 'none', +    (map { ("message $_ action"     => 'none', +	    "message $_ own_action" => 'none') +       } @action_protos), +   }); +Irssi::expando_create('nicktrunc', \&expando_nicktrunc, { +    'message public'	     => 'none', +    'message own_public'     => 'none', +    'message private'	     => 'none', +    'message own_private'    => 'none', +    (map { ("message $_ action"     => 'none', +	    "message $_ own_action" => 'none') +       } @action_protos), +   }); +Irssi::expando_create('nickcumode', \&expando_nickcumode, { +    'message public'	     => 'none', +    'message own_public'     => 'none', +    'message private'	     => 'none', +    'message own_private'    => 'none', +    (map { ("message $_ action"     => 'none', +	    "message $_ own_action" => 'none') +       } @action_protos), +   }); + +sub init_hist { +    my ($server, $target) = @_; +    if (my $ch = $server->channel_find($target)) { +	[ max map { length } map { $_->{nick} } $ch->nicks ] +    } +    else { +	[ max map { length } $server->{nick}, $target ] +    } +} + +my %em = ( +    p => '$nickalign', +    c => '$nickcolor', +    t => '$nicktrunc', +    m => '$nickcumode', +   ); + +my %formats = ( +    own_action		   => [5, '{ownaction ',      '$0','}','$1' ], +    action_public	   => [4, '{pubaction ',      '$0','}','$1' ], +    action_private	   => [4, '{pvtaction ',      '$0','}','$2' ], +    action_private_query   => [4, '{pvtaction_query ','$0','}','$2' ], +    #                          * *                   * #  *   * + +    own_msg_private_query  => [3, '{ownprivmsgnick ', ''  ,'{ownprivnick ','$2','}',''               ,'}','$1' ], +    msg_private_query	   => [2, '{privmsgnick '    ,''  ,''             ,'$0','' ,''               ,'}','$2' ], +    own_msg		   => [1, '{ownmsgnick '     ,'$2',' {ownnick '   ,'$0','}',''               ,'}','$1' ], +    own_msg_channel	   => [1, '{ownmsgnick '     ,'$3',' {ownnick '   ,'$0','}','{msgchannel $1}','}','$2' ], +    pubmsg_me		   => [0, '{pubmsgmenick '   ,'$2',' {menick '    ,'$0','}',''               ,'}','$1' ], +    pubmsg_me_channel	   => [0, '{pubmsgmenick '   ,'$3',' {menick '    ,'$0','}','{msgchannel $1}','}','$2' ], +    pubmsg_hilight	   => [0, '{pubmsghinick $0 ','$3',' '            ,'$1', '','',              ,'}','$2' ], +    pubmsg_hilight_channel => [0, '{pubmsghinick $0 ','$4',' '            ,'$1', '','{msgchannel $2}','}','$3' ], +    pubmsg		   => [0, '{pubmsgnick '     ,'$2',' {pubnick '   ,'$0','}',''               ,'}','$1' ], +    pubmsg_channel	   => [0, '{pubmsgnick '     ,'$3',' {pubnick '   ,'$0','}','{msgchannel $1}','}','$2' ], +    #                          * *                   *    *            * #  *   *                 *   * +   ); + +sub reformat_format { +    Irssi::signal_remove('command format', 'update_formats'); +    Irssi::signal_remove('theme changed'  => 'update_formats'); +    %format_ok = () unless @_; +    my ($mode, $server, $target, $nick, $size) = @_; +    for my $fmt (keys %formats) { +	next if defined $mode && $formats{$fmt}[0] != $mode; + +	my @fs = @{ $formats{$fmt} }; + +	my $ls; +	if (defined $mode) { +	    $ls = $size; +	} +	else { +	    $ls = $fs[0] < 4 ? $S{max} : max(0, $S{max} - $S{melength}); +	} +	next if exists $format_ok{$fmt} && $format_ok{$fmt} == $ls; + +	if ($S{truncate_nick} && $ls) { +	    $fs[ $fs[0] < 4 ? 4 : 2 ] =~ s/\$/\$[.$ls]/; +	} +	if ($S{custom_modes} && $fs[0] < 4) { +	    $fs[2] =~ s/\$\K\d/nickcumode/; +	} +	my $s; +	local $em{c} = '' +	    if ($fs[1] =~ /menick/ && !$S{color_menick}) +		|| ($fs[1] =~ /hinick/ && !$S{color_hinick}); +	my $sr = $fs[0] >= 4 ? \@astyle : \@style; +	for my $i (1..$#fs) { +	    $s .= ($sr->[$i] =~ s/(.)/$em{$1}/gr) if defined $sr->[$i]; +	    $s .= $fs[$i]; +	} +	Irssi::command("^format $fmt $s"); +	$format_ok{$fmt} = $ls; +    } +    Irssi::signal_add_last({ +	'theme changed'  => 'update_formats', +	'command format' => 'update_formats', +    }); +} + +sub update_nm { +    my ($mode, $server, $target, $nick) = @_; +    my $tg = $server->{tag}; +    if (my $ch = $server->channel_find($target)) { +	$target = $ch->{name}; +	my $nickobj = $ch->nick_find($nick); +	if ($nickobj) { +	    $nick = $nickobj->{nick}; +	    my $mode = substr $nickobj->{prefixes}.' ', 0, 1; +	    $cumode_expando = exists $cmmap{$mode} ? format_expand($cmmap{$mode}) : $mode; +	} +	else { +	    $cumode_expando = ''; +	} +    } +    elsif (my $q = $server->query_find($target)) { +	$target = $q->{name}; +    } + +    my $longest; +    if ($S{dynamic}) { +	my $hist = $histories{"$tg/$target"} ||= init_hist($server, $target); +	my $last = $histories{"$tg/$target/last"} || 1; +	unshift @$hist, length $nick; +	if (@$hist > 2*$S{history}) { +	    splice @$hist, $S{history}; +	} +	my @add; +	unless ($S{shrink}) { +	    push @add, $last; +	} +	if ($S{staircase}) { +	    push @add, $last - 1 +	} +	$longest = $histories{"$tg/$target/last"} = max(@$hist, @add); + +	if ($S{max} && ($S{max} < $longest || !$S{shrink})) { +	    $longest = $S{max}; +	} +    } +    else { +	$longest = $S{max}; +    } + +    my $size = $mode < 4 ? $longest : max(0, $longest - $S{melength}); +    my $t_add = update_expando($mode, $server, $target, $nick, $size); +    $size = max(0, $size - $t_add) if defined $t_add; +    if ($S{dynamic}) { +	reformat_format($mode, $server, $target, $nick, $size); +    } +} + +sub sig_setup { +    my %old_S = %S; +    $S{history}	 = Irssi::settings_get_int('neat_history'); +    $S{max}	 = Irssi::settings_get_int('neat_maxlength'); +    $S{melength} = Irssi::settings_get_int('neat_melength'); + +    $S{dynamic}	    = Irssi::settings_get_bool('neat_dynamic'); +    $S{shrink}	    = Irssi::settings_get_bool('neat_shrink'); +    $S{staircase}   = Irssi::settings_get_bool('neat_staircase_shrink'); + +    $S{color_hinick}  = Irssi::settings_get_bool('neat_color_hinick'); +    $S{color_menick}  = Irssi::settings_get_bool('neat_color_menick'); +    $S{truncate_nick} = Irssi::settings_get_bool('neat_truncate_nick'); +    $S{custom_modes}  = Irssi::settings_get_bool('neat_custom_modes'); + +    if (!defined $old_S{dynamic} || $old_S{dynamic} != $S{dynamic}) { +	%histories = (); +	reformat_format(); +    } +    elsif ($old_S{max} != $S{max} || $old_S{melength} != $S{melength} +	       || $old_S{color_hinick} != $S{color_hinick} || $old_S{color_menick} != $S{color_menick} +		   || $old_S{truncate_nick} != $S{truncate_nick} || $old_S{custom_modes} != $S{custom_modes}) { +	reformat_format(); +    } +} + +sub update_formats { +    my $was_style = "@style"; +    $S{style} = Irssi::current_theme->get_format(__PACKAGE__, 'neat_style'); +    my $was_action_style = "@astyle"; +    $S{action_style} = Irssi::current_theme->get_format(__PACKAGE__, 'neat_action_style'); +    $S{pad_char} = Irssi::current_theme->get_format(__PACKAGE__, 'neat_pad_char'); +    $S{tno_char} = Irssi::current_theme->get_format(__PACKAGE__, 'neat_notruncate_char'); +    $S{tnolen} = length($S{tno_char} =~ s/$format_re//gr); +    $S{tyeslen} = length($S{tyes_char} =~ s/$format_re//gr); +    $S{tyes_char} = Irssi::current_theme->get_format(__PACKAGE__, 'neat_truncate_char'); +    @style = map { y/pct//cd; $_ } split /,/, $S{style}; +    @astyle = map { y/pctm//cd; $_ } split /,/, $S{action_style}; +    $S{trunc_in_nick} = grep { /t/ } @style[2..min($#style, 6)]; +    $S{trunc_in_anick} = grep { /t/ } @astyle[2..min($#astyle, 3)]; +    my $custom_modes = Irssi::current_theme->get_format(__PACKAGE__, 'neat_custom_modes'); +    %cmmap = map { (substr $_, 0, 1), (substr $_, 1) } $custom_modes =~ /(?:^\s?|\G\s?\|\s?)((?!\s\|)(?:[^\\|[:space:]]|\\.|\s(?!\||$))*)/sg; +    if ($was_style ne "@style" || $was_action_style ne "@astyle") { +	reformat_format(); +    } +} + +{ +    my %format2control = ( +	'F' => "\cDa", '_' => "\cDc", '|' => "\cDe", '#' => "\cDi", "n" => "\cDg", "N" => "\cDg", +	'U' => "\c_", '8' => "\cV", 'I' => "\cDf", +       ); +    my %bg_base = ( +	'0'   => '0', '4' => '1', '2' => '2', '6' => '3', '1' => '4', '5' => '5', '3' => '6', '7' => '7', +	'x08' => '8', 'x09' => '9', 'x0a' => ':', 'x0b' => ';', 'x0c' => '<', 'x0d' => '=', 'x0e' => '>', 'x0f' => '?', +       ); +    my %fg_base = ( +	'k' => '0', 'b' => '1', 'g' => '2', 'c' => '3', 'r' => '4', 'm' => '5', 'p' => '5', 'y' => '6', 'w' => '7', +	'K' => '8', 'B' => '9', 'G' => ':', 'C' => ';', 'R' => '<', 'M' => '=', 'P' => '=', 'Y' => '>', 'W' => '?', +       ); +    my @ext_colour_off = ( +	'.', '-', ',', +	'+', "'", '&', +       ); +    sub format_expand { +	$_[0] =~ s{%(Z.{6}|z.{6}|X..|x..|.)}{ +	    my $c = $1; +	    if (exists $format2control{$c}) { +		$format2control{$c} +	    } +	    elsif (exists $bg_base{$c}) { +		"\cD/$bg_base{$c}" +	    } +	    elsif (exists $fg_base{$c}) { +		"\cD$fg_base{$c}/" +	    } +	    elsif ($c =~ /^[{}%]$/) { +		$c +	    } +	    elsif ($c =~ /^(z|Z)([[:xdigit:]]{2})([[:xdigit:]]{2})([[:xdigit:]]{2})$/) { +		my $bg = $1 eq 'z'; +		my (@rgb) = map { hex $_ } $2, $3, $4; +		my $x = $bg ? 0x1 : 0; +		my $out = "\cD" . (chr -13 + ord '0'); +		for (my $i = 0; $i < 3; ++$i) { +		    if ($rgb[$i] > 0x20) { +			$out .= chr $rgb[$i]; +		    } +		    else { +			$x |= 0x10 << $i; $out .= chr 0x20 + $rgb[$i]; +		    } +		} +		$out .= chr 0x20 + $x; +		$out +	    } +	    elsif ($c =~ /^(x)(?:0([[:xdigit:]])|([1-6])(?:([0-9])|([a-z]))|7([a-x]))$/i) { +		my $bg = $1 eq 'x'; +		my $col = defined $2 ? hex $2 +		    : defined $6 ? 232 + (ord lc $6) - (ord 'a') +			: 16 + 36 * ($3 - 1) + (defined $4 ? $4 : 10 + (ord lc $5) - (ord 'a')); +		if ($col < 0x10) { +		    my $chr = chr $col + ord '0'; +		    "\cD" . ($bg ? "/$chr" : "$chr/") +		} +		else { +		    "\cD" . $ext_colour_off[($col - 0x10) / 0x50 + $bg * 3] . chr (($col - 0x10) % 0x50 - 1 + ord '0') +		} +	    } +	    else { +		"%$c" +	    } +        }ger; +    } +} + +sub init { +    update_formats(); +    sig_setup(); +    lock_keys(%S); +    print "nm2 experimental version, please report issues. thanks!" +} + +Irssi::settings_add_bool('misc', 'neat_dynamic', 1); +Irssi::settings_add_bool('misc', 'neat_shrink', 1); +Irssi::settings_add_bool('misc', 'neat_staircase_shrink', 0); + +Irssi::settings_add_bool('misc', 'neat_color_hinick', 0); +Irssi::settings_add_bool('misc', 'neat_color_menick', 0); +Irssi::settings_add_bool('misc', 'neat_truncate_nick', 1); +Irssi::settings_add_bool('misc', 'neat_custom_modes', 0); + +Irssi::settings_add_int('misc', 'neat_maxlength', 0); +Irssi::settings_add_int('misc', 'neat_melength', 2); +Irssi::settings_add_int('misc', 'neat_history', 50); + +Irssi::signal_add('setup changed' => 'sig_setup'); +Irssi::signal_add_last({ +    'setup reread'   => 'sig_setup', +    'theme changed'  => 'update_formats', +    'command format' => 'update_formats', +   }); + +Irssi::theme_register([ +    'neat_style'	   => ' , , p , , c , t , , , ', +    'neat_action_style'	   => ' , p , , t , ', +    'neat_pad_char'	   => '%K.', +    'neat_truncate_char'   => '%m+', +    'neat_notruncate_char' => '', +    'neat_custom_modes'    => '&%B&%n | @%g@%n | +%y+%n', +   ]); + +Irssi::signal_add_first({ +    'message public' => sub { +	my ($server, $msg, $nick, $address, $target) = @_; +	update_nm(0, $server, $target, $nick); +    }, +    'message private' => sub { +	my ($server, $msg, $nick, $address) = @_; +	update_nm(2, $server, $nick, $nick); +    }, +    (map { ("message $_ action" => sub { +	my ($server, $msg, $nick, $address, $target) = @_; +	update_nm(4, $server, $target, $nick); +    }) } qw(irc silc)), +    'message xmpp action' => sub { +	return unless @_; +	my ($server, $msg, $nick, $target) = @_; +	update_nm(4, $server, $target, $nick); +    }, +   }); + +sub channel_nick { +    my ($server, $target) = @_; +    ($server->channel_find($target)||+{ownnick=>$server})->{ownnick}{nick} +} + +Irssi::signal_add_first({ +    'message own_public' => sub { +	my ($server, $msg, $target) = @_; +	update_nm(1, $server, $target, channel_nick($server, $target)); +    }, +    'message own_private' => sub { +	my ($server, $msg, $target) = @_; +	update_nm(3, $server, $target, $server->{nick}); +    }, +    (map { ("message $_ own_action" => sub { +	my ($server, $msg, $target) = @_; +	update_nm(5, $server, $target, $server->{nick}); +    }) } qw(irc silc)), +    'message xmpp own_action' => sub { +	return unless @_; +	my ($server, $msg, $target) = @_; +	update_nm(5, $server, $target, channel_nick($server, $target)); +    }, +   }); +Irssi::signal_add_last({ +    'channel destroyed' => sub { +	my ($channel) = @_; +	delete $histories{ $channel->{server}{tag} . '/' . $channel->{name} }; +	delete $histories{ $channel->{server}{tag} . '/' . $channel->{name} . '/last' }; +    }, +    'query destroyed' => sub { +	my ($query) = @_; +	delete $histories{ $query->{server}{tag} . '/' . $query->{name} }; +	delete $histories{ $query->{server}{tag} . '/' . $query->{name} . '/last' }; +    }, +    'query nick changed' => sub { +	my ($query, $old_nick) = @_; +	delete $histories{ $query->{server}{tag} . '/' . $old_nick }; +	delete $histories{ $query->{server}{tag} . '/' . $old_nick . '/last' }; +    }, +    'query server changed' => sub { +	my ($query, $old_server) = @_; +	delete $histories{ $old_server->{tag} . '/' . $query->{name} }; +	delete $histories{ $old_server->{tag} . '/' . $query->{name} . '/last' }; +    } +   }); +Irssi::signal_add({ +    'print text' => 'prnt_clear_levels', +}); + +init(); + +# Changelog +# ========= +# 2.0-dev +# - fix crash if xmpp action signal is not registered (just ignore it) +# - do not grow either when using no-shrink with maxlength +# - hopefully fix alignment in xmpp muc | 
