view docs/conf.py @ 253:c12bf3b4c31c

Suppress section numbering for changelog items. Use the recently implemented feature in my-doc-style.sty.
author Franz Glasner <fzglas.hg@dom66.de>
date Sun, 17 May 2026 11:40:41 +0200
parents 5d3f7d80766f
children 881ae18c07f8
line wrap: on
line source

# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

import ast
import datetime
import functools
import io
import os
import sys
import re

import pygments.lexers
import pygments.filters
import sphinx.util.logging
import sphinx.transforms

sys.path.insert(0, os.path.dirname(os.path.abspath('.')))

from pygments_lexer_pseudocode2.lexers.algpseudocode import (
    AlgPseudocodeLexer, AlgPseudocodeLexer_DE, AlgPseudocodeLexer_FR)
from pygments_lexer_pseudocode2.lexers.fr_pseudocode import FrPseudocodeLexer
from pygments_lexer_pseudocode2.filters import (
    TokenReplaceFilter, ErrorToGenericErrorTokenFilter)


needs_sphinx = '2.1'
"""This is the theory:

- 2.1: - :py:meth:Sphinx.add_lexer` takes a class as argument

Currently really built and tested with Sphinx 7.1.2.

"""

current_date = datetime.date.today().isoformat()

master_doc = "index"

# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

project = 'Pygments Pseudocode Lexer'
copyright = u'2026 Franz Glasner. © Copyright 2015 Simon Wachter'
author = 'Franz Glasner'

#
# Determine "release" and other release metadata dynamically from the
# package's "__version__" or other VCS data.
#

#
# Optimistically assume that all keywords are expanded properly everywhere:
# do not define special VCSxxx keyword below.
#
define_rest_keywords = False
with io.open("../pygments_lexer_pseudocode2/__init__.py",
             "rt",
             encoding="utf-8") as relfp:
    verfiledata = relfp.read()
release = ast.literal_eval(
    re.search(r"""^\s*__version__\s*=\s*(("|')[^"']*\2)""",
              verfiledata,
              re.MULTILINE).group(1))
release_date = today = ast.literal_eval(
    re.search(r"""^\s*__date__\s*=\s*(("|')[^"']*\2)""",
              verfiledata,
              re.MULTILINE).group(1))
if (not release_date
        or (release_date.startswith("|") and release_date.endswith("|"))):
    release_date = today = "dev-%s" % (current_date,)
release_rev = ast.literal_eval(
    re.search(r"""^\s*__revision__\s*=\s*(("|')[^"']*\2)""",
              verfiledata,
              re.MULTILINE).group(1))
if (not release_rev
        or (release_rev.startswith("|") or release_rev.endswith("|"))):
    #
    # Above assumption is not true: "hg kwarchive" may not have been called.
    # Try to determine from VCS.
    #
    import subprocess
    try:
        release_rev = subprocess.check_output(
            ["hg", "id", "-i"], stderr=subprocess.STDOUT)
    except Exception:
        release_rev = "<UNKNOWN>"
    else:
        if sys.version_info[0] >= 3:
            release_rev = release_rev.decode("ascii")
        release_rev = "dev-%s" % (release_rev.strip(),)
    define_rest_keywords = True

version = release
primary_domain = None

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

extensions = [
    "sphinx.ext.todo",
]

templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'lexerlist.rst']

highlight_language = "none"

rst_prolog = """
.. role:: algpseudocode(code)
.. _Pygments: https://pygments.org/
.. _Sphinx: https://www.sphinx-doc.org
.. _Python: https://www.python.org/
.. _Algpseudocodex: https://ctan.org/pkg/algpseudocodex
"""


# --- Options for todo extension ---------------------------------------------
todo_include_todos = True


# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_static_path = ['_static']
html_extra_path = ['../LICENSES']
html_copy_source = False
html_show_sourcelink = False

#html_theme = 'alabaster'
html_theme = 'haiku'
html_css_files = ["custom-haiku.css"]
html_title = 'The %s v%s' % (project, release)
html_short_title = html_title
html_last_updated_fmt = "%s (rev %s)" % (current_date, release_rev)
#pygments_style = "sphinx"
pygments_style = "default"

# --- Options for LaTeX output -----------------------------------------------
# https://www.sphinx-doc.org/en/master/latex.html
latex_engine = 'lualatex'
latex_elements = {
    "papersize": "a4paper",
    "babel": r"\usepackage{babel}",
    "fontpkg": r"\usepackage[fonts=adobesourcepro]{my-doc-fonts}",
    "releasename": "Version",
    "fncychap": r"\usepackage[Sonny]{fncychap}",
    "preamble": r"\usepackage[stdtitle=false]{my-doc-style}",
    "maketitle": r"\builddate{%s}\vcsrevision{%s}\sphinxmaketitle"
        % (current_date, release_rev),
}
latex_theme = "manual"
latex_show_urls = "footnote"
latex_show_pagerefs = True
latex_domain_indices = False
latex_documents = [
    ("_latex/index-latex", "PygmentsLexerPseudocode2.tex", "The Pygments Pseudocode Lexer", "Franz Glasner", "manual", True),
]
latex_additional_files = [
    "_latex/my-doc-fonts.sty",
    "_latex/my-doc-style.sty",
    "examples/example-1.pseudocode",         # linked via \url{}
    "examples/algorithm-dinic.pseudocode",
    "examples/algorithm-ford-fulkerson.pseudocode",
    "examples/algorithm-edmonds-karp.pseudocode",
]


