-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmenupick
executable file
·154 lines (135 loc) · 3.94 KB
/
menupick
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#!/usr/bin/perl
use Getopt::Std;
my $opt = { 1 => 0, n => 30, "q" => 0 };
getopts('1qn:', $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;
$quit = 1, last if $opt->{q} and @set;
}
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)
-q: quick mode: exit as soon as at least one item has been selected
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;
}