def _execute(self, source, command: str, remaining: str, context: dict): success_read = len(command) - len(remaining) try: result = self.parse(remaining) except CommandSyntaxError as error: error.set_parsed_command(command[:success_read]) error.set_failed_command(command[:success_read + error.char_read]) self.__raise_error(source, error, context) else: success_read += result.char_read trimmed_remaining = utils.remove_divider_prefix(remaining[result.char_read:]) if self.__does_store_thing(): context[self.name] = result.value if self.requirement is not None: if not self.__smart_callback(self.requirement, source, context): getter = self.requirement_failure_message_getter if self.requirement_failure_message_getter is not None else lambda: None failure_message = self.__smart_callback(getter, source, context) self.__raise_error(source, RequirementNotMet(command[:success_read], command[:success_read], failure_message), context) # Parsing finished if len(trimmed_remaining) == 0: if self.callback is not None: self.__smart_callback(self.callback, source, context) else: self.__raise_error(source, UnknownCommand(command[:success_read], command[:success_read]), context) # Un-parsed command string remains else: # Redirecting node = self if self.redirect_node is None else self.redirect_node argument_unknown = False # No child at all if not node.has_children(): argument_unknown = True else: # Pass the remaining command string to the children try: # Check literal children first next_literal = utils.get_element(trimmed_remaining) for child_literal in node.children_literal.get(next_literal, []): try: child_literal._execute(source, command, trimmed_remaining, context) break except LiteralNotMatch: # it's ok for a direct literal node to fail pass else: # All literal children fails for child in node.children: child._execute(source, command, trimmed_remaining, context) break else: # No argument child argument_unknown = True except CommandError as error: self.__handle_error(source, error, context, self.child_error_handlers) raise error from None if argument_unknown: self.__raise_error(source, UnknownArgument(command[:success_read], command), context)
def _generate_suggestions(self, context: CommandContext) -> CommandSuggestions: """ Return a list of tuple (suggested command, suggested argument) """ def self_suggestions(): return CommandSuggestions([CommandSuggestion(command_read_at_the_beginning, s) for s in self._get_suggestions(context)]) suggestions = CommandSuggestions() # [!!aa bb cc] dd # read suggested command_read_at_the_beginning = context.command_read if len(context.command_remaining) == 0: return self_suggestions() try: result = self.parse(context.command_remaining) except CommandSyntaxError: return self_suggestions() else: success_read = len(context.command) - len(context.command_remaining) + result.char_read # type: int next_remaining = utils.remove_divider_prefix(context.command_remaining[result.char_read:]) # type: str total_read = len(context.command) - len(next_remaining) # type: int with context.read_command(self, result, total_read): if self._requirement is not None and not self.__smart_callback(self._requirement, context.source, context): return CommandSuggestions() # Parsing finished if len(next_remaining) == 0: # total_read == success_read means DIVIDER does not exists at the end of the input string # in that case, ends at this current node if success_read == total_read: return self_suggestions() node = self if self._redirect_node is None else self._redirect_node # Check literal children first children_literal = node._children_literal.get(utils.get_element(next_remaining), []) for child_literal in children_literal: with context.enter_child(child_literal): suggestions.extend(child_literal._generate_suggestions(context)) if len(children_literal) == 0: for literal_list in node._children_literal.values(): for child_literal in literal_list: with context.enter_child(child_literal): suggestions.extend(child_literal._generate_suggestions(context)) usages = [] for child in node._children: with context.enter_child(child): suggestions.extend(child._generate_suggestions(context)) if len(next_remaining) == 0: usages.append(child._get_usage()) if len(next_remaining) == 0: suggestions.complete_hint = '|'.join(usages) return suggestions
def _execute_command(self, context: CommandContext) -> None: command = context.command # type: str try: result = self.parse(context.command_remaining) except CommandSyntaxError as error: error.set_parsed_command(context.command_read) error.set_failed_command( context.command_read + context.command_remaining[:error.char_read]) self.__raise_error(error, context) else: next_remaining = utils.remove_divider_prefix( context.command_remaining[result.char_read:]) # type: str total_read = len(command) - len(next_remaining) # type: int with context.read_command(self, result, total_read): if self._requirement is not None: if not self.__smart_callback(self._requirement, context.source, context): getter = self._requirement_failure_message_getter or ( lambda: None) failure_message = self.__smart_callback( getter, context.source, context) self.__raise_error( RequirementNotMet(context.command_read, context.command_read, failure_message), context) # Parsing finished if len(next_remaining) == 0: if self._callback is not None: self.__smart_callback(self._callback, context.source, context) else: self.__raise_error( UnknownCommand(context.command_read, context.command_read), context) # Un-parsed command string remains else: # Redirecting node = self if self._redirect_node is None else self._redirect_node argument_unknown = False # No child at all if not node.has_children(): argument_unknown = True else: # Pass the remaining command string to the children next_literal = utils.get_element(next_remaining) try: # Check literal children first literal_error = None for child_literal in node._children_literal.get( next_literal, []): try: with context.enter_child(child_literal): child_literal._execute_command(context) break except CommandError as e: # it's ok for a direct literal node to fail # other literal might still have a chance to consume this command literal_error = e else: # All literal children fails if literal_error is not None: raise literal_error for child in node._children: with context.enter_child(child): child._execute_command(context) break else: # No argument child argument_unknown = True except CommandError as error: self.__handle_error(error, context, self._child_error_handlers) raise error from None if argument_unknown: self.__raise_error( UnknownArgument(context.command_read, command), context)