SF.net SVN: docutils:[10017 ] trunk/docutils

milde--- via Docutils-checkins <[email protected]> Thu, 06 Mar 2025 08:41:12 +0000
Newsgroups gmane.text.docutils.cvs
Message-ID <[email protected]>
Revision: 10017
          http://sourceforge.net/p/docutils/code/10017
Author:   milde
Date:     2025-03-06 08:41:10 +0000 (Thu, 06 Mar 2025)
Log Message:
-----------
Fix LaTeX docinfo handling of affiliation fields preceding author field.

With "use_latex_docinfo", the content of the bibliographic fields
"address", "contact", and "organization" is attached to the author name.

Reserve the first position for the author name instead of creating an
"author info" list without author if any of these fields appeares before
an "author" or "authors" field.

Modified Paths:
--------------
    trunk/docutils/HISTORY.rst
    trunk/docutils/docs/ref/doctree.rst
    trunk/docutils/docs/ref/rst/restructuredtext.rst
    trunk/docutils/docutils/writers/latex2e/__init__.py
    trunk/docutils/test/test_writers/test_latex2e_parts.py

Modified: trunk/docutils/HISTORY.rst
===================================================================
--- trunk/docutils/HISTORY.rst	2025-03-06 08:40:49 UTC (rev 10016)
+++ trunk/docutils/HISTORY.rst	2025-03-06 08:41:10 UTC (rev 10017)
@@ -189,6 +189,8 @@
     and`LaTeXTranslator.fallbacks`.
   - Use <document> "title" attribute in pdfinfo.
   - Encode <meta> element content in pdfinfo.
