Skip to content

Commit

Permalink
fix: Make ids of Markdown sub-documents prefixed with the parent item id
Browse files Browse the repository at this point in the history
Issue #186: #186
Issue #193: #193
PR #199: #199
  • Loading branch information
oprypin authored Dec 22, 2020
1 parent edfbe51 commit d493d33
Show file tree
Hide file tree
Showing 15 changed files with 89 additions and 26 deletions.
57 changes: 55 additions & 2 deletions src/mkdocstrings/handlers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,23 +128,26 @@ def do_any(seq: Sequence, attribute: str = None) -> bool:
return any(_[attribute] for _ in seq)


def do_convert_markdown(md: Markdown, text: str, heading_level: int) -> Markup:
def do_convert_markdown(md: Markdown, text: str, heading_level: int, html_id: str = "") -> Markup:
"""
Render Markdown text; for use inside templates.
Arguments:
md: A `markdown.Markdown` instance.
text: The text to convert.
heading_level: The base heading level to start all Markdown headings from.
html_id: The HTML id of the element that's considered the parent of this element.
Returns:
An HTML string.
"""
md.treeprocessors["mkdocstrings_headings"].shift_by = heading_level
md.treeprocessors["mkdocstrings_ids"].id_prefix = html_id and html_id + "--"
try: # noqa: WPS501 (no except)
return Markup(md.convert(text))
finally:
md.treeprocessors["mkdocstrings_headings"].shift_by = 0
md.treeprocessors["mkdocstrings_ids"].id_prefix = ""
md.reset()


