Now tracking irssi
This commit is contained in:
2954
home/.irssi/scripts/autorun/adv_windowlist.pl
Executable file
2954
home/.irssi/scripts/autorun/adv_windowlist.pl
Executable file
File diff suppressed because it is too large
Load Diff
88
home/.irssi/scripts/autorun/bitlbee_tab_completion.pl
Normal file
88
home/.irssi/scripts/autorun/bitlbee_tab_completion.pl
Normal file
@@ -0,0 +1,88 @@
|
||||
use strict;
|
||||
use vars qw($VERSION %IRSSI);
|
||||
|
||||
$VERSION = '1.3';
|
||||
|
||||
%IRSSI = (
|
||||
authors => 'Tijmen "timing" Ruizendaal & Wilmer van der Gaast',
|
||||
contact => 'tijmen.ruizendaal@gmail.com',
|
||||
name => 'BitlBee_tab_completion',
|
||||
description => 'Intelligent Tab-completion for BitlBee commands.',
|
||||
license => 'GPLv2',
|
||||
url => 'http://the-timing.nl/stuff/irssi-bitlbee',
|
||||
changed => '2009-08-11',
|
||||
);
|
||||
|
||||
my $root_nick = 'root';
|
||||
my $bitlbee_channel = '&bitlbee';
|
||||
my $bitlbee_server_tag = 'localhost';
|
||||
my $get_completions = 0;
|
||||
|
||||
my @commands;
|
||||
|
||||
Irssi::signal_add_last 'channel sync' => sub {
|
||||
my( $channel ) = @_;
|
||||
if( $channel->{topic} eq "Welcome to the control channel. Type \x02help\x02 for help information." ){
|
||||
$bitlbee_server_tag = $channel->{server}->{tag};
|
||||
$bitlbee_channel = $channel->{name};
|
||||
request_completions();
|
||||
}
|
||||
};
|
||||
|
||||
if (get_channel()) {
|
||||
request_completions();
|
||||
}
|
||||
|
||||
sub request_completions {
|
||||
$get_completions = 1;
|
||||
Irssi::server_find_tag($bitlbee_server_tag)->send_raw( 'COMPLETIONS' );
|
||||
}
|
||||
|
||||
sub get_channel {
|
||||
my @channels = Irssi::channels();
|
||||
foreach my $channel(@channels) {
|
||||
if ($channel->{topic} eq "Welcome to the control channel. Type \x02help\x02 for help information.") {
|
||||
$bitlbee_channel = $channel->{name};
|
||||
$bitlbee_server_tag = $channel->{server}->{tag};
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub irc_notice {
|
||||
return unless $get_completions;
|
||||
my( $server, $msg, $from, $address, $target ) = @_;
|
||||
|
||||
if( $msg =~ s/^COMPLETIONS // ) {
|
||||
$root_nick = $from;
|
||||
if( $msg eq 'OK' ) {
|
||||
@commands = ();
|
||||
}
|
||||
elsif( $msg eq 'END' ) {
|
||||
$get_completions = 0;
|
||||
}
|
||||
@commands = ( @commands, $msg );
|
||||
|
||||
Irssi::signal_stop();
|
||||
}
|
||||
}
|
||||
|
||||
sub complete_word {
|
||||
my ($complist, $window, $word, $linestart, $want_space) = @_;
|
||||
my $channel = $window->get_active_name();
|
||||
if ($channel eq $bitlbee_channel or $channel eq $root_nick or $linestart =~ /^\/(msg|query) \Q$root_nick\E */i){
|
||||
$linestart =~ s/^\/(msg|query) \Q$root_nick\E *//i;
|
||||
$linestart =~ s/^\Q$root_nick\E[:,] *//i;
|
||||
foreach my $command(@commands) {
|
||||
if ($command =~ /^$word/i) {
|
||||
push @$complist, $command;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Irssi::signal_add_last('complete word', 'complete_word');
|
||||
Irssi::signal_add_first('message irc notice', 'irc_notice');
|
||||
|
||||
115
home/.irssi/scripts/autorun/go.pl
Normal file
115
home/.irssi/scripts/autorun/go.pl
Normal file
@@ -0,0 +1,115 @@
|
||||
use strict;
|
||||
use vars qw($VERSION %IRSSI);
|
||||
use Irssi;
|
||||
use Irssi::Irc;
|
||||
|
||||
# Usage:
|
||||
# /script load go.pl
|
||||
# If you are in #irssi you can type /go #irssi or /go irssi or even /go ir ...
|
||||
# also try /go ir<tab> and /go <tab> (that's two spaces)
|
||||
#
|
||||
# The following settings exist:
|
||||
#
|
||||
# /SET go_match_case_sensitive [ON|OFF]
|
||||
# Match window/item names sensitively (the default). Turning this off
|
||||
# means e.g. "/go foo" would jump to a window named "Foobar", too.
|
||||
#
|
||||
# /SET go_match_anchored [ON|OFF]
|
||||
# Match window/names only at the start of the word (the default). Turning
|
||||
# this off will mean that strings can match anywhere in the window/names.
|
||||
# The leading '#' of channel names is optional either way.
|
||||
#
|
||||
# /SET go_complete_case_sensitive [ON|OFF]
|
||||
# When using tab-completion, match case-insensitively (the default).
|
||||
# Turning this on means that "/go foo<tab>" will *not* suggest "Foobar".
|
||||
#
|
||||
# /SET go_complete_anchored [ON|OFF]
|
||||
# Match window/names only at the start of the word. The default is 'off',
|
||||
# which causes completion to match anywhere in the window/names during
|
||||
# completion. The leading '#' of channel names is optional either way.
|
||||
#
|
||||
|
||||
$VERSION = '1.1.1';
|
||||
|
||||
%IRSSI = (
|
||||
authors => 'nohar',
|
||||
contact => 'nohar@freenode',
|
||||
name => 'go to window',
|
||||
description => 'Implements /go command that activates a window given a name/partial name. It features a nice completion.',
|
||||
license => 'GPLv2 or later',
|
||||
changed => '2019-02-25'
|
||||
);
|
||||
|
||||
sub _make_regexp {
|
||||
my ($name, $ci, $aw) = @_;
|
||||
my $re = "\Q${name}\E";
|
||||
$re = "(?i:$re)" unless $ci;
|
||||
$re = "^#?$re" if $aw;
|
||||
return $re;
|
||||
}
|
||||
|
||||
sub signal_complete_go {
|
||||
my ($complist, $window, $word, $linestart, $want_space) = @_;
|
||||
my $channel = $window->get_active_name();
|
||||
my $k = Irssi::parse_special('$k');
|
||||
|
||||
return unless ($linestart =~ /^\Q${k}\Ego\b/i);
|
||||
|
||||
my $re = _make_regexp($word,
|
||||
Irssi::settings_get_bool('go_complete_case_sensitive'),
|
||||
Irssi::settings_get_bool('go_complete_anchored'));
|
||||
@$complist = ();
|
||||
foreach my $w (Irssi::windows) {
|
||||
my $name = $w->get_active_name();
|
||||
if ($word ne "") {
|
||||
if ($name =~ $re) {
|
||||
push(@$complist, $name)
|
||||
}
|
||||
} else {
|
||||
push(@$complist, $name);
|
||||
}
|
||||
}
|
||||
Irssi::signal_stop();
|
||||
};
|
||||
|
||||
sub cmd_go
|
||||
{
|
||||
my($chan,$server,$witem) = @_;
|
||||
|
||||
my $case_sensitive = Irssi::settings_get_bool('go_match_case_sensitive');
|
||||
my $match_anchored = Irssi::settings_get_bool('go_match_anchored');
|
||||
|
||||
$chan =~ s/ *//g;
|
||||
my $re = _make_regexp($chan, $case_sensitive, $match_anchored);
|
||||
|
||||
my @matches;
|
||||
foreach my $w (Irssi::windows) {
|
||||
my $name = $w->get_active_name();
|
||||
if (($case_sensitive && $name eq $chan) ||
|
||||
(!$case_sensitive && CORE::fc $name eq CORE::fc $chan)) {
|
||||
$w->set_active();
|
||||
return;
|
||||
} elsif ($name =~ /$re/) {
|
||||
push(@matches, $w);
|
||||
}
|
||||
}
|
||||
if (@matches) {
|
||||
$matches[0]->set_active();
|
||||
}
|
||||
}
|
||||
|
||||
Irssi::command_bind("go", "cmd_go");
|
||||
Irssi::signal_add_first('complete word', 'signal_complete_go');
|
||||
Irssi::settings_add_bool('go', 'go_match_case_sensitive', 1);
|
||||
Irssi::settings_add_bool('go', 'go_complete_case_sensitive', 0);
|
||||
Irssi::settings_add_bool('go', 'go_match_anchored', 1);
|
||||
Irssi::settings_add_bool('go', 'go_complete_anchored', 0);
|
||||
|
||||
# Changelog
|
||||
#
|
||||
# 2017-02-02 1.1 martin f. krafft <madduck@madduck.net>
|
||||
# - made case-sensitivity of match configurable
|
||||
# - made anchoring of search strings configurable
|
||||
#
|
||||
# 2019-02-025 1.1.1 dylan lloyd <dylan@disinclined.org>
|
||||
# - prefer exact channel matches
|
||||
113
home/.irssi/scripts/autorun/highlite.pl
Normal file
113
home/.irssi/scripts/autorun/highlite.pl
Normal file
@@ -0,0 +1,113 @@
|
||||
use strict;
|
||||
use Irssi;
|
||||
use Irssi::Irc;
|
||||
|
||||
use vars qw($VERSION %IRSSI);
|
||||
|
||||
$VERSION = "1.0";
|
||||
%IRSSI = (
|
||||
"authors" => "Mantis",
|
||||
"contact" => "mantis\@inta-link.com",
|
||||
"name" => "highlite",
|
||||
"description" => "shows events happening in all channels you are in that may concern you",
|
||||
"url" => "http://www.inta-link.com/",
|
||||
"license" => "GNU GPL v2",
|
||||
"changed" => "2003-01-03"
|
||||
);
|
||||
|
||||
sub msg_join
|
||||
{
|
||||
my ($server, $channame, $nick, $host) = @_;
|
||||
$channame =~ s/^://;
|
||||
|
||||
my $windowname = Irssi::window_find_name('highlite');
|
||||
$windowname->print("%B%0JOIN : " . $nick . " : " . $channame . " : " . $host, MSGLEVEL_CLIENTCRAP) if ($windowname);
|
||||
}
|
||||
|
||||
sub msg_part
|
||||
{
|
||||
my ($server, $channame, $nick, $host) = @_;
|
||||
$channame =~ s/^://;
|
||||
|
||||
my $windowname = Irssi::window_find_name('highlite');
|
||||
$windowname->print("%b%0PART : " . $nick . " : " . $channame . " : " . $host, MSGLEVEL_CLIENTCRAP) if ($windowname);
|
||||
}
|
||||
|
||||
sub msg_quit
|
||||
{
|
||||
my ($server, $nick, $host, $quitmsg) = @_;
|
||||
|
||||
if (substr($quitmsg, 0, 14) eq "Read error to ")
|
||||
{
|
||||
$quitmsg = "[ General Read Error ]";
|
||||
}
|
||||
if (substr($quitmsg, 0, 17) eq "Ping timeout for ")
|
||||
{
|
||||
$quitmsg = "[ General Ping Timeout Error ]";
|
||||
}
|
||||
|
||||
my $windowname = Irssi::window_find_name('highlite');
|
||||
$windowname->print("%R%0QUIT : " . $nick . " : " . $host . " : " . $quitmsg, MSGLEVEL_CLIENTCRAP) if ($windowname);
|
||||
|
||||
$quitmsg = "";
|
||||
}
|
||||
|
||||
sub msg_topic
|
||||
{
|
||||
my ($server, $channame, $topicmsg, $nick, $host) = @_;
|
||||
$channame =~ s/^://;
|
||||
|
||||
my $windowname = Irssi::window_find_name('highlite');
|
||||
$windowname->print("%G%0TOPIC : " . $nick . " : " . $channame . " : " . $topicmsg, MSGLEVEL_CLIENTCRAP) if ($windowname);
|
||||
}
|
||||
|
||||
sub msg_nick
|
||||
{
|
||||
my ($server, $nick, $old_nick, $host) = @_;
|
||||
|
||||
my $windowname = Irssi::window_find_name('highlite');
|
||||
$windowname->print("%m%0NICK : " . $old_nick . " : " . $nick . " : " . $host, MSGLEVEL_CLIENTCRAP) if ($windowname);
|
||||
}
|
||||
|
||||
sub msg_kick
|
||||
{
|
||||
my ($server, $channame, $kicked, $nick, $host, $reason) = @_;
|
||||
$channame =~ s/^://;
|
||||
|
||||
my $windowname = Irssi::window_find_name('highlite');
|
||||
$windowname->print("%Y%0KICK : " . $kicked . " : " . $channame . " : " . $nick . " : " . $reason, MSGLEVEL_CLIENTCRAP) if ($windowname);
|
||||
}
|
||||
|
||||
sub sig_printtext {
|
||||
my ($dest, $text, $stripped) = @_;
|
||||
|
||||
if (($dest->{level} & (MSGLEVEL_HILIGHT|MSGLEVEL_MSGS)) && ($dest->{level} & MSGLEVEL_NOHILIGHT) == 0)
|
||||
{
|
||||
if ($dest->{level} & MSGLEVEL_PUBLIC)
|
||||
{
|
||||
my $windowname = Irssi::window_find_name('highlite');
|
||||
|
||||
$windowname->print("%W%0HIGHLITE : " . $dest->{target} . " : " . $text, MSGLEVEL_CLIENTCRAP) if ($windowname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $windowname = Irssi::window_find_name('highlite');
|
||||
if (!$windowname)
|
||||
{
|
||||
Irssi::command("window new hidden");
|
||||
Irssi::command("window name highlite");
|
||||
}
|
||||
|
||||
Irssi::signal_add(
|
||||
{
|
||||
'message join' => \&msg_join,
|
||||
'message part' => \&msg_part,
|
||||
'message quit' => \&msg_quit,
|
||||
'message topic' => \&msg_topic,
|
||||
'print text', 'sig_printtext',
|
||||
'message nick' => \&msg_nick,
|
||||
'message kick' => \&msg_kick
|
||||
}
|
||||
);
|
||||
|
||||
1165
home/.irssi/scripts/autorun/ido_switcher.pl
Normal file
1165
home/.irssi/scripts/autorun/ido_switcher.pl
Normal file
File diff suppressed because it is too large
Load Diff
253
home/.irssi/scripts/autorun/nickcolor.pl
Normal file
253
home/.irssi/scripts/autorun/nickcolor.pl
Normal file
@@ -0,0 +1,253 @@
|
||||
use strict;
|
||||
use Irssi 20020101.0250 ();
|
||||
use vars qw($VERSION %IRSSI);
|
||||
$VERSION = "2.1";
|
||||
%IRSSI = (
|
||||
authors => "Timo Sirainen, Ian Peters, David Leadbeater, Bruno Cattáneo",
|
||||
contact => "tss\@iki.fi",
|
||||
name => "Nick Color",
|
||||
description => "assign a different color for each nick",
|
||||
license => "Public Domain",
|
||||
url => "http://irssi.org/",
|
||||
changed => "Mon 08 Jan 21:28:53 BST 2018",
|
||||
);
|
||||
|
||||
# Settings:
|
||||
# nickcolor_colors: List of color codes to use.
|
||||
# e.g. /set nickcolor_colors 2 3 4 5 6 7 9 10 11 12 13
|
||||
# (avoid 8, as used for hilights in the default theme).
|
||||
#
|
||||
# nickcolor_enable_prefix: Enables prefix for same nick.
|
||||
#
|
||||
# nickcolor_enable_truncate: Enables nick truncation.
|
||||
#
|
||||
# nickcolor_prefix_text: Prefix text for succesive messages.
|
||||
# e.g. /set nickcolor_prefix_text -
|
||||
#
|
||||
# nickcolor_truncate_value: Truncate nick value.
|
||||
# e.g. /set nickcolor_truncate_value -7
|
||||
# This will truncate nicknames at 7 characters and make them right aligned
|
||||
|
||||
my %saved_colors;
|
||||
my %session_colors = {};
|
||||
my %saved_nicks; # To store each channel's last nickname
|
||||
|
||||
sub load_colors {
|
||||
open my $color_fh, "<", "$ENV{HOME}/.irssi/saved_colors";
|
||||
while (<$color_fh>) {
|
||||
chomp;
|
||||
my($nick, $color) = split ":";
|
||||
$saved_colors{$nick} = $color;
|
||||
}
|
||||
}
|
||||
|
||||
sub save_colors {
|
||||
open COLORS, ">", "$ENV{HOME}/.irssi/saved_colors";
|
||||
|
||||
foreach my $nick (keys %saved_colors) {
|
||||
print COLORS "$nick:$saved_colors{$nick}\n";
|
||||
}
|
||||
|
||||
close COLORS;
|
||||
}
|
||||
|
||||
# If someone we've colored (either through the saved colors, or the hash
|
||||
# function) changes their nick, we'd like to keep the same color associated
|
||||
# with them (but only in the session_colors, ie a temporary mapping).
|
||||
|
||||
sub sig_nick {
|
||||
my ($server, $newnick, $nick, $address) = @_;
|
||||
my $color;
|
||||
|
||||
$newnick = substr ($newnick, 1) if ($newnick =~ /^:/);
|
||||
|
||||
if ($color = $saved_colors{$nick}) {
|
||||
$session_colors{$newnick} = $color;
|
||||
} elsif ($color = $session_colors{$nick}) {
|
||||
$session_colors{$newnick} = $color;
|
||||
}
|
||||
}
|
||||
|
||||
# This gave reasonable distribution values when run across
|
||||
# /usr/share/dict/words
|
||||
|
||||
sub simple_hash {
|
||||
my ($string) = @_;
|
||||
chomp $string;
|
||||
my @chars = split //, $string;
|
||||
my $counter;
|
||||
|
||||
foreach my $char (@chars) {
|
||||
$counter += ord $char;
|
||||
}
|
||||
|
||||
my @colors = split / /, Irssi::settings_get_str('nickcolor_colors');
|
||||
$counter = $colors[$counter % @colors];
|
||||
|
||||
return $counter;
|
||||
}
|
||||
|
||||
# process public (others) messages
|
||||
sub sig_public {
|
||||
my ($server, $msg, $nick, $address, $target) = @_;
|
||||
|
||||
my $enable_prefix = Irssi::settings_get_bool('nickcolor_enable_prefix');
|
||||
my $enable_truncate = Irssi::settings_get_bool('nickcolor_enable_truncate');
|
||||
my $prefix_text = Irssi::settings_get_str('nickcolor_prefix_text');
|
||||
my $truncate_value = Irssi::settings_get_int('nickcolor_truncate_value');
|
||||
|
||||
# Reference for server/channel
|
||||
my $tagtarget = "$server->{tag}/$target";
|
||||
|
||||
# Set default nick truncate value to 0 if option is disabled
|
||||
$truncate_value = 0 if (!$enable_truncate);
|
||||
|
||||
# Has the user assigned this nick a color?
|
||||
my $color = $saved_colors{$nick};
|
||||
|
||||
# Have -we- already assigned this nick a color?
|
||||
if (!$color) {
|
||||
$color = $session_colors{$nick};
|
||||
}
|
||||
|
||||
# Let's assign this nick a color
|
||||
if (!$color) {
|
||||
$color = simple_hash $nick;
|
||||
$session_colors{$nick} = $color;
|
||||
}
|
||||
|
||||
$color = sprintf "\003%02d", $color;
|
||||
|
||||
# Optional: We check if it's the same nickname for current target
|
||||
if ($saved_nicks{$tagtarget} eq $nick && $enable_prefix)
|
||||
{
|
||||
# Grouped message
|
||||
Irssi::command('/^format pubmsg ' . $prefix_text . '$1');
|
||||
}
|
||||
else
|
||||
{
|
||||
# Normal message
|
||||
Irssi::command('/^format pubmsg {pubmsgnick $2 {pubnick ' . $color . '$[' . $truncate_value . ']0}}$1');
|
||||
|
||||
# Save nickname for next message
|
||||
$saved_nicks{$tagtarget} = $nick;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# process public (me) messages
|
||||
sub sig_me {
|
||||
my ($server, $msg, $target) = @_;
|
||||
my $nick = $server->{nick};
|
||||
|
||||
my $enable_prefix = Irssi::settings_get_bool('nickcolor_enable_prefix');
|
||||
my $enable_truncate = Irssi::settings_get_bool('nickcolor_enable_truncate');
|
||||
my $prefix_text = Irssi::settings_get_str('nickcolor_prefix_text');
|
||||
my $truncate_value = Irssi::settings_get_int('nickcolor_truncate_value');
|
||||
|
||||
# Reference for server/channel
|
||||
my $tagtarget = "$server->{tag}/$target";
|
||||
|
||||
# Set default nick truncate value to 0 if option is disabled
|
||||
$truncate_value = 0 if (!$enable_truncate);
|
||||
|
||||
# Optional: We check if it's the same nickname for current target
|
||||
if ($saved_nicks{$tagtarget} eq $nick && $enable_prefix)
|
||||
{
|
||||
# Grouped message
|
||||
Irssi::command('/^format own_msg ' . $prefix_text . '$1');
|
||||
}
|
||||
else
|
||||
{
|
||||
# Normal message
|
||||
Irssi::command('/^format own_msg {ownmsgnick $2 {ownnick $[' . $truncate_value . ']0}}$1');
|
||||
|
||||
# Save nickname for next message
|
||||
$saved_nicks{$tagtarget} = $nick;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# process public (others) actions
|
||||
sub sig_action_public {
|
||||
my ($server, $msg, $nick, $address, $target) = @_;
|
||||
|
||||
my $enable_prefix = Irssi::settings_get_bool('nickcolor_enable_prefix');
|
||||
|
||||
# Reference for server/channel
|
||||
my $tagtarget = "$server->{tag}/$target";
|
||||
|
||||
# Empty current target nick if prefix option is enabled
|
||||
$saved_nicks{$tagtarget} = '' if ($enable_prefix);
|
||||
|
||||
}
|
||||
|
||||
# process public (me) actions
|
||||
sub sig_action_me {
|
||||
my ($server, $msg, $target) = @_;
|
||||
my $nick = $server->{nick};
|
||||
|
||||
my $enable_prefix = Irssi::settings_get_bool('nickcolor_enable_prefix');
|
||||
|
||||
# Reference for server/channel
|
||||
my $tagtarget = "$server->{tag}/$target";
|
||||
|
||||
# Empty current target nick if prefix option is enabled
|
||||
$saved_nicks{$tagtarget} = '' if ($enable_prefix);
|
||||
|
||||
}
|
||||
|
||||
sub cmd_color {
|
||||
my ($data, $server, $witem) = @_;
|
||||
my ($op, $nick, $color) = split " ", $data;
|
||||
|
||||
$op = lc $op;
|
||||
|
||||
if (!$op) {
|
||||
Irssi::print ("No operation given (save/set/clear/list/preview)");
|
||||
} elsif ($op eq "save") {
|
||||
save_colors;
|
||||
} elsif ($op eq "set") {
|
||||
if (!$nick) {
|
||||
Irssi::print ("Nick not given");
|
||||
} elsif (!$color) {
|
||||
Irssi::print ("Color not given");
|
||||
} elsif ($color < 2 || $color > 14) {
|
||||
Irssi::print ("Color must be between 2 and 14 inclusive");
|
||||
} else {
|
||||
$saved_colors{$nick} = $color;
|
||||
}
|
||||
} elsif ($op eq "clear") {
|
||||
if (!$nick) {
|
||||
Irssi::print ("Nick not given");
|
||||
} else {
|
||||
delete ($saved_colors{$nick});
|
||||
}
|
||||
} elsif ($op eq "list") {
|
||||
Irssi::print ("\nSaved Colors:");
|
||||
foreach my $nick (keys %saved_colors) {
|
||||
Irssi::print (chr (3) . sprintf("%02d", $saved_colors{$nick}) . "$nick" .
|
||||
chr (3) . "1 ($saved_colors{$nick})");
|
||||
}
|
||||
} elsif ($op eq "preview") {
|
||||
Irssi::print ("\nAvailable colors:");
|
||||
foreach my $i (2..14) {
|
||||
Irssi::print (chr (3) . "$i" . "Color #$i");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
load_colors;
|
||||
|
||||
Irssi::settings_add_str('misc', 'nickcolor_colors', '2 3 4 5 6 7 9 10 11 12 13');
|
||||
Irssi::settings_add_bool('misc', 'nickcolor_enable_prefix', 0);
|
||||
Irssi::settings_add_bool('misc', 'nickcolor_enable_truncate', 0);
|
||||
Irssi::settings_add_str('misc', 'nickcolor_prefix_text' => '- ');
|
||||
Irssi::settings_add_int('misc', 'nickcolor_truncate_value' => 0);
|
||||
Irssi::command_bind('color', 'cmd_color');
|
||||
|
||||
Irssi::signal_add('message public', 'sig_public');
|
||||
Irssi::signal_add('message own_public', 'sig_me');
|
||||
Irssi::signal_add('message irc action', 'sig_action_public');
|
||||
Irssi::signal_add('message irc own_action', 'sig_action_me');
|
||||
Irssi::signal_add('event nick', 'sig_nick');
|
||||
248
home/.irssi/scripts/autorun/screen_away.pl
Normal file
248
home/.irssi/scripts/autorun/screen_away.pl
Normal file
@@ -0,0 +1,248 @@
|
||||
use Irssi;
|
||||
use strict;
|
||||
use FileHandle;
|
||||
|
||||
use vars qw($VERSION %IRSSI);
|
||||
|
||||
$VERSION = "0.9.8.2";
|
||||
%IRSSI = (
|
||||
authors => 'Andreas \'ads\' Scherbaum <ads@wars-nicht.de>',
|
||||
name => 'screen_away',
|
||||
description => 'set (un)away, if screen is attached/detached',
|
||||
license => 'GPL v2',
|
||||
url => 'none',
|
||||
);
|
||||
|
||||
# screen_away irssi module
|
||||
#
|
||||
# written by Andreas 'ads' Scherbaum <ads@ufp.de>
|
||||
#
|
||||
# changes:
|
||||
# 20.12.2014 fix the bug when screenname is changed during the session
|
||||
# 07.02.2004 fix error with away mode
|
||||
# thanks to Michael Schiansky for reporting and fixing this one
|
||||
# 07.08.2004 new function for changing nick on away
|
||||
# 24.08.2004 fixing bug where the away nick was not storedcorrectly
|
||||
# thanks for Harald Wurpts for help debugging this one
|
||||
# 17.09.2004 rewrote init part to use $ENV{'STY'}
|
||||
# 05.12.2004 add patch for remember away state
|
||||
# thanks to Jilles Tjoelker <jilles@stack.nl>
|
||||
# change "chatnet" to "tag"
|
||||
# 18.05.2007 fix '-one' for SILC networks
|
||||
#
|
||||
#
|
||||
# usage:
|
||||
#
|
||||
# put this script into your autorun directory and/or load it with
|
||||
# /SCRIPT LOAD <name>
|
||||
#
|
||||
# there are 5 settings available:
|
||||
#
|
||||
# /set screen_away_active ON/OFF/TOGGLE
|
||||
# /set screen_away_repeat <integer>
|
||||
# /set screen_away_message <string>
|
||||
# /set screen_away_window <string>
|
||||
# /set screen_away_nick <string>
|
||||
#
|
||||
# active means, that you will be only set away/unaway, if this
|
||||
# flag is set, default is ON
|
||||
# repeat is the number of seconds, after the script will check the
|
||||
# screen status again, default is 5 seconds
|
||||
# message is the away message sent to the server, default: not here ...
|
||||
# window is a window number or name, if set, the script will switch
|
||||
# to this window, if it sets you away, default is '1'
|
||||
# nick is the new nick, if the script goes away
|
||||
# will only be used it not empty
|
||||
#
|
||||
# normal you should be able to rename the script to something other
|
||||
# than 'screen_away' (as example, if you dont like the name) by simple
|
||||
# changing the 'name' parameter in the %IRSSI hash at the top of this script
|
||||
|
||||
|
||||
# variables
|
||||
my $timer_name = undef;
|
||||
my $away_status = 0;
|
||||
my %old_nicks = ();
|
||||
my %away = ();
|
||||
|
||||
# Register formats
|
||||
Irssi::theme_register(
|
||||
[
|
||||
'screen_away_crap',
|
||||
'{line_start}{hilight ' . $IRSSI{'name'} . ':} $0'
|
||||
]);
|
||||
|
||||
# if we are running
|
||||
my $screen_away_used = 0;
|
||||
|
||||
# try to find out, if we are running in a screen
|
||||
# (see, if $ENV{STY} is set
|
||||
if (!defined($ENV{STY})) {
|
||||
# just return, we will never be called again
|
||||
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'screen_away_crap',
|
||||
"could not open status file for parent process (pid: " . getppid() . "): $!");
|
||||
return;
|
||||
}
|
||||
|
||||
my ($socket_pid, $socket_name, $socket_path);
|
||||
|
||||
# search for socket
|
||||
# normal we could search the socket file, ... if we know the path
|
||||
# but so we have to call one time the screen executable
|
||||
# disable locale
|
||||
# the quotes around C force perl 5.005_03 to use the shell
|
||||
# thanks to Jilles Tjoelker <jilles@stack.nl> for pointing this out
|
||||
my $socket = `LC_ALL="C" screen -ls`;
|
||||
|
||||
|
||||
|
||||
my $running_in_screen = 0;
|
||||
# locale doesnt seems to be an problem (yet)
|
||||
if ($socket !~ /^No Sockets found/s) {
|
||||
# ok, should have only one socket
|
||||
# $STY won't change if sessionname is changed during session
|
||||
# therefore first find the pid and use that to find the actual sessionname
|
||||
$socket_pid = substr($ENV{'STY'}, 0, index($ENV{'STY'}, '.'));
|
||||
$socket_path = $socket;
|
||||
$socket_path =~ s/^.*\d+ Sockets? in ([^\n]+)\..*$/$1/s;
|
||||
$socket_name = $socket;
|
||||
$socket_name =~ s/^.+?($socket_pid\.\S+).+$/$1/s;
|
||||
if (length($socket_path) != length($socket)) {
|
||||
# only activate, if string length is different
|
||||
# (to make sure, we really got a dir name)
|
||||
$screen_away_used = 1;
|
||||
} else {
|
||||
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'screen_away_crap',
|
||||
"error reading screen informations from:");
|
||||
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'screen_away_crap',
|
||||
"$socket");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# last check
|
||||
if ($screen_away_used == 0) {
|
||||
# we will never be called again
|
||||
return;
|
||||
}
|
||||
|
||||
# build complete socket name
|
||||
$socket = $socket_path . "/" . $socket_name;
|
||||
|
||||
# register config variables
|
||||
Irssi::settings_add_bool('misc', $IRSSI{'name'} . '_active', 1);
|
||||
Irssi::settings_add_int('misc', $IRSSI{'name'} . '_repeat', 5);
|
||||
Irssi::settings_add_str('misc', $IRSSI{'name'} . '_message', "not here ...");
|
||||
Irssi::settings_add_str('misc', $IRSSI{'name'} . '_window', "1");
|
||||
Irssi::settings_add_str('misc', $IRSSI{'name'} . '_nick', "");
|
||||
|
||||
# init process
|
||||
screen_away();
|
||||
|
||||
# screen_away()
|
||||
#
|
||||
# check, set or reset the away status
|
||||
#
|
||||
# parameter:
|
||||
# none
|
||||
# return:
|
||||
# 0 (OK)
|
||||
sub screen_away {
|
||||
my ($away, @screen, $screen);
|
||||
|
||||
# only run, if activated
|
||||
if (Irssi::settings_get_bool($IRSSI{'name'} . '_active') == 1) {
|
||||
if ($away_status == 0) {
|
||||
# display init message at first time
|
||||
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'screen_away_crap',
|
||||
"activating $IRSSI{'name'} (interval: " . Irssi::settings_get_int($IRSSI{'name'} . '_repeat') . " seconds)");
|
||||
}
|
||||
# get actual screen status
|
||||
my @screen = stat($socket);
|
||||
# 00100 is the mode for "user has execute permissions", see stat.h
|
||||
if (($screen[2] & 00100) == 0) {
|
||||
# no execute permissions, Detached
|
||||
$away = 1;
|
||||
} else {
|
||||
# execute permissions, Attached
|
||||
$away = 2;
|
||||
}
|
||||
|
||||
# check if status has changed
|
||||
if ($away == 1 and $away_status != 1) {
|
||||
# set away
|
||||
if (length(Irssi::settings_get_str($IRSSI{'name'} . '_window')) > 0) {
|
||||
# if length of window is greater then 0, make this window active
|
||||
Irssi::command('window goto ' . Irssi::settings_get_str($IRSSI{'name'} . '_window'));
|
||||
}
|
||||
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'screen_away_crap',
|
||||
"Set away");
|
||||
my $message = Irssi::settings_get_str($IRSSI{'name'} . '_message');
|
||||
if (length($message) == 0) {
|
||||
# we have to set a message or we wouldnt go away
|
||||
$message = "not here ...";
|
||||
}
|
||||
my ($server);
|
||||
foreach $server (Irssi::servers()) {
|
||||
if (!$server->{usermode_away}) {
|
||||
# user isnt yet away
|
||||
$away{$server->{'tag'}} = 0;
|
||||
$server->command("AWAY " . (($server->{chat_type} ne 'SILC') ? "-one " : "") . "$message") if (!$server->{usermode_away});
|
||||
if (length(Irssi::settings_get_str($IRSSI{'name'} . '_nick')) > 0) {
|
||||
# only change, if actual nick isnt already the away nick
|
||||
if (Irssi::settings_get_str($IRSSI{'name'} . '_nick') ne $server->{nick}) {
|
||||
# keep old nick
|
||||
$old_nicks{$server->{'tag'}} = $server->{nick};
|
||||
# set new nick
|
||||
$server->command("NICK " . Irssi::settings_get_str($IRSSI{'name'} . '_nick'));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# user is already away, remember this
|
||||
$away{$server->{'tag'}} = 1;
|
||||
}
|
||||
}
|
||||
$away_status = $away;
|
||||
} elsif ($away == 2 and $away_status != 2) {
|
||||
# unset away
|
||||
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'screen_away_crap',
|
||||
"Reset away");
|
||||
my ($server);
|
||||
foreach $server (Irssi::servers()) {
|
||||
if ($away{$server->{'tag'}} == 1) {
|
||||
# user was already away, dont reset away
|
||||
$away{$server->{'tag'}} = 0;
|
||||
next;
|
||||
}
|
||||
$server->command("AWAY" . (($server->{chat_type} ne 'SILC') ? " -one" : "")) if ($server->{usermode_away});
|
||||
if (defined($old_nicks{$server->{'tag'}}) and length($old_nicks{$server->{'tag'}}) > 0) {
|
||||
# set old nick
|
||||
$server->command("NICK " . $old_nicks{$server->{'tag'}});
|
||||
$old_nicks{$server->{'tag'}} = "";
|
||||
}
|
||||
}
|
||||
$away_status = $away;
|
||||
}
|
||||
}
|
||||
# but everytimes install a new timer
|
||||
register_screen_away_timer();
|
||||
return 0;
|
||||
}
|
||||
|
||||
# register_screen_away_timer()
|
||||
#
|
||||
# remove old timer and install a new one
|
||||
#
|
||||
# parameter:
|
||||
# none
|
||||
# return:
|
||||
# none
|
||||
sub register_screen_away_timer {
|
||||
if (defined($timer_name)) {
|
||||
# remove old timer, if defined
|
||||
Irssi::timeout_remove($timer_name);
|
||||
}
|
||||
# add new timer with new timeout (maybe the timeout has been changed)
|
||||
$timer_name = Irssi::timeout_add(Irssi::settings_get_int($IRSSI{'name'} . '_repeat') * 1000, 'screen_away', '');
|
||||
}
|
||||
|
||||
433
home/.irssi/scripts/autorun/tmux-nicklist-portable.pl
Executable file
433
home/.irssi/scripts/autorun/tmux-nicklist-portable.pl
Executable file
@@ -0,0 +1,433 @@
|
||||
# based on the nicklist.pl script
|
||||
################################################################################
|
||||
# tmux_nicklist.pl
|
||||
# This script integrates tmux and irssi to display a list of nicks in a
|
||||
# vertical right pane with 20% width. Right now theres no configuration
|
||||
# or setup, simply initialize the script with irssi and by default you
|
||||
# will get the nicklist for every channel(customize by altering
|
||||
# the regex in /set nicklist_channel_re)
|
||||
#
|
||||
# /set nicklist_channel_re <regex>
|
||||
# * only show on channels matching this regular expression
|
||||
#
|
||||
# /set nicklist_max_users <num>
|
||||
# * only show when the channel has so many users or less (0 = always)
|
||||
#
|
||||
# /set nicklist_smallest_main <num>
|
||||
# * only show when main window is larger than this (0 = always)
|
||||
#
|
||||
# /set nicklist_pane_width <num>
|
||||
# * width of the nicklist pane
|
||||
#
|
||||
# /set nicklist_color <ON|OFF>
|
||||
# * colourise the nicks in the nicklist (required nickcolor script
|
||||
# with get_nick_color2 and debug_ansicolour functions)
|
||||
#
|
||||
# /set nicklist_gone_sort <ON|OFF>
|
||||
# * sort away people below
|
||||
#
|
||||
# It supports mouse scrolling and the following keys:
|
||||
# k/up arrow: up one line
|
||||
# j/down arrow: down one line
|
||||
# u/pageup: up 50% lines
|
||||
# d/pagedown: down 50% lines
|
||||
# gg: go to top
|
||||
# G: go to bottom
|
||||
#
|
||||
# For better integration, unrecognized sequences will be sent to irssi and
|
||||
# its pane will be focused.
|
||||
#
|
||||
# to toggle the nicklist if it is in the way you can make a key binding:
|
||||
# /bind meta-Z /script exec Irssi::Script::tmux_nicklist_portable::toggle_nicklist
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use IO::Handle;
|
||||
use IO::Select;
|
||||
use POSIX;
|
||||
use File::Temp qw/ :mktemp /;
|
||||
use File::Basename;
|
||||
our $VERSION = '0.1.8';
|
||||
our %IRSSI = (
|
||||
authors => 'Thiago de Arruda',
|
||||
contact => 'tpadilha84@gmail.com',
|
||||
name => 'tmux-nicklist',
|
||||
description => 'displays a list of nicks in a separate tmux pane',
|
||||
license => 'WTFPL',
|
||||
);
|
||||
|
||||
# "other" prefixes by danielg4 <daniel@gimpelevich.san-francisco.ca.us>
|
||||
# added 'd' and 'u' navigation as in vim, by @gerardbm (github)
|
||||
|
||||
{ package Irssi::Nick }
|
||||
|
||||
if ($#ARGV == -1) {
|
||||
require Irssi;
|
||||
|
||||
my $enabled = 0;
|
||||
my $nicklist_toggle = 1;
|
||||
my $script_path = __FILE__;
|
||||
my $tmpdir;
|
||||
my $fifo_path;
|
||||
my $fifo;
|
||||
my $just_launched;
|
||||
my $resize_timer;
|
||||
|
||||
sub enable_nicklist {
|
||||
return if ($enabled);
|
||||
$tmpdir = mkdtemp Irssi::get_irssi_dir()."/nicklist-XXXXXXXX";
|
||||
$fifo_path = "$tmpdir/fifo";
|
||||
POSIX::mkfifo($fifo_path, 0600) or die "can't mkfifo $fifo_path: $!";
|
||||
my $cmd = "perl $script_path $fifo_path $ENV{TMUX_PANE}";
|
||||
#my $width = Irssi::settings_get_int('nicklist_pane_width');
|
||||
my $width = 20;
|
||||
system('tmux', 'split-window', '-dh', '-l', $width, '-t', $ENV{TMUX_PANE}, $cmd);
|
||||
open_fifo();
|
||||
Irssi::timeout_remove($just_launched) if defined $just_launched;
|
||||
$just_launched = Irssi::timeout_add_once(300, sub { $just_launched = undef; }, '');
|
||||
}
|
||||
|
||||
sub open_fifo {
|
||||
# The next system call will block until the other pane has opened the pipe
|
||||
# for reading, so synchronization is not an issue here.
|
||||
open $fifo, ">", $fifo_path or do {
|
||||
if ($! == 4) {
|
||||
Irssi::timeout_add_once(300, \&open_fifo, '');
|
||||
$enabled = -1 unless $enabled;
|
||||
return;
|
||||
}
|
||||
die "can't open $fifo_path: $!";
|
||||
};
|
||||
$fifo->autoflush(1);
|
||||
if ($enabled < -1) {
|
||||
$enabled = 1;
|
||||
disable_nicklist();
|
||||
} elsif ($enabled == -1) {
|
||||
$enabled = 1;
|
||||
reset_nicklist("enabled");
|
||||
} else {
|
||||
$enabled = 1;
|
||||
}
|
||||
}
|
||||
|
||||
sub disable_nicklist {
|
||||
return unless ($enabled);
|
||||
if ($enabled > 0) {
|
||||
print $fifo "EXIT\n";
|
||||
close $fifo;
|
||||
$fifo = undef;
|
||||
unlink $fifo_path;
|
||||
rmdir $tmpdir;
|
||||
}
|
||||
$enabled--;
|
||||
}
|
||||
|
||||
sub reset_nicklist {
|
||||
my $event = shift;
|
||||
my $active = Irssi::active_win();
|
||||
my $channel = $active->{active};
|
||||
return disable_nicklist unless $channel && ref $channel;
|
||||
if ($event =~ /^nick/) {
|
||||
# check if that nick event is for the current channel/nicklist
|
||||
my ($event_channel) = @_;
|
||||
return unless $channel->{_irssi} == $event_channel->{_irssi};
|
||||
}
|
||||
my ($colourer, $ansifier);
|
||||
if (Irssi::settings_get_bool('nicklist_color')) {
|
||||
for my $script (sort map { my $z = $_; $z =~ s/::$//; $z } grep { /^nickcolor|nm/ } keys %Irssi::Script::) {
|
||||
if ($colourer = "Irssi::Script::$script"->can('get_nick_color2')) {
|
||||
$ansifier = "Irssi::Script::$script"->can('debug_ansicolour');
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
my $channel_pattern = Irssi::settings_get_str('nicklist_channel_re');
|
||||
{ local $@;
|
||||
$channel_pattern = eval { qr/$channel_pattern/ };
|
||||
$channel_pattern = qr/(?!)/ if $@;
|
||||
}
|
||||
my $smallest_main = Irssi::settings_get_int('nicklist_smallest_main');
|
||||
if (!$nicklist_toggle
|
||||
|| !$channel || !ref($channel)
|
||||
|| !$channel->isa('Irssi::Channel')
|
||||
|| !$channel->{'names_got'}
|
||||
|| $channel->{'name'} !~ $channel_pattern
|
||||
|| ($smallest_main && $channel->window->{width} < $smallest_main)) {
|
||||
disable_nicklist;
|
||||
} else {
|
||||
my %colour;
|
||||
my @nicks = $channel->nicks();
|
||||
my $max_nicks = Irssi::settings_get_int('nicklist_max_users');
|
||||
if ($max_nicks && @nicks > $max_nicks) {
|
||||
disable_nicklist;
|
||||
} else {
|
||||
enable_nicklist;
|
||||
return unless $enabled > 0;
|
||||
foreach my $nick (sort { $a->{_irssi} <=> $b->{_irssi} } @nicks) {
|
||||
$colour{$nick->{nick}} = ($ansifier && $colourer) ? $ansifier->($colourer->($active->{active}{server}{tag}, $channel->{name}, $nick->{nick}, 0)) : '';
|
||||
}
|
||||
print($fifo "BEGIN\n");
|
||||
my $gone_sort = Irssi::settings_get_bool('nicklist_gone_sort');
|
||||
my $prefer_real;
|
||||
if (exists $Irssi::Script::{'realnames::'}) {
|
||||
my $code = "Irssi::Script::realnames"->can('use_realnames');
|
||||
$prefer_real = $code && $code->($channel);
|
||||
}
|
||||
my $_real = sub {
|
||||
my $nick = shift;
|
||||
$prefer_real && length $nick->{'realname'} ? $nick->{'realname'} : $nick->{'nick'}
|
||||
};
|
||||
foreach my $nick (sort {($a->{'op'}?'1':$a->{'halfop'}?'2':$a->{'voice'}?'3':$a->{'other'}>32?'0':'4').($gone_sort?($a->{'gone'}?1:0):'').lc($_real->($a))
|
||||
cmp ($b->{'op'}?'1':$b->{'halfop'}?'2':$b->{'voice'}?'3':$b->{'other'}>32?'0':'4').($gone_sort?($b->{'gone'}?1:0):'').lc($_real->($b))} @nicks) {
|
||||
my $colour = $colour{$nick->{nick}} || "\e[39m";
|
||||
$colour = "\e[37m" if $nick->{'gone'};
|
||||
print($fifo "NICK");
|
||||
if ($nick->{'op'}) {
|
||||
print($fifo "\e[32m\@$colour".$_real->($nick)."\e[39m");
|
||||
} elsif ($nick->{'halfop'}) {
|
||||
print($fifo "\e[34m%$colour".$_real->($nick)."\e[39m");
|
||||
} elsif ($nick->{'voice'}) {
|
||||
print($fifo "\e[33m+$colour".$_real->($nick)."\e[39m");
|
||||
} elsif ($nick->{'other'}>32) {
|
||||
print($fifo "\e[31m".(chr $nick->{'other'})."$colour".$_real->($nick)."\e[39m");
|
||||
} else {
|
||||
print($fifo " $colour".$_real->($nick)."\e[39m");
|
||||
}
|
||||
print($fifo "\n");
|
||||
}
|
||||
print($fifo "END\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub toggle_nicklist {
|
||||
if ($enabled) {
|
||||
$nicklist_toggle = undef
|
||||
} else {
|
||||
$nicklist_toggle = 1;
|
||||
}
|
||||
reset_nicklist("toggle");
|
||||
}
|
||||
|
||||
sub switch_channel {
|
||||
print $fifo "SWITCH_CHANNEL\n" if $fifo;
|
||||
&reset_nicklist;
|
||||
}
|
||||
|
||||
sub resized_timed {
|
||||
Irssi::timeout_remove($resize_timer) if defined $resize_timer;
|
||||
return if defined $just_launched;
|
||||
$resize_timer = Irssi::timeout_add_once(1100, \&resized, '');
|
||||
#resized();
|
||||
}
|
||||
sub resized {
|
||||
$resize_timer = undef;
|
||||
return if defined $just_launched;
|
||||
return unless $enabled >= 0;
|
||||
disable_nicklist;
|
||||
Irssi::timeout_add_once(200, sub{reset_nicklist("terminal resized")}, '');
|
||||
}
|
||||
sub UNLOAD {
|
||||
disable_nicklist;
|
||||
}
|
||||
|
||||
Irssi::settings_add_str('tmux_nicklist', 'nicklist_channel_re', '.*');
|
||||
Irssi::settings_add_int('tmux_nicklist', 'nicklist_max_users', 0);
|
||||
Irssi::settings_add_int('tmux_nicklist', 'nicklist_smallest_main', 0);
|
||||
Irssi::settings_add_int('tmux_nicklist', 'nicklist_pane_width', 13);
|
||||
Irssi::settings_add_bool('tmux_nicklist', 'nicklist_color', 1);
|
||||
Irssi::settings_add_bool('tmux_nicklist', 'nicklist_gone_sort', 0);
|
||||
Irssi::signal_add_last('window item changed', sub{switch_channel("window item changed",@_)});
|
||||
Irssi::signal_add_last('window changed', sub{switch_channel("window changed",@_)});
|
||||
Irssi::signal_add_last('channel joined', sub{switch_channel("channel joined",@_)});
|
||||
Irssi::signal_add('nicklist new', sub{reset_nicklist("nicklist new",@_)});
|
||||
Irssi::signal_add('nicklist remove', sub{reset_nicklist("nicklist remove",@_)});
|
||||
Irssi::signal_add('nicklist changed', sub{reset_nicklist("nicklist changed",@_)});
|
||||
Irssi::signal_add_first('nick mode changed', sub{reset_nicklist("nick mode changed",@_)});
|
||||
Irssi::signal_add('gui exit', \&disable_nicklist);
|
||||
Irssi::signal_add_last('terminal resized', \&resized_timed);
|
||||
|
||||
} else {
|
||||
my $fifo_path = $ARGV[0];
|
||||
my $irssi_pane = $ARGV[1];
|
||||
# array to store the current channel nicknames
|
||||
my @nicknames = ();
|
||||
|
||||
# helper functions for manipulating the terminal
|
||||
# escape sequences taken from
|
||||
# http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x361.html
|
||||
sub enable_mouse { print "\e[?1000h"; }
|
||||
# recognized sequences
|
||||
my $MOUSE_SCROLL_DOWN="\e[Ma";
|
||||
my $MOUSE_SCROLL_UP="\e[M`";
|
||||
my $ARROW_DOWN="\e[B";
|
||||
my $ARROW_UP="\e[A";
|
||||
my $DOWN="j";
|
||||
my $UP="k";
|
||||
my $PAGE_DOWN="\e[6~";
|
||||
my $PAGE_UP="\e[5~";
|
||||
my $PAGE_DOWN_D="d";
|
||||
my $PAGE_UP_U="u";
|
||||
my $GO_TOP="gg";
|
||||
my $GO_BOTTOM="G";
|
||||
|
||||
my $current_line = 0;
|
||||
my $sequence = '';
|
||||
my ($rows, $cols);
|
||||
|
||||
sub term_size {
|
||||
split ' ', `stty size`;
|
||||
}
|
||||
|
||||
sub redraw {
|
||||
my $last_nick_idx = @nicknames;
|
||||
my $last_idx = $current_line + $rows;
|
||||
# normalize last visible index
|
||||
if ($last_idx > ($last_nick_idx)) {
|
||||
$last_idx = $last_nick_idx;
|
||||
}
|
||||
# redraw visible nicks
|
||||
for my $i (reverse 1..$rows) {
|
||||
print "\e[$i;1H\e[K";
|
||||
my $idx = $current_line + $i - 1;
|
||||
if ($idx < $last_idx) {
|
||||
my $z = 0; my $col = $cols;
|
||||
for (split /(\e\[(?:\d|;|:|\?|\s)*.)/, $nicknames[$idx]) {
|
||||
if ($z ^= 1) {
|
||||
print +(substr $_, 0, $col) if $col > 0;
|
||||
$col -= length;
|
||||
} else {
|
||||
print
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub move_down {
|
||||
$sequence = '';
|
||||
my $count = int $_[0];
|
||||
my $nickcount = $#nicknames;
|
||||
return if ($nickcount <= $rows);
|
||||
if ($count == -1) {
|
||||
$current_line = $nickcount - $rows + 1;
|
||||
redraw;
|
||||
return;
|
||||
}
|
||||
my $visible = $nickcount - $current_line - $count + 1;
|
||||
if ($visible > $rows) {
|
||||
$current_line += $count;
|
||||
redraw;
|
||||
} elsif (($visible + $count) > $rows) {
|
||||
# scroll the maximum we can
|
||||
$current_line = $nickcount - $rows + 1;
|
||||
redraw;
|
||||
}
|
||||
}
|
||||
|
||||
sub move_up {
|
||||
$sequence = '';
|
||||
my $count = int $_[0];
|
||||
if ($count == -1) {
|
||||
$current_line = 0;
|
||||
redraw;
|
||||
return;
|
||||
}
|
||||
return if ($current_line == 0);
|
||||
$count = 1 if $count == 0;
|
||||
$current_line -= $count;
|
||||
$current_line = 0 if $current_line < 0;
|
||||
redraw;
|
||||
}
|
||||
|
||||
$SIG{INT} = 'IGNORE';
|
||||
|
||||
STDOUT->autoflush(1);
|
||||
# setup terminal so we can listen for individual key presses without echo
|
||||
`stty -icanon -echo`;
|
||||
|
||||
# open named pipe and setup the 'select' wrapper object for listening on both
|
||||
# fds(fifo and sdtin)
|
||||
open my $fifo, "<", $fifo_path or die "can't open $fifo_path: $!";
|
||||
my $select = IO::Select->new();
|
||||
my @ready;
|
||||
$select->add($fifo);
|
||||
$select->add(\*STDIN);
|
||||
|
||||
enable_mouse;
|
||||
system('tput', 'smcup');
|
||||
print "\e[?7l"; #system('tput', 'rmam');
|
||||
system('tput', 'civis');
|
||||
MAIN: {
|
||||
while (@ready = $select->can_read) {
|
||||
foreach my $fd (@ready) {
|
||||
($rows, $cols) = term_size;
|
||||
if ($fd == $fifo) {
|
||||
while (<$fifo>) {
|
||||
my $line = $_;
|
||||
if ($line =~ /^BEGIN/) {
|
||||
@nicknames = ();
|
||||
} elsif ($line =~ /^SWITCH_CHANNEL/) {
|
||||
$current_line = 0;
|
||||
} elsif ($line =~ /^NICK(.+)$/) {
|
||||
push @nicknames, $1;
|
||||
} elsif ($line =~ /^END$/) {
|
||||
redraw;
|
||||
last;
|
||||
} elsif ($line =~ /^EXIT$/) {
|
||||
last MAIN;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
my $key = '';
|
||||
sysread(STDIN, $key, 1);
|
||||
$sequence .= $key;
|
||||
if ($MOUSE_SCROLL_DOWN =~ /^\Q$sequence\E/) {
|
||||
if ($MOUSE_SCROLL_DOWN eq $sequence) {
|
||||
move_down 3;
|
||||
# mouse scroll has two more bytes that I dont use here
|
||||
# so consume them now to avoid sending unwanted bytes to
|
||||
# irssi
|
||||
sysread(STDIN, $key, 2);
|
||||
}
|
||||
} elsif ($MOUSE_SCROLL_UP =~ /^\Q$sequence\E/) {
|
||||
if ($MOUSE_SCROLL_UP eq $sequence) {
|
||||
move_up 3;
|
||||
sysread(STDIN, $key, 2);
|
||||
}
|
||||
} elsif ($ARROW_DOWN =~ /^\Q$sequence\E/) {
|
||||
move_down 1 if ($ARROW_DOWN eq $sequence);
|
||||
} elsif ($ARROW_UP =~ /^\Q$sequence\E/) {
|
||||
move_up 1 if ($ARROW_UP eq $sequence);
|
||||
} elsif ($DOWN =~ /^\Q$sequence\E/) {
|
||||
move_down 1 if ($DOWN eq $sequence);
|
||||
} elsif ($UP =~ /^\Q$sequence\E/) {
|
||||
move_up 1 if ($UP eq $sequence);
|
||||
} elsif ($PAGE_DOWN =~ /^\Q$sequence\E/) {
|
||||
move_down $rows/2 if ($PAGE_DOWN eq $sequence);
|
||||
} elsif ($PAGE_UP =~ /^\Q$sequence\E/) {
|
||||
move_up $rows/2 if ($PAGE_UP eq $sequence);
|
||||
} elsif ($PAGE_DOWN_D =~ /^\Q$sequence\E/) {
|
||||
move_down $rows/2 if ($PAGE_DOWN_D eq $sequence);
|
||||
} elsif ($PAGE_UP_U =~ /^\Q$sequence\E/) {
|
||||
move_up $rows/2 if ($PAGE_UP_U eq $sequence);
|
||||
} elsif ($GO_BOTTOM =~ /^\Q$sequence\E/) {
|
||||
move_down -1 if ($GO_BOTTOM eq $sequence);
|
||||
} elsif ($GO_TOP =~ /^\Q$sequence\E/) {
|
||||
move_up -1 if ($GO_TOP eq $sequence);
|
||||
} else {
|
||||
# Unrecognized sequences will be send to irssi and its pane
|
||||
# will be focused
|
||||
system('tmux', 'send-keys', '-t', $irssi_pane, $sequence);
|
||||
system('tmux', 'select-pane', '-t', $irssi_pane);
|
||||
$sequence = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close $fifo;
|
||||
|
||||
}
|
||||
606
home/.irssi/scripts/autorun/trackbar.pl
Normal file
606
home/.irssi/scripts/autorun/trackbar.pl
Normal file
@@ -0,0 +1,606 @@
|
||||
## trackbar.pl
|
||||
#
|
||||
# This little script will do just one thing: it will draw a line each time you
|
||||
# switch away from a window. This way, you always know just upto where you've
|
||||
# been reading that window :) It also removes the previous drawn line, so you
|
||||
# don't see double lines.
|
||||
#
|
||||
# redraw trackbar only works on irssi 0.8.17 or higher.
|
||||
#
|
||||
##
|
||||
|
||||
## Usage:
|
||||
#
|
||||
# The script works right out of the box, but if you want you can change
|
||||
# the working by /set'ing the following variables:
|
||||
#
|
||||
# Setting: trackbar_style
|
||||
# Description: This setting will be the color of your trackbar line.
|
||||
# By default the value will be '%K', only Irssi color
|
||||
# formats are allowed. If you don't know the color formats
|
||||
# by heart, you can take a look at the formats documentation.
|
||||
# You will find the proper docs on http://www.irssi.org/docs.
|
||||
#
|
||||
# Setting: trackbar_string
|
||||
# Description: This is the string that your line will display. This can
|
||||
# be multiple characters or just one. For example: '~-~-'
|
||||
# The default setting is '-'.
|
||||
# Here are some unicode characters you can try:
|
||||
# "───" => U+2500 => a line
|
||||
# "═══" => U+2550 => a double line
|
||||
# "━━━" => U+2501 => a wide line
|
||||
# "▭ " => U+25ad => a white rectangle
|
||||
#
|
||||
# Setting: trackbar_use_status_window
|
||||
# Description: If this setting is set to OFF, Irssi won't print a trackbar
|
||||
# in the statuswindow
|
||||
#
|
||||
# Setting: trackbar_ignore_windows
|
||||
# Description: A list of windows where no trackbar should be printed
|
||||
#
|
||||
# Setting: trackbar_print_timestamp
|
||||
# Description: If this setting is set to ON, Irssi will print the formatted
|
||||
# timestamp in front of the trackbar.
|
||||
#
|
||||
# Setting: trackbar_require_seen
|
||||
# Description: Only clear the trackbar if it has been scrolled to.
|
||||
#
|
||||
# Setting: trackbar_all_manual
|
||||
# Description: Never clear the trackbar until you do /mark.
|
||||
#
|
||||
# /mark is a command that will redraw the line at the bottom.
|
||||
#
|
||||
# Command: /trackbar, /trackbar goto
|
||||
# Description: Jump to where the trackbar is, to pick up reading
|
||||
#
|
||||
# Command: /trackbar keep
|
||||
# Description: Keep this window's trackbar where it is the next time
|
||||
# you switch windows (then this flag is cleared again)
|
||||
#
|
||||
# Command: /mark, /trackbar mark
|
||||
# Description: Remove the old trackbar and mark the bottom of this
|
||||
# window with a new trackbar
|
||||
#
|
||||
# Command: /trackbar markvisible
|
||||
# Description: Like mark for all visible windows
|
||||
#
|
||||
# Command: /trackbar markall
|
||||
# Description: Like mark for all windows
|
||||
#
|
||||
# Command: /trackbar remove
|
||||
# Description: Remove this window's trackbar
|
||||
#
|
||||
# Command: /trackbar removeall
|
||||
# Description: Remove all windows' trackbars
|
||||
#
|
||||
# Command: /trackbar redraw
|
||||
# Description: Force redraw of trackbars
|
||||
#
|
||||
##
|
||||
|
||||
##
|
||||
#
|
||||
# For bugreports and other improvements contact one of the authors.
|
||||
#
|
||||
# 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 script; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
##
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use vars qw($VERSION %IRSSI);
|
||||
|
||||
$VERSION = "2.9"; # a4c78e85092a271
|
||||
|
||||
%IRSSI = (
|
||||
authors => "Peter 'kinlo' Leurs, Uwe Dudenhoeffer, " .
|
||||
"Michiel Holtkamp, Nico R. Wohlgemuth, " .
|
||||
"Geert Hauwaerts",
|
||||
contact => 'peter@pfoe.be',
|
||||
patchers => 'Johan Kiviniemi (UTF-8), Uwe Dudenhoeffer (on-upgrade-remove-line)',
|
||||
name => 'trackbar',
|
||||
description => 'Shows a bar where you have last read a window.',
|
||||
license => 'GNU General Public License',
|
||||
url => 'http://www.pfoe.be/~peter/trackbar/',
|
||||
commands => 'trackbar',
|
||||
);
|
||||
|
||||
## Comments and remarks.
|
||||
#
|
||||
# This script uses settings.
|
||||
# Use /SET to change the value or /TOGGLE to switch it on or off.
|
||||
#
|
||||
#
|
||||
# Tip: The command 'trackbar' is very useful if you bind that to a key,
|
||||
# so you can easily jump to the trackbar. Please see 'help bind' for
|
||||
# more information about keybindings in Irssi.
|
||||
#
|
||||
# Command: /BIND meta2-P key F1
|
||||
# /BIND F1 command trackbar
|
||||
#
|
||||
##
|
||||
|
||||
## Bugfixes and new items in this rewrite.
|
||||
#
|
||||
# * Remove all the trackbars before upgrading.
|
||||
# * New setting trackbar_use_status_window to control the statuswindow trackbar.
|
||||
# * New setting trackbar_print_timestamp to print a timestamp or not.
|
||||
# * New command 'trackbar' to scroll up to the trackbar.
|
||||
# * When resizing your terminal, Irssi will update all the trackbars to the new size.
|
||||
# * When changing trackbar settings, change all the trackbars to the new settings.
|
||||
# * New command 'trackbar mark' to draw a new trackbar (The old '/mark').
|
||||
# * New command 'trackbar markall' to draw a new trackbar in each window.
|
||||
# * New command 'trackbar remove' to remove the trackbar from the current window.
|
||||
# * New command 'trackbar removeall' to remove all the trackbars.
|
||||
# * Don't draw a trackbar in empty windows.
|
||||
# * Added a version check to prevent Irssi redraw errors.
|
||||
# * Fixed a bookmark NULL versus 0 bug.
|
||||
# * Fixed a remove-line bug in Uwe Dudenhoeffer his patch.
|
||||
# * New command 'help trackbar' to display the trackbar commands.
|
||||
# * Fixed an Irssi startup bug, now processing each auto-created window.
|
||||
#
|
||||
##
|
||||
|
||||
## Known bugs and the todolist.
|
||||
#
|
||||
# Todo: * Instead of drawing a line, invert the line.
|
||||
#
|
||||
##
|
||||
|
||||
## Authors:
|
||||
#
|
||||
# - Main maintainer & author: Peter 'kinlo' Leurs
|
||||
# - Many thanks to Timo 'cras' Sirainen for placing me on my way
|
||||
# - on-upgrade-remove-line patch by Uwe Dudenhoeffer
|
||||
# - trackbar resizing by Michiel Holtkamp (02 Jul 2012)
|
||||
# - scroll to trackbar, window excludes, and timestamp options by Nico R.
|
||||
# Wohlgemuth (22 Sep 2012)
|
||||
#
|
||||
##
|
||||
|
||||
## Version history:
|
||||
#
|
||||
# 2.9: - fix crash on /mark in empty window
|
||||
# 2.8: - fix /^join bug
|
||||
# 2.7: - add /set trackbar_all_manual option
|
||||
# 2.5: - merge back on scripts.irssi.org
|
||||
# - fix /trackbar redraw broken in 2.4
|
||||
# - fix legacy encodings
|
||||
# - add workaround for irssi issue #271
|
||||
# 2.4: - add support for horizontal splits
|
||||
# 2.3: - add some features for seen tracking using other scripts
|
||||
# 2.0: - big rewrite based on 1.4
|
||||
# * removed /tb, you can have it with /alias tb trackbar if you want
|
||||
# * subcommand and settings changes:
|
||||
# /trackbar vmark => /trackbar markvisible
|
||||
# /trackbar scroll => /trackbar goto (or just /trackbar)
|
||||
# /trackbar help => /help trackbar
|
||||
# /set trackbar_hide_windows => /set trackbar_ignore_windows
|
||||
# /set trackbar_timestamp => /set trackbar_print_timestamp
|
||||
# * magic line strings were removed, just paste the unicode you want!
|
||||
# * trackbar_timestamp_styled is not currently supported
|
||||
# 1.9: - add version guard
|
||||
# 1.8: - sub draw_bar
|
||||
# 1.7: - Added /tb scroll, trackbar_hide_windows, trackbar_timestamp_timestamp
|
||||
# and trackbar_timestamp_styled
|
||||
# 1.6: - Work around Irssi resize bug, please do /upgrade! (see below)
|
||||
# 1.5: - Resize trackbars in all windows when terminal is resized
|
||||
# 1.4: - Changed our's by my's so the irssi script header is valid
|
||||
# - Removed utf-8 support. In theory, the script should work w/o any
|
||||
# problems for utf-8, just set trackbar_string to a valid utf-8 character
|
||||
# and everything *should* work. However, this script is being plagued by
|
||||
# irssi internal bugs. The function Irssi::settings_get_str does NOT handle
|
||||
# unicode strings properly, hence you will notice problems when setting the bar
|
||||
# to a unicode char. For changing your bar to utf-8 symbols, read the line sub.
|
||||
# 1.3: - Upgrade now removes the trackbars.
|
||||
# - Some code cleanups, other defaults
|
||||
# - /mark sets the line to the bottom
|
||||
# 1.2: - Support for utf-8
|
||||
# - How the bar looks can now be configured with trackbar_string
|
||||
# and trackbar_style
|
||||
# 1.1: - Fixed bug when closing window
|
||||
# 1.0: - Initial release
|
||||
#
|
||||
##
|
||||
|
||||
use Irssi;
|
||||
use Irssi::TextUI;
|
||||
use Encode;
|
||||
|
||||
use POSIX qw(strftime);
|
||||
|
||||
sub cmd_help {
|
||||
my ($args) = @_;
|
||||
if ($args =~ /^trackbar *$/i) {
|
||||
print CLIENTCRAP <<HELP
|
||||
%9Syntax:%9
|
||||
|
||||
TRACKBAR
|
||||
TRACKBAR GOTO
|
||||
TRACKBAR KEEP
|
||||
TRACKBAR MARK
|
||||
TRACKBAR MARKVISIBLE
|
||||
TRACKBAR MARKALL
|
||||
TRACKBAR REMOVE
|
||||
TRACKBAR REMOVEALL
|
||||
TRACKBAR REDRAW
|
||||
|
||||
%9Parameters:%9
|
||||
|
||||
GOTO: Jump to where the trackbar is, to pick up reading
|
||||
KEEP: Keep this window's trackbar where it is the next time
|
||||
you switch windows (then this flag is cleared again)
|
||||
MARK: Remove the old trackbar and mark the bottom of this
|
||||
window with a new trackbar
|
||||
MARKVISIBLE: Like mark for all visible windows
|
||||
MARKALL: Like mark for all windows
|
||||
REMOVE: Remove this window's trackbar
|
||||
REMOVEALL: Remove all windows' trackbars
|
||||
REDRAW: Force redraw of trackbars
|
||||
|
||||
%9Description:%9
|
||||
|
||||
Manage a trackbar. Without arguments, it will scroll up to the trackbar.
|
||||
|
||||
%9Examples:%9
|
||||
|
||||
/TRACKBAR MARK
|
||||
/TRACKBAR REMOVE
|
||||
HELP
|
||||
}
|
||||
}
|
||||
|
||||
Irssi::theme_register([
|
||||
'trackbar_loaded', '%R>>%n %_Scriptinfo:%_ Loaded $0 version $1 by $2.',
|
||||
'trackbar_wrong_version', '%R>>%n %_Trackbar:%_ Please upgrade your client to 0.8.17 or above if you would like to use this feature of trackbar.',
|
||||
'trackbar_all_removed', '%R>>%n %_Trackbar:%_ All the trackbars have been removed.',
|
||||
'trackbar_not_found', '%R>>%n %_Trackbar:%_ No trackbar found in this window.',
|
||||
]);
|
||||
|
||||
my $old_irssi = Irssi::version < 20140701;
|
||||
sub check_version {
|
||||
if ($old_irssi) {
|
||||
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'trackbar_wrong_version');
|
||||
return;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
sub is_utf8 {
|
||||
lc Irssi::settings_get_str('term_charset') eq 'utf-8'
|
||||
}
|
||||
|
||||
my (%config, %keep_trackbar, %unseen_trackbar);
|
||||
|
||||
sub remove_one_trackbar {
|
||||
my $win = shift;
|
||||
my $view = shift || $win->view;
|
||||
my $line = $view->get_bookmark('trackbar');
|
||||
if (defined $line) {
|
||||
my $bottom = $view->{bottom};
|
||||
$view->remove_line($line);
|
||||
$win->command('^scrollback end') if $bottom && !$win->view->{bottom};
|
||||
$view->redraw;
|
||||
}
|
||||
}
|
||||
|
||||
sub add_one_trackbar_pt1 {
|
||||
my $win = shift;
|
||||
my $view = shift || $win->view;
|
||||
|
||||
my $last_cur_line = ($view->{buffer}{cur_line}||+{})->{_irssi};
|
||||
$win->print(line($win->{width}), MSGLEVEL_NEVER);
|
||||
|
||||
my $cur_line = ($win->view->{buffer}{cur_line}||+{})->{_irssi}; # get a fresh buffer
|
||||
|
||||
($last_cur_line//'') ne ($cur_line//'') # printing was successful
|
||||
}
|
||||
|
||||
sub add_one_trackbar_pt2 {
|
||||
my $win = shift;
|
||||
my $view = $win->view;
|
||||
|
||||
$view->set_bookmark_bottom('trackbar');
|
||||
$unseen_trackbar{ $win->{_irssi} } = 1;
|
||||
Irssi::signal_emit("window trackbar added", $win);
|
||||
$view->redraw;
|
||||
}
|
||||
|
||||
sub update_one_trackbar {
|
||||
my $win = shift;
|
||||
my $view = shift || $win->view;
|
||||
my $force = shift;
|
||||
my $ignored = win_ignored($win, $view);
|
||||
my $success;
|
||||
|
||||
$success = add_one_trackbar_pt1($win, $view) ? 1 : 0
|
||||
if $force || !$ignored;
|
||||
|
||||
remove_one_trackbar($win, $view)
|
||||
if ( $success || !defined $success ) && ( $force || !defined $force || !$ignored );
|
||||
|
||||
add_one_trackbar_pt2($win)
|
||||
if $success;
|
||||
}
|
||||
|
||||
sub win_ignored {
|
||||
my $win = shift;
|
||||
my $view = shift || $win->view;
|
||||
return 1 unless $view->{buffer}{lines_count};
|
||||
return 1 if $win->{name} eq '(status)' && !$config{use_status_window};
|
||||
no warnings 'uninitialized';
|
||||
return 1 if grep { $win->{name} eq $_ || $win->{refnum} eq $_
|
||||
|| $win->get_active_name eq $_ } @{ $config{ignore_windows} };
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub sig_window_changed {
|
||||
my ($newwindow, $oldwindow) = @_;
|
||||
return unless $oldwindow;
|
||||
redraw_one_trackbar($newwindow) unless $old_irssi;
|
||||
trackbar_update_seen($newwindow);
|
||||
return if delete $keep_trackbar{ $oldwindow->{_irssi} };
|
||||
trackbar_update_seen($oldwindow);
|
||||
return if $config{require_seen} && $unseen_trackbar{ $oldwindow->{_irssi } };
|
||||
return if $config{all_manual};
|
||||
update_one_trackbar($oldwindow, undef, 0);
|
||||
}
|
||||
|
||||
sub trackbar_update_seen {
|
||||
my $win = shift;
|
||||
return unless $win;
|
||||
return unless $unseen_trackbar{ $win->{_irssi} };
|
||||
|
||||
my $view = $win->view;
|
||||
my $line = $view->get_bookmark('trackbar');
|
||||
unless ($line) {
|
||||
delete $unseen_trackbar{ $win->{_irssi} };
|
||||
Irssi::signal_emit("window trackbar seen", $win);
|
||||
return;
|
||||
}
|
||||
my $startline = $view->{startline};
|
||||
return unless $startline;
|
||||
|
||||
if ($startline->{info}{time} < $line->{info}{time}
|
||||
|| $startline->{_irssi} == $line->{_irssi}) {
|
||||
delete $unseen_trackbar{ $win->{_irssi} };
|
||||
Irssi::signal_emit("window trackbar seen", $win);
|
||||
}
|
||||
}
|
||||
|
||||
sub screen_length;
|
||||
{ local $@;
|
||||
eval { require Text::CharWidth; };
|
||||
unless ($@) {
|
||||
*screen_length = sub { Text::CharWidth::mbswidth($_[0]) };
|
||||
}
|
||||
else {
|
||||
*screen_length = sub {
|
||||
my $temp = shift;
|
||||
Encode::_utf8_on($temp) if is_utf8();
|
||||
length($temp)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
{ my %strip_table = (
|
||||
(map { $_ => '' } (split //, '04261537' . 'kbgcrmyw' . 'KBGCRMYW' . 'U9_8I:|FnN>#[' . 'pP')),
|
||||
(map { $_ => $_ } (split //, '{}%')),
|
||||
);
|
||||
sub c_length {
|
||||
my $o = Irssi::strip_codes($_[0]);
|
||||
$o =~ s/(%(%|Z.{6}|z.{6}|X..|x..|.))/exists $strip_table{$2} ? $strip_table{$2} :
|
||||
$2 =~ m{x(?:0[a-f]|[1-6][0-9a-z]|7[a-x])|z[0-9a-f]{6}}i ? '' : $1/gex;
|
||||
screen_length($o)
|
||||
}
|
||||
}
|
||||
|
||||
sub line {
|
||||
my ($width, $time) = @_;
|
||||
my $string = $config{string};
|
||||
$string = ' ' unless length $string;
|
||||
$time ||= time;
|
||||
|
||||
Encode::_utf8_on($string) if is_utf8();
|
||||
my $length = c_length($string);
|
||||
|
||||
my $format = '';
|
||||
if ($config{print_timestamp}) {
|
||||
$format = $config{timestamp_str};
|
||||
$format =~ y/%/\01/;
|
||||
$format =~ s/\01\01/%/g;
|
||||
$format = strftime($format, localtime $time);
|
||||
$format =~ y/\01/%/;
|
||||
}
|
||||
|
||||
my $times = $width / $length;
|
||||
$times += 1 if $times != int $times;
|
||||
my $style = "$config{style}";
|
||||
Encode::_utf8_on($style) if is_utf8();
|
||||
$format .= $style;
|
||||
$width -= c_length($format);
|
||||
$string x= $times;
|
||||
chop $string while length $string && c_length($string) > $width;
|
||||
return $format . $string;
|
||||
}
|
||||
|
||||
sub remove_all_trackbars {
|
||||
for my $window (Irssi::windows) {
|
||||
next unless ref $window;
|
||||
remove_one_trackbar($window);
|
||||
}
|
||||
}
|
||||
|
||||
sub UNLOAD {
|
||||
remove_all_trackbars();
|
||||
}
|
||||
|
||||
sub redraw_one_trackbar {
|
||||
my $win = shift;
|
||||
my $view = $win->view;
|
||||
my $line = $view->get_bookmark('trackbar');
|
||||
return unless $line;
|
||||
my $bottom = $view->{bottom};
|
||||
$win->print_after($line, MSGLEVEL_NEVER, line($win->{width}, $line->{info}{time}),
|
||||
$line->{info}{time});
|
||||
$view->set_bookmark('trackbar', $win->last_line_insert);
|
||||
$view->remove_line($line);
|
||||
$win->command('^scrollback end') if $bottom && !$win->view->{bottom};
|
||||
$view->redraw;
|
||||
}
|
||||
|
||||
sub redraw_trackbars {
|
||||
return unless check_version();
|
||||
for my $win (Irssi::windows) {
|
||||
next unless ref $win;
|
||||
redraw_one_trackbar($win);
|
||||
}
|
||||
}
|
||||
|
||||
sub goto_trackbar {
|
||||
my $win = Irssi::active_win;
|
||||
my $line = $win->view->get_bookmark('trackbar');
|
||||
|
||||
if ($line) {
|
||||
$win->command("scrollback goto ". strftime("%d %H:%M:%S", localtime($line->{info}{time})));
|
||||
} else {
|
||||
$win->printformat(MSGLEVEL_CLIENTCRAP, 'trackbar_not_found');
|
||||
}
|
||||
}
|
||||
|
||||
sub cmd_mark {
|
||||
update_one_trackbar(Irssi::active_win, undef, 1);
|
||||
}
|
||||
|
||||
sub cmd_markall {
|
||||
for my $window (Irssi::windows) {
|
||||
next unless ref $window;
|
||||
update_one_trackbar($window);
|
||||
}
|
||||
}
|
||||
|
||||
sub signal_stop {
|
||||
Irssi::signal_stop;
|
||||
}
|
||||
|
||||
sub cmd_markvisible {
|
||||
my @wins = Irssi::windows;
|
||||
my $awin =
|
||||
my $bwin = Irssi::active_win;
|
||||
my $awin_counter = 0;
|
||||
Irssi::signal_add_priority('window changed' => 'signal_stop', -99);
|
||||
do {
|
||||
Irssi::active_win->command('window up');
|
||||
$awin = Irssi::active_win;
|
||||
update_one_trackbar($awin);
|
||||
++$awin_counter;
|
||||
} until ($awin->{refnum} == $bwin->{refnum} || $awin_counter >= @wins);
|
||||
Irssi::signal_remove('window changed' => 'signal_stop');
|
||||
}
|
||||
|
||||
sub cmd_trackbar_remove_one {
|
||||
remove_one_trackbar(Irssi::active_win);
|
||||
}
|
||||
|
||||
sub cmd_remove_all_trackbars {
|
||||
remove_all_trackbars();
|
||||
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'trackbar_all_removed');
|
||||
}
|
||||
|
||||
sub cmd_keep_once {
|
||||
$keep_trackbar{ Irssi::active_win->{_irssi} } = 1;
|
||||
}
|
||||
|
||||
sub trackbar_runsub {
|
||||
my ($data, $server, $item) = @_;
|
||||
$data =~ s/\s+$//g;
|
||||
|
||||
if ($data) {
|
||||
Irssi::command_runsub('trackbar', $data, $server, $item);
|
||||
} else {
|
||||
goto_trackbar();
|
||||
}
|
||||
}
|
||||
|
||||
sub update_config {
|
||||
my $was_status_window = $config{use_status_window};
|
||||
$config{style} = Irssi::settings_get_str('trackbar_style');
|
||||
$config{string} = Irssi::settings_get_str('trackbar_string');
|
||||
$config{require_seen} = Irssi::settings_get_bool('trackbar_require_seen');
|
||||
$config{all_manual} = Irssi::settings_get_bool('trackbar_all_manual');
|
||||
$config{ignore_windows} = [ split /[,\s]+/, Irssi::settings_get_str('trackbar_ignore_windows') ];
|
||||
$config{use_status_window} = Irssi::settings_get_bool('trackbar_use_status_window');
|
||||
$config{print_timestamp} = Irssi::settings_get_bool('trackbar_print_timestamp');
|
||||
if (defined $was_status_window && $was_status_window != $config{use_status_window}) {
|
||||
if (my $swin = Irssi::window_find_name('(status)')) {
|
||||
if ($config{use_status_window}) {
|
||||
update_one_trackbar($swin);
|
||||
}
|
||||
else {
|
||||
remove_one_trackbar($swin);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($config{print_timestamp}) {
|
||||
my $ts_format = Irssi::settings_get_str('timestamp_format');
|
||||
my $ts_theme = Irssi::current_theme->get_format('fe-common/core', 'timestamp');
|
||||
my $render_str = Irssi::current_theme->format_expand($ts_theme);
|
||||
(my $ts_escaped = $ts_format) =~ s/([%\$])/$1$1/g;
|
||||
$render_str =~ s/(?|\$(.)(?!\w)|\$\{(\w+)\})/$1 eq 'Z' ? $ts_escaped : $1/ge;
|
||||
$config{timestamp_str} = $render_str;
|
||||
}
|
||||
redraw_trackbars() unless $old_irssi;
|
||||
}
|
||||
|
||||
Irssi::settings_add_str('trackbar', 'trackbar_string', is_utf8() ? "\x{2500}" : '-');
|
||||
Irssi::settings_add_str('trackbar', 'trackbar_style', '%K');
|
||||
Irssi::settings_add_str('trackbar', 'trackbar_ignore_windows', '');
|
||||
Irssi::settings_add_bool('trackbar', 'trackbar_use_status_window', 1);
|
||||
Irssi::settings_add_bool('trackbar', 'trackbar_print_timestamp', 0);
|
||||
Irssi::settings_add_bool('trackbar', 'trackbar_require_seen', 0);
|
||||
Irssi::settings_add_bool('trackbar', 'trackbar_all_manual', 0);
|
||||
|
||||
update_config();
|
||||
|
||||
Irssi::signal_add_last( 'mainwindow resized' => 'redraw_trackbars')
|
||||
unless $old_irssi;
|
||||
|
||||
Irssi::signal_register({'window trackbar added' => [qw/Irssi::UI::Window/]});
|
||||
Irssi::signal_register({'window trackbar seen' => [qw/Irssi::UI::Window/]});
|
||||
Irssi::signal_register({'gui page scrolled' => [qw/Irssi::UI::Window/]});
|
||||
Irssi::signal_add_last('gui page scrolled' => 'trackbar_update_seen');
|
||||
|
||||
Irssi::signal_add('setup changed' => 'update_config');
|
||||
Irssi::signal_add_priority('session save' => 'remove_all_trackbars', Irssi::SIGNAL_PRIORITY_HIGH-1);
|
||||
|
||||
Irssi::signal_add('window changed' => 'sig_window_changed');
|
||||
|
||||
Irssi::command_bind('trackbar goto' => 'goto_trackbar');
|
||||
Irssi::command_bind('trackbar keep' => 'cmd_keep_once');
|
||||
Irssi::command_bind('trackbar mark' => 'cmd_mark');
|
||||
Irssi::command_bind('trackbar markvisible' => 'cmd_markvisible');
|
||||
Irssi::command_bind('trackbar markall' => 'cmd_markall');
|
||||
Irssi::command_bind('trackbar remove' => 'cmd_trackbar_remove_one');
|
||||
Irssi::command_bind('trackbar removeall' => 'cmd_remove_all_trackbars');
|
||||
Irssi::command_bind('trackbar redraw' => 'redraw_trackbars');
|
||||
Irssi::command_bind('trackbar' => 'trackbar_runsub');
|
||||
Irssi::command_bind('mark' => 'cmd_mark');
|
||||
Irssi::command_bind_last('help' => 'cmd_help');
|
||||
|
||||
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'trackbar_loaded', $IRSSI{name}, $VERSION, $IRSSI{authors});
|
||||
|
||||
# workaround for issue #271
|
||||
{ package Irssi::Nick }
|
||||
774
home/.irssi/scripts/autorun/uberprompt.pl
Normal file
774
home/.irssi/scripts/autorun/uberprompt.pl
Normal file
@@ -0,0 +1,774 @@
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
uberprompt.pl
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This script replaces the default prompt status-bar item with one capable of
|
||||
displaying additional information, under either user control or via scripts.
|
||||
|
||||
=head1 INSTALLATION
|
||||
|
||||
Copy into your F<~/.irssi/scripts/> directory and load with
|
||||
C</SCRIPT LOAD F<filename>>.
|
||||
|
||||
It is recommended that you make it autoload in one of the
|
||||
L<usual ways|https://github.com/shabble/irssi-docs/wiki/Guide#Autorunning_Scripts>.
|
||||
|
||||
=head1 SETUP
|
||||
|
||||
If you have a custom prompt format, you may need to copy it to the
|
||||
uberprompt_format setting. See below for details.
|
||||
|
||||
=head1 USAGE
|
||||
|
||||
Although the script is designed primarily for other scripts to set
|
||||
status information into the prompt, the following commands are available:
|
||||
|
||||
=over 4
|
||||
|
||||
=item * C</prompt set [-inner|-pre|-post|only] E<lt>msgE<gt>>
|
||||
|
||||
Sets the prompt to the given argument. Any use of C<$p> in the argument will
|
||||
be replaced by the original prompt content.
|
||||
|
||||
A parameter corresponding to the C<UP_*> constants listed below is required, in
|
||||
the format C</prompt set -inner Hello!>
|
||||
|
||||
=item * C</prompt clear>
|
||||
|
||||
Clears the additional data provided to the prompt.
|
||||
|
||||
=item * C</prompt on>
|
||||
|
||||
Eenables the uberprompt (things may get confused if this is used
|
||||
whilst the prompt is already enabled)
|
||||
|
||||
=item * C</prompt off>
|
||||
|
||||
Restore the original irssi prompt and prompt_empty statusbars. unloading the
|
||||
script has the same effect.
|
||||
|
||||
=item * C</help prompt>
|
||||
|
||||
show help for uberprompt commands
|
||||
|
||||
=back
|
||||
|
||||
=head1 SETTINGS
|
||||
|
||||
=head2 UBERPROMPT FORMAT
|
||||
|
||||
C</set uberprompt_format E<lt>formatE<gt>>
|
||||
|
||||
The default is C<[$*$uber]>, which is the same as the default provided in
|
||||
F<default.theme>.
|
||||
|
||||
Changing this setting will update the prompt immediately, unlike editing your theme.
|
||||
|
||||
An additional variable available within this format is C<$uber>, which expands to
|
||||
the content of prompt data provided with the C<UP_INNER> or C</prompt set -inner>
|
||||
placement argument.
|
||||
|
||||
For all other placement arguments, it will expand to the empty string.
|
||||
|
||||
B<Note:> This setting completely overrides the C<prompt="...";> line in your
|
||||
.theme file, and may cause unexpected behaviour if your theme wishes to set a
|
||||
different form of prompt. It can be simply copied from the theme file into the
|
||||
above setting.
|
||||
|
||||
=head2 OTHER SETTINGS
|
||||
|
||||
=over 4
|
||||
|
||||
=item * C<uberprompt_autostart>
|
||||
|
||||
Boolean value, which determines if uberprompt should enable itself automatically
|
||||
upon loading. If Off, it must be enabled manually with C</prompt on>. Defaults to On.
|
||||
|
||||
=item * C<uberprompt_debug>
|
||||
|
||||
Boolean value, which determines if uberprompt should print debugging information.
|
||||
Defaults to Off, and should probably be left that way unless requested for bug-tracing
|
||||
purposes.
|
||||
|
||||
=item * C<uberprompt_format>
|
||||
|
||||
String value containing the format-string which uberprompt uses to display the
|
||||
prompt. Defaults to "C<[$*$uber] >", where C<$*> is the content the prompt would
|
||||
normally display, and C<$uber> is a placeholder variable for dynamic content, as
|
||||
described in the section above.
|
||||
|
||||
=item * C<uberprompt_load_hook>
|
||||
|
||||
String value which can contain one or more commands to be run whenever the uberprompt
|
||||
is enabled, either via autostart, or C</prompt on>. Defaults to the empty string, in
|
||||
which case no commands are run. Some examples include:
|
||||
|
||||
C</set uberprompt_load_hook /echo prompt enabled> or
|
||||
|
||||
C</^sbar prompt add -after input vim_mode> for those using vim_mode.pl who want
|
||||
the command status indicator on the prompt line.
|
||||
|
||||
=item * C<uberprompt_unload_hook>
|
||||
|
||||
String value, defaulting to the empty string, which can contain commands which
|
||||
are executed when the uberprompt is disabled, either by unloading the script,
|
||||
or by the command C</prompt off>.
|
||||
|
||||
=item * C<uberprompt_use_replaces>
|
||||
|
||||
Boolean value, defaults to Off. If enabled, the format string for the prompt
|
||||
will be subject to the I<replaces> section of the theme. The most obvious
|
||||
effect of this is that bracket characters C<[ ]> are displayed in a different
|
||||
colour, typically quite dark.
|
||||
|
||||
=back
|
||||
|
||||
B<Note:> For both C<uberprompt_*_hook> settings above, multiple commands can
|
||||
be chained together in the form C</eval /^cmd1 ; /^cmd2>. The C<^> prevents
|
||||
any output from the commands (such as error messages) being displayed.
|
||||
|
||||
=head2 SCRIPTING USAGE
|
||||
|
||||
The primary purpose of uberprompt is to be used by other scripts to
|
||||
display information in a way that is not possible by printing to the active
|
||||
window or using statusbar items.
|
||||
|
||||
The content of the prompt can be set from other scripts via the C<"change prompt">
|
||||
signal.
|
||||
|
||||
For Example:
|
||||
|
||||
signal_emit 'change prompt' 'some_string', UberPrompt::UP_INNER;
|
||||
|
||||
will set the prompt to include that content, by default 'C<[$* some_string]>'
|
||||
|
||||
The possible position arguments are the following strings:
|
||||
|
||||
=over 4
|
||||
|
||||
=item * C<UP_PRE> - place the provided string before the prompt - C<$string$prompt>
|
||||
|
||||
=item * C<UP_INNER> - place the provided string inside the prompt - C<{prompt $* $string}>
|
||||
|
||||
=item * C<UP_POST> - place the provided string after the prompt - C<$prompt$string>
|
||||
|
||||
=item * C<UP_ONLY> - replace the prompt with the provided string - C<$string>
|
||||
|
||||
=back
|
||||
|
||||
All strings may use the special variable 'C<$prompt>' to include the prompt
|
||||
verbatim at that position in the string. It is probably only useful for
|
||||
the C<UP_ONLY> mode however. '$C<prompt_nt>' will include the prompt, minus any
|
||||
trailing whitespace.
|
||||
|
||||
=head2 CHANGE NOTIFICATIONS
|
||||
|
||||
You can also be notified when the prompt changes in response to the previous
|
||||
signal or manual C</prompt> commands via:
|
||||
|
||||
signal_add 'prompt changed', sub { my ($text, $len) = @_; ... do something ... };
|
||||
|
||||
This callback will occur whenever the contents of the prompt is changed.
|
||||
|
||||
|
||||
=head2 NOTES FOR SCRIPT WRITERS:
|
||||
|
||||
The following code snippet can be used within your own script as a preamble
|
||||
to ensure that uberprompt is loaded before your script to avoid
|
||||
any issues with loading order. It first checks if uberprompt is loaded, and
|
||||
if not, attempts to load it. If the load fails, the script will die
|
||||
with an error message, otherwise it will call your app_init() function.
|
||||
|
||||
I<---- start of snippet ---->
|
||||
|
||||
my $DEBUG_ENABLED = 0;
|
||||
sub DEBUG () { $DEBUG_ENABLED }
|
||||
|
||||
# check we have uberprompt loaded.
|
||||
|
||||
sub script_is_loaded {
|
||||
return exists($Irssi::Script::{$_[0] . '::'});
|
||||
}
|
||||
|
||||
if (not script_is_loaded('uberprompt')) {
|
||||
|
||||
print "This script requires 'uberprompt.pl' in order to work. "
|
||||
. "Attempting to load it now...";
|
||||
|
||||
Irssi::signal_add('script error', 'load_uberprompt_failed');
|
||||
Irssi::command("script load uberprompt.pl");
|
||||
|
||||
unless(script_is_loaded('uberprompt')) {
|
||||
load_uberprompt_failed("File does not exist");
|
||||
}
|
||||
app_init();
|
||||
} else {
|
||||
app_init();
|
||||
}
|
||||
|
||||
sub load_uberprompt_failed {
|
||||
Irssi::signal_remove('script error', 'load_uberprompt_failed');
|
||||
|
||||
print "Script could not be loaded. Script cannot continue. "
|
||||
. "Check you have uberprompt.pl installed in your path and "
|
||||
. "try again.";
|
||||
|
||||
die "Script Load Failed: " . join(" ", @_);
|
||||
}
|
||||
|
||||
I<---- end of snippet ---->
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Copyright E<copy> 2011 Tom Feist C<E<lt>shabble+irssi@metavore.orgE<gt>>
|
||||
|
||||
=head1 LICENCE
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
Resizing the terminal rapidly whilst using this script in debug mode may cause
|
||||
irssi to crash. See bug report at http://bugs.irssi.org/index.php?do=details&task_id=772 for details.
|
||||
|
||||
=back
|
||||
|
||||
=head1 TODO
|
||||
|
||||
=over 4
|
||||
|
||||
=item * report failure (somehow) to clients if hte prompt is disabled.
|
||||
|
||||
=item * fix issue at autorun startup with sbar item doesn't exist.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Irssi;
|
||||
use Irssi::TextUI;
|
||||
use Data::Dumper;
|
||||
|
||||
{ package Irssi::Nick } # magic.
|
||||
|
||||
our $VERSION = "0.2";
|
||||
our %IRSSI =
|
||||
(
|
||||
authors => "shabble",
|
||||
contact => 'shabble+irssi@metavore.org, shabble@#irssi/Freenode',
|
||||
name => "uberprompt",
|
||||
description => "Helper script for dynamically adding text "
|
||||
. "into the input-bar prompt.",
|
||||
license => "MIT",
|
||||
changed => "24/7/2010"
|
||||
);
|
||||
|
||||
|
||||
my $DEBUG_ENABLED = 0;
|
||||
sub DEBUG { $DEBUG_ENABLED }
|
||||
|
||||
my $prompt_data = '';
|
||||
my $prompt_data_pos = 'UP_INNER';
|
||||
|
||||
my $prompt_last = '';
|
||||
my $prompt_format = '';
|
||||
my $prompt_format_empty = '';
|
||||
|
||||
# flag to indicate whether rendering of hte prompt should allow the replaces
|
||||
# theme formats to be applied to the content.
|
||||
my $use_replaces = 0;
|
||||
my $trim_data = 0;
|
||||
|
||||
my $emit_request = 0;
|
||||
|
||||
my $expando_refresh_timer;
|
||||
my $expando_vars = {};
|
||||
|
||||
my $init_callbacks = {load => '', unload => ''};
|
||||
|
||||
pre_init();
|
||||
|
||||
sub pre_init {
|
||||
Irssi::command('statusbar prompt reset');
|
||||
init();
|
||||
}
|
||||
|
||||
sub prompt_subcmd_handler {
|
||||
my ($data, $server, $item) = @_;
|
||||
#$data =~ s/\s+$//g; # strip trailing whitespace.
|
||||
Irssi::command_runsub('prompt', $data, $server, $item);
|
||||
}
|
||||
|
||||
sub _error($) {
|
||||
my ($msg) = @_;
|
||||
Irssi::active_win->print($msg, MSGLEVEL_CLIENTERROR);
|
||||
}
|
||||
|
||||
sub _debug_print($) {
|
||||
return unless DEBUG;
|
||||
my ($msg) = @_;
|
||||
Irssi::active_win->print($msg, MSGLEVEL_CLIENTCRAP);
|
||||
}
|
||||
|
||||
sub _print_help {
|
||||
my ($args) = @_;
|
||||
if ($args =~ m/^\s*prompt/i) {
|
||||
my @help_lines =
|
||||
(
|
||||
"",
|
||||
"PROMPT ON",
|
||||
"PROMPT OFF",
|
||||
"PROMPT CLEAR",
|
||||
"PROMPT SET { -pre | -post | -only | -inner } <content>",
|
||||
"",
|
||||
"Commands for manipulating the UberPrompt.",
|
||||
"",
|
||||
"/PROMPT ON enables uberprompt, replacing the existing prompt ",
|
||||
" statusbar-item",
|
||||
"/PROMPT OFF disables it, and restores the original prompt item",
|
||||
"/PROMPT CLEAR resets the value of any additional data set by /PROMPT SET",
|
||||
" or a script",
|
||||
"/PROMPT SET changes the contents of the prompt, according to the mode",
|
||||
" and content provided.",
|
||||
" { -inner sets the value of the \$uber psuedo-variable in the",
|
||||
" /set uberprompt_format setting.",
|
||||
" | -pre places the content before the current prompt string",
|
||||
" | -post places the content after the prompt string",
|
||||
" | -only replaces the entire prompt contents with the given string }",
|
||||
"",
|
||||
"See Also:",
|
||||
'',
|
||||
'/SET uberprompt_format -- defaults to "[$*$uber] "',
|
||||
'/SET uberprompt_format_empty -- defaults to "[$*] "',
|
||||
"/SET uberprompt_autostart -- determines whether /PROMPT ON is run",
|
||||
" automatically when the script loads",
|
||||
"/SET uberprompt_use_replaces -- toggles the use of the current theme",
|
||||
" \"replaces\" setting. Especially",
|
||||
" noticeable on brackets \"[ ]\" ",
|
||||
"/SET uberprompt_trim_data -- defaults to off. Removes whitespace from",
|
||||
" both sides of the \$uber result.",
|
||||
"",
|
||||
);
|
||||
|
||||
Irssi::print($_, MSGLEVEL_CLIENTCRAP) for @help_lines;
|
||||
Irssi::signal_stop;
|
||||
}
|
||||
}
|
||||
|
||||
sub UNLOAD {
|
||||
deinit();
|
||||
}
|
||||
|
||||
sub exp_lbrace() { '{' }
|
||||
sub exp_rbrace() { '}' }
|
||||
|
||||
sub deinit {
|
||||
Irssi::expando_destroy('lbrace');
|
||||
Irssi::expando_destroy('rbrace');
|
||||
|
||||
if (Irssi::settings_get_bool('uberprompt_restore_on_exit')) {
|
||||
# remove uberprompt and return the original ones.
|
||||
print "Removing uberprompt and restoring original";
|
||||
restore_prompt_items();
|
||||
}
|
||||
}
|
||||
|
||||
sub init {
|
||||
Irssi::statusbar_item_register('uberprompt', 0, 'uberprompt_draw');
|
||||
|
||||
# TODO: flags to prevent these from being recomputed?
|
||||
Irssi::expando_create('lbrace', \&exp_lbrace, {});
|
||||
Irssi::expando_create('rbrace', \&exp_rbrace, {});
|
||||
|
||||
Irssi::settings_add_str ('uberprompt', 'uberprompt_format', '[$*$uber] ');
|
||||
Irssi::settings_add_str ('uberprompt', 'uberprompt_format_empty', '[$*] ');
|
||||
|
||||
Irssi::settings_add_str ('uberprompt', 'uberprompt_load_hook', '');
|
||||
Irssi::settings_add_str ('uberprompt', 'uberprompt_unload_hook', '');
|
||||
|
||||
Irssi::settings_add_bool('uberprompt', 'uberprompt_debug', 0);
|
||||
Irssi::settings_add_bool('uberprompt', 'uberprompt_autostart', 1);
|
||||
Irssi::settings_add_bool ('uberprompt', 'uberprompt_restore_on_exit', 1);
|
||||
|
||||
Irssi::settings_add_bool('uberprompt', 'uberprompt_use_replaces', 0);
|
||||
Irssi::settings_add_bool('uberprompt', 'uberprompt_trim_data', 0);
|
||||
|
||||
Irssi::command_bind("prompt", \&prompt_subcmd_handler);
|
||||
Irssi::command_bind('prompt on', \&replace_prompt_items);
|
||||
Irssi::command_bind('prompt off', \&restore_prompt_items);
|
||||
Irssi::command_bind('prompt set', \&cmd_prompt_set);
|
||||
Irssi::command_bind('prompt clear',
|
||||
sub {
|
||||
Irssi::signal_emit 'change prompt', '$p', 'UP_POST';
|
||||
});
|
||||
|
||||
my $prompt_set_args_format = "inner pre post only";
|
||||
Irssi::command_set_options('prompt set', $prompt_set_args_format);
|
||||
|
||||
Irssi::command_bind('help', \&_print_help);
|
||||
|
||||
Irssi::signal_add('setup changed', \&reload_settings);
|
||||
|
||||
# intialise the prompt format.
|
||||
reload_settings();
|
||||
|
||||
# make sure we redraw when necessary.
|
||||
Irssi::signal_add('window changed', \&uberprompt_refresh);
|
||||
Irssi::signal_add('window name changed', \&uberprompt_refresh);
|
||||
Irssi::signal_add('window changed automatic', \&uberprompt_refresh);
|
||||
Irssi::signal_add('window item changed', \&uberprompt_refresh);
|
||||
Irssi::signal_add('window item server changed', \&uberprompt_refresh);
|
||||
Irssi::signal_add('window server changed', \&uberprompt_refresh);
|
||||
Irssi::signal_add('server nick changed', \&uberprompt_refresh);
|
||||
|
||||
Irssi::signal_add('nick mode changed', \&refresh_if_me);
|
||||
|
||||
# install our statusbars if required.
|
||||
if (Irssi::settings_get_bool('uberprompt_autostart')) {
|
||||
replace_prompt_items();
|
||||
}
|
||||
|
||||
# API signals
|
||||
|
||||
Irssi::signal_register({'change prompt' => [qw/string string/]});
|
||||
Irssi::signal_add('change prompt' => \&change_prompt_handler);
|
||||
|
||||
# other scripts (specifically overlay/visual) can subscribe to
|
||||
# this event to be notified when the prompt changes.
|
||||
# arguments are new contents (string), new length (int)
|
||||
Irssi::signal_register({'prompt changed' => [qw/string int/]});
|
||||
Irssi::signal_register({'prompt length request' => []});
|
||||
|
||||
Irssi::signal_add('prompt length request', \&length_request_handler);
|
||||
}
|
||||
|
||||
sub cmd_prompt_set {
|
||||
my $args = shift;
|
||||
my @options_list = Irssi::command_parse_options "prompt set", $args;
|
||||
if (@options_list) {
|
||||
my ($options, $rest) = @options_list;
|
||||
|
||||
my @opt_modes = keys %$options;
|
||||
if (@opt_modes != 1) {
|
||||
_error '%_/prompt set%_ must specify exactly one mode of'
|
||||
. ' {-inner, -only, -pre, -post}';
|
||||
return;
|
||||
}
|
||||
|
||||
my $mode = 'UP_' . uc($opt_modes[0]);
|
||||
|
||||
Irssi::signal_emit 'change prompt', $rest, $mode;
|
||||
} else {
|
||||
_error ('%_/prompt set%_ must specify a mode {-inner, -only, -pre, -post}');
|
||||
}
|
||||
}
|
||||
|
||||
sub refresh_if_me {
|
||||
my ($channel, $nick) = @_;
|
||||
|
||||
return unless $channel and $nick;
|
||||
|
||||
my $server = Irssi::active_server;
|
||||
my $window = Irssi::active_win;
|
||||
|
||||
return unless $server and $window;
|
||||
|
||||
my $my_chan = $window->{active}->{name};
|
||||
my $my_nick = $server->parse_special('$N');
|
||||
|
||||
return unless $my_chan and $my_nick;
|
||||
|
||||
_debug_print "Chan: $channel->{name}, "
|
||||
. "nick: $nick->{nick}, "
|
||||
. "me: $my_nick, chan: $my_chan";
|
||||
|
||||
if ($my_chan eq $channel->{name} and $my_nick eq $nick->{nick}) {
|
||||
uberprompt_refresh();
|
||||
}
|
||||
}
|
||||
|
||||
sub length_request_handler {
|
||||
$emit_request = 1;
|
||||
uberprompt_render_prompt();
|
||||
$emit_request = 0;
|
||||
}
|
||||
|
||||
sub reload_settings {
|
||||
|
||||
$use_replaces = Irssi::settings_get_bool('uberprompt_use_replaces');
|
||||
$DEBUG_ENABLED = Irssi::settings_get_bool('uberprompt_debug');
|
||||
|
||||
$init_callbacks = {
|
||||
load => Irssi::settings_get_str('uberprompt_load_hook'),
|
||||
unload => Irssi::settings_get_str('uberprompt_unload_hook'),
|
||||
};
|
||||
|
||||
if (DEBUG) {
|
||||
Irssi::signal_add 'prompt changed', 'debug_prompt_changed';
|
||||
} else {
|
||||
Irssi::signal_remove 'prompt changed', 'debug_prompt_changed';
|
||||
}
|
||||
|
||||
my $new = Irssi::settings_get_str('uberprompt_format');
|
||||
|
||||
if ($prompt_format ne $new) {
|
||||
_debug_print("Updated prompt format");
|
||||
$prompt_format = $new;
|
||||
$prompt_format =~ s/\$uber/\$\$uber/;
|
||||
Irssi::abstracts_register(['uberprompt', $prompt_format]);
|
||||
|
||||
$expando_vars = {};
|
||||
|
||||
# TODO: something clever here to check if we need to schedule
|
||||
# an update timer or something, rather than just refreshing on
|
||||
# every possible activity in init()
|
||||
while ($prompt_format =~ m/(?<!\$)(\$[A-Za-z,.:;][a-z_]*)/g) {
|
||||
_debug_print("Detected Irssi expando variable $1");
|
||||
my $var_name = substr $1, 1; # strip the $
|
||||
$expando_vars->{$var_name} = Irssi::parse_special($1);
|
||||
}
|
||||
}
|
||||
|
||||
$new = Irssi::settings_get_str('uberprompt_format_empty');
|
||||
|
||||
if ($prompt_format_empty ne $new) {
|
||||
_debug_print("Updated prompt format");
|
||||
$prompt_format_empty = $new;
|
||||
$prompt_format_empty =~ s/\$uber/\$\$uber/;
|
||||
Irssi::abstracts_register(['uberprompt_empty', $prompt_format_empty]);
|
||||
|
||||
$expando_vars = {};
|
||||
|
||||
# TODO: something clever here to check if we need to schedule
|
||||
# an update timer or something, rather than just refreshing on
|
||||
# every possible activity in init()
|
||||
while ($prompt_format_empty =~ m/(?<!\$)(\$[A-Za-z,.:;][a-z_]*)/g) {
|
||||
_debug_print("Detected Irssi expando variable $1");
|
||||
my $var_name = substr $1, 1; # strip the $
|
||||
$expando_vars->{$var_name} = Irssi::parse_special($1);
|
||||
}
|
||||
}
|
||||
|
||||
$trim_data = Irssi::settings_get_bool('uberprompt_trim_data');
|
||||
}
|
||||
|
||||
sub debug_prompt_changed {
|
||||
my ($text, $len) = @_;
|
||||
|
||||
$text =~ s/%/%%/g;
|
||||
|
||||
print "DEBUG_HANDLER: Prompt Changed to: \"$text\", length: $len";
|
||||
}
|
||||
|
||||
sub change_prompt_handler {
|
||||
my ($text, $pos) = @_;
|
||||
|
||||
# fix for people who used prompt_info and hence the signal won't
|
||||
# pass the second argument.
|
||||
$pos = 'UP_INNER' unless defined $pos;
|
||||
_debug_print("Got prompt change signal with: $text, $pos");
|
||||
|
||||
my ($changed_text, $changed_pos);
|
||||
$changed_text = defined $prompt_data ? $prompt_data ne $text : 1;
|
||||
$changed_pos = defined $prompt_data_pos ? $prompt_data_pos ne $pos : 1;
|
||||
|
||||
$prompt_data = $text;
|
||||
$prompt_data_pos = $pos;
|
||||
|
||||
if ($changed_text || $changed_pos) {
|
||||
_debug_print("Redrawing prompt");
|
||||
uberprompt_refresh();
|
||||
}
|
||||
}
|
||||
|
||||
sub _escape_prompt_special {
|
||||
my $str = shift;
|
||||
$str =~ s/\$/\$\$/g;
|
||||
$str =~ s/\\/\\\\/g;
|
||||
#$str =~ s/%/%%/g;
|
||||
$str =~ s/{/\${lbrace}/g;
|
||||
$str =~ s/}/\${rbrace}/g;
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
sub uberprompt_render_prompt {
|
||||
|
||||
my $window = Irssi::active_win;
|
||||
my $prompt_arg = '';
|
||||
|
||||
# default prompt sbar arguments (from config)
|
||||
if (scalar( () = $window->items )) {
|
||||
$prompt_arg = '$[.15]{itemname}';
|
||||
} else {
|
||||
$prompt_arg = '${winname}';
|
||||
}
|
||||
|
||||
my $prompt = ''; # rendered content of the prompt.
|
||||
my $theme = Irssi::current_theme;
|
||||
|
||||
my $arg = $use_replaces ? 0 : Irssi::EXPAND_FLAG_IGNORE_REPLACES;
|
||||
|
||||
if ($prompt_data && (!$trim_data || trim($prompt_data))) {
|
||||
$prompt = $theme->format_expand("{uberprompt $prompt_arg}", $arg);
|
||||
}
|
||||
else {
|
||||
$prompt = $theme->format_expand("{uberprompt_empty $prompt_arg}", $arg);
|
||||
}
|
||||
|
||||
if ($prompt_data_pos eq 'UP_ONLY') {
|
||||
$prompt =~ s/\$\$uber//; # no need for recursive prompting, I hope.
|
||||
|
||||
# TODO: only compute this if necessary?
|
||||
my $prompt_nt = $prompt;
|
||||
$prompt_nt =~ s/\s+$//;
|
||||
|
||||
my $pdata_copy = $prompt_data;
|
||||
|
||||
$pdata_copy =~ s/\$prompt_nt/$prompt_nt/;
|
||||
$pdata_copy =~ s/\$prompt/$prompt/;
|
||||
|
||||
$prompt = $pdata_copy;
|
||||
|
||||
} elsif ($prompt_data_pos eq 'UP_INNER' && defined $prompt_data) {
|
||||
|
||||
my $esc = _escape_prompt_special($prompt_data);
|
||||
$esc = $trim_data ? trim($esc) : $esc;
|
||||
$prompt =~ s/\$\$uber/$esc/;
|
||||
|
||||
} else {
|
||||
# remove the $uber marker
|
||||
$prompt =~ s/\$\$uber//;
|
||||
|
||||
# and add the additional text at the appropriate position.
|
||||
if ($prompt_data_pos eq 'UP_PRE') {
|
||||
$prompt = $prompt_data . $prompt;
|
||||
} elsif ($prompt_data_pos eq 'UP_POST') {
|
||||
$prompt .= $prompt_data;
|
||||
}
|
||||
}
|
||||
|
||||
_debug_print("rendering with: $prompt");
|
||||
|
||||
|
||||
if (($prompt ne $prompt_last) or $emit_request) {
|
||||
|
||||
# _debug_print("Emitting prompt changed signal");
|
||||
# my $exp = Irssi::current_theme()->format_expand($text, 0);
|
||||
my $ps = Irssi::parse_special($prompt);
|
||||
|
||||
Irssi::signal_emit('prompt changed', $ps, length($ps));
|
||||
$prompt_last = $prompt;
|
||||
}
|
||||
return $prompt;
|
||||
}
|
||||
|
||||
sub uberprompt_draw {
|
||||
my ($sb_item, $get_size_only) = @_;
|
||||
|
||||
my $prompt = uberprompt_render_prompt();
|
||||
|
||||
my $ret = $sb_item->default_handler($get_size_only, $prompt, '', 0);
|
||||
_debug_print("redrawing with: $prompt");
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub uberprompt_refresh {
|
||||
Irssi::statusbar_items_redraw('uberprompt');
|
||||
}
|
||||
|
||||
sub replace_prompt_items {
|
||||
# remove existing ones.
|
||||
_debug_print("Removing original prompt");
|
||||
|
||||
_sbar_command('prompt', 'remove', 'prompt');
|
||||
_sbar_command('prompt', 'remove', 'prompt_empty');
|
||||
|
||||
# add the new one.
|
||||
|
||||
_sbar_command('prompt', 'add', 'uberprompt',
|
||||
qw/-alignment left -before input -priority '-1'/);
|
||||
|
||||
_sbar_command('prompt', 'position', '100');
|
||||
|
||||
my $load_hook = $init_callbacks->{load};
|
||||
if (defined $load_hook and length $load_hook) {
|
||||
eval {
|
||||
Irssi::command($load_hook);
|
||||
};
|
||||
if ($@) {
|
||||
_error("Uberprompt user load-hook command ($load_hook) failed: $@");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub restore_prompt_items {
|
||||
|
||||
_sbar_command('prompt', 'remove', 'uberprompt');
|
||||
|
||||
_debug_print("Restoring original prompt");
|
||||
|
||||
_sbar_command('prompt', 'reset');
|
||||
|
||||
my $unload_hook = $init_callbacks->{unload};
|
||||
|
||||
if (defined $unload_hook and length $unload_hook) {
|
||||
eval {
|
||||
Irssi::command($unload_hook);
|
||||
};
|
||||
if ($@) {
|
||||
_error("Uberprompt user unload-hook command ($unload_hook) failed: $@");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub _sbar_command {
|
||||
my ($bar, $cmd, $item, @args) = @_;
|
||||
|
||||
my $args_str = join ' ', @args;
|
||||
|
||||
$args_str .= ' ' if length $args_str && defined $item;
|
||||
|
||||
my $command = sprintf 'STATUSBAR %s %s %s%s',
|
||||
$bar, $cmd, $args_str, defined $item ? $item : '';
|
||||
|
||||
_debug_print("Running command: $command");
|
||||
Irssi::command($command);
|
||||
}
|
||||
|
||||
sub trim {
|
||||
my $string = shift;
|
||||
|
||||
$string =~ s/^\s*//;
|
||||
$string =~ s/\s*$//;
|
||||
|
||||
return $string;
|
||||
}
|
||||
296
home/.irssi/scripts/clones_scanner.pl
Executable file
296
home/.irssi/scripts/clones_scanner.pl
Executable file
@@ -0,0 +1,296 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
{ package Irssi::Nick }
|
||||
# just in case, to avoid Irssi::Nick warnings ( see http://bugs.irssi.org/index.php?do=details&task_id=242 )
|
||||
|
||||
use Irssi;
|
||||
use vars qw($VERSION %IRSSI);
|
||||
|
||||
# Thanks to:
|
||||
# -noi_esportista!#Girona@chathispano for his suggestions about how this script should work.
|
||||
# -dg!#irssi@freenode (David Leadbeater) for the several code style issues that he pointed out and that helped me to improve my Perl.
|
||||
|
||||
$VERSION = '1.6';
|
||||
%IRSSI = (
|
||||
authors => 'Pablo Martín Báez Echevarría',
|
||||
contact => 'pab_24n@outlook.com',
|
||||
name => 'clones_scanner',
|
||||
description => 'when a nick joins #channel, notifies you if there is (or there has been) someone in #channel with the same hostname',
|
||||
license => 'Public Domain',
|
||||
url => 'http://reirssi.wordpress.com',
|
||||
changed => '22:30:25, Dec 20th, 2014 UYT',
|
||||
);
|
||||
|
||||
#
|
||||
# USAGE
|
||||
# =====
|
||||
# Copy the script to ~/.irssi/scripts/
|
||||
#
|
||||
# In irssi:
|
||||
# /run clones_scanner
|
||||
#
|
||||
#
|
||||
# OPTIONS
|
||||
# =======
|
||||
# Settings can be reset to defaults with /set -default
|
||||
#
|
||||
# /set clones_scanner_maxtime <time>
|
||||
# * This is the maximum time in which the script remembers that a specific hostname
|
||||
# left a channel because of a PART, QUIT or KICK event (default is 900secs = 15mins).
|
||||
# For example, suppose it is 1 hour. If someone with mask type nick1!*@host left #channel
|
||||
# at 11:00 and then comes back at 12:01 with mask type nick2!*@host, you will not be
|
||||
# notified that 'nick2' was seen earlier in #channel as 'nick1'.
|
||||
# It must be a time type, that is a series of integers with optional unit specifiers.
|
||||
# Valid specifiers are:
|
||||
#
|
||||
# d[ays]
|
||||
# h[ours]
|
||||
# m[inutes]
|
||||
# s[econds]
|
||||
# mil[liseconds] | ms[econds]
|
||||
#
|
||||
# Any unambiguous part of a specifier can be used, as shown by the strings in braces in
|
||||
# the above list. Multiple specifiers can be combined, with or without spaces between them.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# /set clones_scanner_maxtime 1hour30mins
|
||||
# /set clones_scanner_maxtime 2h
|
||||
# /set clones_scanner_maxtime 3h 10secs
|
||||
#
|
||||
# There must not be a space between the number and the unit specifier.
|
||||
#
|
||||
#
|
||||
# COMMANDS
|
||||
# ========
|
||||
# /clones_scanner_size
|
||||
# * Displays how many entries the data structure where the hosts are stored has, and how much
|
||||
# memory is used for that purpose.
|
||||
#
|
||||
# WARNING: This feature requires Devel::Size module. It seems that when installing Devel::Size
|
||||
# some tests started to fail since Perl 5.19.3 so if you're using the latest Perl release
|
||||
# (Perl 5.20.1) you'll have to wait for someone to fix Devel::Size for recent Perl versions.
|
||||
# See more about this issue at: https://rt.cpan.org/Public/Bug/Display.html?id=95493
|
||||
# Remeber that you can find out Perl version with
|
||||
# $ perl -v
|
||||
# in a terminal or alternatively executing /script exec print $^V in irssi.
|
||||
#
|
||||
|
||||
|
||||
Irssi::settings_add_time('clones_scanner', 'clones_scanner_maxtime', 900);
|
||||
|
||||
# global variables
|
||||
my $have_devel_size = eval { require Devel::Size };
|
||||
my %hosts_hash = ();
|
||||
my $old_maxtime_msecs;
|
||||
my $old_maxtime_str;
|
||||
my $total_entries = 0;
|
||||
|
||||
##########
|
||||
|
||||
sub add_entry {
|
||||
my ( $network, $channel, $address, $nick ) = @_;
|
||||
|
||||
(my $host = $address) =~ s/^[^@]+@//;
|
||||
|
||||
if (defined $hosts_hash{$network}{$channel}{$host}) {
|
||||
my $old_tag = $hosts_hash{$network}{$channel}{$host}[2];
|
||||
Irssi::timeout_remove( $old_tag );
|
||||
$total_entries--;
|
||||
}
|
||||
|
||||
my $time = Irssi::settings_get_time("clones_scanner_maxtime");
|
||||
my @data = ( $network, $channel, $host );
|
||||
my $tag = Irssi::timeout_add_once($time, "remove_entry", \@data);
|
||||
|
||||
my $entry = [$nick, time(), $tag];
|
||||
$hosts_hash{$network}{$channel}{$host} = $entry;
|
||||
$total_entries++;
|
||||
|
||||
}
|
||||
|
||||
sub str_time {
|
||||
my ( $secs ) = @_;
|
||||
|
||||
my $d = int($secs/3600/24);
|
||||
my $h = int($secs/3600%24);
|
||||
my $m = int($secs/60%60);
|
||||
my $s = int($secs%60);
|
||||
|
||||
my $d_str = ($d == 1) ? "day": "days";
|
||||
my $h_str = ($h == 1) ? "hour": "hours";
|
||||
my $m_str = ($m == 1) ? "minute": "minutes";
|
||||
my $s_str = ($s == 1) ? "second": "seconds";
|
||||
|
||||
my $raw_str = $d.$d_str.", ".$h.$h_str.", ".$m.$m_str.", ".$s.$s_str;
|
||||
|
||||
(my $str_res = $raw_str) =~ s/\b0\w+(?:,\s)?//g;
|
||||
($str_res = $str_res) =~ s/,\s$//;
|
||||
($str_res = $str_res) =~ s/(\d)([dhms])/$1 $2/g;
|
||||
|
||||
return $str_res eq "" ? "less than 1 second" : $str_res;
|
||||
}
|
||||
|
||||
sub remove_entry {
|
||||
my ( $ref_data ) = @_;
|
||||
|
||||
my $network = @{$ref_data}[0];
|
||||
my $chan = @{$ref_data}[1];
|
||||
my $host = @{$ref_data}[2];
|
||||
|
||||
delete $hosts_hash{$network}{$chan}{$host};
|
||||
$total_entries--;
|
||||
delete $hosts_hash{$network}{$chan} if (!keys %{$hosts_hash{$network}{$chan}});
|
||||
delete $hosts_hash{$network} if (!keys %{$hosts_hash{$network}});
|
||||
}
|
||||
|
||||
sub update_hash {
|
||||
my ( $nw_maxtime ) = @_;
|
||||
my $remainder;
|
||||
my $ni;
|
||||
my $se;
|
||||
my $tg;
|
||||
my $nw_tg;
|
||||
|
||||
foreach my $network (keys %hosts_hash) {
|
||||
foreach my $channel (keys %{$hosts_hash{$network}}) {
|
||||
foreach my $host (keys %{$hosts_hash{$network}{$channel}}) {
|
||||
$ni = @{$hosts_hash{$network}{$channel}{$host}}[0];
|
||||
$se = @{$hosts_hash{$network}{$channel}{$host}}[1];
|
||||
$tg = @{$hosts_hash{$network}{$channel}{$host}}[2];
|
||||
Irssi::timeout_remove( $tg );
|
||||
$remainder = $nw_maxtime - (time() - $se);
|
||||
if( $remainder > 0 ) {
|
||||
my @data = ( $network, $channel, $host );
|
||||
$nw_tg = Irssi::timeout_add_once( $remainder*1000, "remove_entry", \@data);
|
||||
$hosts_hash{$network}{$channel}{$host} = [$ni, $se, $nw_tg];
|
||||
} else {
|
||||
delete $hosts_hash{$network}{$channel}{$host};
|
||||
$total_entries--;
|
||||
}
|
||||
}
|
||||
delete $hosts_hash{$network}{$channel} if (!keys %{$hosts_hash{$network}{$channel}});
|
||||
}
|
||||
delete $hosts_hash{$network} if (!keys %{$hosts_hash{$network}});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub setup_changed {
|
||||
my $new_maxtime_msecs = Irssi::settings_get_time("clones_scanner_maxtime");
|
||||
if($new_maxtime_msecs < 10) {
|
||||
Irssi::print("Invalid timestamp (must be >= 10 msecs)", MSGLEVEL_CLIENTERROR);
|
||||
Irssi::settings_set_time("clones_scanner_maxtime", $old_maxtime_str);
|
||||
$new_maxtime_msecs = Irssi::settings_get_time("clones_scanner_maxtime");
|
||||
}
|
||||
update_hash(int($new_maxtime_msecs/1000)) if ($new_maxtime_msecs != $old_maxtime_msecs);
|
||||
}
|
||||
|
||||
##########
|
||||
|
||||
sub part_method {
|
||||
my ($server, $channel, $nick, $address, $reason) = @_;
|
||||
|
||||
add_entry($server->{tag}, $channel, $address, $nick);
|
||||
}
|
||||
|
||||
sub quit_method {
|
||||
my ($server, $nick, $address, $reason) = @_;
|
||||
|
||||
foreach($server->channels()) {
|
||||
if ($_->nick_find($nick)) {
|
||||
add_entry($server->{tag}, $_->{name}, $address, $nick);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub kick_method {
|
||||
my ($server, $channel, $nick, $kicker, $address, $reason) = @_;
|
||||
|
||||
Irssi::signal_stop();
|
||||
my $kicked_address = $server->channel_find($channel)->nick_find($nick)->{host};
|
||||
Irssi::signal_continue(@_);
|
||||
add_entry($server->{tag}, $channel, $kicked_address, $nick);
|
||||
}
|
||||
|
||||
##########
|
||||
|
||||
sub join_method {
|
||||
my ($server, $channel, $nick, $address) = @_;
|
||||
|
||||
Irssi::signal_continue(@_);
|
||||
|
||||
my $servtag = $server->{tag};
|
||||
(my $host = $address) =~ s/^[^@]+@//;
|
||||
my $chan_rec = $server->channel_find($channel);
|
||||
|
||||
# ==== find clones ====
|
||||
my $ni_host;
|
||||
my $str_clones = "";
|
||||
my @clones;
|
||||
foreach my $ni ($chan_rec->nicks()) {
|
||||
($ni_host = "$ni->{host}") =~ s/^[^@]+@//;
|
||||
if ( ($ni->{nick} ne $nick)&&($ni_host eq $host) ) {
|
||||
$str_clones .= "$ni->{nick}".", ";
|
||||
push @clones, $ni->{nick};
|
||||
}
|
||||
}
|
||||
if( $str_clones ne "") {
|
||||
($str_clones = $str_clones) =~ s/,\s$//;
|
||||
$chan_rec->printformat(Irssi::MSGLEVEL_JOINS, "clones_scanner_clones", $nick, $str_clones);
|
||||
}
|
||||
|
||||
# ==== search in %hosts_hash ====
|
||||
my $exists_nick_in_hash = (defined $hosts_hash{$servtag})&&(defined $hosts_hash{$servtag}{$channel})
|
||||
&&(defined $hosts_hash{$servtag}{$channel}{$host});
|
||||
|
||||
if ($exists_nick_in_hash) {
|
||||
my @alias = @{ $hosts_hash{$servtag}{$channel}{$host} };
|
||||
if ( ($nick ne $alias[0]) && (!(grep {$_ eq $alias[0]} @clones)) ) {
|
||||
my $time = Irssi::settings_get_time("clones_scanner_maxtime");
|
||||
$chan_rec->printformat( Irssi::MSGLEVEL_JOINS, "clones_scanner_track_nick", $nick, str_time(int($time/1000)),
|
||||
$alias[0], str_time(time()-$alias[1]));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
##########
|
||||
|
||||
Irssi::theme_register([
|
||||
"clones_scanner_clones", 'Clones of {nick $0}: $1',
|
||||
"clones_scanner_track_nick", '=> {nick $0} was seen during the last $1 as {nick $2} ($3 ago)',
|
||||
]);
|
||||
|
||||
##########
|
||||
|
||||
|
||||
if ($have_devel_size) {
|
||||
|
||||
Irssi::command_bind('clones_scanner_size' , sub {
|
||||
my $bytes = Devel::Size::total_size(\%hosts_hash);
|
||||
print "Number of entries in \%hosts_hash: ", $total_entries;
|
||||
print "Size in bytes: ", $bytes;
|
||||
print int($bytes/1024/1024)."MB ".int($bytes/1024%1024)."kB ".int($bytes%1024)."B of data";
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
print "Missing Devel::Size module. The command `/clones_scanner_size` will not be available.";
|
||||
|
||||
}
|
||||
|
||||
Irssi::signal_add_first('message part', \&part_method);
|
||||
Irssi::signal_add_first('message quit', \&quit_method);
|
||||
Irssi::signal_add_first('message kick', \&kick_method);
|
||||
|
||||
Irssi::signal_add_last('message join', \&join_method);
|
||||
|
||||
Irssi::signal_add_last('setup changed', \&setup_changed);
|
||||
|
||||
Irssi::signal_add_first('send command',
|
||||
sub {
|
||||
$old_maxtime_msecs = Irssi::settings_get_time("clones_scanner_maxtime");
|
||||
$old_maxtime_str = Irssi::settings_get_str("clones_scanner_maxtime");
|
||||
});
|
||||
39
home/.irssi/scripts/fifo_input.pl
Normal file
39
home/.irssi/scripts/fifo_input.pl
Normal file
@@ -0,0 +1,39 @@
|
||||
use strict;
|
||||
use Irssi;
|
||||
use IO::Handle;
|
||||
use POSIX;
|
||||
|
||||
our $pipe_path = "/tmp/irssi_pipe";
|
||||
our $pipe_fh;
|
||||
|
||||
Irssi::settings_add_str('fifo_input', 'fifo_pipe_path', $pipe_path);
|
||||
|
||||
sub fifo_input_open {
|
||||
$pipe_path = Irssi::settings_get_str('fifo_pipe_path');
|
||||
unless (-p $pipe_path) {
|
||||
mkfifo($pipe_path, 0700) or die "Cannot create FIFO pipe: $!";
|
||||
}
|
||||
|
||||
open($pipe_fh, '<', $pipe_path) or die "Cannot open FIFO pipe: $!";
|
||||
$pipe_fh->blocking(0);
|
||||
Irssi::input_add(fileno($pipe_fh), Irssi::INPUT_READ, \&fifo_input_read, undef);
|
||||
}
|
||||
|
||||
sub fifo_input_read {
|
||||
while (my $line = <$pipe_fh>) {
|
||||
chomp $line;
|
||||
Irssi::command($line);
|
||||
}
|
||||
}
|
||||
|
||||
sub fifo_input_close {
|
||||
Irssi::input_remove(fileno($pipe_fh));
|
||||
close($pipe_fh);
|
||||
}
|
||||
|
||||
Irssi::signal_add('setup changed', \&fifo_input_open);
|
||||
Irssi::command_bind('fifo_close', \&fifo_input_close);
|
||||
|
||||
fifo_input_open();
|
||||
|
||||
Irssi::print("FIFO input script loaded. Listening on $pipe_path");
|
||||
253
home/.irssi/scripts/nickcolor.pl
Executable file
253
home/.irssi/scripts/nickcolor.pl
Executable file
@@ -0,0 +1,253 @@
|
||||
use strict;
|
||||
use Irssi 20020101.0250 ();
|
||||
use vars qw($VERSION %IRSSI);
|
||||
$VERSION = "2.1";
|
||||
%IRSSI = (
|
||||
authors => "Timo Sirainen, Ian Peters, David Leadbeater, Bruno Cattáneo",
|
||||
contact => "tss\@iki.fi",
|
||||
name => "Nick Color",
|
||||
description => "assign a different color for each nick",
|
||||
license => "Public Domain",
|
||||
url => "http://irssi.org/",
|
||||
changed => "Mon 08 Jan 21:28:53 BST 2018",
|
||||
);
|
||||
|
||||
# Settings:
|
||||
# nickcolor_colors: List of color codes to use.
|
||||
# e.g. /set nickcolor_colors 2 3 4 5 6 7 9 10 11 12 13
|
||||
# (avoid 8, as used for hilights in the default theme).
|
||||
#
|
||||
# nickcolor_enable_prefix: Enables prefix for same nick.
|
||||
#
|
||||
# nickcolor_enable_truncate: Enables nick truncation.
|
||||
#
|
||||
# nickcolor_prefix_text: Prefix text for succesive messages.
|
||||
# e.g. /set nickcolor_prefix_text -
|
||||
#
|
||||
# nickcolor_truncate_value: Truncate nick value.
|
||||
# e.g. /set nickcolor_truncate_value -7
|
||||
# This will truncate nicknames at 7 characters and make them right aligned
|
||||
|
||||
my %saved_colors;
|
||||
my %session_colors = {};
|
||||
my %saved_nicks; # To store each channel's last nickname
|
||||
|
||||
sub load_colors {
|
||||
open my $color_fh, "<", "$ENV{HOME}/.irssi/saved_colors";
|
||||
while (<$color_fh>) {
|
||||
chomp;
|
||||
my($nick, $color) = split ":";
|
||||
$saved_colors{$nick} = $color;
|
||||
}
|
||||
}
|
||||
|
||||
sub save_colors {
|
||||
open COLORS, ">", "$ENV{HOME}/.irssi/saved_colors";
|
||||
|
||||
foreach my $nick (keys %saved_colors) {
|
||||
print COLORS "$nick:$saved_colors{$nick}\n";
|
||||
}
|
||||
|
||||
close COLORS;
|
||||
}
|
||||
|
||||
# If someone we've colored (either through the saved colors, or the hash
|
||||
# function) changes their nick, we'd like to keep the same color associated
|
||||
# with them (but only in the session_colors, ie a temporary mapping).
|
||||
|
||||
sub sig_nick {
|
||||
my ($server, $newnick, $nick, $address) = @_;
|
||||
my $color;
|
||||
|
||||
$newnick = substr ($newnick, 1) if ($newnick =~ /^:/);
|
||||
|
||||
if ($color = $saved_colors{$nick}) {
|
||||
$session_colors{$newnick} = $color;
|
||||
} elsif ($color = $session_colors{$nick}) {
|
||||
$session_colors{$newnick} = $color;
|
||||
}
|
||||
}
|
||||
|
||||
# This gave reasonable distribution values when run across
|
||||
# /usr/share/dict/words
|
||||
|
||||
sub simple_hash {
|
||||
my ($string) = @_;
|
||||
chomp $string;
|
||||
my @chars = split //, $string;
|
||||
my $counter;
|
||||
|
||||
foreach my $char (@chars) {
|
||||
$counter += ord $char;
|
||||
}
|
||||
|
||||
my @colors = split / /, Irssi::settings_get_str('nickcolor_colors');
|
||||
$counter = $colors[$counter % @colors];
|
||||
|
||||
return $counter;
|
||||
}
|
||||
|
||||
# process public (others) messages
|
||||
sub sig_public {
|
||||
my ($server, $msg, $nick, $address, $target) = @_;
|
||||
|
||||
my $enable_prefix = Irssi::settings_get_bool('nickcolor_enable_prefix');
|
||||
my $enable_truncate = Irssi::settings_get_bool('nickcolor_enable_truncate');
|
||||
my $prefix_text = Irssi::settings_get_str('nickcolor_prefix_text');
|
||||
my $truncate_value = Irssi::settings_get_int('nickcolor_truncate_value');
|
||||
|
||||
# Reference for server/channel
|
||||
my $tagtarget = "$server->{tag}/$target";
|
||||
|
||||
# Set default nick truncate value to 0 if option is disabled
|
||||
$truncate_value = 0 if (!$enable_truncate);
|
||||
|
||||
# Has the user assigned this nick a color?
|
||||
my $color = $saved_colors{$nick};
|
||||
|
||||
# Have -we- already assigned this nick a color?
|
||||
if (!$color) {
|
||||
$color = $session_colors{$nick};
|
||||
}
|
||||
|
||||
# Let's assign this nick a color
|
||||
if (!$color) {
|
||||
$color = simple_hash $nick;
|
||||
$session_colors{$nick} = $color;
|
||||
}
|
||||
|
||||
$color = sprintf "\003%02d", $color;
|
||||
|
||||
# Optional: We check if it's the same nickname for current target
|
||||
if ($saved_nicks{$tagtarget} eq $nick && $enable_prefix)
|
||||
{
|
||||
# Grouped message
|
||||
Irssi::command('/^format pubmsg ' . $prefix_text . '$1');
|
||||
}
|
||||
else
|
||||
{
|
||||
# Normal message
|
||||
Irssi::command('/^format pubmsg {pubmsgnick $2 {pubnick ' . $color . '$[' . $truncate_value . ']0}}$1');
|
||||
|
||||
# Save nickname for next message
|
||||
$saved_nicks{$tagtarget} = $nick;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# process public (me) messages
|
||||
sub sig_me {
|
||||
my ($server, $msg, $target) = @_;
|
||||
my $nick = $server->{nick};
|
||||
|
||||
my $enable_prefix = Irssi::settings_get_bool('nickcolor_enable_prefix');
|
||||
my $enable_truncate = Irssi::settings_get_bool('nickcolor_enable_truncate');
|
||||
my $prefix_text = Irssi::settings_get_str('nickcolor_prefix_text');
|
||||
my $truncate_value = Irssi::settings_get_int('nickcolor_truncate_value');
|
||||
|
||||
# Reference for server/channel
|
||||
my $tagtarget = "$server->{tag}/$target";
|
||||
|
||||
# Set default nick truncate value to 0 if option is disabled
|
||||
$truncate_value = 0 if (!$enable_truncate);
|
||||
|
||||
# Optional: We check if it's the same nickname for current target
|
||||
if ($saved_nicks{$tagtarget} eq $nick && $enable_prefix)
|
||||
{
|
||||
# Grouped message
|
||||
Irssi::command('/^format own_msg ' . $prefix_text . '$1');
|
||||
}
|
||||
else
|
||||
{
|
||||
# Normal message
|
||||
Irssi::command('/^format own_msg {ownmsgnick $2 {ownnick $[' . $truncate_value . ']0}}$1');
|
||||
|
||||
# Save nickname for next message
|
||||
$saved_nicks{$tagtarget} = $nick;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# process public (others) actions
|
||||
sub sig_action_public {
|
||||
my ($server, $msg, $nick, $address, $target) = @_;
|
||||
|
||||
my $enable_prefix = Irssi::settings_get_bool('nickcolor_enable_prefix');
|
||||
|
||||
# Reference for server/channel
|
||||
my $tagtarget = "$server->{tag}/$target";
|
||||
|
||||
# Empty current target nick if prefix option is enabled
|
||||
$saved_nicks{$tagtarget} = '' if ($enable_prefix);
|
||||
|
||||
}
|
||||
|
||||
# process public (me) actions
|
||||
sub sig_action_me {
|
||||
my ($server, $msg, $target) = @_;
|
||||
my $nick = $server->{nick};
|
||||
|
||||
my $enable_prefix = Irssi::settings_get_bool('nickcolor_enable_prefix');
|
||||
|
||||
# Reference for server/channel
|
||||
my $tagtarget = "$server->{tag}/$target";
|
||||
|
||||
# Empty current target nick if prefix option is enabled
|
||||
$saved_nicks{$tagtarget} = '' if ($enable_prefix);
|
||||
|
||||
}
|
||||
|
||||
sub cmd_color {
|
||||
my ($data, $server, $witem) = @_;
|
||||
my ($op, $nick, $color) = split " ", $data;
|
||||
|
||||
$op = lc $op;
|
||||
|
||||
if (!$op) {
|
||||
Irssi::print ("No operation given (save/set/clear/list/preview)");
|
||||
} elsif ($op eq "save") {
|
||||
save_colors;
|
||||
} elsif ($op eq "set") {
|
||||
if (!$nick) {
|
||||
Irssi::print ("Nick not given");
|
||||
} elsif (!$color) {
|
||||
Irssi::print ("Color not given");
|
||||
} elsif ($color < 2 || $color > 14) {
|
||||
Irssi::print ("Color must be between 2 and 14 inclusive");
|
||||
} else {
|
||||
$saved_colors{$nick} = $color;
|
||||
}
|
||||
} elsif ($op eq "clear") {
|
||||
if (!$nick) {
|
||||
Irssi::print ("Nick not given");
|
||||
} else {
|
||||
delete ($saved_colors{$nick});
|
||||
}
|
||||
} elsif ($op eq "list") {
|
||||
Irssi::print ("\nSaved Colors:");
|
||||
foreach my $nick (keys %saved_colors) {
|
||||
Irssi::print (chr (3) . sprintf("%02d", $saved_colors{$nick}) . "$nick" .
|
||||
chr (3) . "1 ($saved_colors{$nick})");
|
||||
}
|
||||
} elsif ($op eq "preview") {
|
||||
Irssi::print ("\nAvailable colors:");
|
||||
foreach my $i (2..14) {
|
||||
Irssi::print (chr (3) . "$i" . "Color #$i");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
load_colors;
|
||||
|
||||
Irssi::settings_add_str('misc', 'nickcolor_colors', '2 3 4 5 6 7 9 10 11 12 13');
|
||||
Irssi::settings_add_bool('misc', 'nickcolor_enable_prefix', 0);
|
||||
Irssi::settings_add_bool('misc', 'nickcolor_enable_truncate', 0);
|
||||
Irssi::settings_add_str('misc', 'nickcolor_prefix_text' => '- ');
|
||||
Irssi::settings_add_int('misc', 'nickcolor_truncate_value' => 0);
|
||||
Irssi::command_bind('color', 'cmd_color');
|
||||
|
||||
Irssi::signal_add('message public', 'sig_public');
|
||||
Irssi::signal_add('message own_public', 'sig_me');
|
||||
Irssi::signal_add('message irc action', 'sig_action_public');
|
||||
Irssi::signal_add('message irc own_action', 'sig_action_me');
|
||||
Irssi::signal_add('event nick', 'sig_nick');
|
||||
828
home/.irssi/scripts/nicklist.pl
Executable file
828
home/.irssi/scripts/nicklist.pl
Executable file
@@ -0,0 +1,828 @@
|
||||
# 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 <coekie@irssi.org>
|
||||
#
|
||||
# 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.12';
|
||||
%IRSSI = (
|
||||
authors => 'Wouter Coekaerts',
|
||||
contact => 'coekie@irssi.org',
|
||||
name => 'nicklist',
|
||||
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 => '2018-10-02'
|
||||
);
|
||||
|
||||
sub cmd_help {
|
||||
print ( <<EOF
|
||||
Commands:
|
||||
NICKLIST HELP
|
||||
NICKLIST SCROLL <nr of lines>
|
||||
NICKLIST SCREEN
|
||||
NICKLIST FIFO
|
||||
NICKLIST ON
|
||||
NICKLIST OFF
|
||||
NICKLIST TOGGLE
|
||||
NICKLIST UPDATE
|
||||
|
||||
For help see: http://wouter.coekaerts.be/site/irssi/nicklist
|
||||
|
||||
in short:
|
||||
|
||||
1. FIFO MODE
|
||||
- in irssi: /NICKLIST FIFO (only the first time, to create the fifo)
|
||||
- in a shell, in a window where you want the nicklist: cat ~/.irssi/nicklistfifo
|
||||
- back in irssi:
|
||||
/SET nicklist_heigth <height of nicklist>
|
||||
/SET nicklist_width <width of nicklist>
|
||||
/NICKLIST FIFO
|
||||
|
||||
2. SCREEN MODE
|
||||
- start irssi inside screen ("screen irssi")
|
||||
- /NICKLIST SCREEN
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
my $prev_lines = 0; # number of lines in previous written nicklist
|
||||
my $scroll_pos = 0; # scrolling position
|
||||
my $cursor_line; # line the cursor is currently on
|
||||
my ($OFF, $SCREEN, $FIFO) = (0,1,2); # modes
|
||||
my $mode = $OFF; # current mode
|
||||
my $need_redraw = 0; # nicklist needs redrawing
|
||||
my $screen_resizing = 0; # terminal is being resized
|
||||
my $active_channel; # (REC)
|
||||
|
||||
my @nicklist=(); # array of hashes, containing the internal nicklist of the active channel
|
||||
# nick => realnick
|
||||
# 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, $check_friends, @prefix_friends);
|
||||
|
||||
sub read_settings {
|
||||
($screen_prefix = Irssi::settings_get_str('nicklist_screen_prefix')) =~ 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 <mode character>=<prefix>");
|
||||
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 <flags>=<prefix>");
|
||||
last;
|
||||
} else {
|
||||
push @prefix_friends, {'flags' => $1, 'prefix' => $2};
|
||||
}
|
||||
}
|
||||
|
||||
$check_friends = ($prefix_friends ne '');
|
||||
|
||||
if ($mode != $SCREEN) {
|
||||
$height = Irssi::settings_get_int('nicklist_height');
|
||||
}
|
||||
my $new_nicklist_width = Irssi::settings_get_int('nicklist_width');
|
||||
if ($new_nicklist_width != $nicklist_width && $mode == $SCREEN) {
|
||||
sig_terminal_resized();
|
||||
}
|
||||
$nicklist_width = $new_nicklist_width;
|
||||
}
|
||||
|
||||
sub update {
|
||||
read_settings();
|
||||
make_nicklist();
|
||||
}
|
||||
|
||||
##################
|
||||
##### OUTPUT #####
|
||||
##################
|
||||
|
||||
### on ###
|
||||
|
||||
sub cmd_on {
|
||||
if (uc(Irssi::settings_get_str('nicklist_automode')) eq 'SCREEN') {
|
||||
cmd_screen_start();
|
||||
} elsif (uc(Irssi::settings_get_str('nicklist_automode')) eq 'FIFO') {
|
||||
cmd_fifo_start();
|
||||
}
|
||||
}
|
||||
|
||||
### off ###
|
||||
|
||||
sub cmd_off {
|
||||
if ($mode == $SCREEN) {
|
||||
screen_stop();
|
||||
} elsif ($mode == $FIFO) {
|
||||
fifo_stop();
|
||||
}
|
||||
}
|
||||
|
||||
### toggle ###
|
||||
|
||||
sub cmd_toggle {
|
||||
if ($mode == $OFF) {
|
||||
cmd_on();
|
||||
} else {
|
||||
cmd_off();
|
||||
}
|
||||
}
|
||||
|
||||
### fifo ###
|
||||
|
||||
sub cmd_fifo_start {
|
||||
read_settings();
|
||||
my $path = Irssi::settings_get_str('nicklist_fifo_path');
|
||||
unless (-p $path) { # not a pipe
|
||||
if (-e _) { # but a something else
|
||||
die "$0: $path exists and is not a pipe, please remove it\n";
|
||||
} else {
|
||||
require POSIX;
|
||||
POSIX::mkfifo($path, 0666) or die "can\'t mkfifo $path: $!";
|
||||
Irssi::print("Fifo created. Start reading it (\"cat $path\") and try again.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!sysopen(FIFO, $path, O_WRONLY | O_NONBLOCK)) { # or die "can't write $path: $!";
|
||||
Irssi::print("Couldn\'t write to the fifo ($!). Please start reading the fifo (\"cat $path\") and try again.");
|
||||
return;
|
||||
}
|
||||
FIFO->autoflush(1);
|
||||
print FIFO "\033[2J\033[1;1H"; # erase screen & jump to 0,0
|
||||
$cursor_line = 0;
|
||||
if ($mode == $SCREEN) {
|
||||
screen_stop();
|
||||
}
|
||||
$mode = $FIFO;
|
||||
make_nicklist();
|
||||
}
|
||||
|
||||
sub fifo_stop {
|
||||
close FIFO;
|
||||
$mode = $OFF;
|
||||
Irssi::print("Fifo closed.");
|
||||
}
|
||||
|
||||
### screen ###
|
||||
|
||||
sub cmd_screen_start {
|
||||
if (!defined($ENV{'STY'})) {
|
||||
Irssi::print 'screen not detected, screen mode only works inside screen';
|
||||
return;
|
||||
}
|
||||
read_settings();
|
||||
if ($mode == $SCREEN) {return;}
|
||||
if ($mode == $FIFO) {
|
||||
fifo_stop();
|
||||
}
|
||||
$mode = $SCREEN;
|
||||
Irssi::signal_add_last('gui print text finished', \&sig_gui_print_text_finished);
|
||||
Irssi::signal_add_last('gui page scrolled', \&sig_page_scrolled);
|
||||
Irssi::signal_add('terminal resized', \&sig_terminal_resized);
|
||||
screen_size();
|
||||
make_nicklist();
|
||||
}
|
||||
|
||||
sub screen_stop {
|
||||
$mode = $OFF;
|
||||
Irssi::signal_remove('gui print text finished', \&sig_gui_print_text_finished);
|
||||
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;
|
||||
}
|
||||
$screen_resizing = 1;
|
||||
# fit screen
|
||||
system 'screen -x '.$ENV{'STY'}.' -X fit';
|
||||
# get size (from perldoc -q size)
|
||||
my ($winsize, $row, $col, $xpixel, $ypixel);
|
||||
eval 'use Term::ReadKey; ($col, $row, $xpixel, $ypixel) = GetTerminalSize';
|
||||
# require Term::ReadKey 'GetTerminalSize';
|
||||
# ($col, $row, $xpixel, $ypixel) = Term::ReadKey::GetTerminalSize;
|
||||
#};
|
||||
if ($@) { # no Term::ReadKey, try the ugly way
|
||||
eval {
|
||||
require 'sys/ioctl.ph';
|
||||
# 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";
|
||||
}
|
||||
open(TTY, "+<","/dev/tty") or die "No tty: $!";
|
||||
unless (ioctl(TTY, &TIOCGWINSZ, $winsize='')) {
|
||||
die "Term::ReadKey not found, and ioctl 'workaround' failed ($!). Install the Term::ReadKey perl module to use screen mode.\n";
|
||||
}
|
||||
close(TTY);
|
||||
($row, $col, $xpixel, $ypixel) = unpack('S4', $winsize);
|
||||
}
|
||||
|
||||
# set screen width
|
||||
$irssi_width = $col-$nicklist_width-1;
|
||||
$height = $row-1;
|
||||
|
||||
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 {
|
||||
if ($screen_resizing) {
|
||||
return;
|
||||
}
|
||||
$screen_resizing = 1;
|
||||
Irssi::timeout_add_once(1000,\&screen_size,[]);
|
||||
}
|
||||
|
||||
|
||||
### both ###
|
||||
|
||||
sub nicklist_write_start {
|
||||
if ($mode == $SCREEN) {
|
||||
print STDERR "\033P\0337\033\\"; # save cursor
|
||||
}
|
||||
}
|
||||
|
||||
sub nicklist_write_end {
|
||||
if ($mode == $SCREEN) {
|
||||
print STDERR "\033P\0338\033\\"; # restore cursor
|
||||
}
|
||||
}
|
||||
|
||||
sub nicklist_write_line {
|
||||
my ($line, $data) = @_;
|
||||
if ($mode == $SCREEN) {
|
||||
print STDERR "\033P\033[" . ($line+1) . ';'. ($irssi_width+1) .'H'. $screen_prefix . $data . "\033\\";
|
||||
} elsif ($mode == $FIFO) {
|
||||
$data = "\033[m$data"; # reset color
|
||||
if ($line == $cursor_line+1) {
|
||||
$data = "\n$data"; # next line
|
||||
} elsif ($line == $cursor_line) {
|
||||
$data = "\033[1G".$data; # back to beginning of line
|
||||
} else {
|
||||
$data = "\033[".($line+1).";0H".$data; # jump
|
||||
}
|
||||
$cursor_line=$line;
|
||||
print(FIFO $data) or fifo_stop();
|
||||
}
|
||||
}
|
||||
|
||||
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~/; # 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
|
||||
sub redraw_nick_nr {
|
||||
my ($nr) = @_;
|
||||
my $line = $nr - $scroll_pos;
|
||||
if ($line >= 0 && $line < $height) {
|
||||
nicklist_write_line($line, $nicklist[$nr]->{'text'});
|
||||
}
|
||||
}
|
||||
|
||||
# nick was inserted, redraw area if necessary
|
||||
sub draw_insert_nick_nr {
|
||||
my ($nr) = @_;
|
||||
my $line = $nr - $scroll_pos;
|
||||
if ($line < 0) { # nick is inserted above visible area
|
||||
$scroll_pos++; # 'scroll' down :)
|
||||
} elsif ($line < $height) { # line is visible
|
||||
if ($mode == $SCREEN) {
|
||||
need_redraw();
|
||||
} elsif ($mode == $FIFO) {
|
||||
my $data = "\033[m\033[L". $nicklist[$nr]->{'text'}; # reset color & insert line & write nick
|
||||
if ($line == $cursor_line) {
|
||||
$data = "\033[1G".$data; # back to beginning of line
|
||||
} else {
|
||||
$data = "\033[".($line+1).";1H".$data; # jump
|
||||
}
|
||||
$cursor_line=$line;
|
||||
print(FIFO $data) or fifo_stop();
|
||||
if ($prev_lines < $height) {
|
||||
$prev_lines++; # the nicklist has one line more
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub draw_remove_nick_nr {
|
||||
my ($nr) = @_;
|
||||
my $line = $nr - $scroll_pos;
|
||||
if ($line < 0) { # nick removed above visible area
|
||||
$scroll_pos--; # 'scroll' up :)
|
||||
} elsif ($line < $height) { # line is visible
|
||||
if ($mode == $SCREEN) {
|
||||
need_redraw();
|
||||
} elsif ($mode == $FIFO) {
|
||||
#my $data = "\033[m\033[L[i$line]". $nicklist[$nr]->{'text'}; # reset color & insert line & write nick
|
||||
my $data = "\033[M"; # delete line
|
||||
if ($line != $cursor_line) {
|
||||
$data = "\033[".($line+1)."d".$data; # jump
|
||||
}
|
||||
$cursor_line=$line;
|
||||
print(FIFO $data) or fifo_stop();
|
||||
if (@nicklist-$scroll_pos >= $height) {
|
||||
redraw_nick_nr($scroll_pos+$height-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# redraw the whole nicklist
|
||||
sub redraw {
|
||||
$need_redraw = 0;
|
||||
#make_nicklist();
|
||||
nicklist_write_start();
|
||||
my $line = 0;
|
||||
### draw nicklist ###
|
||||
for (my $i=$scroll_pos;$line < $height && $i < @nicklist; $i++) {
|
||||
nicklist_write_line($line++, $nicklist[$i]->{'text'});
|
||||
}
|
||||
|
||||
### clean up other lines ###
|
||||
my $real_lines = $line;
|
||||
while($line < $prev_lines) {
|
||||
nicklist_write_line($line++,' ' x $nicklist_width);
|
||||
}
|
||||
$prev_lines = $real_lines;
|
||||
nicklist_write_end();
|
||||
}
|
||||
|
||||
# redraw (with little delay to avoid redrawing to much)
|
||||
sub need_redraw {
|
||||
if(!$need_redraw) {
|
||||
$need_redraw = 1;
|
||||
Irssi::timeout_add_once(10,\&redraw,[]);
|
||||
}
|
||||
}
|
||||
|
||||
sub sig_page_scrolled {
|
||||
$prev_lines = $height; # we'll need to redraw everything if he scrolled up
|
||||
need_redraw;
|
||||
}
|
||||
|
||||
# redraw (with delay) if the window is visible (only in screen mode)
|
||||
sub sig_gui_print_text_finished {
|
||||
if ($need_redraw) { # there's already a redraw 'queued'
|
||||
return;
|
||||
}
|
||||
my $window = @_[0];
|
||||
if ($window->{'refnum'} == Irssi::active_win->{'refnum'} || Irssi::settings_get_str('nicklist_screen_split_windows') eq '*') {
|
||||
need_redraw;
|
||||
return;
|
||||
}
|
||||
foreach my $win (split(/[ ,]/, Irssi::settings_get_str('nicklist_screen_split_windows'))) {
|
||||
if ($window->{'refnum'} == $win || $window->{'name'} eq $win) {
|
||||
need_redraw;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
###################
|
||||
##### 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 #####
|
||||
####################
|
||||
|
||||
# returns the position of the given nick(as string) in the (internal) nicklist
|
||||
sub find_nick {
|
||||
my ($nick) = @_;
|
||||
for (my $i=0;$i < @nicklist; $i++) {
|
||||
if ($nicklist[$i]->{'nick'} eq $nick) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
# find position where nick should be inserted into the list
|
||||
sub find_insert_pos {
|
||||
my ($cmp)= @_;
|
||||
for (my $i=0;$i < @nicklist; $i++) {
|
||||
if ($nicklist[$i]->{'cmp'} gt $cmp) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
return scalar(@nicklist); #last
|
||||
}
|
||||
|
||||
# make the (internal) nicklist (@nicklist)
|
||||
sub make_nicklist {
|
||||
@nicklist = ();
|
||||
$scroll_pos = 0;
|
||||
|
||||
### get & check channel ###
|
||||
my $channel = Irssi::active_win->{active};
|
||||
|
||||
if (!$channel || (ref($channel) ne 'Irssi::Irc::Channel' && ref($channel) ne 'Irssi::Silc::Channel' && ref($channel) ne 'Irssi::Xmpp::Channel') || $channel->{'type'} ne 'CHANNEL' || ($channel->{chat_type} ne 'SILC' && !$channel->{'names_got'}) ) {
|
||||
$active_channel = undef;
|
||||
# no nicklist
|
||||
} else {
|
||||
$active_channel = $channel;
|
||||
### make nicklist ###
|
||||
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();
|
||||
}
|
||||
|
||||
# insert nick(as hash) into nicklist
|
||||
# pre: cmp has to be calculated
|
||||
sub insert_nick {
|
||||
my ($nick) = @_;
|
||||
my $nr = find_insert_pos($nick->{'cmp'});
|
||||
splice @nicklist, $nr, 0, $nick;
|
||||
draw_insert_nick_nr($nr);
|
||||
}
|
||||
|
||||
# remove nick(as nr) from nicklist
|
||||
sub remove_nick {
|
||||
my ($nr) = @_;
|
||||
splice @nicklist, $nr, 1;
|
||||
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};
|
||||
if (!$channel || !$channel->can('nicks')) { # active window is not a channel
|
||||
return;
|
||||
}
|
||||
my @nicks = $channel->nicks;
|
||||
my $nick_count = scalar(@nicks)+0;
|
||||
|
||||
if (!$active_channel) { # not a channel active
|
||||
return;
|
||||
}
|
||||
if (!$channel || $channel->{type} ne 'CHANNEL' || !$channel->{names_got} || $nick_count <= $height) {
|
||||
return;
|
||||
}
|
||||
if ($nick_count <= Irssi::settings_get_int('nicklist_height')) {
|
||||
return;
|
||||
}
|
||||
$scroll_pos += @_[0];
|
||||
|
||||
if ($scroll_pos > $nick_count - $height) {
|
||||
$scroll_pos = $nick_count - $height;
|
||||
}
|
||||
if ($scroll_pos <= 0) {
|
||||
$scroll_pos = 0;
|
||||
}
|
||||
need_redraw();
|
||||
}
|
||||
|
||||
sub is_active_channel {
|
||||
my ($server,$channel) = @_; # (channel as string)
|
||||
return ($server && $server->{'tag'} eq $active_channel->{'server'}->{'tag'} && $server->channel_find($channel) && $active_channel && $server->channel_find($channel)->{'name'} eq $active_channel->{'name'});
|
||||
}
|
||||
|
||||
sub sig_channel_wholist { # this is actualy a little late, when the names are received would be better
|
||||
my ($channel) = @_;
|
||||
if (Irssi::active_win->{'active'} && Irssi::active_win->{'active'}->{'name'} eq $channel->{'name'}) { # the channel joined is active
|
||||
make_nicklist
|
||||
}
|
||||
}
|
||||
|
||||
sub sig_join {
|
||||
my ($server,$channel,$nick,$address) = @_;
|
||||
if (!is_active_channel($server,$channel)) {
|
||||
return;
|
||||
}
|
||||
my $newnick = {'nick' => $nick};
|
||||
recalc_nick($newnick);
|
||||
insert_nick($newnick);
|
||||
}
|
||||
|
||||
sub sig_kick {
|
||||
my ($server, $channel, $nick, $kicker, $address, $reason) = @_;
|
||||
if (!is_active_channel($server,$channel)) {
|
||||
return;
|
||||
}
|
||||
my $nr = find_nick($nick);
|
||||
if ($nr == -1) {
|
||||
Irssi::print("nicklist warning: $nick was kicked from $channel, but not found in nicklist");
|
||||
} else {
|
||||
remove_nick($nr);
|
||||
}
|
||||
}
|
||||
|
||||
sub sig_part {
|
||||
my ($server,$channel,$nick,$address, $reason) = @_;
|
||||
if (!is_active_channel($server,$channel)) {
|
||||
return;
|
||||
}
|
||||
my $nr = find_nick($nick);
|
||||
if ($nr == -1) {
|
||||
Irssi::print("nicklist warning: $nick has parted $channel, but was not found in nicklist");
|
||||
} else {
|
||||
remove_nick($nr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub sig_quit {
|
||||
my ($server,$nick,$address, $reason) = @_;
|
||||
if ($server->{'tag'} ne $active_channel->{'server'}->{'tag'}) {
|
||||
return;
|
||||
}
|
||||
my $nr = find_nick($nick);
|
||||
if ($nr != -1) {
|
||||
remove_nick($nr);
|
||||
}
|
||||
}
|
||||
|
||||
sub sig_nick {
|
||||
my ($server, $newnick, $oldnick, $address) = @_;
|
||||
if ($server->{'tag'} ne $active_channel->{'server'}->{'tag'}) {
|
||||
return;
|
||||
}
|
||||
my $nr = find_nick($oldnick);
|
||||
if ($nr != -1) { # if nick was found (nickchange is in current channel)
|
||||
my $nick = $nicklist[$nr];
|
||||
remove_nick($nr);
|
||||
$nick->{'nick'} = $newnick;
|
||||
calc_text($nick);
|
||||
insert_nick($nick);
|
||||
}
|
||||
}
|
||||
|
||||
sub sig_mode {
|
||||
my ($channel, $nick, $setby, $mode, $type) = @_; # (nick and channel as rec)
|
||||
if ($channel->{'server'}->{'tag'} ne $active_channel->{'server'}->{'tag'} || $channel->{'name'} ne $active_channel->{'name'}) {
|
||||
return;
|
||||
}
|
||||
my $nr = find_nick($nick->{'nick'});
|
||||
if ($nr == -1) {
|
||||
Irssi::print("nicklist warning: $nick->{'nick'} had mode set on $channel->{'name'}, but was not found in nicklist");
|
||||
} else {
|
||||
my $nicklist_item = $nicklist[$nr];
|
||||
remove_nick($nr);
|
||||
recalc_nick($nicklist_item, $nick);
|
||||
insert_nick($nicklist_item);
|
||||
}
|
||||
}
|
||||
|
||||
##### command binds #####
|
||||
Irssi::command_bind 'nicklist' => sub {
|
||||
my ( $data, $server, $item ) = @_;
|
||||
$data =~ s/\s+$//g;
|
||||
Irssi::command_runsub ('nicklist', $data, $server, $item ) ;
|
||||
};
|
||||
Irssi::signal_add_first 'default command nicklist' => sub {
|
||||
# gets triggered if called with unknown subcommand
|
||||
cmd_help();
|
||||
};
|
||||
Irssi::command_bind('nicklist update',\&update);
|
||||
Irssi::command_bind('nicklist help',\&cmd_help);
|
||||
Irssi::command_bind('nicklist scroll',\&cmd_scroll);
|
||||
Irssi::command_bind('nicklist fifo',\&cmd_fifo_start);
|
||||
Irssi::command_bind('nicklist screen',\&cmd_screen_start);
|
||||
Irssi::command_bind('nicklist screensize',\&screen_size);
|
||||
Irssi::command_bind('nicklist on',\&cmd_on);
|
||||
Irssi::command_bind('nicklist off',\&cmd_off);
|
||||
Irssi::command_bind('nicklist toggle',\&cmd_toggle);
|
||||
|
||||
##### signals #####
|
||||
Irssi::signal_add_last('window item changed', \&make_nicklist);
|
||||
Irssi::signal_add_last('window changed', \&make_nicklist);
|
||||
Irssi::signal_add_last('channel wholist', \&sig_channel_wholist);
|
||||
Irssi::signal_add_first('message join', \&sig_join); # first, to be before ignores
|
||||
Irssi::signal_add_first('message part', \&sig_part);
|
||||
Irssi::signal_add_first('message kick', \&sig_kick);
|
||||
Irssi::signal_add_first('message quit', \&sig_quit);
|
||||
Irssi::signal_add_first('message nick', \&sig_nick);
|
||||
Irssi::signal_add_first('message own_nick', \&sig_nick);
|
||||
Irssi::signal_add_first('nick mode changed', \&sig_mode);
|
||||
|
||||
Irssi::signal_add('setup changed', \&read_settings);
|
||||
|
||||
##### settings #####
|
||||
Irssi::settings_add_str('nicklist', 'nicklist_screen_prefix', '\e[m ');
|
||||
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);
|
||||
Irssi::settings_add_str('nicklist', 'nicklist_fifo_path', Irssi::get_irssi_dir . '/nicklistfifo');
|
||||
Irssi::settings_add_str('nicklist', 'nicklist_screen_split_windows', '');
|
||||
Irssi::settings_add_str('nicklist', 'nicklist_automode', '');
|
||||
|
||||
read_settings();
|
||||
cmd_on();
|
||||
83
home/.irssi/scripts/notify.pl
Normal file
83
home/.irssi/scripts/notify.pl
Normal file
@@ -0,0 +1,83 @@
|
||||
##
|
||||
## Put me in ~/.irssi/scripts, and then execute the following in irssi:
|
||||
##
|
||||
## /load perl
|
||||
## /script load notify
|
||||
##
|
||||
|
||||
use strict;
|
||||
use Irssi;
|
||||
use vars qw($VERSION %IRSSI);
|
||||
use HTML::Entities;
|
||||
|
||||
$VERSION = "0.5";
|
||||
%IRSSI = (
|
||||
authors => 'Luke Macken, Paul W. Frields',
|
||||
contact => 'lewk@csh.rit.edu, stickster@gmail.com',
|
||||
name => 'notify.pl',
|
||||
description => 'Use D-Bus to alert user to hilighted messages',
|
||||
license => 'GNU General Public License',
|
||||
url => 'http://code.google.com/p/irssi-libnotify',
|
||||
);
|
||||
|
||||
Irssi::settings_add_str('notify', 'notify_remote', '');
|
||||
|
||||
sub sanitize {
|
||||
my ($text) = @_;
|
||||
encode_entities($text,'\'<>&');
|
||||
my $apos = "'";
|
||||
my $aposenc = "\'";
|
||||
$text =~ s/$apos/$aposenc/g;
|
||||
$text =~ s/"/\\"/g;
|
||||
return $text;
|
||||
}
|
||||
|
||||
sub notify {
|
||||
my ($server, $summary, $message) = @_;
|
||||
|
||||
# Make the message entity-safe
|
||||
$summary = sanitize($summary);
|
||||
$message = sanitize($message);
|
||||
|
||||
my $cmd = "EXEC - " .
|
||||
"notify-send -a irssi -- '" . $summary . "' '". $message . "'";
|
||||
$server->command($cmd);
|
||||
|
||||
my $remote = Irssi::settings_get_str('notify_remote');
|
||||
if ($remote ne '') {
|
||||
my $cmd = "EXEC - ssh -q " . $remote .
|
||||
"notify-send -a irssi -- '" . $summary . "' '". $message . "'";
|
||||
$server->command($cmd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub print_text_notify {
|
||||
my ($dest, $text, $stripped) = @_;
|
||||
my $server = $dest->{server};
|
||||
#my $channel = $dest->{channel};
|
||||
return if (!$server || !($dest->{level} & MSGLEVEL_HILIGHT));
|
||||
my $sender = $stripped;
|
||||
$sender =~ s/^\<?(.+?)\>? .*/\1/ ;
|
||||
$stripped =~ s/^.+? +(.*)/\1/ ;
|
||||
notify($server, $sender, $stripped);
|
||||
}
|
||||
|
||||
sub message_private_notify {
|
||||
my ($server, $msg, $nick, $address) = @_;
|
||||
|
||||
return if (!$server);
|
||||
notify($server, "PM from ".$nick, $msg);
|
||||
}
|
||||
|
||||
sub dcc_request_notify {
|
||||
my ($dcc, $sendaddr) = @_;
|
||||
my $server = $dcc->{server};
|
||||
|
||||
return if (!$dcc);
|
||||
notify($server, "DCC ".$dcc->{type}." request", $dcc->{nick});
|
||||
}
|
||||
|
||||
Irssi::signal_add('print text', 'print_text_notify');
|
||||
Irssi::signal_add('message private', 'message_private_notify');
|
||||
Irssi::signal_add('dcc request', 'dcc_request_notify');
|
||||
84
home/.irssi/scripts/notify.pl.1
Normal file
84
home/.irssi/scripts/notify.pl.1
Normal file
@@ -0,0 +1,84 @@
|
||||
##
|
||||
## Put me in ~/.irssi/scripts, and then execute the following in irssi:
|
||||
##
|
||||
## /load perl
|
||||
## /script load notify
|
||||
##
|
||||
|
||||
use strict;
|
||||
use Irssi;
|
||||
use vars qw($VERSION %IRSSI);
|
||||
use HTML::Entities;
|
||||
|
||||
$VERSION = "0.5";
|
||||
%IRSSI = (
|
||||
authors => 'Luke Macken, Paul W. Frields',
|
||||
contact => 'lewk@csh.rit.edu, stickster@gmail.com',
|
||||
name => 'notify.pl',
|
||||
description => 'Use D-Bus to alert user to hilighted messages',
|
||||
license => 'GNU General Public License',
|
||||
url => 'http://code.google.com/p/irssi-libnotify',
|
||||
);
|
||||
|
||||
Irssi::settings_add_str('notify', 'notify_remote', '');
|
||||
|
||||
sub sanitize {
|
||||
my ($text) = @_;
|
||||
encode_entities($text,'\'<>&');
|
||||
my $apos = "'";
|
||||
my $aposenc = "\'";
|
||||
$text =~ s/$apos/$aposenc/g;
|
||||
$text =~ s/"/\\"/g;
|
||||
return $text;
|
||||
}
|
||||
|
||||
sub notify {
|
||||
my ($server, $summary, $message) = @_;
|
||||
|
||||
# Make the message entity-safe
|
||||
$summary = sanitize($summary);
|
||||
$message = sanitize($message);
|
||||
|
||||
my $cmd = "EXEC - " .
|
||||
"notify-send -a irssi -- '" . $summary . "' '". $message . "'";
|
||||
$server->command($cmd);
|
||||
|
||||
my $remote = Irssi::settings_get_str('notify_remote');
|
||||
if ($remote ne '') {
|
||||
my $cmd = "EXEC - ssh -q " . $remote .
|
||||
"notify-send -a irssi -- '" . $summary . "' '". $message . "'";
|
||||
$server->command($cmd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub print_text_notify {
|
||||
my ($dest, $text, $stripped) = @_;
|
||||
my $server = $dest->{server};
|
||||
#my $channel = $dest->{channel};
|
||||
return if (!$server || !($dest->{level} & MSGLEVEL_HILIGHT));
|
||||
my $sender = $stripped;
|
||||
$sender =~ s/^\<?(.+?)\>? .*/\1/ ;
|
||||
$stripped =~ s/^.+? +(.*)/\1/ ;
|
||||
notify($server, $sender, $stripped);
|
||||
}
|
||||
|
||||
sub message_private_notify {
|
||||
my ($server, $msg, $nick, $address) = @_;
|
||||
|
||||
return if (!$server);
|
||||
notify($server, "PM from ".$nick, $msg);
|
||||
}
|
||||
|
||||
sub dcc_request_notify {
|
||||
my ($dcc, $sendaddr) = @_;
|
||||
my $server = $dcc->{server};
|
||||
|
||||
return if (!$dcc);
|
||||
notify($server, "DCC ".$dcc->{type}." request", $dcc->{nick});
|
||||
}
|
||||
|
||||
Irssi::signal_add('print text', 'print_text_notify');
|
||||
Irssi::signal_add('message private', 'message_private_notify');
|
||||
Irssi::signal_add('dcc request', 'dcc_request_notify');
|
||||
|
||||
2954
home/.irssi/scripts/old/adv_windowlist.pl.old
Executable file
2954
home/.irssi/scripts/old/adv_windowlist.pl.old
Executable file
File diff suppressed because it is too large
Load Diff
120
home/.irssi/scripts/old/desktop-notify.pl.old
Executable file
120
home/.irssi/scripts/old/desktop-notify.pl.old
Executable file
@@ -0,0 +1,120 @@
|
||||
# Copyright (C) 2015 Felipe F. Tonello <eu@felipetonello.com>
|
||||
#
|
||||
# Based on fnotify.pl 0.0.5 by Thorsten Leemhuis, James Shubin and
|
||||
# Serge van Ginderachter
|
||||
#
|
||||
# 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# NOTE:
|
||||
# This program requires libnotify, perl-glib-object-introspection and
|
||||
# perl-html-parser packages
|
||||
|
||||
use strict;
|
||||
use Irssi;
|
||||
use HTML::Entities;
|
||||
use Glib::Object::Introspection; # Ignore 'late INIT' warning message if autoloading
|
||||
use Encode;
|
||||
|
||||
our $VERSION = '1.0.1';
|
||||
our %IRSSI = (
|
||||
authors => 'Felipe F. Tonello',
|
||||
contact => 'eu@felipetonello.com',
|
||||
name => 'desktop-notify',
|
||||
description => 'Sends notification using the Desktop Notifications Specification.',
|
||||
license => 'GPL v3+',
|
||||
);
|
||||
|
||||
# /set notify_icon <icon-name>
|
||||
# List of standard icons can be found here:
|
||||
# http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html#names
|
||||
my $notify_icon;
|
||||
my $term_charset;
|
||||
|
||||
my $help = '
|
||||
/set notify_icon <icon-name>
|
||||
Change notificationicon (default is mail-message-new). A complete list of standard ' .
|
||||
'icons can be found here: ' .
|
||||
'http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html#names
|
||||
';
|
||||
|
||||
sub init {
|
||||
Glib::Object::Introspection->setup(
|
||||
basename => 'Notify',
|
||||
version => '0.7',
|
||||
package => 'Notify');
|
||||
Notify::init('Irssi');
|
||||
}
|
||||
|
||||
sub UNLOAD {
|
||||
Notify::uninit();
|
||||
}
|
||||
|
||||
sub setup_changed {
|
||||
$notify_icon = Irssi::settings_get_str('notify_icon');
|
||||
$term_charset = Irssi::settings_get_str('term_charset');
|
||||
}
|
||||
|
||||
sub priv_msg {
|
||||
my ($server, $msg, $nick, $address) = @_;
|
||||
my $window = Irssi::active_win();
|
||||
|
||||
# We shouldn't notify if active window is the same as the private message
|
||||
if ($window->{active}->{name} eq $nick) {
|
||||
return;
|
||||
}
|
||||
|
||||
my $msg = HTML::Entities::encode_entities(Irssi::strip_codes($msg), "\<>&'");
|
||||
my $network = $server->{tag};
|
||||
my $noti = Notify::Notification->new($nick . '@' . $network, decode($term_charset, $msg), $notify_icon);
|
||||
$noti->show();
|
||||
}
|
||||
|
||||
sub hilight {
|
||||
my ($dest, $text, $stripped) = @_;
|
||||
my $server = $dest->{server};
|
||||
my $window = Irssi::active_win();
|
||||
|
||||
# Check if we should notify user of message:
|
||||
# * if message is notice or highligh type
|
||||
# * if the channel belongs to the current server
|
||||
# * if the user is not focused on the channel window
|
||||
if (!($server &&
|
||||
$dest->{level} & (MSGLEVEL_HILIGHT | MSGLEVEL_NOTICES) &&
|
||||
$server->ischannel($dest->{target}) &&
|
||||
$window->{refnum} != $dest->{window}->{refnum})) {
|
||||
return;
|
||||
}
|
||||
|
||||
my $network = $server->{tag};
|
||||
my $msg = HTML::Entities::encode_entities($stripped, "\'<>&");
|
||||
my $noti = Notify::Notification->new($dest->{target} . '@' . $network, decode($term_charset, $msg), $notify_icon);
|
||||
$noti->show();
|
||||
}
|
||||
|
||||
Irssi::settings_add_str('desktop-notify', 'notify_icon', 'mail-message-new');
|
||||
|
||||
Irssi::signal_add('setup changed' => \&setup_changed);
|
||||
Irssi::signal_add_last('message private' => \&priv_msg);
|
||||
Irssi::signal_add_last('print text' => \&hilight);
|
||||
|
||||
Irssi::command_bind('help', sub {
|
||||
if ($_[0] eq $IRSSI{name}) {
|
||||
Irssi::print($help, MSGLEVEL_CLIENTCRAP);
|
||||
Irssi::signal_stop();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
init();
|
||||
setup_changed();
|
||||
828
home/.irssi/scripts/old/nicklist.pl.old
Executable file
828
home/.irssi/scripts/old/nicklist.pl.old
Executable file
@@ -0,0 +1,828 @@
|
||||
# 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 <coekie@irssi.org>
|
||||
#
|
||||
# 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.12';
|
||||
%IRSSI = (
|
||||
authors => 'Wouter Coekaerts',
|
||||
contact => 'coekie@irssi.org',
|
||||
name => 'nicklist',
|
||||
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 => '2018-10-02'
|
||||
);
|
||||
|
||||
sub cmd_help {
|
||||
print ( <<EOF
|
||||
Commands:
|
||||
NICKLIST HELP
|
||||
NICKLIST SCROLL <nr of lines>
|
||||
NICKLIST SCREEN
|
||||
NICKLIST FIFO
|
||||
NICKLIST ON
|
||||
NICKLIST OFF
|
||||
NICKLIST TOGGLE
|
||||
NICKLIST UPDATE
|
||||
|
||||
For help see: http://wouter.coekaerts.be/site/irssi/nicklist
|
||||
|
||||
in short:
|
||||
|
||||
1. FIFO MODE
|
||||
- in irssi: /NICKLIST FIFO (only the first time, to create the fifo)
|
||||
- in a shell, in a window where you want the nicklist: cat ~/.irssi/nicklistfifo
|
||||
- back in irssi:
|
||||
/SET nicklist_heigth <height of nicklist>
|
||||
/SET nicklist_width <width of nicklist>
|
||||
/NICKLIST FIFO
|
||||
|
||||
2. SCREEN MODE
|
||||
- start irssi inside screen ("screen irssi")
|
||||
- /NICKLIST SCREEN
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
my $prev_lines = 0; # number of lines in previous written nicklist
|
||||
my $scroll_pos = 0; # scrolling position
|
||||
my $cursor_line; # line the cursor is currently on
|
||||
my ($OFF, $SCREEN, $FIFO) = (0,1,2); # modes
|
||||
my $mode = $OFF; # current mode
|
||||
my $need_redraw = 0; # nicklist needs redrawing
|
||||
my $screen_resizing = 0; # terminal is being resized
|
||||
my $active_channel; # (REC)
|
||||
|
||||
my @nicklist=(); # array of hashes, containing the internal nicklist of the active channel
|
||||
# nick => realnick
|
||||
# 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, $check_friends, @prefix_friends);
|
||||
|
||||
sub read_settings {
|
||||
($screen_prefix = Irssi::settings_get_str('nicklist_screen_prefix')) =~ 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 <mode character>=<prefix>");
|
||||
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 <flags>=<prefix>");
|
||||
last;
|
||||
} else {
|
||||
push @prefix_friends, {'flags' => $1, 'prefix' => $2};
|
||||
}
|
||||
}
|
||||
|
||||
$check_friends = ($prefix_friends ne '');
|
||||
|
||||
if ($mode != $SCREEN) {
|
||||
$height = Irssi::settings_get_int('nicklist_height');
|
||||
}
|
||||
my $new_nicklist_width = Irssi::settings_get_int('nicklist_width');
|
||||
if ($new_nicklist_width != $nicklist_width && $mode == $SCREEN) {
|
||||
sig_terminal_resized();
|
||||
}
|
||||
$nicklist_width = $new_nicklist_width;
|
||||
}
|
||||
|
||||
sub update {
|
||||
read_settings();
|
||||
make_nicklist();
|
||||
}
|
||||
|
||||
##################
|
||||
##### OUTPUT #####
|
||||
##################
|
||||
|
||||
### on ###
|
||||
|
||||
sub cmd_on {
|
||||
if (uc(Irssi::settings_get_str('nicklist_automode')) eq 'SCREEN') {
|
||||
cmd_screen_start();
|
||||
} elsif (uc(Irssi::settings_get_str('nicklist_automode')) eq 'FIFO') {
|
||||
cmd_fifo_start();
|
||||
}
|
||||
}
|
||||
|
||||
### off ###
|
||||
|
||||
sub cmd_off {
|
||||
if ($mode == $SCREEN) {
|
||||
screen_stop();
|
||||
} elsif ($mode == $FIFO) {
|
||||
fifo_stop();
|
||||
}
|
||||
}
|
||||
|
||||
### toggle ###
|
||||
|
||||
sub cmd_toggle {
|
||||
if ($mode == $OFF) {
|
||||
cmd_on();
|
||||
} else {
|
||||
cmd_off();
|
||||
}
|
||||
}
|
||||
|
||||
### fifo ###
|
||||
|
||||
sub cmd_fifo_start {
|
||||
read_settings();
|
||||
my $path = Irssi::settings_get_str('nicklist_fifo_path');
|
||||
unless (-p $path) { # not a pipe
|
||||
if (-e _) { # but a something else
|
||||
die "$0: $path exists and is not a pipe, please remove it\n";
|
||||
} else {
|
||||
require POSIX;
|
||||
POSIX::mkfifo($path, 0666) or die "can\'t mkfifo $path: $!";
|
||||
Irssi::print("Fifo created. Start reading it (\"cat $path\") and try again.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!sysopen(FIFO, $path, O_WRONLY | O_NONBLOCK)) { # or die "can't write $path: $!";
|
||||
Irssi::print("Couldn\'t write to the fifo ($!). Please start reading the fifo (\"cat $path\") and try again.");
|
||||
return;
|
||||
}
|
||||
FIFO->autoflush(1);
|
||||
print FIFO "\033[2J\033[1;1H"; # erase screen & jump to 0,0
|
||||
$cursor_line = 0;
|
||||
if ($mode == $SCREEN) {
|
||||
screen_stop();
|
||||
}
|
||||
$mode = $FIFO;
|
||||
make_nicklist();
|
||||
}
|
||||
|
||||
sub fifo_stop {
|
||||
close FIFO;
|
||||
$mode = $OFF;
|
||||
Irssi::print("Fifo closed.");
|
||||
}
|
||||
|
||||
### screen ###
|
||||
|
||||
sub cmd_screen_start {
|
||||
if (!defined($ENV{'STY'})) {
|
||||
Irssi::print 'screen not detected, screen mode only works inside screen';
|
||||
return;
|
||||
}
|
||||
read_settings();
|
||||
if ($mode == $SCREEN) {return;}
|
||||
if ($mode == $FIFO) {
|
||||
fifo_stop();
|
||||
}
|
||||
$mode = $SCREEN;
|
||||
Irssi::signal_add_last('gui print text finished', \&sig_gui_print_text_finished);
|
||||
Irssi::signal_add_last('gui page scrolled', \&sig_page_scrolled);
|
||||
Irssi::signal_add('terminal resized', \&sig_terminal_resized);
|
||||
screen_size();
|
||||
make_nicklist();
|
||||
}
|
||||
|
||||
sub screen_stop {
|
||||
$mode = $OFF;
|
||||
Irssi::signal_remove('gui print text finished', \&sig_gui_print_text_finished);
|
||||
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;
|
||||
}
|
||||
$screen_resizing = 1;
|
||||
# fit screen
|
||||
system 'screen -x '.$ENV{'STY'}.' -X fit';
|
||||
# get size (from perldoc -q size)
|
||||
my ($winsize, $row, $col, $xpixel, $ypixel);
|
||||
eval 'use Term::ReadKey; ($col, $row, $xpixel, $ypixel) = GetTerminalSize';
|
||||
# require Term::ReadKey 'GetTerminalSize';
|
||||
# ($col, $row, $xpixel, $ypixel) = Term::ReadKey::GetTerminalSize;
|
||||
#};
|
||||
if ($@) { # no Term::ReadKey, try the ugly way
|
||||
eval {
|
||||
require 'sys/ioctl.ph';
|
||||
# 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";
|
||||
}
|
||||
open(TTY, "+<","/dev/tty") or die "No tty: $!";
|
||||
unless (ioctl(TTY, &TIOCGWINSZ, $winsize='')) {
|
||||
die "Term::ReadKey not found, and ioctl 'workaround' failed ($!). Install the Term::ReadKey perl module to use screen mode.\n";
|
||||
}
|
||||
close(TTY);
|
||||
($row, $col, $xpixel, $ypixel) = unpack('S4', $winsize);
|
||||
}
|
||||
|
||||
# set screen width
|
||||
$irssi_width = $col-$nicklist_width-1;
|
||||
$height = $row-1;
|
||||
|
||||
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 {
|
||||
if ($screen_resizing) {
|
||||
return;
|
||||
}
|
||||
$screen_resizing = 1;
|
||||
Irssi::timeout_add_once(1000,\&screen_size,[]);
|
||||
}
|
||||
|
||||
|
||||
### both ###
|
||||
|
||||
sub nicklist_write_start {
|
||||
if ($mode == $SCREEN) {
|
||||
print STDERR "\033P\0337\033\\"; # save cursor
|
||||
}
|
||||
}
|
||||
|
||||
sub nicklist_write_end {
|
||||
if ($mode == $SCREEN) {
|
||||
print STDERR "\033P\0338\033\\"; # restore cursor
|
||||
}
|
||||
}
|
||||
|
||||
sub nicklist_write_line {
|
||||
my ($line, $data) = @_;
|
||||
if ($mode == $SCREEN) {
|
||||
print STDERR "\033P\033[" . ($line+1) . ';'. ($irssi_width+1) .'H'. $screen_prefix . $data . "\033\\";
|
||||
} elsif ($mode == $FIFO) {
|
||||
$data = "\033[m$data"; # reset color
|
||||
if ($line == $cursor_line+1) {
|
||||
$data = "\n$data"; # next line
|
||||
} elsif ($line == $cursor_line) {
|
||||
$data = "\033[1G".$data; # back to beginning of line
|
||||
} else {
|
||||
$data = "\033[".($line+1).";0H".$data; # jump
|
||||
}
|
||||
$cursor_line=$line;
|
||||
print(FIFO $data) or fifo_stop();
|
||||
}
|
||||
}
|
||||
|
||||
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~/; # 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
|
||||
sub redraw_nick_nr {
|
||||
my ($nr) = @_;
|
||||
my $line = $nr - $scroll_pos;
|
||||
if ($line >= 0 && $line < $height) {
|
||||
nicklist_write_line($line, $nicklist[$nr]->{'text'});
|
||||
}
|
||||
}
|
||||
|
||||
# nick was inserted, redraw area if necessary
|
||||
sub draw_insert_nick_nr {
|
||||
my ($nr) = @_;
|
||||
my $line = $nr - $scroll_pos;
|
||||
if ($line < 0) { # nick is inserted above visible area
|
||||
$scroll_pos++; # 'scroll' down :)
|
||||
} elsif ($line < $height) { # line is visible
|
||||
if ($mode == $SCREEN) {
|
||||
need_redraw();
|
||||
} elsif ($mode == $FIFO) {
|
||||
my $data = "\033[m\033[L". $nicklist[$nr]->{'text'}; # reset color & insert line & write nick
|
||||
if ($line == $cursor_line) {
|
||||
$data = "\033[1G".$data; # back to beginning of line
|
||||
} else {
|
||||
$data = "\033[".($line+1).";1H".$data; # jump
|
||||
}
|
||||
$cursor_line=$line;
|
||||
print(FIFO $data) or fifo_stop();
|
||||
if ($prev_lines < $height) {
|
||||
$prev_lines++; # the nicklist has one line more
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub draw_remove_nick_nr {
|
||||
my ($nr) = @_;
|
||||
my $line = $nr - $scroll_pos;
|
||||
if ($line < 0) { # nick removed above visible area
|
||||
$scroll_pos--; # 'scroll' up :)
|
||||
} elsif ($line < $height) { # line is visible
|
||||
if ($mode == $SCREEN) {
|
||||
need_redraw();
|
||||
} elsif ($mode == $FIFO) {
|
||||
#my $data = "\033[m\033[L[i$line]". $nicklist[$nr]->{'text'}; # reset color & insert line & write nick
|
||||
my $data = "\033[M"; # delete line
|
||||
if ($line != $cursor_line) {
|
||||
$data = "\033[".($line+1)."d".$data; # jump
|
||||
}
|
||||
$cursor_line=$line;
|
||||
print(FIFO $data) or fifo_stop();
|
||||
if (@nicklist-$scroll_pos >= $height) {
|
||||
redraw_nick_nr($scroll_pos+$height-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# redraw the whole nicklist
|
||||
sub redraw {
|
||||
$need_redraw = 0;
|
||||
#make_nicklist();
|
||||
nicklist_write_start();
|
||||
my $line = 0;
|
||||
### draw nicklist ###
|
||||
for (my $i=$scroll_pos;$line < $height && $i < @nicklist; $i++) {
|
||||
nicklist_write_line($line++, $nicklist[$i]->{'text'});
|
||||
}
|
||||
|
||||
### clean up other lines ###
|
||||
my $real_lines = $line;
|
||||
while($line < $prev_lines) {
|
||||
nicklist_write_line($line++,' ' x $nicklist_width);
|
||||
}
|
||||
$prev_lines = $real_lines;
|
||||
nicklist_write_end();
|
||||
}
|
||||
|
||||
# redraw (with little delay to avoid redrawing to much)
|
||||
sub need_redraw {
|
||||
if(!$need_redraw) {
|
||||
$need_redraw = 1;
|
||||
Irssi::timeout_add_once(10,\&redraw,[]);
|
||||
}
|
||||
}
|
||||
|
||||
sub sig_page_scrolled {
|
||||
$prev_lines = $height; # we'll need to redraw everything if he scrolled up
|
||||
need_redraw;
|
||||
}
|
||||
|
||||
# redraw (with delay) if the window is visible (only in screen mode)
|
||||
sub sig_gui_print_text_finished {
|
||||
if ($need_redraw) { # there's already a redraw 'queued'
|
||||
return;
|
||||
}
|
||||
my $window = @_[0];
|
||||
if ($window->{'refnum'} == Irssi::active_win->{'refnum'} || Irssi::settings_get_str('nicklist_screen_split_windows') eq '*') {
|
||||
need_redraw;
|
||||
return;
|
||||
}
|
||||
foreach my $win (split(/[ ,]/, Irssi::settings_get_str('nicklist_screen_split_windows'))) {
|
||||
if ($window->{'refnum'} == $win || $window->{'name'} eq $win) {
|
||||
need_redraw;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
###################
|
||||
##### 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 #####
|
||||
####################
|
||||
|
||||
# returns the position of the given nick(as string) in the (internal) nicklist
|
||||
sub find_nick {
|
||||
my ($nick) = @_;
|
||||
for (my $i=0;$i < @nicklist; $i++) {
|
||||
if ($nicklist[$i]->{'nick'} eq $nick) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
# find position where nick should be inserted into the list
|
||||
sub find_insert_pos {
|
||||
my ($cmp)= @_;
|
||||
for (my $i=0;$i < @nicklist; $i++) {
|
||||
if ($nicklist[$i]->{'cmp'} gt $cmp) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
return scalar(@nicklist); #last
|
||||
}
|
||||
|
||||
# make the (internal) nicklist (@nicklist)
|
||||
sub make_nicklist {
|
||||
@nicklist = ();
|
||||
$scroll_pos = 0;
|
||||
|
||||
### get & check channel ###
|
||||
my $channel = Irssi::active_win->{active};
|
||||
|
||||
if (!$channel || (ref($channel) ne 'Irssi::Irc::Channel' && ref($channel) ne 'Irssi::Silc::Channel' && ref($channel) ne 'Irssi::Xmpp::Channel') || $channel->{'type'} ne 'CHANNEL' || ($channel->{chat_type} ne 'SILC' && !$channel->{'names_got'}) ) {
|
||||
$active_channel = undef;
|
||||
# no nicklist
|
||||
} else {
|
||||
$active_channel = $channel;
|
||||
### make nicklist ###
|
||||
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();
|
||||
}
|
||||
|
||||
# insert nick(as hash) into nicklist
|
||||
# pre: cmp has to be calculated
|
||||
sub insert_nick {
|
||||
my ($nick) = @_;
|
||||
my $nr = find_insert_pos($nick->{'cmp'});
|
||||
splice @nicklist, $nr, 0, $nick;
|
||||
draw_insert_nick_nr($nr);
|
||||
}
|
||||
|
||||
# remove nick(as nr) from nicklist
|
||||
sub remove_nick {
|
||||
my ($nr) = @_;
|
||||
splice @nicklist, $nr, 1;
|
||||
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};
|
||||
if (!$channel || !$channel->can('nicks')) { # active window is not a channel
|
||||
return;
|
||||
}
|
||||
my @nicks = $channel->nicks;
|
||||
my $nick_count = scalar(@nicks)+0;
|
||||
|
||||
if (!$active_channel) { # not a channel active
|
||||
return;
|
||||
}
|
||||
if (!$channel || $channel->{type} ne 'CHANNEL' || !$channel->{names_got} || $nick_count <= $height) {
|
||||
return;
|
||||
}
|
||||
if ($nick_count <= Irssi::settings_get_int('nicklist_height')) {
|
||||
return;
|
||||
}
|
||||
$scroll_pos += @_[0];
|
||||
|
||||
if ($scroll_pos > $nick_count - $height) {
|
||||
$scroll_pos = $nick_count - $height;
|
||||
}
|
||||
if ($scroll_pos <= 0) {
|
||||
$scroll_pos = 0;
|
||||
}
|
||||
need_redraw();
|
||||
}
|
||||
|
||||
sub is_active_channel {
|
||||
my ($server,$channel) = @_; # (channel as string)
|
||||
return ($server && $server->{'tag'} eq $active_channel->{'server'}->{'tag'} && $server->channel_find($channel) && $active_channel && $server->channel_find($channel)->{'name'} eq $active_channel->{'name'});
|
||||
}
|
||||
|
||||
sub sig_channel_wholist { # this is actualy a little late, when the names are received would be better
|
||||
my ($channel) = @_;
|
||||
if (Irssi::active_win->{'active'} && Irssi::active_win->{'active'}->{'name'} eq $channel->{'name'}) { # the channel joined is active
|
||||
make_nicklist
|
||||
}
|
||||
}
|
||||
|
||||
sub sig_join {
|
||||
my ($server,$channel,$nick,$address) = @_;
|
||||
if (!is_active_channel($server,$channel)) {
|
||||
return;
|
||||
}
|
||||
my $newnick = {'nick' => $nick};
|
||||
recalc_nick($newnick);
|
||||
insert_nick($newnick);
|
||||
}
|
||||
|
||||
sub sig_kick {
|
||||
my ($server, $channel, $nick, $kicker, $address, $reason) = @_;
|
||||
if (!is_active_channel($server,$channel)) {
|
||||
return;
|
||||
}
|
||||
my $nr = find_nick($nick);
|
||||
if ($nr == -1) {
|
||||
Irssi::print("nicklist warning: $nick was kicked from $channel, but not found in nicklist");
|
||||
} else {
|
||||
remove_nick($nr);
|
||||
}
|
||||
}
|
||||
|
||||
sub sig_part {
|
||||
my ($server,$channel,$nick,$address, $reason) = @_;
|
||||
if (!is_active_channel($server,$channel)) {
|
||||
return;
|
||||
}
|
||||
my $nr = find_nick($nick);
|
||||
if ($nr == -1) {
|
||||
Irssi::print("nicklist warning: $nick has parted $channel, but was not found in nicklist");
|
||||
} else {
|
||||
remove_nick($nr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub sig_quit {
|
||||
my ($server,$nick,$address, $reason) = @_;
|
||||
if ($server->{'tag'} ne $active_channel->{'server'}->{'tag'}) {
|
||||
return;
|
||||
}
|
||||
my $nr = find_nick($nick);
|
||||
if ($nr != -1) {
|
||||
remove_nick($nr);
|
||||
}
|
||||
}
|
||||
|
||||
sub sig_nick {
|
||||
my ($server, $newnick, $oldnick, $address) = @_;
|
||||
if ($server->{'tag'} ne $active_channel->{'server'}->{'tag'}) {
|
||||
return;
|
||||
}
|
||||
my $nr = find_nick($oldnick);
|
||||
if ($nr != -1) { # if nick was found (nickchange is in current channel)
|
||||
my $nick = $nicklist[$nr];
|
||||
remove_nick($nr);
|
||||
$nick->{'nick'} = $newnick;
|
||||
calc_text($nick);
|
||||
insert_nick($nick);
|
||||
}
|
||||
}
|
||||
|
||||
sub sig_mode {
|
||||
my ($channel, $nick, $setby, $mode, $type) = @_; # (nick and channel as rec)
|
||||
if ($channel->{'server'}->{'tag'} ne $active_channel->{'server'}->{'tag'} || $channel->{'name'} ne $active_channel->{'name'}) {
|
||||
return;
|
||||
}
|
||||
my $nr = find_nick($nick->{'nick'});
|
||||
if ($nr == -1) {
|
||||
Irssi::print("nicklist warning: $nick->{'nick'} had mode set on $channel->{'name'}, but was not found in nicklist");
|
||||
} else {
|
||||
my $nicklist_item = $nicklist[$nr];
|
||||
remove_nick($nr);
|
||||
recalc_nick($nicklist_item, $nick);
|
||||
insert_nick($nicklist_item);
|
||||
}
|
||||
}
|
||||
|
||||
##### command binds #####
|
||||
Irssi::command_bind 'nicklist' => sub {
|
||||
my ( $data, $server, $item ) = @_;
|
||||
$data =~ s/\s+$//g;
|
||||
Irssi::command_runsub ('nicklist', $data, $server, $item ) ;
|
||||
};
|
||||
Irssi::signal_add_first 'default command nicklist' => sub {
|
||||
# gets triggered if called with unknown subcommand
|
||||
cmd_help();
|
||||
};
|
||||
Irssi::command_bind('nicklist update',\&update);
|
||||
Irssi::command_bind('nicklist help',\&cmd_help);
|
||||
Irssi::command_bind('nicklist scroll',\&cmd_scroll);
|
||||
Irssi::command_bind('nicklist fifo',\&cmd_fifo_start);
|
||||
Irssi::command_bind('nicklist screen',\&cmd_screen_start);
|
||||
Irssi::command_bind('nicklist screensize',\&screen_size);
|
||||
Irssi::command_bind('nicklist on',\&cmd_on);
|
||||
Irssi::command_bind('nicklist off',\&cmd_off);
|
||||
Irssi::command_bind('nicklist toggle',\&cmd_toggle);
|
||||
|
||||
##### signals #####
|
||||
Irssi::signal_add_last('window item changed', \&make_nicklist);
|
||||
Irssi::signal_add_last('window changed', \&make_nicklist);
|
||||
Irssi::signal_add_last('channel wholist', \&sig_channel_wholist);
|
||||
Irssi::signal_add_first('message join', \&sig_join); # first, to be before ignores
|
||||
Irssi::signal_add_first('message part', \&sig_part);
|
||||
Irssi::signal_add_first('message kick', \&sig_kick);
|
||||
Irssi::signal_add_first('message quit', \&sig_quit);
|
||||
Irssi::signal_add_first('message nick', \&sig_nick);
|
||||
Irssi::signal_add_first('message own_nick', \&sig_nick);
|
||||
Irssi::signal_add_first('nick mode changed', \&sig_mode);
|
||||
|
||||
Irssi::signal_add('setup changed', \&read_settings);
|
||||
|
||||
##### settings #####
|
||||
Irssi::settings_add_str('nicklist', 'nicklist_screen_prefix', '\e[m ');
|
||||
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);
|
||||
Irssi::settings_add_str('nicklist', 'nicklist_fifo_path', Irssi::get_irssi_dir . '/nicklistfifo');
|
||||
Irssi::settings_add_str('nicklist', 'nicklist_screen_split_windows', '');
|
||||
Irssi::settings_add_str('nicklist', 'nicklist_automode', '');
|
||||
|
||||
read_settings();
|
||||
cmd_on();
|
||||
Reference in New Issue
Block a user