From 2bf0cc077f68f2a0aebc8318ec587e5c8db9da0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Mazzucotelli?= Date: Thu, 23 Jan 2025 23:46:45 +0100 Subject: [PATCH] feat: Support backlinks Issue-153: https://github.com/mkdocstrings/python/issues/153 --- mkdocs.yml | 1 + src/mkdocstrings_handlers/python/config.py | 8 ++ src/mkdocstrings_handlers/python/handler.py | 14 ++++ src/mkdocstrings_handlers/python/rendering.py | 66 ++++++++++++++- .../material/_base/attribute.html.jinja | 2 + .../material/_base/backlinks.html.jinja | 65 ++++++++++++++ .../templates/material/_base/class.html.jinja | 8 +- .../docstring/other_parameters.html.jinja | 6 +- .../_base/docstring/parameters.html.jinja | 12 +-- .../_base/docstring/raises.html.jinja | 6 +- .../_base/docstring/receives.html.jinja | 8 +- .../_base/docstring/returns.html.jinja | 8 +- .../material/_base/docstring/warns.html.jinja | 6 +- .../_base/docstring/yields.html.jinja | 8 +- .../material/_base/expression.html.jinja | 14 ++-- .../material/_base/function.html.jinja | 2 + .../material/_base/module.html.jinja | 2 + .../material/_base/signature.html.jinja | 10 ++- .../templates/material/backlinks.html.jinja | 1 + .../python/templates/material/style.css | 84 +++++++++++++++++-- .../docstring/other_parameters.html.jinja | 2 +- .../_base/docstring/parameters.html.jinja | 4 +- .../_base/docstring/raises.html.jinja | 2 +- .../_base/docstring/receives.html.jinja | 2 +- .../_base/docstring/returns.html.jinja | 2 +- .../_base/docstring/warns.html.jinja | 2 +- .../_base/docstring/yields.html.jinja | 2 +- 27 files changed, 291 insertions(+), 56 deletions(-) create mode 100644 src/mkdocstrings_handlers/python/templates/material/_base/backlinks.html.jinja create mode 100644 src/mkdocstrings_handlers/python/templates/material/backlinks.html.jinja diff --git a/mkdocs.yml b/mkdocs.yml index 396f738..92cbeea 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -160,6 +160,7 @@ plugins: - https://mkdocstrings.github.io/griffe/objects.inv - https://python-markdown.github.io/objects.inv options: + backlinks: flat docstring_options: ignore_init_summary: true docstring_section_style: list diff --git a/src/mkdocstrings_handlers/python/config.py b/src/mkdocstrings_handlers/python/config.py index 6607d01..8efe05b 100644 --- a/src/mkdocstrings_handlers/python/config.py +++ b/src/mkdocstrings_handlers/python/config.py @@ -386,6 +386,14 @@ class PythonInputOptions: ), ] = "brief" + backlinks: Annotated[ + Literal["flat", "tree", False], + Field( + group="general", + description="Whether to render backlinks, and how.", + ), + ] = False + docstring_options: Annotated[ GoogleStyleOptions | NumpyStyleOptions | SphinxStyleOptions | AutoStyleOptions | None, Field( diff --git a/src/mkdocstrings_handlers/python/handler.py b/src/mkdocstrings_handlers/python/handler.py index 0051be0..8146c19 100644 --- a/src/mkdocstrings_handlers/python/handler.py +++ b/src/mkdocstrings_handlers/python/handler.py @@ -6,6 +6,7 @@ import os import posixpath import sys +from collections.abc import Iterable from contextlib import suppress from dataclasses import asdict from pathlib import Path @@ -25,6 +26,7 @@ from mkdocstrings.handlers.base import BaseHandler, CollectionError, CollectorItem, HandlerOptions from mkdocstrings.inventory import Inventory from mkdocstrings.loggers import get_logger +from mkdocs_autorefs.plugin import BacklinkCrumb from mkdocstrings_handlers.python import rendering from mkdocstrings_handlers.python.config import PythonConfig, PythonOptions @@ -33,6 +35,7 @@ from collections.abc import Iterator, Mapping, MutableMapping, Sequence from mkdocs.config.defaults import MkDocsConfig + from mkdocs_autorefs.plugin import Backlink if sys.version_info >= (3, 11): @@ -280,6 +283,16 @@ def render(self, data: CollectorItem, options: PythonOptions) -> str: # noqa: D }, ) + def render_backlinks(self, backlinks: Mapping[str, Iterable[Backlink]]) -> str: # noqa: D102 (ignore missing docstring) + template = self.env.get_template("backlinks.html.jinja") + verbose_type = {key: key.capitalize().replace("-by", " by") for key in backlinks.keys()} + return template.render( + backlinks=backlinks, + config=self.get_options({}), + verbose_type=verbose_type, + default_crumb=BacklinkCrumb(title="", url=""), + ) + def update_env(self, config: Any) -> None: # noqa: ARG002 """Update the Jinja environment with custom filters and tests. @@ -303,6 +316,7 @@ def update_env(self, config: Any) -> None: # noqa: ARG002 self.env.filters["as_functions_section"] = rendering.do_as_functions_section self.env.filters["as_classes_section"] = rendering.do_as_classes_section self.env.filters["as_modules_section"] = rendering.do_as_modules_section + self.env.filters["backlink_tree"] = rendering.do_backlink_tree self.env.globals["AutorefsHook"] = rendering.AutorefsHook self.env.tests["existing_template"] = lambda template_name: template_name in self.env.list_templates() diff --git a/src/mkdocstrings_handlers/python/rendering.py b/src/mkdocstrings_handlers/python/rendering.py index d284567..a99f78a 100644 --- a/src/mkdocstrings_handlers/python/rendering.py +++ b/src/mkdocstrings_handlers/python/rendering.py @@ -2,6 +2,7 @@ from __future__ import annotations +from collections.abc import Iterable import random import re import string @@ -12,7 +13,7 @@ from functools import lru_cache from pathlib import Path from re import Match, Pattern -from typing import TYPE_CHECKING, Any, Callable, ClassVar, Literal +from typing import TYPE_CHECKING, Any, Callable, ClassVar, Literal, TypeVar from griffe import ( Alias, @@ -26,9 +27,12 @@ DocstringSectionModules, Object, ) +from collections import defaultdict +from typing import Optional, Sequence, Union + from jinja2 import TemplateNotFound, pass_context, pass_environment from markupsafe import Markup -from mkdocs_autorefs import AutorefsHookInterface +from mkdocs_autorefs import AutorefsHookInterface, Backlink, BacklinkCrumb from mkdocstrings.loggers import get_logger if TYPE_CHECKING: @@ -210,10 +214,15 @@ def do_format_attribute( signature = str(attribute_path).strip() if annotations and attribute.annotation: - annotation = template.render(context.parent, expression=attribute.annotation, signature=True) + annotation = template.render( + context.parent, + expression=attribute.annotation, + signature=True, + backlink_type="returned-by", + ) signature += f": {annotation}" if attribute.value: - value = template.render(context.parent, expression=attribute.value, signature=True) + value = template.render(context.parent, expression=attribute.value, signature=True, backlink_type="used-by") signature += f" = {value}" signature = do_format_code(signature, line_length) @@ -725,3 +734,52 @@ def get_context(self) -> AutorefsHookInterface.Context: filepath=str(filepath), lineno=lineno, ) + + +T = TypeVar("T") +Tree = dict[T, "Tree"] +CompactTree = dict[tuple[T, ...], "CompactTree"] +_rtree = lambda: defaultdict(_rtree) + + +def _tree(data: Iterable[tuple[T, ...]]) -> Tree: + new_tree = _rtree() + for nav in data: + *path, leaf = nav + node = new_tree + for key in path: + node = node[key] + node[leaf] = _rtree() + return new_tree + + +def print_tree(tree: Tree, level: int = 0) -> None: + for key, value in tree.items(): + print(" " * level + str(key)) + if value: + print_tree(value, level + 1) + + +def _compact_tree(tree: Tree) -> CompactTree: + new_tree = _rtree() + for key, value in tree.items(): + child = _compact_tree(value) + if len(child) == 1: + child_key, child_value = next(iter(child.items())) + new_key = (key, *child_key) + new_tree[new_key] = child_value + else: + new_tree[(key,)] = child + return new_tree + + +def do_backlink_tree(backlinks: list[Backlink]) -> CompactTree[BacklinkCrumb]: + """Build a tree of backlinks. + + Parameters: + backlinks: The list of backlinks. + + Returns: + A tree of backlinks. + """ + return _compact_tree(_tree((backlink.crumbs for backlink in backlinks))) diff --git a/src/mkdocstrings_handlers/python/templates/material/_base/attribute.html.jinja b/src/mkdocstrings_handlers/python/templates/material/_base/attribute.html.jinja index c13bb64..17a86f5 100644 --- a/src/mkdocstrings_handlers/python/templates/material/_base/attribute.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/material/_base/attribute.html.jinja @@ -113,6 +113,8 @@ Context: {% include "docstring"|get_template with context %} {% endwith %} {% endblock docstring %} + + {% endblock contents %} diff --git a/src/mkdocstrings_handlers/python/templates/material/_base/backlinks.html.jinja b/src/mkdocstrings_handlers/python/templates/material/_base/backlinks.html.jinja new file mode 100644 index 0000000..2edcf43 --- /dev/null +++ b/src/mkdocstrings_handlers/python/templates/material/_base/backlinks.html.jinja @@ -0,0 +1,65 @@ +{#- Template for backlinks. + +This template renders backlinks. + +Context: + backlinks (Mapping[str, Iterable[str]]): The backlinks to render. + config (dict): The configuration options. +-#} + +{% block logs scoped %} + {#- Logging block. + + This block can be used to log debug messages, deprecation messages, warnings, etc. + -#} + {{ log.debug("Rendering backlinks") }} +{% endblock logs %} + +{% macro render_crumb(crumb, last=false) %} + + {% if crumb.url and crumb.title %} + {{ crumb.title | safe }} + {% elif crumb.title %} + {{ crumb.title | safe }} + {% endif %} + +{% endmacro %} + +{% macro render_tree(tree) %} + +{% endmacro %} + +{% if config.backlinks %} + +{% endif %} diff --git a/src/mkdocstrings_handlers/python/templates/material/_base/class.html.jinja b/src/mkdocstrings_handlers/python/templates/material/_base/class.html.jinja index e8f89fa..ac35bf9 100644 --- a/src/mkdocstrings_handlers/python/templates/material/_base/class.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/material/_base/class.html.jinja @@ -130,7 +130,11 @@ Context: {% if config.show_bases and class.bases %}

