mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '2.0'
This commit is contained in:
commit
15c266c445
15
CHANGES
15
CHANGES
@ -50,12 +50,15 @@ Deprecated
|
||||
* ``sphinx.builders.gettext.POHEADER``
|
||||
* ``sphinx.io.SphinxStandaloneReader.app``
|
||||
* ``sphinx.io.SphinxStandaloneReader.env``
|
||||
* ``sphinx.util.texescape.tex_escape_map``
|
||||
* ``sphinx.util.texescape.tex_hl_escape_map_new``
|
||||
|
||||
Features added
|
||||
--------------
|
||||
|
||||
* #6707: C++, support bit-fields.
|
||||
* #267: html: Eliminate prompt characters of doctest block from copyable text
|
||||
* #6548: html: Use favicon for OpenSearch if available
|
||||
* #6729: html theme: agogo theme now supports ``rightsidebar`` option
|
||||
* #6780: Add PEP-561 Support
|
||||
* #6762: latex: Allow to load additonal LaTeX packages via ``extrapackages`` key
|
||||
@ -63,10 +66,14 @@ Features added
|
||||
* #1331: Add new config variable: :confval:`user_agent`
|
||||
* #6000: LaTeX: have backslash also be an inline literal word wrap break
|
||||
character
|
||||
* #4186: LaTeX: Support upLaTeX as a new :confval:`latex_engine` (experimental)
|
||||
* #6812: Improve a warning message when extensions are not parallel safe
|
||||
* #6818: Improve Intersphinx performance for multiple remote inventories.
|
||||
* #2546: apidoc: .so file support
|
||||
* #6798: autosummary: emit ``autodoc-skip-member`` event on generating stub file
|
||||
* #6483: i18n: make explicit titles in toctree translatable
|
||||
* #6816: linkcheck: Add :confval:`linkcheck_auth` option to provide
|
||||
authentication information when doing ``linkcheck`` builds
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
@ -80,6 +87,7 @@ Bugs fixed
|
||||
supported LaTeX engines: ¶, §, €, ∞, ±, →, ‣, –, superscript and subscript
|
||||
digits go through "as is" (as default OpenType font supports them)
|
||||
* #6704: linkcheck: Be defensive and handle newly defined HTTP error code
|
||||
* #6806: linkcheck: Failure on parsing content
|
||||
* #6655: image URLs containing ``data:`` causes gettext builder crashed
|
||||
* #6584: i18n: Error when compiling message catalogs on Hindi
|
||||
* #6718: i18n: KeyError is raised if section title and table title are same
|
||||
@ -95,6 +103,13 @@ Bugs fixed
|
||||
* #6809: LaTeX: code-block in a danger type admonition can easily spill over
|
||||
bottom of page
|
||||
* #6793: texinfo: Code examples broken following "sidebar"
|
||||
* #6813: An orphan warning is emitted for included document on Windows. Thanks
|
||||
to @drillan
|
||||
* #6850: Fix smartypants module calls re.sub() with wrong options
|
||||
* #6824: HTML search: If a search term is partially matched in the title and
|
||||
fully matched in a text paragraph on the same page, the search does not
|
||||
include this match.
|
||||
* #6848: config.py shouldn't pop extensions from overrides
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
@ -41,6 +41,16 @@ The following is a list of deprecated interfaces.
|
||||
- 4.0
|
||||
- ``sphinx.io.SphinxStandaloneReader.setup()``
|
||||
|
||||
* - ``sphinx.util.texescape.tex_escape_map``
|
||||
- 2.3
|
||||
- 4.0
|
||||
- ``sphinx.util.texescape.escape()``
|
||||
|
||||
* - ``sphinx.util.texescape.tex_hl_escape_map_new``
|
||||
- 2.3
|
||||
- 4.0
|
||||
- ``sphinx.util.texescape.hlescape()``
|
||||
|
||||
* - ``sphinx.domains.math.MathDomain.add_equation()``
|
||||
- 2.2
|
||||
- 4.0
|
||||
|
@ -538,7 +538,7 @@ General configuration
|
||||
directory pointed ``REQUESTS_CA_BUNDLE`` environment
|
||||
variable if ``tls_cacerts`` not set.
|
||||
|
||||
.. _requests: http://docs.python-requests.org/en/master/
|
||||
.. _requests: https://requests.readthedocs.io/en/master/
|
||||
|
||||
.. confval:: today
|
||||
today_fmt
|
||||
@ -662,12 +662,17 @@ documentation on :ref:`intl` for details.
|
||||
|
||||
Currently supported languages by Sphinx are:
|
||||
|
||||
* ``ar`` -- Arabic
|
||||
* ``bn`` -- Bengali
|
||||
* ``ca`` -- Catalan
|
||||
* ``cak`` -- Kaqchikel
|
||||
* ``cs`` -- Czech
|
||||
* ``cy`` -- Welsh
|
||||
* ``da`` -- Danish
|
||||
* ``de`` -- German
|
||||
* ``el`` -- Greek
|
||||
* ``en`` -- English
|
||||
* ``eo`` -- Esperanto
|
||||
* ``es`` -- Spanish
|
||||
* ``et`` -- Estonian
|
||||
* ``eu`` -- Basque
|
||||
@ -675,6 +680,7 @@ documentation on :ref:`intl` for details.
|
||||
* ``fi`` -- Finnish
|
||||
* ``fr`` -- French
|
||||
* ``he`` -- Hebrew
|
||||
* ``hi`` -- Hindi
|
||||
* ``hr`` -- Croatian
|
||||
* ``hu`` -- Hungarian
|
||||
* ``id`` -- Indonesian
|
||||
@ -688,15 +694,20 @@ documentation on :ref:`intl` for details.
|
||||
* ``ne`` -- Nepali
|
||||
* ``nl`` -- Dutch
|
||||
* ``pl`` -- Polish
|
||||
* ``pt`` -- Portuguese
|
||||
* ``pt_BR`` -- Brazilian Portuguese
|
||||
* ``pt_PT`` -- European Portuguese
|
||||
* ``ro`` -- Romanian
|
||||
* ``ru`` -- Russian
|
||||
* ``si`` -- Sinhala
|
||||
* ``sk`` -- Slovak
|
||||
* ``sl`` -- Slovenian
|
||||
* ``sr`` -- Serbian
|
||||
* ``sv`` -- Swedish
|
||||
* ``ta`` -- Tamil
|
||||
* ``tr`` -- Turkish
|
||||
* ``uk_UA`` -- Ukrainian
|
||||
* ``ur`` -- Urdu
|
||||
* ``vi`` -- Vietnamese
|
||||
* ``zh_CN`` -- Simplified Chinese
|
||||
* ``zh_TW`` -- Traditional Chinese
|
||||
@ -1836,6 +1847,7 @@ These options influence LaTeX output.
|
||||
* ``'xelatex'`` -- XeLaTeX
|
||||
* ``'lualatex'`` -- LuaLaTeX
|
||||
* ``'platex'`` -- pLaTeX (default if :confval:`language` is ``'ja'``)
|
||||
* ``'uplatex'`` -- upLaTeX (experimental)
|
||||
|
||||
``'pdflatex'``\ 's support for Unicode characters is limited.
|
||||
|
||||
@ -1861,6 +1873,10 @@ These options influence LaTeX output.
|
||||
|
||||
Use ``xelatex`` by default for Greek documents.
|
||||
|
||||
.. versionchanged:: 2.3
|
||||
|
||||
Add ``uplatex`` support.
|
||||
|
||||
Contrarily to :ref:`MathJaX math rendering in HTML output <math-support>`,
|
||||
LaTeX requires some extra configuration to support Unicode literals in
|
||||
:rst:dir:`math`: the only comprehensive solution (as far as we know) is to
|
||||
@ -2364,6 +2380,34 @@ Options for the linkcheck builder
|
||||
|
||||
.. versionadded:: 1.5
|
||||
|
||||
.. confval:: linkcheck_auth
|
||||
|
||||
Pass authentication information when doing a ``linkcheck`` build.
|
||||
|
||||
A list of ``(regex_pattern, auth_info)`` tuples where the items are:
|
||||
|
||||
*regex_pattern*
|
||||
A regular expression that matches a URI.
|
||||
*auth_info*
|
||||
Authentication information to use for that URI. The value can be anything
|
||||
that is understood by the ``requests`` library (see `requests
|
||||
Authentication <requests-auth>`_ for details).
|
||||
|
||||
.. _requests-auth: https://requests.readthedocs.io/en/master/user/authentication/
|
||||
|
||||
The ``linkcheck`` builder will use the first matching ``auth_info`` value
|
||||
it can find in the :confval:`linkcheck_auth` list, so values earlier in the
|
||||
list have higher priority.
|
||||
|
||||
Example::
|
||||
|
||||
linkcheck_auth = [
|
||||
('https://foo\.yourcompany\.com/.+', ('johndoe', 'secret')),
|
||||
('https://.+\.yourcompany\.com/.+', HTTPDigestAuth(...)),
|
||||
]
|
||||
|
||||
.. versionadded:: 2.3
|
||||
|
||||
|
||||
Options for the XML builder
|
||||
---------------------------
|
||||
|
@ -439,7 +439,7 @@ There are also config values that you can set:
|
||||
* ``'signature'`` -- Show typehints as its signature (default)
|
||||
* ``'none'`` -- Do not show typehints
|
||||
|
||||
.. versionadded: 2.1
|
||||
.. versionadded:: 2.1
|
||||
|
||||
.. confval:: autodoc_warningiserror
|
||||
|
||||
|
@ -143,6 +143,11 @@ also use these config values:
|
||||
The new files will be placed in the directories specified in the
|
||||
``:toctree:`` options of the directives.
|
||||
|
||||
.. versionchanged:: 2.3
|
||||
|
||||
Emits :event:`autodoc-skip-member` event as :mod:`~sphinx.ext.autodoc`
|
||||
does.
|
||||
|
||||
.. confval:: autosummary_generate_overwrite
|
||||
|
||||
If true, autosummary already overwrites stub files by generated contents.
|
||||
|
@ -56,7 +56,7 @@ source code files.
|
||||
.. _Google:
|
||||
https://google.github.io/styleguide/pyguide.html#Comments
|
||||
.. _NumPy:
|
||||
https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
|
||||
https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard
|
||||
.. _Khan Academy:
|
||||
https://github.com/Khan/style-guides/blob/master/style/python.md#docstrings
|
||||
|
||||
|
@ -427,8 +427,12 @@ def default_latex_engine(config: Config) -> str:
|
||||
def default_latex_docclass(config: Config) -> Dict[str, str]:
|
||||
""" Better default latex_docclass settings for specific languages. """
|
||||
if config.language == 'ja':
|
||||
return {'manual': 'jsbook',
|
||||
'howto': 'jreport'}
|
||||
if config.latex_engine == 'uplatex':
|
||||
return {'manual': 'ujbook',
|
||||
'howto': 'ujreport'}
|
||||
else:
|
||||
return {'manual': 'jsbook',
|
||||
'howto': 'jreport'}
|
||||
else:
|
||||
return {}
|
||||
|
||||
@ -440,10 +444,12 @@ def default_latex_use_xindy(config: Config) -> bool:
|
||||
|
||||
def default_latex_documents(config: Config) -> List[Tuple[str, str, str, str, str]]:
|
||||
""" Better default latex_documents settings. """
|
||||
project = texescape.escape(config.project, config.latex_engine)
|
||||
author = texescape.escape(config.author, config.latex_engine)
|
||||
return [(config.master_doc,
|
||||
make_filename_from_project(config.project) + '.tex',
|
||||
texescape.escape_abbr(texescape.escape(config.project)),
|
||||
texescape.escape_abbr(texescape.escape(config.author)),
|
||||
texescape.escape_abbr(project),
|
||||
texescape.escape_abbr(author),
|
||||
'manual')]
|
||||
|
||||
|
||||
@ -454,7 +460,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.connect('config-inited', validate_config_values)
|
||||
|
||||
app.add_config_value('latex_engine', default_latex_engine, None,
|
||||
ENUM('pdflatex', 'xelatex', 'lualatex', 'platex'))
|
||||
ENUM('pdflatex', 'xelatex', 'lualatex', 'platex', 'uplatex'))
|
||||
app.add_config_value('latex_documents', default_latex_documents, None)
|
||||
app.add_config_value('latex_logo', None, None, [str])
|
||||
app.add_config_value('latex_appendices', [], None)
|
||||
|
@ -59,6 +59,9 @@ def check_anchor(response: requests.requests.Response, anchor: str) -> bool:
|
||||
# Read file in chunks. If we find a matching anchor, we break
|
||||
# the loop early in hopes not to have to download the whole thing.
|
||||
for chunk in response.iter_content(chunk_size=4096, decode_unicode=True):
|
||||
if isinstance(chunk, bytes): # requests failed to decode
|
||||
chunk = chunk.decode() # manually try to decode it
|
||||
|
||||
parser.feed(chunk)
|
||||
if parser.found:
|
||||
break
|
||||
@ -78,6 +81,8 @@ class CheckExternalLinksBuilder(Builder):
|
||||
self.to_ignore = [re.compile(x) for x in self.app.config.linkcheck_ignore]
|
||||
self.anchors_ignore = [re.compile(x)
|
||||
for x in self.app.config.linkcheck_anchors_ignore]
|
||||
self.auth = [(re.compile(pattern), auth_info) for pattern, auth_info
|
||||
in self.app.config.linkcheck_auth]
|
||||
self.good = set() # type: Set[str]
|
||||
self.broken = {} # type: Dict[str, str]
|
||||
self.redirected = {} # type: Dict[str, Tuple[str, int]]
|
||||
@ -124,11 +129,18 @@ class CheckExternalLinksBuilder(Builder):
|
||||
except UnicodeError:
|
||||
req_url = encode_uri(req_url)
|
||||
|
||||
# Get auth info, if any
|
||||
for pattern, auth_info in self.auth:
|
||||
if pattern.match(uri):
|
||||
break
|
||||
else:
|
||||
auth_info = None
|
||||
|
||||
try:
|
||||
if anchor and self.app.config.linkcheck_anchors:
|
||||
# Read the whole document and see if #anchor exists
|
||||
response = requests.get(req_url, stream=True, config=self.app.config,
|
||||
**kwargs)
|
||||
auth=auth_info, **kwargs)
|
||||
found = check_anchor(response, unquote(anchor))
|
||||
|
||||
if not found:
|
||||
@ -137,13 +149,14 @@ class CheckExternalLinksBuilder(Builder):
|
||||
try:
|
||||
# try a HEAD request first, which should be easier on
|
||||
# the server and the network
|
||||
response = requests.head(req_url, config=self.app.config, **kwargs)
|
||||
response = requests.head(req_url, config=self.app.config,
|
||||
auth=auth_info, **kwargs)
|
||||
response.raise_for_status()
|
||||
except HTTPError:
|
||||
# retry with GET request if that fails, some servers
|
||||
# don't like HEAD requests.
|
||||
response = requests.get(req_url, stream=True, config=self.app.config,
|
||||
**kwargs)
|
||||
auth=auth_info, **kwargs)
|
||||
response.raise_for_status()
|
||||
except HTTPError as err:
|
||||
if err.response.status_code == 401:
|
||||
@ -302,6 +315,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_builder(CheckExternalLinksBuilder)
|
||||
|
||||
app.add_config_value('linkcheck_ignore', [], None)
|
||||
app.add_config_value('linkcheck_auth', [], None)
|
||||
app.add_config_value('linkcheck_retries', 1, None)
|
||||
app.add_config_value('linkcheck_timeout', None, None, [int])
|
||||
app.add_config_value('linkcheck_workers', 5, None)
|
||||
|
@ -158,16 +158,16 @@ class Config:
|
||||
|
||||
def __init__(self, config={}, overrides={}):
|
||||
# type: (Dict[str, Any], Dict[str, Any]) -> None
|
||||
self.overrides = overrides
|
||||
self.overrides = dict(overrides)
|
||||
self.values = Config.config_values.copy()
|
||||
self._raw_config = config
|
||||
self.setup = config.get('setup', None) # type: Callable
|
||||
|
||||
if 'extensions' in overrides:
|
||||
if isinstance(overrides['extensions'], str):
|
||||
config['extensions'] = overrides.pop('extensions').split(',')
|
||||
if 'extensions' in self.overrides:
|
||||
if isinstance(self.overrides['extensions'], str):
|
||||
config['extensions'] = self.overrides.pop('extensions').split(',')
|
||||
else:
|
||||
config['extensions'] = overrides.pop('extensions')
|
||||
config['extensions'] = self.overrides.pop('extensions')
|
||||
self.extensions = config.get('extensions', []) # type: List[str]
|
||||
|
||||
@classmethod
|
||||
|
@ -138,9 +138,20 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
||||
if not template.exists(template_name):
|
||||
template_name = 'autosummary/base.rst'
|
||||
|
||||
def skip_member(obj: Any, name: str, objtype: str) -> bool:
|
||||
try:
|
||||
return app.emit_firstresult('autodoc-skip-member', objtype, name,
|
||||
obj, False, {})
|
||||
except Exception as exc:
|
||||
logger.warning(__('autosummary: failed to determine %r to be documented.'
|
||||
'the following exception was raised:\n%s'),
|
||||
name, exc, type='autosummary')
|
||||
return False
|
||||
|
||||
def get_members(obj: Any, types: Set[str], include_public: List[str] = [],
|
||||
imported: bool = True) -> Tuple[List[str], List[str]]:
|
||||
items = [] # type: List[str]
|
||||
public = [] # type: List[str]
|
||||
for name in dir(obj):
|
||||
try:
|
||||
value = safe_getattr(obj, name)
|
||||
@ -148,11 +159,20 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
||||
continue
|
||||
documenter = get_documenter(app, value, obj)
|
||||
if documenter.objtype in types:
|
||||
# skip imported members if expected
|
||||
if imported or getattr(value, '__module__', None) == obj.__name__:
|
||||
# skip imported members if expected
|
||||
items.append(name)
|
||||
public = [x for x in items
|
||||
if x in include_public or not x.startswith('_')]
|
||||
skipped = skip_member(value, name, documenter.objtype)
|
||||
if skipped is True:
|
||||
pass
|
||||
elif skipped is False:
|
||||
# show the member forcedly
|
||||
items.append(name)
|
||||
public.append(name)
|
||||
else:
|
||||
items.append(name)
|
||||
if name in include_public or not name.startswith('_'):
|
||||
# considers member as public
|
||||
public.append(name)
|
||||
return public, items
|
||||
|
||||
ns = {} # type: Dict[str, Any]
|
||||
|
@ -27,10 +27,9 @@ from sphinx.domains import Domain
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.errors import NoUri
|
||||
from sphinx.locale import _, __
|
||||
from sphinx.util import logging
|
||||
from sphinx.util import logging, texescape
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
from sphinx.util.nodes import make_refnode
|
||||
from sphinx.util.texescape import get_escape_func
|
||||
from sphinx.writers.html import HTMLTranslator
|
||||
from sphinx.writers.latex import LaTeXTranslator
|
||||
|
||||
@ -299,11 +298,12 @@ def depart_todo_node(self: HTMLTranslator, node: todo_node) -> None:
|
||||
|
||||
def latex_visit_todo_node(self: LaTeXTranslator, node: todo_node) -> None:
|
||||
if self.config.todo_include_todos:
|
||||
escape = get_escape_func(self.config.latex_engine)
|
||||
self.body.append('\n\\begin{sphinxadmonition}{note}{')
|
||||
self.body.append(self.hypertarget_to(node))
|
||||
|
||||
title_node = cast(nodes.title, node[0])
|
||||
self.body.append('%s:}' % escape(title_node.astext()))
|
||||
title = texescape.escape(title_node.astext(), self.config.latex_engine)
|
||||
self.body.append('%s:}' % title)
|
||||
node.pop(0)
|
||||
else:
|
||||
raise nodes.SkipNode
|
||||
|
@ -23,8 +23,7 @@ from pygments.util import ClassNotFound
|
||||
|
||||
from sphinx.locale import __
|
||||
from sphinx.pygments_styles import SphinxStyle, NoneStyle
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.texescape import get_hlescape_func
|
||||
from sphinx.util import logging, texescape
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
@ -165,8 +164,7 @@ class PygmentsBridge:
|
||||
if self.dest == 'html':
|
||||
return hlsource
|
||||
else:
|
||||
escape = get_hlescape_func(self.latex_engine)
|
||||
return escape(hlsource)
|
||||
return texescape.hlescape(hlsource, self.latex_engine)
|
||||
|
||||
def get_stylesheet(self):
|
||||
# type: () -> str
|
||||
|
@ -13,6 +13,7 @@ import os
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import get_matching_files
|
||||
from sphinx.util import logging
|
||||
from sphinx.util import path_stabilize
|
||||
from sphinx.util.matching import compile_matchers
|
||||
from sphinx.util.osutil import SEP, relpath
|
||||
|
||||
@ -71,6 +72,7 @@ class Project:
|
||||
filename = relpath(filename, self.srcdir)
|
||||
for suffix in self.source_suffix:
|
||||
if filename.endswith(suffix):
|
||||
filename = path_stabilize(filename)
|
||||
return filename[:-len(suffix)]
|
||||
|
||||
# the file does not have docname
|
||||
|
@ -36,7 +36,7 @@ XINDYOPTS += -M LatinRules.xdy
|
||||
# format: pdf or dvi (used only by archive targets)
|
||||
FMT = pdf
|
||||
|
||||
{% if latex_engine == 'platex' -%}
|
||||
{% if latex_engine in ('platex', 'uplatex') -%}
|
||||
# latexmkrc is read then overridden by latexmkjarc
|
||||
LATEX = latexmk -r latexmkjarc -dvi
|
||||
PDFLATEX = latexmk -r latexmkjarc -pdfdvi -dvi- -ps-
|
||||
|
@ -1,4 +1,4 @@
|
||||
$latex = 'platex ' . $ENV{'LATEXOPTS'} . ' -kanji=utf8 %O %S';
|
||||
$latex = '{{ latex_engine }} ' . $ENV{'LATEXOPTS'} . ' -kanji=utf8 %O %S';
|
||||
$dvipdf = 'dvipdfmx %O -o %D %S';
|
||||
$makeindex = 'internal mendex %S %B %D';
|
||||
sub mendex {
|
@ -6,5 +6,8 @@
|
||||
<Url type="text/html" method="get"
|
||||
template="{{ use_opensearch }}/{{ pathto('search') }}?q={searchTerms}"/>
|
||||
<LongName>{{ docstitle|e }}</LongName>
|
||||
{%- if favicon %}
|
||||
<Image height="16" width="16" type="image/x-icon">{{ use_opensearch }}/{{ pathto('_static/' + favicon, 1) }}</Image>
|
||||
{%- endif %}
|
||||
{% block extra %} {# Put e.g. an <Image> element here. #} {% endblock %}
|
||||
</OpenSearchDescription>
|
||||
|
@ -424,7 +424,7 @@ var Search = {
|
||||
for (j = 0; j < _files.length; j++) {
|
||||
file = _files[j];
|
||||
if (!(file in scoreMap))
|
||||
scoreMap[file] = {}
|
||||
scoreMap[file] = {};
|
||||
scoreMap[file][word] = o.score;
|
||||
}
|
||||
});
|
||||
@ -432,7 +432,7 @@ var Search = {
|
||||
// create the mapping
|
||||
for (j = 0; j < files.length; j++) {
|
||||
file = files[j];
|
||||
if (file in fileMap)
|
||||
if (file in fileMap && fileMap[file].indexOf(word) === -1)
|
||||
fileMap[file].push(word);
|
||||
else
|
||||
fileMap[file] = [word];
|
||||
|
@ -155,7 +155,7 @@ def educateQuotes(text: str, language: str = 'en') -> str:
|
||||
|
||||
# Special case for decade abbreviations (the '80s):
|
||||
if language.startswith('en'): # TODO similar cases in other languages?
|
||||
text = re.sub(r"""'(?=\d{2}s)""", apostrophe, text, re.UNICODE)
|
||||
text = re.sub(r"""'(?=\d{2}s)""", apostrophe, text, flags=re.UNICODE)
|
||||
|
||||
close_class = r"""[^\ \t\r\n\[\{\(\-]"""
|
||||
dec_dashes = r"""–|—"""
|
||||
|
@ -9,6 +9,7 @@
|
||||
"""
|
||||
|
||||
import os
|
||||
from functools import partial
|
||||
from typing import Dict, List, Union
|
||||
|
||||
from jinja2.loaders import BaseLoader
|
||||
@ -69,8 +70,9 @@ class LaTeXRenderer(SphinxRenderer):
|
||||
super().__init__(template_path)
|
||||
|
||||
# use texescape as escape filter
|
||||
self.env.filters['e'] = texescape.get_escape_func(latex_engine)
|
||||
self.env.filters['escape'] = texescape.get_escape_func(latex_engine)
|
||||
escape = partial(texescape.escape, latex_engine=latex_engine)
|
||||
self.env.filters['e'] = escape
|
||||
self.env.filters['escape'] = escape
|
||||
self.env.filters['eabbr'] = texescape.escape_abbr
|
||||
|
||||
# use JSP/eRuby like tagging instead because curly bracket; the default
|
||||
|
@ -9,7 +9,10 @@
|
||||
"""
|
||||
|
||||
import re
|
||||
from typing import Callable, Dict
|
||||
from typing import Dict
|
||||
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
||||
|
||||
|
||||
tex_replacements = [
|
||||
# map TeX special chars
|
||||
@ -32,8 +35,6 @@ tex_replacements = [
|
||||
('`', r'{}`'),
|
||||
('<', r'\textless{}'),
|
||||
('>', r'\textgreater{}'),
|
||||
# map char for some unknown reason. TODO: remove this?
|
||||
('|', r'\textbar{}'),
|
||||
# map special Unicode characters to TeX commands
|
||||
('✓', r'\(\checkmark\)'),
|
||||
('✔', r'\(\pmb{\checkmark}\)'),
|
||||
@ -84,47 +85,38 @@ unicode_tex_replacements = [
|
||||
('₉', r'\(\sb{\text{9}}\)'),
|
||||
]
|
||||
|
||||
tex_escape_map = {} # type: Dict[int, str]
|
||||
tex_escape_map_without_unicode = {} # type: Dict[int, str]
|
||||
tex_replace_map = {}
|
||||
tex_hl_escape_map_new = {} # type: Dict[int, str]
|
||||
tex_hl_escape_map_new_without_unicode = {} # type: Dict[int, str]
|
||||
tex_replace_map = {} # type: Dict[int, str]
|
||||
|
||||
_tex_escape_map = {} # type: Dict[int, str]
|
||||
_tex_escape_map_without_unicode = {} # type: Dict[int, str]
|
||||
_tex_hlescape_map = {} # type: Dict[int, str]
|
||||
_tex_hlescape_map_without_unicode = {} # type: Dict[int, str]
|
||||
|
||||
|
||||
def get_escape_func(latex_engine: str) -> Callable[[str], str]:
|
||||
"""Get escape() function for given latex_engine."""
|
||||
if latex_engine in ('lualatex', 'xelatex'):
|
||||
return escape_for_unicode_latex_engine
|
||||
else:
|
||||
return escape
|
||||
deprecated_alias('sphinx.util.texescape',
|
||||
{
|
||||
'tex_escape_map': _tex_escape_map,
|
||||
'tex_hl_escape_map_new': _tex_hlescape_map,
|
||||
},
|
||||
RemovedInSphinx40Warning)
|
||||
|
||||
|
||||
def escape(s: str) -> str:
|
||||
def escape(s: str, latex_engine: str = None) -> str:
|
||||
"""Escape text for LaTeX output."""
|
||||
return s.translate(tex_escape_map)
|
||||
|
||||
|
||||
def escape_for_unicode_latex_engine(s: str) -> str:
|
||||
"""Escape text for unicode supporting LaTeX engine."""
|
||||
return s.translate(tex_escape_map_without_unicode)
|
||||
|
||||
|
||||
def get_hlescape_func(latex_engine: str) -> Callable[[str], str]:
|
||||
"""Get hlescape() function for given latex_engine."""
|
||||
if latex_engine in ('lualatex', 'xelatex'):
|
||||
return hlescape_for_unicode_latex_engine
|
||||
# unicode based LaTeX engine
|
||||
return s.translate(_tex_escape_map_without_unicode)
|
||||
else:
|
||||
return hlescape
|
||||
return s.translate(_tex_escape_map)
|
||||
|
||||
|
||||
def hlescape(s: str) -> str:
|
||||
def hlescape(s: str, latex_engine: str = None) -> str:
|
||||
"""Escape text for LaTeX highlighter."""
|
||||
return s.translate(tex_hl_escape_map_new)
|
||||
|
||||
|
||||
def hlescape_for_unicode_latex_engine(s: str) -> str:
|
||||
"""Escape text for unicode supporting LaTeX engine."""
|
||||
return s.translate(tex_hl_escape_map_new_without_unicode)
|
||||
if latex_engine in ('lualatex', 'xelatex'):
|
||||
# unicode based LaTeX engine
|
||||
return s.translate(_tex_hlescape_map_without_unicode)
|
||||
else:
|
||||
return s.translate(_tex_hlescape_map)
|
||||
|
||||
|
||||
def escape_abbr(text: str) -> str:
|
||||
@ -134,19 +126,19 @@ def escape_abbr(text: str) -> str:
|
||||
|
||||
def init() -> None:
|
||||
for a, b in tex_replacements:
|
||||
tex_escape_map[ord(a)] = b
|
||||
tex_escape_map_without_unicode[ord(a)] = b
|
||||
_tex_escape_map[ord(a)] = b
|
||||
_tex_escape_map_without_unicode[ord(a)] = b
|
||||
tex_replace_map[ord(a)] = '_'
|
||||
|
||||
for a, b in unicode_tex_replacements:
|
||||
tex_escape_map[ord(a)] = b
|
||||
_tex_escape_map[ord(a)] = b
|
||||
tex_replace_map[ord(a)] = '_'
|
||||
|
||||
for a, b in tex_replacements:
|
||||
if a in '[]{}\\':
|
||||
continue
|
||||
tex_hl_escape_map_new[ord(a)] = b
|
||||
tex_hl_escape_map_new_without_unicode[ord(a)] = b
|
||||
_tex_hlescape_map[ord(a)] = b
|
||||
_tex_hlescape_map_without_unicode[ord(a)] = b
|
||||
|
||||
for a, b in unicode_tex_replacements:
|
||||
tex_hl_escape_map_new[ord(a)] = b
|
||||
_tex_hlescape_map[ord(a)] = b
|
||||
|
@ -12,9 +12,11 @@ import copy
|
||||
import os
|
||||
import posixpath
|
||||
import warnings
|
||||
from typing import Iterable, cast
|
||||
from typing import cast
|
||||
from typing import Iterable
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node, Text
|
||||
from docutils.writers.html4css1 import Writer, HTMLTranslator as BaseTranslator
|
||||
|
||||
from sphinx import addnodes
|
||||
@ -27,8 +29,7 @@ from sphinx.util.images import get_image_size
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any # NOQA
|
||||
from sphinx.builders.html import StandaloneHTMLBuilder # NOQA
|
||||
from sphinx.builders.html import StandaloneHTMLBuilder
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -45,13 +46,11 @@ class HTMLWriter(Writer):
|
||||
if '--embed-stylesheet' in _setting[1]:
|
||||
_setting[2]['default'] = 0
|
||||
|
||||
def __init__(self, builder):
|
||||
# type: (StandaloneHTMLBuilder) -> None
|
||||
def __init__(self, builder: "StandaloneHTMLBuilder") -> None:
|
||||
super().__init__()
|
||||
self.builder = builder
|
||||
|
||||
def translate(self):
|
||||
# type: () -> None
|
||||
def translate(self) -> None:
|
||||
# sadly, this is mostly copied from parent class
|
||||
visitor = self.builder.create_translator(self.document, self.builder)
|
||||
self.visitor = cast(HTMLTranslator, visitor)
|
||||
@ -73,8 +72,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
|
||||
builder = None # type: StandaloneHTMLBuilder
|
||||
|
||||
def __init__(self, *args):
|
||||
# type: (Any) -> None
|
||||
def __init__(self, *args) -> None:
|
||||
if isinstance(args[0], nodes.document) and isinstance(args[1], Builder):
|
||||
document, builder = args
|
||||
else:
|
||||
@ -100,26 +98,21 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
self._fieldlist_row_index = 0
|
||||
self.required_params_left = 0
|
||||
|
||||
def visit_start_of_file(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_start_of_file(self, node: Element) -> None:
|
||||
# only occurs in the single-file builder
|
||||
self.docnames.append(node['docname'])
|
||||
self.body.append('<span id="document-%s"></span>' % node['docname'])
|
||||
|
||||
def depart_start_of_file(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_start_of_file(self, node: Element) -> None:
|
||||
self.docnames.pop()
|
||||
|
||||
def visit_desc(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'dl', CLASS=node['objtype']))
|
||||
|
||||
def depart_desc(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc(self, node: Element) -> None:
|
||||
self.body.append('</dl>\n\n')
|
||||
|
||||
def visit_desc_signature(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_signature(self, node: Element) -> None:
|
||||
# the id is set automatically
|
||||
self.body.append(self.starttag(node, 'dt'))
|
||||
# anchor for per-desc interactive data
|
||||
@ -127,57 +120,45 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
and node['ids'] and node['first']:
|
||||
self.body.append('<!--[%s]-->' % node['ids'][0])
|
||||
|
||||
def depart_desc_signature(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_signature(self, node: Element) -> None:
|
||||
if not node.get('is_multiline'):
|
||||
self.add_permalink_ref(node, _('Permalink to this definition'))
|
||||
self.body.append('</dt>\n')
|
||||
|
||||
def visit_desc_signature_line(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_signature_line(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_desc_signature_line(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_signature_line(self, node: Element) -> None:
|
||||
if node.get('add_permalink'):
|
||||
# the permalink info is on the parent desc_signature node
|
||||
self.add_permalink_ref(node.parent, _('Permalink to this definition'))
|
||||
self.body.append('<br />')
|
||||
|
||||
def visit_desc_addname(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_addname(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'code', '', CLASS='descclassname'))
|
||||
|
||||
def depart_desc_addname(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_addname(self, node: Element) -> None:
|
||||
self.body.append('</code>')
|
||||
|
||||
def visit_desc_type(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_type(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_desc_type(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_type(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_desc_returns(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_returns(self, node: Element) -> None:
|
||||
self.body.append(' → ')
|
||||
|
||||
def depart_desc_returns(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_returns(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_desc_name(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_name(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'code', '', CLASS='descname'))
|
||||
|
||||
def depart_desc_name(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_name(self, node: Element) -> None:
|
||||
self.body.append('</code>')
|
||||
|
||||
def visit_desc_parameterlist(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_parameterlist(self, node: Element) -> None:
|
||||
self.body.append('<span class="sig-paren">(</span>')
|
||||
self.first_param = 1
|
||||
self.optional_param_level = 0
|
||||
@ -186,8 +167,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
for c in node.children])
|
||||
self.param_separator = node.child_text_separator
|
||||
|
||||
def depart_desc_parameterlist(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_parameterlist(self, node: Element) -> None:
|
||||
self.body.append('<span class="sig-paren">)</span>')
|
||||
|
||||
# If required parameters are still to come, then put the comma after
|
||||
@ -196,8 +176,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
#
|
||||
# foo([a, ]b, c[, d])
|
||||
#
|
||||
def visit_desc_parameter(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_parameter(self, node: Element) -> None:
|
||||
if self.first_param:
|
||||
self.first_param = 0
|
||||
elif not self.required_params_left:
|
||||
@ -207,50 +186,40 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
if not node.hasattr('noemph'):
|
||||
self.body.append('<em>')
|
||||
|
||||
def depart_desc_parameter(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_parameter(self, node: Element) -> None:
|
||||
if not node.hasattr('noemph'):
|
||||
self.body.append('</em>')
|
||||
if self.required_params_left:
|
||||
self.body.append(self.param_separator)
|
||||
|
||||
def visit_desc_optional(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_optional(self, node: Element) -> None:
|
||||
self.optional_param_level += 1
|
||||
self.body.append('<span class="optional">[</span>')
|
||||
|
||||
def depart_desc_optional(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_optional(self, node: Element) -> None:
|
||||
self.optional_param_level -= 1
|
||||
self.body.append('<span class="optional">]</span>')
|
||||
|
||||
def visit_desc_annotation(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_annotation(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'em', '', CLASS='property'))
|
||||
|
||||
def depart_desc_annotation(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_annotation(self, node: Element) -> None:
|
||||
self.body.append('</em>')
|
||||
|
||||
def visit_desc_content(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_content(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'dd', ''))
|
||||
|
||||
def depart_desc_content(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_content(self, node: Element) -> None:
|
||||
self.body.append('</dd>')
|
||||
|
||||
def visit_versionmodified(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_versionmodified(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'div', CLASS=node['type']))
|
||||
|
||||
def depart_versionmodified(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_versionmodified(self, node: Element) -> None:
|
||||
self.body.append('</div>\n')
|
||||
|
||||
# overwritten
|
||||
def visit_reference(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_reference(self, node: Element) -> None:
|
||||
atts = {'class': 'reference'}
|
||||
if node.get('internal') or 'refuri' not in node:
|
||||
atts['class'] += ' internal'
|
||||
@ -278,38 +247,31 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
self.body.append(('%s' + self.secnumber_suffix) %
|
||||
'.'.join(map(str, node['secnumber'])))
|
||||
|
||||
def visit_number_reference(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_number_reference(self, node: Element) -> None:
|
||||
self.visit_reference(node)
|
||||
|
||||
def depart_number_reference(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_number_reference(self, node: Element) -> None:
|
||||
self.depart_reference(node)
|
||||
|
||||
# overwritten -- we don't want source comments to show up in the HTML
|
||||
def visit_comment(self, node): # type: ignore
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_comment(self, node: Element) -> None: # type: ignore
|
||||
raise nodes.SkipNode
|
||||
|
||||
# overwritten
|
||||
def visit_admonition(self, node, name=''):
|
||||
# type: (nodes.Element, str) -> None
|
||||
def visit_admonition(self, node: Element, name: str = '') -> None:
|
||||
self.body.append(self.starttag(
|
||||
node, 'div', CLASS=('admonition ' + name)))
|
||||
if name:
|
||||
node.insert(0, nodes.title(name, admonitionlabels[name]))
|
||||
self.set_first_last(node)
|
||||
|
||||
def visit_seealso(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_seealso(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'seealso')
|
||||
|
||||
def depart_seealso(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_seealso(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def add_secnumber(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def add_secnumber(self, node: Element) -> None:
|
||||
if node.get('secnumber'):
|
||||
self.body.append('.'.join(map(str, node['secnumber'])) +
|
||||
self.secnumber_suffix)
|
||||
@ -328,10 +290,8 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
self.body.append('.'.join(map(str, numbers)) +
|
||||
self.secnumber_suffix)
|
||||
|
||||
def add_fignumber(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def append_fignumber(figtype, figure_id):
|
||||
# type: (str, str) -> None
|
||||
def add_fignumber(self, node: Element) -> None:
|
||||
def append_fignumber(figtype: str, figure_id: str) -> None:
|
||||
if self.builder.name == 'singlehtml':
|
||||
key = "%s/%s" % (self.docnames[-1], figtype)
|
||||
else:
|
||||
@ -356,14 +316,12 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
else:
|
||||
append_fignumber(figtype, node['ids'][0])
|
||||
|
||||
def add_permalink_ref(self, node, title):
|
||||
# type: (nodes.Element, str) -> None
|
||||
def add_permalink_ref(self, node: Element, title: str) -> None:
|
||||
if node['ids'] and self.permalink_text and self.builder.add_permalinks:
|
||||
format = '<a class="headerlink" href="#%s" title="%s">%s</a>'
|
||||
self.body.append(format % (node['ids'][0], title, self.permalink_text))
|
||||
|
||||
def generate_targets_for_listing(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def generate_targets_for_listing(self, node: Element) -> None:
|
||||
"""Generate hyperlink targets for listings.
|
||||
|
||||
Original visit_bullet_list(), visit_definition_list() and visit_enumerated_list()
|
||||
@ -378,8 +336,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
node['ids'].remove(id)
|
||||
|
||||
# overwritten
|
||||
def visit_bullet_list(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_bullet_list(self, node: Element) -> None:
|
||||
if len(node) == 1 and isinstance(node[0], addnodes.toctree):
|
||||
# avoid emitting empty <ul></ul>
|
||||
raise nodes.SkipNode
|
||||
@ -387,46 +344,39 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
super().visit_bullet_list(node)
|
||||
|
||||
# overwritten
|
||||
def visit_enumerated_list(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_enumerated_list(self, node: Element) -> None:
|
||||
self.generate_targets_for_listing(node)
|
||||
super().visit_enumerated_list(node)
|
||||
|
||||
# overwritten
|
||||
def visit_definition(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_definition(self, node: Element) -> None:
|
||||
# don't insert </dt> here.
|
||||
self.body.append(self.starttag(node, 'dd', ''))
|
||||
|
||||
# overwritten
|
||||
def depart_definition(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_definition(self, node: Element) -> None:
|
||||
self.body.append('</dd>\n')
|
||||
|
||||
# overwritten
|
||||
def visit_classifier(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_classifier(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'span', '', CLASS='classifier'))
|
||||
|
||||
# overwritten
|
||||
def depart_classifier(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_classifier(self, node: Element) -> None:
|
||||
self.body.append('</span>')
|
||||
|
||||
next_node = node.next_node(descend=False, siblings=True) # type: nodes.Node
|
||||
next_node = node.next_node(descend=False, siblings=True) # type: Node
|
||||
if not isinstance(next_node, nodes.classifier):
|
||||
# close `<dt>` tag at the tail of classifiers
|
||||
self.body.append('</dt>')
|
||||
|
||||
# overwritten
|
||||
def visit_term(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_term(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'dt', ''))
|
||||
|
||||
# overwritten
|
||||
def depart_term(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
next_node = node.next_node(descend=False, siblings=True) # type: nodes.Node
|
||||
def depart_term(self, node: Element) -> None:
|
||||
next_node = node.next_node(descend=False, siblings=True) # type: Node
|
||||
if isinstance(next_node, nodes.classifier):
|
||||
# Leave the end tag to `self.depart_classifier()`, in case
|
||||
# there's a classifier.
|
||||
@ -435,16 +385,14 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
self.body.append('</dt>')
|
||||
|
||||
# overwritten
|
||||
def visit_title(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_title(self, node: Element) -> None:
|
||||
super().visit_title(node)
|
||||
self.add_secnumber(node)
|
||||
self.add_fignumber(node.parent)
|
||||
if isinstance(node.parent, nodes.table):
|
||||
self.body.append('<span class="caption-text">')
|
||||
|
||||
def depart_title(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_title(self, node: Element) -> None:
|
||||
close_tag = self.context[-1]
|
||||
if (self.permalink_text and self.builder.add_permalinks and
|
||||
node.parent.hasattr('ids') and node.parent['ids']):
|
||||
@ -466,8 +414,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
super().depart_title(node)
|
||||
|
||||
# overwritten
|
||||
def visit_literal_block(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_literal_block(self, node: Element) -> None:
|
||||
if node.rawsource != node.astext():
|
||||
# most probably a parsed-literal block -- don't highlight
|
||||
return super().visit_literal_block(node)
|
||||
@ -491,8 +438,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
self.body.append(starttag + highlighted + '</div>\n')
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_caption(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_caption(self, node: Element) -> None:
|
||||
if isinstance(node.parent, nodes.container) and node.parent.get('literal_block'):
|
||||
self.body.append('<div class="code-block-caption">')
|
||||
else:
|
||||
@ -500,8 +446,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
self.add_fignumber(node.parent)
|
||||
self.body.append(self.starttag(node, 'span', '', CLASS='caption-text'))
|
||||
|
||||
def depart_caption(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_caption(self, node: Element) -> None:
|
||||
self.body.append('</span>')
|
||||
|
||||
# append permalink if available
|
||||
@ -517,22 +462,18 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
else:
|
||||
super().depart_caption(node)
|
||||
|
||||
def visit_doctest_block(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_doctest_block(self, node: Element) -> None:
|
||||
self.visit_literal_block(node)
|
||||
|
||||
# overwritten to add the <div> (for XHTML compliance)
|
||||
def visit_block_quote(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_block_quote(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'blockquote') + '<div>')
|
||||
|
||||
def depart_block_quote(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_block_quote(self, node: Element) -> None:
|
||||
self.body.append('</div></blockquote>\n')
|
||||
|
||||
# overwritten
|
||||
def visit_literal(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_literal(self, node: Element) -> None:
|
||||
if 'kbd' in node['classes']:
|
||||
self.body.append(self.starttag(node, 'kbd', '',
|
||||
CLASS='docutils literal notranslate'))
|
||||
@ -541,16 +482,14 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
CLASS='docutils literal notranslate'))
|
||||
self.protect_literal_text += 1
|
||||
|
||||
def depart_literal(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_literal(self, node: Element) -> None:
|
||||
if 'kbd' in node['classes']:
|
||||
self.body.append('</kbd>')
|
||||
else:
|
||||
self.protect_literal_text -= 1
|
||||
self.body.append('</code>')
|
||||
|
||||
def visit_productionlist(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_productionlist(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'pre'))
|
||||
names = []
|
||||
productionlist = cast(Iterable[addnodes.production], node)
|
||||
@ -570,30 +509,24 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
self.body.append('</pre>\n')
|
||||
raise nodes.SkipNode
|
||||
|
||||
def depart_productionlist(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_productionlist(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_production(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_production(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_production(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_production(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_centered(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_centered(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'p', CLASS="centered") +
|
||||
'<strong>')
|
||||
|
||||
def depart_centered(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_centered(self, node: Element) -> None:
|
||||
self.body.append('</strong></p>')
|
||||
|
||||
# overwritten
|
||||
def should_be_compact_paragraph(self, node):
|
||||
# type: (nodes.Node) -> bool
|
||||
def should_be_compact_paragraph(self, node: Node) -> bool:
|
||||
"""Determine if the <p> tags around paragraph can be omitted."""
|
||||
if isinstance(node.parent, addnodes.desc_content):
|
||||
# Never compact desc_content items.
|
||||
@ -603,16 +536,13 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
return False
|
||||
return super().should_be_compact_paragraph(node)
|
||||
|
||||
def visit_compact_paragraph(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_compact_paragraph(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_compact_paragraph(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_compact_paragraph(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_download_reference(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_download_reference(self, node: Element) -> None:
|
||||
atts = {'class': 'reference download',
|
||||
'download': ''}
|
||||
|
||||
@ -631,13 +561,11 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
else:
|
||||
self.context.append('')
|
||||
|
||||
def depart_download_reference(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_download_reference(self, node: Element) -> None:
|
||||
self.body.append(self.context.pop())
|
||||
|
||||
# overwritten
|
||||
def visit_image(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_image(self, node: Element) -> None:
|
||||
olduri = node['uri']
|
||||
# rewrite the URI if the environment knows about it
|
||||
if olduri in self.builder.images:
|
||||
@ -678,67 +606,53 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
super().visit_image(node)
|
||||
|
||||
# overwritten
|
||||
def depart_image(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_image(self, node: Element) -> None:
|
||||
if node['uri'].lower().endswith(('svg', 'svgz')):
|
||||
self.body.append(self.context.pop())
|
||||
else:
|
||||
super().depart_image(node)
|
||||
|
||||
def visit_toctree(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_toctree(self, node: Element) -> None:
|
||||
# this only happens when formatting a toc from env.tocs -- in this
|
||||
# case we don't want to include the subtree
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_index(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_index(self, node: Element) -> None:
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_tabular_col_spec(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_tabular_col_spec(self, node: Element) -> None:
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_glossary(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_glossary(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_glossary(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_glossary(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_acks(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_acks(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_acks(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_acks(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_hlist(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_hlist(self, node: Element) -> None:
|
||||
self.body.append('<table class="hlist"><tr>')
|
||||
|
||||
def depart_hlist(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_hlist(self, node: Element) -> None:
|
||||
self.body.append('</tr></table>\n')
|
||||
|
||||
def visit_hlistcol(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_hlistcol(self, node: Element) -> None:
|
||||
self.body.append('<td>')
|
||||
|
||||
def depart_hlistcol(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_hlistcol(self, node: Element) -> None:
|
||||
self.body.append('</td>')
|
||||
|
||||
def visit_option_group(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_option_group(self, node: Element) -> None:
|
||||
super().visit_option_group(node)
|
||||
self.context[-2] = self.context[-2].replace(' ', ' ')
|
||||
|
||||
# overwritten
|
||||
def visit_Text(self, node):
|
||||
# type: (nodes.Text) -> None
|
||||
def visit_Text(self, node: Text) -> None:
|
||||
text = node.astext()
|
||||
encoded = self.encode(text)
|
||||
if self.protect_literal_text:
|
||||
@ -759,127 +673,99 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
encoded = self.cloak_email(encoded)
|
||||
self.body.append(encoded)
|
||||
|
||||
def visit_note(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_note(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'note')
|
||||
|
||||
def depart_note(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_note(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_warning(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_warning(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'warning')
|
||||
|
||||
def depart_warning(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_warning(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_attention(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_attention(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'attention')
|
||||
|
||||
def depart_attention(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_attention(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_caution(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_caution(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'caution')
|
||||
|
||||
def depart_caution(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_caution(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_danger(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_danger(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'danger')
|
||||
|
||||
def depart_danger(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_danger(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_error(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_error(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'error')
|
||||
|
||||
def depart_error(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_error(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_hint(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_hint(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'hint')
|
||||
|
||||
def depart_hint(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_hint(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_important(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_important(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'important')
|
||||
|
||||
def depart_important(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_important(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_tip(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_tip(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'tip')
|
||||
|
||||
def depart_tip(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_tip(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_literal_emphasis(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_literal_emphasis(self, node: Element) -> None:
|
||||
return self.visit_emphasis(node)
|
||||
|
||||
def depart_literal_emphasis(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_literal_emphasis(self, node: Element) -> None:
|
||||
return self.depart_emphasis(node)
|
||||
|
||||
def visit_literal_strong(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_literal_strong(self, node: Element) -> None:
|
||||
return self.visit_strong(node)
|
||||
|
||||
def depart_literal_strong(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_literal_strong(self, node: Element) -> None:
|
||||
return self.depart_strong(node)
|
||||
|
||||
def visit_abbreviation(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_abbreviation(self, node: Element) -> None:
|
||||
attrs = {}
|
||||
if node.hasattr('explanation'):
|
||||
attrs['title'] = node['explanation']
|
||||
self.body.append(self.starttag(node, 'abbr', '', **attrs))
|
||||
|
||||
def depart_abbreviation(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_abbreviation(self, node: Element) -> None:
|
||||
self.body.append('</abbr>')
|
||||
|
||||
def visit_manpage(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_manpage(self, node: Element) -> None:
|
||||
self.visit_literal_emphasis(node)
|
||||
if self.manpages_url:
|
||||
node['refuri'] = self.manpages_url.format(**node.attributes)
|
||||
self.visit_reference(node)
|
||||
|
||||
def depart_manpage(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_manpage(self, node: Element) -> None:
|
||||
if self.manpages_url:
|
||||
self.depart_reference(node)
|
||||
self.depart_literal_emphasis(node)
|
||||
|
||||
# overwritten to add even/odd classes
|
||||
|
||||
def visit_table(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_table(self, node: Element) -> None:
|
||||
self._table_row_index = 0
|
||||
return super().visit_table(node)
|
||||
|
||||
def visit_row(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_row(self, node: Element) -> None:
|
||||
self._table_row_index += 1
|
||||
if self._table_row_index % 2 == 0:
|
||||
node['classes'].append('row-even')
|
||||
@ -888,19 +774,16 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
self.body.append(self.starttag(node, 'tr', ''))
|
||||
node.column = 0 # type: ignore
|
||||
|
||||
def visit_entry(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_entry(self, node: Element) -> None:
|
||||
super().visit_entry(node)
|
||||
if self.body[-1] == ' ':
|
||||
self.body[-1] = ' '
|
||||
|
||||
def visit_field_list(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_field_list(self, node: Element) -> None:
|
||||
self._fieldlist_row_index = 0
|
||||
return super().visit_field_list(node)
|
||||
|
||||
def visit_field(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_field(self, node: Element) -> None:
|
||||
self._fieldlist_row_index += 1
|
||||
if self._fieldlist_row_index % 2 == 0:
|
||||
node['classes'].append('field-even')
|
||||
@ -908,39 +791,33 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
node['classes'].append('field-odd')
|
||||
self.body.append(self.starttag(node, 'tr', '', CLASS='field'))
|
||||
|
||||
def visit_field_name(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_field_name(self, node: Element) -> None:
|
||||
context_count = len(self.context)
|
||||
super().visit_field_name(node)
|
||||
if context_count != len(self.context):
|
||||
self.context[-1] = self.context[-1].replace(' ', ' ')
|
||||
|
||||
def visit_math(self, node, math_env=''):
|
||||
# type: (nodes.Element, str) -> None
|
||||
def visit_math(self, node: Element, math_env: str = '') -> None:
|
||||
name = self.builder.math_renderer_name
|
||||
visit, _ = self.builder.app.registry.html_inline_math_renderers[name]
|
||||
visit(self, node)
|
||||
|
||||
def depart_math(self, node, math_env=''):
|
||||
# type: (nodes.Element, str) -> None
|
||||
def depart_math(self, node: Element, math_env: str = '') -> None:
|
||||
name = self.builder.math_renderer_name
|
||||
_, depart = self.builder.app.registry.html_inline_math_renderers[name]
|
||||
if depart:
|
||||
depart(self, node)
|
||||
|
||||
def visit_math_block(self, node, math_env=''):
|
||||
# type: (nodes.Element, str) -> None
|
||||
def visit_math_block(self, node: Element, math_env: str = '') -> None:
|
||||
name = self.builder.math_renderer_name
|
||||
visit, _ = self.builder.app.registry.html_block_math_renderers[name]
|
||||
visit(self, node)
|
||||
|
||||
def depart_math_block(self, node, math_env=''):
|
||||
# type: (nodes.Element, str) -> None
|
||||
def depart_math_block(self, node: Element, math_env: str = '') -> None:
|
||||
name = self.builder.math_renderer_name
|
||||
_, depart = self.builder.app.registry.html_block_math_renderers[name]
|
||||
if depart:
|
||||
depart(self, node)
|
||||
|
||||
def unknown_visit(self, node):
|
||||
# type: (nodes.Node) -> None
|
||||
def unknown_visit(self, node: Node) -> None:
|
||||
raise NotImplementedError('Unknown node: ' + node.__class__.__name__)
|
||||
|
@ -11,9 +11,11 @@
|
||||
import os
|
||||
import posixpath
|
||||
import warnings
|
||||
from typing import Iterable, cast
|
||||
from typing import cast
|
||||
from typing import Iterable
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node, Text
|
||||
from docutils.writers.html5_polyglot import HTMLTranslator as BaseTranslator
|
||||
|
||||
from sphinx import addnodes
|
||||
@ -26,8 +28,7 @@ from sphinx.util.images import get_image_size
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any # NOQA
|
||||
from sphinx.builders.html import StandaloneHTMLBuilder # NOQA
|
||||
from sphinx.builders.html import StandaloneHTMLBuilder
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -43,8 +44,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
|
||||
builder = None # type: StandaloneHTMLBuilder
|
||||
|
||||
def __init__(self, *args):
|
||||
# type: (Any) -> None
|
||||
def __init__(self, *args) -> None:
|
||||
if isinstance(args[0], nodes.document) and isinstance(args[1], Builder):
|
||||
document, builder = args
|
||||
else:
|
||||
@ -70,26 +70,21 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
self._fieldlist_row_index = 0
|
||||
self.required_params_left = 0
|
||||
|
||||
def visit_start_of_file(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_start_of_file(self, node: Element) -> None:
|
||||
# only occurs in the single-file builder
|
||||
self.docnames.append(node['docname'])
|
||||
self.body.append('<span id="document-%s"></span>' % node['docname'])
|
||||
|
||||
def depart_start_of_file(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_start_of_file(self, node: Element) -> None:
|
||||
self.docnames.pop()
|
||||
|
||||
def visit_desc(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'dl', CLASS=node['objtype']))
|
||||
|
||||
def depart_desc(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc(self, node: Element) -> None:
|
||||
self.body.append('</dl>\n\n')
|
||||
|
||||
def visit_desc_signature(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_signature(self, node: Element) -> None:
|
||||
# the id is set automatically
|
||||
self.body.append(self.starttag(node, 'dt'))
|
||||
# anchor for per-desc interactive data
|
||||
@ -97,57 +92,45 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
and node['ids'] and node['first']:
|
||||
self.body.append('<!--[%s]-->' % node['ids'][0])
|
||||
|
||||
def depart_desc_signature(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_signature(self, node: Element) -> None:
|
||||
if not node.get('is_multiline'):
|
||||
self.add_permalink_ref(node, _('Permalink to this definition'))
|
||||
self.body.append('</dt>\n')
|
||||
|
||||
def visit_desc_signature_line(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_signature_line(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_desc_signature_line(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_signature_line(self, node: Element) -> None:
|
||||
if node.get('add_permalink'):
|
||||
# the permalink info is on the parent desc_signature node
|
||||
self.add_permalink_ref(node.parent, _('Permalink to this definition'))
|
||||
self.body.append('<br />')
|
||||
|
||||
def visit_desc_addname(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_addname(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'code', '', CLASS='sig-prename descclassname'))
|
||||
|
||||
def depart_desc_addname(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_addname(self, node: Element) -> None:
|
||||
self.body.append('</code>')
|
||||
|
||||
def visit_desc_type(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_type(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_desc_type(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_type(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_desc_returns(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_returns(self, node: Element) -> None:
|
||||
self.body.append(' → ')
|
||||
|
||||
def depart_desc_returns(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_returns(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_desc_name(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_name(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'code', '', CLASS='sig-name descname'))
|
||||
|
||||
def depart_desc_name(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_name(self, node: Element) -> None:
|
||||
self.body.append('</code>')
|
||||
|
||||
def visit_desc_parameterlist(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_parameterlist(self, node: Element) -> None:
|
||||
self.body.append('<span class="sig-paren">(</span>')
|
||||
self.first_param = 1
|
||||
self.optional_param_level = 0
|
||||
@ -156,8 +139,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
for c in node.children])
|
||||
self.param_separator = node.child_text_separator
|
||||
|
||||
def depart_desc_parameterlist(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_parameterlist(self, node: Element) -> None:
|
||||
self.body.append('<span class="sig-paren">)</span>')
|
||||
|
||||
# If required parameters are still to come, then put the comma after
|
||||
@ -166,8 +148,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
#
|
||||
# foo([a, ]b, c[, d])
|
||||
#
|
||||
def visit_desc_parameter(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_parameter(self, node: Element) -> None:
|
||||
if self.first_param:
|
||||
self.first_param = 0
|
||||
elif not self.required_params_left:
|
||||
@ -177,50 +158,40 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
if not node.hasattr('noemph'):
|
||||
self.body.append('<em class="sig-param">')
|
||||
|
||||
def depart_desc_parameter(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_parameter(self, node: Element) -> None:
|
||||
if not node.hasattr('noemph'):
|
||||
self.body.append('</em>')
|
||||
if self.required_params_left:
|
||||
self.body.append(self.param_separator)
|
||||
|
||||
def visit_desc_optional(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_optional(self, node: Element) -> None:
|
||||
self.optional_param_level += 1
|
||||
self.body.append('<span class="optional">[</span>')
|
||||
|
||||
def depart_desc_optional(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_optional(self, node: Element) -> None:
|
||||
self.optional_param_level -= 1
|
||||
self.body.append('<span class="optional">]</span>')
|
||||
|
||||
def visit_desc_annotation(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_annotation(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'em', '', CLASS='property'))
|
||||
|
||||
def depart_desc_annotation(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_annotation(self, node: Element) -> None:
|
||||
self.body.append('</em>')
|
||||
|
||||
def visit_desc_content(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_content(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'dd', ''))
|
||||
|
||||
def depart_desc_content(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_content(self, node: Element) -> None:
|
||||
self.body.append('</dd>')
|
||||
|
||||
def visit_versionmodified(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_versionmodified(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'div', CLASS=node['type']))
|
||||
|
||||
def depart_versionmodified(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_versionmodified(self, node: Element) -> None:
|
||||
self.body.append('</div>\n')
|
||||
|
||||
# overwritten
|
||||
def visit_reference(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_reference(self, node: Element) -> None:
|
||||
atts = {'class': 'reference'}
|
||||
if node.get('internal') or 'refuri' not in node:
|
||||
atts['class'] += ' internal'
|
||||
@ -248,37 +219,30 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
self.body.append(('%s' + self.secnumber_suffix) %
|
||||
'.'.join(map(str, node['secnumber'])))
|
||||
|
||||
def visit_number_reference(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_number_reference(self, node: Element) -> None:
|
||||
self.visit_reference(node)
|
||||
|
||||
def depart_number_reference(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_number_reference(self, node: Element) -> None:
|
||||
self.depart_reference(node)
|
||||
|
||||
# overwritten -- we don't want source comments to show up in the HTML
|
||||
def visit_comment(self, node): # type: ignore
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_comment(self, node: Element) -> None: # type: ignore
|
||||
raise nodes.SkipNode
|
||||
|
||||
# overwritten
|
||||
def visit_admonition(self, node, name=''):
|
||||
# type: (nodes.Element, str) -> None
|
||||
def visit_admonition(self, node: Element, name: str = '') -> None:
|
||||
self.body.append(self.starttag(
|
||||
node, 'div', CLASS=('admonition ' + name)))
|
||||
if name:
|
||||
node.insert(0, nodes.title(name, admonitionlabels[name]))
|
||||
|
||||
def visit_seealso(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_seealso(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'seealso')
|
||||
|
||||
def depart_seealso(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_seealso(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def add_secnumber(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def add_secnumber(self, node: Element) -> None:
|
||||
if node.get('secnumber'):
|
||||
self.body.append('.'.join(map(str, node['secnumber'])) +
|
||||
self.secnumber_suffix)
|
||||
@ -297,10 +261,8 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
self.body.append('.'.join(map(str, numbers)) +
|
||||
self.secnumber_suffix)
|
||||
|
||||
def add_fignumber(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def append_fignumber(figtype, figure_id):
|
||||
# type: (str, str) -> None
|
||||
def add_fignumber(self, node: Element) -> None:
|
||||
def append_fignumber(figtype: str, figure_id: str) -> None:
|
||||
if self.builder.name == 'singlehtml':
|
||||
key = "%s/%s" % (self.docnames[-1], figtype)
|
||||
else:
|
||||
@ -325,55 +287,47 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
else:
|
||||
append_fignumber(figtype, node['ids'][0])
|
||||
|
||||
def add_permalink_ref(self, node, title):
|
||||
# type: (nodes.Element, str) -> None
|
||||
def add_permalink_ref(self, node: Element, title: str) -> None:
|
||||
if node['ids'] and self.permalink_text and self.builder.add_permalinks:
|
||||
format = '<a class="headerlink" href="#%s" title="%s">%s</a>'
|
||||
self.body.append(format % (node['ids'][0], title, self.permalink_text))
|
||||
|
||||
# overwritten
|
||||
def visit_bullet_list(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_bullet_list(self, node: Element) -> None:
|
||||
if len(node) == 1 and isinstance(node[0], addnodes.toctree):
|
||||
# avoid emitting empty <ul></ul>
|
||||
raise nodes.SkipNode
|
||||
super().visit_bullet_list(node)
|
||||
|
||||
# overwritten
|
||||
def visit_definition(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_definition(self, node: Element) -> None:
|
||||
# don't insert </dt> here.
|
||||
self.body.append(self.starttag(node, 'dd', ''))
|
||||
|
||||
# overwritten
|
||||
def depart_definition(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_definition(self, node: Element) -> None:
|
||||
self.body.append('</dd>\n')
|
||||
|
||||
# overwritten
|
||||
def visit_classifier(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_classifier(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'span', '', CLASS='classifier'))
|
||||
|
||||
# overwritten
|
||||
def depart_classifier(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_classifier(self, node: Element) -> None:
|
||||
self.body.append('</span>')
|
||||
|
||||
next_node = node.next_node(descend=False, siblings=True) # type: nodes.Node
|
||||
next_node = node.next_node(descend=False, siblings=True) # type: Node
|
||||
if not isinstance(next_node, nodes.classifier):
|
||||
# close `<dt>` tag at the tail of classifiers
|
||||
self.body.append('</dt>')
|
||||
|
||||
# overwritten
|
||||
def visit_term(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_term(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'dt', ''))
|
||||
|
||||
# overwritten
|
||||
def depart_term(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
next_node = node.next_node(descend=False, siblings=True) # type: nodes.Node
|
||||
def depart_term(self, node: Element) -> None:
|
||||
next_node = node.next_node(descend=False, siblings=True) # type: Node
|
||||
if isinstance(next_node, nodes.classifier):
|
||||
# Leave the end tag to `self.depart_classifier()`, in case
|
||||
# there's a classifier.
|
||||
@ -382,16 +336,14 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
self.body.append('</dt>')
|
||||
|
||||
# overwritten
|
||||
def visit_title(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_title(self, node: Element) -> None:
|
||||
super().visit_title(node)
|
||||
self.add_secnumber(node)
|
||||
self.add_fignumber(node.parent)
|
||||
if isinstance(node.parent, nodes.table):
|
||||
self.body.append('<span class="caption-text">')
|
||||
|
||||
def depart_title(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_title(self, node: Element) -> None:
|
||||
close_tag = self.context[-1]
|
||||
if (self.permalink_text and self.builder.add_permalinks and
|
||||
node.parent.hasattr('ids') and node.parent['ids']):
|
||||
@ -413,8 +365,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
super().depart_title(node)
|
||||
|
||||
# overwritten
|
||||
def visit_literal_block(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_literal_block(self, node: Element) -> None:
|
||||
if node.rawsource != node.astext():
|
||||
# most probably a parsed-literal block -- don't highlight
|
||||
return super().visit_literal_block(node)
|
||||
@ -438,8 +389,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
self.body.append(starttag + highlighted + '</div>\n')
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_caption(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_caption(self, node: Element) -> None:
|
||||
if isinstance(node.parent, nodes.container) and node.parent.get('literal_block'):
|
||||
self.body.append('<div class="code-block-caption">')
|
||||
else:
|
||||
@ -447,8 +397,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
self.add_fignumber(node.parent)
|
||||
self.body.append(self.starttag(node, 'span', '', CLASS='caption-text'))
|
||||
|
||||
def depart_caption(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_caption(self, node: Element) -> None:
|
||||
self.body.append('</span>')
|
||||
|
||||
# append permalink if available
|
||||
@ -464,22 +413,18 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
else:
|
||||
super().depart_caption(node)
|
||||
|
||||
def visit_doctest_block(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_doctest_block(self, node: Element) -> None:
|
||||
self.visit_literal_block(node)
|
||||
|
||||
# overwritten to add the <div> (for XHTML compliance)
|
||||
def visit_block_quote(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_block_quote(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'blockquote') + '<div>')
|
||||
|
||||
def depart_block_quote(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_block_quote(self, node: Element) -> None:
|
||||
self.body.append('</div></blockquote>\n')
|
||||
|
||||
# overwritten
|
||||
def visit_literal(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_literal(self, node: Element) -> None:
|
||||
if 'kbd' in node['classes']:
|
||||
self.body.append(self.starttag(node, 'kbd', '',
|
||||
CLASS='docutils literal notranslate'))
|
||||
@ -488,16 +433,14 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
CLASS='docutils literal notranslate'))
|
||||
self.protect_literal_text += 1
|
||||
|
||||
def depart_literal(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_literal(self, node: Element) -> None:
|
||||
if 'kbd' in node['classes']:
|
||||
self.body.append('</kbd>')
|
||||
else:
|
||||
self.protect_literal_text -= 1
|
||||
self.body.append('</code>')
|
||||
|
||||
def visit_productionlist(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_productionlist(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'pre'))
|
||||
names = []
|
||||
productionlist = cast(Iterable[addnodes.production], node)
|
||||
@ -517,37 +460,29 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
self.body.append('</pre>\n')
|
||||
raise nodes.SkipNode
|
||||
|
||||
def depart_productionlist(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_productionlist(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_production(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_production(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_production(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_production(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_centered(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_centered(self, node: Element) -> None:
|
||||
self.body.append(self.starttag(node, 'p', CLASS="centered") +
|
||||
'<strong>')
|
||||
|
||||
def depart_centered(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_centered(self, node: Element) -> None:
|
||||
self.body.append('</strong></p>')
|
||||
|
||||
def visit_compact_paragraph(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_compact_paragraph(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_compact_paragraph(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_compact_paragraph(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_download_reference(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_download_reference(self, node: Element) -> None:
|
||||
atts = {'class': 'reference download',
|
||||
'download': ''}
|
||||
|
||||
@ -566,13 +501,11 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
else:
|
||||
self.context.append('')
|
||||
|
||||
def depart_download_reference(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_download_reference(self, node: Element) -> None:
|
||||
self.body.append(self.context.pop())
|
||||
|
||||
# overwritten
|
||||
def visit_image(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_image(self, node: Element) -> None:
|
||||
olduri = node['uri']
|
||||
# rewrite the URI if the environment knows about it
|
||||
if olduri in self.builder.images:
|
||||
@ -613,62 +546,49 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
super().visit_image(node)
|
||||
|
||||
# overwritten
|
||||
def depart_image(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_image(self, node: Element) -> None:
|
||||
if node['uri'].lower().endswith(('svg', 'svgz')):
|
||||
self.body.append(self.context.pop())
|
||||
else:
|
||||
super().depart_image(node)
|
||||
|
||||
def visit_toctree(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_toctree(self, node: Element) -> None:
|
||||
# this only happens when formatting a toc from env.tocs -- in this
|
||||
# case we don't want to include the subtree
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_index(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_index(self, node: Element) -> None:
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_tabular_col_spec(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_tabular_col_spec(self, node: Element) -> None:
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_glossary(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_glossary(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_glossary(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_glossary(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_acks(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_acks(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_acks(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_acks(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_hlist(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_hlist(self, node: Element) -> None:
|
||||
self.body.append('<table class="hlist"><tr>')
|
||||
|
||||
def depart_hlist(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_hlist(self, node: Element) -> None:
|
||||
self.body.append('</tr></table>\n')
|
||||
|
||||
def visit_hlistcol(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_hlistcol(self, node: Element) -> None:
|
||||
self.body.append('<td>')
|
||||
|
||||
def depart_hlistcol(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_hlistcol(self, node: Element) -> None:
|
||||
self.body.append('</td>')
|
||||
|
||||
# overwritten
|
||||
def visit_Text(self, node):
|
||||
# type: (nodes.Text) -> None
|
||||
def visit_Text(self, node: Text) -> None:
|
||||
text = node.astext()
|
||||
encoded = self.encode(text)
|
||||
if self.protect_literal_text:
|
||||
@ -689,122 +609,95 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
encoded = self.cloak_email(encoded)
|
||||
self.body.append(encoded)
|
||||
|
||||
def visit_note(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_note(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'note')
|
||||
|
||||
def depart_note(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_note(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_warning(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_warning(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'warning')
|
||||
|
||||
def depart_warning(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_warning(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_attention(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_attention(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'attention')
|
||||
|
||||
def depart_attention(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_attention(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_caution(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_caution(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'caution')
|
||||
|
||||
def depart_caution(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_caution(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_danger(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_danger(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'danger')
|
||||
|
||||
def depart_danger(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_danger(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_error(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_error(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'error')
|
||||
|
||||
def depart_error(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_error(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_hint(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_hint(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'hint')
|
||||
|
||||
def depart_hint(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_hint(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_important(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_important(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'important')
|
||||
|
||||
def depart_important(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_important(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_tip(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_tip(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'tip')
|
||||
|
||||
def depart_tip(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_tip(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_literal_emphasis(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_literal_emphasis(self, node: Element) -> None:
|
||||
return self.visit_emphasis(node)
|
||||
|
||||
def depart_literal_emphasis(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_literal_emphasis(self, node: Element) -> None:
|
||||
return self.depart_emphasis(node)
|
||||
|
||||
def visit_literal_strong(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_literal_strong(self, node: Element) -> None:
|
||||
return self.visit_strong(node)
|
||||
|
||||
def depart_literal_strong(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_literal_strong(self, node: Element) -> None:
|
||||
return self.depart_strong(node)
|
||||
|
||||
def visit_abbreviation(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_abbreviation(self, node: Element) -> None:
|
||||
attrs = {}
|
||||
if node.hasattr('explanation'):
|
||||
attrs['title'] = node['explanation']
|
||||
self.body.append(self.starttag(node, 'abbr', '', **attrs))
|
||||
|
||||
def depart_abbreviation(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_abbreviation(self, node: Element) -> None:
|
||||
self.body.append('</abbr>')
|
||||
|
||||
def visit_manpage(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_manpage(self, node: Element) -> None:
|
||||
self.visit_literal_emphasis(node)
|
||||
if self.manpages_url:
|
||||
node['refuri'] = self.manpages_url.format(**node.attributes)
|
||||
self.visit_reference(node)
|
||||
|
||||
def depart_manpage(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_manpage(self, node: Element) -> None:
|
||||
if self.manpages_url:
|
||||
self.depart_reference(node)
|
||||
self.depart_literal_emphasis(node)
|
||||
|
||||
# overwritten to add even/odd classes
|
||||
|
||||
def generate_targets_for_table(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def generate_targets_for_table(self, node: Element) -> None:
|
||||
"""Generate hyperlink targets for tables.
|
||||
|
||||
Original visit_table() generates hyperlink targets inside table tags
|
||||
@ -817,8 +710,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
self.body.append('<span id="%s"></span>' % id)
|
||||
node['ids'].remove(id)
|
||||
|
||||
def visit_table(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_table(self, node: Element) -> None:
|
||||
self.generate_targets_for_table(node)
|
||||
|
||||
self._table_row_index = 0
|
||||
@ -830,8 +722,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
tag = self.starttag(node, 'table', CLASS=' '.join(classes))
|
||||
self.body.append(tag)
|
||||
|
||||
def visit_row(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_row(self, node: Element) -> None:
|
||||
self._table_row_index += 1
|
||||
if self._table_row_index % 2 == 0:
|
||||
node['classes'].append('row-even')
|
||||
@ -840,45 +731,38 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
self.body.append(self.starttag(node, 'tr', ''))
|
||||
node.column = 0 # type: ignore
|
||||
|
||||
def visit_field_list(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_field_list(self, node: Element) -> None:
|
||||
self._fieldlist_row_index = 0
|
||||
return super().visit_field_list(node)
|
||||
|
||||
def visit_field(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_field(self, node: Element) -> None:
|
||||
self._fieldlist_row_index += 1
|
||||
if self._fieldlist_row_index % 2 == 0:
|
||||
node['classes'].append('field-even')
|
||||
else:
|
||||
node['classes'].append('field-odd')
|
||||
|
||||
def visit_math(self, node, math_env=''):
|
||||
# type: (nodes.Element, str) -> None
|
||||
def visit_math(self, node: Element, math_env: str = '') -> None:
|
||||
name = self.builder.math_renderer_name
|
||||
visit, _ = self.builder.app.registry.html_inline_math_renderers[name]
|
||||
visit(self, node)
|
||||
|
||||
def depart_math(self, node, math_env=''):
|
||||
# type: (nodes.Element, str) -> None
|
||||
def depart_math(self, node: Element, math_env: str = '') -> None:
|
||||
name = self.builder.math_renderer_name
|
||||
_, depart = self.builder.app.registry.html_inline_math_renderers[name]
|
||||
if depart:
|
||||
depart(self, node)
|
||||
|
||||
def visit_math_block(self, node, math_env=''):
|
||||
# type: (nodes.Element, str) -> None
|
||||
def visit_math_block(self, node: Element, math_env: str = '') -> None:
|
||||
name = self.builder.math_renderer_name
|
||||
visit, _ = self.builder.app.registry.html_block_math_renderers[name]
|
||||
visit(self, node)
|
||||
|
||||
def depart_math_block(self, node, math_env=''):
|
||||
# type: (nodes.Element, str) -> None
|
||||
def depart_math_block(self, node: Element, math_env: str = '') -> None:
|
||||
name = self.builder.math_renderer_name
|
||||
_, depart = self.builder.app.registry.html_block_math_renderers[name]
|
||||
if depart:
|
||||
depart(self, node)
|
||||
|
||||
def unknown_visit(self, node):
|
||||
# type: (nodes.Node) -> None
|
||||
def unknown_visit(self, node: Node) -> None:
|
||||
raise NotImplementedError('Unknown node: ' + node.__class__.__name__)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,9 +9,11 @@
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from typing import Iterable, cast
|
||||
from typing import Any, Dict, Iterable
|
||||
from typing import cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node, TextElement
|
||||
from docutils.writers.manpage import (
|
||||
Writer,
|
||||
Translator as BaseTranslator
|
||||
@ -26,21 +28,16 @@ from sphinx.util.docutils import SphinxTranslator
|
||||
from sphinx.util.i18n import format_date
|
||||
from sphinx.util.nodes import NodeMatcher
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Dict # NOQA
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ManualPageWriter(Writer):
|
||||
def __init__(self, builder):
|
||||
# type: (Builder) -> None
|
||||
def __init__(self, builder: Builder) -> None:
|
||||
super().__init__()
|
||||
self.builder = builder
|
||||
|
||||
def translate(self):
|
||||
# type: () -> None
|
||||
def translate(self) -> None:
|
||||
transform = NestedInlineTransform(self.document)
|
||||
transform.apply()
|
||||
visitor = self.builder.create_translator(self.document, self.builder)
|
||||
@ -60,14 +57,12 @@ class NestedInlineTransform:
|
||||
<strong>foo=</strong><emphasis>var</emphasis>
|
||||
<strong>&bar=</strong><emphasis>2</emphasis>
|
||||
"""
|
||||
def __init__(self, document):
|
||||
# type: (nodes.document) -> None
|
||||
def __init__(self, document: nodes.document) -> None:
|
||||
self.document = document
|
||||
|
||||
def apply(self, **kwargs):
|
||||
# type: (Any) -> None
|
||||
def apply(self, **kwargs) -> None:
|
||||
matcher = NodeMatcher(nodes.literal, nodes.emphasis, nodes.strong)
|
||||
for node in self.document.traverse(matcher): # type: nodes.TextElement
|
||||
for node in self.document.traverse(matcher): # type: TextElement
|
||||
if any(matcher(subnode) for subnode in node):
|
||||
pos = node.parent.index(node)
|
||||
for subnode in reversed(node[1:]):
|
||||
@ -86,8 +81,7 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator):
|
||||
|
||||
_docinfo = {} # type: Dict[str, Any]
|
||||
|
||||
def __init__(self, *args):
|
||||
# type: (Any) -> None
|
||||
def __init__(self, *args) -> None:
|
||||
if isinstance(args[0], nodes.document) and isinstance(args[1], Builder):
|
||||
document, builder = args
|
||||
else:
|
||||
@ -126,153 +120,120 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator):
|
||||
self.language.labels[label] = self.deunicode(translation) # type: ignore
|
||||
|
||||
# overwritten -- added quotes around all .TH arguments
|
||||
def header(self):
|
||||
# type: () -> str
|
||||
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")
|
||||
return tmpl % self._docinfo
|
||||
|
||||
def visit_start_of_file(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_start_of_file(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_start_of_file(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_start_of_file(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_desc(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc(self, node: Element) -> None:
|
||||
self.visit_definition_list(node)
|
||||
|
||||
def depart_desc(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc(self, node: Element) -> None:
|
||||
self.depart_definition_list(node)
|
||||
|
||||
def visit_desc_signature(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_signature(self, node: Element) -> None:
|
||||
self.visit_definition_list_item(node)
|
||||
self.visit_term(node)
|
||||
|
||||
def depart_desc_signature(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_signature(self, node: Element) -> None:
|
||||
self.depart_term(node)
|
||||
|
||||
def visit_desc_signature_line(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_signature_line(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_desc_signature_line(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_signature_line(self, node: Element) -> None:
|
||||
self.body.append(' ')
|
||||
|
||||
def visit_desc_addname(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_addname(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_desc_addname(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_addname(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_desc_type(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_type(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_desc_type(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_type(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_desc_returns(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_returns(self, node: Element) -> None:
|
||||
self.body.append(' -> ')
|
||||
|
||||
def depart_desc_returns(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_returns(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_desc_name(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_name(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_desc_name(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_name(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_desc_parameterlist(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_parameterlist(self, node: Element) -> None:
|
||||
self.body.append('(')
|
||||
self.first_param = 1
|
||||
|
||||
def depart_desc_parameterlist(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_parameterlist(self, node: Element) -> None:
|
||||
self.body.append(')')
|
||||
|
||||
def visit_desc_parameter(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_parameter(self, node: Element) -> None:
|
||||
if not self.first_param:
|
||||
self.body.append(', ')
|
||||
else:
|
||||
self.first_param = 0
|
||||
|
||||
def depart_desc_parameter(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_parameter(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_desc_optional(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_optional(self, node: Element) -> None:
|
||||
self.body.append('[')
|
||||
|
||||
def depart_desc_optional(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_optional(self, node: Element) -> None:
|
||||
self.body.append(']')
|
||||
|
||||
def visit_desc_annotation(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_annotation(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_desc_annotation(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_annotation(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_desc_content(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_desc_content(self, node: Element) -> None:
|
||||
self.visit_definition(node)
|
||||
|
||||
def depart_desc_content(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_desc_content(self, node: Element) -> None:
|
||||
self.depart_definition(node)
|
||||
|
||||
def visit_versionmodified(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_versionmodified(self, node: Element) -> None:
|
||||
self.visit_paragraph(node)
|
||||
|
||||
def depart_versionmodified(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_versionmodified(self, node: Element) -> None:
|
||||
self.depart_paragraph(node)
|
||||
|
||||
# overwritten -- don't make whole of term bold if it includes strong node
|
||||
def visit_term(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_term(self, node: Element) -> None:
|
||||
if node.traverse(nodes.strong):
|
||||
self.body.append('\n')
|
||||
else:
|
||||
super().visit_term(node)
|
||||
|
||||
# overwritten -- we don't want source comments to show up
|
||||
def visit_comment(self, node): # type: ignore
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_comment(self, node: Element) -> None: # type: ignore
|
||||
raise nodes.SkipNode
|
||||
|
||||
# overwritten -- added ensure_eol()
|
||||
def visit_footnote(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_footnote(self, node: Element) -> None:
|
||||
self.ensure_eol()
|
||||
super().visit_footnote(node)
|
||||
|
||||
# overwritten -- handle footnotes rubric
|
||||
def visit_rubric(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_rubric(self, node: Element) -> None:
|
||||
self.ensure_eol()
|
||||
if len(node) == 1 and node.astext() in ('Footnotes', _('Footnotes')):
|
||||
self.body.append('.SH ' + self.deunicode(node.astext()).upper() + '\n')
|
||||
@ -280,20 +241,16 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator):
|
||||
else:
|
||||
self.body.append('.sp\n')
|
||||
|
||||
def depart_rubric(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_rubric(self, node: Element) -> None:
|
||||
self.body.append('\n')
|
||||
|
||||
def visit_seealso(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_seealso(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'seealso')
|
||||
|
||||
def depart_seealso(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_seealso(self, node: Element) -> None:
|
||||
self.depart_admonition(node)
|
||||
|
||||
def visit_productionlist(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_productionlist(self, node: Element) -> None:
|
||||
self.ensure_eol()
|
||||
names = []
|
||||
self.in_productionlist += 1
|
||||
@ -318,25 +275,21 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator):
|
||||
self.in_productionlist -= 1
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_production(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_production(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_production(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_production(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
# overwritten -- don't emit a warning for images
|
||||
def visit_image(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_image(self, node: Element) -> None:
|
||||
if 'alt' in node.attributes:
|
||||
self.body.append(_('[image: %s]') % node['alt'] + '\n')
|
||||
self.body.append(_('[image]') + '\n')
|
||||
raise nodes.SkipNode
|
||||
|
||||
# overwritten -- don't visit inner marked up nodes
|
||||
def visit_reference(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_reference(self, node: Element) -> None:
|
||||
self.body.append(self.defs['reference'][0])
|
||||
# avoid repeating escaping code... fine since
|
||||
# visit_Text calls astext() and only works on that afterwards
|
||||
@ -357,59 +310,46 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator):
|
||||
'>'])
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_number_reference(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_number_reference(self, node: Element) -> None:
|
||||
text = nodes.Text(node.get('title', '#'))
|
||||
self.visit_Text(text)
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_centered(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_centered(self, node: Element) -> None:
|
||||
self.ensure_eol()
|
||||
self.body.append('.sp\n.ce\n')
|
||||
|
||||
def depart_centered(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_centered(self, node: Element) -> None:
|
||||
self.body.append('\n.ce 0\n')
|
||||
|
||||
def visit_compact_paragraph(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_compact_paragraph(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_compact_paragraph(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_compact_paragraph(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_download_reference(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_download_reference(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_download_reference(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_download_reference(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_toctree(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_toctree(self, node: Element) -> None:
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_index(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_index(self, node: Element) -> None:
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_tabular_col_spec(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_tabular_col_spec(self, node: Element) -> None:
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_glossary(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_glossary(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_glossary(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_glossary(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_acks(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_acks(self, node: Element) -> None:
|
||||
bullet_list = cast(nodes.bullet_list, node[0])
|
||||
list_items = cast(Iterable[nodes.list_item], bullet_list)
|
||||
self.ensure_eol()
|
||||
@ -419,72 +359,57 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator):
|
||||
self.body.append('\n')
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_hlist(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_hlist(self, node: Element) -> None:
|
||||
self.visit_bullet_list(node)
|
||||
|
||||
def depart_hlist(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_hlist(self, node: Element) -> None:
|
||||
self.depart_bullet_list(node)
|
||||
|
||||
def visit_hlistcol(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_hlistcol(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_hlistcol(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_hlistcol(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_literal_emphasis(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_literal_emphasis(self, node: Element) -> None:
|
||||
return self.visit_emphasis(node)
|
||||
|
||||
def depart_literal_emphasis(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_literal_emphasis(self, node: Element) -> None:
|
||||
return self.depart_emphasis(node)
|
||||
|
||||
def visit_literal_strong(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_literal_strong(self, node: Element) -> None:
|
||||
return self.visit_strong(node)
|
||||
|
||||
def depart_literal_strong(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_literal_strong(self, node: Element) -> None:
|
||||
return self.depart_strong(node)
|
||||
|
||||
def visit_abbreviation(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_abbreviation(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_abbreviation(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_abbreviation(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_manpage(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_manpage(self, node: Element) -> None:
|
||||
return self.visit_strong(node)
|
||||
|
||||
def depart_manpage(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_manpage(self, node: Element) -> None:
|
||||
return self.depart_strong(node)
|
||||
|
||||
# overwritten: handle section titles better than in 0.6 release
|
||||
def visit_caption(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_caption(self, node: Element) -> None:
|
||||
if isinstance(node.parent, nodes.container) and node.parent.get('literal_block'):
|
||||
self.body.append('.sp\n')
|
||||
else:
|
||||
super().visit_caption(node)
|
||||
|
||||
def depart_caption(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_caption(self, node: Element) -> None:
|
||||
if isinstance(node.parent, nodes.container) and node.parent.get('literal_block'):
|
||||
self.body.append('\n')
|
||||
else:
|
||||
super().depart_caption(node)
|
||||
|
||||
# overwritten: handle section titles better than in 0.6 release
|
||||
def visit_title(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_title(self, node: Element) -> None:
|
||||
if isinstance(node.parent, addnodes.seealso):
|
||||
self.body.append('.IP "')
|
||||
return
|
||||
@ -498,47 +423,37 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator):
|
||||
raise nodes.SkipNode
|
||||
return super().visit_title(node)
|
||||
|
||||
def depart_title(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_title(self, node: Element) -> None:
|
||||
if isinstance(node.parent, addnodes.seealso):
|
||||
self.body.append('"\n')
|
||||
return
|
||||
return super().depart_title(node)
|
||||
|
||||
def visit_raw(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_raw(self, node: Element) -> None:
|
||||
if 'manpage' in node.get('format', '').split():
|
||||
self.body.append(node.astext())
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_meta(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_meta(self, node: Element) -> None:
|
||||
raise nodes.SkipNode
|
||||
|
||||
def visit_inline(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_inline(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_inline(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_inline(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_math(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_math(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_math(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_math(self, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def visit_math_block(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def visit_math_block(self, node: Element) -> None:
|
||||
self.visit_centered(node)
|
||||
|
||||
def depart_math_block(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
def depart_math_block(self, node: Element) -> None:
|
||||
self.depart_centered(node)
|
||||
|
||||
def unknown_visit(self, node):
|
||||
# type: (nodes.Node) -> None
|
||||
def unknown_visit(self, node: Node) -> None:
|
||||
raise NotImplementedError('Unknown node: ' + node.__class__.__name__)
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -10,22 +10,16 @@
|
||||
|
||||
from docutils.writers.docutils_xml import Writer as BaseXMLWriter
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any # NOQA
|
||||
from sphinx.builders import Builder # NOQA
|
||||
from sphinx.builders import Builder
|
||||
|
||||
|
||||
class XMLWriter(BaseXMLWriter):
|
||||
|
||||
def __init__(self, builder):
|
||||
# type: (Builder) -> None
|
||||
def __init__(self, builder: Builder) -> None:
|
||||
super().__init__()
|
||||
self.builder = builder
|
||||
self.translator_class = self.builder.get_translator_class()
|
||||
|
||||
def translate(self, *args, **kwargs):
|
||||
# type: (Any, Any) -> None
|
||||
def translate(self, *args, **kwargs) -> None:
|
||||
self.document.settings.newlines = \
|
||||
self.document.settings.indents = \
|
||||
self.builder.env.config.xml_pretty
|
||||
@ -45,16 +39,13 @@ class PseudoXMLWriter(BaseXMLWriter):
|
||||
output = None
|
||||
"""Final translated form of `document`."""
|
||||
|
||||
def __init__(self, builder):
|
||||
# type: (Builder) -> None
|
||||
def __init__(self, builder: Builder) -> None:
|
||||
super().__init__()
|
||||
self.builder = builder
|
||||
|
||||
def translate(self):
|
||||
# type: () -> None
|
||||
def translate(self) -> None:
|
||||
self.output = self.document.pformat()
|
||||
|
||||
def supports(self, format):
|
||||
# type: (str) -> bool
|
||||
def supports(self, format: str) -> bool:
|
||||
"""This writer supports all format-specific elements."""
|
||||
return True
|
||||
|
20
tests/roots/test-ext-autosummary-skip-member/conf.py
Normal file
20
tests/roots/test-ext-autosummary-skip-member/conf.py
Normal file
@ -0,0 +1,20 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
|
||||
extensions = ['sphinx.ext.autosummary']
|
||||
autosummary_generate = True
|
||||
autodoc_default_options = {'members': True}
|
||||
|
||||
|
||||
def skip_member(app, what, name, obj, skip, options):
|
||||
if name == 'skipmeth':
|
||||
return True
|
||||
elif name == '_privatemeth':
|
||||
return False
|
||||
|
||||
|
||||
def setup(app):
|
||||
app.connect('autodoc-skip-member', skip_member)
|
4
tests/roots/test-ext-autosummary-skip-member/index.rst
Normal file
4
tests/roots/test-ext-autosummary-skip-member/index.rst
Normal file
@ -0,0 +1,4 @@
|
||||
.. autosummary::
|
||||
:toctree: generate
|
||||
|
||||
target.Foo
|
14
tests/roots/test-ext-autosummary-skip-member/target.py
Normal file
14
tests/roots/test-ext-autosummary-skip-member/target.py
Normal file
@ -0,0 +1,14 @@
|
||||
class Foo:
|
||||
"""docstring of Foo."""
|
||||
|
||||
def meth(self):
|
||||
"""docstring of meth."""
|
||||
pass
|
||||
|
||||
def skipmeth(self):
|
||||
"""docstring of skipmeth."""
|
||||
pass
|
||||
|
||||
def _privatemeth(self):
|
||||
"""docstring of _privatemeth."""
|
||||
pass
|
@ -315,7 +315,7 @@ def test_numref_with_prefix2(app, status, warning):
|
||||
assert ('\\hyperref[\\detokenize{baz:table22}]'
|
||||
'{Table:\\ref{\\detokenize{baz:table22}}}') in result
|
||||
assert ('\\hyperref[\\detokenize{index:code-1}]{Code-\\ref{\\detokenize{index:code-1}} '
|
||||
'\\textbar{} }') in result
|
||||
'| }') in result
|
||||
assert ('\\hyperref[\\detokenize{baz:code22}]'
|
||||
'{Code-\\ref{\\detokenize{baz:code22}}}') in result
|
||||
assert ('\\hyperref[\\detokenize{foo:foo}]'
|
||||
@ -1414,6 +1414,7 @@ def test_default_latex_documents():
|
||||
'project': 'STASI™ Documentation',
|
||||
'author': "Wolfgang Schäuble & G'Beckstein."})
|
||||
config.init_values()
|
||||
config.add('latex_engine', None, True, None)
|
||||
expected = [('index', 'stasi.tex', 'STASI™ Documentation',
|
||||
r"Wolfgang Schäuble \& G'Beckstein.\@{}", 'manual')]
|
||||
assert default_latex_documents(config) == expected
|
||||
|
@ -8,6 +8,7 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from unittest import mock
|
||||
import pytest
|
||||
|
||||
|
||||
@ -47,3 +48,25 @@ def test_anchors_ignored(app, status, warning):
|
||||
|
||||
# expect all ok when excluding #top
|
||||
assert not content
|
||||
|
||||
|
||||
@pytest.mark.sphinx(
|
||||
'linkcheck', testroot='linkcheck', freshenv=True,
|
||||
confoverrides={'linkcheck_auth': [
|
||||
(r'.+google\.com/image.+', 'authinfo1'),
|
||||
(r'.+google\.com.+', 'authinfo2'),
|
||||
]
|
||||
})
|
||||
def test_auth(app, status, warning):
|
||||
mock_req = mock.MagicMock()
|
||||
mock_req.return_value = 'fake-response'
|
||||
|
||||
with mock.patch.multiple('requests', get=mock_req, head=mock_req):
|
||||
app.builder.build_all()
|
||||
for c_args, c_kwargs in mock_req.call_args_list:
|
||||
if 'google.com/image' in c_args[0]:
|
||||
assert c_kwargs['auth'] == 'authinfo1'
|
||||
elif 'google.com' in c_args[0]:
|
||||
assert c_kwargs['auth'] == 'authinfo2'
|
||||
else:
|
||||
assert not c_kwargs['auth']
|
||||
|
@ -37,6 +37,11 @@ default_kw = {
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(scope='function', autouse=True)
|
||||
def unload_target_module():
|
||||
sys.modules.pop('target', None)
|
||||
|
||||
|
||||
def test_mangle_signature():
|
||||
TEST = """
|
||||
() :: ()
|
||||
@ -335,6 +340,15 @@ def test_generate_autosummary_docs_property(app):
|
||||
".. autoproperty:: Base.prop")
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='ext-autosummary-skip-member')
|
||||
def test_autosummary_skip_member(app):
|
||||
app.build()
|
||||
|
||||
content = (app.srcdir / 'generate' / 'target.Foo.rst').text()
|
||||
assert 'Foo.skipmeth' not in content
|
||||
assert 'Foo._privatemeth' in content
|
||||
|
||||
|
||||
@pytest.mark.sphinx('dummy', testroot='ext-autosummary',
|
||||
confoverrides={'autosummary_generate': []})
|
||||
def test_empty_autosummary_generate(app, status, warning):
|
||||
|
Loading…
Reference in New Issue
Block a user