use strict; use warnings; use Irssi; use Irssi::TextUI; use Hash::Util qw(); our $VERSION = '0.3'; # 8a7f8770be646c3 our %IRSSI = ( authors => 'Nei', contact => 'Nei @ [email protected]', url => "http://anti.teamidiot.de/", name => 'linebuffer', description => 'dump the linebuffer content', license => 'GNU GPLv2 or later', ); sub cmd_help { my ($args) = @_; if ($args =~ /^dumplines *$/i) { print CLIENTCRAP <] [-format] [-ids] [-levels[-prepend|-hex]] [-time] [ []] Dump the content of the line buffer to a window or file. -file: Output to this file. -format: Format the text output. -ids: Print line IDs. -levels: Print levels. -prepend: before text, -hex: as hex value -time: Print time stamp. count: Number of lines to reproduce. refnum: Specifies the window to dump. HELP } } { my %control2format_d = ( 'a' => 'F', 'c' => '_', 'e' => '|', 'i' => '#', 'f' => 'I', 'g' => 'n', ); my %control2format_c = ( "\c_" => 'U', "\cV" => '8', ); my %base_bg = ( '0' => '0', '1' => '4', '2' => '2', '3' => '6', '4' => '1', '5' => '5', '6' => '3', '7' => '7', '8' => 'x08', '9' => 'x09', ':' => 'x0a', ';' => 'x0b', '<' => 'x0c', '=' => 'x0d', '>' => 'x0e', '?' => 'x0f', ); my %base_fg = ( '0' => 'k', '1' => 'b', '2' => 'g', '3' => 'c', '4' => 'r', '5' => 'm', # p '6' => 'y', '7' => 'w', '8' => 'K', '9' => 'B', ':' => 'G', ';' => 'C', '<' => 'R', '=' => 'M', # P '>' => 'Y', '?' => 'W', ); my $to_true_color = sub { my (@rgbx) = map { ord } @_; $rgbx[3] -= 0x20; for (my $i = 0; $i < 3; ++$i) { if ($rgbx[3] & (0x10 << $i)) { $rgbx[$i] -= 0x20; } } my $color = $rgbx[0] << 16 | $rgbx[1] << 8 | $rgbx[2]; ($rgbx[3] & 0x1 ? 'z' : 'Z') . sprintf '%06X', $color; }; my %ext_color_off = ( '.' => [0, 0x10], '-' => [0, 0x60], ',' => [0, 0xb0], '+' => [1, 0x10], "'" => [1, 0x60], '&' => [1, 0xb0], ); my @ext_color_al = (0..9, 'A' .. 'Z'); my $to_ext_color = sub { my ($sig, $chr) = @_; my ($bg, $off) = @{ $ext_color_off{$sig} }; my $color = $off - 0x3f + ord $chr; $color += 10 if $color > 214; ($bg ? 'x' : 'X') . (1+int($color / 36)) . $ext_color_al[$color % 36]; }; sub control2format { my $line = shift; $line =~ s/%/%%/g; $line =~ s{( \c_ | \cV ) |(?:\cD(?: ([aceigf]) |(?:\#(.)(.)(.)(.)) |(?:([-.,+'&])(.)) |(?:(?:/|([0-?]))(?:/|([/0-?]))) |\xff/|(/\xff) )) }{ '%'.(defined $1 ? $control2format_c{$1} : defined $2 ? $control2format_d{$2} : defined $6 ? $to_true_color->($3,$4,$5,$6) : defined $8 ? $to_ext_color->($7,$8) : defined $10 ? ($base_bg{$10} . (defined $9 ? '%'.$base_fg{$9} : '')) : defined $9 ? $base_fg{$9} : defined $11 ? 'o' : 'n') }gex; $line } } sub simpletime { my ($sec, $min, $hour, $mday, $mon, $year) = localtime $_[0]; sprintf "%04d"."%02d"x5, 1900+$year, 1+$mon, $mday, $hour, $min, $sec; } sub prt_report { my $fh = shift; if ($fh->isa('Irssi::UI::Window')) { for (split "\n", (join $,//'', @_)) { my $line; for (split "\t") { if (defined $line) { $line .= ' ' x (5 - (length $line) % 6); $line .= ' '; } $line .= $_; } $line .= ''; $fh->print($line, MSGLEVEL_NEVER); } } else { $fh->print(@_); } } sub dump_lines { my ($data, $server, $item) = @_; my ($args, $rest) = Irssi::command_parse_options('dumplines', $data); ref $args or return; my $win = Irssi::active_win; my ($count, $winnum) = $data =~ /(-?\d+)/g; if (defined $winnum) { $win = Irssi::window_find_refnum($winnum) // do { print CLIENTERROR "Window #$winnum not found"; return; }; } my $fh; my $is_file; if (defined $args->{file}) { unless (length $args->{file}) { print CLIENTERROR "Missing argument to option: file"; return; } open $fh, '>', $args->{file} or do { print CLIENTERROR "Error opening ".$args->{file}.": $!"; return; }; $is_file = 1; } else { $fh = Irssi::Windowitem::window_create(undef, 0); $fh->command('^scrollback home'); $fh->command('^scrollback clear'); $fh->command('^window scroll off'); } prt_report($fh, "\n==========\nwindow: ", $win->{refnum}, "\n"); my $view = $win->view; my $lclength = length $view->{buffer}{lines_count}; $lclength = 3 if $lclength < 3; my $padlen = $lclength; my $hdr = sprintf "%${lclength}s", " # "; my $hllen = length sprintf '%x', MSGLEVEL_LASTLOG << 1; #123456789012345 if (defined $args->{ids}) { $padlen += 10; $hdr .= '| ID ' } if (defined $args->{time}) { $padlen += 15; $hdr .= '| date & time ' } if (defined $args->{'levels-hex'}) { $padlen += $hllen + 1; $hdr .= sprintf "|%${hllen}s", ' levels ' } prt_report($fh, " "x$padlen,"\t/buffer first line\n", " "x$padlen,"\t|/buffer cur line\n", " "x$padlen,"\t||/bottom start line\n", $hdr,"\t|||/start line\n"); my $j = 1; $count = $view->{height} unless $count; my $start_line; if ($count < 0) { $start_line = $view->get_lines; } else { $j = $view->{buffer}{lines_count} - $count + 1; $j = 1 if $j < 1; $start_line = $view->{buffer}{cur_line}; for (my $line = $start_line; $line && $count--; ($start_line, $line) = ($line, $line->prev)) {} } for (my $line = $start_line; $line; $line = $line->next) { my $i = 0; my $t = sprintf "%${lclength}d", $j++; $t .= sprintf " %9d", $line->{_irssi} if defined $args->{ids}; $t .= ' '.simpletime($line->{info}{time}) if defined $args->{time}; $t .= sprintf " %${hllen}x", $line->{info}{level} if defined $args->{'levels-hex'}; $t .= "\t" . (join '', map {;++$i; $_->{_irssi} == $line->{_irssi} ? $i : ' ' } $view->{buffer}{first_line}, $view->{buffer}{cur_line}, $view->{bottom_startline}, $view->{startline}); $t .= "\t"; my $text = $line->get_text(1); if (defined $args->{format}) { if (!$is_file) { $text = control2format($text); $text =~ s{(%.)}{ $1 eq "%o" ? "\cD/\xff" : $1 }ge; } } else { $text = control2format($text); if (!$is_file) { $text =~ s/%/%%/g; } } my $lst; if (defined $args->{'levels-prepend'} || defined $args->{levels}) { my $levels = Irssi::bits2level($line->{info}{level}); if (!$is_file) { $lst = "%n%r[%n$levels%r]%n"; } else { $lst = "[$levels]"; } } $t .= "$lst\t" if defined $args->{'levels-prepend'}; $t .= $text; $t .= "\t$lst" if defined $args->{levels}; $t .= "\n"; prt_report($fh, $t); } prt_report($fh, "----------\n", map { $_ // 'NULL' } "view w", $view->{width}, " h", $view->{height}, " scroll ", $view->{scroll}, "\n", " ypos ", $view->{ypos}, "\n", " bottom subline ", $view->{bottom_subline}, " subline ", $view->{subline}, ", is bottom: ", $view->{bottom}, "\n", "buffer: lines count ", $view->{buffer}{lines_count}, ", was last eol: ", $view->{buffer}{last_eol}, "\n", "win: last line ", simpletime($win->{last_line}),"\n\n"); } Irssi::command_bind('dumplines' => 'dump_lines'); Irssi::command_set_options('dumplines' => 'format ids time levels levels-prepend levels-hex 1 -file'); Irssi::command_bind_last('help' => 'cmd_help');