mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Separate htmlhelp to sphinxcontrib package
This commit is contained in:
parent
cd542fb2af
commit
3b49f9fe3d
1
CHANGES
1
CHANGES
@ -23,6 +23,7 @@ Dependencies
|
|||||||
|
|
||||||
- sphinxcontrib.applehelp
|
- sphinxcontrib.applehelp
|
||||||
- sphinxcontrib.devhelp
|
- sphinxcontrib.devhelp
|
||||||
|
- sphinxcontrib.htmlhelp
|
||||||
- sphinxcontrib.jsmath
|
- sphinxcontrib.jsmath
|
||||||
- sphinxcontrib.qthelp
|
- sphinxcontrib.qthelp
|
||||||
|
|
||||||
|
@ -295,6 +295,11 @@ The following is a list of deprecated interfaces.
|
|||||||
- 4.0
|
- 4.0
|
||||||
- ``sphinx.builders.singlehtml.SingleFileHTMLBuilder``
|
- ``sphinx.builders.singlehtml.SingleFileHTMLBuilder``
|
||||||
|
|
||||||
|
* - ``sphinx.builders.htmlhelp``
|
||||||
|
- 2.0
|
||||||
|
- 4.0
|
||||||
|
- ``sphinxcontrib.htmlhelp``
|
||||||
|
|
||||||
* - ``sphinx.builders.htmlhelp.HTMLHelpBuilder.open_file()``
|
* - ``sphinx.builders.htmlhelp.HTMLHelpBuilder.open_file()``
|
||||||
- 2.0
|
- 2.0
|
||||||
- 4.0
|
- 4.0
|
||||||
|
1
setup.py
1
setup.py
@ -18,6 +18,7 @@ install_requires = [
|
|||||||
'sphinxcontrib-applehelp',
|
'sphinxcontrib-applehelp',
|
||||||
'sphinxcontrib-devhelp',
|
'sphinxcontrib-devhelp',
|
||||||
'sphinxcontrib-jsmath',
|
'sphinxcontrib-jsmath',
|
||||||
|
'sphinxcontrib-htmlhelp',
|
||||||
'sphinxcontrib-qthelp',
|
'sphinxcontrib-qthelp',
|
||||||
'Jinja2>=2.3',
|
'Jinja2>=2.3',
|
||||||
'Pygments>=2.0',
|
'Pygments>=2.0',
|
||||||
|
@ -67,7 +67,6 @@ builtin_extensions = (
|
|||||||
'sphinx.builders.dummy',
|
'sphinx.builders.dummy',
|
||||||
'sphinx.builders.gettext',
|
'sphinx.builders.gettext',
|
||||||
'sphinx.builders.html',
|
'sphinx.builders.html',
|
||||||
'sphinx.builders.htmlhelp',
|
|
||||||
'sphinx.builders.latex',
|
'sphinx.builders.latex',
|
||||||
'sphinx.builders.linkcheck',
|
'sphinx.builders.linkcheck',
|
||||||
'sphinx.builders.manpage',
|
'sphinx.builders.manpage',
|
||||||
@ -107,6 +106,7 @@ builtin_extensions = (
|
|||||||
# 1st party extensions
|
# 1st party extensions
|
||||||
'sphinxcontrib.applehelp',
|
'sphinxcontrib.applehelp',
|
||||||
'sphinxcontrib.devhelp',
|
'sphinxcontrib.devhelp',
|
||||||
|
'sphinxcontrib.htmlhelp',
|
||||||
'sphinxcontrib.qthelp',
|
'sphinxcontrib.qthelp',
|
||||||
# Strictly, alabaster theme is not a builtin extension,
|
# Strictly, alabaster theme is not a builtin extension,
|
||||||
# but it is loaded automatically to use it as default theme.
|
# but it is loaded automatically to use it as default theme.
|
||||||
|
@ -9,374 +9,36 @@
|
|||||||
:license: BSD, see LICENSE for details.
|
:license: BSD, see LICENSE for details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import html
|
|
||||||
import os
|
|
||||||
import warnings
|
import warnings
|
||||||
from os import path
|
|
||||||
|
|
||||||
from docutils import nodes
|
from sphinxcontrib.htmlhelp import (
|
||||||
|
chm_locales, chm_htmlescape, HTMLHelpBuilder, default_htmlhelp_basename
|
||||||
|
)
|
||||||
|
|
||||||
|
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
||||||
|
|
||||||
from sphinx import addnodes
|
|
||||||
from sphinx import package_dir
|
|
||||||
from sphinx.builders.html import StandaloneHTMLBuilder
|
|
||||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
|
||||||
from sphinx.environment.adapters.indexentries import IndexEntries
|
|
||||||
from sphinx.locale import __
|
|
||||||
from sphinx.util import logging
|
|
||||||
from sphinx.util import progress_message
|
|
||||||
from sphinx.util.fileutil import copy_asset_file
|
|
||||||
from sphinx.util.nodes import NodeMatcher
|
|
||||||
from sphinx.util.osutil import make_filename_from_project, relpath
|
|
||||||
from sphinx.util.template import SphinxRenderer
|
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
# For type annotation
|
# For type annotation
|
||||||
from typing import Any, Dict, IO, List, Match, Tuple # NOQA
|
from typing import Any, Dict # NOQA
|
||||||
from sphinx.application import Sphinx # NOQA
|
from sphinx.application import Sphinx # NOQA
|
||||||
from sphinx.config import Config # NOQA
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
deprecated_alias('sphinx.builders.devhelp',
|
||||||
|
{
|
||||||
template_dir = path.join(package_dir, 'templates', 'htmlhelp')
|
'chm_locales': chm_locales,
|
||||||
|
'chm_htmlescape': chm_htmlescape,
|
||||||
|
'HTMLHelpBuilder': HTMLHelpBuilder,
|
||||||
# Project file (*.hhp) template. 'outname' is the file basename (like
|
'default_htmlhelp_basename': default_htmlhelp_basename,
|
||||||
# the pythlp in pythlp.hhp); 'version' is the doc version number (like
|
},
|
||||||
# the 2.2 in Python 2.2).
|
|
||||||
# The magical numbers in the long line under [WINDOWS] set most of the
|
|
||||||
# user-visible features (visible buttons, tabs, etc).
|
|
||||||
# About 0x10384e: This defines the buttons in the help viewer. The
|
|
||||||
# following defns are taken from htmlhelp.h. Not all possibilities
|
|
||||||
# actually work, and not all those that work are available from the Help
|
|
||||||
# Workshop GUI. In particular, the Zoom/Font button works and is not
|
|
||||||
# available from the GUI. The ones we're using are marked with 'x':
|
|
||||||
#
|
|
||||||
# 0x000002 Hide/Show x
|
|
||||||
# 0x000004 Back x
|
|
||||||
# 0x000008 Forward x
|
|
||||||
# 0x000010 Stop
|
|
||||||
# 0x000020 Refresh
|
|
||||||
# 0x000040 Home x
|
|
||||||
# 0x000080 Forward
|
|
||||||
# 0x000100 Back
|
|
||||||
# 0x000200 Notes
|
|
||||||
# 0x000400 Contents
|
|
||||||
# 0x000800 Locate x
|
|
||||||
# 0x001000 Options x
|
|
||||||
# 0x002000 Print x
|
|
||||||
# 0x004000 Index
|
|
||||||
# 0x008000 Search
|
|
||||||
# 0x010000 History
|
|
||||||
# 0x020000 Favorites
|
|
||||||
# 0x040000 Jump 1
|
|
||||||
# 0x080000 Jump 2
|
|
||||||
# 0x100000 Zoom/Font x
|
|
||||||
# 0x200000 TOC Next
|
|
||||||
# 0x400000 TOC Prev
|
|
||||||
|
|
||||||
object_sitemap = '''\
|
|
||||||
<OBJECT type="text/sitemap">
|
|
||||||
<param name="Name" value="%s">
|
|
||||||
<param name="Local" value="%s">
|
|
||||||
</OBJECT>
|
|
||||||
'''
|
|
||||||
|
|
||||||
# The following list includes only languages supported by Sphinx. See
|
|
||||||
# https://docs.microsoft.com/en-us/previous-versions/windows/embedded/ms930130(v=msdn.10)
|
|
||||||
# for more.
|
|
||||||
chm_locales = {
|
|
||||||
# lang: LCID, encoding
|
|
||||||
'ca': (0x403, 'cp1252'),
|
|
||||||
'cs': (0x405, 'cp1250'),
|
|
||||||
'da': (0x406, 'cp1252'),
|
|
||||||
'de': (0x407, 'cp1252'),
|
|
||||||
'en': (0x409, 'cp1252'),
|
|
||||||
'es': (0x40a, 'cp1252'),
|
|
||||||
'et': (0x425, 'cp1257'),
|
|
||||||
'fa': (0x429, 'cp1256'),
|
|
||||||
'fi': (0x40b, 'cp1252'),
|
|
||||||
'fr': (0x40c, 'cp1252'),
|
|
||||||
'hr': (0x41a, 'cp1250'),
|
|
||||||
'hu': (0x40e, 'cp1250'),
|
|
||||||
'it': (0x410, 'cp1252'),
|
|
||||||
'ja': (0x411, 'cp932'),
|
|
||||||
'ko': (0x412, 'cp949'),
|
|
||||||
'lt': (0x427, 'cp1257'),
|
|
||||||
'lv': (0x426, 'cp1257'),
|
|
||||||
'nl': (0x413, 'cp1252'),
|
|
||||||
'no_NB': (0x414, 'cp1252'),
|
|
||||||
'pl': (0x415, 'cp1250'),
|
|
||||||
'pt_BR': (0x416, 'cp1252'),
|
|
||||||
'ru': (0x419, 'cp1251'),
|
|
||||||
'sk': (0x41b, 'cp1250'),
|
|
||||||
'sl': (0x424, 'cp1250'),
|
|
||||||
'sv': (0x41d, 'cp1252'),
|
|
||||||
'tr': (0x41f, 'cp1254'),
|
|
||||||
'uk_UA': (0x422, 'cp1251'),
|
|
||||||
'zh_CN': (0x804, 'cp936'),
|
|
||||||
'zh_TW': (0x404, 'cp950'),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def chm_htmlescape(s, quote=True):
|
|
||||||
# type: (str, bool) -> str
|
|
||||||
"""
|
|
||||||
chm_htmlescape() is a wrapper of html.escape().
|
|
||||||
.hhc/.hhk files don't recognize hex escaping, we need convert
|
|
||||||
hex escaping to decimal escaping. for example: ``'`` -> ``'``
|
|
||||||
html.escape() may generates a hex escaping ``'`` for single
|
|
||||||
quote ``'``, this wrapper fixes this.
|
|
||||||
"""
|
|
||||||
s = html.escape(s, quote)
|
|
||||||
s = s.replace(''', ''') # re-escape as decimal
|
|
||||||
return s
|
|
||||||
|
|
||||||
|
|
||||||
class ToCTreeVisitor(nodes.NodeVisitor):
|
|
||||||
def __init__(self, document):
|
|
||||||
# type: (nodes.document) -> None
|
|
||||||
super().__init__(document)
|
|
||||||
self.body = [] # type: List[str]
|
|
||||||
self.depth = 0
|
|
||||||
|
|
||||||
def append(self, text):
|
|
||||||
# type: (str) -> None
|
|
||||||
indent = ' ' * (self.depth - 1)
|
|
||||||
self.body.append(indent + text)
|
|
||||||
|
|
||||||
def astext(self):
|
|
||||||
# type: () -> str
|
|
||||||
return '\n'.join(self.body)
|
|
||||||
|
|
||||||
def unknown_visit(self, node):
|
|
||||||
# type: (nodes.Node) -> None
|
|
||||||
pass
|
|
||||||
|
|
||||||
def unknown_departure(self, node):
|
|
||||||
# type: (nodes.Node) -> None
|
|
||||||
pass
|
|
||||||
|
|
||||||
def visit_bullet_list(self, node):
|
|
||||||
# type: (nodes.Element) -> None
|
|
||||||
if self.depth > 0:
|
|
||||||
self.append('<UL>')
|
|
||||||
|
|
||||||
self.depth += 1
|
|
||||||
|
|
||||||
def depart_bullet_list(self, node):
|
|
||||||
# type: (nodes.Element) -> None
|
|
||||||
self.depth -= 1
|
|
||||||
if self.depth > 0:
|
|
||||||
self.append('</UL>')
|
|
||||||
|
|
||||||
def visit_list_item(self, node):
|
|
||||||
# type: (nodes.Element) -> None
|
|
||||||
self.append('<LI>')
|
|
||||||
self.depth += 1
|
|
||||||
|
|
||||||
def depart_list_item(self, node):
|
|
||||||
# type: (nodes.Element) -> None
|
|
||||||
self.depth -= 1
|
|
||||||
self.append('</LI>')
|
|
||||||
|
|
||||||
def visit_reference(self, node):
|
|
||||||
# type: (nodes.Element) -> None
|
|
||||||
title = chm_htmlescape(node.astext(), True)
|
|
||||||
self.append('<OBJECT type="text/sitemap">')
|
|
||||||
self.append(' <PARAM name="Name" value="%s" />' % title)
|
|
||||||
self.append(' <PARAM name="Local" value="%s" />' % node['refuri'])
|
|
||||||
self.append('</OBJECT>')
|
|
||||||
raise nodes.SkipNode
|
|
||||||
|
|
||||||
|
|
||||||
class HTMLHelpBuilder(StandaloneHTMLBuilder):
|
|
||||||
"""
|
|
||||||
Builder that also outputs Windows HTML help project, contents and
|
|
||||||
index files. Adapted from the original Doc/tools/prechm.py.
|
|
||||||
"""
|
|
||||||
name = 'htmlhelp'
|
|
||||||
epilog = __('You can now run HTML Help Workshop with the .htp file in '
|
|
||||||
'%(outdir)s.')
|
|
||||||
|
|
||||||
# don't copy the reST source
|
|
||||||
copysource = False
|
|
||||||
supported_image_types = ['image/png', 'image/gif', 'image/jpeg']
|
|
||||||
|
|
||||||
# don't add links
|
|
||||||
add_permalinks = False
|
|
||||||
# don't add sidebar etc.
|
|
||||||
embedded = True
|
|
||||||
|
|
||||||
# don't generate search index or include search page
|
|
||||||
search = False
|
|
||||||
|
|
||||||
lcid = 0x409
|
|
||||||
encoding = 'cp1252'
|
|
||||||
|
|
||||||
def init(self):
|
|
||||||
# type: () -> None
|
|
||||||
# the output files for HTML help is .html by default
|
|
||||||
self.out_suffix = '.html'
|
|
||||||
self.link_suffix = '.html'
|
|
||||||
super().init()
|
|
||||||
# determine the correct locale setting
|
|
||||||
locale = chm_locales.get(self.config.language)
|
|
||||||
if locale is not None:
|
|
||||||
self.lcid, self.encoding = locale
|
|
||||||
|
|
||||||
def open_file(self, outdir, basename, mode='w'):
|
|
||||||
# type: (str, str, str) -> IO
|
|
||||||
# open a file with the correct encoding for the selected language
|
|
||||||
warnings.warn('HTMLHelpBuilder.open_file() is deprecated.',
|
|
||||||
RemovedInSphinx40Warning)
|
RemovedInSphinx40Warning)
|
||||||
return open(path.join(outdir, basename), mode, encoding=self.encoding,
|
|
||||||
errors='xmlcharrefreplace')
|
|
||||||
|
|
||||||
def update_page_context(self, pagename, templatename, ctx, event_arg):
|
|
||||||
# type: (str, str, Dict, str) -> None
|
|
||||||
ctx['encoding'] = self.encoding
|
|
||||||
|
|
||||||
def handle_finish(self):
|
|
||||||
# type: () -> None
|
|
||||||
self.copy_stopword_list()
|
|
||||||
self.build_project_file()
|
|
||||||
self.build_toc_file()
|
|
||||||
self.build_hhx(self.outdir, self.config.htmlhelp_basename)
|
|
||||||
|
|
||||||
def write_doc(self, docname, doctree):
|
|
||||||
# type: (str, nodes.document) -> None
|
|
||||||
for node in doctree.traverse(nodes.reference):
|
|
||||||
# add ``target=_blank`` attributes to external links
|
|
||||||
if node.get('internal') is None and 'refuri' in node:
|
|
||||||
node['target'] = '_blank'
|
|
||||||
|
|
||||||
super().write_doc(docname, doctree)
|
|
||||||
|
|
||||||
def render(self, name, context):
|
|
||||||
# type: (str, Dict) -> str
|
|
||||||
template = SphinxRenderer(template_dir)
|
|
||||||
return template.render(name, context)
|
|
||||||
|
|
||||||
@progress_message(__('copying stopword list'))
|
|
||||||
def copy_stopword_list(self):
|
|
||||||
# type: () -> None
|
|
||||||
"""Copy a stopword list (.stp) to outdir.
|
|
||||||
|
|
||||||
The stopword list contains a list of words the full text search facility
|
|
||||||
shouldn't index. Note that this list must be pretty small. Different
|
|
||||||
versions of the MS docs claim the file has a maximum size of 256 or 512
|
|
||||||
bytes (including \r\n at the end of each line). Note that "and", "or",
|
|
||||||
"not" and "near" are operators in the search language, so no point
|
|
||||||
indexing them even if we wanted to.
|
|
||||||
"""
|
|
||||||
template = path.join(template_dir, 'project.stp')
|
|
||||||
filename = path.join(self.outdir, self.config.htmlhelp_basename + '.stp')
|
|
||||||
copy_asset_file(template, filename)
|
|
||||||
|
|
||||||
@progress_message(__('writing project file'))
|
|
||||||
def build_project_file(self):
|
|
||||||
# type: () -> None
|
|
||||||
"""Create a project file (.hhp) on outdir."""
|
|
||||||
# scan project files
|
|
||||||
project_files = [] # type: List[str]
|
|
||||||
for root, dirs, files in os.walk(self.outdir):
|
|
||||||
dirs.sort()
|
|
||||||
files.sort()
|
|
||||||
in_staticdir = root.startswith(path.join(self.outdir, '_static'))
|
|
||||||
for fn in sorted(files):
|
|
||||||
if (in_staticdir and not fn.endswith('.js')) or fn.endswith('.html'):
|
|
||||||
fn = relpath(path.join(root, fn), self.outdir)
|
|
||||||
project_files.append(fn.replace(os.sep, '\\'))
|
|
||||||
|
|
||||||
filename = path.join(self.outdir, self.config.htmlhelp_basename + '.hhp')
|
|
||||||
with open(filename, 'w', encoding=self.encoding, errors='xmlcharrefreplace') as f:
|
|
||||||
context = {
|
|
||||||
'outname': self.config.htmlhelp_basename,
|
|
||||||
'title': self.config.html_title,
|
|
||||||
'version': self.config.version,
|
|
||||||
'project': self.config.project,
|
|
||||||
'lcid': self.lcid,
|
|
||||||
'master_doc': self.config.master_doc + self.out_suffix,
|
|
||||||
'files': project_files,
|
|
||||||
}
|
|
||||||
body = self.render('project.hhp', context)
|
|
||||||
f.write(body)
|
|
||||||
|
|
||||||
@progress_message(__('writing TOC file'))
|
|
||||||
def build_toc_file(self):
|
|
||||||
# type: () -> None
|
|
||||||
"""Create a ToC file (.hhp) on outdir."""
|
|
||||||
filename = path.join(self.outdir, self.config.htmlhelp_basename + '.hhc')
|
|
||||||
with open(filename, 'w', encoding=self.encoding, errors='xmlcharrefreplace') as f:
|
|
||||||
toctree = self.env.get_and_resolve_doctree(self.config.master_doc, self,
|
|
||||||
prune_toctrees=False)
|
|
||||||
visitor = ToCTreeVisitor(toctree)
|
|
||||||
matcher = NodeMatcher(addnodes.compact_paragraph, toctree=True)
|
|
||||||
for node in toctree.traverse(matcher): # type: addnodes.compact_paragraph
|
|
||||||
node.walkabout(visitor)
|
|
||||||
|
|
||||||
context = {
|
|
||||||
'body': visitor.astext(),
|
|
||||||
'suffix': self.out_suffix,
|
|
||||||
'short_title': self.config.html_short_title,
|
|
||||||
'master_doc': self.config.master_doc,
|
|
||||||
'domain_indices': self.domain_indices,
|
|
||||||
}
|
|
||||||
f.write(self.render('project.hhc', context))
|
|
||||||
|
|
||||||
def build_hhx(self, outdir, outname):
|
|
||||||
# type: (str, str) -> None
|
|
||||||
logger.info(__('writing index file...'))
|
|
||||||
index = IndexEntries(self.env).create_index(self)
|
|
||||||
filename = path.join(outdir, outname + '.hhk')
|
|
||||||
with open(filename, 'w', encoding=self.encoding, errors='xmlcharrefreplace') as f:
|
|
||||||
f.write('<UL>\n')
|
|
||||||
|
|
||||||
def write_index(title, refs, subitems):
|
|
||||||
# type: (str, List[Tuple[str, str]], List[Tuple[str, List[Tuple[str, str]]]]) -> None # NOQA
|
|
||||||
def write_param(name, value):
|
|
||||||
# type: (str, str) -> None
|
|
||||||
item = ' <param name="%s" value="%s">\n' % (name, value)
|
|
||||||
f.write(item)
|
|
||||||
title = chm_htmlescape(title, True)
|
|
||||||
f.write('<LI> <OBJECT type="text/sitemap">\n')
|
|
||||||
write_param('Keyword', title)
|
|
||||||
if len(refs) == 0:
|
|
||||||
write_param('See Also', title)
|
|
||||||
elif len(refs) == 1:
|
|
||||||
write_param('Local', refs[0][1])
|
|
||||||
else:
|
|
||||||
for i, ref in enumerate(refs):
|
|
||||||
# XXX: better title?
|
|
||||||
write_param('Name', '[%d] %s' % (i, ref[1]))
|
|
||||||
write_param('Local', ref[1])
|
|
||||||
f.write('</OBJECT>\n')
|
|
||||||
if subitems:
|
|
||||||
f.write('<UL> ')
|
|
||||||
for subitem in subitems:
|
|
||||||
write_index(subitem[0], subitem[1], [])
|
|
||||||
f.write('</UL>')
|
|
||||||
for (key, group) in index:
|
|
||||||
for title, (refs, subitems, key_) in group:
|
|
||||||
write_index(title, refs, subitems)
|
|
||||||
f.write('</UL>\n')
|
|
||||||
|
|
||||||
|
|
||||||
def default_htmlhelp_basename(config):
|
|
||||||
# type: (Config) -> str
|
|
||||||
"""Better default htmlhelp_basename setting."""
|
|
||||||
return make_filename_from_project(config.project) + 'doc'
|
|
||||||
|
|
||||||
|
|
||||||
def setup(app):
|
def setup(app):
|
||||||
# type: (Sphinx) -> Dict[str, Any]
|
# type: (Sphinx) -> Dict[str, Any]
|
||||||
app.setup_extension('sphinx.builders.html')
|
warnings.warn('sphinx.builders.htmlhelp has been moved to sphinxcontrib-htmlhelp.',
|
||||||
app.add_builder(HTMLHelpBuilder)
|
RemovedInSphinx40Warning)
|
||||||
|
app.setup_extension('sphinxcontrib.htmlhelp')
|
||||||
app.add_config_value('htmlhelp_basename', default_htmlhelp_basename, None)
|
|
||||||
app.add_config_value('htmlhelp_file_suffix', None, 'html', [str])
|
|
||||||
app.add_config_value('htmlhelp_link_suffix', None, 'html', [str])
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'version': 'builtin',
|
'version': 'builtin',
|
||||||
|
@ -1 +0,0 @@
|
|||||||
project = 'test'
|
|
@ -1,19 +0,0 @@
|
|||||||
Index markup
|
|
||||||
------------
|
|
||||||
|
|
||||||
.. index::
|
|
||||||
single: entry
|
|
||||||
pair: entry; pair
|
|
||||||
double: entry; double
|
|
||||||
triple: index; entry; triple
|
|
||||||
keyword: with
|
|
||||||
see: from; to
|
|
||||||
seealso: fromalso; toalso
|
|
||||||
|
|
||||||
.. index::
|
|
||||||
!Main, !Other
|
|
||||||
!single: entry; pair
|
|
||||||
|
|
||||||
.. index:: triple-quoted string, Unicode Consortium, raw string
|
|
||||||
single: """; string literal
|
|
||||||
single: '''; string literal
|
|
@ -1,2 +0,0 @@
|
|||||||
bar
|
|
||||||
---
|
|
@ -1,2 +0,0 @@
|
|||||||
baz
|
|
||||||
---
|
|
@ -1 +0,0 @@
|
|||||||
html_short_title = "Sphinx's documentation"
|
|
@ -1,6 +0,0 @@
|
|||||||
foo
|
|
||||||
---
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
|
|
||||||
bar
|
|
@ -1,15 +0,0 @@
|
|||||||
test-htmlhelp-domain_indices
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
section
|
|
||||||
~~~~~~~
|
|
||||||
|
|
||||||
.. py:module:: sphinx
|
|
||||||
|
|
||||||
subsection
|
|
||||||
^^^^^^^^^^
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
|
|
||||||
foo
|
|
||||||
baz
|
|
@ -60,7 +60,7 @@ def nonascii_srcdir(request, rootdir, sphinx_test_tempdir):
|
|||||||
"buildername",
|
"buildername",
|
||||||
[
|
[
|
||||||
# note: no 'html' - if it's ok with dirhtml it's ok with html
|
# note: no 'html' - if it's ok with dirhtml it's ok with html
|
||||||
'dirhtml', 'singlehtml', 'pickle', 'json', 'text', 'htmlhelp',
|
'dirhtml', 'singlehtml', 'pickle', 'json', 'text',
|
||||||
'changes', 'xml', 'pseudoxml', 'linkcheck',
|
'changes', 'xml', 'pseudoxml', 'linkcheck',
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -1,131 +0,0 @@
|
|||||||
"""
|
|
||||||
test_build_htmlhelp
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Test the HTML Help builder and check output against XPath.
|
|
||||||
|
|
||||||
:copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
|
|
||||||
:license: BSD, see LICENSE for details.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import re
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
from html5lib import HTMLParser
|
|
||||||
|
|
||||||
from sphinx.builders.htmlhelp import chm_htmlescape, default_htmlhelp_basename
|
|
||||||
from sphinx.config import Config
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx('htmlhelp', testroot='basic')
|
|
||||||
def test_build_htmlhelp(app, status, warning):
|
|
||||||
app.build()
|
|
||||||
|
|
||||||
hhp = (app.outdir / 'pythondoc.hhp').text()
|
|
||||||
assert 'Compiled file=pythondoc.chm' in hhp
|
|
||||||
assert 'Contents file=pythondoc.hhc' in hhp
|
|
||||||
assert 'Default Window=pythondoc' in hhp
|
|
||||||
assert 'Default topic=index.html' in hhp
|
|
||||||
assert 'Full text search stop list file=pythondoc.stp' in hhp
|
|
||||||
assert 'Index file=pythondoc.hhk' in hhp
|
|
||||||
assert 'Language=0x409' in hhp
|
|
||||||
assert 'Title=Python documentation' in hhp
|
|
||||||
assert ('pythondoc="Python documentation","pythondoc.hhc",'
|
|
||||||
'"pythondoc.hhk","index.html","index.html",,,,,'
|
|
||||||
'0x63520,220,0x10384e,[0,0,1024,768],,,,,,,0' in hhp)
|
|
||||||
|
|
||||||
files = ['genindex.html', 'index.html', '_static\\alabaster.css', '_static\\basic.css',
|
|
||||||
'_static\\custom.css', '_static\\file.png', '_static\\minus.png',
|
|
||||||
'_static\\plus.png', '_static\\pygments.css']
|
|
||||||
assert '[FILES]\n%s' % '\n'.join(files) in hhp
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx('htmlhelp', testroot='basic')
|
|
||||||
def test_default_htmlhelp_file_suffix(app, warning):
|
|
||||||
assert app.builder.out_suffix == '.html'
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx('htmlhelp', testroot='basic',
|
|
||||||
confoverrides={'htmlhelp_file_suffix': '.htm'})
|
|
||||||
def test_htmlhelp_file_suffix(app, warning):
|
|
||||||
assert app.builder.out_suffix == '.htm'
|
|
||||||
|
|
||||||
|
|
||||||
def test_default_htmlhelp_basename():
|
|
||||||
config = Config({'project': 'Sphinx Documentation'})
|
|
||||||
config.init_values()
|
|
||||||
assert default_htmlhelp_basename(config) == 'sphinxdoc'
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx('htmlhelp', testroot='build-htmlhelp')
|
|
||||||
def test_chm(app):
|
|
||||||
app.build()
|
|
||||||
|
|
||||||
# check .hhk file
|
|
||||||
outname = app.builder.config.htmlhelp_basename
|
|
||||||
hhk_path = str(app.outdir / outname + '.hhk')
|
|
||||||
|
|
||||||
with open(hhk_path, 'rb') as f:
|
|
||||||
data = f.read()
|
|
||||||
m = re.search(br'&#[xX][0-9a-fA-F]+;', data)
|
|
||||||
assert m is None, 'Hex escaping exists in .hhk file: ' + str(m.group(0))
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx('htmlhelp', testroot='htmlhelp-hhc')
|
|
||||||
def test_htmlhelp_hhc(app):
|
|
||||||
app.build()
|
|
||||||
|
|
||||||
def assert_sitemap(node, name, filename):
|
|
||||||
assert node.tag == 'object'
|
|
||||||
assert len(node) == 2
|
|
||||||
assert node[0].tag == 'param'
|
|
||||||
assert node[0].attrib == {'name': 'Name', 'value': name}
|
|
||||||
assert node[1].tag == 'param'
|
|
||||||
assert node[1].attrib == {'name': 'Local', 'value': filename}
|
|
||||||
|
|
||||||
# .hhc file
|
|
||||||
hhc = (app.outdir / 'pythondoc.hhc').text()
|
|
||||||
tree = HTMLParser(namespaceHTMLElements=False).parse(hhc)
|
|
||||||
items = tree.find('.//body/ul')
|
|
||||||
assert len(items) == 4
|
|
||||||
|
|
||||||
# index
|
|
||||||
assert items[0].tag == 'li'
|
|
||||||
assert len(items[0]) == 1
|
|
||||||
assert_sitemap(items[0][0], "Sphinx's documentation", 'index.html')
|
|
||||||
|
|
||||||
# py-modindex
|
|
||||||
assert items[1].tag == 'li'
|
|
||||||
assert len(items[1]) == 1
|
|
||||||
assert_sitemap(items[1][0], 'Python Module Index', 'py-modindex.html')
|
|
||||||
|
|
||||||
# toctree
|
|
||||||
assert items[2].tag == 'li'
|
|
||||||
assert len(items[2]) == 2
|
|
||||||
assert_sitemap(items[2][0], 'foo', 'foo.html')
|
|
||||||
|
|
||||||
assert items[2][1].tag == 'ul'
|
|
||||||
assert len(items[2][1]) == 1
|
|
||||||
assert items[2][1][0].tag == 'li'
|
|
||||||
assert_sitemap(items[2][1][0][0], 'bar', 'bar.html')
|
|
||||||
|
|
||||||
assert items[3].tag == 'li'
|
|
||||||
assert len(items[3]) == 1
|
|
||||||
assert_sitemap(items[3][0], 'baz', 'baz.html')
|
|
||||||
|
|
||||||
# single quotes should be escaped as decimal (')
|
|
||||||
assert "Sphinx's documentation" in hhc
|
|
||||||
|
|
||||||
|
|
||||||
def test_chm_htmlescape():
|
|
||||||
assert chm_htmlescape('Hello world') == 'Hello world'
|
|
||||||
assert chm_htmlescape(u'Unicode 文字') == u'Unicode 文字'
|
|
||||||
assert chm_htmlescape('E') == '&#x45'
|
|
||||||
|
|
||||||
assert chm_htmlescape('<Hello> "world"') == '<Hello> "world"'
|
|
||||||
assert chm_htmlescape('<Hello> "world"', True) == '<Hello> "world"'
|
|
||||||
assert chm_htmlescape('<Hello> "world"', False) == '<Hello> "world"'
|
|
||||||
|
|
||||||
assert chm_htmlescape("Hello 'world'") == "Hello 'world'"
|
|
||||||
assert chm_htmlescape("Hello 'world'", True) == "Hello 'world'"
|
|
||||||
assert chm_htmlescape("Hello 'world'", False) == "Hello 'world'"
|
|
Loading…
Reference in New Issue
Block a user