🔥
This commit is contained in:
304
irssi/scripts/tmux-nicklist.pl
Normal file
304
irssi/scripts/tmux-nicklist.pl
Normal file
@@ -0,0 +1,304 @@
|
||||
# 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 '$channel_pattern'.
|
||||
#
|
||||
# It supports mouse scrolling and the following keys:
|
||||
# k/up arrow: up one line
|
||||
# j/down arrow: down one line
|
||||
# pageup: up 20 lines
|
||||
# pagedown: down 20 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.
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use IO::Handle;
|
||||
use IO::Select;
|
||||
use POSIX;
|
||||
use File::Temp qw/ :mktemp /;
|
||||
use File::Basename;
|
||||
use vars qw($VERSION %IRSSI);
|
||||
$VERSION = '0.0.0';
|
||||
%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',
|
||||
);
|
||||
|
||||
if ($#ARGV == -1) {
|
||||
require Irssi;
|
||||
|
||||
my $enabled = 0;
|
||||
my $script_path = __FILE__;
|
||||
my $tmpdir;
|
||||
my $fifo_path;
|
||||
# my $channel_pattern = '^&bitlbee$';
|
||||
my $channel_pattern = '^.+$';
|
||||
|
||||
sub enable_nicklist {
|
||||
return if ($enabled);
|
||||
$tmpdir = mkdtemp "/tmp/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'}";
|
||||
system('tmux', 'split-window', '-dh', '-p', '20', $cmd);
|
||||
# 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 die "can't open $fifo_path: $!";
|
||||
FIFO->autoflush(1);
|
||||
$enabled = 1;
|
||||
}
|
||||
|
||||
sub disable_nicklist {
|
||||
return unless ($enabled);
|
||||
print(FIFO "EXIT\n");
|
||||
close FIFO;
|
||||
unlink $fifo_path;
|
||||
rmdir $tmpdir;
|
||||
$enabled = 0;
|
||||
}
|
||||
|
||||
sub reset_nicklist {
|
||||
my $active = Irssi::active_win();
|
||||
my $channel = $active->{active};
|
||||
|
||||
if ((!$channel ||
|
||||
(ref($channel) ne 'Irssi::Irc::Channel' && ref($channel) ne
|
||||
'Irssi::Silc::Channel') || $channel->{'type'} ne 'CHANNEL' ||
|
||||
($channel->{chat_type} ne 'SILC' && !$channel->{'names_got'})) ||
|
||||
($channel->{'name'} !~ /$channel_pattern/ )) {
|
||||
disable_nicklist;
|
||||
} else {
|
||||
enable_nicklist;
|
||||
print(FIFO "BEGIN\n");
|
||||
foreach my $nick (sort {(($a->{'op'}?'1':$a->{'halfop'}?'2':$a->{'voice'}?'3':'4').lc($a->{'nick'}))
|
||||
cmp (($b->{'op'}?'1':$b->{'halfop'}?'2':$b->{'voice'}?'3':'4').lc($b->{'nick'}))} $channel->nicks()) {
|
||||
print(FIFO "NICK");
|
||||
if ($nick->{'op'}) {
|
||||
print(FIFO "\e[32m\@$nick->{'nick'}\e[39m");
|
||||
} elsif ($nick->{'halfop'}) {
|
||||
print(FIFO "\e[34m%$nick->{'nick'}\e[39m");
|
||||
} elsif ($nick->{'voice'}) {
|
||||
print(FIFO "\e[33m+$nick->{'nick'}\e[39m");
|
||||
} else {
|
||||
print(FIFO " $nick->{'nick'}");
|
||||
}
|
||||
print(FIFO "\n");
|
||||
}
|
||||
print(FIFO "END\n");
|
||||
}
|
||||
}
|
||||
|
||||
sub switch_channel {
|
||||
print(FIFO "SWITCH_CHANNEL\n");
|
||||
reset_nicklist;
|
||||
}
|
||||
|
||||
Irssi::signal_add_last('window item changed', \&switch_channel);
|
||||
Irssi::signal_add_last('window changed', \&switch_channel);
|
||||
Irssi::signal_add_last('channel wholist', \&reset_nicklist);
|
||||
# first, to be before ignores
|
||||
Irssi::signal_add_first('message join', \&reset_nicklist);
|
||||
Irssi::signal_add_first('message part', \&reset_nicklist);
|
||||
Irssi::signal_add_first('message kick', \&reset_nicklist);
|
||||
Irssi::signal_add_first('message quit', \&reset_nicklist);
|
||||
Irssi::signal_add_first('message nick', \&reset_nicklist);
|
||||
Irssi::signal_add_first('message own_nick', \&reset_nicklist);
|
||||
Irssi::signal_add_first('nick mode changed', \&reset_nicklist);
|
||||
Irssi::signal_add('gui exit', \&disable_nicklist);
|
||||
|
||||
} else {
|
||||
require 'sys/ioctl.ph';
|
||||
# open STDERR, '>', "$ENV{'HOME'}/.nickbar-errors.log";
|
||||
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 clear_screen { print "\e[2J"; }
|
||||
sub save_cursor { print "\e[s"; }
|
||||
sub restore_cursor { print "\e[u"; }
|
||||
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 $UP="k";
|
||||
my $DOWN="j";
|
||||
my $PAGE_DOWN="\e[6~";
|
||||
my $PAGE_UP="\e[5~";
|
||||
my $GO_TOP="gg";
|
||||
my $GO_BOTTOM="G";
|
||||
|
||||
my $current_line = 0;
|
||||
my $sequence = '';
|
||||
|
||||
sub term_row_count {
|
||||
# from http://stackoverflow.com/questions/4286158/how-do-i-get-width-and-height-of-my-terminal-with-ioctl
|
||||
my $terminal_size;
|
||||
ioctl(STDOUT, TIOCGWINSZ() , $terminal_size);
|
||||
my ($rows, $cols, $xpix, $ypix) = unpack 'S4', $terminal_size;
|
||||
return $rows;
|
||||
}
|
||||
|
||||
sub redraw {
|
||||
my $rows = term_row_count;
|
||||
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
|
||||
restore_cursor;
|
||||
clear_screen;
|
||||
for (my $idx = $current_line; $idx <= $last_idx; $idx++) {
|
||||
print "$nicknames[$idx]\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub move_down {
|
||||
$sequence = '';
|
||||
my $count = $_[0];
|
||||
my $nickcount = $#nicknames;
|
||||
my $rows = term_row_count;
|
||||
return if ($nickcount <= $rows);
|
||||
if ($count == -1) {
|
||||
$current_line = $nickcount - $rows - 1;
|
||||
redraw;
|
||||
return;
|
||||
}
|
||||
my $visible = $nickcount - $current_line - $count;
|
||||
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 = $_[0];
|
||||
if ($count == -1) {
|
||||
$current_line = 0;
|
||||
redraw;
|
||||
return;
|
||||
}
|
||||
return if ($current_line == 0);
|
||||
if (($current_line - $count) >= 0) {
|
||||
$current_line -= $count;
|
||||
redraw;
|
||||
}
|
||||
}
|
||||
|
||||
$SIG{INT} = 'IGNORE';
|
||||
|
||||
# setup terminal so we can listen for individual key presses without echo
|
||||
my ($term, $oterm, $echo, $noecho, $fd_stdin);
|
||||
$fd_stdin = fileno(STDIN);
|
||||
$term = POSIX::Termios->new();
|
||||
$term->getattr($fd_stdin);
|
||||
$oterm = $term->getlflag();
|
||||
$echo = ECHO | ECHOK | ICANON;
|
||||
$noecho = $oterm & ~$echo;
|
||||
$term->setlflag($noecho);
|
||||
$term->setcc(VTIME, 1);
|
||||
$term->setattr($fd_stdin, TCSANOW);
|
||||
|
||||
# open named pipe and setup the 'select' wrapper object for listening on both
|
||||
# fds(fifo and sdtin)
|
||||
open (FIFO, "< $fifo_path") or die "can't open $fifo_path: $!";
|
||||
my $fifo = \*FIFO;
|
||||
my $stdin = \*STDIN;
|
||||
my $select = IO::Select->new();
|
||||
my @ready;
|
||||
$select->add($fifo);
|
||||
$select->add($stdin);
|
||||
|
||||
save_cursor;
|
||||
enable_mouse;
|
||||
system('tput', 'civis');
|
||||
MAIN: {
|
||||
while (@ready = $select->can_read) {
|
||||
foreach my $fd (@ready) {
|
||||
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 20 if ($PAGE_DOWN eq $sequence);
|
||||
} elsif ($PAGE_UP =~ /^\Q$sequence\E/) {
|
||||
move_up 20 if ($PAGE_UP 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', '-l', '-t', $irssi_pane, $sequence);
|
||||
system('tmux', 'select-pane', '-t', $irssi_pane);
|
||||
$sequence = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close FIFO;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user