-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 8302ce5
Showing
53 changed files
with
1,793 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
.idea/ | ||
__pycache__/ | ||
*.py[cod] | ||
dist/ | ||
*.egg-info/ | ||
build/ | ||
htmlcov/ | ||
.coverage* | ||
pip-wheel-metadata/ | ||
.pytest_cache/ | ||
.mypy_cache/ | ||
site/ | ||
pdm.lock | ||
.pdm.toml | ||
__pypackages__/ | ||
.venv/ | ||
.eggs/ | ||
src/version.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# mkdocstrings-vba | ||
|
||
A VBA handler for [mkdocstrings](https://github.com/mkdocstrings/mkdocstrings). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import setuptools | ||
|
||
with open("README.md", "r") as fh: | ||
long_description = fh.read() | ||
|
||
setuptools.setup( | ||
name="mkdocstrings-vba", | ||
author="Rudolf Byker", | ||
author_email="[email protected]", | ||
description="MkDocstrings VBA handler", | ||
long_description=long_description, | ||
long_description_content_type="text/markdown", | ||
url="https://github.com/AutoActuary/mkdocstrings-vba", | ||
packages=setuptools.find_packages(), | ||
classifiers=[ | ||
"Programming Language :: Python :: 3", | ||
"License :: Other/Proprietary License", | ||
"Operating System :: OS Independent", | ||
], | ||
python_requires=">=3.7", | ||
use_scm_version={ | ||
"write_to": "src/version.py", | ||
}, | ||
setup_requires=[ | ||
"setuptools_scm", | ||
], | ||
install_requires=[ | ||
"mkdocstrings[python]>=0.18", | ||
"mkdocs-material", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
"""This package implements a handler for the VBA language.""" | ||
|
||
from mkdocstrings_handlers.vba.handler import get_handler | ||
|
||
__all__ = ["get_handler"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
""" | ||
This module implements a collector for the VBA language. | ||
""" | ||
from pathlib import Path | ||
|
||
from mkdocstrings.handlers.base import BaseCollector | ||
|
||
from mkdocstrings_handlers.vba.types import VbaModuleInfo | ||
from mkdocstrings_handlers.vba.util import ( | ||
collapse_long_lines, | ||
find_file_docstring, | ||
find_procedures, | ||
) | ||
|
||
|
||
class VbaCollector(BaseCollector): | ||
""" | ||
Collect data from a VBA file. | ||
""" | ||
|
||
def collect( | ||
self, | ||
identifier: str, | ||
config: dict, | ||
) -> VbaModuleInfo: | ||
"""Collect the documentation tree given an identifier and selection options. | ||
Arguments: | ||
identifier: Which VBA file (.bas or .cls) to collect from. | ||
config: Selection options, used to alter the data collection. | ||
Raises: | ||
CollectionError: When there was a problem collecting the documentation. | ||
Returns: | ||
The collected object tree. | ||
""" | ||
p = Path(identifier) | ||
with p.open("r") as f: | ||
code = f.read() | ||
|
||
code = collapse_long_lines(code) | ||
|
||
return VbaModuleInfo( | ||
docstring=find_file_docstring(code), | ||
source=code.splitlines(), | ||
path=p, | ||
procedures=list(find_procedures(code)), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
"""This module implements a handler for the VBA language.""" | ||
|
||
import posixpath | ||
from typing import Any, BinaryIO, Iterator, Optional, Tuple | ||
|
||
from griffe.logger import patch_loggers | ||
from mkdocstrings.handlers.base import BaseHandler | ||
from mkdocstrings.inventory import Inventory | ||
from mkdocstrings.loggers import get_logger | ||
|
||
from mkdocstrings_handlers.vba.collector import VbaCollector | ||
from mkdocstrings_handlers.vba.renderer import VbaRenderer | ||
|
||
patch_loggers(get_logger) | ||
|
||
|
||
class VbaHandler(BaseHandler): | ||
"""The Vba handler class.""" | ||
|
||
domain: str = "vba" | ||
"""The cross-documentation domain/language for this handler.""" | ||
|
||
enable_inventory: bool = True | ||
"""Whether this handler is interested in enabling the creation of the `objects.inv` Sphinx inventory file.""" | ||
|
||
@classmethod | ||
def load_inventory( | ||
cls, | ||
in_file: BinaryIO, | ||
url: str, | ||
base_url: Optional[str] = None, | ||
**kwargs: Any, | ||
) -> Iterator[Tuple[str, str]]: | ||
"""Yield items and their URLs from an inventory file streamed from `in_file`. | ||
This implements mkdocstrings' `load_inventory` "protocol" (see plugin.py). | ||
Arguments: | ||
in_file: The binary file-like object to read the inventory from. | ||
url: The URL that this file is being streamed from (used to guess `base_url`). | ||
base_url: The URL that this inventory's sub-paths are relative to. | ||
**kwargs: Ignore additional arguments passed from the config. | ||
Yields: | ||
Tuples of (item identifier, item URL). | ||
""" | ||
if base_url is None: | ||
base_url = posixpath.dirname(url) | ||
|
||
for item in Inventory.parse_sphinx(in_file, domain_filter=("py",)).values(): | ||
yield item.name, posixpath.join(base_url, item.uri) | ||
|
||
|
||
def get_handler( | ||
theme: str, | ||
custom_templates: Optional[str] = None, | ||
**config: Any, | ||
) -> VbaHandler: | ||
"""Simply return an instance of `VbaHandler`. | ||
Arguments: | ||
theme: The theme to use when rendering contents. | ||
custom_templates: Directory containing custom templates. | ||
**config: Configuration passed to the handler. | ||
Returns: | ||
An instance of `VbaHandler`. | ||
""" | ||
return VbaHandler( | ||
collector=VbaCollector(), | ||
renderer=VbaRenderer("vba", theme, custom_templates), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
""" | ||
This module implements a renderer for the VBA language. | ||
Most of this is just copied / hacked together from the Python renderer. | ||
""" | ||
|
||
from __future__ import annotations | ||
|
||
import enum | ||
import re | ||
import sys | ||
from collections import ChainMap | ||
from typing import Any, Sequence | ||
|
||
from griffe.dataclasses import Alias, Object | ||
from markdown import Markdown | ||
from markupsafe import Markup | ||
from mkdocstrings.extension import PluginError | ||
from mkdocstrings.handlers.base import BaseRenderer, CollectorItem | ||
from mkdocstrings.loggers import get_logger | ||
|
||
from mkdocstrings_handlers.vba.types import VbaModuleInfo | ||
|
||
logger = get_logger(__name__) | ||
|
||
|
||
class Order(enum.Enum): | ||
"""Enumeration for the possible members ordering.""" | ||
|
||
alphabetical = "alphabetical" | ||
source = "source" | ||
|
||
|
||
def _sort_key_alphabetical(item: CollectorItem) -> Any: | ||
# chr(sys.maxunicode) is a string that contains the final unicode | ||
# character, so if 'name' isn't found on the object, the item will go to | ||
# the end of the list. | ||
return item.name or chr(sys.maxunicode) | ||
|
||
|
||
def _sort_key_source(item: CollectorItem) -> Any: | ||
# if 'lineno' is none, the item will go to the start of the list. | ||
return item.lineno if item.lineno is not None else -1 | ||
|
||
|
||
order_map = { | ||
Order.alphabetical: _sort_key_alphabetical, | ||
Order.source: _sort_key_source, | ||
} | ||
|
||
|
||
class VbaRenderer(BaseRenderer): | ||
"""The class responsible for loading Jinja templates and rendering them. | ||
It defines some configuration options, implements the `render` method, | ||
and overrides the `update_env` method of the [`BaseRenderer` class][mkdocstrings.handlers.base.BaseRenderer]. | ||
""" | ||
|
||
fallback_theme = "material" | ||
""" | ||
The theme to fall back to. | ||
""" | ||
|
||
default_config: dict = { | ||
"show_root_heading": False, | ||
"show_root_toc_entry": True, | ||
"show_root_full_path": True, | ||
"show_root_members_full_path": False, | ||
"show_object_full_path": False, | ||
"show_category_heading": False, | ||
"show_if_no_docstring": False, | ||
"show_signature": True, | ||
"separate_signature": False, | ||
"line_length": 60, | ||
"show_source": True, | ||
"show_bases": True, | ||
"show_submodules": True, | ||
"heading_level": 2, | ||
"members_order": Order.alphabetical.value, | ||
"docstring_section_style": "table", | ||
} | ||
"""The default rendering options. | ||
See [`default_config`][mkdocstrings_handlers.vba.renderer.VbaRenderer.default_config]. | ||
Option | Type | Description | Default | ||
------ | ---- | ----------- | ------- | ||
**`show_root_heading`** | `bool` | Show the heading of the object at the root of the documentation tree. | `False` | ||
**`show_root_toc_entry`** | `bool` | If the root heading is not shown, at least add a ToC entry for it. | `True` | ||
**`show_root_full_path`** | `bool` | Show the full VBA path for the root object heading. | `True` | ||
**`show_object_full_path`** | `bool` | Show the full VBA path of every object. | `False` | ||
**`show_root_members_full_path`** | `bool` | Show the full VBA path of objects that are children of the root object (for example, classes in a module). When False, `show_object_full_path` overrides. | `False` | ||
**`show_category_heading`** | `bool` | When grouped by categories, show a heading for each category. | `False` | ||
**`show_if_no_docstring`** | `bool` | Show the object heading even if it has no docstring or children with docstrings. | `False` | ||
**`show_signature`** | `bool` | Show method and function signatures. | `True` | ||
**`separate_signature`** | `bool` | Whether to put the whole signature in a code block below the heading. | `False` | ||
**`line_length`** | `int` | Maximum line length when formatting code. | `60` | ||
**`show_source`** | `bool` | Show the source code of this object. | `True` | ||
**`show_bases`** | `bool` | Show the base classes of a class. | `True` | ||
**`show_submodules`** | `bool` | When rendering a module, show its submodules recursively. | `True` | ||
**`heading_level`** | `int` | The initial heading level to use. | `2` | ||
**`members_order`** | `str` | The members ordering to use. Options: `alphabetical` - order by the members names, `source` - order members as they appear in the source file. | `alphabetical` | ||
**`docstring_section_style`** | `str` | The style used to render docstring sections. Options: `table`, `list`, `spacy`. | `table` | ||
""" # noqa: E501 | ||
|
||
def render( | ||
self, | ||
data: VbaModuleInfo, | ||
config: dict, | ||
) -> str: | ||
final_config = ChainMap(config, self.default_config) | ||
render_type = "module" | ||
|
||
template = self.env.get_template(f"{render_type}.html") | ||
|
||
# Heading level is a "state" variable, that will change at each step | ||
# of the rendering recursion. Therefore, it's easier to use it as a plain value | ||
# than as an item in a dictionary. | ||
heading_level = final_config["heading_level"] | ||
try: | ||
final_config["members_order"] = Order(final_config["members_order"]) | ||
except ValueError: | ||
choices = "', '".join(item.value for item in Order) | ||
raise PluginError( | ||
f"Unknown members_order '{final_config['members_order']}', choose between '{choices}'." | ||
) | ||
|
||
return template.render( | ||
**{ | ||
"config": final_config, | ||
render_type: data, | ||
"heading_level": heading_level, | ||
"root": True, | ||
}, | ||
) | ||
|
||
def get_anchors(self, data: VbaModuleInfo) -> list[str]: | ||
return list( | ||
{data.path.as_posix(), *(p.signature.name for p in data.procedures)} | ||
) | ||
|
||
def update_env(self, md: Markdown, config: dict) -> None: | ||
super().update_env(md, config) | ||
self.env.trim_blocks = True | ||
self.env.lstrip_blocks = True | ||
self.env.keep_trailing_newline = False | ||
self.env.filters["crossref"] = self.do_crossref | ||
self.env.filters["multi_crossref"] = self.do_multi_crossref | ||
self.env.filters["order_members"] = self.do_order_members | ||
|
||
@staticmethod | ||
def do_order_members( | ||
members: Sequence[Object | Alias], order: Order | ||
) -> Sequence[Object | Alias]: | ||
"""Order members given an ordering method. | ||
Parameters: | ||
members: The members to order. | ||
order: The ordering method. | ||
Returns: | ||
The same members, ordered. | ||
""" | ||
return sorted(members, key=order_map[order]) | ||
|
||
@staticmethod | ||
def do_crossref(path: str, brief: bool = True) -> Markup: | ||
"""Filter to create cross-references. | ||
Parameters: | ||
path: The path to link to. | ||
brief: Show only the last part of the path, add full path as hover. | ||
Returns: | ||
Markup text. | ||
""" | ||
full_path = path | ||
if brief: | ||
path = full_path.split(".")[-1] | ||
return Markup( | ||
"<span data-autorefs-optional-hover={full_path}>{path}</span>" | ||
).format(full_path=full_path, path=path) | ||
|
||
@staticmethod | ||
def do_multi_crossref(text: str, code: bool = True) -> Markup: | ||
"""Filter to create cross-references. | ||
Parameters: | ||
text: The text to scan. | ||
code: Whether to wrap the result in a code tag. | ||
Returns: | ||
Markup text. | ||
""" | ||
group_number = 0 | ||
variables = {} | ||
|
||
def repl(match): # noqa: WPS430 | ||
nonlocal group_number # noqa: WPS420 | ||
group_number += 1 | ||
path = match.group() | ||
path_var = f"path{group_number}" | ||
variables[path_var] = path | ||
return f"<span data-autorefs-optional-hover={{{path_var}}}>{{{path_var}}}</span>" | ||
|
||
text = re.sub(r"([\w.]+)", repl, text) | ||
if code: | ||
text = f"<code>{text}</code>" | ||
return Markup(text).format(**variables) |
Oops, something went wrong.