def _prepare_args_completions(self, parsed_command: pp.ParseResults, last_token) -> Iterable[Completion]: assert parsed_command is not None args_meta = self.meta.arguments.values() # are we expecting a sub command? if self.cmd.super_command: # We have a sub-command (supposedly) subcommand = parsed_command.get("__subcommand__") assert subcommand sub_meta = self.cmd.subcommand_metadata(subcommand) if not sub_meta: logging.debug("Parsing unknown sub-command failed!") return [] # we did find the sub-command, yay! # In this case we chain the arguments from super and the # sub-command together args_meta = itertools.chain(args_meta, sub_meta.arguments.values()) # Now let's see if we can figure which argument we are talking about args_meta = self._filter_arguments_by_prefix(last_token, args_meta) # Which arguments did we fully parse already? let's avoid printing them # in completions parsed_keys = parsed_command.asDict().get("kv", []) # We are either completing an argument name, argument value, or # positional value. # Dissect the last_token and figure what is the right completion parsed_token = TokenParse(last_token) if parsed_token.is_positional: # TODO: Handle positional argument completions too # To figure which positional we are in right now, we need to run the # same logic that figures if all required arguments has been # supplied and how many positionals have been processed and which # one is next. # This code is already in cmdbase.py run_interactive but needs to be # refactored to be reusable here. pass elif parsed_token.is_argument: argument_name = parsed_token.argument_name arg = self._find_argument_by_name(argument_name) if not arg or arg.choices in [False, None]: return [] # TODO: Support dictionary keys/named tuples completion if parsed_token.is_dict: return [] # We are completing a value, in this case, we need to get the last # meaninful piece of the token `x=[Tr` => `Tr` return [ Completion( text=str(choice), start_position=-len(parsed_token.last_value), ) for choice in arg.choices if str(choice).lower().startswith( parsed_token.last_value.lower()) ] # We are completing arguments, or positionals. # TODO: We would like to only show positional choices if we exhaust all # required arguments. This will make it easier for the user to figure # that there are still required named arguments. After that point we # will show optional arguments and positionals as possible completions ret = [ Completion( text=arg_meta.name + "=", start_position=-len(last_token), display_meta=self._get_arg_help(arg_meta), ) for arg_meta in args_meta if arg_meta.name not in parsed_keys ] return ret
def call_parse_result(self, res: pp.ParseResults, msg, *args, **kwargs): d = res.asDict() if "help" in d["options"]: return d["options"]["help"] return d["command"](msg, *args, bot=self, args=d["options"], **kwargs)