summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES4
-rw-r--r--sphinx/builders/htmlhelp.py2
-rw-r--r--sphinx/builders/latex/__init__.py (renamed from sphinx/builders/latex.py)0
-rw-r--r--sphinx/builders/latex/transforms.py161
-rw-r--r--sphinx/ext/jsmath.py6
-rw-r--r--sphinx/ext/mathjax.py4
-rw-r--r--sphinx/themes/basic/static/doctools.js_t4
-rw-r--r--sphinx/writers/latex.py116
-rw-r--r--tests/test_ext_math.py22
9 files changed, 192 insertions, 127 deletions
diff --git a/CHANGES b/CHANGES
index d07d4f132..de26728a6 100644
--- a/CHANGES
+++ b/CHANGES
@@ -104,6 +104,9 @@ Bugs fixed
* #4817: wrong URLs on warning messages
* #4784: latex: :confval:`latex_show_urls` assigns incorrect footnote numbers if
hyperlinks exists inside substitutions
+* #4837: latex with class memoir Error: Font command ``\sf`` is not supported
+* #4803: latex: too slow in proportion to number of auto numbered footnotes
+* #4838: htmlhelp: The entries in .hhp file is not ordered
Testing
--------
@@ -138,6 +141,7 @@ Bugs fixed
* #1435: qthelp builder should htmlescape keywords
* epub: Fix docTitle elements of toc.ncx is not escaped
* #4520: apidoc: Subpackage not in toc (introduced in 1.6.6) now fixed
+* #4767: html: search highlighting breaks mathjax equations
Release 1.7.1 (released Feb 23, 2018)
=====================================
diff --git a/sphinx/builders/htmlhelp.py b/sphinx/builders/htmlhelp.py
index 8d4ded246..49d48361e 100644
--- a/sphinx/builders/htmlhelp.py
+++ b/sphinx/builders/htmlhelp.py
@@ -248,6 +248,8 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
outdir += os.sep
olen = len(outdir)
for root, dirs, files in os.walk(outdir):
+ dirs.sort()
+ files.sort()
staticdir = root.startswith(path.join(outdir, '_static'))
for fn in sorted(files):
if (staticdir and not fn.endswith('.js')) or \
diff --git a/sphinx/builders/latex.py b/sphinx/builders/latex/__init__.py
index d0357c6a0..d0357c6a0 100644
--- a/sphinx/builders/latex.py
+++ b/sphinx/builders/latex/__init__.py
diff --git a/sphinx/builders/latex/transforms.py b/sphinx/builders/latex/transforms.py
new file mode 100644
index 000000000..201129989
--- /dev/null
+++ b/sphinx/builders/latex/transforms.py
@@ -0,0 +1,161 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.builders.latex.transforms
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Transforms for LaTeX builder.
+
+ :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from docutils import nodes
+
+from sphinx.transforms import SphinxTransform
+
+if False:
+ # For type annotation
+ from typing import Dict, List, Set, Union # NOQA
+
+URI_SCHEMES = ('mailto:', 'http:', 'https:', 'ftp:')
+
+
+class ShowUrlsTransform(SphinxTransform):
+ """Expand references to inline text or footnotes.
+
+ For more information, see :confval:`latex_show_urls`.
+ """
+ default_priority = 400
+
+ # references are expanded to footnotes (or not)
+ expanded = False
+
+ def apply(self):
+ # type: () -> None
+ # replace id_prefix temporarily
+ id_prefix = self.document.settings.id_prefix
+ self.document.settings.id_prefix = 'show_urls'
+
+ self.expand_show_urls()
+ if self.expanded:
+ self.renumber_footnotes()
+
+ # restore id_prefix
+ self.document.settings.id_prefix = id_prefix
+
+ def expand_show_urls(self):
+ # type: () -> None
+ show_urls = self.document.settings.env.config.latex_show_urls
+ if show_urls is False or show_urls == 'no':
+ return
+
+ for node in self.document.traverse(nodes.reference):
+ uri = node.get('refuri', '')
+ if uri.startswith(URI_SCHEMES):
+ if uri.startswith('mailto:'):
+ uri = uri[7:]
+ if node.astext() != uri:
+ index = node.parent.index(node)
+ if show_urls == 'footnote':
+ footnote_nodes = self.create_footnote(uri)
+ for i, fn in enumerate(footnote_nodes):
+ node.parent.insert(index + i + 1, fn)
+
+ self.expanded = True
+ else: # all other true values (b/w compat)
+ textnode = nodes.Text(" (%s)" % uri)
+ node.parent.insert(index + 1, textnode)
+
+ def create_footnote(self, uri):
+ # type: (unicode) -> List[Union[nodes.footnote, nodes.footnote_ref]]
+ label = nodes.label('', '#')
+ para = nodes.paragraph()
+ para.append(nodes.reference('', nodes.Text(uri), refuri=uri, nolinkurl=True))
+ footnote = nodes.footnote(uri, label, para, auto=1)
+ footnote['names'].append('#')
+ self.document.note_autofootnote(footnote)
+
+ label = nodes.Text('#')
+ footnote_ref = nodes.footnote_reference('[#]_', label, auto=1,
+ refid=footnote['ids'][0])
+ self.document.note_autofootnote_ref(footnote_ref)
+ footnote.add_backref(footnote_ref['ids'][0])
+
+ return [footnote, footnote_ref]
+
+ def renumber_footnotes(self):
+ # type: () -> None
+ collector = FootnoteCollector(self.document)
+ self.document.walkabout(collector)
+
+ num = 0
+ for document, footnote in collector.auto_footnotes:
+ # search unused footnote number
+ while True:
+ num += 1
+ if str(num) not in collector.used_footnote_numbers:
+ break
+
+ # assign new footnote number
+ old_label = footnote[0].astext()
+ footnote[0].replace_self(nodes.label('', str(num)))
+ if old_label in footnote['names']:
+ footnote['names'].remove(old_label)
+ footnote['names'].append(str(num))
+
+ # update footnote_references by new footnote number
+ for ref in collector.footnote_refs.get(document, []):
+ if footnote['ids'][0] == ref['refid']:
+ ref.remove(ref[0])
+ ref += nodes.Text(str(num))
+
+
+class FootnoteCollector(nodes.NodeVisitor):
+ """Collect footnotes and footnote references on the document"""
+
+ def __init__(self, document):
+ # type: (nodes.document) -> None
+ self.auto_footnotes = [] # type: List[nodes.footnote]
+ self.used_footnote_numbers = set() # type: Set[unicode]
+ self.footnote_refs = {} # type: Dict[nodes.Node, List[nodes.footnote_reference]] # NOQA
+ self.current_document = [] # type: List[nodes.Node]
+ nodes.NodeVisitor.__init__(self, document)
+
+ def visit_document(self, node):
+ # type: (nodes.Node) -> None
+ self.current_document.append(node)
+
+ def depart_document(self, node):
+ # type: (nodes.Node) -> None
+ self.current_document.pop()
+
+ def visit_start_of_file(self, node):
+ # type: (nodes.Node) -> None
+ self.current_document.append(node)
+
+ def depart_start_of_file(self, node):
+ # type: (nodes.Node) -> None
+ self.current_document.pop()
+
+ def unknown_visit(self, node):
+ # type: (nodes.Node) -> None
+ pass
+
+ def visit_footnote(self, node):
+ # type: (nodes.footnote) -> None
+ document = self.current_document[-1]
+ if node.get('auto'):
+ self.auto_footnotes.append((document, node))
+ else:
+ for name in node['names']:
+ self.used_footnote_numbers.add(name)
+
+ def visit_footnote_reference(self, node):
+ # type: (nodes.footnote_reference) -> None
+ document = self.current_document[-1]
+ footnote_refs = self.footnote_refs.setdefault(document, [])
+ footnote_refs.append(node)
+
+ def unknown_departure(self, node):
+ # type: (nodes.Node) -> None
+ pass
diff --git a/sphinx/ext/jsmath.py b/sphinx/ext/jsmath.py
index b377a6479..9e8662b03 100644
--- a/sphinx/ext/jsmath.py
+++ b/sphinx/ext/jsmath.py
@@ -26,7 +26,7 @@ if False:
def html_visit_math(self, node):
# type: (nodes.NodeVisitor, nodes.Node) -> None
- self.body.append(self.starttag(node, 'span', '', CLASS='math notranslate'))
+ self.body.append(self.starttag(node, 'span', '', CLASS='math notranslate nohighlight'))
self.body.append(self.encode(node['latex']) + '</span>')
raise nodes.SkipNode
@@ -34,7 +34,7 @@ def html_visit_math(self, node):
def html_visit_displaymath(self, node):
# type: (nodes.NodeVisitor, nodes.Node) -> None
if node['nowrap']:
- self.body.append(self.starttag(node, 'div', CLASS='math notranslate'))
+ self.body.append(self.starttag(node, 'div', CLASS='math notranslate nohighlight'))
self.body.append(self.encode(node['latex']))
self.body.append('</div>')
raise nodes.SkipNode
@@ -47,7 +47,7 @@ def html_visit_displaymath(self, node):
self.body.append('<span class="eqno">(%s)' % number)
self.add_permalink_ref(node, _('Permalink to this equation'))
self.body.append('</span>')
- self.body.append(self.starttag(node, 'div', CLASS='math notranslate'))
+ self.body.append(self.starttag(node, 'div', CLASS='math notranslate nohighlight'))
else:
# but only once!
self.body.append('<div class="math">')
diff --git a/sphinx/ext/mathjax.py b/sphinx/ext/mathjax.py
index e3f7afebe..2bb7eec09 100644
--- a/sphinx/ext/mathjax.py
+++ b/sphinx/ext/mathjax.py
@@ -27,7 +27,7 @@ if False:
def html_visit_math(self, node):
# type: (nodes.NodeVisitor, nodes.Node) -> None
- self.body.append(self.starttag(node, 'span', '', CLASS='math notranslate'))
+ self.body.append(self.starttag(node, 'span', '', CLASS='math notranslate nohighlight'))
self.body.append(self.builder.config.mathjax_inline[0] +
self.encode(node['latex']) +
self.builder.config.mathjax_inline[1] + '</span>')
@@ -36,7 +36,7 @@ def html_visit_math(self, node):
def html_visit_displaymath(self, node):
# type: (nodes.NodeVisitor, nodes.Node) -> None
- self.body.append(self.starttag(node, 'div', CLASS='math notranslate'))
+ self.body.append(self.starttag(node, 'div', CLASS='math notranslate nohighlight'))
if node['nowrap']:
self.body.append(self.encode(node['latex']))
self.body.append('</div>')
diff --git a/sphinx/themes/basic/static/doctools.js_t b/sphinx/themes/basic/static/doctools.js_t
index b261a44f3..1dca47404 100644
--- a/sphinx/themes/basic/static/doctools.js_t
+++ b/sphinx/themes/basic/static/doctools.js_t
@@ -70,7 +70,9 @@ jQuery.fn.highlightText = function(text, className) {
if (node.nodeType === 3) {
var val = node.nodeValue;
var pos = val.toLowerCase().indexOf(text);
- if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
+ if (pos >= 0 &&
+ !jQuery(node.parentNode).hasClass(className) &&
+ !jQuery(node.parentNode).hasClass("nohighlight")) {
var span;
var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg");
if (isInSVG) {
diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py
index 68acc8e9a..f05959aca 100644
--- a/sphinx/writers/latex.py
+++ b/sphinx/writers/latex.py
@@ -23,12 +23,12 @@ from six import itervalues, text_type
from sphinx import addnodes
from sphinx import highlighting
+from sphinx.builders.latex.transforms import URI_SCHEMES, ShowUrlsTransform # NOQA # for compatibility
from sphinx.errors import SphinxError
from sphinx.locale import admonitionlabels, _, __
-from sphinx.transforms import SphinxTransform
from sphinx.util import split_into, logging
from sphinx.util.i18n import format_date
-from sphinx.util.nodes import clean_astext, traverse_parent
+from sphinx.util.nodes import clean_astext
from sphinx.util.template import LaTeXRenderer
from sphinx.util.texescape import tex_escape_map, tex_replace_map
@@ -47,7 +47,6 @@ BEGIN_DOC = r'''
'''
-URI_SCHEMES = ('mailto:', 'http:', 'https:', 'ftp:')
LATEXSECTIONNAMES = ["part", "chapter", "section", "subsection",
"subsubsection", "paragraph", "subparagraph"]
@@ -227,112 +226,6 @@ class ExtBabel(Babel):
return language
-class ShowUrlsTransform(SphinxTransform, object):
- def __init__(self, document, startnode=None):
- # type: (nodes.document, nodes.Node) -> None
- super(ShowUrlsTransform, self).__init__(document, startnode)
- self.expanded = False
-
- def apply(self):
- # type: () -> None
- # replace id_prefix temporarily
- id_prefix = self.document.settings.id_prefix
- self.document.settings.id_prefix = 'show_urls'
-
- self.expand_show_urls()
- if self.expanded:
- self.renumber_footnotes()
-
- # restore id_prefix
- self.document.settings.id_prefix = id_prefix
-
- def expand_show_urls(self):
- # type: () -> None
- show_urls = self.document.settings.env.config.latex_show_urls
- if show_urls is False or show_urls == 'no':
- return
-
- for node in self.document.traverse(nodes.reference):
- uri = node.get('refuri', '')
- if uri.startswith(URI_SCHEMES):
- if uri.startswith('mailto:'):
- uri = uri[7:]
- if node.astext() != uri:
- index = node.parent.index(node)
- if show_urls == 'footnote':
- footnote_nodes = self.create_footnote(uri)
- for i, fn in enumerate(footnote_nodes):
- node.parent.insert(index + i + 1, fn)
-
- self.expanded = True
- else: # all other true values (b/w compat)
- textnode = nodes.Text(" (%s)" % uri)
- node.parent.insert(index + 1, textnode)
-
- def create_footnote(self, uri):
- # type: (unicode) -> List[Union[nodes.footnote, nodes.footnote_ref]]
- label = nodes.label('', '#')
- para = nodes.paragraph()
- para.append(nodes.reference('', nodes.Text(uri), refuri=uri, nolinkurl=True))
- footnote = nodes.footnote(uri, label, para, auto=1)
- footnote['names'].append('#')
- self.document.note_autofootnote(footnote)
-
- label = nodes.Text('#')
- footnote_ref = nodes.footnote_reference('[#]_', label, auto=1,
- refid=footnote['ids'][0])
- self.document.note_autofootnote_ref(footnote_ref)
- footnote.add_backref(footnote_ref['ids'][0])
-
- return [footnote, footnote_ref]
-
- def renumber_footnotes(self):
- # type: () -> None
- def is_used_number(number):
- # type: (unicode) -> bool
- for node in self.document.traverse(nodes.footnote):
- if not node.get('auto') and number in node['names']:
- return True
-
- return False
-
- def is_auto_footnote(node):
- # type: (nodes.Node) -> bool
- return isinstance(node, nodes.footnote) and node.get('auto')
-
- def footnote_ref_by(node):
- # type: (nodes.Node) -> Callable[[nodes.Node], bool]
- ids = node['ids']
- parent = list(traverse_parent(node, (nodes.document, addnodes.start_of_file)))[0]
-
- def is_footnote_ref(node):
- # type: (nodes.Node) -> bool
- return (isinstance(node, nodes.footnote_reference) and
- ids[0] == node['refid'] and
- parent in list(traverse_parent(node)))
-
- return is_footnote_ref
-
- startnum = 1
- for footnote in self.document.traverse(is_auto_footnote):
- while True:
- label = str(startnum)
- startnum += 1
- if not is_used_number(label):
- break
-
- old_label = footnote[0].astext()
- footnote.remove(footnote[0])
- footnote.insert(0, nodes.label('', label))
- if old_label in footnote['names']:
- footnote['names'].remove(old_label)
- footnote['names'].append(label)
-
- for footnote_ref in self.document.traverse(footnote_ref_by(footnote)):
- footnote_ref.remove(footnote_ref[0])
- footnote_ref += nodes.Text(label)
-
-
class Table(object):
"""A table data"""
@@ -618,7 +511,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
if builder.config.language \
and 'fncychap' not in builder.config.latex_elements:
# use Sonny style if any language specified
- self.elements['fncychap'] = '\\usepackage[Sonny]{fncychap}'
+ self.elements['fncychap'] = ('\\usepackage[Sonny]{fncychap}\n'
+ '\\ChNameVar{\\Large\\normalfont'
+ '\\sffamily}\n\\ChTitleVar{\\Large'
+ '\\normalfont\\sffamily}')
self.babel = ExtBabel(builder.config.language)
if builder.config.language and not self.babel.is_supported_language():
diff --git a/tests/test_ext_math.py b/tests/test_ext_math.py
index 755a9e955..28ce094a8 100644
--- a/tests/test_ext_math.py
+++ b/tests/test_ext_math.py
@@ -35,19 +35,19 @@ def test_jsmath(app, status, warning):
app.builder.build_all()
content = (app.outdir / 'math.html').text()
- assert '<div class="math notranslate">\na^2 + b^2 = c^2</div>' in content
- assert ('<div class="math notranslate">\n\\begin{split}a + 1 &lt; b\\end{split}</div>'
- in content)
+ assert '<div class="math notranslate nohighlight">\na^2 + b^2 = c^2</div>' in content
+ assert ('<div class="math notranslate nohighlight">\n\\begin{split}a + 1 &lt; '
+ 'b\\end{split}</div>' in content)
assert (u'<span class="eqno">(1)<a class="headerlink" href="#equation-foo" '
u'title="Permalink to this equation">\xb6</a></span>'
- u'<div class="math notranslate" id="equation-foo">\ne^{i\\pi} = 1</div>'
- in content)
+ u'<div class="math notranslate nohighlight" id="equation-foo">'
+ '\ne^{i\\pi} = 1</div>' in content)
assert (u'<span class="eqno">(2)<a class="headerlink" href="#equation-math-0" '
u'title="Permalink to this equation">\xb6</a></span>'
- u'<div class="math notranslate" id="equation-math-0">\n'
+ u'<div class="math notranslate nohighlight" id="equation-math-0">\n'
u'e^{ix} = \\cos x + i\\sin x</div>' in content)
- assert '<div class="math notranslate">\nn \\in \\mathbb N</div>' in content
- assert '<div class="math notranslate">\na + 1 &lt; b</div>' in content
+ assert '<div class="math notranslate nohighlight">\nn \\in \\mathbb N</div>' in content
+ assert '<div class="math notranslate nohighlight">\na + 1 &lt; b</div>' in content
@pytest.mark.skipif(not has_binary('dvipng'),
@@ -91,7 +91,7 @@ def test_mathjax_align(app, status, warning):
app.builder.build_all()
content = (app.outdir / 'index.html').text()
- html = (r'<div class="math notranslate">\s*'
+ html = (r'<div class="math notranslate nohighlight">\s*'
r'\\\[ \\begin\{align\}\\begin\{aligned\}S \&amp;= \\pi r\^2\\\\'
r'V \&amp;= \\frac\{4\}\{3\} \\pi r\^3\\end\{aligned\}\\end\{align\} \\\]</div>')
assert re.search(html, content, re.S)
@@ -104,7 +104,7 @@ def test_math_number_all_mathjax(app, status, warning):
app.builder.build_all()
content = (app.outdir / 'index.html').text()
- html = (r'<div class="math notranslate" id="equation-index-0">\s*'
+ html = (r'<div class="math notranslate nohighlight" id="equation-index-0">\s*'
r'<span class="eqno">\(1\)<a .*>\xb6</a></span>\\\[a\^2\+b\^2=c\^2\\\]</div>')
assert re.search(html, content, re.S)
@@ -169,7 +169,7 @@ def test_mathjax_numfig_html(app, status, warning):
app.builder.build_all()
content = (app.outdir / 'math.html').text()
- html = ('<div class="math notranslate" id="equation-math-0">\n'
+ html = ('<div class="math notranslate nohighlight" id="equation-math-0">\n'
'<span class="eqno">(1.2)')
assert html in content
html = ('<p>Referencing equation <a class="reference internal" '