From: Frantisek Tobias Date: Fri, 18 Oct 2024 11:26:10 +0000 (+0200) Subject: kresctl: tab-completion: display config keywords in config completion X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=refs%2Fenvironments%2Fdocs-develop-kres-ph09xl%2Fdeployments%2F5364;p=thirdparty%2Fknot-resolver.git kresctl: tab-completion: display config keywords in config completion --- diff --git a/python/knot_resolver/client/command.py b/python/knot_resolver/client/command.py index 6c1334b1a..b0ae38ccd 100644 --- a/python/knot_resolver/client/command.py +++ b/python/knot_resolver/client/command.py @@ -139,5 +139,36 @@ class Command(ABC): raise NotImplementedError() @staticmethod - def completion(parser: argparse.ArgumentParser) -> CompWords: - return get_subparsers_words(parser._actions) # pylint: disable=W0212 + def completion(parser: argparse.ArgumentParser, args: Optional[List[str]]) -> CompWords: + words: CompWords = get_subparsers_words(parser._actions) # Get subparser words + if args is None or args == ['']: + return words + + subparsers = parser._subparsers + + if subparsers: + words = get_subparsers_words(subparsers._actions) + + for i in range(len(args)): + uarg = args[i] + subparser = get_subparser_by_name(uarg, subparsers._actions) # pylint: disable=W0212 + + # print(f"uarg: {uarg}, {args}, {words}\n") + if subparser: + try: + cmd = get_subparser_command(subparser) + subparser_args = args[i + 1 :] + words = cmd.completion(subparser, subparser_args) + except: + return get_subparsers_words(subparser._actions) + + break + elif uarg in ["-s", "--socket", "-c", "--config"]: + # Skip next argument if a known flag is detected + i += 1 + # next(uargs, None) + continue + elif uarg in ["--bash", "--space"]: + # Continue if the argument is a valid subparser + continue + return words diff --git a/python/knot_resolver/client/commands/completion.py b/python/knot_resolver/client/commands/completion.py index 3fca63149..cffd7e0df 100644 --- a/python/knot_resolver/client/commands/completion.py +++ b/python/knot_resolver/client/commands/completion.py @@ -60,32 +60,7 @@ class CompletionCommand(Command): return completion, CompletionCommand def run(self, args: CommandArgs) -> None: - subparsers = args.parser._subparsers - words: CompWords = {} - - if subparsers: - words = get_subparsers_words(subparsers._actions) - - uargs = iter(self.comp_args) - for uarg in uargs: - subparser = get_subparser_by_name(uarg, subparsers._actions) # pylint: disable=W0212 - - if subparser: - cmd: Command = get_subparser_command(subparser) - subparser_args = self.comp_args[self.comp_args.index(uarg) + 1 :] - if subparser_args or self.space: - if isinstance(cmd, ConfigCommand): - words = cmd.completion(subparser, subparser_args) - else: - words = cmd.completion(subparser) - # break - # elif uarg in ["-s", "--socket", "-c", "--config"]: - # # if arg is socket config, skip next arg - # next(uargs) - # continue - # elif uarg in words: - # # uarg is valid (complete) arg, continue - # continue + words = Command.completion(args.parser, self.comp_args) # print completion words # based on required bash/fish shell format diff --git a/python/knot_resolver/client/commands/config.py b/python/knot_resolver/client/commands/config.py index 844bed6fc..8523cf2bf 100644 --- a/python/knot_resolver/client/commands/config.py +++ b/python/knot_resolver/client/commands/config.py @@ -3,9 +3,10 @@ import sys from enum import Enum from typing import Any, Dict, List, Literal, Optional, Tuple, Type -from knot_resolver.client.command import Command, CommandArgs, CompWords, register_command +from knot_resolver.client.command import Command, CommandArgs, CompWords, register_command, get_subparser_by_name, get_subparsers_words from knot_resolver.utils.modeling.parsing import DataFormat, parse_json, try_to_parse from knot_resolver.utils.requests import request +from knot_resolver.datamodel import KresConfig class Operations(Enum): @@ -152,6 +153,24 @@ class ConfigCommand(Command): nargs="?", ) + # GET & SET config options + prop_words = _properties_words(KresConfig.json_schema()["properties"]) + for prop_key in prop_words: + get.add_argument( + prop_key, + help=prop_words[prop_key], + type=str, + nargs="?", + ) + + set.add_argument( + prop_key, + help=prop_words[prop_key], + action="store", + type=str, + nargs="?", + ) + # DELETE operation delete = config_subparsers.add_parser( "delete", help="Delete given configuration property or list item at the given index." @@ -170,15 +189,30 @@ class ConfigCommand(Command): @staticmethod def completion(parser: argparse.ArgumentParser, args: Optional[List[str]] = None) -> CompWords: - words = Command.completion(parser) - if args is None: - return words - - arg = args[-1] - config_path = arg[1:].split("/") if arg.startswith("/") else arg.split("/") - schema_props: Dict[str, Any] = KresConfig.json_schema()["properties"] - return _path_comp_words(config_path[0], config_path, schema_props) - + if args is None or len(args) <= 1: + return Command.completion(parser, args) + + words: CompWords = get_subparsers_words(parser._actions) + subparsers = parser._subparsers + + if subparsers: + for i in range(len(args)): + uarg = args[i] + subparser = get_subparser_by_name(uarg, subparsers._actions) # pylint: disable=W0212 + if subparser is not None: + subparser_words = get_subparsers_words(subparser._actions) + words = dict() + for action in subparser._actions: + if action.dest not in subparser_words: + subparser_words[action.dest] = action.help or None + + words.update(subparser_words) + + subparsers = subparser._subparsers + if not subparsers: + break + else: + break # for arg in args: # if arg in words: @@ -191,7 +225,9 @@ class ConfigCommand(Command): # return _path_comp_words(config_path[0], config_path, schema_props) # else: # break - return {} + + return words + def run(self, args: CommandArgs) -> None: if not self.operation: