Changed CLI help:

- visually closer to pm3 (differenciate groups and commands)
- "dumphelp" allows to quickly dump all cmds and their options
- now all commands support '-h', so e.g. `hw settings store -h` will print help instead of storing
- no more command description in decorator, it is now taken from argparse description
This commit is contained in:
Philippe Teuwen
2023-10-05 00:48:50 +02:00
parent 702dba0d93
commit 707b0c6d4a
4 changed files with 283 additions and 164 deletions
+1
View File
@@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased]
- Changed CLI help: lists display and now all commands support `-h` (@doegox)
- Added button action to show battery level (@doegox)
- Added GUI Page docs (@GameTec-live)
- Changed CLI threads polling into blocking reads, to reduce CPU usage (@doegox)
+58 -15
View File
@@ -37,6 +37,35 @@ BANNER = """
"""
def dump_help(cmd_node, depth=0, dump_cmd_groups=False, dump_description=False):
if cmd_node.cls:
cmd_title = f"{colorama.Fore.GREEN}{cmd_node.fullname}{colorama.Style.RESET_ALL}"
if dump_description:
print(f" {cmd_title}".ljust(37) + f"{cmd_node.help_text}")
else:
print(f" {cmd_title}".ljust(37), end="")
p = cmd_node.cls().args_parser()
assert p is not None
p.prog = ""
usage = p.format_usage().removeprefix("usage: ").rstrip()
if usage != "[-h]":
usage = usage.removeprefix("[-h] ")
if dump_description:
print(f"{colorama.Fore.GREEN}{colorama.Style.RESET_ALL}".ljust(37), end="")
print(f"{colorama.Fore.YELLOW}{usage}{colorama.Style.RESET_ALL}")
else:
print("")
else:
if dump_cmd_groups:
cmd_title = f"{colorama.Fore.YELLOW}{cmd_node.fullname}{colorama.Style.RESET_ALL}"
if dump_description:
print(f" {cmd_title}".ljust(37) + f"{{ {cmd_node.help_text}... }}")
else:
print(f" {cmd_title}")
for child in cmd_node.children:
dump_help(child, depth + 1, dump_cmd_groups, dump_description)
class ChameleonCLI:
"""
CLI for chameleon
@@ -122,6 +151,10 @@ class ChameleonCLI:
elif cmd_str == "clear":
os.system('clear' if os.name == 'posix' else 'cls')
continue
elif cmd_str == "dumphelp":
for _, cmd_node in chameleon_cli_unit.root_commands.items():
dump_help(cmd_node)
continue
elif cmd_str == "":
continue
@@ -146,8 +179,14 @@ class ChameleonCLI:
for cmd_name, cmd_node in chameleon_cli_unit.root_commands.items():
cmd_title = f"{colorama.Fore.GREEN}{cmd_name}{colorama.Style.RESET_ALL}"
help_line = (f" - {cmd_title}".ljust(37)
) + f"[ {cmd_node.help_text} ]"
) + f"{{ {cmd_node.help_text}... }}"
print(help_line)
print(f" - {colorama.Fore.GREEN}clear{colorama.Style.RESET_ALL}".ljust(37) +
"Clear screen")
print(f" - {colorama.Fore.GREEN}exit{colorama.Style.RESET_ALL}".ljust(37) +
"Exit program")
print(f" - {colorama.Fore.GREEN}rem ...{colorama.Style.RESET_ALL}".ljust(37) +
"Display a comment with a timestamp")
continue
tree_node, arg_list = self.get_cmd_node(
@@ -158,8 +197,12 @@ class ChameleonCLI:
print("".ljust(18, "-") + "".ljust(10) + "".ljust(30, "-"))
for child in tree_node.children:
cmd_title = f"{colorama.Fore.GREEN}{child.name}{colorama.Style.RESET_ALL}"
help_line = (f" - {cmd_title}".ljust(37)
) + f"[ {child.help_text} ]"
if not child.cls:
help_line = (f" - {cmd_title}".ljust(37)
) + f"{{ {child.help_text}... }}"
else:
help_line = (f" - {cmd_title}".ljust(37)
) + f"{child.help_text}"
print(help_line)
continue
@@ -167,18 +210,18 @@ class ChameleonCLI:
unit.device_com = self.device_com
args_parse_result = unit.args_parser()
if args_parse_result is not None:
args: argparse.ArgumentParser = args_parse_result
args.prog = tree_node.fullname
try:
args_parse_result = args.parse_args(arg_list)
except chameleon_utils.ArgsParserError as e:
args.print_usage()
print(str(e).strip(), end="\n\n")
continue
except chameleon_utils.ParserExitIntercept:
# don't exit process.
continue
assert args_parse_result is not None
args: argparse.ArgumentParser = args_parse_result
args.prog = tree_node.fullname
try:
args_parse_result = args.parse_args(arg_list)
except chameleon_utils.ArgsParserError as e:
args.print_usage()
print(str(e).strip(), end="\n\n")
continue
except chameleon_utils.ParserExitIntercept:
# don't exit process.
continue
try:
# before process cmd, we need to do something...
if not unit.before_exec(args_parse_result):
File diff suppressed because it is too large Load Diff
+8 -4
View File
@@ -85,6 +85,11 @@ class CLITree:
self.fullname: str = fullname if fullname else name
self.children: list[CLITree] = children if children else list()
self.cls = cls
if self.help_text is None:
assert self.cls is not None
parser = self.cls().args_parser()
assert parser is not None
self.help_text = parser.description
def subgroup(self, name, help_text=None):
"""
@@ -98,16 +103,15 @@ class CLITree:
self.children.append(child)
return child
def command(self, name, help_text=None):
def command(self, name):
"""
Create a child command
:param name: Name of the command
:param help_text: Hint displayed for the command
"""
def decorator(cls):
self.children.append(
CLITree(name=name, fullname=f'{self.fullname} {name}', help_text=help_text, cls=cls))
CLITree(name=name, fullname=f'{self.fullname} {name}', cls=cls))
return cls
return decorator
@@ -160,7 +164,7 @@ class CustomNestedCompleter(NestedCompleter):
meta_dict = {}
for child_node in node.children:
if child_node.cls and child_node.cls().args_parser():
if child_node.cls:
# CLITree is a standalone command with arguments
options[child_node.name] = ArgparseCompleter(
child_node.cls().args_parser())