Skip to content

Commit 20f1c46

Browse files
LaTeX: Inhibit breaks for rows with merged vertical cells (#14227)
1 parent 3c85411 commit 20f1c46

File tree

9 files changed

+338
-12
lines changed

9 files changed

+338
-12
lines changed

CHANGES.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ Bugs fixed
3535
Patch by Günter Milde
3636
* LaTeX: Fix rendering for grid filled merged vertical cell.
3737
Patch by Tim Nordell
38+
* #14228: LaTeX: Fix overrun footer for cases of merged vertical table cells.
39+
Patch by Tim Nordell
3840
* #14207: Fix creating ``HTMLThemeFactory`` objects in third-party extensions.
3941
Patch by Adam Turner
4042
* #3099: LaTeX: PDF build crashes if a code-block contains more than

sphinx/texinputs/sphinxlatextables.sty

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
%% TABLES (WITH SUPPORT FOR MERGED CELLS OF GENERAL CONTENTS)
22
%
33
% change this info string if making any custom modification
4-
\ProvidesPackage{sphinxlatextables}[2025/06/30 v9.0.0 tables]%
4+
\ProvidesPackage{sphinxlatextables}[2025/12/30 v9.1.0 tables]%
55

66
% Provides support for this output mark-up from Sphinx latex writer
77
% and table templates:
@@ -776,7 +776,7 @@
776776
\leaders\hrule\@height\arrayrulewidth\hfill}%
777777
\cr
778778
% the last one will need to be compensated, this is job of \sphinxclines
779-
\noalign{\vskip-\arrayrulewidth}%
779+
\noalign{\nobreak\vskip-\arrayrulewidth}%
780780
}
781781
\def\spx@table@fixvlinejoin{%
782782
{\CT@arc@ % this is the color command set up by \arrayrulecolor
@@ -800,7 +800,7 @@
800800
\hfill
801801
\spx@table@fixvlinejoin
802802
\cr
803-
\noalign{\vskip-\arrayrulewidth}%
803+
\noalign{\nobreak\vskip-\arrayrulewidth}%
804804
}
805805
% This "fixclines" is also needed if no \sphinxcline emitted and is useful
806806
% even in extreme case with no \sphinxvlinecrossing either, to give correct
@@ -819,6 +819,7 @@
819819
\spx@table@fixvlinejoin% fill small gap at right-bordered table
820820
\cr
821821
% this final one does NO \vskip-\arrayrulewidth... that's the whole point
822+
\noalign{\nobreak}%
822823
}
823824
%%%% end of \cline workarounds
824825

sphinx/writers/latex.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1307,15 +1307,16 @@ def visit_row(self, node: Element) -> None:
13071307

13081308
def depart_row(self, node: Element) -> None:
13091309
assert self.table is not None
1310-
self.body.append(r'\\' + CR)
13111310
cells = [self.table.cell(self.table.row, i) for i in range(self.table.colcount)]
13121311
underlined = [
13131312
cell.row + cell.height == self.table.row + 1 # type: ignore[union-attr]
13141313
for cell in cells
13151314
]
13161315
if all(underlined):
1316+
self.body.append(r'\\' + CR)
13171317
self.body.append(r'\sphinxhline')
13181318
else:
1319+
self.body.append(r'\\*' + CR)
13191320
i = 0
13201321
underlined.extend([False]) # sentinel
13211322
if underlined[0] is False:

tests/roots/test-latex-table/expects/complex_spanning_cell.tex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,15 @@
5252
\sphinxbeforeendvarwidth
5353
\end{varwidth}%
5454
}%
55-
\\
55+
\\*
5656
\sphinxvlinecrossing{1}\sphinxcline{3-3}\sphinxvlinecrossing{4}\sphinxfixclines{5}\sphinxtablestrut{1}&\sphinxtablestrut{2}&\sphinxmultirow{2}{6}{%
5757
\begin{varwidth}[t]{\sphinxcolwidth{1}{5}}
5858
\sphinxAtStartPar
5959
cell2\sphinxhyphen{}3
6060
\sphinxbeforeendvarwidth
6161
\end{varwidth}%
6262
}%
63-
&\sphinxtablestrut{4}&\sphinxtablestrut{5}\\
63+
&\sphinxtablestrut{4}&\sphinxtablestrut{5}\\*
6464
\sphinxvlinecrossing{1}\sphinxvlinecrossing{2}\sphinxvlinecrossing{3}\sphinxcline{5-5}\sphinxfixclines{5}\sphinxtablestrut{1}&\sphinxtablestrut{2}&\sphinxtablestrut{6}&\sphinxtablestrut{4}&\begin{varwidth}[t]{\sphinxcolwidth{1}{5}}
6565
\sphinxAtStartPar
6666
cell3\sphinxhyphen{}5

