@@ -422,6 +422,41 @@ private static class CommandDescriptor {
422
422
" done\n " +
423
423
" echo \" $result\" \n " +
424
424
"}\n " +
425
+ "\n " +
426
+ "# compReplyArray generates a list of completion suggestions based on an array, ensuring all values are properly escaped.\n " +
427
+ "#\n " +
428
+ "# compReplyArray takes a single parameter: the array of options to be displayed\n " +
429
+ "#\n " +
430
+ "# The output is echoed to std_out, one option per line.\n "
431
+ + "#\n "
432
+ + "# Example usage:\n "
433
+ + "# local options=(\" foo\" , \" bar\" , \" baz\" )\n "
434
+ + "# local IFS=$'\\ n'\n "
435
+ + "# COMPREPLY=$(compReplyArray \" ${options[@]}\" )\n " +
436
+ "function compReplyArray() {\n " +
437
+ " declare -a options\n " +
438
+ " options=(\" $@\" )\n " +
439
+ " local curr_word=${COMP_WORDS[COMP_CWORD]}\n " +
440
+ " local i\n " +
441
+ " local quoted\n " +
442
+ " local optionList=()\n " +
443
+ "\n " +
444
+ " for (( i=0; i<${#options[@]}; i++ )); do\n " +
445
+ " # Double escape, since we want escaped values, but compgen -W expands the argument\n " +
446
+ " printf -v quoted %%q \" ${options[i]}\" \n " +
447
+ " quoted=\\ '${quoted//\\ '/\\ '\\ \\ \\ '\\ '}\\ '\n " +
448
+ "\n " +
449
+ " optionList[i]=$quoted\n " +
450
+ " done\n " +
451
+ "\n " +
452
+ " # We also have to add another round of escaping to $curr_word.\n " +
453
+ " curr_word=${curr_word//\\ \\ /\\ \\ \\ \\ }\n " +
454
+ " curr_word=${curr_word//\\ '/\\ \\ \\ '}\n " +
455
+ "\n " +
456
+ " # Actually generate completions.\n " +
457
+ " local IFS=$'\\ n'\n " +
458
+ " echo -e \" $(compgen -W \" ${optionList[*]}\" -- \" $curr_word\" )\" \n " +
459
+ "}\n " +
425
460
"\n " ;
426
461
427
462
private static final String SCRIPT_FOOTER = "" +
@@ -750,9 +785,7 @@ private static String generatePositionalParamsCases(List<PositionalParamSpec> po
750
785
int max = param .index ().max ();
751
786
if (param .completionCandidates () != null ) {
752
787
buff .append (format ("%s %s (( currIndex >= %d && currIndex <= %d )); then\n " , indent , ifOrElif , min , max ));
753
- buff .append (format ("%s local IFS=$'\\ n'\n " , indent ));
754
- buff .append (format ("%s positionals=$( compgen -W \" ${%s_pos_param_args[*]}\" -- \" %s\" )\n " ,
755
- indent , paramName , currWord ));
788
+ buff .append (format ("%s positionals=$( compReplyArray \" ${%s_pos_param_args[@]}\" )\n " , indent , paramName , currWord ));
756
789
} else if (type .equals (File .class ) || "java.nio.file.Path" .equals (type .getName ())) {
757
790
buff .append (format ("%s %s (( currIndex >= %d && currIndex <= %d )); then\n " , indent , ifOrElif , min , max ));
758
791
buff .append (format ("%s local IFS=$'\\ n'\n " , indent ));
@@ -796,8 +829,7 @@ private static String generateOptionsCases(List<OptionSpec> argOptionFields, Str
796
829
if (option .completionCandidates () != null ) {
797
830
buff .append (format ("%s %s)\n " , indent , concat ("|" , option .names ()))); // " -u|--timeUnit)\n"
798
831
buff .append (format ("%s local IFS=$'\\ n'\n " , indent ));
799
- buff .append (format ("%s COMPREPLY=( $( compgen -W \" ${%s_option_args[*]}\" -- \" %s\" ) )\n " , indent ,
800
- bashify (option .paramLabel ()), currWord ));
832
+ buff .append (format ("%s COMPREPLY=( $( compReplyArray \" ${%s_option_args[@]}\" ) )\n " , indent , bashify (option .paramLabel ()), currWord ));
801
833
buff .append (format ("%s return $?\n " , indent ));
802
834
buff .append (format ("%s ;;\n " , indent ));
803
835
} else if (type .equals (File .class ) || "java.nio.file.Path" .equals (type .getName ())) {
0 commit comments