def execute_command(self, source: InfoCommandSource, command: str): first_literal_element = utils.get_element(command) plugin_root_nodes = self.root_nodes.get(first_literal_element, []) if len(plugin_root_nodes) > 0 and source.is_console: # If this is a command, don't send it towards the server if it's from console input source.get_info().cancel_send_to_server() command_errors = [] for plugin_root_node in plugin_root_nodes: plugin = plugin_root_node.plugin node = plugin_root_node.node with self.mcdr_server.plugin_manager.with_plugin_context(plugin): try: node.execute(source, command) except CommandError as e: command_errors.append(e) except: self.logger.exception( 'Error when executing command "{}" with command source "{}" on {} registered by {}' .format(command, source, node, plugin)) for error in command_errors: if not error.is_handled(): translation_key = 'command_exception.{}'.format( string_util.hump_to_underline(type(error).__name__)) try: error.set_translated_message( translation_key, lambda key, args: self.mcdr_server.tr( key, *args, allow_failure=False)) except KeyError: self.logger.debug( 'Fail to translated command error with key {}'.format( translation_key), option=DebugOption.COMMAND) source.reply(error.to_mc_color_text())
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 parse(self, text: str) -> ParseResult: arg = utils.get_element(text) try: enum = self.__enum_class[arg] except KeyError: raise InvalidEnumeration(arg) from None else: return ParseResult(enum, len(arg))
def parse(self, text: str) -> ParseResult: arg = utils.get_element(text) if arg.lower() == 'true': value = True elif arg.lower() == 'false': value = False else: raise InvalidBoolean(arg) return ParseResult(value, len(arg))
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, source: CommandSource, command: str): first_literal_element = utils.get_element(command) root_nodes = self.root_nodes.get(first_literal_element, []) if len(root_nodes ) > 0 and source.source_type == CommandSourceType.CONSOLE: # If this is a command, don't send it towards the server if it's from console input source.get_info().cancel_send_to_server() command_errors = [] general_exc_info = [] for node in root_nodes: try: node.execute(source, command) except CommandError as e: command_errors.append(e) except: general_exc_info.append(sys.exc_info()) for exc_info in general_exc_info: self.logger.error( 'Error when executing command "{}" with command source "{}"'. format(command, source), exc_info=exc_info) for error in command_errors: if not error.is_handled(): translation_key = 'command_exception.{}'.format( string_util.hump_to_underline(type(error).__name__)) try: error.set_translated_message( translation_key, lambda key, args: self.mcdr_server.tr( key, *args, allow_failure=False)) except KeyError: self.logger.debug( 'Fail to translated command error with key {}'.format( translation_key), option=DebugOption.COMMAND) source.reply(error.to_mc_color_text())
def _traverse(self, command: str, source: CommandSource, purpose: TraversePurpose) -> None or List[CommandSuggestion]: first_literal_element = utils.get_element(command) plugin_root_nodes = self.root_nodes.get(first_literal_element, []) suggestions = CommandSuggestions() if purpose == TraversePurpose.EXECUTE and isinstance(source, InfoCommandSource): if len(plugin_root_nodes) > 0 and source.is_console: # If this is a command, don't send it towards the server if it's from console input source.get_info().cancel_send_to_server() if purpose == TraversePurpose.SUGGEST and len(plugin_root_nodes) == 0: return CommandSuggestions([CommandSuggestion('', literal) for literal in self.root_nodes.keys()]) for plugin_root_node in plugin_root_nodes: plugin = plugin_root_node.plugin node = plugin_root_node.node try: with self.mcdr_server.plugin_manager.with_plugin_context(plugin): if purpose == TraversePurpose.EXECUTE: node.execute(source, command) elif purpose == TraversePurpose.SUGGEST: suggestions.extend(node.generate_suggestions(source, command)) except CommandError as error: if not error.is_handled(): translation_key = 'command_exception.{}'.format(string_util.hump_to_underline(type(error).__name__)) try: error.set_message(self.__translate_command_error_header(translation_key, error)) except KeyError: self.logger.debug('Fail to translated command error with key {}'.format(translation_key), option=DebugOption.COMMAND) source.reply(error.to_mc_color_text()) except: self.logger.exception('Error when executing command "{}" with command source "{}" on {} registered by {}'.format(command, source, node, plugin)) if purpose == TraversePurpose.SUGGEST: return suggestions
def parse(self, text): arg = utils.get_element(text) if arg in self.literals: return ParseResult(None, len(arg)) else: raise LiteralNotMatch('Invalid Argument', len(arg))
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)
def parse(self, text): arg = utils.get_element(text) return self._check_length_in_range_and_return(arg, len(arg))