]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
kresctl: tab-completion: implement suggestions/completion for first argument docs-develop-kres-ph09xl/deployments/5289
authorFrantisek Tobias <frantisek.tobias@nic.cz>
Mon, 7 Oct 2024 11:51:46 +0000 (13:51 +0200)
committerFrantisek Tobias <frantisek.tobias@nic.cz>
Tue, 8 Oct 2024 08:05:32 +0000 (10:05 +0200)
python/knot_resolver/client/commands/cache.py
python/knot_resolver/client/commands/completion.py

index 60417eec5df7272e531893526a8400a93b4672b7..ef64302b30cfeb74fac71171aee6d1c2a358ac66 100644 (file)
@@ -8,6 +8,7 @@ from knot_resolver.datamodel.cache_schema import CacheClearRPCSchema
 from knot_resolver.utils.modeling.exceptions import AggregateDataValidationError, DataValidationError
 from knot_resolver.utils.modeling.parsing import DataFormat, parse_json
 from knot_resolver.utils.requests import request
+from argparse import _SubParsersAction
 
 
 class CacheOperations(Enum):
@@ -99,7 +100,16 @@ class CacheCommand(Command):
 
     @staticmethod
     def completion(args: List[str], parser: argparse.ArgumentParser) -> CompWords:
-        return {}
+        words = dict()
+        for action in parser._actions:
+            if isinstance(action, _SubParsersAction):
+                if action.choices is not None:
+                    for choice in action.choices:
+                        words[choice] = action.choices.get(choice)
+            else:
+                for opt in action.option_strings:
+                    words[opt] = action.help
+        return words
 
     def run(self, args: CommandArgs) -> None:
         if not self.operation:
index 05fdded82a81adf5d763f5e6e4c05acdffa8d2d3..23871afd7be4839a950f7f05e81834ba639f38c6 100644 (file)
@@ -3,6 +3,7 @@ from enum import Enum
 from typing import List, Tuple, Type
 
 from knot_resolver.client.command import Command, CommandArgs, CompWords, register_command
+from argparse import _SubParsersAction
 
 
 class Shells(Enum):
@@ -10,6 +11,38 @@ class Shells(Enum):
     FISH = 1
 
 
+def parser_words(actions):
+    words = dict()
+    for action in actions:
+        if isinstance(action, _SubParsersAction):
+            if action.choices is not None:
+                for choice in action.choices:
+                    words[choice] = action.choices.get(choice)
+        else:
+            for opt in action.option_strings:
+                words[opt] = action.help
+
+    return words
+
+
+def subparser_by_name(uarg: str, actions) -> argparse.ArgumentParser | None:
+    for action in actions:
+        if isinstance(action, _SubParsersAction):
+            if action.choices is not None:
+                for choice in action.choices:
+                    # if uarg == choice:
+                    if uarg in choice:
+                        return  action.choices.get(choice)
+    return None
+
+
+def subparser_command(subparser: argparse.ArgumentParser) -> Command:
+    com_class: Command | None = subparser._defaults.get("command")
+    # NOTE: This is just a temporary bandage to silence pyright
+    assert(com_class is not None)
+    return com_class
+
+
 @register_command
 class CompletionCommand(Command):
     def __init__(self, namespace: argparse.Namespace) -> None:
@@ -57,39 +90,40 @@ class CompletionCommand(Command):
         return words
 
     def run(self, args: CommandArgs) -> None:
-        pass
-        # subparsers = args.parser._subparsers
-        # words: CompWords = {}
-
-        # if subparsers:
-        #     words = parser_words(subparsers._actions)
-
-        #     uargs = iter(self.comp_args)
-        #     for uarg in uargs:
-        #         subparser = subparser_by_name(uarg, subparsers._actions)  # pylint: disable=W0212
-
-        #         if subparser:
-        #             cmd: Command = subparser_command(subparser)
-        #             subparser_args = self.comp_args[self.comp_args.index(uarg) + 1 :]
-        #             if subparser_args:
-        #                 words = cmd.completion(subparser_args, subparser)
-        #             break
-        #         elif uarg in ["-s", "--socket"]:
-        #             # if arg is socket config, skip next arg
-        #             next(uargs)
-        #             continue
-        #         elif uarg in words:
-        #             # uarg is walid arg, continue
-        #             continue
-        #         else:
-        #             raise ValueError(f"unknown argument: {uarg}")
-
-        # # print completion words
-        # # based on required bash/fish shell format
-        # if self.shell == Shells.BASH:
-        #     print(" ".join(words))
-        # elif self.shell == Shells.FISH:
-        #     # TODO: FISH completion implementation
-        #     pass
-        # else:
-        #     raise ValueError(f"unexpected value of {Shells}: {self.shell}")
+        subparsers = args.parser._subparsers
+        words: CompWords = {}
+
+        if subparsers:
+            words = parser_words(subparsers._actions)
+
+            uargs = iter(self.comp_args)
+            # skip kresctl
+            next(uargs)
+            for uarg in uargs:
+                subparser = subparser_by_name(uarg, subparsers._actions)  # pylint: disable=W0212
+
+                if subparser:
+                    cmd: Command = subparser_command(subparser)
+                    subparser_args = self.comp_args[self.comp_args.index(uarg) + 1 :]
+                    if subparser_args:
+                        words = cmd.completion(subparser_args, subparser)
+                    break
+                elif uarg in ["-s", "--socket"]:
+                    # if arg is socket config, skip next arg
+                    next(uargs)
+                    continue
+                elif uarg in words:
+                    # uarg is walid arg, continue
+                    continue
+                else:
+                    raise ValueError(f"unknown argument: {uarg}")
+
+        # print completion words
+        # based on required bash/fish shell format
+        if self.shell == Shells.BASH:
+            print(" ".join(words))
+        elif self.shell == Shells.FISH:
+            # TODO: FISH completion implementation
+            pass
+        else:
+            raise ValueError(f"unexpected value of {Shells}: {self.shell}")