Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Latex: fix vertical spacing for cpp:function. #10087

Merged
merged 3 commits into from Feb 14, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
93 changes: 58 additions & 35 deletions sphinx/texinputs/sphinxlatexobjects.sty
@@ -1,7 +1,7 @@
%% MODULE RELEASE DATA AND OBJECT DESCRIPTIONS
%
% change this info string if making any custom modification
\ProvidesFile{sphinxlatexobjects.sty}[2021/12/05 documentation environments]
\ProvidesFile{sphinxlatexobjects.sty}[2022/01/13 documentation environments]

% Provides support for this output mark-up from Sphinx latex writer:
%
Expand Down Expand Up @@ -77,56 +77,79 @@

% Signatures, possibly multi-line
%
% For legacy reasons Sphinx uses LaTeX \list and \item's for signatures
% This is delicate:
% - the actual item label is not typeset immediately by \item but later as part
% of the \everypar which will be triggered by either next paragraph or a manual
% \leavevmode, or if nothing in-between by the next \item,
% - \begingroup <set-up>\item[foo] <setup>\endgroup leads to errors,
% - vertical space depends on \parskip and \itemsep values in somewhat
% subtle manners.
%
% Since the 2022/01/13 version things are simpler as \parskip is simply set
% to zero during execution of \pysigline/\pysiglinewithargsret
%
% Parameter for separation via \itemsep of multiple signatures with common desc
\newlength\sphinxsignaturesep
\setlength\sphinxsignaturesep{\smallskipamount}
marxin marked this conversation as resolved.
Show resolved Hide resolved
% latex.py outputs mark-up like this:
% \pysigstartsignatures <signatures> \pysigstopsignatures <actual desc>
\newcommand{\pysigstartsignatures}{%
% store current \parskip and \itemsep
\edef\pysig@restore@itemsep@and@parskip{%
\itemsep\the\itemsep\relax
\parskip\the\parskip\relax
}%
% set them to control the spacing between signatures sharing common desc
\parskip\z@skip
\itemsep\sphinxsignaturesep
}
\newcommand{\pysigstopsignatures}{%
\leavevmode
% it is important \leavevmode was issued before the \parskip reset, and
% it is also needed for the case of an object desc itself a LaTeX \list
% now restore \itemsep and \parskip
\pysig@restore@itemsep@and@parskip
}
%
% Use a \parbox to accomodate long argument list in signatures
% LaTeX did not imagine that an \item label could need multi-line rendering
\newlength{\py@argswidth}
\newcommand{\py@sigparams}[2]{%
% The \py@argswidth has been computed in \pysiglinewithargsret to make this
% occupy full available width on line.
% The \py@argswidth has been computed in \pysiglinewithargsret to make the
% argument list use full available width
\parbox[t]{\py@argswidth}{\raggedright #1\sphinxcode{)}#2\strut}%
% final strut is to help get correct vertical separation in case of multi-line
% box with the item contents.
% final strut is to help get correct vertical separation
}
\newcommand{\pysigline}[1]{%
% the \py@argswidth is available we use it despite its name (no "args" here)
% the \relax\relax is because \py@argswidth is a "skip" variable and the first
% \relax only ends its "dimen" part
% as \py@argswidth is available, we use it but no "args" here
% the \relax\relax is because \py@argswidth is a "skip" variable
% this will make the label occupy the full available linewidth
\py@argswidth=\dimexpr\linewidth+\labelwidth\relax\relax
\item[{\parbox[t]{\py@argswidth}{\raggedright #1\strut}}]
\futurelet\sphinx@token\pysigline@preparevspace@i
\pysigadjustitemsep
}
\newcommand{\pysiglinewithargsret}[3]{%
\settowidth{\py@argswidth}{#1\sphinxcode{(}}%
\py@argswidth=\dimexpr\linewidth+\labelwidth-\py@argswidth\relax\relax
\item[{#1\sphinxcode{(}\py@sigparams{#2}{#3}\strut}]
\futurelet\sphinx@token\pysigline@preparevspace@i
\pysigadjustitemsep
}
\def\pysigline@preparevspace@i{%
\ifx\sphinx@token\@sptoken
\expandafter\pysigline@preparevspace@again
\else\expandafter\pysigline@preparevspace@ii
\fi
}
\@firstofone{\def\pysigline@preparevspace@again} {\futurelet\sphinx@token\pysigline@preparevspace@i}
\long\def\pysigline@preparevspace@ii#1{%
\ifx\sphinx@token\bgroup\expandafter\@firstoftwo
\newcommand{\pysigadjustitemsep}{%
% adjust \itemsep to control the separation with the next signature
% sharing common description
\ifsphinxsigismultiline
% inside a multiline signature, no extra vertical spacing
% ("multiline" here does not refer to possibly long
% list of arguments, but to a cpp domain feature)
\itemsep\z@skip
\else
\ifx\sphinx@token\phantomsection
\else
% this strange incantation is because at its root LaTeX in fact did not
% imagine a multi-line label, it is always wrapped in a horizontal box at core
% LaTeX level and we have to find tricks to get correct interline distances.
% It interacts badly with a follow-up \phantomsection hence the test above
\leavevmode\par\nobreak\vskip-\parskip\prevdepth\dp\strutbox
\fi
\expandafter\@secondoftwo
\itemsep\sphinxsignaturesep
\fi
{{#1}}{#1}%
}
\newcommand{\pysigstartmultiline}{%
\def\pysigstartmultiline{\vskip\smallskipamount\parskip\z@skip\itemsep\z@skip}%
\edef\pysigstopmultiline
{\noexpand\leavevmode\parskip\the\parskip\relax\itemsep\the\itemsep\relax}%
\parskip\z@skip\itemsep\z@skip
}
\newif\ifsphinxsigismultiline
\newcommand{\pysigstartmultiline}{\sphinxsigismultilinetrue}%
\newcommand{\pysigstopmultiline}{\sphinxsigismultilinefalse\itemsep\sphinxsignaturesep}%

% Production lists
%
Expand Down
21 changes: 14 additions & 7 deletions sphinx/writers/latex.py
Expand Up @@ -304,6 +304,7 @@ def __init__(self, document: nodes.document, builder: "LaTeXBuilder",
self.in_parsed_literal = 0
self.compact_list = 0
self.first_param = 0
self.in_desc_signature = False

sphinxpkgoptions = []

Expand Down Expand Up @@ -715,6 +716,9 @@ def visit_desc(self, node: Element) -> None:
self.table.has_problematic = True

def depart_desc(self, node: Element) -> None:
if self.in_desc_signature:
self.body.append(CR + r'\pysigstopsignatures')
self.in_desc_signature = False
if self.config.latex_show_urls == 'footnote':
self.body.append(CR + r'\end{fulllineitems}\end{savenotes}' + BLANKLINE)
else:
Expand All @@ -723,10 +727,10 @@ def depart_desc(self, node: Element) -> None:
def _visit_signature_line(self, node: Element) -> None:
for child in node:
if isinstance(child, addnodes.desc_parameterlist):
self.body.append(r'\pysiglinewithargsret{')
self.body.append(CR + r'\pysiglinewithargsret{')
break
else:
self.body.append(r'\pysigline{')
self.body.append(CR + r'\pysigline{')

def _depart_signature_line(self, node: Element) -> None:
self.body.append('}')
Expand All @@ -737,18 +741,19 @@ def visit_desc_signature(self, node: Element) -> None:
else:
hyper = ''
self.body.append(hyper)
if not self.in_desc_signature:
self.in_desc_signature = True
self.body.append(CR + r'\pysigstartsignatures')
if not node.get('is_multiline'):
self._visit_signature_line(node)
else:
self.body.append('%' + CR)
self.body.append(r'\pysigstartmultiline' + CR)
self.body.append(CR + r'\pysigstartmultiline')

def depart_desc_signature(self, node: Element) -> None:
if not node.get('is_multiline'):
self._depart_signature_line(node)
else:
self.body.append('%' + CR)
self.body.append(r'\pysigstopmultiline')
self.body.append(CR + r'\pysigstopmultiline')

def visit_desc_signature_line(self, node: Element) -> None:
self._visit_signature_line(node)
Expand All @@ -757,7 +762,9 @@ def depart_desc_signature_line(self, node: Element) -> None:
self._depart_signature_line(node)

def visit_desc_content(self, node: Element) -> None:
pass
assert self.in_desc_signature
self.body.append(CR + r'\pysigstopsignatures')
self.in_desc_signature = False

def depart_desc_content(self, node: Element) -> None:
pass
Expand Down