+  - Improve docinfo handling with "use_latex_docinfo".
+  - `LaTeXTranslator.pop_output_collector() now returns the popped list.
 
   .. _reference-label: docs/user/config.html#reference-label
   __ docs/user/config.html#stylesheet-latex-writers

Modified: trunk/docutils/docs/ref/doctree.rst
===================================================================
--- trunk/docutils/docs/ref/doctree.rst	2025-03-06 08:40:49 UTC (rev 10016)
+++ trunk/docutils/docs/ref/doctree.rst	2025-03-06 08:41:10 UTC (rev 10017)
@@ -611,7 +611,7 @@
 Examples
 --------
 
-In reStructuredText, "authors" is one of the registered
+In reStructuredText, the `"authors" field`_ is one of the registered
 `bibliographic fields`_::
 
     Document Title
@@ -631,10 +631,8 @@
                 <author>
                     Jane Doe
 
-In reStructuredText, multiple author's names are separated with
-semicolons (";") or commas (","); semicolons take precedence.
-There is currently no way to represent the author's organization,
-address, or contact in a reStructuredText "Authors" field.
+There is currently no way to represent an individual author's <organization>,
+<address>, or <contact> in a reStructuredText `"authors" field`_.
 
 See `\<docinfo>`_ for a more complete example, including processing
 context.
@@ -5221,6 +5219,7 @@
 .. _auto-symbol:            rst/restructuredtext.html#auto-symbol-footnotes
 .. _bibliographic data:
 .. _bibliographic fields:   rst/restructuredtext.html#bibliographic-fields
+.. _"authors" field:        rst/restructuredtext.html#authors
 .. _block quote:            rst/restructuredtext.html#block-quotes
 .. _bullet list:            rst/restructuredtext.html#bullet-lists
 .. _CSS3 length units:      rst/restructuredtext.html#length-units

Modified: trunk/docutils/docs/ref/rst/restructuredtext.rst
===================================================================
--- trunk/docutils/docs/ref/rst/restructuredtext.rst	2025-03-06 08:40:49 UTC (rev 10016)
+++ trunk/docutils/docs/ref/rst/restructuredtext.rst	2025-03-06 08:41:10 UTC (rev 10017)
@@ -1003,12 +1003,12 @@
   ===================  ================
 
 .. compound::
-   The "Authors" field may contain
+   The "_`Authors`" field may contain
 
    * a single paragraph consisting of a list of authors, separated by
      ``;`` or ``,`` (``;`` is checked first, so ``Doe, Jane; Doe,
-     John`` will work.) [#i18n]_
-   * multiple paragraphs (one per author) or
+     John`` will work), [#i18n]_
+   * multiple paragraphs (one per author), or
    * a bullet list whose elements each contain a single paragraph per author.
 
    In some languages (e.g. Swedish), there is no singular/plural distinction
@@ -1017,6 +1017,11 @@
    contains a comma, end it with a semicolon to disambiguate:
    ``:Författare: Doe, Jane;``.
 
+   There is currently no way to represent an individual author's
+   organization or contact info in a reStructuredText "Authors" field.
+   However, you may use an "Author" field followed by
+   "Organization", "Address", and/or "Contact" for each author.
+
 The "Address" field is for a multi-line surface mailing address.
 Newlines and whitespace will be preserved.
 

Modified: trunk/docutils/docutils/writers/latex2e/__init__.py
===================================================================
--- trunk/docutils/docutils/writers/latex2e/__init__.py	2025-03-06 08:40:49 UTC (rev 10016)
+++ trunk/docutils/docutils/writers/latex2e/__init__.py	2025-03-06 08:41:10 UTC (rev 10017)
@@ -1193,6 +1193,10 @@
     literal = False                     # literal text (block or inline)
     alltt = False                       # inside `alltt` environment
 
+    # Nodes affected by "use_latex_docinfo" setting:
+    LATEX_DOCINFO_NODES = (nodes.address, nodes.author, nodes.contact,
+                           nodes.date, nodes.organization)
+
     def __init__(self, document, babel_class=Babel) -> None:
         super().__init__(document)
         # Reporter
@@ -1298,9 +1302,8 @@
         # Title metadata:
         self.title_labels = []
         self.subtitle_labels = []
-        # (if use_latex_docinfo: collects lists of
-        # author/organization/contact/address lines)
-        self.author_stack = []
+        # with "use_latex_docinfo", we also need
+        self.author_stack = [['']]  # first item reserved for author name
         self.date = []
 
         # PDF properties:
@@ -1636,12 +1639,14 @@
                     self.fallbacks['DUclass'] = PreambleCmds.duclass
                 self.out.append('\\end{DUclass}\n')
 
-    def push_output_collector(self, new_out) -> None:
+    def push_output_collector(self, new_out: list) -> None:
         self.out_stack.append(self.out)
         self.out = new_out
 
-    def pop_output_collector(self) -> None:
+    def pop_output_collector(self) -> list:
+        old_out = self.out
         self.out = self.out_stack.pop()
+        return old_out
 
     def term_postfix(self, node):
         """
@@ -1957,9 +1962,8 @@
                           DeprecationWarning, stacklevel=2)
         if isinstance(node, nodes.address):
             self.insert_newline = True  # preserve newlines
-        if self.use_latex_docinfo and isinstance(
-               node, (nodes.address, nodes.author, nodes.contact,
-                      nodes.date, nodes.organization)):
+        if self.use_latex_docinfo and isinstance(node,
+                                                 self.LATEX_DOCINFO_NODES):
             self.push_output_collector([])  # see depart_docinfo_item()
         else:
             label = self.language_label(node.tagname)
@@ -1973,19 +1977,21 @@
 
     def depart_docinfo_item(self, node) -> None:
         self.insert_newline = False  # reset change with <address> node
-        if self.use_latex_docinfo and isinstance(
-               node, (nodes.address, nodes.author, nodes.contact,
-                      nodes.date, nodes.organization)):
-            text = ''.join(self.out)
-            self.pop_output_collector()
+        if self.use_latex_docinfo and isinstance(node,
+                                                 self.LATEX_DOCINFO_NODES):
+            # Collect date and author info for use in `self.make_title()`:
+            text = ''.join(self.pop_output_collector())
             if isinstance(node, nodes.date):
                 self.date.append(text)
+            elif isinstance(node, nodes.author):
+                # Insert author name as first item of an "author info" list.
+                # If author name already set, start a new list.
+                if self.author_stack[-1][0]:
+                    self.author_stack.append([text])
+                else:
+                    self.author_stack[-1][0] = text
             else:
-                # Attach to the last author.  If any of them precedes
-                # the first author, put them in a separate "author" group
-                # (in lack of better semantics).
-                if isinstance(node, nodes.author) or not self.author_stack:
-                    self.author_stack.append([])
+                # Append affiliation/contact info to current "author info".
                 self.author_stack[-1].append(text)
         else:
             if isinstance(node, nodes.address):
@@ -2023,8 +2029,7 @@
         if self.pdfinfo:
             self.pdfsetup += [r'\hypersetup{'] + self.pdfinfo + ['}']
         # * title (including author(s) and date if using "latex_docinfo")
-        if self.title or (self.use_latex_docinfo
-                          and (self.author_stack or self.date)):
+        if self.title or self.date or self.author_stack != [['']]:
             self.make_title()  # see below
         # * bibliography
         if self._bibitems:
@@ -2042,11 +2047,12 @@
     def make_title(self) -> None:
         # Auxiliary function called by `self.depart_document()`.
         #
-        # Append ``\title``, ``\author``, and ``\date`` to "titledata".
-        # (We need all three, even if empty, to prevent errors
-        # and/or automatic display of the current date by \maketitle.)
-        # Append ``\maketitle`` to "body_pre_docinfo" parts.
-        #
+        # The document title is stored in the "titledata" document part.
+        # Date and author info is included with "use_latex_docinfo".
+        # However, we need the ``\title``, ``\author``, and ``\date``
+        # macros even if empty, to prevent errors and/or automatic
+        # display of the current date by ``\maketitle``.
+
         # \title
         title_arg = [''.join(self.title)]  # ensure len == 1
         if self.title:
@@ -2057,15 +2063,16 @@
                           ] + self.subtitle_labels
         self.titledata.append(r'\title{%s}' % '%\n  '.join(title_arg))
         # \author
-        author_arg = ['\\\\\n'.join(author_entry)
-                      for author_entry in self.author_stack]
-        self.titledata.append(r'\author{%s}' %
-                              ' \\and\n'.join(author_arg))
+        # author name(s) and optional affiliation and contact info
+        # cf. https://tex.stackexchange.com/a/377030/288060.
+        authors = ['\\\\\n'.join((field for field in author_entry if field))
+                   for author_entry in self.author_stack]
+        self.titledata.append(r'\author{%s}' % ' \\and\n'.join(authors))
         # \date
         self.titledata.append(r'\date{%s}' % ', '.join(self.date))
         # \maketitle
-        # Must be in the document body. We add it to `body_pre_docinfo`
-        # to allow templates to put `titledata` into the document preamble.
+        # Must be in the document body.  Append to "body_pre_docinfo" part
+        # so templates may use the "titledata" part in the document preamble.
         self.body_pre_docinfo.append('\\maketitle\n')
 
     def append_bibliogaphy(self) -> None:

Modified: trunk/docutils/test/test_writers/test_latex2e_parts.py
===================================================================
--- trunk/docutils/test/test_writers/test_latex2e_parts.py	2025-03-06 08:40:49 UTC (rev 10016)
+++ trunk/docutils/test/test_writers/test_latex2e_parts.py	2025-03-06 08:41:10 UTC (rev 10017)
@@ -687,7 +687,6 @@
 \date{}
 """
   }],
-
 # template
 ["""\
 """,
@@ -694,7 +693,46 @@
  {'body': '',
   'requirements': '\\usepackage[T1]{fontenc}\n'
   }],
+# bibliographic fields
+["""
+:contact: here@home
+:organization: Example & Cie.
+:author:  Mr. Smith
+:date:    yesterday
+:address: 0231 Abendglanz
+          Milky Way 23 b
+""",
+ {'requirements': '\\usepackage[T1]{fontenc}\n'
+                  '\\usepackage{tabularx}\n',
+  'fallbacks': r"""
+% Provide a length variable and set default, if it is new
+\providecommand*{\DUprovidelength}[2]{%
+  \ifdefined#1
+  \else
+    \newlength{#1}\setlength{#1}{#2}%
+  \fi
+}
 
+% width of docinfo table
+\DUprovidelength{\DUdocinfowidth}{0.9\linewidth}
+""",
+  'pdfsetup': DEFAULT_PARTS['pdfsetup']
+  + '\\hypersetup{\n  pdfauthor={Mr. Smith}\n}\n',
+  'docinfo': r"""
+% Docinfo
+\begin{center}
+\begin{tabularx}{\DUdocinfowidth}{lX}
+\textbf{Contact}: & \href{mailto:here@home}{here@home} \\
+\textbf{Organization}: & Example \& Cie. \\
+\textbf{Author}: & Mr. Smith \\
+\textbf{Date}: & yesterday \\
+\textbf{Address}: & {\raggedright
+0231 Abendglanz\\
+Milky Way 23 b} \\
+\end{tabularx}
+\end{center}
+""",
+  }],
 ])
 
 samples['book'] = ({'documentclass': 'book'}, [
@@ -942,7 +980,60 @@
   }],
 ])
 
+samples['LaTeX docinfo'] = ({'use_latex_docinfo': True}, [
+# bibliographic fields
+["""
+:contact: here@home
+:organization: Example & Cie.
+:author:  Mr. Smith
+:date:    yesterday
+:address: 0231 Abendglanz
+          Milky Way 23 b
+""",
+ {'pdfsetup': DEFAULT_PARTS['pdfsetup']
+  + '\\hypersetup{\n  pdfauthor={Mr. Smith}\n}\n',
+  'titledata': r"""\title{}
+\author{Mr. Smith\\
+\href{mailto:here@home}{here@home}\\
+Example \& Cie.\\
+0231 Abendglanz\\
+Milky Way 23 b}
+\date{yesterday}
+""",
+  'body_pre_docinfo': '\\maketitle\n',
+  }],
+# bibliographic fields
+["""
+:keywords: custom, docinfo, field
+""",
+ {'requirements': '\\usepackage[T1]{fontenc}\n'
+                  '\\usepackage{tabularx}\n',
+  'fallbacks': r"""
+% Provide a length variable and set default, if it is new
+\providecommand*{\DUprovidelength}[2]{%
+  \ifdefined#1
+  \else
+    \newlength{#1}\setlength{#1}{#2}%
+  \fi
+}
 
+% width of docinfo table
+\DUprovidelength{\DUdocinfowidth}{0.9\linewidth}
+""",
+  'docinfo': r"""
+% Docinfo
+\begin{center}
+\begin{tabularx}{\DUdocinfowidth}{lX}
+\textbf{keywords}: &
+custom, docinfo, field
+\\
+\end{tabularx}
+\end{center}
+""",
+  }],
+])
+
+
 samples['embed_stylesheet'] = ({'stylesheet_path': f'{spam},{ham}',
                                 'embed_stylesheet': True,
                                 'warning_stream': ''}, [

This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.



_______________________________________________
Docutils-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/docutils-checkins