]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
kresctl: tab-completion: enable config completion
authorFrantisek Tobias <frantisek.tobias@nic.cz>
Tue, 15 Oct 2024 10:40:23 +0000 (12:40 +0200)
committerAleš Mrázek <ales.mrazek@nic.cz>
Fri, 20 Dec 2024 21:24:22 +0000 (22:24 +0100)
python/knot_resolver/client/commands/config.py

index 52df39c41bb62b34c45d7bee22f6722fb37b8e3e..dbf6ccaa16d0f51ffb67fab36bef4b3d92fdf36d 100644 (file)
@@ -1,9 +1,10 @@
 import argparse
 import sys
 from enum import Enum
-from typing import List, Literal, Optional, Tuple, Type
+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, get_subparsers_words, register_command
+from knot_resolver.datamodel import KresConfig
 from knot_resolver.utils.modeling.parsing import DataFormat, parse_json, try_to_parse
 from knot_resolver.utils.requests import request
 
@@ -22,54 +23,53 @@ def operation_to_method(operation: Operations) -> Literal["PUT", "GET", "DELETE"
     return "GET"
 
 
-# def _properties_words(props: Dict[str, Any]) -> CompWords:
-#     words: CompWords = {}
-#     for name, prop in props.items():
-#         words[name] = prop["description"] if "description" in prop else None
-#     return words
-
-
-# def _path_comp_words(node: str, nodes: List[str], props: Dict[str, Any]) -> CompWords:
-#     i = nodes.index(node)
-#     ln = len(nodes[i:])
-
-#     # if node is last in path, return all possible words on thi level
-#     if ln == 1:
-#         return _properties_words(props)
-#     # if node is valid
-#     elif node in props:
-#         node_schema = props[node]
-
-#         if "anyOf" in node_schema:
-#             for item in node_schema["anyOf"]:
-#                 print(item)
-
-#         elif "type" not in node_schema:
-#             pass
-
-#         elif node_schema["type"] == "array":
-#             if ln > 2:
-#                 # skip index for item in array
-#                 return _path_comp_words(nodes[i + 2], nodes, node_schema["items"]["properties"])
-#             if "enum" in node_schema["items"]:
-#                 print(node_schema["items"]["enum"])
-#             return {"0": "first array item", "-": "last array item"}
-#         elif node_schema["type"] == "object":
-#             if "additionalProperties" in node_schema:
-#                 print(node_schema)
-#             return _path_comp_words(nodes[i + 1], nodes, node_schema["properties"])
-#         return {}
-
-#         # arrays/lists must be handled sparately
-#         if node_schema["type"] == "array":
-#             if ln > 2:
-#                 # skip index for item in array
-#                 return _path_comp_words(nodes[i + 2], nodes, node_schema["items"]["properties"])
-#             return {"0": "first array item", "-": "last array item"}
-#         return _path_comp_words(nodes[i + 1], nodes, node_schema["properties"])
-#     else:
-#         # if node is not last or valid, value error
-#         raise ValueError(f"unknown config path node: {node}")
+def _properties_words(props: Dict[str, Any]) -> CompWords:
+    words: CompWords = {}
+    for name, prop in props.items():
+        words[name] = prop["description"] if "description" in prop else None
+    return words
+
+
+def _path_comp_words(node: str, nodes: List[str], props: Dict[str, Any]) -> CompWords:  # noqa: PLR0911, PLR0912
+    i = nodes.index(node)
+    ln = len(nodes[i:])
+
+    # if node is last in path, return all possible words on thi level
+    if ln == 1:
+        return _properties_words(props)
+    # if node is valid
+    if node in props:
+        node_schema = props[node]
+
+        if "anyOf" in node_schema:
+            for item in node_schema["anyOf"]:
+                print(item)
+
+        elif "type" not in node_schema:
+            pass
+
+        elif node_schema["type"] == "array":
+            if ln > 2:
+                # skip index for item in array
+                return _path_comp_words(nodes[i + 2], nodes, node_schema["items"]["properties"])
+            if "enum" in node_schema["items"]:
+                print(node_schema["items"]["enum"])
+            return {"0": "first array item", "-": "last array item"}
+        elif node_schema["type"] == "object":
+            if "additionalProperties" in node_schema:
+                print(node_schema)
+            return _path_comp_words(nodes[i + 1], nodes, node_schema["properties"])
+        # return {}
+
+        # arrays/lists must be handled sparately
+        if node_schema["type"] == "array":
+            if ln > 2:
+                # skip index for item in array
+                return _path_comp_words(nodes[i + 2], nodes, node_schema["items"]["properties"])
+            return {"0": "first array item", "-": "last array item"}
+        return _path_comp_words(nodes[i + 1], nodes, node_schema["properties"])
+    # if node is not last or valid, value error
+    raise ValueError(f"unknown config path node: {node}")
 
 
 @register_command
@@ -170,7 +170,14 @@ class ConfigCommand(Command):
 
     @staticmethod
     def completion(args: List[str], parser: argparse.ArgumentParser) -> CompWords:
-        # words = parser_words(parser._actions)  # pylint: disable=W0212
+        words = get_subparsers_words(parser._actions)  # noqa: SLF001
+        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)
 
         # for arg in args:
         #     if arg in words: