sphinx-doc / sphinx

The Sphinx documentation generator
https://www.sphinx-doc.org/
Other
6.43k stars 2.1k forks source link

LaTeX: PDF build breaks if admonition of danger type contains code-block long enough not to fit on one page #6804

Closed jfbu closed 4 years ago

jfbu commented 4 years ago

Describe the bug

PDF build is broken if inside an admonition (warning, caution, attention, danger, error) there is a code-block with many lines (about 130 suffices)

To Reproduce

make latexpdf on project with index.rst as below

Expected behavior

PDF build succeeds

Your project

index.rst:

test
====

.. danger::

   ::

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130

Explanation

This is basically same phenomenon as #5936. LaTeX uses for the danger admonition a "framed box". The code-block also uses a "framed box". Nesting of breakable framed boxes is not possible so the inner one is configured to wrap itself in a "minipage" and becomes unbreakable. The long unbreakable object (about longer than the text area on page) causes framed LaTeX package to drop into an infinite loop. After about 5000 pages of this loop, the PDF build stops in an error state.

For #5936 we fixed it by making sure included images are always resized to fit on the page. For this problem, this is more problematic.

There is definitly an upstream bug of LaTeX package framed which should not end up in any circumstance in an infinite loop. On the other hand I know of no LaTeX package providing nestable breakable framable boxes, for example the tcolorbox says in its documentation:

You can nest an unbreakable tcolorbox inside another tcolorbox, even inside a break- able one. But you cannot not nest a breakable box inside a breakable box. The /tcb/breakable key for a nested box is ignored automatically, i.e. inner boxes are always unbreakable.

Environment info

Related

jfbu commented 4 years ago

Some remarks, mainly as memo.

I have identified the triggering factor inside framed.sty code. Deep inside its main core macro \fb@put@frame at lines 390-393 there is

        \setbox\@tempboxa\vbox{% simulate frame and flexiblity of the page:
           \vskip \fb@frh \@plus\pagestretch \@minus.8\pageshrink
           \kern137sp\kern-137sp\penalty-30
           \unvbox\@tempboxa}%

This has the effect of adding some top glue but it creates a potential breakpoint and when the contents offer no breakpoints whatsover one ends up in infinite loop where framed.sty keeps adding this top glue, then splits it off, ships out a page and repeats indefinitly. Problem is that there are no hook points to customize this and only way is to override it. But it has its rationale anyway, so removing is no real option, and better would be to add some mechanism to detect and break out from infinite loop. PDF build would not crash but output would be bad anyhow as contents would spill over at bottom of the page.

Usage of framed.sty for code-blocks was already there in Sphinx 1.0. Later on this usage became more sophisticated to fix various problems and add various features.

And later (in particular at 1.4.2 for admonitions) framed.sty was then used for other things. This creates this problem and #5936 because it now became possible to end up in a nested situation. I have some idea of a possible workaround, a bit too LaTeX-nical to comment about at length here. Another idea is that as code-blocks are so far handled by Sphinx at the core via fancyvrb package it is potentially possible to completely avoid using framed package because fancyvrb can be hooked into to decorate each code line and thus it is possible certainly to do same effect as using framed. But the "continues/continued" hints are problematic to implement.

And, in future it is reasonable for Sphinx to adopt tcolorbox (see #3099, #3790), in particular for code-blocks, and spending too much effort now might not be worth it if code-block rendering is destined to be changed again completely in not too distant future. But switching to tcolorbox would not solve the current issue by itself alone (it probably will avoid build crash but will not provide good PDF output without extra effort of the type alluded too already above and may even make it even more inaccessible to a fix).

jfbu commented 4 years ago

Fixed at https://github.com/sphinx-doc/sphinx/commit/2e68d7624469c2804fe22047fcab9e9b05bbf59b