File Coverage

blib/lib/Complete/Getopt/Long.pm
Criterion Covered Total %
statement 254 341 74.4
branch 125 228 54.8
condition 61 83 73.4
subroutine 9 9 100.0
pod 1 1 100.0
total 450 662 67.9


line stmt bran cond sub pod time code
1             package Complete::Getopt::Long;
2              
3             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
4             our $DATE = '2020-04-16'; # DATE
5             our $DIST = 'Complete-Getopt-Long'; # DIST
6             our $VERSION = '0.479'; # VERSION
7              
8 1     1   9036 use 5.010001;
  1         4  
9 1     1   6 use strict;
  1         3  
  1         21  
10 1     1   6 use warnings;
  1         2  
  1         24  
11 1     1   5 use Log::ger;
  1         2  
  1         5  
12              
13             require Exporter;
14             our @ISA = qw(Exporter);
15             our @EXPORT_OK = qw(
16             complete_cli_arg
17             );
18              
19             our %SPEC;
20              
21             our $COMPLETE_GETOPT_LONG_TRACE=$ENV{COMPLETE_GETOPT_LONG_TRACE} // 0;
22             our $COMPLETE_GETOPT_LONG_DEFAULT_ENV = $ENV{COMPLETE_GETOPT_LONG_DEFAULT_ENV} // 1;
23             our $COMPLETE_GETOPT_LONG_DEFAULT_FILE = $ENV{COMPLETE_GETOPT_LONG_DEFAULT_FILE} // 1;
24              
25             sub _default_completion {
26 1     1   747 require Complete::Env;
27 1         1445 require Complete::File;
28 1         2016 require Complete::Util;
29              
30 1         8 my %args = @_;
31 1   50     6 my $word = $args{word} // '';
32              
33 1         2 my $fres;
34 1 50       3 log_trace('[compgl] entering default completion routine') if $COMPLETE_GETOPT_LONG_TRACE;
35              
36             # try completing '$...' with shell variables
37 1 0 33     5 if ($word =~ /\A\$/ && $COMPLETE_GETOPT_LONG_DEFAULT_ENV) {
38 0 0       0 log_trace('[compgl] completing shell variable') if $COMPLETE_GETOPT_LONG_TRACE;
39             {
40 0         0 my $compres = Complete::Env::complete_env(
  0         0  
41             word=>$word);
42 0 0       0 last unless @$compres;
43 0         0 $fres = {words=>$compres, esc_mode=>'shellvar'};
44 0         0 goto RETURN_RES;
45             }
46             # if empty, fallback to searching file
47             }
48              
49             # try completing '~foo' with user dir (appending / if user's home exists)
50 1 0 33     5 if ($word =~ m!\A~([^/]*)\z! && $COMPLETE_GETOPT_LONG_DEFAULT_FILE) {
51 0 0       0 log_trace("[compgl] completing userdir, user=%s", $1) if $COMPLETE_GETOPT_LONG_TRACE;
52             {
53 0         0 eval { require Unix::Passwd::File };
  0         0  
  0         0  
54 0 0       0 last if $@;
55 0         0 my $res = Unix::Passwd::File::list_users(detail=>1);
56 0 0       0 last unless $res->[0] == 200;
57             my $compres = Complete::Util::complete_array_elem(
58 0 0       0 array=>[map {"~" . $_->{user} . ((-d $_->{home}) ? "/":"")}
59 0         0 @{ $res->[2] }],
  0         0  
60             word=>$word,
61             );
62 0 0       0 last unless @$compres;
63 0         0 $fres = {words=>$compres, path_sep=>'/'};
64 0         0 goto RETURN_RES;
65             }
66             # if empty, fallback to searching file
67             }
68              
69             # try completing '~/blah' or '~foo/blah' as if completing file, but do not
70             # expand ~foo (this is supported by complete_file(), so we just give it off
71             # to the routine)
72 1 0 33     4 if ($word =~ m!\A(~[^/]*)/! && $COMPLETE_GETOPT_LONG_DEFAULT_FILE) {
73 0 0       0 log_trace("[compgl] completing file, path=<%s>", $word) if $COMPLETE_GETOPT_LONG_TRACE;
74 0         0 $fres = Complete::Util::hashify_answer(
75             Complete::File::complete_file(word=>$word),
76             {path_sep=>'/'}
77             );
78 0         0 goto RETURN_RES;
79             }
80              
81             # try completing something that contains wildcard with glob. for
82             # convenience, we add '*' at the end so that when user type [AB] it is
83             # treated like [AB]*.
84 1         604 require String::Wildcard::Bash;
85 1 0 33     1149 if (String::Wildcard::Bash::contains_wildcard($word) && $COMPLETE_GETOPT_LONG_DEFAULT_FILE) {
86 0 0       0 log_trace("[compgl] completing with wildcard glob, glob=<%s>", "$word*") if $COMPLETE_GETOPT_LONG_TRACE;
87             {
88 0         0 my $compres = [glob("$word*")];
  0         0  
89 0 0       0 last unless @$compres;
90 0         0 for (@$compres) {
91 0 0       0 $_ .= "/" if (-d $_);
92             }
93 0         0 $fres = {words=>$compres, path_sep=>'/'};
94 0         0 goto RETURN_RES;
95             }
96             # if empty, fallback to searching file
97             }
98              
99 1 50       14 if ($COMPLETE_GETOPT_LONG_DEFAULT_FILE) {
100 1 50       3 log_trace("[compgl] completing with file, file=<%s>", $word) if $COMPLETE_GETOPT_LONG_TRACE;
101 1         5 $fres = Complete::Util::hashify_answer(
102             Complete::File::complete_file(word=>$word),
103             {path_sep=>'/'}
104             );
105             }
106              
107             RETURN_RES:
108 1 50       13900 log_trace("[compgl] leaving default completion routine, result=%s", $fres) if $COMPLETE_GETOPT_LONG_TRACE;
109 1         7 $fres;
110             }
111              
112             # return the possible options. if there is only one candidate (unambiguous
113             # expansion) then scalar will be returned. otherwise, an array of candidates
114             # will be returned.
115             sub _matching_opts {
116 41     41   83 my ($opt, $opts) = @_;
117 41         58 my %candidates;
118 41         241 for (sort {length($a)<=>length($b)} keys %$opts) {
  1242         1672  
119 261 100       512 next unless index($_, $opt) == 0;
120 108         219 $candidates{$_} = $opts->{$_};
121 108 100       213 last if $opt eq $_;
122             }
123 41         124 \%candidates;
124             }
125              
126             # mark an option (and all its aliases) as seen
127             sub _mark_seen {
128 48     48   96 my ($seen_opts, $opt, $opts) = @_;
129 48         76 my $opthash = $opts->{$opt};
130 48 50       94 return unless $opthash;
131 48         77 my $ospec = $opthash->{ospec};
132 48         184 for (keys %$opts) {
133 632         826 my $v = $opts->{$_};
134 632 100       1242 $seen_opts->{$_}++ if $v->{ospec} eq $ospec;
135             }
136             }
137              
138             $SPEC{complete_cli_arg} = {
139             v => 1.1,
140             summary => 'Complete command-line argument using '.
141             'Getopt::Long specification',
142             description => <<'_',
143              
144             This routine can complete option names, where the option names are retrieved
145             from specification. If you provide completion routine in
146             `completion`, you can also complete _option values_ and _arguments_.
147              
148             Note that this routine does not use (it does its own parsing)
149             and currently is not affected by Getopt::Long's configuration. Its behavior
150             mimics Getopt::Long under these configuration: `no_ignore_case`, `bundling` (or
151             `no_bundling` if the `bundling` option is turned off). Which I think is the
152             sensible default. This routine also does not currently support `auto_help` and
153             `auto_version`, so you'll need to add those options specifically if you want to
154             recognize `--help/-?` and `--version`, respectively.
155              
156             _
157             args => {
158             getopt_spec => {
159             summary => 'Getopt::Long specification',
160             schema => 'array*',
161             req => 1,
162             },
163             completion => {
164             summary =>
165             'Completion routine to complete option value/argument',
166             schema => 'code*',
167             description => <<'_',
168              
169             Completion code will receive a hash of arguments (`%args`) containing these
170             keys:
171              
172             * `type` (str, what is being completed, either `optval`, or `arg`)
173             * `word` (str, word to be completed)
174             * `cword` (int, position of words in the words array, starts from 0)
175             * `opt` (str, option name, e.g. `--str`; undef if we're completing argument)
176             * `ospec` (str, Getopt::Long option spec, e.g. `str|S=s`; undef when completing
177             argument)
178             * `argpos` (int, argument position, zero-based; undef if type='optval')
179             * `nth` (int, the number of times this option has seen before, starts from 0
180             that means this is the first time this option has been seen; undef when
181             type='arg')
182             * `seen_opts` (hash, all the options seen in `words`)
183             * `parsed_opts` (hash, options parsed the standard/raw way)
184              
185             as well as all keys from `extras` (but these won't override the above keys).
186              
187             and is expected to return a completion answer structure as described in
188             `Complete` which is either a hash or an array. The simplest form of answer is
189             just to return an array of strings. The various `complete_*` function like those
190             in or the other `Complete::*` modules are suitable to use
191             here.
192              
193             Completion routine can also return undef to express declination, in which case
194             the default completion routine will then be consulted. The default routine
195             completes from shell environment variables (`$FOO`), Unix usernames (`~foo`),
196             and files/directories.
197              
198             Example:
199              
200             use Complete::Unix qw(complete_user);
201             use Complete::Util qw(complete_array_elem);
202             complete_cli_arg(
203             getopt_spec => [
204             'help|h' => sub{...},
205             'format=s' => \$format,
206             'user=s' => \$user,
207             ],
208             completion => sub {
209             my %args = @_;
210             my $word = $args{word};
211             my $ospec = $args{ospec};
212             if ($ospec && $ospec eq 'format=s') {
213             complete_array_elem(array=>[qw/json text xml yaml/], word=>$word);
214             } else {
215             complete_user(word=>$word);
216             }
217             },
218             );
219              
220             _
221             },
222             words => {
223             summary => 'Command line arguments, like @ARGV',
224             description => <<'_',
225              
226             See function `parse_cmdline` in on how to produce this (if
227             you're using bash).
228              
229             _
230             schema => 'array*',
231             req => 1,
232             },
233             cword => {
234             summary =>
235             "Index in words of the word we're trying to complete",
236             description => <<'_',
237              
238             See function `parse_cmdline` in on how to produce this (if
239             you're using bash).
240              
241             _
242             schema => 'int*',
243             req => 1,
244             },
245             extras => {
246             summary => 'Add extra arguments to completion routine',
247             schema => 'hash',
248             description => <<'_',
249              
250             The keys from this `extras` hash will be merged into the final `%args` passed to
251             completion routines. Note that standard keys like `type`, `word`, and so on as
252             described in the function description will not be overwritten by this.
253              
254             _
255             },
256             bundling => {
257             schema => 'bool*',
258             default => 1,
259             'summary.alt.bool.not' => 'Turn off bundling',
260             description => <<'_',
261              
262             If you turn off bundling, completion of short-letter options won't support
263             bundling (e.g. `-b` won't add more single-letter options), but single-dash
264             multiletter options can be recognized. Currently only those specified with a
265             single dash will be completed. For example if you have `-foo=s` in your option
266             specification, `-f` can complete it.
267              
268             This can be used to complete old-style programs, e.g. emacs which has options
269             like `-nw`, `-nbc` etc (but also have double-dash options like
270             `--no-window-system` or `--no-blinking-cursor`).
271              
272             _
273             },
274             },
275             result_naked => 1,
276             result => {
277             schema => ['any*' => of => ['hash*', 'array*']],
278             description => <<'_',
279              
280             You can use `format_completion` function in module to format
281             the result of this function for bash.
282              
283             _
284             },
285             };
286             sub complete_cli_arg {
287 35     35 1 111461 require Complete::Util;
288 35         6379 require Getopt::Long::Util;
289              
290 35         1919 my %args = @_;
291              
292 35         70 my $fname = __PACKAGE__ . "::complete_cli_arg"; # XXX use __SUB__
293 35         55 my $fres;
294              
295 35 50       96 $args{words} or die "Please specify words";
296 35         56 my @words = @{ $args{words} };
  35         87  
297 35 50       86 defined(my $cword = $args{cword}) or die "Please specify cword";
298 35 50       76 my $gospec = $args{getopt_spec} or die "Please specify getopt_spec";
299 35         55 my $comp = $args{completion};
300 35   100     147 my $extras = $args{extras} // {};
301 35   100     119 my $bundling = $args{bundling} // 1;
302 35         53 my %parsed_opts;
303              
304             # backward compatibility: gospec was expected to be a hash, now an array
305 35 100       108 if (ref $gospec eq 'HASH') {
306 1         2 my $ary_gospec = [];
307 1         5 for (keys %$gospec) {
308 2         5 push @$ary_gospec, $_;
309 2 50       7 push @$ary_gospec, $gospec->{$_} if ref $gospec->{$_};
310             }
311 1         3 $gospec = $ary_gospec;
312             }
313              
314 35 50       78 log_trace('[compgl] entering %s(), words=%s, cword=%d, word=<%s>',
315             $fname, \@words, $cword, $words[$cword]) if $COMPLETE_GETOPT_LONG_TRACE;
316              
317             # strip hash storage from getopt_spec
318 35 100       79 shift @$gospec if ref $gospec->[0] eq 'HASH';
319              
320             # parse all options first & supply default completion routine
321 35         50 my %opts;
322 35         49 my $i = -1;
323 35         56 while (++$i <= $#{$gospec}) {
  248         588  
324 213         356 my $ospec = $gospec->[$i];
325 213 100 100     300 my $dest = $i+1 <= $#{$gospec} && ref $gospec->[$i+1] ?
326             splice(@$gospec, $i+1, 1) : undef;
327              
328 213 50       509 my $res = Getopt::Long::Util::parse_getopt_long_opt_spec($ospec)
329             or die "Can't parse option spec '$ospec'";
330 213 50       10158 next if $res->{is_arg};
331 213 100 66     906 $res->{min_vals} //= $res->{type} ? 1 : 0;
332 213 100 100     974 $res->{max_vals} //= $res->{type} || $res->{opttype} ? 1:0;
      66        
333 213         320 for my $o0 (@{ $res->{opts} }) {
  213         426  
334 363 100 100     1232 my @ary = $res->{is_neg} && length($o0) > 1 ?
335             ([$o0, 0], ["no$o0",1], ["no-$o0",1]) : ([$o0,0]);
336 363         593 for my $elem (@ary) {
337 411         656 my $o = $elem->[0];
338 411         532 my $is_neg = $elem->[1];
339             my $k = length($o)==1 ||
340 411 100 100     1384 (!$bundling && $res->{dash_prefix} eq '-') ?
341             "-$o" : "--$o";
342 411         1855 $opts{$k} = {
343             name => $k,
344             ospec => $ospec,
345             dest => $dest,
346             parsed => $res,
347             is_neg => $is_neg,
348             };
349             }
350             }
351             }
352 35         317 my @optnames = sort keys %opts;
353              
354             my $code_get_summary = sub {
355             # currently we only extract summaries from Rinci metadata and
356             # Perinci::CmdLine object
357 169 50   169   292 return unless $extras;
358 169         229 my $ggls_res = $extras->{ggls_res};
359 169 50       494 return unless $ggls_res;
360 0         0 my $cmdline = $extras->{cmdline};
361 0 0       0 return unless $cmdline;
362 0         0 my $r = $extras->{r};
363 0 0       0 return unless $r;
364              
365 0         0 my $optname = shift;
366 0         0 my $ospec = $opts{$optname}{ospec};
367 0 0       0 return unless $ospec; # shouldn't happen
368 0         0 my $specmeta = $ggls_res->[3]{'func.specmeta'};
369 0         0 my $ospecmeta = $specmeta->{$ospec};
370              
371 0 0       0 if ($ospecmeta->{is_alias}) {
372 0         0 my $real_ospecmeta = $specmeta->{ $ospecmeta->{alias_for} };
373 0         0 my $real_opt = $real_ospecmeta->{parsed}{opts}[0];
374 0 0       0 $real_opt = length($real_opt) == 1 ? "-$real_opt" : "--$real_opt";
375 0         0 return "Alias for $real_opt";
376             }
377              
378 0 0       0 if (defined(my $coptname = $ospecmeta->{common_opt})) {
379             # it's a common Perinci::CmdLine option
380 0         0 my $coptspec = $cmdline->{common_opts}{$coptname};
381             #use DD; dd $coptspec;
382 0 0       0 return unless $coptspec;
383              
384 0         0 my $summ;
385             # XXX translate
386 0 0       0 if ($opts{$optname}{is_neg}) {
387 0         0 $summ = $coptspec->{"summary.alt.bool.not"};
388 0 0       0 return $summ if defined $summ;
389 0         0 my $pos_opt = $ospecmeta->{pos_opts}[0];
390 0 0       0 $pos_opt = length($pos_opt) == 1 ? "-$pos_opt" : "--$pos_opt";
391 0         0 return "The opposite of $pos_opt";
392             } else {
393 0         0 $summ = $coptspec->{"summary.alt.bool.yes"};
394 0 0       0 return $summ if defined $summ;
395 0         0 $summ = $coptspec->{"summary"};
396 0 0       0 return $summ if defined $summ;
397             }
398             } else {
399             # it's option from function argument
400 0         0 my $arg = $ospecmeta->{arg};
401 0         0 my $argspec = $extras->{r}{meta}{args}{$arg};
402             #use DD; dd $argspec;
403              
404 0         0 my $summ;
405             # XXX translate
406             #use DD; dd {optname=>$optname, ospecmeta=>$ospecmeta};
407 0 0       0 if ($ospecmeta->{is_neg}) {
408 0         0 $summ = $argspec->{"summary.alt.bool.not"};
409 0 0       0 return $summ if defined $summ;
410 0         0 my $pos_opt = $ospecmeta->{pos_opts}[0];
411 0 0       0 $pos_opt = length($pos_opt) == 1 ? "-$pos_opt" : "--$pos_opt";
412 0         0 return "The opposite of $pos_opt";
413             } else {
414 0         0 $summ = $argspec->{"summary.alt.bool.yes"};
415 0 0       0 return $summ if defined $summ;
416 0         0 $summ = $argspec->{"summary"};
417 0 0       0 return $summ if defined $summ;
418             }
419             }
420              
421 0         0 return;
422 35         292 };
423              
424 35         76 my %seen_opts;
425              
426             # for each word (each element in this array), we try to find out whether
427             # it's supposed to complete option name, or option value, or argument, or
428             # separator (or more than one of them). plus some other information.
429             #
430             # each element is a hash. if hash contains 'optname' key then it expects an
431             # option name. if hash contains 'optval' key then it expects an option
432             # value.
433             #
434             # 'short_only' means that the word is not to be completed with long option
435             # name, only (bundle of) one-letter option names.
436              
437             my @expects;
438              
439 35         53 $i = -1;
440 35         51 my $argpos = 0;
441              
442             WORD:
443 35         52 while (1) {
444 80 100       188 last WORD if ++$i >= @words;
445 48         93 my $word = $words[$i];
446             #say "D:i=$i, word=$word, ~~\@words=",~~@words;
447              
448 48 50 66     121 if ($word eq '--' && $i != $cword) {
449 0         0 $expects[$i] = {separator=>1};
450 0         0 while (1) {
451 0         0 $i++;
452 0 0       0 last WORD if $i >= @words;
453 0         0 $expects[$i] = {arg=>1, argpos=>$argpos++};
454             }
455             }
456              
457 48 100       173 if ($word =~ /\A-/) {
458              
459             # check if it is a (bundle) of short option names
460             SHORT_OPTS:
461             {
462             # it's not a known short option
463 41 100       59 last unless $opts{"-".substr($word,1,1)};
  41         146  
464              
465             # not a bundle, regard as only a single short option name
466 12 100       49 last unless $bundling;
467              
468             # expand bundle
469 11         25 my $j = $i;
470 11         20 my $rest = substr($word, 1);
471 11         20 my @inswords;
472             my $encounter_equal_sign;
473             EXPAND:
474 11         17 while (1) {
475 27 100       97 $rest =~ s/(.)// or last;
476 20         56 my $opt = "-$1";
477 20         32 my $opthash = $opts{$opt};
478 20 50       43 unless ($opthash) {
479             # we encounter an unknown option, doubt that this is a
480             # bundle of short option name, it could be someone
481             # typing --long as -long
482 0         0 @inswords = ();
483 0         0 $expects[$i]{short_only} = 0;
484 0         0 $rest = $word;
485 0         0 last EXPAND;
486             }
487 20 100       46 if ($opthash->{parsed}{max_vals}) {
488             # stop after an option that requires value
489 4         12 _mark_seen(\%seen_opts, $opt, \%opts);
490              
491 4 100       14 if ($i == $j) {
492 2         5 $words[$i] = $opt;
493             } else {
494 2         5 push @inswords, $opt;
495 2         4 $j++;
496             }
497              
498 4         5 my $expand;
499 4 100       9 if (length $rest) {
500 2         6 $expand++;
501             # complete -Sfoo^ is completing option value
502 2 100       9 $expects[$j > $i ? $j+1 : $j+2]{do_complete_optname} = 0;
503 2 100       7 $expects[$j > $i ? $j+1 : $j+2]{optval} = $opt;
504             } else {
505             # complete -S^ as [-S] to add space
506 2 100       22 $expects[$j > $i ? $j-1 : $j]{optname} = $opt;
507             $expects[$j > $i ? $j-1 : $j]{comp_result} = [
508 2 100       22 substr($word, 0, length($word)-length($rest))];
509             }
510              
511 4 50       22 if ($rest =~ s/\A=//) {
512 0         0 $encounter_equal_sign++;
513             }
514              
515 4 100       11 if ($expand) {
516 2         5 push @inswords, "=", $rest;
517 2         4 $j+=2;
518             }
519 4         10 last EXPAND;
520             }
521             # continue splitting
522 16         48 _mark_seen(\%seen_opts, $opt, \%opts);
523 16 100       46 if ($i == $j) {
524 9         19 $words[$i] = $opt;
525             } else {
526 7         18 push @inswords, $opt;
527             }
528 16         25 $j++;
529             }
530              
531             #use DD; print "D:inswords: "; dd \@inswords;
532              
533 11 50       33 my $prefix = $encounter_equal_sign ? '' :
534             substr($word, 0, length($word)-length($rest));
535 11         29 splice @words, $i+1, 0, @inswords;
536 11         33 for (0..@inswords) {
537 24         67 $expects[$i+$_]{prefix} = $prefix;
538 24         74 $expects[$i+$_]{word} = $rest;
539             }
540 11         21 $cword += @inswords;
541 11         18 $i += @inswords;
542 11         22 $word = $words[$i];
543 11   50     55 $expects[$i]{short_only} //= 1;
544             } # SHORT_OPTS
545              
546             # split --foo=val -> --foo, =, val
547             SPLIT_EQUAL:
548             {
549 41 100       56 if ($word =~ /\A(--?[^=]+)(=)(.*)/) {
  41         113  
550 4         20 splice @words, $i, 1, $1, $2, $3;
551 4         11 $word = $1;
552 4 50       11 $cword += 2 if $cword >= $i;
553             }
554             }
555              
556 41         65 my $opt = $word;
557 41         92 my $matching_opts = _matching_opts($opt, \%opts);
558              
559 41 100       118 if (keys(%$matching_opts) == 1) {
560 28         68 my $opthash = $matching_opts->{ (keys %$matching_opts)[0] };
561 28         59 $opt = $opthash->{name};
562 28         62 $expects[$i]{optname} = $opt;
563 28   100     102 my $nth = $seen_opts{$opt} // 0;
564 28         54 $expects[$i]{nth} = $nth;
565 28         76 _mark_seen(\%seen_opts, $opt, \%opts);
566              
567 28         61 my $min_vals = $opthash->{parsed}{min_vals};
568 28         47 my $max_vals = $opthash->{parsed}{max_vals};
569             #say "D:min_vals=$min_vals, max_vals=$max_vals";
570              
571             # detect = after --opt
572 28 100 100     97 if ($i+1 < @words && $words[$i+1] eq '=') {
573 3         5 $i++;
574 3         14 $expects[$i] = {separator=>1, optval=>$opt, word=>'', nth=>$nth};
575             # force expecting a value due to =
576 3         7 $min_vals = 1;
577 3 100       8 $max_vals = $min_vals if $max_vals < $min_vals;
578             }
579              
580 28         75 for (1 .. $min_vals) {
581 16         23 $i++;
582 16 100       66 last WORD if $i >= @words;
583 13         34 $expects[$i]{optval} = $opt;
584 13         21 $expects[$i]{nth} = $nth;
585 13         19 push @{ $parsed_opts{$opt} }, $words[$i];
  13         45  
586             }
587 25         85 for (1 .. $max_vals-$min_vals) {
588 1 50       5 last if $i+$_ >= @words;
589 1 50       5 last if $words[$i+$_] =~ /\A-/; # a new option
590 1         3 $expects[$i+$_]{optval} = $opt; # but can also be optname
591 1         3 $expects[$i]{nth} = $nth;
592 1         2 push @{ $parsed_opts{$opt} }, $words[$i+$_];
  1         5  
593             }
594             } else {
595             # an unknown or still ambiguous option, assume it doesn't
596             # require argument, unless it's --opt= or --opt=foo
597 13         22 $opt = undef;
598 13         31 $expects[$i]{optname} = $opt;
599 13         83 my $possible_optnames = [sort keys %$matching_opts];
600 13         34 $expects[$i]{possible_optnames} = $possible_optnames;
601              
602             # detect = after --opt
603 13 100 100     75 if ($i+1 < @words && $words[$i+1] eq '=') {
604 1         2 $i++;
605 1         5 $expects[$i] = {separator=>1, optval=>undef, possible_optnames=>$possible_optnames, word=>''};
606 1 50       5 if ($i+1 < @words) {
607 1         2 $i++;
608 1         2 $expects[$i]{optval} = $opt;
609 1         4 $expects[$i]{possible_optnames} = $possible_optnames;
610             }
611             }
612             }
613             } else {
614 7         17 $expects[$i]{optname} = '';
615 7         14 $expects[$i]{arg} = 1;
616 7         16 $expects[$i]{argpos} = $argpos++;
617             }
618             }
619              
620 35         60 my $exp = $expects[$cword];
621 35   100     115 my $word = $exp->{word} // $words[$cword];
622              
623             #use DD; say "D:opts: "; dd \%opts;
624             #use DD; print "D:words: "; dd \@words;
625             #say "D:cword: $cword";
626             #use DD; print "D:expects: "; dd \@expects;
627             #use DD; print "D:seen_opts: "; dd \%seen_opts;
628             #use DD; print "D:parsed_opts: "; dd \%parsed_opts;
629             #use DD; print "D:exp: "; dd $exp;
630             #use DD; say "D:word:<$word>";
631              
632 35         51 my @answers;
633              
634             # complete option names
635             {
636 35 100       96 last if $word =~ /\A[^-]/;
637 33 100       72 last unless exists $exp->{optname};
638             last if defined($exp->{do_complete_optname}) &&
639 26 50 33     79 !$exp->{do_complete_optname};
640 26 100       56 if ($exp->{comp_result}) {
641 2         5 push @answers, $exp->{comp_result};
642 2         4 last;
643             }
644             #say "D:completing option names";
645 24         37 my $opt = $exp->{optname};
646 24         56 my @o;
647             my @osumms;
648 24         0 my $o_has_summaries;
649 24         47 for my $optname (@optnames) {
650 247         318 my $repeatable = 0;
651 247 100 100     566 next if $exp->{short_only} && $optname =~ /\A--/;
652 197 100       340 if ($seen_opts{$optname}) {
653 34         48 my $opthash = $opts{$optname};
654 34         54 my $parsed = $opthash->{parsed};
655 34         47 my $dest = $opthash->{dest};
656 34 100 66     123 if (ref $dest eq 'ARRAY') {
    100          
657 1         2 $repeatable = 1;
658             } elsif ($parsed->{desttype} || $parsed->{is_inc}) {
659 3         7 $repeatable = 1;
660             }
661             }
662             # skip options that have been specified and not repeatable
663             #use DD; dd {'$_'=>$_, seen=>$seen_opts{$_}, repeatable=>$repeatable, opt=>$opt};
664             next if $seen_opts{$optname} && !$repeatable && (
665             # long option has been specified
666             (!$opt || $opt ne $optname) ||
667             # short option (in a bundle) has been specified
668             (defined($exp->{prefix}) &&
669 197 100 100     484 index($exp->{prefix}, substr($opt, 1, 1)) >= 0));
      66        
      100        
670 169 100       278 if (defined $exp->{prefix}) {
671 18         31 my $o = $optname; $o =~ s/\A-//;
  18         59  
672 18         47 push @o, "$exp->{prefix}$o";
673             } else {
674 151         252 push @o, $optname;
675             }
676 169   50     278 my $summ = $code_get_summary->($optname) // '';
677 169 50       270 if (length $summ) {
678 0         0 $o_has_summaries = 1;
679 0         0 push @osumms, $summ;
680             } else {
681 169         338 push @osumms, '';
682             }
683             }
684             #use DD; dd \@o;
685             #use DD; dd \@osumms;
686 24         95 my $compres = Complete::Util::complete_array_elem(
687             array => \@o, word => $word,
688             (summaries => \@osumms) x !!$o_has_summaries,
689             );
690 24 50       3992 log_trace('[compgl] adding result from option names, '.
691             'matching options=%s', $compres) if $COMPLETE_GETOPT_LONG_TRACE;
692 24         65 push @answers, $compres;
693 24 100 100     107 if (!exists($exp->{optval}) && !exists($exp->{arg})) {
694 17         53 $fres = {words=>$compres, esc_mode=>'option'};
695 17         279 goto RETURN_RES;
696             }
697             }
698              
699             # complete option value
700             {
701 35 100       50 last unless exists($exp->{optval});
  18         52  
702             #say "D:completing option value";
703 10         37 my $opt = $exp->{optval};
704 10 100       12 my $opthash; $opthash = $opts{$opt} if $opt;
  10         27  
705             my %compargs = (
706             %$extras,
707             type=>'optval', words=>\@words, cword=>$args{cword},
708             word=>$word, opt=>($opt // $exp->{possible_optnames}), ospec=>$opthash->{ospec},
709 10   66     107 argpos=>undef, nth=>$exp->{nth}, seen_opts=>\%seen_opts,
710             parsed_opts=>\%parsed_opts,
711             );
712 10         20 my $compres;
713 10 50       22 if ($comp) {
714 10 50       21 log_trace("[compgl] invoking routine supplied from 'completion' argument to complete option value, option=<%s>", $opt) if $COMPLETE_GETOPT_LONG_TRACE;
715 10         106 $compres = $comp->(%compargs);
716             Complete::Util::modify_answer(answer=>$compres, prefix=>$exp->{prefix})
717 10 100       307 if defined $exp->{prefix};
718 10 50       66 log_trace('[compgl] adding result from routine: %s', $compres) if $COMPLETE_GETOPT_LONG_TRACE;
719             }
720 10 50 33     39 if (!$compres || !$comp) {
721 0         0 $compres = _default_completion(%compargs);
722             Complete::Util::modify_answer(answer=>$compres, prefix=>$exp->{prefix})
723 0 0       0 if defined $exp->{prefix};
724 0 0       0 log_trace('[compgl] adding result from default '.
725             'completion routine') if $COMPLETE_GETOPT_LONG_TRACE;
726             }
727 10         36 push @answers, $compres;
728             }
729              
730             # complete argument
731             {
732 18 100       31 last unless exists($exp->{arg});
  18         28  
  18         39  
733             my %compargs = (
734             %$extras,
735             type=>'arg', words=>\@words, cword=>$args{cword},
736             word=>$word, opt=>undef, ospec=>undef,
737 7         72 argpos=>$exp->{argpos}, seen_opts=>\%seen_opts,
738             parsed_opts=>\%parsed_opts,
739             );
740 7 50       21 log_trace('[compgl] invoking \'completion\' routine '.
741             'to complete argument') if $COMPLETE_GETOPT_LONG_TRACE;
742 7 100       19 my $compres; $compres = $comp->(%compargs) if $comp;
  7         34  
743 7 100       35 if (!defined $compres) {
744 1         6 $compres = _default_completion(%compargs);
745 1 50       5 log_trace('[compgl] adding result from default '.
746             'completion routine: %s', $compres) if $COMPLETE_GETOPT_LONG_TRACE;
747             }
748 7         25 push @answers, $compres;
749             }
750              
751 18 50       43 log_trace("[compgl] combining result from %d source(s)", scalar @answers) if $COMPLETE_GETOPT_LONG_TRACE;
752 18   50     52 $fres = Complete::Util::combine_answers(@answers) // [];
753              
754 35 50       1164 RETURN_RES:
755             log_trace("[compgl] leaving %s(), result=%s", $fname, $fres) if $COMPLETE_GETOPT_LONG_TRACE;
756 35         968 $fres;
757             }
758              
759             1;
760             # ABSTRACT: Complete command-line argument using Getopt::Long specification
761              
762             __END__