diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb38024..83f8062 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,6 +2,8 @@ name: ci on: push: + branches: + - main pull_request: branches: - main diff --git a/src/mkdocstrings_handlers/zig/_internal/zig_docs_extractor.py b/src/mkdocstrings_handlers/zig/_internal/zig_docs_extractor.py index d15f45b..0ba6d32 100644 --- a/src/mkdocstrings_handlers/zig/_internal/zig_docs_extractor.py +++ b/src/mkdocstrings_handlers/zig/_internal/zig_docs_extractor.py @@ -94,7 +94,7 @@ def _parse_function(self, node: Node) -> dict | None: fn_name = self._get_node_name(node) doc_comment = self._get_doc_comments(node) if fn_name and doc_comment: - return { + result = { "node_type": "function", "name": fn_name, "doc": doc_comment, @@ -102,6 +102,12 @@ def _parse_function(self, node: Node) -> dict | None: "short_signature": self._get_short_function_signature(node), } + return_struct = self._get_return_struct(node) + if return_struct: + result["return_struct"] = return_struct + + return result + return None def _get_function_signature(self, node: Node) -> str: @@ -172,7 +178,7 @@ def _parse_field(self, node: Node) -> dict | None: field_name = None field_type = None for child in node.children: - if child.type == "identifier": + if child.type == "identifier" and not field_name: field_name = self._get_node_text(child) elif child.type == ":": continue @@ -189,6 +195,50 @@ def _parse_field(self, node: Node) -> dict | None: return None + def _get_return_struct(self, node: Node) -> dict | None: + """ + Parse structure returned from a function. + Probably recursive search for return is needed, but for we support only basic case. + """ + function_body = self._get_function_body(node) + if not function_body: + return None + + for child in function_body.children: + if child.type == "expression_statement": + return_expression = self._get_return_expression(child) + if not return_expression: + continue + + struct = self._get_struct_declaration(return_expression) + if not struct: + continue + + parsed_struct = self._parse_structure(struct) + if not parsed_struct: + continue + + parsed_struct["node_type"] = "struct" + return parsed_struct + + return None + + def _get_function_body(self, node: Node) -> Node | None: + """Get the block which represents the function's body""" + for child in node.children: + if child.type == "block": + return child + + return None + + def _get_return_expression(self, node: Node) -> Node | None: + """Check if the statement is return and return the return value""" + for child in node.children: + if child.type == "return_expression": + return child + + return None + def _main() -> None: import json # noqa: PLC0415 @@ -217,6 +267,14 @@ def _main() -> None: .y = std.math.maxInt(u32), }; }; + + /// Generic structure factory example + fn GenericStructure(comptime T: type) type { + return struct { + /// Contained value + value: T, + }; + } """ extractor = _ZigDocsExtractor(code) diff --git a/src/mkdocstrings_handlers/zig/templates/material/partials/constant.html.jinja b/src/mkdocstrings_handlers/zig/templates/material/_base/constant.html.jinja similarity index 100% rename from src/mkdocstrings_handlers/zig/templates/material/partials/constant.html.jinja rename to src/mkdocstrings_handlers/zig/templates/material/_base/constant.html.jinja diff --git a/src/mkdocstrings_handlers/zig/templates/material/partials/docstring.html.jinja b/src/mkdocstrings_handlers/zig/templates/material/_base/docstring.html.jinja similarity index 100% rename from src/mkdocstrings_handlers/zig/templates/material/partials/docstring.html.jinja rename to src/mkdocstrings_handlers/zig/templates/material/_base/docstring.html.jinja diff --git a/src/mkdocstrings_handlers/zig/templates/material/partials/fields.html.jinja b/src/mkdocstrings_handlers/zig/templates/material/_base/fields.html.jinja similarity index 100% rename from src/mkdocstrings_handlers/zig/templates/material/partials/fields.html.jinja rename to src/mkdocstrings_handlers/zig/templates/material/_base/fields.html.jinja diff --git a/src/mkdocstrings_handlers/zig/templates/material/partials/function.html.jinja b/src/mkdocstrings_handlers/zig/templates/material/_base/function.html.jinja similarity index 75% rename from src/mkdocstrings_handlers/zig/templates/material/partials/function.html.jinja rename to src/mkdocstrings_handlers/zig/templates/material/_base/function.html.jinja index bfec082..dd72035 100644 --- a/src/mkdocstrings_handlers/zig/templates/material/partials/function.html.jinja +++ b/src/mkdocstrings_handlers/zig/templates/material/_base/function.html.jinja @@ -13,6 +13,10 @@ {% endif %} - {% include "partials/parameters.html.jinja" %} + {% include "parameters.html.jinja" %} + + {% with parent = parent.return_struct %} + {% include "struct.html.jinja" %} + {% endwith %} {% endif %} \ No newline at end of file diff --git a/src/mkdocstrings_handlers/zig/templates/material/partials/heading.html.jinja b/src/mkdocstrings_handlers/zig/templates/material/_base/heading.html.jinja similarity index 100% rename from src/mkdocstrings_handlers/zig/templates/material/partials/heading.html.jinja rename to src/mkdocstrings_handlers/zig/templates/material/_base/heading.html.jinja diff --git a/src/mkdocstrings_handlers/zig/templates/material/partials/module.html.jinja b/src/mkdocstrings_handlers/zig/templates/material/_base/module.html.jinja similarity index 61% rename from src/mkdocstrings_handlers/zig/templates/material/partials/module.html.jinja rename to src/mkdocstrings_handlers/zig/templates/material/_base/module.html.jinja index 68bfa3b..f6ad861 100644 --- a/src/mkdocstrings_handlers/zig/templates/material/partials/module.html.jinja +++ b/src/mkdocstrings_handlers/zig/templates/material/_base/module.html.jinja @@ -4,18 +4,18 @@
{% with obj = data, html_id = data.path %} - {% include "partials/heading.html.jinja" %} + {% include "heading.html.jinja" %} {% with heading_level=heading_level+1 %}
{% block contents scoped %} - {% include "partials/docstring.html.jinja" %} + {% include "docstring.html.jinja" %} {% for child in data.children %} {% with parent=child %} - {% include "partials/fields.html.jinja" %} - {% include "partials/constant.html.jinja" %} - {% include "partials/struct.html.jinja" %} - {% include "partials/function.html.jinja" %} + {% include "fields.html.jinja" %} + {% include "constant.html.jinja" %} + {% include "struct.html.jinja" %} + {% include "function.html.jinja" %} {% endwith %} {% endfor %} {% endblock contents %} diff --git a/src/mkdocstrings_handlers/zig/templates/material/partials/parameters.html.jinja b/src/mkdocstrings_handlers/zig/templates/material/_base/parameters.html.jinja similarity index 100% rename from src/mkdocstrings_handlers/zig/templates/material/partials/parameters.html.jinja rename to src/mkdocstrings_handlers/zig/templates/material/_base/parameters.html.jinja diff --git a/src/mkdocstrings_handlers/zig/templates/material/_base/root.html.jinja b/src/mkdocstrings_handlers/zig/templates/material/_base/root.html.jinja index e39bcbe..5bb8e04 100644 --- a/src/mkdocstrings_handlers/zig/templates/material/_base/root.html.jinja +++ b/src/mkdocstrings_handlers/zig/templates/material/_base/root.html.jinja @@ -1 +1,5 @@ -{% include "partials/modules.html.jinja" %} +{% for child in data %} + {% with data=child %} + {% include "module.html.jinja" %} + {% endwith %} +{% endfor %} \ No newline at end of file diff --git a/src/mkdocstrings_handlers/zig/templates/material/partials/struct.html.jinja b/src/mkdocstrings_handlers/zig/templates/material/_base/struct.html.jinja similarity index 66% rename from src/mkdocstrings_handlers/zig/templates/material/partials/struct.html.jinja rename to src/mkdocstrings_handlers/zig/templates/material/_base/struct.html.jinja index 1fcdaff..c8f953b 100644 --- a/src/mkdocstrings_handlers/zig/templates/material/partials/struct.html.jinja +++ b/src/mkdocstrings_handlers/zig/templates/material/_base/struct.html.jinja @@ -1,7 +1,9 @@ -{% if parent.node_type == "struct" %} +{% if parent and parent.node_type == "struct" %}
+ {% if parent.name %} {% filter heading(heading_level, id=html_id ~ parent.name) %}{{ parent.short_signature }}{% endfilter %} - + {% endif %} + {% if parent.doc %}
{% with heading_level=heading_level + 1 %} @@ -12,10 +14,10 @@ {% for child in parent.children %} {% with parent = child, heading_level = heading_level + 1 %} - {% include "partials/fields.html.jinja" %} - {% include "partials/constant.html.jinja" %} - {% include "partials/struct.html.jinja" %} - {% include "partials/function.html.jinja" %} + {% include "fields.html.jinja" %} + {% include "constant.html.jinja" %} + {% include "struct.html.jinja" %} + {% include "function.html.jinja" %} {% endwith %} {% endfor %}
diff --git a/src/mkdocstrings_handlers/zig/templates/material/constant.html.jinja b/src/mkdocstrings_handlers/zig/templates/material/constant.html.jinja new file mode 100644 index 0000000..396239b --- /dev/null +++ b/src/mkdocstrings_handlers/zig/templates/material/constant.html.jinja @@ -0,0 +1 @@ +{% extends "_base/constant.html.jinja" %} diff --git a/src/mkdocstrings_handlers/zig/templates/material/docstring.html.jinja b/src/mkdocstrings_handlers/zig/templates/material/docstring.html.jinja new file mode 100644 index 0000000..a7ccd66 --- /dev/null +++ b/src/mkdocstrings_handlers/zig/templates/material/docstring.html.jinja @@ -0,0 +1 @@ +{% extends "_base/docstring.html.jinja" %} diff --git a/src/mkdocstrings_handlers/zig/templates/material/fields.html.jinja b/src/mkdocstrings_handlers/zig/templates/material/fields.html.jinja new file mode 100644 index 0000000..3ee1496 --- /dev/null +++ b/src/mkdocstrings_handlers/zig/templates/material/fields.html.jinja @@ -0,0 +1 @@ +{% extends "_base/fields.html.jinja" %} diff --git a/src/mkdocstrings_handlers/zig/templates/material/function.html.jinja b/src/mkdocstrings_handlers/zig/templates/material/function.html.jinja new file mode 100644 index 0000000..54bba06 --- /dev/null +++ b/src/mkdocstrings_handlers/zig/templates/material/function.html.jinja @@ -0,0 +1 @@ +{% extends "_base/function.html.jinja" %} diff --git a/src/mkdocstrings_handlers/zig/templates/material/heading.html.jinja b/src/mkdocstrings_handlers/zig/templates/material/heading.html.jinja new file mode 100644 index 0000000..0dfc02e --- /dev/null +++ b/src/mkdocstrings_handlers/zig/templates/material/heading.html.jinja @@ -0,0 +1 @@ +{% extends "_base/heading.html.jinja" %} diff --git a/src/mkdocstrings_handlers/zig/templates/material/module.html.jinja b/src/mkdocstrings_handlers/zig/templates/material/module.html.jinja new file mode 100644 index 0000000..9d8efea --- /dev/null +++ b/src/mkdocstrings_handlers/zig/templates/material/module.html.jinja @@ -0,0 +1 @@ +{% extends "_base/module.html.jinja" %} diff --git a/src/mkdocstrings_handlers/zig/templates/material/parameters.html.jinja b/src/mkdocstrings_handlers/zig/templates/material/parameters.html.jinja new file mode 100644 index 0000000..432f4d0 --- /dev/null +++ b/src/mkdocstrings_handlers/zig/templates/material/parameters.html.jinja @@ -0,0 +1 @@ +{% extends "_base/parameters.html.jinja" %} diff --git a/src/mkdocstrings_handlers/zig/templates/material/partials/modules.html.jinja b/src/mkdocstrings_handlers/zig/templates/material/partials/modules.html.jinja deleted file mode 100644 index be19382..0000000 --- a/src/mkdocstrings_handlers/zig/templates/material/partials/modules.html.jinja +++ /dev/null @@ -1,5 +0,0 @@ -{% for child in data %} - {% with data=child %} - {% include "partials/module.html.jinja" %} - {% endwith %} -{% endfor %} \ No newline at end of file diff --git a/src/mkdocstrings_handlers/zig/templates/material/struct.html.jinja b/src/mkdocstrings_handlers/zig/templates/material/struct.html.jinja new file mode 100644 index 0000000..f2fda90 --- /dev/null +++ b/src/mkdocstrings_handlers/zig/templates/material/struct.html.jinja @@ -0,0 +1 @@ +{% extends "_base/struct.html.jinja" %} diff --git a/test_zig_project/src/main.zig b/test_zig_project/src/main.zig index a3ab419..f934682 100644 --- a/test_zig_project/src/main.zig +++ b/test_zig_project/src/main.zig @@ -48,3 +48,11 @@ const std = @import("std"); /// This imports the separate module containing `root.zig`. Take a look in `build.zig` for details. const lib = @import("test_zig_project_lib"); + +/// Generic structure factory example +fn GenericStructure(comptime T: type) type { + return struct { + /// Contained value + value: T, + }; +} diff --git a/tests/test_zig_parser.py b/tests/test_zig_parser.py index e0985eb..5f34e06 100644 --- a/tests/test_zig_parser.py +++ b/tests/test_zig_parser.py @@ -12,7 +12,7 @@ def test_parser() -> None: /// Adds two numbers. fn add(a: i32, b: i32) i32 { - return a b; + return a + b; } /// A constant named PI. @@ -33,6 +33,14 @@ def test_parser() -> None: pub fn main() void { std.print("Hello, world!\n"); } + + /// Generic structure factory example + fn GenericStructure(comptime T: type) type { + return struct { + /// Contained value + value: T, + }; + } """ parsed = ZigDocsExtractor(zig_code).get_docs() @@ -88,5 +96,27 @@ def test_parser() -> None: "signature": "pub fn main() void", "short_signature": "pub fn main", }, + { + "node_type": "function", + "name": "GenericStructure", + "doc": "Generic structure factory example", + "signature": "fn GenericStructure(comptime T: type) type", + "short_signature": "fn GenericStructure", + "return_struct": { + "node_type": "struct", + "children": [ + { + "node_type": "fields", + "children": [ + { + "doc": "Contained value", + "name": "value", + "type": "T", + }, + ], + }, + ], + }, + }, ], }