From: coekie Date: Mon, 2 Apr 2018 21:32:07 +0000 (+0200) Subject: [nicklist][#486] add patch 0.4.6+ X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=e4defa5aac60cfe839512412631e7e5fd3b41e19;p=irssi-scripts.irssi.org.git [nicklist][#486] add patch 0.4.6+ --- diff --git a/scripts/nicklist.pl b/scripts/nicklist.pl index 98e62b3..2690e26 100755 --- a/scripts/nicklist.pl +++ b/scripts/nicklist.pl @@ -1,11 +1,28 @@ +# This script adds a nicklist to the right of irssi # for documentation: see http://wouter.coekaerts.be/site/irssi/nicklist +# Copyright (C) 2002-2007 Wouter Coekaerts +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + use Irssi; use strict; use IO::Handle; # for (auto)flush use Fcntl; # for sysopen use vars qw($VERSION %IRSSI); -$VERSION = '0.4.9'; +$VERSION = '0.4.10'; %IRSSI = ( authors => 'Wouter Coekaerts', contact => 'coekie@irssi.org', @@ -13,7 +30,7 @@ $VERSION = '0.4.9'; description => 'draws a nicklist to another terminal, or at the right of your irssi in the same terminal', license => 'GPLv2', url => 'http://wouter.coekaerts.be/irssi', - changed => '28/06/2017' + changed => '2018-04-02' ); sub cmd_help { @@ -58,25 +75,47 @@ my $active_channel; # (REC) my @nicklist=(); # array of hashes, containing the internal nicklist of the active channel # nick => realnick - # mode => - my ($MODE_OP, $MODE_HALFOP, $MODE_VOICE, $MODE_NORMAL) = (0,1,2,3); - # status => - my ($STATUS_NORMAL, $STATUS_JOINING, $STATUS_PARTING, $STATUS_QUITING, $STATUS_KICKED, $STATUS_SPLIT) = (0,1,2,3,4,5); + # modeflag => '@', '%', '+', or other mode char + # modepos => number representing the position in which to sort nicks with that mode + # status => (not used yet...) # text => text to be printed # cmp => text used to compare (sort) nicks - # 'cached' settings -my ($screen_prefix, $irssi_width, @prefix_mode, @prefix_status, $height, $nicklist_width); +my ($screen_prefix, $irssi_width, %prefix_mode, @prefix_status, $height, $nicklist_width, $check_friends, @prefix_friends); sub read_settings { ($screen_prefix = Irssi::settings_get_str('nicklist_screen_prefix')) =~ s/\\e/\033/g; - ($prefix_mode[$MODE_OP] = Irssi::settings_get_str('nicklist_prefix_mode_op')) =~ s/\\e/\033/g; - ($prefix_mode[$MODE_HALFOP] = Irssi::settings_get_str('nicklist_prefix_mode_halfop')) =~ s/\\e/\033/g; - ($prefix_mode[$MODE_VOICE] = Irssi::settings_get_str('nicklist_prefix_mode_voice')) =~ s/\\e/\033/g; - ($prefix_mode[$MODE_NORMAL] = Irssi::settings_get_str('nicklist_prefix_mode_normal')) =~ s/\\e/\033/g; - + ($prefix_mode{'@'} = Irssi::settings_get_str('nicklist_prefix_mode_op')) =~ s/\\e/\033/g; + ($prefix_mode{'%'} = Irssi::settings_get_str('nicklist_prefix_mode_halfop')) =~ s/\\e/\033/g; + ($prefix_mode{'+'} = Irssi::settings_get_str('nicklist_prefix_mode_voice')) =~ s/\\e/\033/g; + ($prefix_mode{' '} = Irssi::settings_get_str('nicklist_prefix_mode_normal')) =~ s/\\e/\033/g; + + (my $prefix_mode_other = Irssi::settings_get_str('nicklist_prefix_mode_other')) =~ s/\\e/\033/g; + foreach my $p (split (/ /, $prefix_mode_other)) { + next if $p eq ''; + if ($p !~ /(.)=(.*)/) { + Irssi::print("Could not parse nicklist_prefix_mode_other part '$p'. Expected space separated list of ="); + last; + } else { + $prefix_mode{$1} = $2; + } + } + + (my $prefix_friends = Irssi::settings_get_str('nicklist_prefix_friends')) =~ s/\\e/\033/g; + foreach my $p (split (/ /, $prefix_friends)) { + next if $p eq ''; + if ($p !~ /(.+?)=(.*)/) { + Irssi::print("Could not parse nicklist_prefix_friends part '$p'. Expected space separated list of ="); + last; + } else { + push @prefix_friends, {'flags' => $1, 'prefix' => $2}; + } + } + + $check_friends = ($prefix_friends ne ''); + if ($mode != $SCREEN) { $height = Irssi::settings_get_int('nicklist_height'); } @@ -187,8 +226,11 @@ sub screen_stop { Irssi::signal_remove('gui page scrolled', \&sig_page_scrolled); Irssi::signal_remove('terminal resized', \&sig_terminal_resized); system 'screen -x '.$ENV{'STY'}.' -X fit'; + # we wait a second to make sure the fit command was processed + Irssi::timeout_add_once(1000, \&screen_size, []); } +#sub screen_size_real { sub screen_size { if ($mode != $SCREEN) { return; @@ -208,10 +250,10 @@ sub screen_size { # without this reloading doesn't work. workaround for some unknown bug do 'asm/ioctls.ph'; }; - + # ugly way not working, let's try something uglier, the dg-hack(tm) (constant for linux only?) if($@) { no strict 'refs'; *TIOCGWINSZ = sub { return 0x5413 } } - + unless (defined &TIOCGWINSZ) { die "Term::ReadKey not found, and ioctl 'workaround' failed. Install the Term::ReadKey perl module to use screen mode.\n"; } @@ -222,19 +264,14 @@ sub screen_size { close(TTY); ($row, $col, $xpixel, $ypixel) = unpack('S4', $winsize); } - + # set screen width $irssi_width = $col-$nicklist_width-1; $height = $row-1; - - # on some recent systems, "screen -X fit; screen -X width -w 50" doesn't work, needs a sleep in between the 2 commands - # so we wait a second before setting the width - Irssi::timeout_add_once(1000, sub { - my ($new_irssi_width) = @_; - system 'screen -x '.$ENV{'STY'}.' -X width -w ' . $new_irssi_width; - # and then we wait another second for the resizing, and then redraw. - Irssi::timeout_add_once(1000,sub {$screen_resizing = 0; redraw()}, []); - }, $irssi_width); + + system 'screen -x '.$ENV{'STY'}.' -X width -w ' . $irssi_width; + # wait another second for the resizing, and then redraw. + Irssi::timeout_add_once(1000,sub {$screen_resizing = 0; redraw()}, []); } sub sig_terminal_resized { @@ -278,13 +315,50 @@ sub nicklist_write_line { } } +sub calc_prefix_friends { + my ($nick) = @_; + + return '' unless $check_friends + && $nick->{'host'} + && is_friend($active_channel->{'server'}->{'chatnet'}, $active_channel->{'name'}, $nick->{'nick'}, $nick->{'host'}); + + my $flags = get_flags($active_channel->{'server'}->{'chatnet'}, $active_channel->{'name'}, $nick->{'nick'}, $nick->{'host'}); + + my $prefix; + foreach my $prefix_friend (@prefix_friends) { + if ($prefix_friend->{'flags'} eq 'noflag') { + if ($flags eq '') { + $prefix = $prefix_friend->{'prefix'}; + last; + } + } elsif (check_modes($flags, $prefix_friend->{'flags'})) { + $prefix = $prefix_friend->{'prefix'}; + } + } + + return $prefix ? $prefix : ''; +} + # recalc the text of the nicklist item sub calc_text { my ($nick) = @_; my $tmp = $nicklist_width-3; - (my $text = $nick->{'nick'}) =~ s/^(.{$tmp})..+$/$1\033[34m~\033[m/; - $nick->{'text'} = $prefix_mode[$nick->{'mode'}] . $text . (' ' x ($nicklist_width-length($nick->{'nick'})-1)); - $nick->{'cmp'} = $nick->{'mode'}.lc($nick->{'nick'}); + (my $text = $nick->{'nick'}) =~ s/^(.{$tmp})..+$/$1\033[34m~/; # strip nick if too long + + my $prefix_mode = $prefix_mode{$nick->{'modeflag'}}; + if (! defined($prefix_mode) ) { + $prefix_mode = $nick->{'modeflag'}; + } + + my $prefix_friends = calc_prefix_friends($nick); + + $nick->{'text'} = + $prefix_mode . + $prefix_friends . + $text . + (' ' x ($nicklist_width-length($nick->{'nick'})-1)) . + "\033[m"; # reset + $nick->{'cmp'} = $nick->{'modepos'}.lc($nick->{'nick'}); } # redraw the given nick (nr) if it is visible @@ -395,6 +469,95 @@ sub sig_gui_print_text_finished { } } +################### +##### FRIENDS ##### +################### + +# checks if $has_modes is in $need_modes, copied from trigger.pl +sub check_modes { + my ($has_modes, $need_modes) = @_; + my $matches; + my $switch = 1; # if a '-' if found, will be 0 (meaning the modes should not be set) + foreach my $need_mode (split /&/,$need_modes) { + $matches = 0; + foreach my $char (split //,$need_mode) { + if ($char eq '-') { + $switch = 0; + } elsif ($char eq '+') { + $switch = 1; + } elsif ((index($has_modes,$char) != -1) == $switch) { + $matches = 1; + last; + } + } + if (!$matches) { + return 0; + } + } + return 1; +} + +# get someones flags from people.pl or friends(_shasta).pl, copied from trigger.pl +sub get_flags { + my ($chatnet, $channel, $nick, $address) = @_; + my $flags; + no strict 'refs'; + if (%{ 'Irssi::Script::people::' }) { + if (defined ($channel)) { + $flags = (&{ 'Irssi::Script::people::find_local_flags' }($chatnet,$channel,$nick,$address)); + } else { + $flags = (&{ 'Irssi::Script::people::find_global_flags' }($chatnet,$nick,$address)); + } + $flags = join('',keys(%{$flags})); + } else { + my $shasta; + if (%{ 'Irssi::Script::friends_shasta::' }) { + $shasta = 'friends_shasta'; + } elsif (defined &{ 'Irssi::Script::friends::get_idx' }) { + $shasta = 'friends'; + } + if (!$shasta) { + return undef; + } + my $idx = (&{ 'Irssi::Script::'.$shasta.'::get_idx' }($nick,$address)); + if ($idx == -1) { + return ''; + } + $flags = (&{ 'Irssi::Script::'.$shasta.'::get_friends_flags' }($idx,undef)); + if ($channel) { + $flags .= (&{ 'Irssi::Script::'.$shasta.'::get_friends_flags' }($idx,$channel)); + } + } + return $flags; +} + +sub is_friend { + my ($chatnet, $channel, $nick, $address) = @_; + no strict 'refs'; + if (%{ 'Irssi::Script::people::' }) { + return (() != &{'Irssi::Script::people::find_users'}($chatnet, $nick, $address)); + my $flags; + if (defined ($channel)) { + $flags = (&{ 'Irssi::Script::people::find_local_flags' }($chatnet,$channel,$nick,$address)); + } else { + $flags = (&{ 'Irssi::Script::people::find_global_flags' }($chatnet,$nick,$address)); + } + return ($flags ne ''); # TODO: test this + } else { + my $shasta; + if (%{ 'Irssi::Script::friends_shasta::' }) { + $shasta = 'friends_shasta'; + } elsif (defined &{ 'Irssi::Script::friends::get_idx' }) { + $shasta = 'friends'; + } + if (!$shasta) { + return undef; + } + my $idx = (&{ 'Irssi::Script::'.$shasta.'::get_idx' }($nick,$address)); + return ($idx != -1); + } +} + #################### ##### NICKLIST ##### #################### @@ -435,13 +598,12 @@ sub make_nicklist { } else { $active_channel = $channel; ### make nicklist ### - my $thisnick; - foreach my $nick (sort {(($a->{'op'}?'1':$a->{'halfop'}?'2':$a->{'voice'}?'3':'4').lc($a->{'nick'})) - cmp (($b->{'op'}?'1':$b->{'halfop'}?'2':$b->{'voice'}?'3':'4').lc($b->{'nick'}))} $channel->nicks()) { - $thisnick = {'nick' => $nick->{'nick'}, 'mode' => ($nick->{'op'}?$MODE_OP:$nick->{'halfop'}?$MODE_HALFOP:$nick->{'voice'}?$MODE_VOICE:$MODE_NORMAL)}; - calc_text($thisnick); + foreach my $nick ($channel->nicks()) { + my $thisnick = {'nick' => $nick->{'nick'}}; + recalc_nick($thisnick, $nick); push @nicklist, $thisnick; } + @nicklist = sort {$a->{'cmp'} cmp $b->{'cmp'}} @nicklist; } need_redraw(); } @@ -462,21 +624,49 @@ sub remove_nick { draw_remove_nick_nr($nr); } +# update the mode and cmp of a nick, based on a nickrec from irssi +sub recalc_nick { + my ($nick, $nickrec) = @_; + if (! $nickrec) { + $nickrec = $active_channel->nick_find($nick->{'nick'}); + } + + my $nickflags = $active_channel->{'server'}->get_nick_flags() . ' '; + + my $flag = ( + $nickrec->{'op'} ? '@' : + $nickrec->{'halfop'} ? '%' : + $nickrec->{'voice'} ? '+' : + ' ' + ); + + if ($nickrec->{'other'} && index($nickflags, $nick->{'other'}) < index($nickflags, $flag)) { + $flag = chr($nickrec->{'other'}); + } + + $nick->{'modepos'} = index($nickflags, $flag); + $nick->{'modeflag'} = $flag; + + $nick->{'host'} = $nickrec->{'host'}; + calc_text($nick); +} + ################### ##### ACTIONS ##### ################### # scroll the nicklist, arg = number of lines to scroll, positive = down, negative = up sub cmd_scroll { + my $channel = Irssi::active_win->{active}; + my @nicks = $channel->nicks; + my $nick_count = scalar(@nicks)+0; + if (!$active_channel) { # not a channel active return; } - my $channel = Irssi::active_win->{active}; - if (!$channel || $channel->{type} ne 'CHANNEL' || !$channel->{names_got}) { + if (!$channel || $channel->{type} ne 'CHANNEL' || !$channel->{names_got} || $nick_count <= $height) { return; } - my @nicks = $channel->nicks; - my $nick_count = scalar(@nicks)+0; if ($nick_count <= Irssi::settings_get_int('nicklist_height')) { return; } @@ -508,8 +698,8 @@ sub sig_join { if (!is_active_channel($server,$channel)) { return; } - my $newnick = {'nick' => $nick, 'mode' => $MODE_NORMAL}; - calc_text($newnick); + my $newnick = {'nick' => $nick}; + recalc_nick($newnick); insert_nick($newnick); } @@ -577,8 +767,7 @@ sub sig_mode { } else { my $nicklist_item = $nicklist[$nr]; remove_nick($nr); - $nicklist_item->{'mode'} = ($nick->{'op'}?$MODE_OP:$nick->{'halfop'}?$MODE_HALFOP:$nick->{'voice'}?$MODE_VOICE:$MODE_NORMAL); - calc_text($nicklist_item); + recalc_nick($nicklist_item, $nick); insert_nick($nicklist_item); } } @@ -623,6 +812,8 @@ Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_op', '\e[32m@\e[39m'); Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_halfop', '\e[34m%\e[39m'); Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_voice', '\e[33m+\e[39m'); Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_normal', ' '); +Irssi::settings_add_str('nicklist', 'nicklist_prefix_mode_other', '&=\e[31m&\e[39m ~=\e[35m~\e[39m'); +Irssi::settings_add_str('nicklist', 'nicklist_prefix_friends', 'o=\e[32m v=\e[33m noflag=\e[1m'); Irssi::settings_add_int('nicklist', 'nicklist_width',11); Irssi::settings_add_int('nicklist', 'nicklist_height',24);