diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2020-07-15 10:04:25 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2020-07-15 10:12:50 +0200 |
commit | e49c7597c091559caa5b1e0f2cabe1bb64ae9cb5 (patch) | |
tree | 33978dc3fba68ec39a77855148fc7816d0b56764 /rtemsspec/sphinxcontent.py | |
parent | Rename "external" in "modules" (diff) | |
download | rtems-central-e49c7597c091559caa5b1e0f2cabe1bb64ae9cb5.tar.bz2 |
Rename "rtemsqual" in "rtemsspec"
Diffstat (limited to 'rtemsspec/sphinxcontent.py')
-rw-r--r-- | rtemsspec/sphinxcontent.py | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/rtemsspec/sphinxcontent.py b/rtemsspec/sphinxcontent.py new file mode 100644 index 00000000..6247f987 --- /dev/null +++ b/rtemsspec/sphinxcontent.py @@ -0,0 +1,240 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" This module provides classes for Sphinx content generation. """ + +# Copyright (C) 2019, 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from contextlib import contextmanager +import re +from typing import Any, Iterable, Iterator, List, Optional, Union + +from rtemsspec.content import Content, make_lines +from rtemsspec.items import Item, ItemGetValueContext, ItemMapper + +GenericContent = Union[str, List[str], "Content"] +GenericContentIterable = Union[Iterable[str], Iterable[List[str]], + Iterable[GenericContent]] + +_HEADER_LEVELS = ["#", "*", "=", "-", "^", "\""] + + +def _to_camel_case(name: str) -> str: + return name[0].upper() + re.sub( + r"\s+(.)", lambda match: match.group(1).upper(), + re.sub(r"[^ \t\n\r\f\va-zA-Z0-9]", " ", name[1:].replace("+", "X"))) + + +def get_reference(label: str, name: Optional[str] = None) -> str: + """ Returns the reference to the specified label. """ + if name: + return f":ref:`{name} <{label}>`" + return f":ref:`{label}`" + + +def get_label(name: str) -> str: + """ Returns the label for the specified name. """ + return _to_camel_case(name.strip()) + + +class SphinxContent(Content): + """ This class builds Sphinx content. """ + def __init__(self, section_level: int = 2): + super().__init__("CC-BY-SA-4.0", True) + self._tab = " " + self._section_level = section_level + self.section_label_prefix = "Section" + + def add_label(self, label: str) -> None: + """ Adds a label. """ + self.add(".. _" + label.strip() + ":") + + def add_header(self, name, level=2) -> None: + """ Adds a header. """ + name = name.strip() + self.add([name, _HEADER_LEVELS[level] * len(name)]) + + def add_header_with_label(self, + name: str, + level: int = 2, + label_prefix: Optional[str] = None) -> str: + """ Adds a header with label. """ + if label_prefix is None: + label_prefix = self.section_label_prefix + label = label_prefix + get_label(name) + self.add_label(label) + self.add_header(name, level) + return label + + def add_index_entries(self, entries) -> None: + """ Adds a list of index entries the content. """ + self.add([".. index:: " + entry for entry in make_lines(entries)]) + + def add_definition_item(self, + name: GenericContent, + definition: GenericContent, + wrap: bool = False) -> None: + """ Adds a definition item the content. """ + @contextmanager + def _definition_item_context(content: Content) -> Iterator[None]: + content.append(name) + content.push_indent() + yield + content.pop_indent() + + if wrap: + self.wrap(definition, context=_definition_item_context) + else: + self.add(definition, context=_definition_item_context) + + @contextmanager + def definition_item(self, name: GenericContent) -> Iterator[None]: + """ Opens a definition item context. """ + self.wrap(name) + self.push_indent() + yield + self.pop_indent() + + def open_directive(self, + name: str, + value: Optional[str] = None, + options: Optional[List[str]] = None) -> None: + """ Opens a directive. """ + value = " " + value if value else "" + self.add(f".. {name.strip()}::{value}") + self.push_indent() + self.add(options) + self.gap = True + + def close_directive(self) -> None: + """ Closes a directive. """ + self.pop_indent() + + @contextmanager + def directive(self, + name: str, + value: Optional[str] = None, + options: Optional[List[str]] = None): + """ Opens a directive context. """ + self.open_directive(name, value, options) + yield + self.close_directive() + + def open_section(self, + name: str, + label_prefix: Optional[str] = None) -> str: + """ Opens a section. """ + label = self.add_header_with_label(name, self._section_level, + label_prefix) + self._section_level += 1 + return label + + def close_section(self) -> None: + """ Closes a section. """ + self._section_level -= 1 + + @contextmanager + def section(self, + name: str, + label_prefix: Optional[str] = None) -> Iterator[str]: + """ Opens a section context. """ + yield self.open_section(name, label_prefix) + self.close_section() + + def add_list_item(self, content: GenericContent) -> None: + """ Adds a list item. """ + self.wrap(content, initial_indent="* ", subsequent_indent=" ") + + def add_list(self, + items: GenericContentIterable, + prologue: Optional[GenericContent] = None, + epilogue: Optional[GenericContent] = None, + add_blank_line: bool = False) -> None: + """ Adds a list with introduction. """ + if items: + self.wrap(prologue) + for item in items: + self.add_list_item(item) + if add_blank_line: + self.add_blank_line() + self.wrap(epilogue) + + def open_list_item(self, content: GenericContent) -> None: + """ Opens a list item. """ + self.add(["* "]) + self.push_indent(" ") + self.gap = True + self.paste(content) + + def close_list_item(self) -> None: + """ Closes a list item. """ + self.pop_indent() + self.gap = True + + @contextmanager + def list_item(self, content: GenericContent) -> Iterator[None]: + """ Opens a list item context. """ + self.open_list_item(content) + yield + self.close_list_item() + + def add_licence_and_copyrights(self) -> None: + """ + Adds a licence and copyright block according to the registered licenses + and copyrights. + """ + statements = self._copyrights.get_statements() + if statements: + self.prepend("") + self.prepend([f".. {stm}" for stm in statements]) + self.prepend([f".. SPDX-License-Identifier: {self._license}", ""]) + + +def _get_ref_term(ctx: ItemGetValueContext) -> Any: + return f":term:`{ctx.value[ctx.key]}`" + + +def _get_ref_term_plural(ctx: ItemGetValueContext) -> Any: + try: + return f":term:`{ctx.value[ctx.key]} <{ctx.value['term']}>`" + except KeyError: + return f":term:`{ctx.value['term']}s <{ctx.value['term']}>`" + + +def _get_appl_config_option(ctx: ItemGetValueContext) -> Any: + return f":ref:`{ctx.value[ctx.key]}`" + + +class SphinxMapper(ItemMapper): + """ Sphinx item mapper. """ + def __init__(self, item: Item): + super().__init__(item) + self.add_get_value("glossary/term:/term", _get_ref_term) + self.add_get_value("glossary/term:/plural", _get_ref_term_plural) + self.add_get_value("interface/appl-config-option/feature-enable:/name", + _get_appl_config_option) + self.add_get_value("interface/appl-config-option/feature:/name", + _get_appl_config_option) + self.add_get_value("interface/appl-config-option/initializer:/name", + _get_appl_config_option) + self.add_get_value("interface/appl-config-option/integer:/name", + _get_appl_config_option) |