tests/roots/test-latex-table/expects/grid_table.tex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
cell1\sphinxhyphen{}3
4141
\sphinxbeforeendvarwidth
4242
\end{varwidth}%
43-
\\
43+
\\*
4444
\sphinxcline{1-1}\sphinxcline{3-3}\sphinxfixclines{3}\sphinxmultirow{2}{7}{%
4545
\begin{varwidth}[t]{\sphinxcolwidth{1}{3}}
4646
\sphinxAtStartPar
@@ -53,7 +53,7 @@
5353
cell2\sphinxhyphen{}3
5454
\sphinxbeforeendvarwidth
5555
\end{varwidth}%
56-
\\
56+
\\*
5757
\sphinxcline{2-3}\sphinxfixclines{3}\sphinxtablestrut{7}&\sphinxstartmulticolumn{2}%
5858
\sphinxmultirow{2}{9}{%
5959
\begin{varwidth}[t]{\sphinxcolwidth{2}{3}}
@@ -66,7 +66,7 @@
6666
\end{varwidth}%
6767
}%
6868
\sphinxstopmulticolumn
69-
\\
69+
\\*
7070
\sphinxcline{1-1}\sphinxfixclines{3}\begin{varwidth}[t]{\sphinxcolwidth{1}{3}}
7171
\sphinxAtStartPar
7272
cell4\sphinxhyphen{}1

tests/roots/test-latex-table/expects/grid_table_with_tabularcolumns.tex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
cell1\sphinxhyphen{}3
4141
\sphinxbeforeendvarwidth
4242
\end{varwidth}%
43-
\\
43+
\\*
4444
\sphinxcline{1-1}\sphinxcline{3-3}\sphinxfixclines{3}\sphinxmultirow{2}{7}{%
4545
\begin{varwidth}[t]{\sphinxcolwidth{1}{3}}
4646
\sphinxAtStartPar
@@ -53,7 +53,7 @@
5353
cell2\sphinxhyphen{}3
5454
\sphinxbeforeendvarwidth
5555
\end{varwidth}%
56-
\\
56+
\\*
5757
\sphinxcline{2-3}\sphinxfixclines{3}\sphinxtablestrut{7}&\sphinxstartmulticolumn{2}%
5858
\sphinxmultirow{2}{9}{%
5959
\begin{varwidth}[t]{\sphinxcolwidth{2}{3}}
@@ -66,7 +66,7 @@
6666
\end{varwidth}%
6767
}%
6868
\sphinxstopmulticolumn
69-
\\
69+
\\*
7070
\sphinxcline{1-1}\sphinxfixclines{3}\begin{varwidth}[t]{\sphinxcolwidth{1}{3}}
7171
\sphinxAtStartPar
7272
cell4\sphinxhyphen{}1
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
\label{\detokenize{longtable:longtable-with-multirow-cell-near-page-footer}}
2+
\sphinxAtStartPar
3+
table having …
4+
\begin{itemize}
5+
\item {}
6+
\sphinxAtStartPar
7+
consecutive multirow near footer
8+
9+
\end{itemize}
10+
11+
\newpage
12+
\vspace*{\dimeval{\textheight - 5\baselineskip}}
13+
14+
15+
\begin{savenotes}
16+
\sphinxatlongtablestart
17+
\sphinxthistablewithglobalstyle
18+
\makeatletter
19+
\LTleft \@totalleftmargin plus1fill
20+
\LTright\dimexpr\columnwidth-\@totalleftmargin-\linewidth\relax plus1fill
21+
\makeatother
22+
\begin{longtable}{|l|l|}
23+
\sphinxtoprule
24+
\endfirsthead
25+
26+
\multicolumn{2}{c}{\sphinxnorowcolor
27+
\makebox[0pt]{\sphinxtablecontinued{\tablename\ \thetable{} \textendash{} continued from previous page}}%
28+
}\\
29+
\sphinxtoprule
30+
\endhead
31+
32+
\sphinxbottomrule
33+
\multicolumn{2}{r}{\sphinxnorowcolor
34+
\makebox[0pt][r]{\sphinxtablecontinued{continues on next page}}%
35+
}\\
36+
\endfoot
37+
38+
\endlastfoot
39+
\sphinxtableatstartofbodyhook
40+
\sphinxmultirow{16}{1}{%
41+
\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
42+
\sphinxAtStartPar
43+
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex
44+
sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis
45+
convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus
46+
fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada
47+
lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti
48+
sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.
49+
\sphinxbeforeendvarwidth
50+
\end{varwidth}%
51+
}%
52+
&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
53+
\sphinxAtStartPar
54+
Cell 1
55+
\sphinxbeforeendvarwidth
56+
\end{varwidth}%
57+
\\*
58+
\sphinxcline{2-2}\sphinxfixclines{2}\sphinxtablestrut{1}&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
59+
\sphinxAtStartPar
60+
Cell 2
61+
\sphinxbeforeendvarwidth
62+
\end{varwidth}%
63+
\\*
64+
\sphinxcline{2-2}\sphinxfixclines{2}\sphinxtablestrut{1}&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
65+
\sphinxAtStartPar
66+
Cell 3
67+
\sphinxbeforeendvarwidth
68+
\end{varwidth}%
69+
\\*
70+
\sphinxcline{2-2}\sphinxfixclines{2}\sphinxtablestrut{1}&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
71+
\sphinxAtStartPar
72+
Cell 4
73+
\sphinxbeforeendvarwidth
74+
\end{varwidth}%
75+
\\*
76+
\sphinxcline{2-2}\sphinxfixclines{2}\sphinxtablestrut{1}&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
77+
\sphinxAtStartPar
78+
Cell 5
79+
\sphinxbeforeendvarwidth
80+
\end{varwidth}%
81+
\\*
82+
\sphinxcline{2-2}\sphinxfixclines{2}\sphinxtablestrut{1}&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
83+
\sphinxAtStartPar
84+
Cell 6
85+
\sphinxbeforeendvarwidth
86+
\end{varwidth}%
87+
\\*
88+
\sphinxcline{2-2}\sphinxfixclines{2}\sphinxtablestrut{1}&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
89+
\sphinxAtStartPar
90+
Cell 7
91+
\sphinxbeforeendvarwidth
92+
\end{varwidth}%
93+
\\*
94+
\sphinxcline{2-2}\sphinxfixclines{2}\sphinxtablestrut{1}&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
95+
\sphinxAtStartPar
96+
Cell 8
97+
\sphinxbeforeendvarwidth
98+
\end{varwidth}%
99+
\\*
100+
\sphinxcline{2-2}\sphinxfixclines{2}\sphinxtablestrut{1}&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
101+
\sphinxAtStartPar
102+
Cell 9
103+
\sphinxbeforeendvarwidth
104+
\end{varwidth}%
105+
\\*
106+
\sphinxcline{2-2}\sphinxfixclines{2}\sphinxtablestrut{1}&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
107+
\sphinxAtStartPar
108+
Cell 10
109+
\sphinxbeforeendvarwidth
110+
\end{varwidth}%
111+
\\*
112+
\sphinxcline{2-2}\sphinxfixclines{2}\sphinxtablestrut{1}&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
113+
\sphinxAtStartPar
114+
Cell 11
115+
\sphinxbeforeendvarwidth
116+
\end{varwidth}%
117+
\\*
118+
\sphinxcline{2-2}\sphinxfixclines{2}\sphinxtablestrut{1}&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
119+
\sphinxAtStartPar
120+
Cell 12
121+
\sphinxbeforeendvarwidth
122+
\end{varwidth}%
123+
\\*
124+
\sphinxcline{2-2}\sphinxfixclines{2}\sphinxtablestrut{1}&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
125+
\sphinxAtStartPar
126+
Cell 13
127+
\sphinxbeforeendvarwidth
128+
\end{varwidth}%
129+
\\*
130+
\sphinxcline{2-2}\sphinxfixclines{2}\sphinxtablestrut{1}&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
131+
\sphinxAtStartPar
132+
Cell 14
133+
\sphinxbeforeendvarwidth
134+
\end{varwidth}%
135+
\\*
136+
\sphinxcline{2-2}\sphinxfixclines{2}\sphinxtablestrut{1}&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
137+
\sphinxAtStartPar
138+
Cell 15
139+
\sphinxbeforeendvarwidth
140+
\end{varwidth}%
141+
\\*
142+
\sphinxcline{2-2}\sphinxfixclines{2}\sphinxtablestrut{1}&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
143+
\sphinxAtStartPar
144+
Cell 16
145+
\sphinxbeforeendvarwidth
146+
\end{varwidth}%
147+
\\
148+
\sphinxhline\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
149+
\sphinxAtStartPar
150+
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex
151+
sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis
152+
convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus
153+
fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada
154+
lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti
155+
sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.
156+
\sphinxbeforeendvarwidth
157+
\end{varwidth}%
158+
&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
159+
\sphinxbeforeendvarwidth
160+
\end{varwidth}%
161+
\\
162+
\sphinxhline\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
163+
\sphinxAtStartPar
164+
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex
165+
sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis
166+
convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus
167+
fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada
168+
lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti
169+
sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.
170+
\sphinxbeforeendvarwidth
171+
\end{varwidth}%
172+
&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
173+
\sphinxbeforeendvarwidth
174+
\end{varwidth}%
175+
\\
176+
\sphinxhline\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
177+
\sphinxAtStartPar
178+
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex
179+
sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis
180+
convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus
181+
fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada
182+
lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti
183+
sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.
184+
\sphinxbeforeendvarwidth
185+
\end{varwidth}%
186+
&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
187+
\sphinxbeforeendvarwidth
188+
\end{varwidth}%
189+
\\
190+
\sphinxhline\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
191+
\sphinxAtStartPar
192+
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex
193+
sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis
194+
convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus
195+
fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada
196+
lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti
197+
sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.
198+
\sphinxbeforeendvarwidth
199+
\end{varwidth}%
200+
&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
201+
\sphinxbeforeendvarwidth
202+
\end{varwidth}%
203+
\\
204+
\sphinxhline\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
205+
\sphinxAtStartPar
206+
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex
207+
sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis
208+
convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus
209+
fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada
210+
lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti
211+
sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.
212+
\sphinxbeforeendvarwidth
213+
\end{varwidth}%
214+
&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
215+
\sphinxbeforeendvarwidth
216+
\end{varwidth}%
217+
\\
218+
\sphinxhline\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
219+
\sphinxAtStartPar
220+
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex
221+
sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis
222+
convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus
223+
fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada
224+
lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti
225+
sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.
226+
\sphinxbeforeendvarwidth
227+
\end{varwidth}%
228+
&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
229+
\sphinxbeforeendvarwidth
230+
\end{varwidth}%
231+
\\
232+
\sphinxhline\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
233+
\sphinxAtStartPar
234+
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex
235+
sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis
236+
convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus
237+
fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada
238+
lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti
239+
sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.
240+
\sphinxbeforeendvarwidth
241+
\end{varwidth}%
242+
&\begin{varwidth}[t]{\sphinxcolwidth{1}{2}}
243+
\sphinxbeforeendvarwidth
244+
\end{varwidth}%
245+
\\
246+
\sphinxbottomrule
247+
\end{longtable}
248+
\sphinxtableafterendhook
249+
\sphinxatlongtableend
250+
\end{savenotes}

0 commit comments

Comments
 (0)