diff --git a/sphinx/templates/latex/tabular.tex_t b/sphinx/templates/latex/tabular.tex_t index 62af2ffa8..3fd347e53 100644 --- a/sphinx/templates/latex/tabular.tex_t +++ b/sphinx/templates/latex/tabular.tex_t @@ -11,8 +11,9 @@ \centering <%- endif %> <% if table.caption -%> -\begin{threeparttable} -\capstart\caption{<%= ''.join(table.caption) %>}<%= labels %> +\sphinxcapstartof{table} +\sphinxcaption{<%= ''.join(table.caption) %>}<%= labels %> +\sphinxaftercaption <% endif -%> \begin{tabular}[t]<%= table.get_colspec() -%> \hline @@ -22,8 +23,5 @@ <%- endif -%> <%=- ''.join(table.body) %> \end{tabular} -<%- if table.caption %> -\end{threeparttable} -<%- endif %> \par \sphinxattableend\end{savenotes} diff --git a/sphinx/templates/latex/tabulary.tex_t b/sphinx/templates/latex/tabulary.tex_t index c51d53396..16d15192b 100644 --- a/sphinx/templates/latex/tabulary.tex_t +++ b/sphinx/templates/latex/tabulary.tex_t @@ -11,8 +11,9 @@ \centering <%- endif %> <% if table.caption -%> -\begin{threeparttable} -\capstart\caption{<%= ''.join(table.caption) %>}<%= labels %> +\sphinxcapstartof{table} +\sphinxcaption{<%= ''.join(table.caption) %>}<%= labels %> +\sphinxaftercaption <% endif -%> \begin{tabulary}{\linewidth}[t]<%= table.get_colspec() -%> \hline @@ -22,8 +23,5 @@ <%- endif -%> <%=- ''.join(table.body) %> \end{tabulary} -<%- if table.caption %> -\end{threeparttable} -<%- endif %> \par \sphinxattableend\end{savenotes} diff --git a/sphinx/texinputs/sphinx.sty b/sphinx/texinputs/sphinx.sty index 5a5088303..2c73a9e10 100644 --- a/sphinx/texinputs/sphinx.sty +++ b/sphinx/texinputs/sphinx.sty @@ -77,40 +77,63 @@ #1\dimexpr\linewidth-\arrayrulewidth\relax-\tw@\tabcolsep-\arrayrulewidth\relax}} % using here T (for Tabulary) feels less of a problem than the X could be \newcolumntype{T}{J}% +% For tables allowing pagebreaks \RequirePackage{longtable} -% For table captions. -\RequirePackage{threeparttable} -% fixing the LaTeX mess of vertical spaces with threeparttable and longtable -% The user interface: +% User interface to set-up whitespace before and after tables: \newcommand*\sphinxtablepre {0pt}% \newcommand*\sphinxtablepost{\medskipamount}% +\newcommand*\sphinxbelowcaptionspace{.5\sphinxbaselineskip}% % as one can not use \baselineskip from inside longtable (it is zero there) % we need \sphinxbaselineskip, which defaults to \baselineskip -\newcommand*\sphinxbelowcaptionspace{.5\sphinxbaselineskip}% \def\sphinxbaselineskip{\baselineskip}% -% Helper macros, not a priori for user customization +% These commands are inserted by the table templates \def\sphinxatlongtablestart {\par \vskip\parskip \vskip\dimexpr\sphinxtablepre\relax % adjust vertical position \vbox{}% get correct baseline from above \LTpre\z@skip\LTpost\z@skip % set to zero longtable's own skips - \edef\sphinxbaselineskip{\dimexpr\the\dimexpr\baselineskip\relax\relax}}% + \edef\sphinxbaselineskip{\dimexpr\the\dimexpr\baselineskip\relax\relax}% + }% \def\sphinxatlongtableend{\prevdepth\z@\vskip\sphinxtablepost\relax}% -% the longtable template inserts a \strut at caption's end \def\sphinxlongtablecapskipadjust - {\dimexpr-\dp\strutbox-\sphinxbaselineskip - +\sphinxbelowcaptionspace\relax}% -% tabular(y) with or without threeparttable + {\dimexpr-\dp\strutbox-\sphinxbaselineskip+\sphinxbelowcaptionspace\relax}% +% Now for tables not using longtable \def\sphinxattablestart {\par \vskip\dimexpr\sphinxtablepre\relax - \belowcaptionskip\sphinx@TPTbelowcaptionskip}% + }% \let\sphinxattableend\sphinxatlongtableend -% the tabular(y) templates use [t] vertical placement parameter -\def\sphinx@TPTbelowcaptionskip - {\dimexpr-1.2\baselineskip % .2\baselineskip hardcoded in threeparttable - +\sphinxbelowcaptionspace\relax }% +% longtable's wraps captions to a maximal width of \LTcapwidth +% so we do the same for all tables +\newcommand*\sphinxcapstartof[1]{% + \vskip\parskip + \vbox{}% force baselineskip for good positioning by capstart of hyperanchor + \def\@captype{#1}% + \capstart +% move back vertically to compensate space inserted by next paragraph + \vskip-\baselineskip\vskip-\parskip +}% +\newcommand\sphinxcaption[2][\LTcapwidth]{% + \noindent\hb@xt@\linewidth{\hss + \vtop{\@tempdima\dimexpr#1\relax +% don't exceed linewidth for the caption width + \ifdim\@tempdima>\linewidth\hsize\linewidth\else\hsize\@tempdima\fi +% longtable ignores \abovecaptionskip/\belowcaptionskip, so do the same here + \abovecaptionskip\z@skip + \belowcaptionskip\z@skip + \caption[{#2}]% + {\strut\ignorespaces#2\ifhmode\unskip\@finalstrut\strutbox\fi}% + }\hss}% + \par\prevdepth\dp\strutbox +}% +\newcommand\sphinxaftercaption +{% this default definition serves with a caption *above* a table, to make sure + % its last baseline is \sphinxbelowcaptionspace above table top + \nobreak + \vskip\dimexpr\sphinxbelowcaptionspace\relax + \vskip-\baselineskip\vskip-\parskip +}% % varwidth is crucial for our handling of general contents in merged cells \RequirePackage{varwidth} % but addition of a compatibility patch with hyperref is needed @@ -598,6 +621,7 @@ % \newenvironment{sphinxfigure-in-table}[1][\linewidth]{% \def\@captype{figure}% + \sphinxsetvskipsforfigintablecaption \begin{minipage}{#1}% }{\end{minipage}} % store original \caption macro for use with figures in longtable and tabulary @@ -606,7 +630,9 @@ {\ifx\equation$%$% this is trick to identify tabulary first pass \firstchoice@false\else\firstchoice@true\fi \spx@originalcaption } - +\newcommand*\sphinxsetvskipsforfigintablecaption + {\abovecaptionskip\smallskipamount + \belowcaptionskip\smallskipamount} %% FOOTNOTES % diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py index 2e5a5d78b..6b5cfef5b 100644 --- a/tests/test_build_latex.py +++ b/tests/test_build_latex.py @@ -31,7 +31,7 @@ from test_build_html import ENV_WARNINGS LATEX_ENGINES = ['pdflatex', 'lualatex', 'xelatex'] DOCCLASSES = ['howto', 'manual'] STYLEFILES = ['article.cls', 'fancyhdr.sty', 'titlesec.sty', 'amsmath.sty', - 'framed.sty', 'color.sty', 'fancyvrb.sty', 'threeparttable.sty', + 'framed.sty', 'color.sty', 'fancyvrb.sty', 'fncychap.sty', 'geometry.sty', 'kvoptions.sty', 'hyperref.sty'] LATEX_WARNINGS = ENV_WARNINGS + """\ @@ -492,7 +492,7 @@ def test_footnote(app, status, warning): assert ('\\bibitem[bar]{\\detokenize{bar}}' '{\\phantomsection\\label{\\detokenize{footnote:bar}} ' '\ncite\n}') in result - assert '\\caption{Table caption \\sphinxfootnotemark[4]' in result + assert '\\sphinxcaption{Table caption \\sphinxfootnotemark[4]' in result assert ('\\hline%\n\\begin{footnotetext}[4]\\sphinxAtStartFootnote\n' 'footnote in table caption\n%\n\\end{footnotetext}\\ignorespaces %\n' '\\begin{footnotetext}[5]\\sphinxAtStartFootnote\n' @@ -501,7 +501,7 @@ def test_footnote(app, status, warning): assert ('Information about VIDIOC\\_CROPCAP %\n' '\\begin{footnote}[6]\\sphinxAtStartFootnote\n' 'footnote in table not in header\n%\n\\end{footnote}\n\\\\\n\\hline\n' - '\\end{tabulary}\n\\end{threeparttable}\n' + '\\end{tabulary}\n' '\\par\n\\sphinxattableend\\end{savenotes}\n') in result @@ -517,7 +517,8 @@ def test_reference_in_caption_and_codeblock_in_footnote(app, status, warning): '{\\hyperref[\\detokenize{index:authoryear}]' '{\\sphinxcrossref{{[}AuthorYear{]}}}}.}' in result) assert '\\chapter{The section with a reference to {[}AuthorYear{]}}' in result - assert '\\caption{The table title with a reference to {[}AuthorYear{]}}' in result + assert ('\\sphinxcaption{The table title with a reference' + ' to {[}AuthorYear{]}}' in result) assert '\\paragraph{The rubric title with a reference to {[}AuthorYear{]}}' in result assert ('\\chapter{The section with a reference to \\sphinxfootnotemark[4]}\n' '\\label{\\detokenize{index:the-section-with-a-reference-to}}' @@ -527,8 +528,8 @@ def test_reference_in_caption_and_codeblock_in_footnote(app, status, warning): '\\sphinxfootnotemark[6].}\\label{\\detokenize{index:id27}}\\end{figure}\n' '%\n\\begin{footnotetext}[6]\\sphinxAtStartFootnote\n' 'Footnote in caption\n%\n\\end{footnotetext}')in result - assert ('\\caption{footnote \\sphinxfootnotemark[7] ' - 'in caption of normal table}\\label{\\detokenize{index:id28}}') in result + assert ('\\sphinxcaption{footnote \\sphinxfootnotemark[7] in ' + 'caption of normal table}\\label{\\detokenize{index:id28}}') in result assert ('\\caption{footnote \\sphinxfootnotemark[8] ' 'in caption \\sphinxfootnotemark[9] of longtable\\strut}') in result assert ('\\endlastfoot\n%\n\\begin{footnotetext}[8]\\sphinxAtStartFootnote\n' @@ -895,10 +896,12 @@ def test_latex_table_tabulars(app, status, warning): # table having caption table = tables['table having caption'] assert ('\\begin{savenotes}\\sphinxattablestart\n\\centering\n' - '\\begin{threeparttable}\n\\capstart\\caption{caption for table}' - '\\label{\\detokenize{tabular:id1}}' in table) + '\\sphinxcapstartof{table}\n' + '\\sphinxcaption{caption for table}' + '\\label{\\detokenize{tabular:id1}}\n' + '\\sphinxaftercaption' in table) assert ('\\begin{tabulary}{\\linewidth}[t]{|T|T|}' in table) - assert ('\\hline\n\\end{tabulary}\n\\end{threeparttable}' + assert ('\\hline\n\\end{tabulary}' '\n\\par\n\\sphinxattableend\\end{savenotes}' in table) # table having verbatim