File Coverage

blib/lib/Perinci/Sub/Complete.pm
Criterion Covered Total %
statement 313 494 63.3
branch 97 202 48.0
condition 52 83 62.6
subroutine 13 13 100.0
pod 4 4 100.0
total 479 796 60.1


line stmt bran cond sub pod time code
1              
2             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
3             our $DATE = '2021-05-07'; # DATE
4             our $DIST = 'Perinci-Sub-Complete'; # DIST
5             our $VERSION = '0.944'; # VERSION
6              
7             use 5.010001;
8 1     1   26667 use strict;
  1         9  
9 1     1   4 use warnings;
  1         2  
  1         16  
10 1     1   3 use Log::ger;
  1         2  
  1         18  
11 1     1   4  
  1         2  
  1         4  
12             use Complete::Common qw(:all);
13 1     1   558 use Complete::Sah;
  1         299  
  1         113  
14 1     1   407 use Complete::Util qw(hashify_answer complete_array_elem complete_hash_key combine_answers modify_answer);
  1         6846  
  1         45  
15 1     1   5 use Perinci::Sub::Util qw(gen_modified_sub);
  1         2  
  1         46  
16 1     1   5  
  1         2  
  1         3946  
17             require Exporter;
18             our @ISA = qw(Exporter);
19             our @EXPORT_OK = qw(
20             complete_from_schema
21             complete_arg_val
22             complete_arg_index
23             complete_arg_elem
24             complete_cli_arg
25             );
26             our %SPEC;
27              
28             $SPEC{':package'} = {
29             v => 1.1,
30             summary => 'Complete command-line argument using Rinci metadata',
31             };
32              
33             my %common_args_riap = (
34             riap_client => {
35             summary => 'Optional, to perform complete_arg_val to the server',
36             schema => 'obj*',
37             description => <<'_',
38              
39             When the argument spec in the Rinci metadata contains `completion` key, this
40             means there is custom completion code for that argument. However, if retrieved
41             from a remote server, sometimes the `completion` key no longer contains the code
42             (it has been cleansed into a string). Moreover, the completion code needs to run
43             on the server.
44              
45             If supplied this argument and te `riap_server_url` argument, the function will
46             try to request to the server (via Riap request `complete_arg_val`). Otherwise,
47             the function will just give up/decline completing.
48              
49             _
50             },
51             riap_server_url => {
52             summary => 'Optional, to perform complete_arg_val to the server',
53             schema => 'str*',
54             description => <<'_',
55              
56             See the `riap_client` argument.
57              
58             _
59             },
60             riap_uri => {
61             summary => 'Optional, to perform complete_arg_val to the server',
62             schema => 'str*',
63             description => <<'_',
64              
65             See the `riap_client` argument.
66              
67             _
68             },
69             );
70              
71             # backward compatibility, will be removed in the future
72             *complete_from_schema = \&Complete::Sah::complete_from_schema;
73             $SPEC{complete_from_schema} = $Complete::Sah::SPEC{complete_from_schema};
74              
75             $SPEC{complete_arg_val} = {
76             v => 1.1,
77             summary => 'Given argument name and function metadata, complete value',
78             description => <<'_',
79              
80             Will attempt to complete using the completion routine specified in the argument
81             specification (the `completion` property, or in the case of `complete_arg_elem`
82             function, the `element_completion` property), or if that is not specified, from
83             argument's schema using `complete_from_schema`.
84              
85             Completion routine will get `%args`, with the following keys:
86              
87             * `word` (str, the word to be completed)
88             * `arg` (str, the argument name which value is currently being completed)
89             * `index (int, only for the `complete_arg_elem` function, the index in the
90             argument array that is currently being completed, starts from 0)
91             * `args` (hash, the argument hash to the function, so far)
92              
93             as well as extra keys from `extras` (but these won't overwrite the above
94             standard keys).
95              
96             Completion routine should return a completion answer structure (described in
97             <pm:Complete>) which is either a hash or an array. The simplest form of answer
98             is just to return an array of strings. Completion routine can also return undef
99             to express declination.
100              
101             _
102             args => {
103             meta => {
104             summary => 'Rinci function metadata, must be normalized',
105             schema => 'hash*',
106             req => 1,
107             },
108             arg => {
109             summary => 'Argument name',
110             schema => 'str*',
111             req => 1,
112             },
113             word => {
114             summary => 'Word to be completed',
115             schema => ['str*', default => ''],
116             },
117             args => {
118             summary => 'Collected arguments so far, '.
119             'will be passed to completion routines',
120             schema => 'hash',
121             },
122             extras => {
123             summary => 'Add extra arguments to completion routine',
124             schema => 'hash',
125             description => <<'_',
126              
127             The keys from this `extras` hash will be merged into the final `%args` passed to
128             completion routines. Note that standard keys like `word`, `cword`, and so on as
129             described in the function description will not be overwritten by this.
130              
131             _
132             },
133              
134             %common_args_riap,
135             },
136             result_naked => 1,
137             result => {
138             schema => 'array', # XXX of => str*
139             },
140             };
141             my %args = @_;
142              
143 7     7 1 29 log_trace("[comp][periscomp] entering complete_arg_val, arg=<%s>", $args{arg});
144             my $fres;
145 7         20  
146 7         16 my $extras = $args{extras} // {};
147              
148 7   50     15 my $meta = $args{meta} or do {
149             log_trace("[comp][periscomp] meta is not supplied, declining");
150 7 50       16 goto RETURN_RES;
151 0         0 };
152 0         0 my $arg = $args{arg} or do {
153             log_trace("[comp][periscomp] arg is not supplied, declining");
154 7 50       17 goto RETURN_RES;
155 0         0 };
156 0         0 my $word = $args{word} // '';
157              
158 7   50     17 # XXX reject if meta's v is not 1.1
159              
160             my $args_prop = $meta->{args} // {};
161             my $arg_spec = $args_prop->{$arg} or do {
162 7   50     14 log_trace("[comp][periscomp] arg '$arg' is not specified in meta, declining");
163 7 50       16 goto RETURN_RES;
164 0         0 };
165 0         0  
166             my $static;
167             eval { # completion sub can die, etc.
168 7         9  
169 7         13 my $comp;
170             GET_COMP_ROUTINE:
171 7         9 {
172             $comp = $arg_spec->{completion};
173             if ($comp) {
174 7         8 log_trace("[comp][periscomp] using arg completion routine from arg spec's 'completion' property");
  7         11  
175 7 100       15 last GET_COMP_ROUTINE;
176 2         7 }
177 2         6 my $xcomp = $arg_spec->{'x.completion'};
178             if ($xcomp) {
179 5         7 if (ref($xcomp) eq 'CODE') {
180 5 50       9 $comp = $xcomp;
181 0 0       0 } else {
182 0         0 my ($submod, $xcargs);
183             if (ref($xcomp) eq 'ARRAY') {
184 0         0 $submod = $xcomp->[0];
185 0 0       0 $xcargs = $xcomp->[1];
186 0         0 } else {
187 0         0 $submod = $xcomp;
188             $xcargs = {};
189 0         0 }
190 0         0 my $mod = "Perinci::Sub::XCompletion::$submod";
191             require Module::Installed::Tiny;
192 0         0 if (Module::Installed::Tiny::module_installed($mod)) {
193 0         0 log_trace("[comp][periscomp] loading module %s ...", $mod);
194 0 0       0 my $mod_pm = $mod; $mod_pm =~ s!::!/!g; $mod_pm .= ".pm";
195 0         0 require $mod_pm;
196 0         0 my $fref = \&{"$mod\::gen_completion"};
  0         0  
  0         0  
197 0         0 log_trace("[comp][periscomp] invoking %s\::gen_completion(%s) ...", $mod, $xcargs);
198 0         0 $comp = $fref->(%$xcargs);
  0         0  
199 0         0 } else {
200 0         0 log_trace("[comp][periscomp] module %s is not installed, skipped", $mod);
201             }
202 0         0 }
203             if ($comp) {
204             log_trace("[comp][periscomp] using arg completion routine from arg spec's 'x.completion' attribute");
205 0 0       0 last GET_COMP_ROUTINE;
206 0         0 }
207 0         0 }
208             my $ent = $arg_spec->{'x.schema.entity'};
209             if ($ent) {
210 5         8 require Module::Installed::Tiny;
211 5 50       9 my $mod = "Perinci::Sub::ArgEntity::$ent";
212 0         0 if (Module::Installed::Tiny::module_installed($mod)) {
213 0         0 log_trace("[comp][periscomp] loading module %s ...", $mod);
214 0 0       0 my $mod_pm = $mod; $mod_pm =~ s!::!/!g; $mod_pm .= ".pm";
215 0         0 require $mod_pm;
216 0         0 if (defined &{"$mod\::complete_arg_val"}) {
  0         0  
  0         0  
217 0         0 log_trace("[comp][periscomp] invoking complete_arg_val() from %s ...", $mod);
218 0 0       0 $comp = \&{"$mod\::complete_arg_val"};
  0         0  
219 0         0 last GET_COMP_ROUTINE;
220 0         0 } else {
  0         0  
221 0         0 log_trace("[comp][periscomp] module %s doesn't define complete_arg_val(), skipped", $mod);
222             }
223 0         0 } else {
224             log_trace("[comp][periscomp] module %s not installed, skipped", $mod);
225             }
226 0         0 }
227             } # GET_COMP_ROUTINE
228              
229             if ($comp) {
230             if (ref($comp) eq 'CODE') {
231 7 100       15 my %cargs = (
232 2 50       8 %$extras,
    0          
233             word=>$word, arg=>$arg, args=>$args{args},
234             );
235             log_trace("[comp][periscomp] invoking arg completion routine with args (%s)", \%cargs);
236 2         14 $fres = $comp->(%cargs);
237 2         7 return; # from eval
238 2         11 } elsif (ref($comp) eq 'ARRAY') {
239 2         1791 # this is deprecated but will be supported for some time
240             log_trace("[comp][periscomp] using array specified in arg completion routine: %s", $comp);
241             $fres = complete_array_elem(array=>$comp, word=>$word);
242 0         0 $static++;
243 0         0 return; # from eval
244 0         0 }
245 0         0  
246             log_trace("[comp][periscomp] arg spec's 'completion' property is not a coderef or arrayref");
247             if ($args{riap_client} && $args{riap_server_url}) {
248 0         0 log_trace("[comp][periscomp] trying to perform complete_arg_val request to Riap server");
249 0 0 0     0 my $res = $args{riap_client}->request(
250 0         0 complete_arg_val => $args{riap_server_url},
251             {(uri=>$args{riap_uri}) x !!defined($args{riap_uri}),
252             arg=>$arg, word=>$word},
253 0         0 );
254             if ($res->[0] != 200) {
255             log_trace("[comp][periscomp] Riap request failed (%s), declining", $res);
256 0 0       0 return; # from eval
257 0         0 }
258 0         0 $fres = $res->[2];
259             return; # from eval
260 0         0 }
261 0         0  
262             log_trace("[comp][periscomp] declining");
263             return; # from eval
264 0         0 }
265 0         0  
266             my $fres_from_arg_examples;
267             COMPLETE_FROM_ARG_EXAMPLES:
268 5         6 {
269             my $egs = $arg_spec->{examples};
270             unless ($egs) {
271 5         7 log_trace("[comp][periscomp] arg spec does not specify examples");
  5         7  
272 5 100       20 last COMPLETE_FROM_ARG_EXAMPLES;
273 4         11 }
274 4         12 my @array;
275             my @summaries;
276 1         2 for my $eg (@$egs) {
277             if (ref $eg eq 'HASH') {
278 1         3 next unless defined $eg->{value};
279 2 100       8 next if ref $eg->{value};
280 1 50       3 push @array, $eg->{value};
281 1 50       4 push @summaries, $eg->{summary};
282 1         3 } else {
283 1         10 next unless defined $eg;
284             next if ref $eg;
285 1 50       38 push @array, $eg;
286 1 50       4 push @summaries, undef;
287 1         3 }
288 1         3 }
289             $fres_from_arg_examples = complete_array_elem(
290             word=>$word, array=>\@array, summaries=>\@summaries);
291 1         7 $static //= 1;
292             } # COMPLETE_FROM_ARG_EXAMPLES
293 1   50     81  
294             my $fres_from_schema;
295             COMPLETE_FROM_SCHEMA:
296 5         6 {
297             my $sch = $arg_spec->{schema};
298             unless ($sch) {
299 5         6 log_trace("[comp][periscomp] arg spec does not specify schema");
  5         9  
300 5 50       12 last COMPLETE_FROM_SCHEMA;
301 0         0 }
302 0         0 # XXX normalize schema if not normalized
303             $fres_from_schema = complete_from_schema(
304             arg=>$arg, extras=>$extras, schema=>$sch, word=>$word,
305 5         13 );
306             $static //= 1;
307             } # COMPLETE_FROM_SCHEMA
308 5   100     2938  
309             $fres = combine_answers(grep {defined} (
310             $fres_from_arg_examples,
311 5         9 $fres_from_schema,
  10         26  
312             ));
313             };
314             log_debug("[comp][periscomp] completion died: $@") if $@;
315             unless ($fres) {
316 7 50       43 log_trace("[comp][periscomp] no completion from metadata possible, declining");
317 7 50       15 goto RETURN_RES;
318 0         0 }
319 0         0  
320             $fres = hashify_answer($fres);
321             $fres->{static} //= $static && $word eq '' ? 1:0;
322 7         17 RETURN_RES:
323 7 100 66     70 log_trace("[comp][periscomp] leaving complete_arg_val, result=%s", $fres);
      100        
324 7         18 $fres;
325             }
326 7         24  
327             gen_modified_sub(
328             output_name => 'complete_arg_elem',
329             install_sub => 0,
330             base_name => 'complete_arg_val',
331             summary => 'Given argument name and function metadata, '.
332             'complete array element',
333             add_args => {
334             index => {
335             summary => 'Index of element to complete',
336             schema => ['str*'],
337             },
338             },
339             );
340             require Data::Sah::Normalize;
341              
342             my %args = @_;
343 3     3 1 21  
344             my $fres;
345 3         17  
346             log_trace("[comp][periscomp] entering complete_arg_elem, arg=<%s>, index=<%d>",
347 3         5 $args{arg}, $args{index});
348              
349             my $extras = $args{extras} // {};
350 3         13  
351             my $ourextras = {arg=>$args{arg}, args=>$args{args}};
352 3   50     13  
353             my $meta = $args{meta} or do {
354 3         11 log_trace("[comp][periscomp] meta is not supplied, declining");
355             goto RETURN_RES;
356 3 50       10 };
357 0         0 my $arg = $args{arg} or do {
358 0         0 log_trace("[comp][periscomp] arg is not supplied, declining");
359             goto RETURN_RES;
360 3 50       9 };
361 0         0 defined(my $index = $args{index}) or do {
362 0         0 log_trace("[comp][periscomp] index is not supplied, declining");
363             goto RETURN_RES;
364 3 50       9 };
365 0         0 my $word = $args{word} // '';
366 0         0  
367             # XXX reject if meta's v is not 1.1
368 3   50     9  
369             my $args_prop = $meta->{args} // {};
370             my $arg_spec = $args_prop->{$arg} or do {
371             log_trace("[comp][periscomp] arg '$arg' is not specified in meta, declining");
372 3   50     9 goto RETURN_RES;
373 3 50       8 };
374 0         0  
375 0         0 my $static;
376             eval { # completion sub can die, etc.
377              
378 3         6 my $elcomp;
379 3         7 GET_ELCOMP_ROUTINE:
380             {
381 3         3 $elcomp = $arg_spec->{element_completion};
382             if ($elcomp) {
383             log_trace("[comp][periscomp] using arg element completion routine from 'element_completion' property");
384 3         5 last GET_ELCOMP_ROUTINE;
  3         18  
385 3 100       10 }
386 2         6 my $xelcomp = $arg_spec->{'x.element_completion'};
387 2         6 if ($xelcomp) {
388             if (ref($xelcomp) eq 'CODE') {
389 1         3 $elcomp = $xelcomp;
390 1 50       27 } else {
391 0 0       0 my ($submod, $xcargs);
392 0         0 if (ref($xelcomp) eq 'ARRAY') {
393             $submod = $xelcomp->[0];
394 0         0 $xcargs = $xelcomp->[1];
395 0 0       0 } else {
396 0         0 $submod = $xelcomp;
397 0         0 $xcargs = {};
398             }
399 0         0 my $mod = "Perinci::Sub::XCompletion::$submod";
400 0         0 require Module::Installed::Tiny;
401             if (Module::Installed::Tiny::module_installed($mod)) {
402 0         0 log_trace("[comp][periscomp] loading module %s ...", $mod);
403 0         0 my $mod_pm = $mod; $mod_pm =~ s!::!/!g; $mod_pm .= ".pm";
404 0 0       0 require $mod_pm;
405 0         0 my $fref = \&{"$mod\::gen_completion"};
406 0         0 log_trace("[comp][periscomp] invoking %s\::gen_completion(%s) ...", $mod, $xcargs);
  0         0  
  0         0  
407 0         0 $elcomp = $fref->(%$xcargs);
408 0         0 } else {
  0         0  
409 0         0 log_trace("[comp][periscomp] module %s is not installed, skipped", $mod);
410 0         0 }
411             }
412 0         0 if ($elcomp) {
413             log_trace("[comp][periscomp] using arg element completion routine from 'x.element_completion' attribute");
414             last GET_ELCOMP_ROUTINE;
415 0 0       0 }
416 0         0 }
417 0         0 my $ent = $arg_spec->{'x.schema.element_entity'};
418             if ($ent) {
419             require Module::Installed::Tiny;
420 1         3 my $mod = "Perinci::Sub::ArgEntity::$ent";
421 1 50       3 if (Module::Installed::Tiny::module_installed($mod)) {
422 0         0 log_trace("[comp][periscomp] loading module %s ...", $mod);
423 0         0 my $mod_pm = $mod; $mod_pm =~ s!::!/!g; $mod_pm .= ".pm";
424 0 0       0 require $mod_pm;
425 0         0 if (defined &{"$mod\::complete_arg_val"}) {
426 0         0 log_trace("[comp][periscomp] invoking complete_arg_val() from %s ...", $mod);
  0         0  
  0         0  
427 0         0 $elcomp = \&{"$mod\::complete_arg_val"};
428 0 0       0 last GET_ELCOMP_ROUTINE;
  0         0  
429 0         0 } else {
430 0         0 log_trace("[comp][periscomp] module %s doesn't defined complete_arg_val(), skipped", $mod);
  0         0  
431 0         0 }
432             } else {
433 0         0 log_trace("[comp][periscomp] module %s is not installed, skipped", $mod);
434             }
435             }
436 0         0 } # GET_ELCOMP_ROUTINE
437              
438             $ourextras->{index} = $index;
439             if ($elcomp) {
440             if (ref($elcomp) eq 'CODE') {
441 3         7 my %cargs = (
442 3 100       9 %$extras,
443 2 50       7 %$ourextras,
    0          
444 2         14 word=>$word,
445             );
446             log_trace("[comp][periscomp] invoking arg element completion routine with args (%s)", \%cargs);
447             $fres = $elcomp->(%cargs);
448             return; # from eval
449 2         8 } elsif (ref($elcomp) eq 'ARRAY') {
450 2         13 log_trace("[comp][periscomp] using array specified in arg element completion routine: %s", $elcomp);
451 2         1001 $fres = complete_array_elem(array=>$elcomp, word=>$word);
452             $static = $word eq '';
453 0         0 }
454 0         0  
455 0         0 log_trace("[comp][periscomp] arg spec's 'element_completion' property is not a coderef or ".
456             "arrayref");
457             if ($args{riap_client} && $args{riap_server_url}) {
458 0         0 log_trace("[comp][periscomp] trying to perform complete_arg_elem request to Riap server");
459             my $res = $args{riap_client}->request(
460 0 0 0     0 complete_arg_elem => $args{riap_server_url},
461 0         0 {(uri=>$args{riap_uri}) x !!defined($args{riap_uri}),
462             arg=>$arg, args=>$args{args}, word=>$word,
463             index=>$index},
464             );
465 0         0 if ($res->[0] != 200) {
466             log_trace("[comp][periscomp] Riap request failed (%s), declining", $res);
467             return; # from eval
468 0 0       0 }
469 0         0 $fres = $res->[2];
470 0         0 return; # from eval
471             }
472 0         0  
473 0         0 log_trace("[comp][periscomp] declining");
474             return; # from eval
475             } # if ($elcomp)
476 0         0  
477 0         0 my $sch = $arg_spec->{schema};
478             unless ($sch) {
479             log_trace("[comp][periscomp] arg spec does not specify schema, declining");
480 1         3 return; # from eval
481 1 50       4 };
482 0         0  
483 0         0 my $nsch = Data::Sah::Normalize::normalize_schema($sch);
484              
485             my ($type, $cs) = @$nsch;
486 1         4 if ($type ne 'array') {
487             log_trace("[comp][periscomp] can't complete element for non-array");
488 1         61 return; # from eval
489 1 50       4 }
490 0         0  
491 0         0 unless ($cs->{of}) {
492             log_trace("[comp][periscomp] schema does not specify 'of' clause, declining");
493             return; # from eval
494 1 50       4 }
495 0         0  
496 0         0 # normalize subschema because normalize_schema (as of 0.01) currently
497             # does not do it yet
498             my $elsch = Data::Sah::Normalize::normalize_schema($cs->{of});
499              
500             $fres = complete_from_schema(
501 1         3 schema=>$elsch, word=>$word,
502             schema_is_normalized=>1,
503 1         50 );
504             };
505             log_debug("[comp][periscomp] completion died: $@") if $@;
506             unless ($fres) {
507             log_trace("[comp][periscomp] no completion from metadata possible, declining");
508 3 50       251 goto RETURN_RES;
509 3 50       11 }
510 0         0  
511 0         0 $fres = hashify_answer($fres);
512             $fres->{static} //= $static && $word eq '' ? 1:0;
513             RETURN_RES:
514 3         10 log_trace("[comp][periscomp] leaving complete_arg_elem, result=%s", $fres);
515 3 50 33     42 $fres;
      66        
516 3         9 }
517              
518 3         13 $SPEC{complete_arg_index} = {
519             v => 1.1,
520             summary => 'Given argument name and function metadata, complete arg element index',
521             description => <<'_',
522              
523             This is only relevant for arguments which have `index_completion` property set
524             (currently only `hash` type arguments). When that property is not set, will
525             simply return undef.
526              
527             Completion routine will get `%args`, with the following keys:
528              
529             * `word` (str, the word to be completed)
530             * `arg` (str, the argument name which value is currently being completed)
531             * `args` (hash, the argument hash to the function, so far)
532              
533             as well as extra keys from `extras` (but these won't overwrite the above
534             standard keys).
535              
536             Completion routine should return a completion answer structure (described in
537             <pm:Complete>) which is either a hash or an array. The simplest form of answer
538             is just to return an array of strings. Completion routine can also return undef
539             to express declination.
540              
541             _
542             args => {
543             meta => {
544             summary => 'Rinci function metadata, must be normalized',
545             schema => 'hash*',
546             req => 1,
547             },
548             arg => {
549             summary => 'Argument name',
550             schema => 'str*',
551             req => 1,
552             },
553             word => {
554             summary => 'Word to be completed',
555             schema => ['str*', default => ''],
556             },
557             args => {
558             summary => 'Collected arguments so far, '.
559             'will be passed to completion routines',
560             schema => 'hash',
561             },
562             extras => {
563             summary => 'Add extra arguments to completion routine',
564             schema => 'hash',
565             description => <<'_',
566              
567             The keys from this `extras` hash will be merged into the final `%args` passed to
568             completion routines. Note that standard keys like `word`, `cword`, and so on as
569             described in the function description will not be overwritten by this.
570              
571             _
572             },
573              
574             %common_args_riap,
575             },
576             result_naked => 1,
577             result => {
578             schema => 'array', # XXX of => str*
579             },
580             };
581             require Data::Sah::Normalize;
582              
583             my %args = @_;
584              
585 3     3 1 17 my $fres;
586              
587 3         13 log_trace("[comp][periscomp] entering complete_arg_index, arg=<%s>",
588             $args{arg});
589 3         6  
590             my $extras = $args{extras} // {};
591              
592 3         9 my $ourextras = {arg=>$args{arg}, args=>$args{args}};
593              
594 3   50     10 my $meta = $args{meta} or do {
595             log_trace("[comp][periscomp] meta is not supplied, declining");
596 3         9 goto RETURN_RES;
597             };
598 3 50       8 my $arg = $args{arg} or do {
599 0         0 log_trace("[comp][periscomp] arg is not supplied, declining");
600 0         0 goto RETURN_RES;
601             };
602 3 50       8 my $word = $args{word} // '';
603 0         0  
604 0         0 # XXX reject if meta's v is not 1.1
605              
606 3   50     8 my $args_prop = $meta->{args} // {};
607             my $arg_spec = $args_prop->{$arg} or do {
608             log_trace("[comp][periscomp] arg '$arg' is not specified in meta, declining");
609             goto RETURN_RES;
610 3   50     6 };
611 3 50       6  
612 0         0 my $static;
613 0         0 eval { # completion sub can die, etc.
614              
615             my $idxcomp;
616 3         4 GET_IDXCOMP_ROUTINE:
617 3         6 {
618             $idxcomp = $arg_spec->{index_completion};
619 3         4 if ($idxcomp) {
620             log_trace("[comp][periscomp] using arg element index completion routine from 'index_completion' property");
621             last GET_IDXCOMP_ROUTINE;
622 3         3 }
  3         5  
623 3 100       6 } # GET_IDXCOMP_ROUTINE
624 1         5  
625 1         3 if ($idxcomp) {
626             if (ref($idxcomp) eq 'CODE') {
627             my %cargs = (
628             %$extras,
629 3 100       7 %$ourextras,
630 1 50       7 word=>$word,
    50          
631 0         0 );
632             log_trace("[comp][periscomp] invoking arg element index completion routine with args (%s)", \%cargs);
633             $fres = $idxcomp->(%cargs);
634             return; # from eval
635             } elsif (ref($idxcomp) eq 'ARRAY') {
636 0         0 log_trace("[comp][periscomp] using array specified in arg element index completion routine: %s", $idxcomp);
637 0         0 $fres = complete_array_elem(array=>$idxcomp, word=>$word);
638 0         0 $static = $word eq '';
639             }
640 1         4  
641 1         5 log_trace("[comp][periscomp] arg spec's 'index_completion' property is not a coderef or ".
642 1         127 "arrayref");
643             if ($args{riap_client} && $args{riap_server_url}) {
644             log_trace("[comp][periscomp] trying to perform complete_arg_index request to Riap server");
645 1         3 my $res = $args{riap_client}->request(
646             complete_arg_index => $args{riap_server_url},
647 1 0 33     4 {(uri=>$args{riap_uri}) x !!defined($args{riap_uri}),
648 0         0 arg=>$arg, args=>$args{args}, word=>$word},
649             );
650             if ($res->[0] != 200) {
651             log_trace("[comp][periscomp] Riap request failed (%s), declining", $res);
652 0         0 return; # from eval
653             }
654 0 0       0 $fres = $res->[2];
655 0         0 return; # from eval
656 0         0 }
657              
658 0         0 log_trace("[comp][periscomp] declining");
659 0         0 return; # from eval
660             } # if ($idxcomp)
661              
662 1         3 my $sch = $arg_spec->{schema};
663 1         3 unless ($sch) {
664             log_trace("[comp][periscomp] arg spec does not specify schema, declining");
665             return; # from eval
666 2         5 };
667 2 50       4  
668 0         0 my $nsch = Data::Sah::Normalize::normalize_schema($sch);
669 0         0  
670             my ($type, $cs) = @$nsch;
671             if ($type ne 'hash') {
672 2         7 log_trace("[comp][periscomp] can't complete element index for non-hash");
673             return; # from eval
674 2         176 }
675 2 50       9  
676 0         0 # collect known keys from some clauses
677 0         0 my %keys;
678             if ($cs->{keys}) {
679             $keys{$_}++ for keys %{ $cs->{keys} };
680             }
681 2         3 if ($cs->{indices}) {
682 2 50       6 $keys{$_}++ for keys %{ $cs->{indices} };
683 2         3 }
  2         11  
684             if ($cs->{req_keys}) {
685 2 50       6 $keys{$_}++ for @{ $cs->{req_keys} };
686 0         0 }
  0         0  
687             if ($cs->{allowed_keys}) {
688 2 50       6 $keys{$_}++ for @{ $cs->{allowed_keys} };
689 0         0 }
  0         0  
690              
691 2 50       4 # exclude keys that have been specified in collected args
692 2         3 for (keys %{$args{args}{$arg} // {}}) {
  2         9  
693             delete $keys{$_};
694             }
695              
696 2   100     3 $fres = complete_hash_key(word => $word, hash => \%keys);
  2         12  
697 1         3  
698             }; # eval
699             log_debug("[comp][periscomp] completion died: $@") if $@;
700 2         8 unless ($fres) {
701             log_trace("[comp][periscomp] no index completion from metadata possible, declining");
702             goto RETURN_RES;
703 3 50       223 }
704 3 50       7  
705 0         0 $fres = hashify_answer($fres);
706 0         0 $fres->{static} //= $static && $word eq '' ? 1:0;
707             RETURN_RES:
708             log_trace("[comp][periscomp] leaving complete_arg_index, result=%s", $fres);
709 3         8 $fres;
710 3 100 66     43 }
      66        
711 3         9  
712             $SPEC{complete_cli_arg} = {
713 3         11 v => 1.1,
714             summary => 'Complete command-line argument using Rinci function metadata',
715             description => <<'_',
716              
717             This routine uses <pm:Perinci::Sub::GetArgs::Argv> to generate <pm:Getopt::Long>
718             specification from arguments list in Rinci function metadata and common options.
719             Then, it will use <pm:Complete::Getopt::Long> to complete option names, option
720             values, as well as arguments.
721              
722             _
723             args => {
724             meta => {
725             summary => 'Rinci function metadata',
726             schema => 'hash*',
727             req => 1,
728             },
729             words => {
730             summary => 'Command-line arguments',
731             schema => ['array*' => {of=>'str*'}],
732             req => 1,
733             },
734             cword => {
735             summary => 'On which argument cursor is located (zero-based)',
736             schema => 'int*',
737             req => 1,
738             },
739             completion => {
740             summary => 'Supply custom completion routine',
741             description => <<'_',
742              
743             If supplied, instead of the default completion routine, this code will be called
744             instead. Will receive all arguments that <pm:Complete::Getopt::Long> will pass,
745             and additionally:
746              
747             * `arg` (str, the name of function argument)
748             * `args` (hash, the function arguments formed so far)
749             * `index` (int, if completing argument element value)
750              
751             _
752             schema => 'code*',
753             },
754             per_arg_json => {
755             summary => 'Will be passed to Perinci::Sub::GetArgs::Argv',
756             schema => 'bool',
757             },
758             per_arg_yaml => {
759             summary => 'Will be passed to Perinci::Sub::GetArgs::Argv',
760             schema => 'bool',
761             },
762             common_opts => {
763             summary => 'Common options',
764             description => <<'_',
765              
766             A hash where the values are hashes containing these keys: `getopt` (Getopt::Long
767             option specification), `handler` (Getopt::Long handler). Will be passed to
768             `get_args_from_argv()`. Example:
769              
770             {
771             help => {
772             getopt => 'help|h|?',
773             handler => sub { ... },
774             summary => 'Display help and exit',
775             },
776             version => {
777             getopt => 'version|v',
778             handler => sub { ... },
779             summary => 'Display version and exit',
780             },
781             }
782              
783             _
784             schema => ['hash*'],
785             },
786             extras => {
787             summary => 'Add extra arguments to completion routine',
788             schema => 'hash',
789             description => <<'_',
790              
791             The keys from this `extras` hash will be merged into the final `%args` passed to
792             completion routines. Note that standard keys like `word`, `cword`, and so on as
793             described in the function description will not be overwritten by this.
794              
795             _
796             },
797             func_arg_starts_at => {
798             schema => 'int*',
799             default => 0,
800             description => <<'_',
801              
802             This is a (temporary?) workaround for <pm:Perinci::CmdLine>. In an application
803             with subcommands (e.g. `cmd --verbose subcmd arg0 arg1 ...`), then `words` will
804             still contain the subcommand name. Positional function arguments then start at 1
805             not 0. This option allows offsetting function arguments.
806              
807             _
808             },
809             %common_args_riap,
810             },
811             result_naked => 1,
812             result => {
813             schema => 'hash*',
814             description => <<'_',
815              
816             You can use `format_completion` function in <pm:Complete::Bash> module to format
817             the result of this function for bash.
818              
819             _
820             },
821             };
822             require Complete::Getopt::Long;
823             require Perinci::Sub::GetArgs::Argv;
824              
825             my %args = @_;
826             my $meta = $args{meta} or die "Please specify meta";
827 24     24 1 107899 my $words = $args{words} or die "Please specify words";
828 24         612 my $cword = $args{cword}; defined($cword) or die "Please specify cword";
829             my $copts = $args{common_opts} // {};
830 24         11249 my $comp = $args{completion};
831 24 50       82 my $extras = {
832 24 50       62 %{ $args{extras} // {} },
833 24 50       39 words => $args{words},
  24         53  
834 24   50     55 cword => $args{cword},
835 24         38 };
836              
837 24   100     129 my $fname = __PACKAGE__ . "::complete_cli_arg"; # XXX use __SUB__
838             my $fres;
839              
840 24         35 my $word = $words->[$cword];
841             my $args_prop = $meta->{args} // {};
842 24         53  
843 24         32 log_trace('[comp][periscomp] entering %s(), words=%s, cword=%d, word=<%s>',
844             $fname, $words, $cword, $word);
845 24         42  
846 24   50     56 my $ggls_res = Perinci::Sub::GetArgs::Argv::gen_getopt_long_spec_from_meta(
847             meta => $meta,
848 24         83 common_opts => $copts,
849             per_arg_json => $args{per_arg_json},
850             per_arg_yaml => $args{per_arg_yaml},
851             ignore_converted_code => 1,
852             );
853             die "Can't generate getopt spec from meta: $ggls_res->[0] - $ggls_res->[1]"
854             unless $ggls_res->[0] == 200;
855             $extras->{ggls_res} = $ggls_res;
856 24         142 my $gospec = $ggls_res->[2];
857             my $specmeta = $ggls_res->[3]{'func.specmeta'};
858 24 50       117736  
859             my $gares = Perinci::Sub::GetArgs::Argv::get_args_from_argv(
860 24         71 argv => [@$words],
861 24         34 meta => $meta,
862 24         49 strict => 0,
863             );
864 24         93  
865             my $copts_by_ospec = {};
866             for (keys %$copts) { $copts_by_ospec->{$copts->{$_}{getopt}}=$copts->{$_} }
867              
868             my $compgl_comp = sub {
869             log_trace("[comp][periscomp] entering completion routine (that we supply to Complete::Getopt::Long)");
870 24         152768 my %cargs = @_;
871 24         72 my $type = $cargs{type};
  24         75  
872             my $ospec = $cargs{ospec} // '';
873             my $word = $cargs{word};
874 21     21   23535  
875 21         123 my $fres;
876 21         46  
877 21   100     74 my %rargs = (
878 21         38 riap_server_url => $args{riap_server_url},
879             riap_uri => $args{riap_uri},
880 21         30 riap_client => $args{riap_client},
881             );
882              
883             $extras->{parsed_opts} = $cargs{parsed_opts};
884              
885             if (my $sm = $specmeta->{$ospec}) {
886 21         73 $cargs{type} = 'optval';
887             if ($sm->{arg}) {
888 21         40 log_trace("[comp][periscomp] completing option value for a known function argument, arg=<%s>, ospec=<%s>", $sm->{arg}, $ospec);
889             $cargs{arg} = $sm->{arg};
890 21 100       66 my $arg_spec = $args_prop->{$sm->{arg}} or goto RETURN_RES;
    50          
891 13         22 if ($comp) {
892 13 100       28 log_trace("[comp][periscomp] invoking routine supplied from 'completion' argument with args (%s)", \%cargs);
893 12         30 my $compres;
894 12         33 eval { $compres = $comp->(%cargs) };
895 12 50       34 log_debug("[comp][periscomp] completion died: $@") if $@;
896 12 100       22 log_trace("[comp][periscomp] result from 'completion' routine: %s", $compres);
897 1         4 if ($compres) {
898 1         2 $fres = $compres;
899 1         2 goto RETURN_RES;
  1         5  
900 1 50       5 }
901 1         3 }
902 1 50       3 if ($ospec =~ /\@$/) {
903 1         3 $fres = complete_arg_elem(
904 1         24 meta=>$meta, arg=>$sm->{arg}, args=>$gares->[2],
905             word=>$word, index=>$cargs{nth}, # XXX correct index
906             extras=>$extras, %rargs);
907 11 100       46 goto RETURN_RES;
    100          
908             } elsif ($ospec =~ /\%$/) {
909             if ($word =~ /(.*?)=(.*)/s) {
910             my $key = $1;
911 1         8 my $val = $2;
912 1         46 $fres = complete_arg_elem(
913             meta=>$meta, arg=>$sm->{arg}, args=>$gares->[2],
914 4 100       11 word=>$val, index=>$key,
915 1         4 extras=>$extras, %rargs);
916 1         2 modify_answer(answer=>$fres, prefix=>"$key=");
917             goto RETURN_RES;
918 1         5 } else {
919             $fres = complete_arg_index(
920             meta=>$meta, arg=>$sm->{arg}, args=>$gares->[2],
921 1         5 word=>$word, extras=>$extras, %rargs);
922 1         48 modify_answer(answer=>$fres, suffix=>"=");
923             $fres->{path_sep} = "=";
924             # XXX actually not entirely correct, we want normal
925 3         18 # escaping but without escaping "=", maybe we should
926             # allow customizing, e.g. esc_mode=normal, dont_esc="="
927 3         10 # (list of characters to not escape)
928 3         69 $fres->{esc_mode} = "none";
929             goto RETURN_RES;
930             }
931             } else {
932             $fres = complete_arg_val(
933 3         6 meta=>$meta, arg=>$sm->{arg}, args=>$gares->[2],
934 3         73 word=>$word, extras=>$extras, %rargs);
935             goto RETURN_RES;
936             }
937             } else {
938 6         24 log_trace("[comp][periscomp] completing option value for a common option, ospec=<%s>", $ospec);
939             $cargs{arg} = undef;
940 6         176 my $codata = $copts_by_ospec->{$ospec};
941             if ($comp) {
942             log_trace("[comp][periscomp] invoking routine supplied from 'completion' argument with args (%s)", \%cargs);
943 1         4 my $res;
944 1         3 eval { $res = $comp->(%cargs) };
945 1         2 log_debug("[comp][periscomp] completion died: $@") if $@;
946 1 50       5 if ($res) {
947 1         4 $fres = $res;
948 1         2 goto RETURN_RES;
949 1         3 }
  1         8  
950 1 50       6 }
951 1 50       4 if ($codata->{completion}) {
952 1         2 $cargs{arg} = undef;
953 1         44 log_trace("[comp][periscomp] completing with common option's 'completion' property with args (%s)", \%cargs);
954             my $res;
955             eval { $res = $codata->{completion}->(%cargs) };
956 0 0       0 log_debug("[comp][periscomp] completion died: $@") if $@;
957 0         0 if ($res) {
958 0         0 $fres = $res;
959 0         0 goto RETURN_RES;
960 0         0 }
  0         0  
961 0 0       0 }
962 0 0       0 if ($codata->{schema}) {
963 0         0 require Data::Sah::Normalize;
964 0         0 my $nsch = Data::Sah::Normalize::normalize_schema(
965             $codata->{schema});
966             log_trace("[comp][periscomp] completing with common option's schema");
967 0 0       0 $fres = complete_from_schema(
968 0         0 schema => $nsch, word=>$word,
969             schema_is_normalized=>1,
970 0         0 );
971 0         0 goto RETURN_RES;
972 0         0 }
973             goto RETURN_RES;
974             }
975             } elsif ($type eq 'arg') {
976 0         0 log_trace("[comp][periscomp] completing argument #%d", $cargs{argpos});
977             $cargs{type} = 'arg';
978 0         0  
979             my $pos = $cargs{argpos};
980             my $fasa = $args{func_arg_starts_at} // 0;
981 8         24  
982 8         23 # find if there is a non-slurpy argument with the exact position
983             for my $an (keys %$args_prop) {
984 8         15 my $arg_spec = $args_prop->{$an};
985 8   50     56 next unless !($arg_spec->{slurpy} // $arg_spec->{greedy}) &&
986             defined($arg_spec->{pos}) && $arg_spec->{pos} == $pos - $fasa;
987             log_trace("[comp][periscomp] this argument position is for non-slurpy function argument <%s>", $an);
988 8         37 $cargs{arg} = $an;
989 80         107 if ($comp) {
990             log_trace("[comp][periscomp] invoking routine supplied from 'completion' argument with args (%s)", \%cargs);
991 80 100 66     294 my $res;
      100        
      100        
992 2         7 eval { $res = $comp->(%cargs) };
993 2         6 log_debug("[comp][periscomp] completion died: $@") if $@;
994 2 100       24 if ($res) {
995 1         4 $fres = $res;
996 1         3 goto RETURN_RES;
997 1         4 }
  1         7  
998 1 50       7 }
999 1 50       3 $fres = complete_arg_val(
1000 1         2 meta=>$meta, arg=>$an, args=>$gares->[2],
1001 1         46 word=>$word, extras=>$extras, %rargs);
1002             goto RETURN_RES;
1003             }
1004 1         7  
1005             # find if there is a slurpy argument which takes elements at that
1006             # position
1007 1         27 for my $an (sort {
1008             ($args_prop->{$b}{pos} // 9999) <=> ($args_prop->{$a}{pos} // 9999)
1009             } keys %$args_prop) {
1010             my $arg_spec = $args_prop->{$an};
1011             next unless ($arg_spec->{slurpy} // $arg_spec->{greedy}) &&
1012 6         28 defined($arg_spec->{pos}) && $arg_spec->{pos} <= $pos - $fasa;
1013 150   100     372 my $index = $pos - $fasa - $arg_spec->{pos};
      100        
1014             $cargs{arg} = $an;
1015 51         62 $cargs{index} = $index;
1016             log_trace("[comp][periscomp] this position is for slurpy function argument <%s>'s element[%d]", $an, $index);
1017 51 50 66     143 if ($comp) {
      66        
      66        
1018 3         9 log_trace("[comp][periscomp] invoking routine supplied from 'completion' argument with args (%s)", \%cargs);
1019 3         6 my $res;
1020 3         7 eval { $res = $comp->(%cargs) };
1021 3         10 log_debug("[comp][periscomp] completion died: $@") if $@;
1022 3 100       13 if ($res) {
1023 2         7 $fres = $res;
1024 2         4 goto RETURN_RES;
1025 2         7 }
  2         13  
1026 2 50       976 }
1027 2 50       6 $fres = complete_arg_elem(
1028 2         4 meta=>$meta, arg=>$an, args=>$gares->[2],
1029 2         84 word=>$word, index=>$index, extras=>$extras, %rargs);
1030             goto RETURN_RES;
1031             }
1032 1         5  
1033             log_trace("[comp][periscomp] there is no matching function argument at this position");
1034             if ($comp) {
1035 1         28 log_trace("[comp][periscomp] invoking routine supplied from 'completion' argument with args (%s)", \%cargs);
1036             my $res;
1037             eval { $res = $comp->(%cargs) };
1038 3         10 log_debug("[comp][periscomp] completion died: $@") if $@;
1039 3 100       11 if ($res) {
1040 2         6 $fres = $res;
1041 2         6 goto RETURN_RES;
1042 2         5 }
  2         11  
1043 2 50       11 }
1044 2 50       6 goto RETURN_RES;
1045 2         4 } else {
1046 2         87 log_trace("[comp][periscomp] completing option value for an unknown/ambiguous option, declining ...");
1047             # decline because there's nothing in Rinci metadata that can aid us
1048             goto RETURN_RES;
1049 1         58 }
1050             RETURN_RES:
1051 0         0 log_trace("[comp][periscomp] leaving completion routine (that we supply to Complete::Getopt::Long)");
1052             $fres;
1053 0         0 }; # completion routine
1054              
1055 21         54 $fres = Complete::Getopt::Long::complete_cli_arg(
1056             getopt_spec => $gospec,
1057 21         105 words => $words,
1058 24         190 cword => $cword,
1059             completion => $compgl_comp,
1060 24         110 extras => $extras,
1061             );
1062              
1063             RETURN_RES:
1064             log_trace('[comp][periscomp] leaving %s(), result=%s',
1065             $fname, $fres);
1066             $fres;
1067             }
1068 24         20623  
1069             1;
1070             # ABSTRACT: Complete command-line argument using Rinci metadata
1071 24         3882  
1072              
1073             =pod
1074              
1075             =encoding UTF-8
1076              
1077             =head1 NAME
1078              
1079             Perinci::Sub::Complete - Complete command-line argument using Rinci metadata
1080              
1081             =head1 VERSION
1082              
1083             This document describes version 0.944 of Perinci::Sub::Complete (from Perl distribution Perinci-Sub-Complete), released on 2021-05-07.
1084              
1085             =head1 SYNOPSIS
1086              
1087             See L<Perinci::CmdLine> or L<Perinci::CmdLine::Lite> or L<App::riap> which use
1088             this module.
1089              
1090             =head1 DESCRIPTION
1091              
1092             =head1 FUNCTIONS
1093              
1094              
1095             =head2 complete_arg_elem
1096              
1097             Usage:
1098              
1099             complete_arg_elem(%args) -> array
1100              
1101             Given argument name and function metadata, complete array element.
1102              
1103             Will attempt to complete using the completion routine specified in the argument
1104             specification (the C<completion> property, or in the case of C<complete_arg_elem>
1105             function, the C<element_completion> property), or if that is not specified, from
1106             argument's schema using C<complete_from_schema>.
1107              
1108             Completion routine will get C<%args>, with the following keys:
1109              
1110             =over
1111              
1112             =item * C<word> (str, the word to be completed)
1113              
1114             =item * C<arg> (str, the argument name which value is currently being completed)
1115              
1116             =item * C<index (int, only for the>complete_arg_elem` function, the index in the
1117             argument array that is currently being completed, starts from 0)
1118              
1119             =item * C<args> (hash, the argument hash to the function, so far)
1120              
1121             =back
1122              
1123             as well as extra keys from C<extras> (but these won't overwrite the above
1124             standard keys).
1125              
1126             Completion routine should return a completion answer structure (described in
1127             L<Complete>) which is either a hash or an array. The simplest form of answer
1128             is just to return an array of strings. Completion routine can also return undef
1129             to express declination.
1130              
1131             This function is not exported by default, but exportable.
1132              
1133             Arguments ('*' denotes required arguments):
1134              
1135             =over 4
1136              
1137             =item * B<arg>* => I<str>
1138              
1139             Argument name.
1140              
1141             =item * B<args> => I<hash>
1142              
1143             Collected arguments so far, will be passed to completion routines.
1144              
1145             =item * B<extras> => I<hash>
1146              
1147             Add extra arguments to completion routine.
1148              
1149             The keys from this C<extras> hash will be merged into the final C<%args> passed to
1150             completion routines. Note that standard keys like C<word>, C<cword>, and so on as
1151             described in the function description will not be overwritten by this.
1152              
1153             =item * B<index> => I<str>
1154              
1155             Index of element to complete.
1156              
1157             =item * B<meta>* => I<hash>
1158              
1159             Rinci function metadata, must be normalized.
1160              
1161             =item * B<riap_client> => I<obj>
1162              
1163             Optional, to perform complete_arg_val to the server.
1164              
1165             When the argument spec in the Rinci metadata contains C<completion> key, this
1166             means there is custom completion code for that argument. However, if retrieved
1167             from a remote server, sometimes the C<completion> key no longer contains the code
1168             (it has been cleansed into a string). Moreover, the completion code needs to run
1169             on the server.
1170              
1171             If supplied this argument and te C<riap_server_url> argument, the function will
1172             try to request to the server (via Riap request C<complete_arg_val>). Otherwise,
1173             the function will just give up/decline completing.
1174              
1175             =item * B<riap_server_url> => I<str>
1176              
1177             Optional, to perform complete_arg_val to the server.
1178              
1179             See the C<riap_client> argument.
1180              
1181             =item * B<riap_uri> => I<str>
1182              
1183             Optional, to perform complete_arg_val to the server.
1184              
1185             See the C<riap_client> argument.
1186              
1187             =item * B<word> => I<str> (default: "")
1188              
1189             Word to be completed.
1190              
1191              
1192             =back
1193              
1194             Return value: (array)
1195              
1196              
1197              
1198             =head2 complete_arg_index
1199              
1200             Usage:
1201              
1202             complete_arg_index(%args) -> array
1203              
1204             Given argument name and function metadata, complete arg element index.
1205              
1206             This is only relevant for arguments which have C<index_completion> property set
1207             (currently only C<hash> type arguments). When that property is not set, will
1208             simply return undef.
1209              
1210             Completion routine will get C<%args>, with the following keys:
1211              
1212             =over
1213              
1214             =item * C<word> (str, the word to be completed)
1215              
1216             =item * C<arg> (str, the argument name which value is currently being completed)
1217              
1218             =item * C<args> (hash, the argument hash to the function, so far)
1219              
1220             =back
1221              
1222             as well as extra keys from C<extras> (but these won't overwrite the above
1223             standard keys).
1224              
1225             Completion routine should return a completion answer structure (described in
1226             L<Complete>) which is either a hash or an array. The simplest form of answer
1227             is just to return an array of strings. Completion routine can also return undef
1228             to express declination.
1229              
1230             This function is not exported by default, but exportable.
1231              
1232             Arguments ('*' denotes required arguments):
1233              
1234             =over 4
1235              
1236             =item * B<arg>* => I<str>
1237              
1238             Argument name.
1239              
1240             =item * B<args> => I<hash>
1241              
1242             Collected arguments so far, will be passed to completion routines.
1243              
1244             =item * B<extras> => I<hash>
1245              
1246             Add extra arguments to completion routine.
1247              
1248             The keys from this C<extras> hash will be merged into the final C<%args> passed to
1249             completion routines. Note that standard keys like C<word>, C<cword>, and so on as
1250             described in the function description will not be overwritten by this.
1251              
1252             =item * B<meta>* => I<hash>
1253              
1254             Rinci function metadata, must be normalized.
1255              
1256             =item * B<riap_client> => I<obj>
1257              
1258             Optional, to perform complete_arg_val to the server.
1259              
1260             When the argument spec in the Rinci metadata contains C<completion> key, this
1261             means there is custom completion code for that argument. However, if retrieved
1262             from a remote server, sometimes the C<completion> key no longer contains the code
1263             (it has been cleansed into a string). Moreover, the completion code needs to run
1264             on the server.
1265              
1266             If supplied this argument and te C<riap_server_url> argument, the function will
1267             try to request to the server (via Riap request C<complete_arg_val>). Otherwise,
1268             the function will just give up/decline completing.
1269              
1270             =item * B<riap_server_url> => I<str>
1271              
1272             Optional, to perform complete_arg_val to the server.
1273              
1274             See the C<riap_client> argument.
1275              
1276             =item * B<riap_uri> => I<str>
1277              
1278             Optional, to perform complete_arg_val to the server.
1279              
1280             See the C<riap_client> argument.
1281              
1282             =item * B<word> => I<str> (default: "")
1283              
1284             Word to be completed.
1285              
1286              
1287             =back
1288              
1289             Return value: (array)
1290              
1291              
1292              
1293             =head2 complete_arg_val
1294              
1295             Usage:
1296              
1297             complete_arg_val(%args) -> array
1298              
1299             Given argument name and function metadata, complete value.
1300              
1301             Will attempt to complete using the completion routine specified in the argument
1302             specification (the C<completion> property, or in the case of C<complete_arg_elem>
1303             function, the C<element_completion> property), or if that is not specified, from
1304             argument's schema using C<complete_from_schema>.
1305              
1306             Completion routine will get C<%args>, with the following keys:
1307              
1308             =over
1309              
1310             =item * C<word> (str, the word to be completed)
1311              
1312             =item * C<arg> (str, the argument name which value is currently being completed)
1313              
1314             =item * C<index (int, only for the>complete_arg_elem` function, the index in the
1315             argument array that is currently being completed, starts from 0)
1316              
1317             =item * C<args> (hash, the argument hash to the function, so far)
1318              
1319             =back
1320              
1321             as well as extra keys from C<extras> (but these won't overwrite the above
1322             standard keys).
1323              
1324             Completion routine should return a completion answer structure (described in
1325             L<Complete>) which is either a hash or an array. The simplest form of answer
1326             is just to return an array of strings. Completion routine can also return undef
1327             to express declination.
1328              
1329             This function is not exported by default, but exportable.
1330              
1331             Arguments ('*' denotes required arguments):
1332              
1333             =over 4
1334              
1335             =item * B<arg>* => I<str>
1336              
1337             Argument name.
1338              
1339             =item * B<args> => I<hash>
1340              
1341             Collected arguments so far, will be passed to completion routines.
1342              
1343             =item * B<extras> => I<hash>
1344              
1345             Add extra arguments to completion routine.
1346              
1347             The keys from this C<extras> hash will be merged into the final C<%args> passed to
1348             completion routines. Note that standard keys like C<word>, C<cword>, and so on as
1349             described in the function description will not be overwritten by this.
1350              
1351             =item * B<meta>* => I<hash>
1352              
1353             Rinci function metadata, must be normalized.
1354              
1355             =item * B<riap_client> => I<obj>
1356              
1357             Optional, to perform complete_arg_val to the server.
1358              
1359             When the argument spec in the Rinci metadata contains C<completion> key, this
1360             means there is custom completion code for that argument. However, if retrieved
1361             from a remote server, sometimes the C<completion> key no longer contains the code
1362             (it has been cleansed into a string). Moreover, the completion code needs to run
1363             on the server.
1364              
1365             If supplied this argument and te C<riap_server_url> argument, the function will
1366             try to request to the server (via Riap request C<complete_arg_val>). Otherwise,
1367             the function will just give up/decline completing.
1368              
1369             =item * B<riap_server_url> => I<str>
1370              
1371             Optional, to perform complete_arg_val to the server.
1372              
1373             See the C<riap_client> argument.
1374              
1375             =item * B<riap_uri> => I<str>
1376              
1377             Optional, to perform complete_arg_val to the server.
1378              
1379             See the C<riap_client> argument.
1380              
1381             =item * B<word> => I<str> (default: "")
1382              
1383             Word to be completed.
1384              
1385              
1386             =back
1387              
1388             Return value: (array)
1389              
1390              
1391              
1392             =head2 complete_cli_arg
1393              
1394             Usage:
1395              
1396             complete_cli_arg(%args) -> hash
1397              
1398             Complete command-line argument using Rinci function metadata.
1399              
1400             This routine uses L<Perinci::Sub::GetArgs::Argv> to generate L<Getopt::Long>
1401             specification from arguments list in Rinci function metadata and common options.
1402             Then, it will use L<Complete::Getopt::Long> to complete option names, option
1403             values, as well as arguments.
1404              
1405             This function is not exported by default, but exportable.
1406              
1407             Arguments ('*' denotes required arguments):
1408              
1409             =over 4
1410              
1411             =item * B<common_opts> => I<hash>
1412              
1413             Common options.
1414              
1415             A hash where the values are hashes containing these keys: C<getopt> (Getopt::Long
1416             option specification), C<handler> (Getopt::Long handler). Will be passed to
1417             C<get_args_from_argv()>. Example:
1418              
1419             {
1420             help => {
1421             getopt => 'help|h|?',
1422             handler => sub { ... },
1423             summary => 'Display help and exit',
1424             },
1425             version => {
1426             getopt => 'version|v',
1427             handler => sub { ... },
1428             summary => 'Display version and exit',
1429             },
1430             }
1431              
1432             =item * B<completion> => I<code>
1433              
1434             Supply custom completion routine.
1435              
1436             If supplied, instead of the default completion routine, this code will be called
1437             instead. Will receive all arguments that L<Complete::Getopt::Long> will pass,
1438             and additionally:
1439              
1440             =over
1441              
1442             =item * C<arg> (str, the name of function argument)
1443              
1444             =item * C<args> (hash, the function arguments formed so far)
1445              
1446             =item * C<index> (int, if completing argument element value)
1447              
1448             =back
1449              
1450             =item * B<cword>* => I<int>
1451              
1452             On which argument cursor is located (zero-based).
1453              
1454             =item * B<extras> => I<hash>
1455              
1456             Add extra arguments to completion routine.
1457              
1458             The keys from this C<extras> hash will be merged into the final C<%args> passed to
1459             completion routines. Note that standard keys like C<word>, C<cword>, and so on as
1460             described in the function description will not be overwritten by this.
1461              
1462             =item * B<func_arg_starts_at> => I<int> (default: 0)
1463              
1464             This is a (temporary?) workaround for L<Perinci::CmdLine>. In an application
1465             with subcommands (e.g. C<cmd --verbose subcmd arg0 arg1 ...>), then C<words> will
1466             still contain the subcommand name. Positional function arguments then start at 1
1467             not 0. This option allows offsetting function arguments.
1468              
1469             =item * B<meta>* => I<hash>
1470              
1471             Rinci function metadata.
1472              
1473             =item * B<per_arg_json> => I<bool>
1474              
1475             Will be passed to Perinci::Sub::GetArgs::Argv.
1476              
1477             =item * B<per_arg_yaml> => I<bool>
1478              
1479             Will be passed to Perinci::Sub::GetArgs::Argv.
1480              
1481             =item * B<riap_client> => I<obj>
1482              
1483             Optional, to perform complete_arg_val to the server.
1484              
1485             When the argument spec in the Rinci metadata contains C<completion> key, this
1486             means there is custom completion code for that argument. However, if retrieved
1487             from a remote server, sometimes the C<completion> key no longer contains the code
1488             (it has been cleansed into a string). Moreover, the completion code needs to run
1489             on the server.
1490              
1491             If supplied this argument and te C<riap_server_url> argument, the function will
1492             try to request to the server (via Riap request C<complete_arg_val>). Otherwise,
1493             the function will just give up/decline completing.
1494              
1495             =item * B<riap_server_url> => I<str>
1496              
1497             Optional, to perform complete_arg_val to the server.
1498              
1499             See the C<riap_client> argument.
1500              
1501             =item * B<riap_uri> => I<str>
1502              
1503             Optional, to perform complete_arg_val to the server.
1504              
1505             See the C<riap_client> argument.
1506              
1507             =item * B<words>* => I<array[str]>
1508              
1509             Command-line arguments.
1510              
1511              
1512             =back
1513              
1514             Return value: (hash)
1515              
1516              
1517             You can use C<format_completion> function in L<Complete::Bash> module to format
1518             the result of this function for bash.
1519              
1520              
1521              
1522             =head2 complete_from_schema
1523              
1524             Usage:
1525              
1526             complete_from_schema(%args) -> [status, msg, payload, meta]
1527              
1528             Complete a value from schema.
1529              
1530             Employ some heuristics to complete a value from Sah schema. For example, if
1531             schema is C<< [str =E<gt> in =E<gt> [qw/new open resolved rejected/]] >>, then we can
1532             complete from the C<in> clause. Or for something like C<< [int =E<gt> between =E<gt> [1,
1533             20]] >> we can complete using values from 1 to 20.
1534              
1535             This function is not exported by default, but exportable.
1536              
1537             Arguments ('*' denotes required arguments):
1538              
1539             =over 4
1540              
1541             =item * B<schema>* => I<any>
1542              
1543             Will be normalized, unless when C<schema_is_normalized> is set to true, in which
1544             case schema must already be normalized.
1545              
1546             =item * B<schema_is_normalized> => I<bool> (default: 0)
1547              
1548             =item * B<word>* => I<str> (default: "")
1549              
1550              
1551             =back
1552              
1553             Returns an enveloped result (an array).
1554              
1555             First element (status) is an integer containing HTTP status code
1556             (200 means OK, 4xx caller error, 5xx function error). Second element
1557             (msg) is a string containing error message, or 'OK' if status is
1558             200. Third element (payload) is optional, the actual result. Fourth
1559             element (meta) is called result metadata and is optional, a hash
1560             that contains extra information.
1561              
1562             Return value: (any)
1563              
1564             =for Pod::Coverage ^(.+)$
1565              
1566             =head1 HOMEPAGE
1567              
1568             Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Sub-Complete>.
1569              
1570             =head1 SOURCE
1571              
1572             Source repository is at L<https://github.com/perlancar/perl-Perinci-Sub-Complete>.
1573              
1574             =head1 BUGS
1575              
1576             Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Sub-Complete>
1577              
1578             When submitting a bug or request, please include a test-file or a
1579             patch to an existing test-file that illustrates the bug or desired
1580             feature.
1581              
1582             =head1 SEE ALSO
1583              
1584             L<Complete>, L<Complete::Getopt::Long>
1585              
1586             L<Perinci::CmdLine>, L<Perinci::CmdLine::Lite>, L<App::riap>
1587              
1588             =head1 AUTHOR
1589              
1590             perlancar <perlancar@cpan.org>
1591              
1592             =head1 COPYRIGHT AND LICENSE
1593              
1594             This software is copyright (c) 2021, 2020, 2019, 2018, 2017, 2016, 2015, 2014, 2013, 2012, 2011 by perlancar@cpan.org.
1595              
1596             This is free software; you can redistribute it and/or modify it under
1597             the same terms as the Perl 5 programming language system itself.
1598              
1599             =cut