Bases: {% for expression in class.bases -%} - {% include "expression"|get_template with context %}{% if not loop.last %}, {% endif %} + + {%- with backlink_type = "subclassed-by" -%} + {%- include "expression"|get_template with context -%} + {%- endwith -%} + {% if not loop.last %}, {% endif %} {% endfor -%}

{% endif %} @@ -159,6 +163,8 @@ Context: {% endif %} {% endblock docstring %} + + {% block summary scoped %} {#- Summary block. diff --git a/src/mkdocstrings_handlers/python/templates/material/_base/docstring/other_parameters.html.jinja b/src/mkdocstrings_handlers/python/templates/material/_base/docstring/other_parameters.html.jinja index 1689dcb..8b64af1 100644 --- a/src/mkdocstrings_handlers/python/templates/material/_base/docstring/other_parameters.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/material/_base/docstring/other_parameters.html.jinja @@ -36,7 +36,7 @@ Context: {{ parameter.name }} {% if parameter.annotation %} - {% with expression = parameter.annotation %} + {% with expression = parameter.annotation, backlink_type = "used-by" %} {% include "expression"|get_template with context %} {% endwith %} {% endif %} @@ -60,7 +60,7 @@ Context:
  • {{ parameter.name }} {% if parameter.annotation %} - {% with expression = parameter.annotation %} + {% with expression = parameter.annotation, backlink_type = "used-by" %} ({% include "expression"|get_template with context %}) {% endwith %} {% endif %} @@ -94,7 +94,7 @@ Context: {% if parameter.annotation %} {{ lang.t("TYPE:") }} - {% with expression = parameter.annotation %} + {% with expression = parameter.annotation, backlink_type = "used-by" %} {% include "expression"|get_template with context %} {% endwith %} diff --git a/src/mkdocstrings_handlers/python/templates/material/_base/docstring/parameters.html.jinja b/src/mkdocstrings_handlers/python/templates/material/_base/docstring/parameters.html.jinja index d4e9acb..ae8fb7a 100644 --- a/src/mkdocstrings_handlers/python/templates/material/_base/docstring/parameters.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/material/_base/docstring/parameters.html.jinja @@ -51,7 +51,7 @@ Context: {% if parameter.annotation %} - {% with expression = parameter.annotation %} + {% with expression = parameter.annotation, backlink_type = "used-by" %} {% include "expression"|get_template with context %} {% endwith %} {% endif %} @@ -63,7 +63,7 @@ Context: {% if parameter.default %} - {% with expression = parameter.default %} + {% with expression = parameter.default, backlink_type = "used-by" %} {% include "expression"|get_template with context %} {% endwith %} {% else %} @@ -96,10 +96,10 @@ Context: {{ parameter.name }} {% endif %} {% if parameter.annotation %} - {% with expression = parameter.annotation %} + {% with expression = parameter.annotation, backlink_type = "used-by" %} ({% include "expression"|get_template with context %} {%- if parameter.default %}, {{ lang.t("default:") }} - {% with expression = parameter.default %} + {% with expression = parameter.default, backlink_type = "used-by" %} {% include "expression"|get_template with context %} {% endwith %} {% endif %}) @@ -149,7 +149,7 @@ Context: {% if parameter.annotation %} {{ lang.t("TYPE:") }} - {% with expression = parameter.annotation %} + {% with expression = parameter.annotation, backlink_type = "used-by" %} {% include "expression"|get_template with context %} {% endwith %} @@ -157,7 +157,7 @@ Context: {% if parameter.default %} {{ lang.t("DEFAULT:") }} - {% with expression = parameter.default %} + {% with expression = parameter.default, backlink_type = "used-by" %} {% include "expression"|get_template with context %} {% endwith %} diff --git a/src/mkdocstrings_handlers/python/templates/material/_base/docstring/raises.html.jinja b/src/mkdocstrings_handlers/python/templates/material/_base/docstring/raises.html.jinja index d734e94..1e1d500 100644 --- a/src/mkdocstrings_handlers/python/templates/material/_base/docstring/raises.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/material/_base/docstring/raises.html.jinja @@ -34,7 +34,7 @@ Context: {% if raises.annotation %} - {% with expression = raises.annotation %} + {% with expression = raises.annotation, backlink_type = "raised-by" %} {% include "expression"|get_template with context %} {% endwith %} {% endif %} @@ -57,7 +57,7 @@ Context: {% for raises in section.value %}
  • {% if raises.annotation %} - {% with expression = raises.annotation %} + {% with expression = raises.annotation, backlink_type = "raised-by" %} {% include "expression"|get_template with context %} {% endwith %} – @@ -84,7 +84,7 @@ Context: - {% with expression = raises.annotation %} + {% with expression = raises.annotation, backlink_type = "raised-by" %} {% include "expression"|get_template with context %} {% endwith %} diff --git a/src/mkdocstrings_handlers/python/templates/material/_base/docstring/receives.html.jinja b/src/mkdocstrings_handlers/python/templates/material/_base/docstring/receives.html.jinja index 3b618c6..a447b21 100644 --- a/src/mkdocstrings_handlers/python/templates/material/_base/docstring/receives.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/material/_base/docstring/receives.html.jinja @@ -37,7 +37,7 @@ Context: {% if name_column %}{% if receives.name %}{{ receives.name }}{% endif %}{% endif %} {% if receives.annotation %} - {% with expression = receives.annotation %} + {% with expression = receives.annotation, backlink_type = "received-by" %} {% include "expression"|get_template with context %} {% endwith %} {% endif %} @@ -61,7 +61,7 @@ Context:
  • {% if receives.name %}{{ receives.name }}{% endif %} {% if receives.annotation %} - {% with expression = receives.annotation %} + {% with expression = receives.annotation, backlink_type = "received-by" %} {% if receives.name %} ({% endif %} {% include "expression"|get_template with context %} {% if receives.name %}){% endif %} @@ -93,7 +93,7 @@ Context: {{ receives.name }} {% elif receives.annotation %} - {% with expression = receives.annotation %} + {% with expression = receives.annotation, backlink_type = "received-by" %} {% include "expression"|get_template with context %} {% endwith %} @@ -107,7 +107,7 @@ Context:

    {{ lang.t("TYPE:") }} - {% with expression = receives.annotation %} + {% with expression = receives.annotation, backlink_type = "received-by" %} {% include "expression"|get_template with context %} {% endwith %} diff --git a/src/mkdocstrings_handlers/python/templates/material/_base/docstring/returns.html.jinja b/src/mkdocstrings_handlers/python/templates/material/_base/docstring/returns.html.jinja index af61fce..30540e6 100644 --- a/src/mkdocstrings_handlers/python/templates/material/_base/docstring/returns.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/material/_base/docstring/returns.html.jinja @@ -37,7 +37,7 @@ Context: {% if name_column %}{% if returns.name %}{{ returns.name }}{% endif %}{% endif %} {% if returns.annotation %} - {% with expression = returns.annotation %} + {% with expression = returns.annotation, backlink_type = "returned-by" %} {% include "expression"|get_template with context %} {% endwith %} {% endif %} @@ -61,7 +61,7 @@ Context:

  • {% if returns.name %}{{ returns.name }}{% endif %} {% if returns.annotation %} - {% with expression = returns.annotation %} + {% with expression = returns.annotation, backlink_type = "returned-by" %} {% if returns.name %} ({% endif %} {% include "expression"|get_template with context %} {% if returns.name %}){% endif %} @@ -93,7 +93,7 @@ Context: {{ returns.name }} {% elif returns.annotation %} - {% with expression = returns.annotation %} + {% with expression = returns.annotation, backlink_type = "returned-by" %} {% include "expression"|get_template with context %} {% endwith %} @@ -107,7 +107,7 @@ Context:

    {{ lang.t("TYPE:") }} - {% with expression = returns.annotation %} + {% with expression = returns.annotation, backlink_type = "returned-by" %} {% include "expression"|get_template with context %} {% endwith %} diff --git a/src/mkdocstrings_handlers/python/templates/material/_base/docstring/warns.html.jinja b/src/mkdocstrings_handlers/python/templates/material/_base/docstring/warns.html.jinja index 782c0cd..814e302 100644 --- a/src/mkdocstrings_handlers/python/templates/material/_base/docstring/warns.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/material/_base/docstring/warns.html.jinja @@ -34,7 +34,7 @@ Context: {% if warns.annotation %} - {% with expression = warns.annotation %} + {% with expression = warns.annotation, backlink_type = "emitted-by" %} {% include "expression"|get_template with context %} {% endwith %} {% endif %} @@ -57,7 +57,7 @@ Context: {% for warns in section.value %}

  • {% if warns.annotation %} - {% with expression = warns.annotation %} + {% with expression = warns.annotation, backlink_type = "emitted-by" %} {% include "expression"|get_template with context %} {% endwith %} – @@ -84,7 +84,7 @@ Context: - {% with expression = warns.annotation %} + {% with expression = warns.annotation, backlink_type = "emitted-by" %} {% include "expression"|get_template with context %} {% endwith %} diff --git a/src/mkdocstrings_handlers/python/templates/material/_base/docstring/yields.html.jinja b/src/mkdocstrings_handlers/python/templates/material/_base/docstring/yields.html.jinja index 6d3cfa1..01b8b9e 100644 --- a/src/mkdocstrings_handlers/python/templates/material/_base/docstring/yields.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/material/_base/docstring/yields.html.jinja @@ -37,7 +37,7 @@ Context: {% if name_column %}{% if yields.name %}{{ yields.name }}{% endif %}{% endif %} {% if yields.annotation %} - {% with expression = yields.annotation %} + {% with expression = yields.annotation, backlink_type = "yielded-by" %} {% include "expression"|get_template with context %} {% endwith %} {% endif %} @@ -61,7 +61,7 @@ Context:
  • {% if yields.name %}{{ yields.name }}{% endif %} {% if yields.annotation %} - {% with expression = yields.annotation %} + {% with expression = yields.annotation, backlink_type = "yielded-by" %} {% if yields.name %} ({% endif %} {% include "expression"|get_template with context %} {% if yields.name %}){% endif %} @@ -93,7 +93,7 @@ Context: {{ yields.name }} {% elif yields.annotation %} - {% with expression = yields.annotation %} + {% with expression = yields.annotation, backlink_type = "yielded-by" %} {% include "expression"|get_template with context %} {% endwith %} @@ -107,7 +107,7 @@ Context:

    {{ lang.t("TYPE:") }}: - {% with expression = yields.annotation %} + {% with expression = yields.annotation, backlink_type = "yielded-by" %} {% include "expression"|get_template with context %} {% endwith %} diff --git a/src/mkdocstrings_handlers/python/templates/material/_base/expression.html.jinja b/src/mkdocstrings_handlers/python/templates/material/_base/expression.html.jinja index 781d46c..d49e43b 100644 --- a/src/mkdocstrings_handlers/python/templates/material/_base/expression.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/material/_base/expression.html.jinja @@ -11,7 +11,7 @@ which is a tree-like structure representing a Python expression. -#} {% endblock logs %} -{%- macro crossref(name, annotation_path) -%} +{%- macro crossref(name, annotation_path, backlink_type="") -%} {#- Output a cross-reference. This macro outputs a cross-reference to the given name. @@ -35,11 +35,11 @@ which is a tree-like structure representing a Python expression. {{ prefix }} {%- if not signature -%} {#- Always render cross-references outside of signatures. We don't need to stash them. -#} - {{ title }} + {{ title }} {%- elif config.signature_crossrefs -%} {#- We're in a signature and cross-references are enabled, we must render one and stash it. -#} {%- filter stash_crossref(length=title|length) -%} - {{ title }} + {{ title }} {%- endfilter -%} {%- else -%} {#- We're in a signature but cross-references are disabled, we just render the title. -#} @@ -72,7 +72,7 @@ which is a tree-like structure representing a Python expression. {%- endif -%} {%- endmacro -%} -{%- macro render(expression, annotations_path) -%} +{%- macro render(expression, annotations_path, backlink_type="") -%} {#- Render an expression. Parameters: @@ -85,13 +85,13 @@ which is a tree-like structure representing a Python expression. {%- if expression is string -%} {%- if signature -%}{{ expression|safe }}{%- else -%}{{ expression }}{%- endif -%} {%- elif expression.classname == "ExprName" -%} - {{ crossref(expression, annotations_path) }} + {{ crossref(expression, annotations_path, backlink_type) }} {%- elif config.unwrap_annotated and expression.classname == "ExprSubscript" and expression.canonical_path in ("typing.Annotated", "typing_extensions.Annotated") -%} {{ render(expression.slice.elements[0], annotations_path) }} {%- elif expression.classname == "ExprAttribute" -%} {%- if annotations_path == "brief" -%} {%- if expression.last.is_enum_value -%} - {{ crossref(expression.last.parent, "brief") }}.value + {{ crossref(expression.last.parent, "brief", backlink_type) }}.value {%- else -%} {{ render(expression.last, "brief") }} {%- endif -%} @@ -116,4 +116,4 @@ which is a tree-like structure representing a Python expression. {%- endif -%} {%- endmacro -%} -{{ render(expression, config.annotations_path) }} +{{ render(expression, config.annotations_path, backlink_type|default("")) }} diff --git a/src/mkdocstrings_handlers/python/templates/material/_base/function.html.jinja b/src/mkdocstrings_handlers/python/templates/material/_base/function.html.jinja index b475cf1..4c2ba08 100644 --- a/src/mkdocstrings_handlers/python/templates/material/_base/function.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/material/_base/function.html.jinja @@ -129,6 +129,8 @@ Context: {% endwith %} {% endblock docstring %} + + {% block source scoped %} {#- Source block. diff --git a/src/mkdocstrings_handlers/python/templates/material/_base/module.html.jinja b/src/mkdocstrings_handlers/python/templates/material/_base/module.html.jinja index fa2d2e6..5b10b7b 100644 --- a/src/mkdocstrings_handlers/python/templates/material/_base/module.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/material/_base/module.html.jinja @@ -97,6 +97,8 @@ Context: {% endwith %} {% endblock docstring %} + + {% block summary scoped %} {#- Summary block. diff --git a/src/mkdocstrings_handlers/python/templates/material/_base/signature.html.jinja b/src/mkdocstrings_handlers/python/templates/material/_base/signature.html.jinja index ce5c3f0..e414fbe 100644 --- a/src/mkdocstrings_handlers/python/templates/material/_base/signature.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/material/_base/signature.html.jinja @@ -49,7 +49,9 @@ Context: {%- set ns.equal = " = " -%} {%- if config.separate_signature -%} {%- with expression = parameter.annotation -%} - {%- set ns.annotation -%}: {% include "expression"|get_template with context %}{%- endset -%} + {%- set ns.annotation -%}: {% with backlink_type = "used-by" -%} + {%- include "expression"|get_template with context -%} + {%- endwith -%}{%- endset -%} {%- endwith -%} {%- else -%} {%- set ns.annotation = ": " + parameter.annotation|safe -%} @@ -102,7 +104,7 @@ Context: {%- if ns.default -%} {{ ns.equal }} {%- if config.signature_crossrefs and config.separate_signature -%} - {%- with expression = parameter.default -%} + {%- with expression = parameter.default, backlink_type = "used-by" -%} {%- include "expression"|get_template with context -%} {%- endwith -%} {%- else -%} @@ -121,7 +123,9 @@ Context: and function.annotation and not (config.merge_init_into_class and function.name == "__init__" ) %} -> {% if config.separate_signature and config.signature_crossrefs -%} - {%- with expression = function.annotation %}{% include "expression"|get_template with context %}{%- endwith -%} + {%- with expression = function.annotation, backlink_type = "returned-by" -%} + {%- include "expression"|get_template with context -%} + {%- endwith -%} {%- else -%} {{ function.annotation|safe }} {%- endif -%} diff --git a/src/mkdocstrings_handlers/python/templates/material/backlinks.html.jinja b/src/mkdocstrings_handlers/python/templates/material/backlinks.html.jinja new file mode 100644 index 0000000..08ba492 --- /dev/null +++ b/src/mkdocstrings_handlers/python/templates/material/backlinks.html.jinja @@ -0,0 +1 @@ +{% extends "_base/backlinks.html.jinja" %} diff --git a/src/mkdocstrings_handlers/python/templates/material/style.css b/src/mkdocstrings_handlers/python/templates/material/style.css index 7e819d8..585be40 100644 --- a/src/mkdocstrings_handlers/python/templates/material/style.css +++ b/src/mkdocstrings_handlers/python/templates/material/style.css @@ -41,6 +41,72 @@ font-weight: bold; } +/* Backlinks crumb separator. */ +.doc-backlink-crumb { + display: inline-flex; + gap: .2rem; + white-space: nowrap; + align-items: center; + vertical-align: middle; +} +.doc-backlink-crumb:not(:first-child)::before { + background-color: var(--md-default-fg-color--lighter); + content: ""; + display: inline; + height: 1rem; + /* TODO: Declare --md-path-icon ourselves, not to depend on Material Insiders! */ + -webkit-mask-image: var(--md-path-icon); + mask-image: var(--md-path-icon); + width: 1rem; +} +.doc-backlink-crumb.last { + font-weight: bold; +} + +.doc-backlink-list { + --tree-clr: var(--md-default-fg-color); + --tree-font-size: 1rem; + --tree-item-height: 1; + --tree-offset: 1rem; + --tree-thickness: 1px; + --tree-style: solid; + display: grid; + list-style: none !important; +} + +.doc-backlink-list li > span:first-child { + text-indent: .3rem; +} +.doc-backlink-list li { + padding-inline-start: var(--tree-offset); + border-left: var(--tree-thickness) var(--tree-style) var(--tree-clr); + position: relative; + margin-left: 0 !important; + + &:last-child { + border-color: transparent; + } + &::before{ + content: ''; + position: absolute; + top: calc(var(--tree-item-height) / 2 * -1 * var(--tree-font-size) + var(--tree-thickness)); + left: calc(var(--tree-thickness) * -1); + width: calc(var(--tree-offset) + var(--tree-thickness) * 2); + height: calc(var(--tree-item-height) * var(--tree-font-size)); + border-left: var(--tree-thickness) var(--tree-style) var(--tree-clr); + border-bottom: var(--tree-thickness) var(--tree-style) var(--tree-clr); + } + &::after{ + content: ''; + position: absolute; + border-radius: 50%; + background-color: var(--tree-clr); + top: calc(var(--tree-item-height) / 2 * 1rem); + left: var(--tree-offset) ; + translate: calc(var(--tree-thickness) * -1) calc(var(--tree-thickness) * -1); + } +} + /* Symbols in Navigation and ToC. */ :root, :host, [data-md-color-scheme="default"] { @@ -82,7 +148,8 @@ code.doc-symbol { font-weight: bold; } -code.doc-symbol-parameter { +code.doc-symbol-parameter, +a code.doc-symbol-parameter { color: var(--doc-symbol-parameter-fg-color); background-color: var(--doc-symbol-parameter-bg-color); } @@ -91,7 +158,8 @@ code.doc-symbol-parameter::after { content: "param"; } -code.doc-symbol-attribute { +code.doc-symbol-attribute, +a code.doc-symbol-attribute { color: var(--doc-symbol-attribute-fg-color); background-color: var(--doc-symbol-attribute-bg-color); } @@ -100,7 +168,8 @@ code.doc-symbol-attribute::after { content: "attr"; } -code.doc-symbol-function { +code.doc-symbol-function, +a code.doc-symbol-function { color: var(--doc-symbol-function-fg-color); background-color: var(--doc-symbol-function-bg-color); } @@ -109,7 +178,8 @@ code.doc-symbol-function::after { content: "func"; } -code.doc-symbol-method { +code.doc-symbol-method, +a code.doc-symbol-method { color: var(--doc-symbol-method-fg-color); background-color: var(--doc-symbol-method-bg-color); } @@ -118,7 +188,8 @@ code.doc-symbol-method::after { content: "meth"; } -code.doc-symbol-class { +code.doc-symbol-class, +a code.doc-symbol-class { color: var(--doc-symbol-class-fg-color); background-color: var(--doc-symbol-class-bg-color); } @@ -127,7 +198,8 @@ code.doc-symbol-class::after { content: "class"; } -code.doc-symbol-module { +code.doc-symbol-module, +a code.doc-symbol-module { color: var(--doc-symbol-module-fg-color); background-color: var(--doc-symbol-module-bg-color); } diff --git a/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/other_parameters.html.jinja b/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/other_parameters.html.jinja index beb4f67..657b21b 100644 --- a/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/other_parameters.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/other_parameters.html.jinja @@ -32,7 +32,7 @@ Context:

  • {{ parameter.name }} {% if parameter.annotation %} - {% with expression = parameter.annotation %} + {% with expression = parameter.annotation, backlink_type = "used-by" %} ({% include "expression"|get_template with context %}) {% endwith %} {% endif %} diff --git a/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/parameters.html.jinja b/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/parameters.html.jinja index 295ab08..6017a8c 100644 --- a/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/parameters.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/parameters.html.jinja @@ -32,10 +32,10 @@ Context:
  • {{ parameter.name }} {% if parameter.annotation %} - {% with expression = parameter.annotation %} + {% with expression = parameter.annotation, backlink_type = "used-by" %} ({% include "expression"|get_template with context %} {%- if parameter.default %}, {{ lang.t("default:") }} - {% with expression = parameter.default %} + {% with expression = parameter.default, backlink_type = "used-by" %} {% include "expression"|get_template with context %} {% endwith %} {% endif %}) diff --git a/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/raises.html.jinja b/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/raises.html.jinja index 7fa8cd8..11f695e 100644 --- a/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/raises.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/raises.html.jinja @@ -31,7 +31,7 @@ Context: {% for raises in section.value %}
  • {% if raises.annotation %} - {% with expression = raises.annotation %} + {% with expression = raises.annotation, backlink_type = "raised-by" %} {% include "expression"|get_template with context %} {% endwith %} {% endif %} diff --git a/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/receives.html.jinja b/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/receives.html.jinja index 9ee189b..aec9a85 100644 --- a/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/receives.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/receives.html.jinja @@ -32,7 +32,7 @@ Context:
  • {% if receives.name %}{{ receives.name }}{% endif %} {% if receives.annotation %} - {% with expression = receives.annotation %} + {% with expression = receives.annotation, backlink_type = "received-by" %} {% if receives.name %}({% endif %} {% include "expression"|get_template with context %} {% if receives.name %}){% endif %} diff --git a/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/returns.html.jinja b/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/returns.html.jinja index 2dbd21a..3f8bbba 100644 --- a/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/returns.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/returns.html.jinja @@ -32,7 +32,7 @@ Context:
  • {% if returns.name %}{{ returns.name }}{% endif %} {% if returns.annotation %} - {% with expression = returns.annotation %} + {% with expression = returns.annotation, backlink_type = "returned-by" %} {% if returns.name %}({% endif %} {% include "expression"|get_template with context %} {% if returns.name %}){% endif %} diff --git a/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/warns.html.jinja b/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/warns.html.jinja index 61f3c83..1d465ec 100644 --- a/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/warns.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/warns.html.jinja @@ -31,7 +31,7 @@ Context: {% for warns in section.value %}
  • {% if warns.annotation %} - {% with expression = warns.annotation %} + {% with expression = warns.annotation, backlink_type = "emitted-by" %} {% include "expression"|get_template with context %} {% endwith %} {% endif %} diff --git a/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/yields.html.jinja b/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/yields.html.jinja index 0fa6fcb..70c782b 100644 --- a/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/yields.html.jinja +++ b/src/mkdocstrings_handlers/python/templates/readthedocs/_base/docstring/yields.html.jinja @@ -32,7 +32,7 @@ Context:
  • {% if yields.name %}{{ yields.name }}{% endif %} {% if yields.annotation %} - {% with expression = yields.annotation %} + {% with expression = yields.annotation, backlink_type = "yielded-by" %} {% if yields.name %}({% endif %} {% include "expression"|get_template with context %} {% if yields.name %}){% endif %}