Skip to content

Commit ecefc80

Browse files
authored
feat: add supports for scripts (#51)
* fix: script does not have kind * fix: tree-sitter query fixes * fix: do not check for property SetAccess for private * feat: add support for scripts * doc: update namespace contents * fix: select only the first comment block as docstring
1 parent 4d7557e commit ecefc80

File tree

12 files changed

+268
-23
lines changed

12 files changed

+268
-23
lines changed

docs/snippets/+mynamespace/mynamespace.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
classA.m
99
classB.m
1010
typed_function.m
11+
myscript.m
1112
```
1213

1314
=== ":material-file-code: `readme.md`"
@@ -32,4 +33,10 @@
3233

3334
```matlab
3435
--8<-- "docs/snippets/+mynamespace/typed_function.m"
35-
```
36+
```
37+
38+
=== ":material-file-code: `myscript.m`"
39+
40+
```matlab
41+
--8<-- "docs/snippets/+mynamespace/myscript.m"
42+
```

docs/snippets/+mynamespace/myscript.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
% This is an example script.
2+
3+
% This is a paragraph.
4+
disp('hello world');

docs/usage/configuration/headings.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,7 @@ This option will prefix items in the ToC with
595595
<code class="doc-symbol doc-symbol-function"></code>,
596596
<code class="doc-symbol doc-symbol-method"></code>,
597597
<code class="doc-symbol doc-symbol-class"></code>,
598+
<code class="doc-symbol doc-symbol-script"></code>,
598599
<code class="doc-symbol doc-symbol-namespace"></code> or.
599600
<code class="doc-symbol doc-symbol-folder"></code> types.
600601
See also [`show_symbol_type_heading`][show_symbol_type_heading].
@@ -621,6 +622,7 @@ plugins:
621622
<ul style="list-style: none;">
622623
<li><code class="doc-symbol doc-symbol-folder"></code> folder</li>
623624
<li><code class="doc-symbol doc-symbol-namespace"></code> namespace</li>
625+
<li><code class="doc-symbol doc-symbol-script"></code> script</li>
624626
<li><code class="doc-symbol doc-symbol-function"></code> function</li>
625627
<li><code class="doc-symbol doc-symbol-class"></code> Class
626628
<ul style="list-style: none;">
@@ -635,6 +637,7 @@ plugins:
635637
<ul style="list-style: none;">
636638
<li>folder</li>
637639
<li>namespace</li>
640+
<li>script</li>
638641
<li>function</li>
639642
<li>Class
640643
<ul style="list-style: none;">

docs/usage/configuration/members.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,16 +169,15 @@ To simplify the definition here, any property or method that do not have attribu
169169
```mermaid
170170
flowchart TD
171171
a[Access=public]
172-
sg[SetAccess=public/immutable and GetAccess=public]
172+
ga[GetAccess=public]
173173
174174
public[not private member]
175175
private[private member]
176176
a -- yes --> public
177177
a -- no --> private
178-
a -- "not specified" --> sg
179-
sg -- no --> private
180-
sg -- yes --> public
181-
178+
a -- "not specified" --> ga
179+
ga -- no --> private
180+
ga -- yes --> public
182181
```
183182

184183
This takes precedence over [`members`][] and [`filters`][], and also applies for [`inherited_members`][]. This means that for any private member to be shown, `private_members` must be enabled, and further selection is possible via [`members`][] and [`filters`][]. Private members will be labeled with it access attribute setting, this can be disabled in [`show_labels`][].

scripts/copy_and_update_python_templates.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def copy_template(
112112
)
113113

114114
## Copy children template
115-
copy_template(
115+
(targetFile, content) = copy_template(
116116
"_base/children.html.jinja",
117117
"children.html.jinja",
118118
{
@@ -124,3 +124,32 @@ def copy_template(
124124
"{% elif child.is_module and config.show_submodules %}": "{% elif (child.is_namespace and config.show_subnamespaces) or obj.is_folder %}",
125125
},
126126
)
127+
128+
129+
scripts = """{% if obj.is_module %}
130+
{% with scripts = obj.scripts|filter_objects(
131+
filters=config.filters,
132+
members_list=members_list,
133+
keep_no_docstrings=config.show_if_no_docstring,
134+
) %}
135+
{% if scripts %}
136+
{% if config.show_category_heading %}
137+
{% filter heading(heading_level, id=html_id ~ "-scripts") %}Scripts{% endfilter %}
138+
{% endif %}
139+
{% with heading_level = heading_level + extra_level %}
140+
{% for script in scripts|order_members(config.members_order.alphabetical, members_list) %}
141+
{% if members_list is not none or (not script.is_alias or script.is_public) %}
142+
{% include script|get_template with context %}
143+
{% endif %}
144+
{% endfor %}
145+
{% endwith %}
146+
{% endif %}
147+
{% endwith %}
148+
{% endif %}
149+
150+
151+
"""
152+
153+
index = content.find("{% if config.show_subnamespaces or obj.is_folder %}")
154+
content = content[:index] + scripts[:-1] + content[index:]
155+
targetFile.write_text(content)

src/mkdocstrings_handlers/matlab/collect.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from collections import defaultdict, deque
44
from copy import copy, deepcopy
55
from pathlib import Path
6-
from typing import Mapping, Sequence, Callable, TypeVar
6+
from typing import Any, Mapping, Sequence, Callable, TypeVar
77

88
from _griffe.collections import LinesCollection as GLC, ModulesCollection
99
from _griffe.docstrings.models import (
@@ -716,9 +716,9 @@ def _collect_parent(self, path: Path) -> _ParentGrabber | None:
716716
parent = None
717717
return parent
718718

719-
def _collect_path(self, path: Path) -> MatlabMixin:
719+
def _collect_path(self, path: Path, **kwargs: Any) -> MatlabMixin:
720720
file = FileParser(path)
721-
model = file.parse(path_collection=self._path_collection)
721+
model = file.parse(path_collection=self._path_collection, **kwargs)
722722
self._lines_collection[path] = file.content.split("\n")
723723
return model
724724

src/mkdocstrings_handlers/matlab/enums.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,23 @@
11
from enum import Enum
2+
from _griffe.enumerations import Kind as GriffeKind
3+
4+
5+
class Kind(str, Enum):
6+
"""
7+
An enumeration representing different kinds of MATLAB code elements.
8+
This enumeration is a subclass of the Griffe `Kind` enumeration, and extends it with additional values.
9+
"""
10+
MODULE = "module"
11+
"""Modules."""
12+
CLASS = "class"
13+
"""Classes."""
14+
FUNCTION = "function"
15+
"""Functions and methods."""
16+
ATTRIBUTE = "attribute"
17+
"""Attributes and properties."""
18+
ALIAS = "alias"
19+
"""Aliases (imported objects)."""
20+
SCRIPT = "script"
221

322

423
class ParameterKind(str, Enum):

src/mkdocstrings_handlers/matlab/models.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
Parameter as GriffeParameter,
1818
)
1919

20-
from mkdocstrings_handlers.matlab.enums import AccessEnum, ParameterKind
20+
from mkdocstrings_handlers.matlab.enums import Kind, AccessEnum, ParameterKind
2121

2222
if TYPE_CHECKING:
2323
from mkdocstrings_handlers.matlab.collect import PathCollection
@@ -151,6 +151,14 @@ def __init__(
151151
def namespaces(self) -> dict[str, "Namespace"]:
152152
return {}
153153

154+
@property
155+
def scripts(self) -> dict[str, "Script"]:
156+
return {name: member for name, member in self.all_members.items() if member.kind is Kind.SCRIPT} # type: ignore[misc]
157+
158+
@property
159+
def is_script(self) -> bool:
160+
return False
161+
154162
@property
155163
def is_namespace(self) -> bool:
156164
return False
@@ -280,9 +288,15 @@ class Script(MatlabMixin, PathMixin, MatlabObject):
280288
This class inherits from `PathMixin` and `MatlabObject` to provide
281289
functionality specific to MATLAB scripts.
282290
"""
291+
kind = Kind.SCRIPT # type: ignore
283292

284-
pass
293+
def __init__(self, *args: Any, **kwargs: Any) -> None:
294+
super().__init__(*args, **kwargs)
295+
self.extra["mkdocstrings"] = {"template": "script.html.jinja"}
285296

297+
@property
298+
def is_script(self) -> bool:
299+
return True
286300

287301
class Class(MatlabMixin, PathMixin, GriffeClass, MatlabObject):
288302
"""
@@ -442,13 +456,9 @@ def __init__(
442456
@property
443457
def Private(self) -> bool:
444458
private = self.Access != AccessEnum.public
445-
set_private = (
446-
self.SetAccess != AccessEnum.public
447-
and self.SetAccess != AccessEnum.immutable
448-
)
449459
get_private = self.GetAccess != AccessEnum.public
450-
return private or set_private or get_private
451-
460+
return private or get_private
461+
452462
@property
453463
def is_private(self) -> bool:
454464
return self.Private or self.Hidden

src/mkdocstrings_handlers/matlab/templates/material/children.html.jinja

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,27 @@ Context:
9999
{% endif %}
100100
{% endwith %}
101101

102+
{% if obj.is_module %}
103+
{% with scripts = obj.scripts|filter_objects(
104+
filters=config.filters,
105+
members_list=members_list,
106+
keep_no_docstrings=config.show_if_no_docstring,
107+
) %}
108+
{% if scripts %}
109+
{% if config.show_category_heading %}
110+
{% filter heading(heading_level, id=html_id ~ "-scripts") %}Scripts{% endfilter %}
111+
{% endif %}
112+
{% with heading_level = heading_level + extra_level %}
113+
{% for script in scripts|order_members(config.members_order.alphabetical, members_list) %}
114+
{% if members_list is not none or (not script.is_alias or script.is_public) %}
115+
{% include script|get_template with context %}
116+
{% endif %}
117+
{% endfor %}
118+
{% endwith %}
119+
{% endif %}
120+
{% endwith %}
121+
{% endif %}
122+
102123
{% if config.show_subnamespaces or obj.is_folder %}
103124
{% with modules = obj.modules|filter_objects(
104125
filters=config.filters,
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
{#- Template for MATLAB scripts.
2+
3+
This template renders a MATLAB script.
4+
5+
Context:
6+
script (mkdocstrings_handlers.matlab.models.Script): The Script to render.
7+
root (bool): Whether this is the root object, injected with `:::` in a Markdown page.
8+
heading_level (int): The HTML heading level to use.
9+
config (dict): The configuration options.
10+
-#}
11+
12+
{% block logs scoped %}
13+
{#- Logging block.
14+
15+
This block can be used to log debug messages, deprecation messages, warnings, etc.
16+
-#}
17+
{{ log.debug("Rendering " + script.path) }}
18+
{% endblock logs %}
19+
20+
<div class="doc doc-object doc-function">
21+
{% with obj = script, html_id = script.path %}
22+
23+
{% if root %}
24+
{% set show_full_path = config.show_root_full_path %}
25+
{% set root_members = True %}
26+
{% elif root_members %}
27+
{% set show_full_path = config.show_root_members_full_path or config.show_object_full_path %}
28+
{% set root_members = False %}
29+
{% else %}
30+
{% set show_full_path = config.show_object_full_path %}
31+
{% endif %}
32+
33+
{% set script_name = script.path if show_full_path else script.name %}
34+
35+
{% if not root or config.show_root_heading %}
36+
{% filter heading(
37+
heading_level,
38+
role="function",
39+
id=html_id,
40+
class="doc doc-heading",
41+
toc_label=('<code class="doc-symbol doc-symbol-toc doc-symbol-script"></code>&nbsp;'|safe if config.show_symbol_type_toc else '') + script.name,
42+
) %}
43+
44+
{% block heading scoped %}
45+
{#- Heading block.
46+
47+
This block renders the heading for the function.
48+
-#}
49+
{% if config.show_symbol_type_heading %}<code class="doc-symbol doc-symbol-heading doc-symbol-script"></code>{% endif %}
50+
{% if config.separate_signature %}
51+
<span class="doc doc-object-name doc-function-name">{{ script_name }}</span>
52+
{% else %}
53+
{%+ filter highlight(language="matlab", inline=True) %}
54+
{{ script_name }}
55+
{% endfilter %}
56+
{% endif %}
57+
{% endblock heading %}
58+
59+
{% block labels scoped %}
60+
{#- Labels block.
61+
62+
This block renders the labels for the script.
63+
-#}
64+
{% with labels = script.labels %}
65+
{% include "labels"|get_template with context %}
66+
{% endwith %}
67+
{% endblock labels %}
68+
69+
{% endfilter %}
70+
71+
{% block signature scoped %}
72+
{#- Signature block.
73+
74+
This block renders the signature for the script.
75+
-#}
76+
{% if config.separate_signature %}
77+
{% filter format_signature(script, config.line_length, crossrefs=config.signature_crossrefs) %}
78+
{{ script.name }}
79+
{% endfilter %}
80+
{% endif %}
81+
{% endblock signature %}
82+
83+
{% else %}
84+
85+
{% if config.show_root_toc_entry %}
86+
{% filter heading(heading_level,
87+
role="function",
88+
id=html_id,
89+
toc_label=('<code class="doc-symbol doc-symbol-toc doc-symbol-script"></code>&nbsp;'|safe if config.show_symbol_type_toc else '') + script.name,
90+
hidden=True,
91+
) %}
92+
{% endfilter %}
93+
{% endif %}
94+
{% set heading_level = heading_level - 1 %}
95+
{% endif %}
96+
97+
<div class="doc doc-contents {% if root %}first{% endif %}">
98+
{% block contents scoped %}
99+
{#- Contents block.
100+
101+
This block renders the contents of the script.
102+
It contains other blocks that users can override.
103+
Overriding the contents block allows to rearrange the order of the blocks.
104+
-#}
105+
{% block docstring scoped %}
106+
{#- Docstring block.
107+
108+
This block renders the docstring for the script.
109+
-#}
110+
{% with docstring_sections = script.docstring.parsed %}
111+
{% include "docstring"|get_template with context %}
112+
{% endwith %}
113+
{% endblock docstring %}
114+
115+
{% block source scoped %}
116+
{#- Source block.
117+
118+
This block renders the source code for the script.
119+
-#}
120+
{% if config.show_source and script.source %}
121+
<details class="quote">
122+
<summary>{{ lang.t("Source code in") }} <code>
123+
{%- if script.relative_filepath.is_absolute() -%}
124+
{{ script.relative_package_filepath }}
125+
{%- else -%}
126+
{{ script.relative_filepath }}
127+
{%- endif -%}
128+
</code></summary>
129+
{{ script.source|highlight(language="python", linestart=script.lineno or 0, linenums=True) }}
130+
</details>
131+
{% endif %}
132+
{% endblock source %}
133+
{% endblock contents %}
134+
</div>
135+
136+
{% endwith %}
137+
</div>

src/mkdocstrings_handlers/matlab/templates/material/style.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,12 @@ code.doc-symbol-property {
2424
code.doc-symbol-property::after {
2525
content: "prop";
2626
}
27+
28+
code.doc-symbol-script {
29+
color: #d0bf3d;
30+
background-color: #fff8a87b;
31+
}
32+
33+
code.doc-symbol-script::after {
34+
content: "prog";
35+
}

0 commit comments

Comments
 (0)