Source code for tmep.doc

"""Extract docstrings from func.py to document the template functions."""

from __future__ import annotations

import argparse
import re
import textwrap
from pathlib import Path
from typing import Literal, Optional

from tmep.functions import DefaultTemplateFunctions

fns = DefaultTemplateFunctions().get()
OutputFormat = Literal["txt", "rst"]


def _underline(text: str, indent: int = 4) -> str:
    """Underline a given text"""
    length = len(text)
    indentation = " " * indent
    return indentation + text + "\n" + indentation + ("-" * length)


def _wrap(text: str, width: int = 78, indent: int = 4) -> str:
    """Apply textwrap to a given text string"""
    return textwrap.fill(
        text,
        width=width,
        initial_indent=" " * indent,
        subsequent_indent=" " * indent,
    )


class FnDoc:
    name: str
    synopsis: Optional[str]
    example: Optional[str]
    description: Optional[str]

    def __init__(self, name: str):
        self.name = name

        doc = fns[name].__doc__
        if doc:
            self.synopsis = self.__extract_value(doc, "synopsis")
            self.example = self.__extract_value(doc, "example")
            self.description = self.__extract_value(doc, "description")

    def __extract_value(self, string: str, key: str) -> Optional[str]:
        """Extract strings from the docstrings

        .. code-block:: text

            * synopsis: ``%shorten{text, max_size}``
            * example: ``%shorten{$title, 32}``
            * description: Shorten “text” on word boundarys.

        """
        value = re.findall(r"\* " + key + ": (.*)", string)
        if value:
            return re.sub(r" {2,}", " ", value[0])
        return None

    def format(self, output_format: OutputFormat = "txt") -> str:
        if output_format == "txt":
            output = _underline(self.name) + "\n\n"
            if self.synopsis:
                output += _wrap(self.synopsis) + "\n"
            if self.description:
                output += _wrap(self.description, indent=8) + "\n"
            if self.example:
                output += _wrap(self.example, indent=8) + "\n"
            return output
        elif output_format == "rst":
            body = _wrap(f"{self.synopsis}:\n\n{self.description}", indent=2)
            if self.example:
                body += "\n\n" + _wrap(f"**Example:** {self.example}", indent=2)
            return self.name + "\n" + body + "\n"


class FnDocCollection:
    fn_names: list[str]
    fn_docs: list[FnDoc]

    def __init__(self) -> None:
        self.fn_docs = []
        self.fn_names = []
        for name, _ in fns.items():
            self.fn_names.append(name)
            self.fn_docs.append(FnDoc(name=name))
        self.fn_names.sort()

    def format(self, output_format: OutputFormat = "txt") -> str:
        """Retrieve a formated text string"""
        output: list[str] = []
        for fn_name in self.fn_names:
            output.append(FnDoc(fn_name).format(output_format))
        return "\n".join(output)


def _format_fn_docs(output_format: OutputFormat = "rst") -> str:
    """
    Format the documentation of the template functions in different formats.

    :return: The documentation string.
    """
    return FnDocCollection().format(output_format)


def _read_general_introduction_rst() -> str:
    with open(Path(__file__).parent / "help.rst", "r") as file:
        return file.read()


DocOutput = Literal[
    "functions_rst",
    "functions_txt",
    "introduction_rst",
]


[docs] def get_doc(doc: DocOutput = "functions_txt") -> str: """O Get the documentation in the specified format. :param doc: The format of the documentation to retrieve. Default is ``functions_txt``. Possible values are ``functions_rst``, ``functions_txt``, and ``introduction_rst``. :return: The documentation in the specified format. """ if doc == "functions_rst": return _format_fn_docs("rst") if doc == "functions_txt": return _format_fn_docs("txt") if doc == "introduction_rst": return _read_general_introduction_rst()
__all__: list[str] = ["get_doc", "print_doc"]