summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormilde <milde@929543f6-e4f2-0310-98a6-ba3bd3dd1d04>2009-09-14 10:38:18 +0000
committermilde <milde@929543f6-e4f2-0310-98a6-ba3bd3dd1d04>2009-09-14 10:38:18 +0000
commit031f7473cf74b7b92df58a13cf2646b64aa6fd13 (patch)
tree27f6dcda29e8e6e5a177464ee09dafdca671622d
parent9840718a800e9db0327ab386f4b045947b97446d (diff)
downloaddocutils-031f7473cf74b7b92df58a13cf2646b64aa6fd13.tar.gz
(LaTeX) footnotes now link forth and back.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@6128 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
-rw-r--r--HISTORY.txt2
-rw-r--r--docs/dev/todo.txt5
-rw-r--r--docutils/writers/latex2e/__init__.py112
-rw-r--r--test/functional/expected/standalone_rst_latex.tex29
4 files changed, 71 insertions, 77 deletions
diff --git a/HISTORY.txt b/HISTORY.txt
index b46066d83..14cd5ca1a 100644
--- a/HISTORY.txt
+++ b/HISTORY.txt
@@ -138,7 +138,7 @@ Changes Since 0.5
- Use template (file and configuration option).
- Render doctest blocks as literal blocks (fixes [ 1586058 ]).
- Use `translate` instead of repeated `replace` calls for text encoding.
- - Hyperlinked footnote marks and support for symbol footnotes with
+ - Hyperlinked footnotes and support for symbol footnotes with
``--use-latex-footnotes``.
* docutils/writers/manpage.py
diff --git a/docs/dev/todo.txt b/docs/dev/todo.txt
index b23577384..7cf0d3adc 100644
--- a/docs/dev/todo.txt
+++ b/docs/dev/todo.txt
@@ -1964,11 +1964,8 @@ Which packages do we want to use?
* footnotes
+ document customization (links to how-to and packages)
-
- + True footnotes with LaTeX auto-numbering? (as option?)
- + Add back-links (analogue to the system message, but in the
- \DUfootnotetext and \DUfootnotemark cmds).
+ + True footnotes with LaTeX auto-numbering? (as option?)
The `hyperref` manual says:
diff --git a/docutils/writers/latex2e/__init__.py b/docutils/writers/latex2e/__init__.py
index 3d7237d8a..1b3d94696 100644
--- a/docutils/writers/latex2e/__init__.py
+++ b/docutils/writers/latex2e/__init__.py
@@ -43,8 +43,7 @@ class Writer(writers.Writer):
'separated by commas. Default is "a4paper".',
['--documentoptions'],
{'default': 'a4paper', }),
- ('Use LaTeX footnotes (currently supports only numbered footnotes). '
- 'Default: no, uses figures.',
+ ('Use LaTeX footnotes. Default: no, uses figures.',
['--use-latex-footnotes'],
{'default': 0, 'action': 'store_true',
'validator': frontend.validate_boolean}),
@@ -403,15 +402,15 @@ PreambleCmds.float_settings = r"""\usepackage{float} % float configuration
\floatplacement{figure}{H} % place figures here definitely"""
PreambleCmds.footnotes = r"""% numeric or symbol footnotes with hyperlinks
-\providecommand*{\DUfootnotemark}[3]{{%
- \renewcommand{\thefootnote}{\csname #2\endcsname{footnote}}%
- \hyperlink{#1}{\footnotemark[#3]}%
-}}
+\providecommand*{\DUfootnotemark}[3]{%
+ \raisebox{1em}{\hypertarget{#1}{}}%
+ \hyperlink{#2}{\textsuperscript{#3}}%
+}
\providecommand{\DUfootnotetext}[4]{{%
\renewcommand{\thefootnote}{%
\protect\raisebox{1em}{\protect\hypertarget{#1}{}}%
- \csname #2\endcsname{footnote}}%
- \footnotetext[#3]{#4}%
+ \protect\hyperlink{#2}{#3}}%
+ \footnotetext{#4}%
}}"""
PreambleCmds.footnote_floats = r"""% settings for footnotes as floats:
@@ -828,7 +827,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
has_latex_toc = False # is there a toc in the doc? (needed by minitoc)
is_toc_list = False # is the current bullet_list a ToC?
section_level = 0
- footnotesymbols = ['*'] # footnote symbols in order of appearance
# Flags to encode():
# inside citation reference labels underscores dont need to be escaped
@@ -1118,7 +1116,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
if self.literal_block or self.literal:
separate_chars += ',`\'"<>'
# LaTeX encoding maps:
- special_chars2latex = {
+ special_chars = {
ord('#'): ur'\#',
ord('$'): ur'\$',
ord('%'): ur'\%',
@@ -1136,13 +1134,18 @@ class LaTeXTranslator(nodes.NodeVisitor):
# Commands with optional args inside an optional arg must be put
# in a group, e.g. ``\item[{\hyperref[label]{text}}]``.
ord('['): ur'{[}',
- ord(']'): ur'{]}',
+ ord(']'): ur'{]}'
+ }
# Unicode chars that are not recognized by LaTeX's utf8 encoding
- 0x21d4: ur'$\Leftrightarrow$',
+ unsupported_unicode_chars = {
0x00A0: ur'~', # NO-BREAK SPACE
+ 0x21d4: ur'$\Leftrightarrow$',
+ # Docutils footnote symbols:
+ 0x2660: ur'$\spadesuit$',
+ 0x2663: ur'$\clubsuit$',
}
# Unicode chars that are recognized by LaTeX's utf8 encoding
- unicode2latex = {
+ unicode_chars = {
0x2013: ur'\textendash{}',
0x2014: ur'\textemdash{}',
0x2018: ur'`',
@@ -1155,13 +1158,19 @@ class LaTeXTranslator(nodes.NodeVisitor):
0x2021: ur'\ddag{}',
0x2026: ur'\dots{}',
0x2122: ur'\texttrademark{}',
- # TODO: greek alphabet ... ?
- # see also LaTeX codec
- # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/252124
- # and unimap.py from TeXML
}
+ # Unicode chars that require a feature/package to render
+ pifont_chars = {
+ 0x2665: ur'\ding{170}', # black heartsuit
+ 0x2666: ur'\ding{169}', # black diamondsuit
+ }
+ # TODO: greek alphabet ... ?
+ # see also LaTeX codec
+ # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/252124
+ # and unimap.py from TeXML
+
# set up the translation table:
- table = special_chars2latex
+ table = special_chars
# keep the underscore in citation references
if self.inside_citation_reference_label:
del(table[ord('_')])
@@ -1189,8 +1198,13 @@ class LaTeXTranslator(nodes.NodeVisitor):
else:
text = self.babel.quote_quotes(text)
# Unicode chars:
+ table.update(unsupported_unicode_chars)
if not self.latex_encoding.startswith('utf8'):
- table.update(unicode2latex)
+ table.update(unicode_chars)
+ # Unicode chars that require a feature/package to render
+ if all([unichr(ch) in text for ch in pifont_chars.keys()]):
+ self.requirements['pifont'] = '\\usepackage{pifont}'
+ table.update(pifont_chars)
text = text.translate(table)
@@ -1222,20 +1236,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
## body = ''.join(self.body_prefix + self.body + self.body_suffix)
## return head + '\n' + body
- def footnotesymbol_number(self, symbol):
- """Return running number for a footnote symbol"""
- try:
- i = self.footnotesymbols.index(symbol) + 1
- except ValueError:
- self.footnotesymbols.append(symbol)
- i = len(self.footnotesymbols)
- if i % 9 == 0:
- warn = self.document.reporter.warning
- warn('symbol footnote ``[*]_``\n'
- 'LaTeX supports only 9 different footnote symbols. '
- 'Starting again with "*".')
- return (i+1) % 9 or 9
-
def is_inline(self, node):
"""Check whether a node represents an inline element"""
return isinstance(node.parent, nodes.TextElement)
@@ -1850,17 +1850,15 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.out = self.body
def visit_footnote(self, node):
+ try:
+ backref = node['backrefs'][0]
+ except IndexError:
+ backref = node['ids'][0] # no backref, use self-ref instead
if self.use_latex_footnotes:
self.fallbacks['footnotes'] = PreambleCmds.footnotes
num,text = node.astext().split(None,1)
- try:
- i = int(num)
- format = 'arabic'
- except ValueError:
- i = self.footnotesymbol_number(num)
- format = 'fnsymbol'
- self.out.append('%%\n\\DUfootnotetext{%s}{%s}{%d}{' %
- (node['ids'][0], format, i))
+ self.out.append('%%\n\\DUfootnotetext{%s}{%s}{%s}{' %
+ (node['ids'][0], backref, self.encode(num)))
if node['ids'] == node['names']:
self.out += self.ids_to_labels(node)
else:
@@ -1883,8 +1881,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
href = node['refid']
elif 'refname' in node:
href = self.document.nameids[node['refname']]
- if self.use_latex_footnotes:
- self.fallbacks['footnotes'] = PreambleCmds.footnotes
+ # if self.use_latex_footnotes:
# TODO: insert footnote content at (or near) this place
# print "footnote-ref to", node['refid']
# footnotes = (self.document.footnotes +
@@ -1894,31 +1891,20 @@ class LaTeXTranslator(nodes.NodeVisitor):
# # print footnote['ids']
# if node.get('refid', '') in footnote['ids']:
# print 'matches', footnote['ids']
- num = node.astext()
- try:
- i = int(num)
- format = 'arabic'
- except ValueError:
- i = self.footnotesymbol_number(num)
- format = 'fnsymbol'
- self.out.append(r'\DUfootnotemark{%s}{%s}{%d}' %
- (href, format, i))
- raise nodes.SkipNode
format = self.settings.footnote_references
if format == 'brackets':
- suffix = '['
- self.context.append(']')
- elif format == 'superscript':
- suffix = r'\textsuperscript{'
+ self.append_hypertargets()
+ self.out.append('[%s\\hyperlink{%s}{' % (href))
+ self.context.append(']}')
+ else:
+ self.fallbacks['footnotes'] = PreambleCmds.footnotes
+ # TODO: second argument = backlink id
+ self.out.append(r'\DUfootnotemark{%s}{%s}{' %
+ (node['ids'][0], href))
self.context.append('}')
- else: # shouldn't happen
- raise AssertionError('Illegal footnote reference format.')
- self.out.append('%s\\hyperlink{%s}{' % (suffix,href))
def depart_footnote_reference(self, node):
- if self.use_latex_footnotes:
- return
- self.out.append('}%s' % self.context.pop())
+ self.out.append(self.context.pop())
# footnote/citation label
def label_delim(self, node, bracket, superscript):
diff --git a/test/functional/expected/standalone_rst_latex.tex b/test/functional/expected/standalone_rst_latex.tex
index e1bc30b49..e87402ce6 100644
--- a/test/functional/expected/standalone_rst_latex.tex
+++ b/test/functional/expected/standalone_rst_latex.tex
@@ -65,6 +65,17 @@
{\quote\description}
{\enddescription\endquote}
}{}
+% numeric or symbol footnotes with hyperlinks
+\providecommand*{\DUfootnotemark}[3]{%
+ \raisebox{1em}{\hypertarget{#1}{}}%
+ \hyperlink{#2}{\textsuperscript{#3}}%
+}
+\providecommand{\DUfootnotetext}[4]{{%
+ \renewcommand{\thefootnote}{%
+ \protect\raisebox{1em}{\protect\hypertarget{#1}{}}%
+ \protect\hyperlink{#2}{#3}}%
+ \footnotetext{#4}%
+}}
% inline markup (custom roles)
% \DUrole{#1}{#2} tries \DUrole#1{#2}
@@ -454,11 +465,11 @@ A paragraph.
Paragraphs contain text and may contain inline markup: \emph{emphasis},
\textbf{strong emphasis}, \texttt{inline literals}, standalone hyperlinks
-(\href{http://www.python.org}{http://www.python.org}), external hyperlinks (\href{http://www.python.org/}{Python}\textsuperscript{\hyperlink{id26}{5}}), internal
+(\href{http://www.python.org}{http://www.python.org}), external hyperlinks (\href{http://www.python.org/}{Python}\DUfootnotemark{id27}{id26}{5}), internal
cross-references (\hyperref[example]{example}), external hyperlinks with embedded URIs
(\href{http://www.python.org}{Python web site}), \href{http://www.python.org/}{anonymous hyperlink
-references}\textsuperscript{\hyperlink{id26}{5}} (\href{http://docutils.sourceforge.net/}{a second reference}\textsuperscript{\hyperlink{id31}{6}}), footnote references (manually
-numbered\textsuperscript{\hyperlink{id8}{1}}, anonymous auto-numbered\textsuperscript{\hyperlink{id12}{3}}, labeled auto-numbered\textsuperscript{\hyperlink{label}{2}}, or symbolic\textsuperscript{\hyperlink{id13}{*}}), citation references ([\hyperlink{cit2002}{CIT2002}]),
+references}\DUfootnotemark{id30}{id26}{5} (\href{http://docutils.sourceforge.net/}{a second reference}\DUfootnotemark{id32}{id31}{6}), footnote references (manually
+numbered\DUfootnotemark{id1}{id8}{1}, anonymous auto-numbered\DUfootnotemark{id2}{id12}{3}, labeled auto-numbered\DUfootnotemark{id3}{label}{2}, or symbolic\DUfootnotemark{id4}{id13}{*}), citation references ([\hyperlink{cit2002}{CIT2002}]),
substitution references (\includegraphics{../../../docs/user/rst/images/biohazard.png}), and %
\phantomsection\label{inline-hyperlink-targets}inline hyperlink targets
(see \hyperref[targets]{Targets} below for a reference back to here). Character-level
@@ -892,10 +903,10 @@ least 3 spaces.
This is the footnote's second paragraph.
\end{figure}
\begin{figure}[b]\raisebox{1em}{\hypertarget{label}{}}\phantomsection\label{label}\textsuperscript{2}
-Footnotes may be numbered, either manually (as in\textsuperscript{\hyperlink{id8}{1}}) or
+Footnotes may be numbered, either manually (as in\DUfootnotemark{id9}{id8}{1}) or
automatically using a ``\#''-prefixed label. This footnote has a
label so it can be referred to from multiple places, both as a
-footnote reference (\textsuperscript{\hyperlink{label}{2}}) and as a \hyperref[label]{hyperlink reference}.
+footnote reference (\DUfootnotemark{id10}{label}{2}) and as a \hyperref[label]{hyperlink reference}.
\end{figure}
\begin{figure}[b]\raisebox{1em}{\hypertarget{id12}{}}\phantomsection\label{id12}\textsuperscript{3}
This footnote is numbered automatically and anonymously using a
@@ -907,7 +918,7 @@ And this is the third paragraph.
\end{figure}
\begin{figure}[b]\raisebox{1em}{\hypertarget{id13}{}}\phantomsection\label{id13}\textsuperscript{*}
Footnotes may also use symbols, specified with a ``*'' label.
-Here's a reference to the next footnote:\textsuperscript{\hyperlink{id15}{\dag{}}}.
+Here's a reference to the next footnote:\DUfootnotemark{id14}{id15}{\dag{}}.
\end{figure}
\begin{figure}[b]\raisebox{1em}{\hypertarget{id15}{}}\phantomsection\label{id15}\textsuperscript{\dag{}}
This footnote shows the next symbol in the sequence.
@@ -956,7 +967,7 @@ Section headers are implicit targets, referred to by name. See
\hyperref[targets]{Targets}, which is a subsection of \hyperref[body-elements]{Body Elements}.
Explicit external targets are interpolated into references such as
-``\href{http://www.python.org/}{Python}\textsuperscript{\hyperlink{id26}{5}}''.
+``\href{http://www.python.org/}{Python}\DUfootnotemark{id28}{id26}{5}''.
Targets may be indirect and anonymous. Thus \hyperref[targets]{this phrase} may also
refer to the \hyperref[targets]{Targets} section.
@@ -1321,7 +1332,7 @@ allowed (e.g. inside a directive).
\label{replacement-text}%
}
-I recommend you try \href{http://www.python.org/}{Python, \emph{the} best language around}\textsuperscript{\hyperlink{id26}{5}}.
+I recommend you try \href{http://www.python.org/}{Python, \emph{the} best language around}\DUfootnotemark{id29}{id26}{5}.
%___________________________________________________________________________
@@ -1419,7 +1430,7 @@ This~is~a~parsed~literal~block.\\
~~~~This~line~is~indented.~~The~next~line~is~blank.\\
~\\
Inline~markup~is~supported,~e.g.~\emph{emphasis},~\textbf{strong},~\texttt{literal\\
-text},~footnotes\textsuperscript{\hyperlink{id8}{1}},~%
+text},~footnotes\DUfootnotemark{id22}{id8}{1},~%
\phantomsection\label{hyperlink-targets}hyperlink~targets,~and~\href{http://www.python.org/}{references}.
}
\end{quote}