Currently, if one converts an input like the following into LaTeX:
This line prevents the field list from being treated as docinfo.
:field name:
- List item 1
- List item 2
then the text in the final rendered PDF will look like:
This line prevents the field list from being treated as docinfo. field name: • List item 1 • List item 2
This is ugly & undesirable, and it can be fixed by inserting \leavevmode
after the field name — as is already done for definition lists — thereby causing the rendered text to instead look like:
This line prevents the field list from being treated as docinfo. field name: • List item 1 • List item 2
The attached patch causes the LaTeX & XeTeX writers to add \leavevmode
after each field name in non-docinfo field lists.
Thank you for the analysis and patch.
For a cleaner LaTeX source, it would be an added bonus, if the
\leavevmode
would only be added if required. The latex writer has an example invisit_table()
where a test withisinstance()
is done before inserting. (While adding such a test indepart_term()
is a TODO item. Maybe there are further instances where \leavevmode is required - then an auxiliary function to insert it given the right conditions may be best.)I've written a new patch that makes both
depart_field_name()
anddepart_term()
only insert\leavevmode
if necessary. The method for determining whether an insertion is necessary is described in the comments. Which constructs require\leavevmode
was determined by typesetting all possible field body constructs in LaTeX and seeing which ones were wonky in a way that could be fixed with\leavevmode
; the reStructuredText source used for that was then converted into the new testsleavevmode_deflist.txt
andleavevmode_fieldlist.txt
, so if you're wondering if a given\leavevmode
is necessary, you can fiddle with the corresponding.tex
files and see the results.Thank you for the updated patch with the comprehensive test document.
I believe, the actual fix can and should be made much simpler:
your research showed, that almost all block-level elements require the
\leavevmode
safeguard. Exceptions are "paragraph" and "math-block" (did I miss something)?Images and Tables are block-level elements in Docutils (exception: inline-images via substitution). Therefore we want them rendered a such and
\leavevmode
is required (no matter whether alignment is defined or not).The Docutils document model requires a block-level element as field body (see doctuisl.dtd).
From previous experience, we know that an unnecessary
\leavevmode
does no harm to the output, so a false positive test is tolerable (especially for seldom used combinations).IMV, a simple test whether the next node is paragraph or math-block should suffice. If skipping nodes like comment, footnote, citation, substitution-reference, ... and testing the next node can be implemented in just a few lines, we might add this but this is actually not necessary. "Compound" elements are rarely used, so IMV don't need a special handling.
Attached: patch, round 3. This just tests whether the next node is a paragraph or math block after skipping invisible nodes.
Thank you for the new patch. I tested, streamlined the implementation, added a fix for images and
came up with the attached. Please check if this looks and work as you want it.
This misses the new tests, which I would prefer to be "minimalized" and merged to either one new functional test or added to latex-cornercases. (The aim is to keep running time low while testing the presence/absence of "leavevmode" where it is important.)
I am unable to successfully apply the new patch. What Subversion revision was it created against?
On 2021-01-12, John Thorvald Wodder II via Docutils-develop wrote in gmane.text.docutils.devel:
Sorry for the inconvenience. It was against "Small fixes." from
08.01.2021, done from my git-svn checkout.
A patch against the status as of today 2021-01-14 is below.
Günter
From 1651b802181cc82f3618a8e9d66bc57c30a3bad6 Mon Sep 17 00:00:00 2001
From: milde milde@users.sf.net
Date: Thu, 7 Jan 2021 13:12:06 +0100
Subject: [PATCH] latex-writer: add \leavevmode after term or field name if required.
docutils/docutils/writers/latex2e/init.py | 32 ++++++++++++++++++++++++++++----
docutils/test/functional/expected/latex_cornercases.tex | 4 ++--
docutils/test/functional/expected/latex_memoir.tex | 20 ++++++++++----------
docutils/test/functional/expected/standalone_rst_latex.tex | 20 ++++++++++----------
docutils/test/functional/expected/standalone_rst_xetex.tex | 20 ++++++++++----------
5 files changed, 60 insertions(+), 36 deletions(-)
diff --git a/docutils/docutils/writers/latex2e/init.py b/docutils/docutils/writers/latex2e/init.py
index 1556d10..e104fa8 100644
--- a/docutils/docutils/writers/latex2e/init.py
+++ b/docutils/docutils/writers/latex2e/init.py
@@ -1577,4 +1577,25 @@ class LaTeXTranslator(nodes.NodeVisitor):
def pop_output_collector(self):
self.out = self.out_stack.pop()
+
+ def term_postfix(self, node):
+ """
+ Return LaTeX code required between term or field name and content.
+
+ In a LaTeX "description" environment (used for definition
+ lists and non-docinfo field lists), a
\\leavevmode
+ between an item's label and content ensures the correct
+ placement of certain block constructs.
+ Images need an additional newline.
+ """
+ visible_children = [child for child in node
+ if not isinstance(child, nodes.Invisible)]
+ if not visible_children:
+ return ''
+ if isinstance(visible_children[0], nodes.image):
+ return '\leavevmode\n'
+ if not isinstance(visible_children[0],
+ (nodes.paragraph, nodes.math_block)):
+ return r'\leavevmode'
+ return ''
@@ -2131,5 +2152,5 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.out.append(self.term_postfix(node))
def depart_field_body(self, node):
@@ -2971,7 +2992,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
def depart_term(self, node):
- # \leavevmode results in a line break if the
- # term is followed by an item list.
- self.out.append('}] \leavevmode ')
+ self.out.append('}] ')
+ # Do we need a \leavevmode (line break if the field body begins
+ # with a list or environment)?
+ next_node = node.next_node(descend=False, siblings=True)
+ if not isinstance(next_node, nodes.classifier):
+ self.out.append(self.term_postfix(next_node))
def visit_tgroup(self, node):
diff --git a/docutils/test/functional/expected/latex_cornercases.tex b/docutils/test/functional/expected/latex_cornercases.tex
index bc9ef36..5621bb1 100644
--- a/docutils/test/functional/expected/latex_cornercases.tex
+++ b/docutils/test/functional/expected/latex_cornercases.tex
@@ -438,5 +438,5 @@ cell 1, 2
\begin{description}
-\item[{definition:}] \leavevmode
+\item[{definition:}]
list
@@ -491,5 +491,5 @@ cell 1, 2
\begin{description}
-\item[{definition:}] \leavevmode
+\item[{definition:}]
list
diff --git a/docutils/test/functional/expected/latex_memoir.tex b/docutils/test/functional/expected/latex_memoir.tex
index a8da5e0..d5057a0 100644
--- a/docutils/test/functional/expected/latex_memoir.tex
+++ b/docutils/test/functional/expected/latex_memoir.tex
@@ -465,16 +465,16 @@ Paragraph 2 of item 2.
\begin{description}
-\item[{Term}] \leavevmode
+\item[{Term}]
Definition
-\item[{Term}] \leavevmode (\textbf{classifier})
+\item[{Term}] (\textbf{classifier})
Definition paragraph 1.
Definition paragraph 2.
-\item[{Term}] \leavevmode
+\item[{Term}]
Definition
-\item[{Term}] \leavevmode (\textbf{classifier one})(\textbf{classifier two})
+\item[{Term}] (\textbf{classifier one})(\textbf{classifier two})
Definition
@@ -1375,5 +1375,5 @@ list,
a paragraph,
\begin{description}
-\item[{a definition}] \leavevmode
+\item[{a definition}]
list,
@@ -1841,5 +1841,5 @@ physical system changes in time.
\begin{description}
-\item[{Math-Accents:}] \leavevmode
+\item[{Math-Accents:}] \leavevmode
\setlength{\DUtablewidth}{\linewidth}%
\begin{longtable*}{p{0.315\DUtablewidth}p{0.315\DUtablewidth}p{0.315\DUtablewidth}}
@@ -2189,5 +2189,5 @@ is contained in a quote
\begin{description}
-\item[{In a definition list:}] \leavevmode
+\item[{In a definition list:}] \leavevmode
\begin{DUoptionlist}
\item[-{}-help] show help
@@ -2647,8 +2647,8 @@ Compare the items in the following lists:
\begin{description}
-\item[{simple}] \leavevmode
+\item[{simple}]
description term
-\item[{{[}bracketed{]}}] \leavevmode
+\item[{{[}bracketed{]}}]
description term
@@ -2720,5 +2720,5 @@ Long URLs should be wrapped in the PDF. This can be achieved with the
\begin{description}
-\item[{Example:}] \leavevmode
+\item[{Example:}]
a long URL that should wrap in the output
\url{http://docutils.sourceforge.net/docs/user/latex.html#id79}
diff --git a/docutils/test/functional/expected/standalone_rst_latex.tex b/docutils/test/functional/expected/standalone_rst_latex.tex
index bc0098e..efb8d8a 100644
--- a/docutils/test/functional/expected/standalone_rst_latex.tex
+++ b/docutils/test/functional/expected/standalone_rst_latex.tex
@@ -469,16 +469,16 @@ Paragraph 2 of item 2.
\begin{description}
-\item[{Term}] \leavevmode
+\item[{Term}]
Definition
-\item[{Term}] \leavevmode (\textbf{classifier})
+\item[{Term}] (\textbf{classifier})
Definition paragraph 1.
Definition paragraph 2.
-\item[{Term}] \leavevmode
+\item[{Term}]
Definition
-\item[{Term}] \leavevmode (\textbf{classifier one})(\textbf{classifier two})
+\item[{Term}] (\textbf{classifier one})(\textbf{classifier two})
Definition
@@ -1379,5 +1379,5 @@ list,
a paragraph,
\begin{description}
-\item[{a definition}] \leavevmode
+\item[{a definition}]
list,
@@ -1845,5 +1845,5 @@ physical system changes in time.
\begin{description}
-\item[{Math-Accents:}] \leavevmode
+\item[{Math-Accents:}] \leavevmode
\setlength{\DUtablewidth}{\linewidth}%
\begin{longtable*}{p{0.315\DUtablewidth}p{0.315\DUtablewidth}p{0.315\DUtablewidth}}
@@ -2193,5 +2193,5 @@ is contained in a quote
\begin{description}
-\item[{In a definition list:}] \leavevmode
+\item[{In a definition list:}] \leavevmode
\begin{DUoptionlist}
\item[-{}-help] show help
@@ -2651,8 +2651,8 @@ Compare the items in the following lists:
\begin{description}
-\item[{simple}] \leavevmode
+\item[{simple}]
description term
-\item[{{[}bracketed{]}}] \leavevmode
+\item[{{[}bracketed{]}}]
description term
@@ -2724,5 +2724,5 @@ Long URLs should be wrapped in the PDF. This can be achieved with the
\begin{description}
-\item[{Example:}] \leavevmode
+\item[{Example:}]
a long URL that should wrap in the output
\url{http://docutils.sourceforge.net/docs/user/latex.html#id79}
diff --git a/docutils/test/functional/expected/standalone_rst_xetex.tex b/docutils/test/functional/expected/standalone_rst_xetex.tex
index 8150e44..a677b67 100644
--- a/docutils/test/functional/expected/standalone_rst_xetex.tex
+++ b/docutils/test/functional/expected/standalone_rst_xetex.tex
@@ -328,16 +328,16 @@ Paragraph 2 of item 2.
\begin{description}
-\item[{Term}] \leavevmode
+\item[{Term}]
Definition
-\item[{Term}] \leavevmode (\textbf{classifier})
+\item[{Term}] (\textbf{classifier})
Definition paragraph 1.
Definition paragraph 2.
-\item[{Term}] \leavevmode
+\item[{Term}]
Definition
-\item[{Term}] \leavevmode (\textbf{classifier one})(\textbf{classifier two})
+\item[{Term}] (\textbf{classifier one})(\textbf{classifier two})
Definition
@@ -1262,5 +1262,5 @@ list,
a paragraph,
\begin{description}
-\item[{a definition}] \leavevmode
+\item[{a definition}]
list,
@@ -1729,5 +1729,5 @@ physical system changes in time.
\begin{description}
-\item[{Math-Accents:}] \leavevmode
+\item[{Math-Accents:}] \leavevmode
\setlength{\DUtablewidth}{\linewidth}%
\begin{longtable*}{p{0.315\DUtablewidth}p{0.315\DUtablewidth}p{0.315\DUtablewidth}}
@@ -2077,5 +2077,5 @@ is contained in a quote
\begin{description}
-\item[{In a definition list:}] \leavevmode
+\item[{In a definition list:}] \leavevmode
\begin{DUoptionlist}
\item[--help] show help
@@ -2535,8 +2535,8 @@ Compare the items in the following lists:
\begin{description}
-\item[{simple}] \leavevmode
+\item[{simple}]
description term
-\item[{{[}bracketed{]}}] \leavevmode
+\item[{{[}bracketed{]}}]
description term
@@ -2608,5 +2608,5 @@ Long URLs should be wrapped in the PDF. This can be achieved with the
\begin{description}
-\item[{Example:}] \leavevmode
+\item[{Example:}]
a long URL that should wrap in the output
\url{http://docutils.sourceforge.net/docs/user/latex.html#id79}
--
libgit2 0.27.7
OK, I finally got around to writing a minimal test case for
\leavevmode
insertion. I also made a small change to the code so that\leavevmode
won't be inserted in docinfo fields. I hope that this patch is satisfactory and that this issue can finally be closed.A modified version of the patch is comitted in r8626.
The test is now an intermediate between the comprehensive and short versions,
some additional tweaks were done for ambiguous cases (footnotes, targets, compound).
Please check if this is what you want.
Thanks again for your work.
Yes, this is just fine.
Fixed in Docutils 0.17.
Many thanks for your patience and your contribution.