diff options
author | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2021-12-11 16:59:56 +0300 |
---|---|---|
committer | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2021-12-11 16:59:56 +0300 |
commit | 5563f672eccd3aa93c304ba6bac04ee2360b8c4e (patch) | |
tree | 48f26368337d0f2c3322aecd5a3e3db85c1b1682 /sphinx/writers | |
parent | 1227799abf0d0e3dafa0d61461cf613468e894df (diff) | |
parent | c6fc5dff5334dc04c7858f2752a5e2c22f25eaeb (diff) |
Merge branch '4.x' into fix-footnote-in-info
Diffstat (limited to 'sphinx/writers')
-rw-r--r-- | sphinx/writers/html.py | 50 | ||||
-rw-r--r-- | sphinx/writers/html5.py | 56 | ||||
-rw-r--r-- | sphinx/writers/latex.py | 33 | ||||
-rw-r--r-- | sphinx/writers/manpage.py | 13 | ||||
-rw-r--r-- | sphinx/writers/texinfo.py | 20 | ||||
-rw-r--r-- | sphinx/writers/text.py | 37 | ||||
-rw-r--r-- | sphinx/writers/xml.py | 4 |
7 files changed, 140 insertions, 73 deletions
diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py index d633f07e8..fead4c61d 100644 --- a/sphinx/writers/html.py +++ b/sphinx/writers/html.py @@ -12,6 +12,7 @@ import copy import os import posixpath import re +import urllib.parse import warnings from typing import TYPE_CHECKING, Iterable, Tuple, cast @@ -22,7 +23,7 @@ from docutils.writers.html4css1 import Writer from sphinx import addnodes from sphinx.builders import Builder -from sphinx.deprecation import RemovedInSphinx50Warning +from sphinx.deprecation import RemovedInSphinx50Warning, RemovedInSphinx60Warning from sphinx.locale import _, __, admonitionlabels from sphinx.util import logging from sphinx.util.docutils import SphinxTranslator @@ -95,8 +96,8 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): self.secnumber_suffix = self.config.html_secnumber_suffix self.param_separator = '' self.optional_param_level = 0 - self._table_row_index = 0 - self._fieldlist_row_index = 0 + self._table_row_indices = [0] + self._fieldlist_row_indices = [0] self.required_params_left = 0 def visit_start_of_file(self, node: Element) -> None: @@ -174,10 +175,12 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): pass def visit_desc_returns(self, node: Element) -> None: - self.body.append(' → ') + self.body.append(' <span class="sig-return">') + self.body.append('<span class="sig-return-icon">→</span>') + self.body.append(' <span class="sig-return-typehint">') def depart_desc_returns(self, node: Element) -> None: - pass + self.body.append('</span></span>') def visit_desc_parameterlist(self, node: Element) -> None: self.body.append('<span class="sig-paren">(</span>') @@ -415,7 +418,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): # overwritten def visit_title(self, node: Element) -> None: if isinstance(node.parent, addnodes.compact_paragraph) and node.parent.get('toctree'): - self.body.append(self.starttag(node, 'p', '', CLASS='caption')) + self.body.append(self.starttag(node, 'p', '', CLASS='caption', ROLE='heading')) self.body.append('<span class="caption-text">') self.context.append('</span></p>\n') else: @@ -587,7 +590,8 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): self.context.append('</a>') elif 'filename' in node: atts['class'] += ' internal' - atts['href'] = posixpath.join(self.builder.dlpath, node['filename']) + atts['href'] = posixpath.join(self.builder.dlpath, + urllib.parse.quote(node['filename'])) self.body.append(self.starttag(node, 'a', '', **atts)) self.context.append('</a>') else: @@ -803,16 +807,20 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): # overwritten to add even/odd classes def visit_table(self, node: Element) -> None: - self._table_row_index = 0 + self._table_row_indices.append(0) # set align=default if align not specified to give a default style node.setdefault('align', 'default') return super().visit_table(node) + def depart_table(self, node: Element) -> None: + self._table_row_indices.pop() + super().depart_table(node) + def visit_row(self, node: Element) -> None: - self._table_row_index += 1 - if self._table_row_index % 2 == 0: + self._table_row_indices[-1] += 1 + if self._table_row_indices[-1] % 2 == 0: node['classes'].append('row-even') else: node['classes'].append('row-odd') @@ -825,12 +833,16 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): self.body[-1] = ' ' def visit_field_list(self, node: Element) -> None: - self._fieldlist_row_index = 0 + self._fieldlist_row_indices.append(0) return super().visit_field_list(node) + def depart_field_list(self, node: Element) -> None: + self._fieldlist_row_indices.pop() + return super().depart_field_list(node) + def visit_field(self, node: Element) -> None: - self._fieldlist_row_index += 1 - if self._fieldlist_row_index % 2 == 0: + self._fieldlist_row_indices[-1] += 1 + if self._fieldlist_row_indices[-1] % 2 == 0: node['classes'].append('field-even') else: node['classes'].append('field-odd') @@ -872,3 +884,15 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): warnings.warn('HTMLTranslator.permalink_text is deprecated.', RemovedInSphinx50Warning, stacklevel=2) return self.config.html_permalinks_icon + + @property + def _fieldlist_row_index(self): + warnings.warn('_fieldlist_row_index is deprecated', + RemovedInSphinx60Warning, stacklevel=2) + return self._fieldlist_row_indices[-1] + + @property + def _table_row_index(self): + warnings.warn('_table_row_index is deprecated', + RemovedInSphinx60Warning, stacklevel=2) + return self._table_row_indices[-1] diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py index 469642591..bba07f447 100644 --- a/sphinx/writers/html5.py +++ b/sphinx/writers/html5.py @@ -2,7 +2,7 @@ sphinx.writers.html5 ~~~~~~~~~~~~~~~~~~~~ - Experimental docutils writers for HTML5 handling Sphinx' custom nodes. + Experimental docutils writers for HTML5 handling Sphinx's custom nodes. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. @@ -11,8 +11,9 @@ import os import posixpath import re +import urllib.parse import warnings -from typing import TYPE_CHECKING, Iterable, Tuple, cast +from typing import TYPE_CHECKING, Iterable, Set, Tuple, cast from docutils import nodes from docutils.nodes import Element, Node, Text @@ -55,6 +56,10 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): """ builder: "StandaloneHTMLBuilder" = None + # Override docutils.writers.html5_polyglot:HTMLTranslator + # otherwise, nodes like <inline classes="s">...</inline> will be + # converted to <s>...</s> by `visit_inline`. + supported_inline_tags: Set[str] = set() def __init__(self, document: nodes.document, builder: Builder) -> None: super().__init__(document, builder) @@ -66,8 +71,8 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): self.secnumber_suffix = self.config.html_secnumber_suffix self.param_separator = '' self.optional_param_level = 0 - self._table_row_index = 0 - self._fieldlist_row_index = 0 + self._table_row_indices = [0] + self._fieldlist_row_indices = [0] self.required_params_left = 0 def visit_start_of_file(self, node: Element) -> None: @@ -145,10 +150,12 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): pass def visit_desc_returns(self, node: Element) -> None: - self.body.append(' → ') + self.body.append(' <span class="sig-return">') + self.body.append('<span class="sig-return-icon">→</span>') + self.body.append(' <span class="sig-return-typehint">') def depart_desc_returns(self, node: Element) -> None: - pass + self.body.append('</span></span>') def visit_desc_parameterlist(self, node: Element) -> None: self.body.append('<span class="sig-paren">(</span>') @@ -366,7 +373,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # overwritten def visit_title(self, node: Element) -> None: if isinstance(node.parent, addnodes.compact_paragraph) and node.parent.get('toctree'): - self.body.append(self.starttag(node, 'p', '', CLASS='caption')) + self.body.append(self.starttag(node, 'p', '', CLASS='caption', ROLE='heading')) self.body.append('<span class="caption-text">') self.context.append('</span></p>\n') else: @@ -527,7 +534,8 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): self.context.append('</a>') elif 'filename' in node: atts['class'] += ' internal' - atts['href'] = posixpath.join(self.builder.dlpath, node['filename']) + atts['href'] = posixpath.join(self.builder.dlpath, + urllib.parse.quote(node['filename'])) self.body.append(self.starttag(node, 'a', '', **atts)) self.context.append('</a>') else: @@ -739,7 +747,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # overwritten to add even/odd classes def visit_table(self, node: Element) -> None: - self._table_row_index = 0 + self._table_row_indices.append(0) atts = {} classes = [cls.strip(' \t\n') for cls in self.settings.table_style.split(',')] @@ -753,9 +761,13 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): tag = self.starttag(node, 'table', CLASS=' '.join(classes), **atts) self.body.append(tag) + def depart_table(self, node: Element) -> None: + self._table_row_indices.pop() + super().depart_table(node) + def visit_row(self, node: Element) -> None: - self._table_row_index += 1 - if self._table_row_index % 2 == 0: + self._table_row_indices[-1] += 1 + if self._table_row_indices[-1] % 2 == 0: node['classes'].append('row-even') else: node['classes'].append('row-odd') @@ -763,12 +775,16 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): node.column = 0 # type: ignore def visit_field_list(self, node: Element) -> None: - self._fieldlist_row_index = 0 + self._fieldlist_row_indices.append(0) return super().visit_field_list(node) + def depart_field_list(self, node: Element) -> None: + self._fieldlist_row_indices.pop() + return super().depart_field_list(node) + def visit_field(self, node: Element) -> None: - self._fieldlist_row_index += 1 - if self._fieldlist_row_index % 2 == 0: + self._fieldlist_row_indices[-1] += 1 + if self._fieldlist_row_indices[-1] % 2 == 0: node['classes'].append('field-even') else: node['classes'].append('field-odd') @@ -818,3 +834,15 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): for id in node['ids'][1:]: self.body.append('<span id="%s"></span>' % id) node['ids'].remove(id) + + @property + def _fieldlist_row_index(self): + warnings.warn('_fieldlist_row_index is deprecated', + RemovedInSphinx60Warning, stacklevel=2) + return self._fieldlist_row_indices[-1] + + @property + def _table_row_index(self): + warnings.warn('_table_row_index is deprecated', + RemovedInSphinx60Warning, stacklevel=2) + return self._table_row_indices[-1] diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 796e0cb92..6f7e20241 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -35,7 +35,7 @@ from sphinx.util.texescape import tex_replace_map try: from docutils.utils.roman import toRoman except ImportError: - # In Debain/Ubuntu, roman package is provided as roman, not as docutils.utils.roman + # In Debian/Ubuntu, roman package is provided as roman, not as docutils.utils.roman from roman import toRoman # type: ignore if TYPE_CHECKING: @@ -123,7 +123,7 @@ class Table: self.col = 0 self.row = 0 - # A mapping a table location to the cell_id (cell = rectangular area) + # A dict mapping a table location to a cell_id (cell = rectangular area) self.cells: Dict[Tuple[int, int], int] = defaultdict(int) self.cell_id = 0 # last assigned cell_id @@ -202,7 +202,7 @@ class Table: class TableCell: - """A cell data of tables.""" + """Data of a cell in a table.""" def __init__(self, table: Table, row: int, col: int) -> None: if table.cells[(row, col)] == 0: @@ -445,8 +445,7 @@ class LaTeXTranslator(SphinxTranslator): return body def format_docclass(self, docclass: str) -> str: - """ prepends prefix to sphinx document classes - """ + """Prepends prefix to sphinx document classes""" warnings.warn('LaTeXWriter.format_docclass() is deprecated.', RemovedInSphinx50Warning, stacklevel=2) if docclass in self.docclasses: @@ -652,7 +651,7 @@ class LaTeXTranslator(SphinxTranslator): raise nodes.SkipNode else: short = '' - if node.traverse(nodes.image): + if list(node.traverse(nodes.image)): short = ('[%s]' % self.escape(' '.join(clean_astext(node).split()))) try: @@ -758,9 +757,7 @@ class LaTeXTranslator(SphinxTranslator): self._depart_signature_line(node) def visit_desc_content(self, node: Element) -> None: - if node.children and not isinstance(node.children[0], nodes.paragraph): - # avoid empty desc environment which causes a formatting bug - self.body.append('~') + pass def depart_desc_content(self, node: Element) -> None: pass @@ -1012,7 +1009,7 @@ class LaTeXTranslator(SphinxTranslator): context = (r'\par' + CR + r'\vskip-\baselineskip' r'\vbox{\hbox{\strut}}\end{varwidth}%' + CR + context) self.needs_linetrimming = 1 - if len(node.traverse(nodes.paragraph)) >= 2: + if len(list(node.traverse(nodes.paragraph))) >= 2: self.table.has_oldproblematic = True if isinstance(node.parent.parent, nodes.thead) or (cell.col in self.table.stubs): if len(node) == 1 and isinstance(node[0], nodes.paragraph) and node.astext() == '': @@ -1211,7 +1208,7 @@ class LaTeXTranslator(SphinxTranslator): ncolumns = node['ncolumns'] if self.compact_list > 1: self.body.append(r'\setlength{\multicolsep}{0pt}' + CR) - self.body.append(r'\begin{multicols}{' + ncolumns + '}\raggedright' + CR) + self.body.append(r'\begin{multicols}{' + ncolumns + r'}\raggedright' + CR) self.body.append(r'\begin{itemize}\setlength{\itemsep}{0pt}' r'\setlength{\parskip}{0pt}' + CR) if self.table: @@ -1225,7 +1222,7 @@ class LaTeXTranslator(SphinxTranslator): pass def depart_hlistcol(self, node: Element) -> None: - # \columnbreak would guarantee same columns as in html ouput. But + # \columnbreak would guarantee same columns as in html output. But # some testing with long items showed that columns may be too uneven. # And in case only of short items, the automatic column breaks should # match the ones pre-computed by the hlist() directive. @@ -1314,7 +1311,7 @@ class LaTeXTranslator(SphinxTranslator): base, ext = path.splitext(uri) if self.in_title and base: # Lowercase tokens forcely because some fncychap themes capitalize - # the options of \sphinxincludegraphics unexpectly (ex. WIDTH=...). + # the options of \sphinxincludegraphics unexpectedly (ex. WIDTH=...). self.body.append(r'\lowercase{\sphinxincludegraphics%s}{{%s}%s}' % (options, base, ext)) else: @@ -1890,7 +1887,7 @@ class LaTeXTranslator(SphinxTranslator): self.context[-1] += 1 def visit_option_argument(self, node: Element) -> None: - """The delimiter betweeen an option and its argument.""" + """The delimiter between an option and its argument.""" self.body.append(node.get('delimiter', ' ')) def depart_option_argument(self, node: Element) -> None: @@ -1975,10 +1972,14 @@ class LaTeXTranslator(SphinxTranslator): pass def visit_container(self, node: Element) -> None: - pass + classes = node.get('classes', []) + for c in classes: + self.body.append('\n\\begin{sphinxuseclass}{%s}' % c) def depart_container(self, node: Element) -> None: - pass + classes = node.get('classes', []) + for c in classes: + self.body.append('\n\\end{sphinxuseclass}') def visit_decoration(self, node: Element) -> None: pass diff --git a/sphinx/writers/manpage.py b/sphinx/writers/manpage.py index 95e0f5658..da5f4c241 100644 --- a/sphinx/writers/manpage.py +++ b/sphinx/writers/manpage.py @@ -56,7 +56,7 @@ class NestedInlineTransform: def apply(self, **kwargs: Any) -> None: matcher = NodeMatcher(nodes.literal, nodes.emphasis, nodes.strong) - for node in self.document.traverse(matcher): # type: TextElement + for node in list(self.document.traverse(matcher)): # type: TextElement if any(matcher(subnode) for subnode in node): pos = node.parent.index(node) for subnode in reversed(list(node)): @@ -73,7 +73,7 @@ class NestedInlineTransform: class ManualPageTranslator(SphinxTranslator, BaseTranslator): """ - Custom translator. + Custom man page translator. """ _docinfo: Dict[str, Any] = {} @@ -112,9 +112,10 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator): # overwritten -- added quotes around all .TH arguments def header(self) -> str: tmpl = (".TH \"%(title_upper)s\" \"%(manual_section)s\"" - " \"%(date)s\" \"%(version)s\" \"%(manual_group)s\"\n" - ".SH NAME\n" - "%(title)s \\- %(subtitle)s\n") + " \"%(date)s\" \"%(version)s\" \"%(manual_group)s\"\n") + if self._docinfo['subtitle']: + tmpl += (".SH NAME\n" + "%(title)s \\- %(subtitle)s\n") return tmpl % self._docinfo def visit_start_of_file(self, node: Element) -> None: @@ -226,7 +227,7 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator): # overwritten -- don't make whole of term bold if it includes strong node def visit_term(self, node: Element) -> None: - if node.traverse(nodes.strong): + if list(node.traverse(nodes.strong)): self.body.append('\n') else: super().visit_term(node) diff --git a/sphinx/writers/texinfo.py b/sphinx/writers/texinfo.py index ebb05d9ab..44842f754 100644 --- a/sphinx/writers/texinfo.py +++ b/sphinx/writers/texinfo.py @@ -194,6 +194,7 @@ class TexinfoTranslator(SphinxTranslator): self.curfilestack: List[str] = [] self.footnotestack: List[Dict[str, List[Union[collected_footnote, bool]]]] = [] # NOQA self.in_footnote = 0 + self.in_samp = 0 self.handled_abbrs: Set[str] = set() self.colwidths: List[int] = None @@ -545,9 +546,12 @@ class TexinfoTranslator(SphinxTranslator): def add_xref(self, id: str, name: str, node: Node) -> None: name = self.escape_menu(name) sid = self.get_short_id(id) - self.body.append('@ref{%s,,%s}' % (sid, name)) - self.referenced_ids.add(sid) - self.referenced_ids.add(self.escape_id(id)) + if self.config.texinfo_cross_references: + self.body.append('@ref{%s,,%s}' % (sid, name)) + self.referenced_ids.add(sid) + self.referenced_ids.add(self.escape_id(id)) + else: + self.body.append(name) # -- Visiting @@ -811,15 +815,23 @@ class TexinfoTranslator(SphinxTranslator): self.body.append('}') def visit_emphasis(self, node: Element) -> None: - self.body.append('@emph{') + element = 'emph' if not self.in_samp else 'var' + self.body.append('@%s{' % element) def depart_emphasis(self, node: Element) -> None: self.body.append('}') + def is_samp(self, node: Element) -> bool: + return 'samp' in node['classes'] + def visit_literal(self, node: Element) -> None: + if self.is_samp(node): + self.in_samp += 1 self.body.append('@code{') def depart_literal(self, node: Element) -> None: + if self.is_samp(node): + self.in_samp -= 1 self.body.append('}') def visit_superscript(self, node: Element) -> None: diff --git a/sphinx/writers/text.py b/sphinx/writers/text.py index d8dab9181..ba310e072 100644 --- a/sphinx/writers/text.py +++ b/sphinx/writers/text.py @@ -29,7 +29,7 @@ if TYPE_CHECKING: class Cell: """Represents a cell in a table. - It can span on multiple columns or on multiple lines. + It can span multiple columns or multiple lines. """ def __init__(self, text: str = "", rowspan: int = 1, colspan: int = 1) -> None: self.text = text @@ -52,7 +52,7 @@ class Cell: class Table: - """Represents a table, handling cells that can span on multiple lines + """Represents a table, handling cells that can span multiple lines or rows, like:: +-----------+-----+ @@ -63,22 +63,22 @@ class Table: | DDD | CCC | +-----+-----------+ - This class can be used in two ways: + This class can be used in two ways, either: - - Either with absolute positions: call ``table[line, col] = Cell(...)``, - this overwrite an existing cell if any. + - With absolute positions: call ``table[line, col] = Cell(...)``, + this overwrites any existing cell(s) at these positions. - - Either with relative positions: call the ``add_row()`` and + - With relative positions: call the ``add_row()`` and ``add_cell(Cell(...))`` as needed. - Cell spanning on multiple rows or multiple columns (having a + Cells spanning multiple rows or multiple columns (having a colspan or rowspan greater than one) are automatically referenced - by all the table cells they covers. This is a useful - representation as we can simply check ``if self[x, y] is self[x, - y+1]`` to recognize a rowspan. + by all the table cells they cover. This is a useful + representation as we can simply check + ``if self[x, y] is self[x, y+1]`` to recognize a rowspan. Colwidth is not automatically computed, it has to be given, either - at construction time, either during the table construction. + at construction time, or during the table construction. Example usage:: @@ -112,14 +112,13 @@ class Table: self.current_col = 0 def set_separator(self) -> None: - """Sets the separator below the current line. - """ + """Sets the separator below the current line.""" self.separator = len(self.lines) def add_cell(self, cell: Cell) -> None: """Add a cell to the current line, to use with ``add_row()``. To add - a cell spanning on multiple lines or rows, simply set the - ``cell.colspan`` or ``cell.rowspan`` BEFORE inserting it to + a cell spanning multiple lines or rows, simply set the + ``cell.colspan`` or ``cell.rowspan`` BEFORE inserting it into the table. """ while self[self.current_line, self.current_col]: @@ -158,7 +157,7 @@ class Table: def cell_width(self, cell: Cell, source: List[int]) -> int: """Give the cell width, according to the given source (either ``self.colwidth`` or ``self.measured_widths``). - This take into account cells spanning on multiple columns. + This takes into account cells spanning multiple columns. """ width = 0 for i in range(self[cell.row, cell.col].colspan): @@ -188,7 +187,7 @@ class Table: self.measured_widths[col] = max(self.measured_widths[col], width) def physical_lines_for_line(self, line: List[Cell]) -> int: - """From a given line, compute the number of physical lines it spans + """For a given line, compute the number of physical lines it spans due to text wrapping. """ physical_lines = 1 @@ -323,7 +322,7 @@ class TextWrapper(textwrap.TextWrapper): """_split(text : string) -> [string] Override original method that only split by 'wordsep_re'. - This '_split' split wide-characters into chunk by one character. + This '_split' splits wide-characters into chunks by one character. """ def split(t: str) -> List[str]: return super(TextWrapper, self)._split(t) @@ -851,7 +850,7 @@ class TextTranslator(SphinxTranslator): self.end_state(first='%s. ' % self.list_counter[-1]) def visit_definition_list_item(self, node: Element) -> None: - self._classifier_count_in_li = len(node.traverse(nodes.classifier)) + self._classifier_count_in_li = len(list(node.traverse(nodes.classifier))) def depart_definition_list_item(self, node: Element) -> None: pass diff --git a/sphinx/writers/xml.py b/sphinx/writers/xml.py index 19fa3c1ef..ef261fde2 100644 --- a/sphinx/writers/xml.py +++ b/sphinx/writers/xml.py @@ -19,7 +19,9 @@ class XMLWriter(BaseXMLWriter): def __init__(self, builder: Builder) -> None: super().__init__() self.builder = builder - self.translator_class = self.builder.get_translator_class() + + # A lambda function to generate translator lazily + self.translator_class = lambda document: self.builder.create_translator(document) def translate(self, *args: Any, **kwargs: Any) -> None: self.document.settings.newlines = \ |