summaryrefslogtreecommitdiffstats
path: root/scripts/hlscroll.pl
blob: 47a4066a9188ad860585ef66c5f0d30e385cc57b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use strict;
use Irssi qw(command_bind MSGLEVEL_HILIGHT);
use vars qw($VERSION %IRSSI);

# Recommended key bindings: alt+pgup, alt+pgdown:
#   /bind meta2-5;3~ /scrollback hlprev
#   /bind meta2-6;3~ /scrollback hlnext

$VERSION = '0.02';
%IRSSI = (
    authors     => 'Juerd, Eevee',
    contact	=> '#####@juerd.nl',
    name	=> 'Scroll to hilights',
    description	=> 'Scrolls to previous or next highlight',
    license	=> 'Public Domain',
    url		=> 'http://juerd.nl/site.plp/irssi',
    changed	=> 'Fri Apr 13 05:48 CEST 2012',
    inspiration => '@eevee on Twitter: "i really want irssi keybindings that will scroll to the next/previous line containing a highlight. why does this not exist"',
);

sub _hlscroll{
    my ($direction, $data, $server, $witem) = @_;
    $witem or return;
    my $window = $witem->window or return;

    my $view = $window->view;
    my $line = $view->{buffer}->{cur_line};
    my $delta = $direction eq 'prev' ? -1 : 1;

    my $linesleft = $view->{ypos} - $view->{height} + 1;
    my $scrollby = 0;  # how many display lines to scroll to the next highlight

    # find the line currently at the bottom of the screen
    while (1) {
        my $line_height = $view->get_line_cache($line)->{count};

        if ($linesleft < $line_height) {
            # found it!
            if ($direction eq 'prev') {
                # skip however much of $line is on the screen
                $scrollby = $linesleft - $line_height;
            }
            else {
                # skip however much of $line is off the screen
                $scrollby = $linesleft;
            }

            last;
        }

        $linesleft -= $line_height;

        last if not $line->prev;
        $line = $line->prev;
    }

    while ($line->$direction) {
        $line = $line->$direction;
        my $line_height = $view->get_line_cache($line)->{count};

        if ($line->{info}{level} & MSGLEVEL_HILIGHT) {
            # this algorithm scrolls to the "border" between lines -- if
            # scrolling down, add in the line's entire height so it's entirely
            # visible
            if ($direction eq 'next') {
                $scrollby += $delta * $line_height;
            }

            $view->scroll($scrollby);
            return;
        }

        $scrollby += $delta * $line_height;
    }

    if ($direction eq 'next' and not $line->next) {
        # scroll all the way to the bottom, after the last highlight
        $view->scroll_line($line);
    }
};

command_bind 'scrollback hlprev' => sub { _hlscroll('prev', @_) };
command_bind 'scrollback hlnext' => sub { _hlscroll('next', @_) };