Expand Down Expand Up @@ -221,7 +224,10 @@ def update_env(self, md: Markdown, config: dict) -> None:
of [mkdocstrings.plugin.MkdocstringsPlugin.on_config][] to see what's in this dictionary.
"""
# Re-instantiate md: see https://github.com/tomchristie/mkautodoc/issues/14
md = Markdown(extensions=config["mdx"] + [ShiftHeadingsExtension()], extension_configs=config["mdx_configs"])
md = Markdown(
extensions=config["mdx"] + [ShiftHeadingsExtension(), PrefixIdsExtension()],
extension_configs=config["mdx_configs"],
)

self.env.filters["convert_markdown"] = functools.partial(do_convert_markdown, md)

Expand Down Expand Up @@ -369,6 +375,53 @@ def teardown(self):
self._handlers.clear()


class _IdPrependingTreeprocessor(Treeprocessor):
def __init__(self, md, id_prefix: str):
super().__init__(md)
self.id_prefix = id_prefix

def run(self, root: Element): # noqa: WPS231 (not complex)
if not self.id_prefix:
return
for el in root.iter():
id_attr = el.get("id")
if id_attr:
el.set("id", self.id_prefix + id_attr)

href_attr = el.get("href")
if href_attr and href_attr.startswith("#"):
el.set("href", "#" + self.id_prefix + href_attr[1:])

name_attr = el.get("name")
if name_attr:
el.set("name", self.id_prefix + name_attr)

if el.tag == "label":
for_attr = el.get("for")
if for_attr:
el.set("for", self.id_prefix + for_attr)


class PrefixIdsExtension(Extension):
"""Prepend the configured prefix to IDs of all HTML elements."""

treeprocessor_priority = 4 # Right after 'toc'.

def extendMarkdown(self, md: Markdown) -> None: # noqa: N802 (casing: parent method's name)
"""
Register the extension, with a treeprocessor under the name 'mkdocstrings_ids'.
Arguments:
md: A `markdown.Markdown` instance.
"""
md.registerExtension(self)
md.treeprocessors.register(
_IdPrependingTreeprocessor(md, ""),
"mkdocstrings_ids",
self.treeprocessor_priority,
)


class _HeadingShiftingTreeprocessor(Treeprocessor):
def __init__(self, md, shift_by: int):
super().__init__(md)
Expand Down
8 changes: 5 additions & 3 deletions src/mkdocstrings/templates/python/material/attribute.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{% if config.show_if_no_docstring or attribute.has_contents %}

<div class="doc doc-object doc-attribute">
{% with html_id = attribute.path %}

{% if not root or config.show_root_heading %}

Expand All @@ -16,7 +17,7 @@
{% endif %}

<h{{ heading_level }}
id="{{ attribute.path }}"
id="{{ html_id }}"
class="doc doc-heading"
data-toc-label="{{ attribute.name }}">

Expand All @@ -34,8 +35,8 @@
{% else %}
{% if config.show_root_toc_entry %}
<h{{ heading_level }} class="hidden-toc"
href="#{{ attribute.path }}"
id="{{ attribute.path }}"
href="#{{ html_id }}"
id="{{ html_id }}"
data-toc-label="{{ attribute.path }}"
style="visibility: hidden; position: absolute;">
</h{{ heading_level }}>
Expand All @@ -49,6 +50,7 @@
{% endwith %}
</div>

{% endwith %}
</div>

{% endif %}
2 changes: 1 addition & 1 deletion src/mkdocstrings/templates/python/material/attributes.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<tr>
<td><code>{{ attribute.name }}</code></td>
<td><code>{{ attribute.annotation }}</code></td>
<td>{{ attribute.description|convert_markdown(heading_level) }}</td>
<td>{{ attribute.description|convert_markdown(heading_level, html_id) }}</td>
</tr>
{% endfor %}
</tbody>
Expand Down
8 changes: 5 additions & 3 deletions src/mkdocstrings/templates/python/material/class.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{% if config.show_if_no_docstring or class.has_contents %}

<div class="doc doc-object doc-class">
{% with html_id = class.path %}

{% if not root or config.show_root_heading %}

Expand All @@ -16,7 +17,7 @@
{% endif %}

<h{{ heading_level }}
id="{{ class.path }}"
id="{{ html_id }}"
class="doc doc-heading"
data-toc-label="{{ class.name }}">

Expand All @@ -31,8 +32,8 @@
{% else %}
{% if config.show_root_toc_entry %}
<h{{ heading_level }} class="hidden-toc"
href="#{{ class.path }}"
id="{{ class.path }}"
href="#{{ html_id }}"
id="{{ html_id }}"
data-toc-label="{{ class.path }}"
style="visibility: hidden; position: absolute;">
</h{{ heading_level }}>
Expand All @@ -59,6 +60,7 @@
{% endwith %}
</div>

{% endwith %}
</div>

{% endif %}
2 changes: 1 addition & 1 deletion src/mkdocstrings/templates/python/material/docstring.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{% if docstring_sections %}
{% for section in docstring_sections %}
{% if section.type == "markdown" %}
{{ section.value|convert_markdown(heading_level) }}
{{ section.value|convert_markdown(heading_level, html_id) }}
{% elif section.type == "attributes" %}
{% with attributes = section.value %}
{% include "attributes.html" with context %}
Expand Down
2 changes: 1 addition & 1 deletion src/mkdocstrings/templates/python/material/examples.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<p><strong>Examples:</strong></p>
{% for section_type, sub_section in examples %}
{% if section_type == "markdown" %}
{{ sub_section|convert_markdown(heading_level) }}
{{ sub_section|convert_markdown(heading_level, html_id) }}
{% elif section_type == "examples" %}
{{ sub_section|highlight(language="python", line_nums=False) }}
{% endif %}
Expand Down
2 changes: 1 addition & 1 deletion src/mkdocstrings/templates/python/material/exceptions.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
{% for exception in exceptions %}
<tr>
<td><code>{{ exception.annotation }}</code></td>
<td>{{ exception.description|convert_markdown(heading_level) }}</td>
<td>{{ exception.description|convert_markdown(heading_level, html_id) }}</td>
</tr>
{% endfor %}
</tbody>
Expand Down
8 changes: 5 additions & 3 deletions src/mkdocstrings/templates/python/material/function.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{% if config.show_if_no_docstring or function.has_contents %}

<div class="doc doc-object doc-function">
{% with html_id = function.path %}

{% if not root or config.show_root_heading %}

Expand All @@ -16,7 +17,7 @@
{% endif %}

<h{{ heading_level }}
id="{{ function.path }}"
id="{{ html_id }}"
class="doc doc-heading"
data-toc-label="{{ function.name }}()">

Expand All @@ -34,8 +35,8 @@
{% else %}
{% if config.show_root_toc_entry %}
<h{{ heading_level }} class="hidden-toc"
href="#{{ function.path }}"
id="{{ function.path }}"
href="#{{ html_id }}"
id="{{ html_id }}"
data-toc-label="{{ function.path }}"
style="visibility: hidden; position: absolute;">
</h{{ heading_level }}>
Expand All @@ -56,6 +57,7 @@
{% endif %}
</div>

{% endwith %}
</div>

{% endif %}
8 changes: 5 additions & 3 deletions src/mkdocstrings/templates/python/material/method.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{% if config.show_if_no_docstring or method.has_contents %}

<div class="doc doc-object doc-method">
{% with html_id = method.path %}

{% if not root or config.show_root_heading %}

Expand All @@ -16,7 +17,7 @@
{% endif %}

<h{{ heading_level }}
id="{{ method.path }}"
id="{{ html_id }}"
class="doc doc-heading"
data-toc-label="{{ method.name }}()">

Expand All @@ -34,8 +35,8 @@
{% else %}
{% if config.show_root_toc_entry %}
<h{{ heading_level }} class="hidden-toc"
href="#{{ method.path }}"
id="{{ method.path }}"
href="#{{ html_id }}"
id="{{ html_id }}"
data-toc-label="{{ method.path }}"
style="visibility: hidden; position: absolute;">
</h{{ heading_level }}>
Expand All @@ -56,6 +57,7 @@
{% endif %}
</div>

{% endwith %}
</div>

{% endif %}
8 changes: 5 additions & 3 deletions src/mkdocstrings/templates/python/material/module.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{% if config.show_if_no_docstring or module.has_contents %}

<div class="doc doc-object doc-module">
{% with html_id = module.path %}

{% if not root or config.show_root_heading %}

Expand All @@ -16,7 +17,7 @@
{% endif %}

<h{{ heading_level }}
id="{{ module.path }}"
id="{{ html_id }}"
class="doc doc-heading"
data-toc-label="{{ module.name }}">

Expand All @@ -31,8 +32,8 @@
{% else %}
{% if config.show_root_toc_entry %}
<h{{ heading_level }} class="hidden-toc"
href="#{{ module.path }}"
id="{{ module.path }}"
href="#{{ html_id }}"
id="{{ html_id }}"
data-toc-label="{{ module.path }}"
style="visibility: hidden; position: absolute;">
</h{{ heading_level }}>
Expand All @@ -52,6 +53,7 @@
{% endwith %}
</div>

{% endwith %}
</div>

{% endif %}
2 changes: 1 addition & 1 deletion src/mkdocstrings/templates/python/material/parameters.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<tr>
<td><code>{{ parameter.name }}</code></td>
<td><code>{{ parameter.annotation }}</code></td>
<td>{{ parameter.description|convert_markdown(heading_level) }}</td>
<td>{{ parameter.description|convert_markdown(heading_level, html_id) }}</td>
<td>{% if parameter.default %}<code>{{ parameter.default }}</code>{% else %}<em>required</em>{% endif %}</td>
</tr>
{% endfor %}
Expand Down
2 changes: 1 addition & 1 deletion src/mkdocstrings/templates/python/material/return.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<tbody>
<tr>
<td><code>{{ return.annotation }}</code></td>
<td>{{ return.description|convert_markdown(heading_level) }}</td>
<td>{{ return.description|convert_markdown(heading_level, html_id) }}</td>
</tr>
</tbody>
</table>
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<td class="field-body">
<ul class="first simple">
{% for exception in exceptions %}
<li>{{ ("`" + exception.annotation + "` – " + exception.description)|convert_markdown(heading_level) }}</li>
<li>{{ ("`" + exception.annotation + "` – " + exception.description)|convert_markdown(heading_level, html_id) }}</li>
{% endfor %}
</ul>
</td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<td class="field-body">
<ul class="first simple">
{% for parameter in parameters %}
<li>{{ ("**" + parameter.name + "** (`" + parameter.annotation + "`) – " + parameter.description)|convert_markdown(heading_level) }}</li>
<li>{{ ("**" + parameter.name + "** (`" + parameter.annotation + "`) – " + parameter.description)|convert_markdown(heading_level, html_id) }}</li>
{% endfor %}
</ul>
</td>
Expand Down
2 changes: 1 addition & 1 deletion src/mkdocstrings/templates/python/readthedocs/return.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<th class="field-name">Returns:</th>
<td class="field-body">
<ul class="first simple">
<li>{{ ("`" + return.annotation + "` – " + return.description)|convert_markdown(heading_level) }}</li>
<li>{{ ("`" + return.annotation + "` – " + return.description)|convert_markdown(heading_level, html_id) }}</li>
</ul>
</td>
</tr>
Expand Down

0 comments on commit d493d33

Please sign in to comment.