class IAMCustomSubstitutions(sphinx.transforms.SphinxTransform):

    """Implement custom variable substitutions"""

    default_priority = sphinx.transforms.DefaultSubstitutions.default_priority

    _SUBSTITUTIONS = {
        "release_date": release_date,
        "release_rev": release_rev
    }
    if define_rest_keywords:
        _SUBSTITUTIONS.update(
            {"VCSJustDate": release_date,
             "VCSRevision": release_rev,
             "VCSHGRevision": release_rev})

    def apply(self):
        from docutils import nodes
        for ref in self.document.traverse(nodes.substitution_reference):
            refname = ref['refname']
            if refname in self._SUBSTITUTIONS:
                stext = self._SUBSTITUTIONS[refname]
                ref.replace_self(nodes.Text(stext, stext))
            #if refname in ('release_date' 'release_rev'):
            #    stext = self.config[refname]
            #    ref.replace_self(nodes.Text(stext, stext))


def setup(app):
    #
    # Custom release_date and commit id variables with a custom substitution
    # |release_date| and |release_rev|'.
    #
    app.add_config_value('release_date', '', 'env')
    app.add_config_value('release_rev', '', 'env')
    # Custom variable substitution
    app.add_transform(IAMCustomSubstitutions)

    #
    # Add a custom lexer: AlgPseudocodeLexer with custom init option "no_end"
    # Given lexer must be callable: so use an indirection with "partial".
    #
    # See also:
    # - https://stackoverflow.com/questions/11413203/sphinx-pygments-lexer-filter-extension
    #
    app.add_lexer("NoEndAlgPseudocode",
                  functools.partial(AlgPseudocodeLexer, no_end=True))
    # For developing a lexer with smoother error handling
    app.add_lexer("no-raiseonerror-algpseudocode",
                  functools.partial(AlgPseudocodeLexer,
                                    prohibit_raiseonerror_filter=True))
    #
    # To test with the custom filter that maps
    # Token.Error to Token.Generic.Error
    #
    app.add_lexer("genericerror-algpseudocode",
                  functools.partial(AlgPseudocodeLexer,
                                    filters=["errortogenericerror"]))

    #
    # Prepare for building docs while the package is not installed:
    # Install by "hand" into pygments!
    # This is an ugly *HACK*!
    #
    # IMPORTANT: Synchronize names with pyproject.toml!
    #
    try:
        if not pygments.lexers.find_lexer_class("AlgPseudocode"):
            sphinx.util.logging.getLogger("conf-setup").info(
                "%s", "Installing lexer `AlgPseudocode' and language variants")
            for clsname, lexer in (
                    ("AlgPseudocodeLexer", AlgPseudocodeLexer),
                    ("AlgPseudocodeLexer_DE", AlgPseudocodeLexer_DE),
                    ("AlgPseudocodeLexer_FR", AlgPseudocodeLexer_FR)):
                pygments.lexers.LEXERS[clsname] = (
                "pygments_lexer_pseudocode2.lexers.algpseudocode",
                lexer.name,
                tuple(lexer.aliases),
                tuple(lexer.filenames),
                tuple(lexer.mimetypes))
        if not pygments.lexers.find_lexer_class("FrPseudocode"):
            sphinx.util.logging.getLogger("conf-setup").info(
                "%s", "Installing lexer `FrPseudocode'")
            for clsname, lexer in (
                    ("FrPseudocodeLexer", FrPseudocodeLexer),):
                pygments.lexers.LEXERS[clsname] = (
                "pygments_lexer_pseudocode2.lexers.fr_pseudocode",
                lexer.name,
                tuple(lexer.aliases),
                tuple(lexer.filenames),
                tuple(lexer.mimetypes))
        if not pygments.filters.find_filter_class("tokenreplace"):
            sphinx.util.logging.getLogger("conf-setup").info(
                "%s", "Installing filter `tokenreplace'")
            pygments.filters.FILTERS["tokenreplace"] = TokenReplaceFilter
        if not pygments.filters.find_filter_class("errortogenericerror"):
            sphinx.util.logging.getLogger("conf-setup").info(
                "%s", "Installing filter `errortogenericerror'")
            pygments.filters.FILTERS["errortogenericerror"] = \
                ErrorToGenericErrorTokenFilter
    except Exception as ex:
        sphinx.util.logging.getLogger("conf-setup").error("%s", str(ex))
        sphinx.util.logging.getLogger("conf-setup").error(
            "%s",
            "No lexers/filters from pygments_lexer_pseudocode2 available;"
            " please install or call `pip install -e .' .")