trackbar.pl (20765B)
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.8"; # 89f27cc2c12368e 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 usefull 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.8: - fix /^join bug 176 # 2.7: - add /set trackbar_all_manual option 177 # 2.5: - merge back on scripts.irssi.org 178 # - fix /trackbar redraw broken in 2.4 179 # - fix legacy encodings 180 # - add workaround for irssi issue #271 181 # 2.4: - add support for horizontal splits 182 # 2.3: - add some features for seen tracking using other scripts 183 # 2.0: - big rewrite based on 1.4 184 # * removed /tb, you can have it with /alias tb trackbar if you want 185 # * subcommand and settings changes: 186 # /trackbar vmark => /trackbar markvisible 187 # /trackbar scroll => /trackbar goto (or just /trackbar) 188 # /trackbar help => /help trackbar 189 # /set trackbar_hide_windows => /set trackbar_ignore_windows 190 # /set trackbar_timestamp => /set trackbar_print_timestamp 191 # * magic line strings were removed, just paste the unicode you want! 192 # * trackbar_timestamp_styled is not currently supported 193 # 1.9: - add version guard 194 # 1.8: - sub draw_bar 195 # 1.7: - Added /tb scroll, trackbar_hide_windows, trackbar_timestamp_timestamp 196 # and trackbar_timestamp_styled 197 # 1.6: - Work around Irssi resize bug, please do /upgrade! (see below) 198 # 1.5: - Resize trackbars in all windows when terminal is resized 199 # 1.4: - Changed our's by my's so the irssi script header is valid 200 # - Removed utf-8 support. In theory, the script should work w/o any 201 # problems for utf-8, just set trackbar_string to a valid utf-8 character 202 # and everything *should* work. However, this script is being plagued by 203 # irssi internal bugs. The function Irssi::settings_get_str does NOT handle 204 # unicode strings properly, hence you will notice problems when setting the bar 205 # to a unicode char. For changing your bar to utf-8 symbols, read the line sub. 206 # 1.3: - Upgrade now removes the trackbars. 207 # - Some code cleanups, other defaults 208 # - /mark sets the line to the bottom 209 # 1.2: - Support for utf-8 210 # - How the bar looks can now be configured with trackbar_string 211 # and trackbar_style 212 # 1.1: - Fixed bug when closing window 213 # 1.0: - Initial release 214 # 215 ## 216 217 use Irssi; 218 use Irssi::TextUI; 219 use Encode; 220 221 use POSIX qw(strftime); 222 223 sub cmd_help { 224 my ($args) = @_; 225 if ($args =~ /^trackbar *$/i) { 226 print CLIENTCRAP <<HELP 227 %9Syntax:%9 228 229 TRACKBAR 230 TRACKBAR GOTO 231 TRACKBAR KEEP 232 TRACKBAR MARK 233 TRACKBAR MARKVISIBLE 234 TRACKBAR MARKALL 235 TRACKBAR REMOVE 236 TRACKBAR REMOVEALL 237 TRACKBAR REDRAW 238 239 %9Parameters:%9 240 241 GOTO: Jump to where the trackbar is, to pick up reading 242 KEEP: Keep this window's trackbar where it is the next time 243 you switch windows (then this flag is cleared again) 244 MARK: Remove the old trackbar and mark the bottom of this 245 window with a new trackbar 246 MARKVISIBLE: Like mark for all visible windows 247 MARKALL: Like mark for all windows 248 REMOVE: Remove this window's trackbar 249 REMOVEALL: Remove all windows' trackbars 250 REDRAW: Force redraw of trackbars 251 252 %9Description:%9 253 254 Manage a trackbar. Without arguments, it will scroll up to the trackbar. 255 256 %9Examples:%9 257 258 /TRACKBAR MARK 259 /TRACKBAR REMOVE 260 HELP 261 } 262 } 263 264 Irssi::theme_register([ 265 'trackbar_loaded', '%R>>%n %_Scriptinfo:%_ Loaded $0 version $1 by $2.', 266 '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.', 267 'trackbar_all_removed', '%R>>%n %_Trackbar:%_ All the trackbars have been removed.', 268 'trackbar_not_found', '%R>>%n %_Trackbar:%_ No trackbar found in this window.', 269 ]); 270 271 my $old_irssi = Irssi::version < 20140701; 272 sub check_version { 273 if ($old_irssi) { 274 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'trackbar_wrong_version'); 275 return; 276 } else { 277 return 1; 278 } 279 } 280 281 sub is_utf8 { 282 lc Irssi::settings_get_str('term_charset') eq 'utf-8' 283 } 284 285 my (%config, %keep_trackbar, %unseen_trackbar); 286 287 sub remove_one_trackbar { 288 my $win = shift; 289 my $view = shift || $win->view; 290 my $line = $view->get_bookmark('trackbar'); 291 if (defined $line) { 292 my $bottom = $view->{bottom}; 293 $view->remove_line($line); 294 $win->command('^scrollback end') if $bottom && !$win->view->{bottom}; 295 $view->redraw; 296 } 297 } 298 299 sub add_one_trackbar_pt1 { 300 my $win = shift; 301 my $view = shift || $win->view; 302 303 my $last_cur_line = $view->{buffer}{cur_line}{_irssi}; 304 $win->print(line($win->{width}), MSGLEVEL_NEVER); 305 306 my $cur_line = $win->view->{buffer}{cur_line}{_irssi}; # get a fresh buffer 307 308 $last_cur_line ne $cur_line # printing was successful 309 } 310 311 sub add_one_trackbar_pt2 { 312 my $win = shift; 313 my $view = $win->view; 314 315 $view->set_bookmark_bottom('trackbar'); 316 $unseen_trackbar{ $win->{_irssi} } = 1; 317 Irssi::signal_emit("window trackbar added", $win); 318 $view->redraw; 319 } 320 321 sub update_one_trackbar { 322 my $win = shift; 323 my $view = shift || $win->view; 324 my $force = shift; 325 my $ignored = win_ignored($win, $view); 326 my $success; 327 328 $success = add_one_trackbar_pt1($win, $view) ? 1 : 0 329 if $force || !$ignored; 330 331 remove_one_trackbar($win, $view) 332 if ( $success || !defined $success ) && ( $force || !defined $force || !$ignored ); 333 334 add_one_trackbar_pt2($win) 335 if $success; 336 } 337 338 sub win_ignored { 339 my $win = shift; 340 my $view = shift || $win->view; 341 return 1 unless $view->{buffer}{lines_count}; 342 return 1 if $win->{name} eq '(status)' && !$config{use_status_window}; 343 no warnings 'uninitialized'; 344 return 1 if grep { $win->{name} eq $_ || $win->{refnum} eq $_ 345 || $win->get_active_name eq $_ } @{ $config{ignore_windows} }; 346 return 0; 347 } 348 349 sub sig_window_changed { 350 my ($newwindow, $oldwindow) = @_; 351 return unless $oldwindow; 352 redraw_one_trackbar($newwindow) unless $old_irssi; 353 trackbar_update_seen($newwindow); 354 return if delete $keep_trackbar{ $oldwindow->{_irssi} }; 355 trackbar_update_seen($oldwindow); 356 return if $config{require_seen} && $unseen_trackbar{ $oldwindow->{_irssi } }; 357 return if $config{all_manual}; 358 update_one_trackbar($oldwindow, undef, 0); 359 } 360 361 sub trackbar_update_seen { 362 my $win = shift; 363 return unless $win; 364 return unless $unseen_trackbar{ $win->{_irssi} }; 365 366 my $view = $win->view; 367 my $line = $view->get_bookmark('trackbar'); 368 unless ($line) { 369 delete $unseen_trackbar{ $win->{_irssi} }; 370 Irssi::signal_emit("window trackbar seen", $win); 371 return; 372 } 373 my $startline = $view->{startline}; 374 return unless $startline; 375 376 if ($startline->{info}{time} < $line->{info}{time} 377 || $startline->{_irssi} == $line->{_irssi}) { 378 delete $unseen_trackbar{ $win->{_irssi} }; 379 Irssi::signal_emit("window trackbar seen", $win); 380 } 381 } 382 383 sub screen_length; 384 { local $@; 385 eval { require Text::CharWidth; }; 386 unless ($@) { 387 *screen_length = sub { Text::CharWidth::mbswidth($_[0]) }; 388 } 389 else { 390 *screen_length = sub { 391 my $temp = shift; 392 Encode::_utf8_on($temp) if is_utf8(); 393 length($temp) 394 }; 395 } 396 } 397 398 { my %strip_table = ( 399 (map { $_ => '' } (split //, '04261537' . 'kbgcrmyw' . 'KBGCRMYW' . 'U9_8I:|FnN>#[' . 'pP')), 400 (map { $_ => $_ } (split //, '{}%')), 401 ); 402 sub c_length { 403 my $o = Irssi::strip_codes($_[0]); 404 $o =~ s/(%(%|Z.{6}|z.{6}|X..|x..|.))/exists $strip_table{$2} ? $strip_table{$2} : 405 $2 =~ m{x(?:0[a-f]|[1-6][0-9a-z]|7[a-x])|z[0-9a-f]{6}}i ? '' : $1/gex; 406 screen_length($o) 407 } 408 } 409 410 sub line { 411 my ($width, $time) = @_; 412 my $string = $config{string}; 413 $string = ' ' unless length $string; 414 $time ||= time; 415 416 Encode::_utf8_on($string) if is_utf8(); 417 my $length = c_length($string); 418 419 my $format = ''; 420 if ($config{print_timestamp}) { 421 $format = $config{timestamp_str}; 422 $format =~ y/%/\01/; 423 $format =~ s/\01\01/%/g; 424 $format = strftime($format, localtime $time); 425 $format =~ y/\01/%/; 426 } 427 428 my $times = $width / $length; 429 $times += 1 if $times != int $times; 430 my $style = "$config{style}"; 431 Encode::_utf8_on($style) if is_utf8(); 432 $format .= $style; 433 $width -= c_length($format); 434 $string x= $times; 435 chop $string while length $string && c_length($string) > $width; 436 return $format . $string; 437 } 438 439 sub remove_all_trackbars { 440 for my $window (Irssi::windows) { 441 next unless ref $window; 442 remove_one_trackbar($window); 443 } 444 } 445 446 sub UNLOAD { 447 remove_all_trackbars(); 448 } 449 450 sub redraw_one_trackbar { 451 my $win = shift; 452 my $view = $win->view; 453 my $line = $view->get_bookmark('trackbar'); 454 return unless $line; 455 my $bottom = $view->{bottom}; 456 $win->print_after($line, MSGLEVEL_NEVER, line($win->{width}, $line->{info}{time}), 457 $line->{info}{time}); 458 $view->set_bookmark('trackbar', $win->last_line_insert); 459 $view->remove_line($line); 460 $win->command('^scrollback end') if $bottom && !$win->view->{bottom}; 461 $view->redraw; 462 } 463 464 sub redraw_trackbars { 465 return unless check_version(); 466 for my $win (Irssi::windows) { 467 next unless ref $win; 468 redraw_one_trackbar($win); 469 } 470 } 471 472 sub goto_trackbar { 473 my $win = Irssi::active_win; 474 my $line = $win->view->get_bookmark('trackbar'); 475 476 if ($line) { 477 $win->command("scrollback goto ". strftime("%d %H:%M:%S", localtime($line->{info}{time}))); 478 } else { 479 $win->printformat(MSGLEVEL_CLIENTCRAP, 'trackbar_not_found'); 480 } 481 } 482 483 sub cmd_mark { 484 update_one_trackbar(Irssi::active_win, undef, 1); 485 } 486 487 sub cmd_markall { 488 for my $window (Irssi::windows) { 489 next unless ref $window; 490 update_one_trackbar($window); 491 } 492 } 493 494 sub signal_stop { 495 Irssi::signal_stop; 496 } 497 498 sub cmd_markvisible { 499 my @wins = Irssi::windows; 500 my $awin = 501 my $bwin = Irssi::active_win; 502 my $awin_counter = 0; 503 Irssi::signal_add_priority('window changed' => 'signal_stop', -99); 504 do { 505 Irssi::active_win->command('window up'); 506 $awin = Irssi::active_win; 507 update_one_trackbar($awin); 508 ++$awin_counter; 509 } until ($awin->{refnum} == $bwin->{refnum} || $awin_counter >= @wins); 510 Irssi::signal_remove('window changed' => 'signal_stop'); 511 } 512 513 sub cmd_trackbar_remove_one { 514 remove_one_trackbar(Irssi::active_win); 515 } 516 517 sub cmd_remove_all_trackbars { 518 remove_all_trackbars(); 519 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'trackbar_all_removed'); 520 } 521 522 sub cmd_keep_once { 523 $keep_trackbar{ Irssi::active_win->{_irssi} } = 1; 524 } 525 526 sub trackbar_runsub { 527 my ($data, $server, $item) = @_; 528 $data =~ s/\s+$//g; 529 530 if ($data) { 531 Irssi::command_runsub('trackbar', $data, $server, $item); 532 } else { 533 goto_trackbar(); 534 } 535 } 536 537 sub update_config { 538 my $was_status_window = $config{use_status_window}; 539 $config{style} = Irssi::settings_get_str('trackbar_style'); 540 $config{string} = Irssi::settings_get_str('trackbar_string'); 541 $config{require_seen} = Irssi::settings_get_bool('trackbar_require_seen'); 542 $config{all_manual} = Irssi::settings_get_bool('trackbar_all_manual'); 543 $config{ignore_windows} = [ split /[,\s]+/, Irssi::settings_get_str('trackbar_ignore_windows') ]; 544 $config{use_status_window} = Irssi::settings_get_bool('trackbar_use_status_window'); 545 $config{print_timestamp} = Irssi::settings_get_bool('trackbar_print_timestamp'); 546 if (defined $was_status_window && $was_status_window != $config{use_status_window}) { 547 if (my $swin = Irssi::window_find_name('(status)')) { 548 if ($config{use_status_window}) { 549 update_one_trackbar($swin); 550 } 551 else { 552 remove_one_trackbar($swin); 553 } 554 } 555 } 556 if ($config{print_timestamp}) { 557 my $ts_format = Irssi::settings_get_str('timestamp_format'); 558 my $ts_theme = Irssi::current_theme->get_format('fe-common/core', 'timestamp'); 559 my $render_str = Irssi::current_theme->format_expand($ts_theme); 560 (my $ts_escaped = $ts_format) =~ s/([%\$])/$1$1/g; 561 $render_str =~ s/(?|\$(.)(?!\w)|\$\{(\w+)\})/$1 eq 'Z' ? $ts_escaped : $1/ge; 562 $config{timestamp_str} = $render_str; 563 } 564 redraw_trackbars() unless $old_irssi; 565 } 566 567 Irssi::settings_add_str('trackbar', 'trackbar_string', is_utf8() ? "\x{2500}" : '-'); 568 Irssi::settings_add_str('trackbar', 'trackbar_style', '%X7E'); 569 Irssi::settings_add_str('trackbar', 'trackbar_ignore_windows', ''); 570 Irssi::settings_add_bool('trackbar', 'trackbar_use_status_window', 1); 571 Irssi::settings_add_bool('trackbar', 'trackbar_print_timestamp', 0); 572 Irssi::settings_add_bool('trackbar', 'trackbar_require_seen', 0); 573 Irssi::settings_add_bool('trackbar', 'trackbar_all_manual', 1); 574 575 update_config(); 576 577 Irssi::signal_add_last( 'mainwindow resized' => 'redraw_trackbars') 578 unless $old_irssi; 579 580 Irssi::signal_register({'window trackbar added' => [qw/Irssi::UI::Window/]}); 581 Irssi::signal_register({'window trackbar seen' => [qw/Irssi::UI::Window/]}); 582 Irssi::signal_register({'gui page scrolled' => [qw/Irssi::UI::Window/]}); 583 Irssi::signal_add_last('gui page scrolled' => 'trackbar_update_seen'); 584 585 Irssi::signal_add('setup changed' => 'update_config'); 586 Irssi::signal_add_priority('session save' => 'remove_all_trackbars', Irssi::SIGNAL_PRIORITY_HIGH-1); 587 588 Irssi::signal_add('window changed' => 'sig_window_changed'); 589 590 Irssi::command_bind('trackbar goto' => 'goto_trackbar'); 591 Irssi::command_bind('trackbar keep' => 'cmd_keep_once'); 592 Irssi::command_bind('trackbar mark' => 'cmd_mark'); 593 Irssi::command_bind('trackbar markvisible' => 'cmd_markvisible'); 594 Irssi::command_bind('trackbar markall' => 'cmd_markall'); 595 Irssi::command_bind('trackbar remove' => 'cmd_trackbar_remove_one'); 596 Irssi::command_bind('trackbar removeall' => 'cmd_remove_all_trackbars'); 597 Irssi::command_bind('trackbar redraw' => 'redraw_trackbars'); 598 Irssi::command_bind('trackbar' => 'trackbar_runsub'); 599 Irssi::command_bind('mark' => 'cmd_mark'); 600 Irssi::command_bind_last('help' => 'cmd_help'); 601 602 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'trackbar_loaded', $IRSSI{name}, $VERSION, $IRSSI{authors}); 603 604 # workaround for issue #271 605 { package Irssi::Nick }