diff --git a/CHANGES b/CHANGES index f4434cbd5..636f7db84 100644 --- a/CHANGES +++ b/CHANGES @@ -38,6 +38,7 @@ Bugs fixed * #5834: apidoc: wrong help for ``--tocfile`` * #5800: todo: crashed if todo is defined in TextElement * #5846: htmlhelp: convert hex escaping to decimal escaping in .hhc/.hhk files +* htmlhelp: broken .hhk file generated when title contains a double quote Testing -------- diff --git a/sphinx/builders/htmlhelp.py b/sphinx/builders/htmlhelp.py index 42ee05c4a..dfb58ede6 100644 --- a/sphinx/builders/htmlhelp.py +++ b/sphinx/builders/htmlhelp.py @@ -13,10 +13,10 @@ from __future__ import print_function import codecs import os -import re from os import path from docutils import nodes +from six import PY3 from sphinx import addnodes from sphinx.builders.html import StandaloneHTMLBuilder @@ -170,22 +170,21 @@ chm_locales = { } -def chm_htmlescape(*args, **kwargs): - # type: (*Any, **Any) -> unicode +def chm_htmlescape(s, quote=None): + # type: (unicode, bool) -> unicode """ - chm_htmlescape() is a wrapper of htmlescape(). + 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: `'` -> `'` - htmlescape() may generates a hex escaping `'` for single - quote `'`, this wrapper fixes this. + hex escaping to decimal escaping. for example: ``'`` -> ``'`` + html.escape() may generates a hex escaping ``'`` for single + quote ``'``, this wrapper fixes this. """ - def convert(matchobj): - # type: (Match[unicode]) -> unicode - codepoint = int(matchobj.group(1), 16) - return '%d;' % codepoint - return re.sub(r'[xX]([0-9a-fA-F]+);', - convert, - htmlescape(*args, **kwargs)) + if quote is None: + quote = PY3 # True for py3, False for py2 (for compatibility) + + s = htmlescape(s, quote) + s = s.replace(''', ''') # re-escape as decimal + return s class HTMLHelpBuilder(StandaloneHTMLBuilder): @@ -297,7 +296,7 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder): write_toc(subnode, ullevel) elif isinstance(node, nodes.reference): link = node['refuri'] - title = chm_htmlescape(node.astext()).replace('"', '"') + title = chm_htmlescape(node.astext(), True) f.write(object_sitemap % (title, link)) elif isinstance(node, nodes.bullet_list): if ullevel != 0: @@ -327,10 +326,9 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder): # type: (unicode, List[Tuple[unicode, unicode]], List[Tuple[unicode, List[Tuple[unicode, unicode]]]]) -> None # NOQA def write_param(name, value): # type: (unicode, unicode) -> None - item = ' \n' % \ - (name, value) + item = ' \n' % (name, value) f.write(item) - title = chm_htmlescape(title) + title = chm_htmlescape(title, True) f.write('