--- iselect.pl 2007/10/25 12:45:18 4 +++ iselect.pl 2007/10/25 14:55:00 9 @@ -2,7 +2,7 @@ use strict; use Term::Screen; -use Carp qw/confess/; +use Carp qw/cluck/; use Data::Dump qw/dump/; my $data = <<'EOF'; @@ -30,6 +30,8 @@ } close($ps); +$data .= "\n--EOF--"; + my $scr; # leave sane terminal if script dies @@ -40,7 +42,7 @@ my @lines = split(/\n/, $data); -my $o = 0; # offset in original text +my $top_screen_line = 0; # offset in original text my $pos = 0; # default: select first line @@ -48,12 +50,13 @@ my $status_text = ''; my $error_text = ''; +my $status_lines = 3; # find which lines are selectable in input file my $selectable_line; for my $l (0 .. $#lines) { - if ($lines[$l] !~ s/^{s}//) { + if ($lines[$l] =~ s/^{s}//) { $selectable_line->{$l}++; } } @@ -73,8 +76,8 @@ sub chunk { my $t = shift; - return unless length($t) > 2; - return substr($t,1,$scr->cols); + cluck "expected line" unless defined $t; + return substr($t,0,$scr->cols); } sub redraw_line { @@ -88,22 +91,22 @@ } sub redraw { - for my $l (0 .. $scr->rows - 3) { - my $line = $lines[ $l + $o ]; - next if (length($line) < 2); + for my $l (0 .. $scr->rows - $status_lines) { + my $line = $lines[ $l + $top_screen_line ]; redraw_line( $l, $line ); last if ($l == $#lines); } + selected(0); } sub status { my $pcnt = int(($pos || 0) * 100 / ($#lines || 1)); my $pos_txt = sprintf('%d, %d%% ',$pos,$pcnt); - $scr->at($scr->rows - 2,0)->reverse()->puts( + $scr->at($scr->rows - $status_lines + 1,0)->reverse()->puts( sprintf(' %-'.($scr->cols - length($pos_txt) - 2).'s ',$status_text) .$pos_txt)->normal(); - $scr->at($scr->rows - 1,0)->puts( + $scr->at($scr->rows - $status_lines + 2,0)->puts( sprintf('%-'.$scr->cols.'s', $error_text) ); } @@ -111,22 +114,24 @@ sub selected { my $d = shift || 0; - my $screen_line = $pos - $o; + my $screen_line = $pos - $top_screen_line; redraw_line( $screen_line, $lines[$pos] ); - my $last_screen_line = $scr->rows - 3; + my $last_screen_line = $scr->rows - $status_lines; if ( $d < 0 && $screen_line == 0 ) { if ( $pos > 0 ) { - $o--; + $top_screen_line--; + $pos--; } else { $error_text = "Already at Begin."; } redraw; } elsif ( $d > 0 && $screen_line == $last_screen_line ) { - if ( $pos <= $#lines ) { - $o++; + if ( $pos < $#lines ) { + $top_screen_line++; + $pos++; } else { $error_text = "Already at End."; } @@ -137,10 +142,10 @@ my $line = $lines[$pos]; if ( defined $selectable_line->{ $pos } ) { - $scr->at($pos - $o,0)->reverse->bold()->puts( full_line( chunk($line) ) )->normal(); + $scr->at($pos - $top_screen_line,0)->reverse->bold()->puts( full_line( chunk($line) ) )->normal(); $sel_pos = $pos; } else { - $scr->at($pos - $o,0)->reverse->puts( full_line( chunk($line) ) ); + $scr->at($pos - $top_screen_line,0)->reverse->puts( full_line( chunk($line) ) ); $sel_pos = -1; } status; @@ -155,13 +160,31 @@ $error_text = ""; + my $lines_on_screen = $scr->rows - $status_lines; + if ($key eq 'ku') { selected( -1 ); } elsif ($key eq 'kd') { selected( +1 ); + } elsif ($key eq 'pgup' ) { + # first line on screen? + if ( $pos == $top_screen_line ) { + $top_screen_line -= $lines_on_screen; + $top_screen_line = 0 if $top_screen_line < 0; + redraw; + } + selected( -( $pos - $top_screen_line ) ); + } elsif ($key eq 'pgdn' ) { + # last line on screen? + if ( $pos - $top_screen_line == $lines_on_screen ) { + $top_screen_line += $lines_on_screen; + $top_screen_line = $#lines - $lines_on_screen if $top_screen_line >= $#lines - $lines_on_screen; + redraw; + } + selected( $top_screen_line + $lines_on_screen - $pos ); } - $status_text = sprintf("pos: %-3d sel_pos: %-3d top offset: %-3d", $pos, $sel_pos, $o ); + $status_text = sprintf("pos: %-3d sel_pos: %-3d top_screen_line: %-3d", $pos, $sel_pos, $top_screen_line ); if ( length($key) > 1 ) { $status_text .= " key: $key"; } else { @@ -170,7 +193,8 @@ status; - redraw if lc($key) eq 'r'; + # CTRL+L + redraw if ord($key) eq 0x0c; exit if (lc($key) eq 'q'); }