trackbar.pl (20837B)
1 ## trackbar.pl 2 # 3 # This little script will do just one thing: it will draw a line each time you 4 # switch away from a window. This way, you always know just upto where you've 5 # been reading that window :) It also removes the previous drawn line, so you 6 # don't see double lines. 7 # 8 # redraw trackbar only works on irssi 0.8.17 or higher. 9 # 10 ## 11 12 ## Usage: 13 # 14 # The script works right out of the box, but if you want you can change 15 # the working by /set'ing the following variables: 16 # 17 # Setting: trackbar_style 18 # Description: This setting will be the color of your trackbar line. 19 # By default the value will be '%K', only Irssi color 20 # formats are allowed. If you don't know the color formats 21 # by heart, you can take a look at the formats documentation. 22 # You will find the proper docs on http://www.irssi.org/docs. 23 # 24 # Setting: trackbar_string 25 # Description: This is the string that your line will display. This can 26 # be multiple characters or just one. For example: '~-~-' 27 # The default setting is '-'. 28 # Here are some unicode characters you can try: 29 # "───" => U+2500 => a line 30 # "═══" => U+2550 => a double line 31 # "━━━" => U+2501 => a wide line 32 # "▭ " => U+25ad => a white rectangle 33 # 34 # Setting: trackbar_use_status_window 35 # Description: If this setting is set to OFF, Irssi won't print a trackbar 36 # in the statuswindow 37 # 38 # Setting: trackbar_ignore_windows 39 # Description: A list of windows where no trackbar should be printed 40 # 41 # Setting: trackbar_print_timestamp 42 # Description: If this setting is set to ON, Irssi will print the formatted 43 # timestamp in front of the trackbar. 44 # 45 # Setting: trackbar_require_seen 46 # Description: Only clear the trackbar if it has been scrolled to. 47 # 48 # Setting: trackbar_all_manual 49 # Description: Never clear the trackbar until you do /mark. 50 # 51 # /mark is a command that will redraw the line at the bottom. 52 # 53 # Command: /trackbar, /trackbar goto 54 # Description: Jump to where the trackbar is, to pick up reading 55 # 56 # Command: /trackbar keep 57 # Description: Keep this window's trackbar where it is the next time 58 # you switch windows (then this flag is cleared again) 59 # 60 # Command: /mark, /trackbar mark 61 # Description: Remove the old trackbar and mark the bottom of this 62 # window with a new trackbar 63 # 64 # Command: /trackbar markvisible 65 # Description: Like mark for all visible windows 66 # 67 # Command: /trackbar markall 68 # Description: Like mark for all windows 69 # 70 # Command: /trackbar remove 71 # Description: Remove this window's trackbar 72 # 73 # Command: /trackbar removeall 74 # Description: Remove all windows' trackbars 75 # 76 # Command: /trackbar redraw 77 # Description: Force redraw of trackbars 78 # 79 ## 80 81 ## 82 # 83 # For bugreports and other improvements contact one of the authors. 84 # 85 # This program is free software; you can redistribute it and/or modify 86 # it under the terms of the GNU General Public License as published by 87 # the Free Software Foundation; either version 2 of the License, or 88 # (at your option) any later version. 89 # 90 # This program is distributed in the hope that it will be useful, 91 # but WITHOUT ANY WARRANTY; without even the implied warranty of 92 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 93 # GNU General Public License for more details. 94 # 95 # You should have received a copy of the GNU General Public License 96 # along with this script; if not, write to the Free Software 97 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 98 # 99 ## 100 101 use strict; 102 use warnings; 103 use vars qw($VERSION %IRSSI); 104 105 $VERSION = "2.9"; # a4c78e85092a271 106 107 %IRSSI = ( 108 authors => "Peter 'kinlo' Leurs, Uwe Dudenhoeffer, " . 109 "Michiel Holtkamp, Nico R. Wohlgemuth, " . 110 "Geert Hauwaerts", 111 contact => 'peter@pfoe.be', 112 patchers => 'Johan Kiviniemi (UTF-8), Uwe Dudenhoeffer (on-upgrade-remove-line)', 113 name => 'trackbar', 114 description => 'Shows a bar where you have last read a window.', 115 license => 'GNU General Public License', 116 url => 'http://www.pfoe.be/~peter/trackbar/', 117 commands => 'trackbar', 118 ); 119 120 ## Comments and remarks. 121 # 122 # This script uses settings. 123 # Use /SET to change the value or /TOGGLE to switch it on or off. 124 # 125 # 126 # Tip: The command 'trackbar' is very useful if you bind that to a key, 127 # so you can easily jump to the trackbar. Please see 'help bind' for 128 # more information about keybindings in Irssi. 129 # 130 # Command: /BIND meta2-P key F1 131 # /BIND F1 command trackbar 132 # 133 ## 134 135 ## Bugfixes and new items in this rewrite. 136 # 137 # * Remove all the trackbars before upgrading. 138 # * New setting trackbar_use_status_window to control the statuswindow trackbar. 139 # * New setting trackbar_print_timestamp to print a timestamp or not. 140 # * New command 'trackbar' to scroll up to the trackbar. 141 # * When resizing your terminal, Irssi will update all the trackbars to the new size. 142 # * When changing trackbar settings, change all the trackbars to the new settings. 143 # * New command 'trackbar mark' to draw a new trackbar (The old '/mark'). 144 # * New command 'trackbar markall' to draw a new trackbar in each window. 145 # * New command 'trackbar remove' to remove the trackbar from the current window. 146 # * New command 'trackbar removeall' to remove all the trackbars. 147 # * Don't draw a trackbar in empty windows. 148 # * Added a version check to prevent Irssi redraw errors. 149 # * Fixed a bookmark NULL versus 0 bug. 150 # * Fixed a remove-line bug in Uwe Dudenhoeffer his patch. 151 # * New command 'help trackbar' to display the trackbar commands. 152 # * Fixed an Irssi startup bug, now processing each auto-created window. 153 # 154 ## 155 156 ## Known bugs and the todolist. 157 # 158 # Todo: * Instead of drawing a line, invert the line. 159 # 160 ## 161 162 ## Authors: 163 # 164 # - Main maintainer & author: Peter 'kinlo' Leurs 165 # - Many thanks to Timo 'cras' Sirainen for placing me on my way 166 # - on-upgrade-remove-line patch by Uwe Dudenhoeffer 167 # - trackbar resizing by Michiel Holtkamp (02 Jul 2012) 168 # - scroll to trackbar, window excludes, and timestamp options by Nico R. 169 # Wohlgemuth (22 Sep 2012) 170 # 171 ## 172 173 ## Version history: 174 # 175 # 2.9: - fix crash on /mark in empty window 176 # 2.8: - fix /^join bug 177 # 2.7: - add /set trackbar_all_manual option 178 # 2.5: - merge back on scripts.irssi.org 179 # - fix /trackbar redraw broken in 2.4 180 # - fix legacy encodings 181 # - add workaround for irssi issue #271 182 # 2.4: - add support for horizontal splits 183 # 2.3: - add some features for seen tracking using other scripts 184 # 2.0: - big rewrite based on 1.4 185 # * removed /tb, you can have it with /alias tb trackbar if you want 186 # * subcommand and settings changes: 187 # /trackbar vmark => /trackbar markvisible 188 # /trackbar scroll => /trackbar goto (or just /trackbar) 189 # /trackbar help => /help trackbar 190 # /set trackbar_hide_windows => /set trackbar_ignore_windows 191 # /set trackbar_timestamp => /set trackbar_print_timestamp 192 # * magic line strings were removed, just paste the unicode you want! 193 # * trackbar_timestamp_styled is not currently supported 194 # 1.9: - add version guard 195 # 1.8: - sub draw_bar 196 # 1.7: - Added /tb scroll, trackbar_hide_windows, trackbar_timestamp_timestamp 197 # and trackbar_timestamp_styled 198 # 1.6: - Work around Irssi resize bug, please do /upgrade! (see below) 199 # 1.5: - Resize trackbars in all windows when terminal is resized 200 # 1.4: - Changed our's by my's so the irssi script header is valid 201 # - Removed utf-8 support. In theory, the script should work w/o any 202 # problems for utf-8, just set trackbar_string to a valid utf-8 character 203 # and everything *should* work. However, this script is being plagued by 204 # irssi internal bugs. The function Irssi::settings_get_str does NOT handle 205 # unicode strings properly, hence you will notice problems when setting the bar 206 # to a unicode char. For changing your bar to utf-8 symbols, read the line sub. 207 # 1.3: - Upgrade now removes the trackbars. 208 # - Some code cleanups, other defaults 209 # - /mark sets the line to the bottom 210 # 1.2: - Support for utf-8 211 # - How the bar looks can now be configured with trackbar_string 212 # and trackbar_style 213 # 1.1: - Fixed bug when closing window 214 # 1.0: - Initial release 215 # 216 ## 217 218 use Irssi; 219 use Irssi::TextUI; 220 use Encode; 221 222 use POSIX qw(strftime); 223 224 sub cmd_help { 225 my ($args) = @_; 226 if ($args =~ /^trackbar *$/i) { 227 print CLIENTCRAP <<HELP 228 %9Syntax:%9 229 230 TRACKBAR 231 TRACKBAR GOTO 232 TRACKBAR KEEP 233 TRACKBAR MARK 234 TRACKBAR MARKVISIBLE 235 TRACKBAR MARKALL 236 TRACKBAR REMOVE 237 TRACKBAR REMOVEALL 238 TRACKBAR REDRAW 239 240 %9Parameters:%9 241 242 GOTO: Jump to where the trackbar is, to pick up reading 243 KEEP: Keep this window's trackbar where it is the next time 244 you switch windows (then this flag is cleared again) 245 MARK: Remove the old trackbar and mark the bottom of this 246 window with a new trackbar 247 MARKVISIBLE: Like mark for all visible windows 248 MARKALL: Like mark for all windows 249 REMOVE: Remove this window's trackbar 250 REMOVEALL: Remove all windows' trackbars 251 REDRAW: Force redraw of trackbars 252 253 %9Description:%9 254 255 Manage a trackbar. Without arguments, it will scroll up to the trackbar. 256 257 %9Examples:%9 258 259 /TRACKBAR MARK 260 /TRACKBAR REMOVE 261 HELP 262 } 263 } 264 265 Irssi::theme_register([ 266 'trackbar_loaded', '%R>>%n %_Scriptinfo:%_ Loaded $0 version $1 by $2.', 267 '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.', 268 'trackbar_all_removed', '%R>>%n %_Trackbar:%_ All the trackbars have been removed.', 269 'trackbar_not_found', '%R>>%n %_Trackbar:%_ No trackbar found in this window.', 270 ]); 271 272 my $old_irssi = Irssi::version < 20140701; 273 sub check_version { 274 if ($old_irssi) { 275 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'trackbar_wrong_version'); 276 return; 277 } else { 278 return 1; 279 } 280 } 281 282 sub is_utf8 { 283 lc Irssi::settings_get_str('term_charset') eq 'utf-8' 284 } 285 286 my (%config, %keep_trackbar, %unseen_trackbar); 287 288 sub remove_one_trackbar { 289 my $win = shift; 290 my $view = shift || $win->view; 291 my $line = $view->get_bookmark('trackbar'); 292 if (defined $line) { 293 my $bottom = $view->{bottom}; 294 $view->remove_line($line); 295 $win->command('^scrollback end') if $bottom && !$win->view->{bottom}; 296 $view->redraw; 297 } 298 } 299 300 sub add_one_trackbar_pt1 { 301 my $win = shift; 302 my $view = shift || $win->view; 303 304 my $last_cur_line = ($view->{buffer}{cur_line}||+{})->{_irssi}; 305 $win->print(line($win->{width}), MSGLEVEL_NEVER); 306 307 my $cur_line = ($win->view->{buffer}{cur_line}||+{})->{_irssi}; # get a fresh buffer 308 309 ($last_cur_line//'') ne ($cur_line//'') # printing was successful 310 } 311 312 sub add_one_trackbar_pt2 { 313 my $win = shift; 314 my $view = $win->view; 315 316 $view->set_bookmark_bottom('trackbar'); 317 $unseen_trackbar{ $win->{_irssi} } = 1; 318 Irssi::signal_emit("window trackbar added", $win); 319 $view->redraw; 320 } 321 322 sub update_one_trackbar { 323 my $win = shift; 324 my $view = shift || $win->view; 325 my $force = shift; 326 my $ignored = win_ignored($win, $view); 327 my $success; 328 329 $success = add_one_trackbar_pt1($win, $view) ? 1 : 0 330 if $force || !$ignored; 331 332 remove_one_trackbar($win, $view) 333 if ( $success || !defined $success ) && ( $force || !defined $force || !$ignored ); 334 335 add_one_trackbar_pt2($win) 336 if $success; 337 } 338 339 sub win_ignored { 340 my $win = shift; 341 my $view = shift || $win->view; 342 return 1 unless $view->{buffer}{lines_count}; 343 return 1 if $win->{name} eq '(status)' && !$config{use_status_window}; 344 no warnings 'uninitialized'; 345 return 1 if grep { $win->{name} eq $_ || $win->{refnum} eq $_ 346 || $win->get_active_name eq $_ } @{ $config{ignore_windows} }; 347 return 0; 348 } 349 350 sub sig_window_changed { 351 my ($newwindow, $oldwindow) = @_; 352 return unless $oldwindow; 353 redraw_one_trackbar($newwindow) unless $old_irssi; 354 trackbar_update_seen($newwindow); 355 return if delete $keep_trackbar{ $oldwindow->{_irssi} }; 356 trackbar_update_seen($oldwindow); 357 return if $config{require_seen} && $unseen_trackbar{ $oldwindow->{_irssi } }; 358 return if $config{all_manual}; 359 update_one_trackbar($oldwindow, undef, 0); 360 } 361 362 sub trackbar_update_seen { 363 my $win = shift; 364 return unless $win; 365 return unless $unseen_trackbar{ $win->{_irssi} }; 366 367 my $view = $win->view; 368 my $line = $view->get_bookmark('trackbar'); 369 unless ($line) { 370 delete $unseen_trackbar{ $win->{_irssi} }; 371 Irssi::signal_emit("window trackbar seen", $win); 372 return; 373 } 374 my $startline = $view->{startline}; 375 return unless $startline; 376 377 if ($startline->{info}{time} < $line->{info}{time} 378 || $startline->{_irssi} == $line->{_irssi}) { 379 delete $unseen_trackbar{ $win->{_irssi} }; 380 Irssi::signal_emit("window trackbar seen", $win); 381 } 382 } 383 384 sub screen_length; 385 { local $@; 386 eval { require Text::CharWidth; }; 387 unless ($@) { 388 *screen_length = sub { Text::CharWidth::mbswidth($_[0]) }; 389 } 390 else { 391 *screen_length = sub { 392 my $temp = shift; 393 Encode::_utf8_on($temp) if is_utf8(); 394 length($temp) 395 }; 396 } 397 } 398 399 { my %strip_table = ( 400 (map { $_ => '' } (split //, '04261537' . 'kbgcrmyw' . 'KBGCRMYW' . 'U9_8I:|FnN>#[' . 'pP')), 401 (map { $_ => $_ } (split //, '{}%')), 402 ); 403 sub c_length { 404 my $o = Irssi::strip_codes($_[0]); 405 $o =~ s/(%(%|Z.{6}|z.{6}|X..|x..|.))/exists $strip_table{$2} ? $strip_table{$2} : 406 $2 =~ m{x(?:0[a-f]|[1-6][0-9a-z]|7[a-x])|z[0-9a-f]{6}}i ? '' : $1/gex; 407 screen_length($o) 408 } 409 } 410 411 sub line { 412 my ($width, $time) = @_; 413 my $string = $config{string}; 414 $string = ' ' unless length $string; 415 $time ||= time; 416 417 Encode::_utf8_on($string) if is_utf8(); 418 my $length = c_length($string); 419 420 my $format = ''; 421 if ($config{print_timestamp}) { 422 $format = $config{timestamp_str}; 423 $format =~ y/%/\01/; 424 $format =~ s/\01\01/%/g; 425 $format = strftime($format, localtime $time); 426 $format =~ y/\01/%/; 427 } 428 429 my $times = $width / $length; 430 $times += 1 if $times != int $times; 431 my $style = "$config{style}"; 432 Encode::_utf8_on($style) if is_utf8(); 433 $format .= $style; 434 $width -= c_length($format); 435 $string x= $times; 436 chop $string while length $string && c_length($string) > $width; 437 return $format . $string; 438 } 439 440 sub remove_all_trackbars { 441 for my $window (Irssi::windows) { 442 next unless ref $window; 443 remove_one_trackbar($window); 444 } 445 } 446 447 sub UNLOAD { 448 remove_all_trackbars(); 449 } 450 451 sub redraw_one_trackbar { 452 my $win = shift; 453 my $view = $win->view; 454 my $line = $view->get_bookmark('trackbar'); 455 return unless $line; 456 my $bottom = $view->{bottom}; 457 $win->print_after($line, MSGLEVEL_NEVER, line($win->{width}, $line->{info}{time}), 458 $line->{info}{time}); 459 $view->set_bookmark('trackbar', $win->last_line_insert); 460 $view->remove_line($line); 461 $win->command('^scrollback end') if $bottom && !$win->view->{bottom}; 462 $view->redraw; 463 } 464 465 sub redraw_trackbars { 466 return unless check_version(); 467 for my $win (Irssi::windows) { 468 next unless ref $win; 469 redraw_one_trackbar($win); 470 } 471 } 472 473 sub goto_trackbar { 474 my $win = Irssi::active_win; 475 my $line = $win->view->get_bookmark('trackbar'); 476 477 if ($line) { 478 $win->command("scrollback goto ". strftime("%d %H:%M:%S", localtime($line->{info}{time}))); 479 } else { 480 $win->printformat(MSGLEVEL_CLIENTCRAP, 'trackbar_not_found'); 481 } 482 } 483 484 sub cmd_mark { 485 update_one_trackbar(Irssi::active_win, undef, 1); 486 } 487 488 sub cmd_markall { 489 for my $window (Irssi::windows) { 490 next unless ref $window; 491 update_one_trackbar($window); 492 } 493 } 494 495 sub signal_stop { 496 Irssi::signal_stop; 497 } 498 499 sub cmd_markvisible { 500 my @wins = Irssi::windows; 501 my $awin = 502 my $bwin = Irssi::active_win; 503 my $awin_counter = 0; 504 Irssi::signal_add_priority('window changed' => 'signal_stop', -99); 505 do { 506 Irssi::active_win->command('window up'); 507 $awin = Irssi::active_win; 508 update_one_trackbar($awin); 509 ++$awin_counter; 510 } until ($awin->{refnum} == $bwin->{refnum} || $awin_counter >= @wins); 511 Irssi::signal_remove('window changed' => 'signal_stop'); 512 } 513 514 sub cmd_trackbar_remove_one { 515 remove_one_trackbar(Irssi::active_win); 516 } 517 518 sub cmd_remove_all_trackbars { 519 remove_all_trackbars(); 520 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'trackbar_all_removed'); 521 } 522 523 sub cmd_keep_once { 524 $keep_trackbar{ Irssi::active_win->{_irssi} } = 1; 525 } 526 527 sub trackbar_runsub { 528 my ($data, $server, $item) = @_; 529 $data =~ s/\s+$//g; 530 531 if ($data) { 532 Irssi::command_runsub('trackbar', $data, $server, $item); 533 } else { 534 goto_trackbar(); 535 } 536 } 537 538 sub update_config { 539 my $was_status_window = $config{use_status_window}; 540 $config{style} = Irssi::settings_get_str('trackbar_style'); 541 $config{string} = Irssi::settings_get_str('trackbar_string'); 542 $config{require_seen} = Irssi::settings_get_bool('trackbar_require_seen'); 543 $config{all_manual} = Irssi::settings_get_bool('trackbar_all_manual'); 544 $config{ignore_windows} = [ split /[,\s]+/, Irssi::settings_get_str('trackbar_ignore_windows') ]; 545 $config{use_status_window} = Irssi::settings_get_bool('trackbar_use_status_window'); 546 $config{print_timestamp} = Irssi::settings_get_bool('trackbar_print_timestamp'); 547 if (defined $was_status_window && $was_status_window != $config{use_status_window}) { 548 if (my $swin = Irssi::window_find_name('(status)')) { 549 if ($config{use_status_window}) { 550 update_one_trackbar($swin); 551 } 552 else { 553 remove_one_trackbar($swin); 554 } 555 } 556 } 557 if ($config{print_timestamp}) { 558 my $ts_format = Irssi::settings_get_str('timestamp_format'); 559 my $ts_theme = Irssi::current_theme->get_format('fe-common/core', 'timestamp'); 560 my $render_str = Irssi::current_theme->format_expand($ts_theme); 561 (my $ts_escaped = $ts_format) =~ s/([%\$])/$1$1/g; 562 $render_str =~ s/(?|\$(.)(?!\w)|\$\{(\w+)\})/$1 eq 'Z' ? $ts_escaped : $1/ge; 563 $config{timestamp_str} = $render_str; 564 } 565 redraw_trackbars() unless $old_irssi; 566 } 567 568 Irssi::settings_add_str('trackbar', 'trackbar_string', is_utf8() ? "\x{2500}" : '-'); 569 Irssi::settings_add_str('trackbar', 'trackbar_style', '%K'); 570 Irssi::settings_add_str('trackbar', 'trackbar_ignore_windows', ''); 571 Irssi::settings_add_bool('trackbar', 'trackbar_use_status_window', 1); 572 Irssi::settings_add_bool('trackbar', 'trackbar_print_timestamp', 0); 573 Irssi::settings_add_bool('trackbar', 'trackbar_require_seen', 0); 574 Irssi::settings_add_bool('trackbar', 'trackbar_all_manual', 0); 575 576 update_config(); 577 578 Irssi::signal_add_last( 'mainwindow resized' => 'redraw_trackbars') 579 unless $old_irssi; 580 581 Irssi::signal_register({'window trackbar added' => [qw/Irssi::UI::Window/]}); 582 Irssi::signal_register({'window trackbar seen' => [qw/Irssi::UI::Window/]}); 583 Irssi::signal_register({'gui page scrolled' => [qw/Irssi::UI::Window/]}); 584 Irssi::signal_add_last('gui page scrolled' => 'trackbar_update_seen'); 585 586 Irssi::signal_add('setup changed' => 'update_config'); 587 Irssi::signal_add_priority('session save' => 'remove_all_trackbars', Irssi::SIGNAL_PRIORITY_HIGH-1); 588 589 Irssi::signal_add('window changed' => 'sig_window_changed'); 590 591 Irssi::command_bind('trackbar goto' => 'goto_trackbar'); 592 Irssi::command_bind('trackbar keep' => 'cmd_keep_once'); 593 Irssi::command_bind('trackbar mark' => 'cmd_mark'); 594 Irssi::command_bind('trackbar markvisible' => 'cmd_markvisible'); 595 Irssi::command_bind('trackbar markall' => 'cmd_markall'); 596 Irssi::command_bind('trackbar remove' => 'cmd_trackbar_remove_one'); 597 Irssi::command_bind('trackbar removeall' => 'cmd_remove_all_trackbars'); 598 Irssi::command_bind('trackbar redraw' => 'redraw_trackbars'); 599 Irssi::command_bind('trackbar' => 'trackbar_runsub'); 600 Irssi::command_bind('mark' => 'cmd_mark'); 601 Irssi::command_bind_last('help' => 'cmd_help'); 602 603 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'trackbar_loaded', $IRSSI{name}, $VERSION, $IRSSI{authors}); 604 605 # workaround for issue #271 606 { package Irssi::Nick }