Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 152 lines (133 sloc) 3.81 KB
#!/usr/bin/perl
use Getopt::Std;
my $opt = { 1 => 0, n => 30 };
getopts('1n:', $opt) or usage();
my $pagesize = $opt->{n};
chomp(my @item = <>);
my $last_page = int(@item / $pagesize);
$last_page-- if @item % $pagesize == 0;
unless (@item) {
warn "No items supplied to menupick\n";
exit;
}
open my($ttyin), "<", "/dev/tty"
or do { warn "No tty: $!\n"; exit 1 };
open my($ttyout), ">", "/dev/tty"
or do { warn "No tty: $!\n"; exit 1 };
if ($opt->{1} && @item == 1) {
print @item, "\n";
exit;
}
sub show_menu {
my ($page, $set) = @_;
$set //= [];
my %sh = map { $_ => 1 } @$set;
my ($start, $end) = page_bounds($page);
for my $i ($start .. $end) {
last unless defined $item[$i];
printf $ttyout "%2d. %s %s\n", $i, $sh{$i} ? "*" : " ", $item[$i];
}
if ($last_page > 0) {
print $ttyout ($page == $last_page ? "--END--\n" : "--more--\n");
}
}
sub page_bounds {
my ($page) = @_;
my $first = $page*$pagesize;
my $last = ($page+1)*$pagesize-1;
$last = $#item if $last > $#item;
return ($first, $last);
}
my $page = 0;
my @set = ();
show_menu(0);
while (1) {
my $commands = prompt($ttyin, $ttyout);
my $newpage;
last unless $commands =~ /\S/;
chomp $commands;
my $quit = $commands =~ s/[!q]\s*$//;
$commands =~ s/(\?+)$/ $1/;
my $show = "";
for my $cmd (split /[,\s]+/, $commands) {
$show = 'long' if $cmd =~ s/\?{2,}//; # ??
$show = 'short' if $cmd =~ s/\?//; # ?
next unless $cmd =~ /\S/;
if ($cmd eq "*") { # *
modify(sprintf("%d-%d", page_bounds($page)), $page, \@set);
} elsif ($cmd =~ /[kKpP]/) {
$newpage = $page - 1;
$newpage = 0 if $newpage < 0;
$show = 'long';
} elsif ($cmd =~ /[JjnN]/) {
$newpage = $page + 1;
$newpage = $last_page if $newpage > $last_page;
$show = 'long';
} else { # 12, !12, -12, 12-17
# Run it up the flagpole...
modify($cmd, $page, \@set);
}
$page = $newpage if defined $newpage;
}
if ($show eq "short") {
print_set($ttyout, @set);
} elsif ($show eq "long") {
show_menu($page, \@set);
}
last if $quit;
}
print join "\n", @item[@set], "";
exit 0;
sub prompt {
my ($in, $out) = @_;
print $out "> ";
my $txt = <$in>;
return $txt;
}
sub modify {
my ($mod, $page, $set) = @_;
my %set;
@set{@$set} = (1) x @$set; # URGH
#mod =~ tr/,/ /;
my @words = split /\s+/, $mod;
for my $word (@words) {
if ($word =~ /^\d+$/) {
$set{$word} = 1;
} elsif ($word =~ /^ (\d+) - (\d+) $/x) {
for ($1 .. $2) { $set{$_} = 1 }
} elsif ($word =~ /^ [-!] (\d+) $/x) {
delete $set{$1};
}
}
@$set = sort { $a <=> $b } keys %set;
}
sub print_set {
my ($out) = shift;
print $out "@_\n";
}
sub usage {
print STDERR "Usage: menupick [-1] [-n pagesize]
Read items from standard input, prompt terminal
for a selection of them, print selected items
on standard output.
-1: if there is only one item, select it without prompting
-n pagesize: maximum number of items on each page of the menu
(default 30)
Commands:
Each line of input is a series of words of the form
N !N N-N *
where N is any number. An empty line, or a line ending in '!',
signals the end of the input.
N selects the specified item.
!N un-selects it.
N-N selects the items in the specified range.
* selects every item on the current page
n goes to the next page
p goes to the previous page
After changing pages, or if the line contains '??' anywhere, a
menu is printed listing the items on the current page, showing
which, if any, are selected. Otherwise, if the line contains '?'
anywhere, the indices of all currently-selected items are listed.
";
exit 2;
}