From 501adbdb6ff3918a39b3a7373a2edc13615373be Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 4 Jun 2009 18:11:17 +0200 Subject: [PATCH 1/3] #191: Don't escape the tilde in URIs in LaTeX. --- CHANGES | 2 ++ sphinx/writers/latex.py | 18 +++++++++++++----- tests/test_markup.py | 3 +++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 1bc081f76..ba5c97429 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ Release 0.6.2 (in development) ============================== +* #191: Don't escape the tilde in URIs in LaTeX. + * Don't consider contents of source comments for the search index. * Set the default encoding to ``utf-8-sig`` to handle files with a diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 4cd6070e2..2ef92e244 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -828,12 +828,16 @@ class LaTeXTranslator(nodes.NodeVisitor): res = "%.3f\\linewidth" % (float(amount) / 100.0) return res + def is_inline(self, node): + """Check whether a node represents an inline element.""" + return isinstance(node.parent, nodes.TextElement) + def visit_image(self, node): attrs = node.attributes pre = [] # in reverse order post = [] include_graphics_options = [] - inline = isinstance(node.parent, nodes.TextElement) + is_inline = self.is_inline(node) if attrs.has_key('scale'): # Could also be done with ``scale`` option to # ``\includegraphics``; doing it this way for consistency. @@ -860,11 +864,11 @@ class LaTeXTranslator(nodes.NodeVisitor): (0, 'left'): ('{', '\\hfill}'), (0, 'right'): ('{\\hfill', '}'),} try: - pre.append(align_prepost[inline, attrs['align']][0]) - post.append(align_prepost[inline, attrs['align']][1]) + pre.append(align_prepost[is_inline, attrs['align']][0]) + post.append(align_prepost[is_inline, attrs['align']][1]) except KeyError: pass # XXX complain here? - if not inline: + if not is_inline: pre.append('\n') post.append('\n') pre.reverse() @@ -1022,7 +1026,7 @@ class LaTeXTranslator(nodes.NodeVisitor): self.context.append('') elif uri.startswith('mailto:') or uri.startswith('http:') or \ uri.startswith('https:') or uri.startswith('ftp:'): - self.body.append('\\href{%s}{' % self.encode(uri)) + self.body.append('\\href{%s}{' % self.encode_uri(uri)) self.context.append('}') elif uri.startswith('#'): self.body.append('\\hyperlink{%s}{' % uri[1:]) @@ -1323,6 +1327,10 @@ class LaTeXTranslator(nodes.NodeVisitor): text = text.replace('--', u'-{-}') return text + def encode_uri(self, text): + # in \href, the tilde is allowed and must be represented literally + return self.encode(text).replace('\\textasciitilde{}', '~') + def visit_Text(self, node): if self.verbatim is not None: self.verbatim += node.astext() diff --git a/tests/test_markup.py b/tests/test_markup.py index 77f2016ed..d65b798e8 100644 --- a/tests/test_markup.py +++ b/tests/test_markup.py @@ -118,3 +118,6 @@ def test_latex_escaping(): u'\\begin{Verbatim}[commandchars=@\\[\\]]\n' u'@PYGZat[]@(@Gamma@)\\@(@infty@)@$@PYGZlb[]@PYGZrb[]\n' u'\\end{Verbatim}') + # in URIs + yield (verify, u'`test `_', None, + u'\\href{http://example.com/~me/}{test}') From 137db91d777468fd76cab9670143c5a359ae8efe Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 4 Jun 2009 18:21:26 +0200 Subject: [PATCH 2/3] When highlighting Python code, ignore extra indentation before trying to parse it as Python. --- CHANGES | 3 +++ sphinx/highlighting.py | 5 +++++ tests/root/includes.txt | 17 ++++++++++++----- tests/test_build.py | 4 +++- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index ba5c97429..7bdbbb0f9 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ Release 0.6.2 (in development) ============================== +* When highlighting Python code, ignore extra indentation before + trying to parse it as Python. + * #191: Don't escape the tilde in URIs in LaTeX. * Don't consider contents of source comments for the search index. diff --git a/sphinx/highlighting.py b/sphinx/highlighting.py index c41720ad3..5bd0fe00a 100644 --- a/sphinx/highlighting.py +++ b/sphinx/highlighting.py @@ -13,6 +13,7 @@ import sys import cgi import re import parser +import textwrap from sphinx.util.texescape import tex_hl_escape_map @@ -129,6 +130,10 @@ class PygmentsBridge(object): # Make sure it ends in a newline src += '\n' + # Ignore consistent indentation. + if src.lstrip('\n').startswith(' '): + src = textwrap.dedent(src) + # Replace "..." by a mark which is also a valid python expression # (Note, the highlighter gets the original source, this is only done # to allow "..." in code and still highlight it as Python code.) diff --git a/tests/root/includes.txt b/tests/root/includes.txt index 44e33af0d..0976bf4a8 100644 --- a/tests/root/includes.txt +++ b/tests/root/includes.txt @@ -1,3 +1,10 @@ +Testing downloadable files +========================== + +Download :download:`img.png` here. +Download :download:`this ` there. +Don't download :download:`this `. + Test file and literal inclusion =============================== @@ -37,10 +44,10 @@ Literalinclude options :start-after: coding: utf-8 :end-before: class Foo +Test if dedenting before parsing works. -Testing downloadable files -========================== +.. highlight:: python -Download :download:`img.png` here. -Download :download:`this ` there. -Don't download :download:`this `. +.. cssclass:: inc-pyobj-dedent +.. literalinclude:: literal.inc + :pyobject: Bar.baz diff --git a/tests/test_build.py b/tests/test_build.py index 72c821d06..4c25c1468 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -43,7 +43,7 @@ ENV_WARNINGS = """\ http://www.python.org/logo.png %(root)s/includes.txt:: (WARNING/2) Encoding 'utf-8-sig' used for reading \ included file u'wrongenc.inc' seems to be wrong, try giving an :encoding: option -%(root)s/includes.txt:56: WARNING: download file not readable: nonexisting.png +%(root)s/includes.txt:4: WARNING: download file not readable: nonexisting.png """ HTML_WARNINGS = ENV_WARNINGS + """\ @@ -134,6 +134,8 @@ if pygments: r'^class Foo:\n pass\nclass Bar:\n$', ".//div[@class='inc-startend highlight-text']/div/pre": ur'^foo = u"Including Unicode characters: üöä"\n$', + ".//div[@class='inc-pyobj-dedent highlight-python']/div/pre/span": + r'def', }) HTML_XPATH['subdir/includes.html'].update({ ".//pre/span": 'line 1', From be49adef8c8bf52c3a2db406e6aa954063f1c877 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 4 Jun 2009 18:39:47 +0200 Subject: [PATCH 3/3] #158: Allow '..' in template names, and absolute template paths; Jinja 2 by default disables both. --- CHANGES | 3 +++ sphinx/jinja2glue.py | 29 ++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 7bdbbb0f9..72bef47bf 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ Release 0.6.2 (in development) ============================== +* #158: Allow '..' in template names, and absolute template paths; + Jinja 2 by default disables both. + * When highlighting Python code, ignore extra indentation before trying to parse it as Python. diff --git a/sphinx/jinja2glue.py b/sphinx/jinja2glue.py index 679447a81..c584a0cde 100644 --- a/sphinx/jinja2glue.py +++ b/sphinx/jinja2glue.py @@ -15,6 +15,7 @@ from pprint import pformat from jinja2 import FileSystemLoader, BaseLoader, TemplateNotFound, \ contextfunction +from jinja2.utils import open_if_exists from jinja2.sandbox import SandboxedEnvironment from sphinx.util import mtimes_of_files @@ -36,6 +37,32 @@ def accesskey(context, key): return '' +class SphinxFileSystemLoader(FileSystemLoader): + """FileSystemLoader subclass that is not so strict about '..' + entries in template names.""" + + def get_source(self, environment, template): + for searchpath in self.searchpath: + filename = path.join(searchpath, template) + f = open_if_exists(filename) + if f is None: + continue + try: + contents = f.read().decode(self.encoding) + finally: + f.close() + + mtime = path.getmtime(filename) + def uptodate(): + try: + return path.getmtime(filename) == mtime + except OSError: + return False + return contents, filename, uptodate + raise TemplateNotFound(template) + + + class BuiltinTemplateLoader(TemplateBridge, BaseLoader): """ Interfaces the rendering environment of jinja2 for use in Sphinx. @@ -65,7 +92,7 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader): self.pathchain = chain # make the paths into loaders - self.loaders = map(FileSystemLoader, chain) + self.loaders = map(SphinxFileSystemLoader, chain) use_i18n = builder.translator is not None extensions = use_i18n and ['jinja2.ext.i18n'] or []