import 'package:args/args.dart'; import 'util.dart'; /* * TODO: an interesting scenario: if there is only one subcommand, * then tabbing into an app just completes to that one command. Weird? */ List getArgsCompletions( ArgParser parser, List providedArgs, String compLine, int compPoint, ) { // all arg entries: no empty items, no null items, all pre-trimmed for (var i = 0; i < providedArgs.length; i++) { final arg = providedArgs[i]; final msg = 'Arg at index $i with value "$arg" '; if (arg.trim() != arg) throw StateError('$msg has whitespace'); if (i < (providedArgs.length - 1)) { if (arg.isEmpty) { throw StateError('$msg – Only the last arg can be an empty string'); } } } void sublog(Object obj) { log(obj, Tag.getArgsCompletions); } sublog('provided args: ${helpfulToString(providedArgs)}'); sublog('COMP_LINE: "$compLine"'); sublog('COMP_POINT: $compPoint'); if (compPoint < compLine.length) { // TODO: ponder smart ways to handle in-line completion sublog('cursor is in the middle of the line. NO-OP'); return const []; } if (providedArgs.isEmpty) { sublog('empty args. Complete with all available commands'); return parser.commands.keys.toList(); } final alignedArgsOptions = providedArgs.map((arg) => _getOptionForArg(parser, arg)).toList(); /* * NOTE: nuanced behavior * If the last item provided is a full, real item (command or option) * It should be completed with its full name so the user can move on * Soooo....we are excluding the last item in [alignedArgsOptions] from * optionsDefinedInArgs * * Keep in mind, if we're already on to the next item to complete, the last * item is likely empty string '' or '--', so this isn't a problem */ // a set of options in use (minus, potentially, the last one) // all non-null, all unique final optionsDefinedInArgs = alignedArgsOptions .take(alignedArgsOptions.length - 1) .whereType