From cf7da1843c45a4c2df7a749f7886a2d2ba0ee92a Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 19:25:40 +0200 Subject: Adding upstream version 7.2.6. Signed-off-by: Daniel Baumann --- sphinx/builders/texinfo.py | 229 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 sphinx/builders/texinfo.py (limited to 'sphinx/builders/texinfo.py') diff --git a/sphinx/builders/texinfo.py b/sphinx/builders/texinfo.py new file mode 100644 index 0000000..441b598 --- /dev/null +++ b/sphinx/builders/texinfo.py @@ -0,0 +1,229 @@ +"""Texinfo builder.""" + +from __future__ import annotations + +import os +import warnings +from os import path +from typing import TYPE_CHECKING, Any + +from docutils import nodes +from docutils.frontend import OptionParser +from docutils.io import FileOutput + +from sphinx import addnodes, package_dir +from sphinx.builders import Builder +from sphinx.environment.adapters.asset import ImageAdapter +from sphinx.errors import NoUri +from sphinx.locale import _, __ +from sphinx.util import logging +from sphinx.util.console import darkgreen # type: ignore[attr-defined] +from sphinx.util.display import progress_message, status_iterator +from sphinx.util.docutils import new_document +from sphinx.util.fileutil import copy_asset_file +from sphinx.util.nodes import inline_all_toctrees +from sphinx.util.osutil import SEP, ensuredir, make_filename_from_project +from sphinx.writers.texinfo import TexinfoTranslator, TexinfoWriter + +if TYPE_CHECKING: + from collections.abc import Iterable + + from docutils.nodes import Node + + from sphinx.application import Sphinx + from sphinx.config import Config + +logger = logging.getLogger(__name__) +template_dir = os.path.join(package_dir, 'templates', 'texinfo') + + +class TexinfoBuilder(Builder): + """ + Builds Texinfo output to create Info documentation. + """ + name = 'texinfo' + format = 'texinfo' + epilog = __('The Texinfo files are in %(outdir)s.') + if os.name == 'posix': + epilog += __("\nRun 'make' in that directory to run these through " + "makeinfo\n" + "(use 'make info' here to do that automatically).") + + supported_image_types = ['image/png', 'image/jpeg', + 'image/gif'] + default_translator_class = TexinfoTranslator + + def init(self) -> None: + self.docnames: Iterable[str] = [] + self.document_data: list[tuple[str, str, str, str, str, str, str, bool]] = [] + + def get_outdated_docs(self) -> str | list[str]: + return 'all documents' # for now + + def get_target_uri(self, docname: str, typ: str | None = None) -> str: + if docname not in self.docnames: + raise NoUri(docname, typ) + return '%' + docname + + def get_relative_uri(self, from_: str, to: str, typ: str | None = None) -> str: + # ignore source path + return self.get_target_uri(to, typ) + + def init_document_data(self) -> None: + preliminary_document_data = [list(x) for x in self.config.texinfo_documents] + if not preliminary_document_data: + logger.warning(__('no "texinfo_documents" config value found; no documents ' + 'will be written')) + return + # assign subdirs to titles + self.titles: list[tuple[str, str]] = [] + for entry in preliminary_document_data: + docname = entry[0] + if docname not in self.env.all_docs: + logger.warning(__('"texinfo_documents" config value references unknown ' + 'document %s'), docname) + continue + self.document_data.append(entry) # type: ignore[arg-type] + if docname.endswith(SEP + 'index'): + docname = docname[:-5] + self.titles.append((docname, entry[2])) + + def write(self, *ignored: Any) -> None: + self.init_document_data() + self.copy_assets() + for entry in self.document_data: + docname, targetname, title, author = entry[:4] + targetname += '.texi' + direntry = description = category = '' + if len(entry) > 6: + direntry, description, category = entry[4:7] + toctree_only = False + if len(entry) > 7: + toctree_only = entry[7] + destination = FileOutput( + destination_path=path.join(self.outdir, targetname), + encoding='utf-8') + with progress_message(__("processing %s") % targetname): + appendices = self.config.texinfo_appendices or [] + doctree = self.assemble_doctree(docname, toctree_only, appendices=appendices) + + with progress_message(__("writing")): + self.post_process_images(doctree) + docwriter = TexinfoWriter(self) + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + # DeprecationWarning: The frontend.OptionParser class will be replaced + # by a subclass of argparse.ArgumentParser in Docutils 0.21 or later. + settings: Any = OptionParser( + defaults=self.env.settings, + components=(docwriter,), + read_config_files=True).get_default_values() + settings.author = author + settings.title = title + settings.texinfo_filename = targetname[:-5] + '.info' + settings.texinfo_elements = self.config.texinfo_elements + settings.texinfo_dir_entry = direntry or '' + settings.texinfo_dir_category = category or '' + settings.texinfo_dir_description = description or '' + settings.docname = docname + doctree.settings = settings + docwriter.write(doctree, destination) + self.copy_image_files(targetname[:-5]) + + def assemble_doctree( + self, indexfile: str, toctree_only: bool, appendices: list[str], + ) -> nodes.document: + self.docnames = set([indexfile] + appendices) + logger.info(darkgreen(indexfile) + " ", nonl=True) + tree = self.env.get_doctree(indexfile) + tree['docname'] = indexfile + if toctree_only: + # extract toctree nodes from the tree and put them in a + # fresh document + new_tree = new_document('') + new_sect = nodes.section() + new_sect += nodes.title('', + '') + new_tree += new_sect + for node in tree.findall(addnodes.toctree): + new_sect += node + tree = new_tree + largetree = inline_all_toctrees(self, self.docnames, indexfile, tree, + darkgreen, [indexfile]) + largetree['docname'] = indexfile + for docname in appendices: + appendix = self.env.get_doctree(docname) + appendix['docname'] = docname + largetree.append(appendix) + logger.info('') + logger.info(__("resolving references...")) + self.env.resolve_references(largetree, indexfile, self) + # TODO: add support for external :ref:s + for pendingnode in largetree.findall(addnodes.pending_xref): + docname = pendingnode['refdocname'] + sectname = pendingnode['refsectname'] + newnodes: list[Node] = [nodes.emphasis(sectname, sectname)] + for subdir, title in self.titles: + if docname.startswith(subdir): + newnodes.append(nodes.Text(_(' (in '))) + newnodes.append(nodes.emphasis(title, title)) + newnodes.append(nodes.Text(')')) + break + else: + pass + pendingnode.replace_self(newnodes) + return largetree + + def copy_assets(self) -> None: + self.copy_support_files() + + def copy_image_files(self, targetname: str) -> None: + if self.images: + stringify_func = ImageAdapter(self.app.env).get_original_image_uri + for src in status_iterator(self.images, __('copying images... '), "brown", + len(self.images), self.app.verbosity, + stringify_func=stringify_func): + dest = self.images[src] + try: + imagedir = path.join(self.outdir, targetname + '-figures') + ensuredir(imagedir) + copy_asset_file(path.join(self.srcdir, src), + path.join(imagedir, dest)) + except Exception as err: + logger.warning(__('cannot copy image file %r: %s'), + path.join(self.srcdir, src), err) + + def copy_support_files(self) -> None: + try: + with progress_message(__('copying Texinfo support files')): + logger.info('Makefile ', nonl=True) + copy_asset_file(os.path.join(template_dir, 'Makefile'), self.outdir) + except OSError as err: + logger.warning(__("error writing file Makefile: %s"), err) + + +def default_texinfo_documents( + config: Config, +) -> list[tuple[str, str, str, str, str, str, str]]: + """ Better default texinfo_documents settings. """ + filename = make_filename_from_project(config.project) + return [(config.root_doc, filename, config.project, config.author, filename, + 'One line description of project', 'Miscellaneous')] + + +def setup(app: Sphinx) -> dict[str, Any]: + app.add_builder(TexinfoBuilder) + + app.add_config_value('texinfo_documents', default_texinfo_documents, False) + app.add_config_value('texinfo_appendices', [], False) + app.add_config_value('texinfo_elements', {}, False) + app.add_config_value('texinfo_domain_indices', True, False, [list]) + app.add_config_value('texinfo_show_urls', 'footnote', False) + app.add_config_value('texinfo_no_detailmenu', False, False) + app.add_config_value('texinfo_cross_references', True, False) + + return { + 'version': 'builtin', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } -- cgit v1.2.3