diff options
Diffstat (limited to 'docs/extensions/refman_links.py')
-rw-r--r-- | docs/extensions/refman_links.py | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/docs/extensions/refman_links.py b/docs/extensions/refman_links.py new file mode 100644 index 0000000..857d2cb --- /dev/null +++ b/docs/extensions/refman_links.py @@ -0,0 +1,108 @@ +from pathlib import Path +from json import loads +import re + +from hotdoc.core.exceptions import HotdocSourceException +from hotdoc.core.extension import Extension +from hotdoc.core.tree import Page +from hotdoc.core.project import Project +from hotdoc.run_hotdoc import Application +from hotdoc.core.formatter import Formatter +from hotdoc.utils.loggable import Logger, warn, info + +import typing as T + +if T.TYPE_CHECKING: + import argparse + +Logger.register_warning_code('unknown-refman-link', HotdocSourceException, 'refman-links') + +class RefmanLinksExtension(Extension): + extension_name = 'refman-links' + argument_prefix = 'refman' + + def __init__(self, app: Application, project: Project): + self.project: Project + super().__init__(app, project) + self._data_file: T.Optional[Path] = None + self._data: T.Dict[str, str] = {} + + @staticmethod + def add_arguments(parser: 'argparse.ArgumentParser'): + group = parser.add_argument_group( + 'Refman links', + 'Custom Meson extension', + ) + + # Add Arguments with `group.add_argument(...)` + group.add_argument( + f'--refman-data-file', + help="JSON file with the mappings to replace", + default=None, + ) + + def parse_config(self, config: T.Dict[str, T.Any]) -> None: + super().parse_config(config) + self._data_file = config.get('refman_data_file') + + def _formatting_page_cb(self, formatter: Formatter, page: Page) -> None: + ''' Replace Meson refman tags + + Links of the form [[function]] are automatically replaced + with valid links to the correct URL. To reference objects / types use the + [[@object]] syntax. + ''' + link_regex = re.compile(r'\[\[#?@?([ \n\t]*[a-zA-Z0-9_]+[ \n\t]*\.)*[ \n\t]*[a-zA-Z0-9_]+[ \n\t]*\]\]', re.MULTILINE) + for m in link_regex.finditer(page.formatted_contents): + i = m.group() + obj_id: str = i[2:-2] + obj_id = re.sub(r'[ \n\t]', '', obj_id) # Remove whitespaces + + # Marked as inside a code block? + in_code_block = False + if obj_id.startswith('#'): + in_code_block = True + obj_id = obj_id[1:] + + if obj_id not in self._data: + warn('unknown-refman-link', f'{Path(page.name).name}: Unknown Meson refman link: "{obj_id}"') + continue + + # Just replaces [[!file.id]] paths with the page file (no fancy HTML) + if obj_id.startswith('!'): + page.formatted_contents = page.formatted_contents.replace(i, self._data[obj_id]) + continue + + # Fancy links for functions and methods + text = obj_id + if text.startswith('@'): + text = text[1:] + else: + text = text + '()' + if not in_code_block: + text = f'<code>{text}</code>' + link = f'<a href="{self._data[obj_id]}"><ins>{text}</ins></a>' + page.formatted_contents = page.formatted_contents.replace(i, link) + + def setup(self) -> None: + super().setup() + + if not self._data_file: + info('Meson refman extension DISABLED') + return + + raw = Path(self._data_file).read_text(encoding='utf-8') + self._data = loads(raw) + + # Register formater + for ext in self.project.extensions.values(): + ext = T.cast(Extension, ext) + ext.formatter.formatting_page_signal.connect(self._formatting_page_cb) + info('Meson refman extension LOADED') + + @staticmethod + def get_dependencies() -> T.List[T.Type[Extension]]: + return [] # In case this extension has dependencies on other extensions + +def get_extension_classes() -> T.List[T.Type[Extension]]: + return [RefmanLinksExtension] |