Archived
1
0
Fork 0
This repository has been archived on 2024-04-26. You can view files and clone it, but cannot push or open issues or pull requests.
akari-bot/core/parser/command.py

132 lines
4.9 KiB
Python
Raw Normal View History

2021-07-19 16:12:29 +00:00
import re
2021-07-18 16:17:09 +00:00
import shlex
2021-10-24 10:55:45 +00:00
import traceback
2021-09-10 18:05:27 +00:00
from typing import Union
2021-08-07 07:56:48 +00:00
2021-07-19 16:12:29 +00:00
from core.docopt import docopt, DocoptExit
2021-10-15 17:36:22 +00:00
from core.elements import Command, Option, Schedule, StartUp, RegexCommand, command_prefix
command_prefix_first = command_prefix[0]
2021-07-19 16:12:29 +00:00
class InvalidHelpDocTypeError(BaseException):
def __init__(self, *args, **kwargs):
pass
2021-07-18 16:17:09 +00:00
2021-07-19 05:34:29 +00:00
class InvalidCommandFormatError(BaseException):
2021-07-18 16:17:09 +00:00
def __init__(self, *args, **kwargs):
pass
class CommandParser:
2021-10-24 10:55:45 +00:00
def __init__(self, args: Union[str, list, tuple, Command, Option, Schedule, StartUp, RegexCommand], prefix=None):
2021-07-19 16:12:29 +00:00
"""
Format: https://github.com/jazzband/docopt-ng#usage-pattern-format
* {} - Detail help information
"""
2021-10-24 10:55:45 +00:00
self.bind_prefix = prefix
self.origin_template = args
2021-10-14 14:49:12 +00:00
if isinstance(args, Command):
2021-10-15 17:36:22 +00:00
self.bind_prefix = args.bind_prefix
2021-10-24 10:55:45 +00:00
help_doc_list = []
none_doc = True
for match in args.match_list.set:
if match.help_doc is not None:
none_doc = False
help_doc_list = help_doc_list + match.help_doc
if not none_doc:
args = help_doc_list
2021-10-15 17:36:22 +00:00
else:
args = None
2021-10-24 10:55:45 +00:00
elif isinstance(args, (Schedule, StartUp, Option, RegexCommand)):
args = None
2021-10-15 17:36:22 +00:00
if args is None:
2021-10-24 10:55:45 +00:00
self.args = None
2021-10-15 17:36:22 +00:00
return
2021-07-19 05:34:29 +00:00
if isinstance(args, str):
2021-07-19 16:12:29 +00:00
args = [args]
2021-10-15 17:36:22 +00:00
self.args_raw = args
2021-10-24 10:55:45 +00:00
elif isinstance(args, tuple):
args = list(args)
if isinstance(args, list):
2021-10-15 17:36:22 +00:00
arglst_raw = []
2021-07-19 16:12:29 +00:00
arglst = []
for x in args:
2021-10-15 17:36:22 +00:00
split = x.split(' ')[0]
if self.bind_prefix is not None:
if split not in [command_prefix_first + self.bind_prefix, self.bind_prefix]:
x = f'{command_prefix_first}{self.bind_prefix} {x}'
arglst_raw.append(x)
2021-07-19 16:12:29 +00:00
match_detail_help = re.match('(.*){.*}$', x)
if match_detail_help:
x = match_detail_help.group(1)
arglst.append(x)
2021-10-15 17:36:22 +00:00
self.args_raw = arglst_raw
2021-08-07 03:59:58 +00:00
self.args = 'Usage:\n ' + '\n '.join(y for y in arglst)
2021-07-19 05:34:29 +00:00
else:
2021-07-19 16:12:29 +00:00
raise InvalidHelpDocTypeError
2021-07-26 12:43:51 +00:00
def return_formatted_help_doc(self) -> str:
2021-10-15 17:36:22 +00:00
if self.args is None:
return '(此模块没有帮助信息)'
2021-07-19 16:12:29 +00:00
args_raw = self.args_raw
2021-10-24 10:55:45 +00:00
if isinstance(args_raw, list):
2021-07-19 16:12:29 +00:00
arglst = []
for x in args_raw:
2021-10-15 17:36:22 +00:00
if x[0] not in command_prefix:
x = command_prefix_first + x
2021-07-19 16:12:29 +00:00
match_detail_help = re.match('(.*){(.*)}$', x)
if match_detail_help:
2021-10-15 17:36:22 +00:00
x = f'{match_detail_help.group(1)}- {match_detail_help.group(2)}'
2021-07-19 16:12:29 +00:00
arglst.append(x)
args = f'用法:\n ' + '\n '.join(y for y in arglst)
else:
raise InvalidHelpDocTypeError
return args
2021-07-18 16:17:09 +00:00
def parse(self, command):
2021-10-24 10:55:45 +00:00
if self.args is None:
2021-09-10 18:05:27 +00:00
return None
2021-10-24 10:55:45 +00:00
command = re.sub(r'[“”]', '"', command)
2021-09-04 13:27:23 +00:00
try:
split_command = shlex.split(command)
except ValueError:
split_command = command.split(' ')
2021-07-19 16:12:29 +00:00
try:
2021-10-24 10:55:45 +00:00
if not isinstance(self.origin_template, Command):
if len(split_command) == 1:
return None
return docopt(self.args, argvs=split_command[1:], default_help=False)
else:
if len(split_command) == 1:
for match in self.origin_template.match_list.set:
if match.help_doc is None:
return match, None
raise InvalidCommandFormatError
else:
base_match = docopt(self.args, argvs=split_command[1:], default_help=False)
for match in self.origin_template.match_list.set:
if match.help_doc is None:
continue
try:
sub_args = CommandParser(match.help_doc, prefix=self.bind_prefix).args
if sub_args is not None:
get_parse = docopt(sub_args,
argvs=split_command[1:], default_help=False)
else:
continue
except DocoptExit:
continue
correct = True
for g in get_parse:
if g not in base_match or get_parse[g] != base_match[g]:
correct = False
if correct:
return match, get_parse
2021-07-19 16:12:29 +00:00
except DocoptExit:
2021-10-24 10:55:45 +00:00
traceback.print_exc()
2021-07-19 16:12:29 +00:00
raise InvalidCommandFormatError