diff options
| author | milde <milde@929543f6-e4f2-0310-98a6-ba3bd3dd1d04> | 2009-09-14 10:38:18 +0000 |
|---|---|---|
| committer | milde <milde@929543f6-e4f2-0310-98a6-ba3bd3dd1d04> | 2009-09-14 10:38:18 +0000 |
| commit | 031f7473cf74b7b92df58a13cf2646b64aa6fd13 (patch) | |
| tree | 27f6dcda29e8e6e5a177464ee09dafdca671622d | |
| parent | 9840718a800e9db0327ab386f4b045947b97446d (diff) | |
| download | docutils-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.txt | 2 | ||||
| -rw-r--r-- | docs/dev/todo.txt | 5 | ||||
| -rw-r--r-- | docutils/writers/latex2e/__init__.py | 112 | ||||
| -rw-r--r-- | test/functional/expected/standalone_rst_latex.tex | 29 |
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} |
