Author: milde Date: 2009-09-28 12:51:11 +0200 (Mon, 28 Sep 2009) New Revision: 6145 Added: trunk/docutils/test/functional/input/data/hyperlinking.txt Modified: trunk/docutils/docutils/writers/latex2e/__init__.py trunk/docutils/test/functional/expected/standalone_rst_latex.tex trunk/docutils/test/functional/input/standalone_rst_latex.txt Log: Fix hyper-targets in captions, support custom roles based on "raw". Modified: trunk/docutils/docutils/writers/latex2e/__init__.py =================================================================== --- trunk/docutils/docutils/writers/latex2e/__init__.py 2009-09-25 22:12:30 UTC (rev 6144) +++ trunk/docutils/docutils/writers/latex2e/__init__.py 2009-09-28 10:51:11 UTC (rev 6145) @@ -619,13 +619,13 @@ def open(self): self._open = 1 self._col_specs = [] - self.caption = None + self.caption = [] self._attrs = {} self._in_head = 0 # maybe context with search def close(self): self._open = 0 self._col_specs = None - self.caption = None + self.caption = [] self._attrs = {} self.stubs = [] def is_open(self): @@ -715,9 +715,10 @@ def get_caption(self): if not self.caption: return '' + caption = ''.join(self.caption) if 1 == self._translator.thead_depth(): - return r'\caption{%s}\\' '\n' % self.caption - return r'\caption[]{%s (... continued)}\\' '\n' % self.caption + return r'\caption{%s}\\' '\n' % caption + return r'\caption[]{%s (... continued)}\\' '\n' % caption def need_recurse(self): if self._latex_type == 'longtable': @@ -953,6 +954,7 @@ # Where to collect the output of visitor methods (default: body) self.out = self.body + self.out_stack = [] # stack of output collectors # Process settings # ~~~~~~~~~~~~~~~~ @@ -1257,7 +1259,13 @@ labels.insert(0, '\\phantomsection') return labels + def push_output_collector(self, new_out): + self.out_stack.append(self.out) + self.out = new_out + def pop_output_collector(self): + self.out = self.out_stack.pop() + # Visitor methods # --------------- @@ -1511,10 +1519,10 @@ pass def visit_docinfo(self, node): - self.out = self.docinfo + self.push_output_collector(self.docinfo) def depart_docinfo(self, node): - self.out = self.body + self.pop_output_collector() # Some itmes (e.g. author) end up at other places if self.docinfo: # tabularx: automatic width of columns, no page breaks allowed. @@ -1841,13 +1849,13 @@ self.out.append(self.context.pop()) def visit_footer(self, node): - self.out = [] + self.push_output_collector([]) self.out.append(r'\newcommand{\DUfooter}{') def depart_footer(self, node): self.out.append('}') self.requirements['~footer'] = ''.join(self.out) - self.out = self.body + self.pop_output_collector() def visit_footnote(self, node): try: @@ -1901,7 +1909,7 @@ else: self.fallbacks['footnotes'] = PreambleCmds.footnotes # TODO: second argument = backlink id - self.out.append(r'\DUfootnotemark{%s}{%s}{' % + self.out.append(r'\DUfootnotemark{%s}{%s}{' % (node['ids'][0], href)) self.context.append('}') @@ -1937,13 +1945,13 @@ pass def visit_header(self, node): - self.out = [] + self.push_output_collector([]) self.out.append(r'\newcommand{\DUheader}{') def depart_header(self, node): self.out.append('}') self.requirements['~header'] = ''.join(self.out) - self.out = self.body + self.pop_output_collector() def visit_hint(self, node): self.visit_admonition(node) @@ -2125,7 +2133,7 @@ if self.literal_block_env != '' and self.is_plaintext(node): self.requirements['literal_block'] = packages.get( self.literal_block_env, '') - self.verbatim = 1 + self.verbatim = True self.out.append('\\begin{%s}%s\n' % (self.literal_block_env, self.literal_block_options)) else: @@ -2247,10 +2255,18 @@ self.out.append('}}') def visit_raw(self, node): - if 'latex' in node.get('format', '').split(): - self.out.append(node.astext()) - raise nodes.SkipNode + if not 'latex' in node.get('format', '').split(): + raise nodes.SkipNode + if node['classes']: + self.visit_inline(node) + # append "as-is" skipping any LaTeX-encoding + self.verbatim = True + def depart_raw(self, node): + self.verbatim = False + if node['classes']: + self.depart_inline(node) + def visit_reference(self, node): # BUG: hash_char '#' is troublesome in LaTeX. # mbox and other environments do not like the '#'. @@ -2413,7 +2429,11 @@ ## self.out.append('%% %s\n' % node) # for debugging return self.out.append('%\n') - self.out += self.ids_to_labels(node) + # do we need an anchor (\phantomsection)? + set_anchor = not(isinstance(node.parent, nodes.caption) or + isinstance(node.parent, nodes.title)) + # TODO: where else can/must we omit the \phantomsection? + self.out += self.ids_to_labels(node, set_anchor) def depart_target(self, node): pass @@ -2505,9 +2525,8 @@ self.context.append('}\n') # Table caption elif isinstance(node.parent, nodes.table): - # caption must be written after column spec - self.active_table.caption = self.encode(node.astext()) - raise nodes.SkipNode + self.push_output_collector(self.active_table.caption) + self.context.append('') # Section title else: self.out.append('\n\n') @@ -2533,6 +2552,8 @@ def depart_title(self, node): self.out.append(self.context.pop()) + if isinstance(node.parent, nodes.table): + self.pop_output_collector() def minitoc(self, title, depth): """Generate a local table of contents with LaTeX package minitoc""" @@ -2604,7 +2625,7 @@ self.context.append('') elif ('abstract' in node['classes'] and self.settings.use_latex_abstract): - self.out = self.abstract + self.push_output_collector(self.abstract) self.out.append('\\begin{abstract}') self.context.append('\\end{abstract}\n') if isinstance(node.next_node(), nodes.title): @@ -2614,17 +2635,19 @@ # special topics: if 'abstract' in node['classes']: self.fallbacks['abstract'] = PreambleCmds.abstract - self.out = self.abstract + self.push_output_collector(self.abstract) if 'dedication' in node['classes']: self.fallbacks['dedication'] = PreambleCmds.dedication - self.out = self.dedication + self.push_output_collector(self.dedication) self.out.append('\n\\DUtopic[%s]{\n' % ','.join(node['classes'])) self.context.append('}\n') def depart_topic(self, node): self.out.append(self.context.pop()) self.is_toc_list = False - self.out = self.body + if ('abstract' in node['classes'] or + 'dedication' in node['classes']): + self.pop_output_collector() def visit_inline(self, node): # <span>, i.e. custom roles # insert fallback definition Modified: trunk/docutils/test/functional/expected/standalone_rst_latex.tex =================================================================== --- trunk/docutils/test/functional/expected/standalone_rst_latex.tex 2009-09-25 22:12:30 UTC (rev 6144) +++ trunk/docutils/test/functional/expected/standalone_rst_latex.tex 2009-09-28 10:51:11 UTC (rev 6145) @@ -375,6 +375,8 @@ \item \hyperref[encoding-special-chars]{3.5~~~Encoding special chars} +\item \hyperref[hyperlinks-and-targets]{3.6~~~Hyperlinks and -targets} + \end{list} \item \hyperref[error-handling]{4~~~Error Handling} @@ -926,8 +928,8 @@ \begin{figure}[b]\raisebox{1em}{\hypertarget{id16}{}}\phantomsection\label{id16}\textsuperscript{4} Here's an unreferenced footnote, with a reference to a nonexistent footnote:% -\raisebox{1em}{\hypertarget{id86}{}}% -\raisebox{1em}{\hypertarget{id17}{}}\hyperlink{id85}{\textbf{\color{red}{[}5{]}\_}}. +\raisebox{1em}{\hypertarget{id87}{}}% +\raisebox{1em}{\hypertarget{id17}{}}\hyperlink{id86}{\textbf{\color{red}{[}5{]}\_}}. \end{figure} @@ -944,8 +946,8 @@ \end{figure} Here's a reference to the above, [\hyperlink{cit2002}{CIT2002}], and a % -\raisebox{1em}{\hypertarget{id88}{}}% -\raisebox{1em}{\hypertarget{id19}{}}\hyperlink{id87}{\textbf{\color{red}{[}nonexistent{]}\_}} +\raisebox{1em}{\hypertarget{id89}{}}% +\raisebox{1em}{\hypertarget{id19}{}}\hyperlink{id88}{\textbf{\color{red}{[}nonexistent{]}\_}} citation. @@ -973,7 +975,7 @@ refer to the \hyperref[targets]{Targets} section. Here's a % -\raisebox{1em}{\hypertarget{id90}{}}\hyperlink{id89}{\textbf{\color{red}`hyperlink reference without a target`\_}}, which generates an +\raisebox{1em}{\hypertarget{id91}{}}\hyperlink{id90}{\textbf{\color{red}`hyperlink reference without a target`\_}}, which generates an error. @@ -1001,7 +1003,7 @@ Since there are two ``Duplicate Target Names'' section headers, we cannot uniquely refer to either of them by name. If we try to (like this: % -\raisebox{1em}{\hypertarget{id92}{}}\hyperlink{id91}{\textbf{\color{red}`Duplicate Target Names`\_}}), an error is generated. +\raisebox{1em}{\hypertarget{id93}{}}\hyperlink{id92}{\textbf{\color{red}`Duplicate Target Names`\_}}), an error is generated. %___________________________________________________________________________ @@ -1481,8 +1483,8 @@ This does not necessarily look nice, because there may be missing white space. It's just there to freeze the behavior. -A test.Second test.Another test with myclass set. -This is the fourth test with myrawroleclass set. +A test.Second test.\DUrole{myclass}{Another test with myclass set.} +This is the \DUrole{myrawroleclass}{fourth test} with myrawroleclass set. Fifth test in LaTeX.\\Line two. %___________________________________________________________________________ @@ -1990,6 +1992,49 @@ } \end{quote} + +%___________________________________________________________________________ + +\subsection*{3.6~~~Hyperlinks and -targets% + \phantomsection% + \addcontentsline{toc}{subsection}{3.6~~~Hyperlinks and -targets}% + \label{hyperlinks-and-targets}% +} + +In LaTeX, we must set an explicit anchor (\texttt{\reflectbox{/}phantomsection}) for a +% +\phantomsection\label{hypertarget-in-plain-text}hypertarget in plain text but not in a table or figure caption: + +\leavevmode +\setlength{\DUtablewidth}{\linewidth} +\begin{longtable}[c]{|p{0.075\DUtablewidth}|p{0.075\DUtablewidth}|p{0.075\DUtablewidth}|} +\caption{Table with % +\label{hypertarget-in-table-title}hypertarget in table title.}\\ +\hline + +False + & +True + & +None + \\ +\hline +\end{longtable} +\begin{figure} +\noindent\makebox[\textwidth][c]{\includegraphics{../../../docs/user/rst/images/biohazard.png}} +\caption{Figure with % +\label{hypertarget-in-figure-caption}hypertarget in figure caption.} +\begin{DUlegend} +Legend with % +\phantomsection\label{hypertarget-in-figure-legend}hypertarget in figure legend. +\end{DUlegend} +\end{figure} + +See \hyperref[hypertarget-in-plain-text]{hypertarget in plain text}, +\hyperref[hypertarget-in-table-title]{hypertarget in table title}, +\hyperref[hypertarget-in-figure-caption]{hypertarget in figure caption}, and +\hyperref[hypertarget-in-figure-legend]{hypertarget in figure legend}, + % unusual combinations (from newlatex, for interactive testing) % .. include:: data/latex.txt @@ -2031,41 +2076,41 @@ \DUadmonition[system-message]{ \DUtitle[system-message]{system-message} -\raisebox{1em}{\hypertarget{id85}{}} +\raisebox{1em}{\hypertarget{id86}{}} {\color{red}ERROR/3} in \texttt{functional/input/standalone\_rst\_latex.txt}, line~359 -\hyperlink{id86}{ +\hyperlink{id87}{ Unknown target name: ``5''. }} \DUadmonition[system-message]{ \DUtitle[system-message]{system-message} -\raisebox{1em}{\hypertarget{id87}{}} +\raisebox{1em}{\hypertarget{id88}{}} {\color{red}ERROR/3} in \texttt{functional/input/data/standard.txt}, line~368 -\hyperlink{id88}{ +\hyperlink{id89}{ Unknown target name: ``nonexistent''. }} \DUadmonition[system-message]{ \DUtitle[system-message]{system-message} -\raisebox{1em}{\hypertarget{id89}{}} +\raisebox{1em}{\hypertarget{id90}{}} {\color{red}ERROR/3} in \texttt{functional/input/data/standard.txt}, line~395 -\hyperlink{id90}{ +\hyperlink{id91}{ Unknown target name: ``hyperlink reference without a target''. }} \DUadmonition[system-message]{ \DUtitle[system-message]{system-message} -\raisebox{1em}{\hypertarget{id91}{}} +\raisebox{1em}{\hypertarget{id92}{}} {\color{red}ERROR/3} in \texttt{functional/input/data/standard.txt}, line~408 -\hyperlink{id92}{ +\hyperlink{id93}{ Duplicate target name, cannot be used as a unique reference: ``duplicate target names''. }} Added: trunk/docutils/test/functional/input/data/hyperlinking.txt =================================================================== --- trunk/docutils/test/functional/input/data/hyperlinking.txt 2009-09-25 22:12:30 UTC (rev 6144) +++ trunk/docutils/test/functional/input/data/hyperlinking.txt 2009-09-28 10:51:11 UTC (rev 6145) @@ -0,0 +1,23 @@ +Hyperlinks and -targets +----------------------- + +In LaTeX, we must set an explicit anchor (``\phantomsection``) for a +_`hypertarget in plain text` but not in a table or figure caption: + +.. table:: Table with _`hypertarget in table title`. + + ===== ===== ===== + False True None + ===== ===== ===== + +.. figure:: ../../../docs/user/rst/images/biohazard.png + + Figure with _`hypertarget in figure caption`. + + Legend with _`hypertarget in figure legend`. + +See `hypertarget in plain text`_, +`hypertarget in table title`_, +`hypertarget in figure caption`_, and +`hypertarget in figure legend`_, + Property changes on: trunk/docutils/test/functional/input/data/hyperlinking.txt ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native Modified: trunk/docutils/test/functional/input/standalone_rst_latex.txt =================================================================== --- trunk/docutils/test/functional/input/standalone_rst_latex.txt 2009-09-25 22:12:30 UTC (rev 6144) +++ trunk/docutils/test/functional/input/standalone_rst_latex.txt 2009-09-28 10:51:11 UTC (rev 6145) @@ -16,6 +16,7 @@ .. include:: data/nonalphanumeric.txt .. include:: data/unicode.txt .. include:: data/latex_encoding.txt +.. include:: data/hyperlinking.txt .. unusual combinations (from newlatex, for interactive testing) .. include:: data/latex.txt |