SF.net SVN: docutils:[10216 ] trunk/docutils
milde--- via Docutils-checkins <[email protected]> Wed, 20 Aug 2025 12:04:33 +0000
| Newsgroups | gmane.text.docutils.cvs |
|---|---|
| Message-ID | <[email protected]> |
Revision: 10216
http://sourceforge.net/p/docutils/code/10216
Author: milde
Date: 2025-08-20 12:04:32 +0000 (Wed, 20 Aug 2025)
Log Message:
-----------
LaTeX writer: fix anchor placement for figures, images, literal blocks, tables.
New attribute "pre_nl" for `ids_to_labels()`: prepend newline to label
definitions if there are labels.
Move anchor and label definition(s) for images, figures, literal blocks,
and tables before class wrappers and element.
Now, after activating a link to the element, it is fully visible
in the PDF viewer.
Modified Paths:
--------------
trunk/docutils/HISTORY.rst
trunk/docutils/docutils/writers/latex2e/__init__.py
trunk/docutils/test/functional/expected/latex_cornercases.tex
trunk/docutils/test/functional/expected/latex_memoir.tex
trunk/docutils/test/functional/expected/standalone_rst_latex.tex
trunk/docutils/test/functional/expected/standalone_rst_xetex.tex
trunk/docutils/test/test_writers/test_latex2e.py
Modified: trunk/docutils/HISTORY.rst
===================================================================
--- trunk/docutils/HISTORY.rst 2025-08-20 12:04:19 UTC (rev 10215)
+++ trunk/docutils/HISTORY.rst 2025-08-20 12:04:32 UTC (rev 10216)
@@ -44,6 +44,8 @@
* docutils/writers/latex2e/__init__.py
- Prepend ``\phantomsection`` to labelled math-blocks.
+ - Fix cross-reference anchor placement in figures, images,
+ literal-blocks, and tables.
Release 0.22 (2026-07-29)
Modified: trunk/docutils/docutils/writers/latex2e/__init__.py
===================================================================
--- trunk/docutils/docutils/writers/latex2e/__init__.py 2025-08-20 12:04:19 UTC (rev 10215)
+++ trunk/docutils/docutils/writers/latex2e/__init__.py 2025-08-20 12:04:32 UTC (rev 10216)
@@ -1560,19 +1560,25 @@
id for id in node['ids']))
def ids_to_labels(self, node, set_anchor=True, protect=False,
- newline=False) -> list[str]:
+ newline=False, pre_nl=False) -> list[str]:
"""Return label definitions for all ids of `node`.
If `set_anchor` is True, an anchor is set with \\phantomsection.
If `protect` is True, the \\label cmd is made robust.
If `newline` is True, a newline is added if there are labels.
+ If `pre_nl` is True, a newline is prepended if there are labels.
+
+ Provisional.
"""
prefix = '\\protect' if protect else ''
- labels = [prefix + '\\label{%s}' % id for id in node['ids']]
- if set_anchor and labels:
- labels.insert(0, '\\phantomsection')
- if newline and labels:
- labels.append('\n')
+ labels = [f'{prefix}\\label{{{id}}}' for id in node['ids']]
+ if labels:
+ if set_anchor:
+ labels.insert(0, '\\phantomsection')
+ if newline:
+ labels.append('\n')
+ if pre_nl:
+ labels.insert(0, '\n')
return labels
def set_align_from_classes(self, node) -> None:
@@ -2297,6 +2303,7 @@
def visit_figure(self, node) -> None:
self.requirements['float'] = PreambleCmds.float
+ self.out += self.ids_to_labels(node, pre_nl=True)
self.duclass_open(node)
# The 'align' attribute sets the "outer alignment",
# for "inner alignment" use LaTeX default alignment (similar to HTML)
@@ -2308,7 +2315,6 @@
self.out.append('\\begin{figure} %% align = "%s"\n' % alignment)
else:
self.out.append('\\begin{figure}\n')
- self.out += self.ids_to_labels(node, newline=True)
def depart_figure(self, node) -> None:
self.out.append('\\end{figure}\n')
@@ -2482,6 +2488,7 @@
if 'width' in attrs:
include_graphics_options.append(
f"width={self.to_latex_length(attrs['width'], node)}")
+ pre.append(''.join(self.ids_to_labels(node, newline=True)))
if not (self.is_inline(node)
or isinstance(node.parent, (nodes.figure, nodes.compound))):
pre.append('\n')
@@ -2501,7 +2508,7 @@
self.out.extend(post)
def depart_image(self, node) -> None:
- self.out += self.ids_to_labels(node, newline=True)
+ pass
def visit_inline(self, node) -> None:
# This function is also called by the visiting functions for
@@ -2623,8 +2630,8 @@
_use_listings = (literal_env == 'lstlisting') and _use_env
# Labels and classes:
+ self.out += self.ids_to_labels(node, pre_nl=True)
self.duclass_open(node)
- self.out += self.ids_to_labels(node, newline=True)
# Highlight code?
if (not _plaintext
and 'code' in node['classes']
@@ -3058,7 +3065,6 @@
self.depart_admonition(node)
def visit_table(self, node) -> None:
- self.duclass_open(node)
self.requirements['table'] = PreambleCmds.table
if not self.settings.legacy_column_widths:
self.requirements['table1'] = PreambleCmds.table_columnwidth
@@ -3090,9 +3096,9 @@
# if it has no caption/title.
# See visit_thead() for tables with caption.
if not self.active_table.caption:
- self.out.extend(self.ids_to_labels(
- node, set_anchor=len(self.table_stack) != 1,
- newline=True))
+ set_anchor = (len(self.table_stack) != 1)
+ self.out += self.ids_to_labels(node, set_anchor, pre_nl=True)
+ self.duclass_open(node)
# TODO: Don't use a longtable or add \noindent before
# the next paragraph, when in a "compound paragraph".
# Start a new line or a new paragraph?
Modified: trunk/docutils/test/functional/expected/latex_cornercases.tex
===================================================================
--- trunk/docutils/test/functional/expected/latex_cornercases.tex 2025-08-20 12:04:19 UTC (rev 10215)
+++ trunk/docutils/test/functional/expected/latex_cornercases.tex 2025-08-20 12:04:32 UTC (rev 10216)
@@ -894,8 +894,8 @@
\hline
\end{longtable}
+\phantomsection\label{figure-label}
\begin{figure}
-\phantomsection\label{figure-label}
\noindent\makebox[\linewidth][c]{\includegraphics{../../../docs/user/rst/images/biohazard.png}}
\caption{Figure with %
\label{hypertarget-in-figure-caption}hypertarget in figure caption.}
@@ -905,8 +905,8 @@
\end{DUlegend}
\end{figure}
+\phantomsection\label{image-label}
\includegraphics{../../../docs/user/rst/images/biohazard.png}
-\phantomsection\label{image-label}
See \hyperref[hypertarget-in-plain-text]{hypertarget in plain text},
\hyperref[table-label]{table label}, \hyperref[hypertarget-in-table-title]{hypertarget in table title},
Modified: trunk/docutils/test/functional/expected/latex_memoir.tex
===================================================================
--- trunk/docutils/test/functional/expected/latex_memoir.tex 2025-08-20 12:04:19 UTC (rev 10215)
+++ trunk/docutils/test/functional/expected/latex_memoir.tex 2025-08-20 12:04:32 UTC (rev 10216)
@@ -824,8 +824,8 @@
Image with multiple IDs:
+\phantomsection\label{image-target-3}\label{image-target-2}\label{image-target-1}
\includegraphics{../../../docs/user/rst/images/biohazard.png}
-\phantomsection\label{image-target-3}\label{image-target-2}\label{image-target-1}
A centered image:
Modified: trunk/docutils/test/functional/expected/standalone_rst_latex.tex
===================================================================
--- trunk/docutils/test/functional/expected/standalone_rst_latex.tex 2025-08-20 12:04:19 UTC (rev 10215)
+++ trunk/docutils/test/functional/expected/standalone_rst_latex.tex 2025-08-20 12:04:32 UTC (rev 10216)
@@ -818,8 +818,8 @@
Image with multiple IDs:
+\phantomsection\label{image-target-3}\label{image-target-2}\label{image-target-1}
\includegraphics{../../../docs/user/rst/images/biohazard.png}
-\phantomsection\label{image-target-3}\label{image-target-2}\label{image-target-1}
A centered image:
Modified: trunk/docutils/test/functional/expected/standalone_rst_xetex.tex
===================================================================
--- trunk/docutils/test/functional/expected/standalone_rst_xetex.tex 2025-08-20 12:04:19 UTC (rev 10215)
+++ trunk/docutils/test/functional/expected/standalone_rst_xetex.tex 2025-08-20 12:04:32 UTC (rev 10216)
@@ -843,8 +843,8 @@
Image with multiple IDs:
+\phantomsection\label{image-target-3}\label{image-target-2}\label{image-target-1}
\includegraphics{../../../docs/user/rst/images/biohazard.png}
-\phantomsection\label{image-target-3}\label{image-target-2}\label{image-target-1}
A centered image:
Modified: trunk/docutils/test/test_writers/test_latex2e.py
===================================================================
--- trunk/docutils/test/test_writers/test_latex2e.py 2025-08-20 12:04:19 UTC (rev 10215)
+++ trunk/docutils/test/test_writers/test_latex2e.py 2025-08-20 12:04:32 UTC (rev 10216)
@@ -133,19 +133,27 @@
["""
.. image:: larch-mini.jpg
:target: larch.jpg
+ :name: the-larch
+ :class: currently ignored
:align: center
""",
r"""
+\phantomsection\label{the-larch}
\noindent\makebox[\linewidth][c]{\href{larch.jpg}{\includegraphics{larch-mini.jpg}}}
"""],
["""\
+.. _fig:larch:
+
.. figure:: larch-mini.jpg
:target: larch.jpg
+ :name: the-larch
The larch
""",
r"""
+\phantomsection\label{fig-larch}
\begin{figure}
+\phantomsection\label{the-larch}
\noindent\makebox[\linewidth][c]{\href{larch.jpg}{\includegraphics{larch-mini.jpg}}}
\caption{The larch}
\end{figure}
@@ -327,6 +335,25 @@
\phantomsection\label{block-target}
\DUrole{custom}{\DUrole{paragraph}{Next paragraph.}}
"""],
+# literal block
+["""\
+.. class:: cls1
+.. _block1:
+
+::
+
+ 1^2_3
+""",
+r"""
+\phantomsection\label{block1}
+\begin{DUclass}{cls1}
+\begin{quote}
+\begin{alltt}
+1^2_3
+\end{alltt}
+\end{quote}
+\end{DUclass}
+"""],
# table with IDs and custom + special class values
["""\
.. class:: cls1
@@ -341,9 +368,9 @@
= =
""",
r"""
+\phantomsection\label{label2}\label{label1}
\begin{DUclass}{cls2}
\begin{DUclass}{cls1}
-\phantomsection\label{label2}\label{label1}
\begin{longtable*}{ll}
Y & N \\
\end{longtable*}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.