Skip to content

Commit

Permalink
Experimental \sphinxbreakablebox [skip ci]
Browse files Browse the repository at this point in the history
  • Loading branch information
jfbu committed Mar 14, 2023
1 parent ee3c720 commit e8efd18
Showing 1 changed file with 195 additions and 0 deletions.
195 changes: 195 additions & 0 deletions sphinx/texinputs/sphinxpackageboxes.sty
Expand Up @@ -277,6 +277,201 @@
\fi
}

% Experimental "breakable" variant. Use at own risk: either it works for your
% use case and then you are fine, or it does not, then use \sphinxbox, or some
% external to Sphinx approaches, such as the lua-hl package for LuaLaTeX only.
%
% These utilities will have to be used in a scope limiting context, else I
% have to add some macro to store and restore a given configuration.
\def\spx@boxes@fcolorbox@setup@openright{%
\spx@boxes@border@right \z@
\spx@boxes@padding@right \z@
\spx@boxes@radius@topright \z@
\spx@boxes@radius@bottomright\z@
% external shadow handling will be complicated
% but if it is on right side it should simply
% work; if on left, then problems a hook should
% be added to shadow drawing
\ifspx@boxes@withshadow
\ifspx@boxes@insetshadow
\ifdim\spx@boxes@shadow@xoffset<\z@
\spx@boxes@shadow@xoffset=\z@
\fi
\fi
\fi
\spx@boxes@fcolorbox@setup@fcolorbox
}%
\def\spx@boxes@fcolorbox@setup@openleft{%
\spx@boxes@border@left \z@
\spx@boxes@padding@left \z@
\spx@boxes@radius@topleft \z@
\spx@boxes@radius@bottomleft\z@
\ifspx@boxes@withshadow
\ifspx@boxes@insetshadow
\ifdim\spx@boxes@shadow@xoffset>\z@
\spx@boxes@shadow@xoffset=\z@
\fi

This comment has been minimized.

Copy link
@jfbu

jfbu Mar 14, 2023

Author Owner

missing \fi

\fi
\spx@boxes@fcolorbox@setup@fcolorbox
}%
\def\spx@boxes@fcolorbox@setup@openboth{%
\spx@boxes@border@left \z@
\spx@boxes@border@right \z@
\spx@boxes@padding@left \z@
\spx@boxes@padding@right \z@
\spx@boxes@radius@topright \z@
\spx@boxes@radius@bottomright\z@
\spx@boxes@radius@topleft \z@
\spx@boxes@radius@bottomleft \z@
\ifspx@boxes@withshadow
\ifspx@boxes@insetshadow
\spx@boxes@shadow@xoffset\z@
\fi
\fi
\def\spx@boxes@fcolorbox{\spx@boxes@fcolorbox@rectangle}%
}%


\catcode`Z=3 % safe delimiter
\newcommand\sphinxbreakablebox[2][]{% #1 stands for the options, they are... optional!
% for this first version I will assume the input has at least 2 characters
\begingroup
% this borrows a box from sphinxlatexliterals, \sphinxafterbreak will insert it
% the original default from verbatimcontinued occupies some place and is red and
% uses \tiny. Of course this here should be made customizable
\sbox\sphinxcontinuationbox {\llap{\textcolor{gray}{$\m@th\hookrightarrow$ }}}%
\sphinxboxsetup{#1}%
\spx@boxes@fcolorbox@setup
{box}
{sphinxboxBorderColor}
{sphinxboxBgColor}
{sphinxboxShadowColor}%
%%% \spx@boxes@shadowinbboxtrue%%% only for last one assume shadow on right if exists
\def\spx@boxes@breakable@localsetup{\spx@boxes@fcolorbox@setup@openright}%
\spx@boxes@breakable@a #2Z%
}
\def\spx@boxes@breakable@a{\futurelet\spx@nexttoken\spx@boxes@breakable@b}
\def\spx@boxes@breakable@b{%
\ifcat\noexpand\spx@nexttoken\relax
\def\next{\spx@boxes@breakable@casei}%
% as this is the most annoying branch its code is given last below
\else
\ifx\spx@nexttoken\bgroup
% naked braced material, should never happen in Sphinx I think
% we will handle this by removing the brace pair and start again
\def\next{\spx@boxes@breakable@caseii}%
\else
\ifx\spx@nexttoken\@sptoken
% a space, so it was following some character or {} and
% we will handle this basically as we handle a single character
\def\next{\spx@boxes@breakable@caseiii}%
\else
% hopefully some character token
\def\next{\spx@boxes@breakable@mainloop}%
\fi\fi\fi
\next
}%
% some braced material; impossible in Sphinx a priori. Unbrace and proceed.
\def\spx@boxes@breakable@caseii#1{\spx@boxes@breakable@a #1}
% handle the blank space
\@firstofone{\def\spx@boxes@breakable@caseiii} {\spx@boxes@breakable@mainloop{ }}
% the simple case
\def\spx@boxes@breakable@mainloop #1{%
% need to check if at end; and add a strut to equalize heights
\def\spx@temp{{#1\strut}}%
\futurelet\spx@nexttoken\spx@boxes@breakable@check
}
\def\spx@boxes@breakable@check{%
\ifx\spx@nexttoken Z%
\def\spx@boxes@breakable@again Z{\endgroup}%
\def\spx@boxes@breakable@localsetup{%
\spx@boxes@shadowinbboxtrue
\spx@boxes@fcolorbox@setup@openleft
}%
\fi
{\spx@boxes@breakable@localsetup\expandafter\spx@boxes@fcolorbox\spx@temp}%
\spx@boxes@breakable@again
}
\def\spx@boxes@breakable@again{%
\discretionary{}{\sphinxafterbreak}{}%
\def\spx@boxes@breakable@localsetup{\spx@boxes@fcolorbox@setup@openboth}%
\futurelet\spx@nexttoken\spx@boxes@breakable@b
}
\let\spx@boxes@breakable@@again\spx@boxes@breakable@again
% The more complex branch
\def\spx@boxes@breakable@casei #1{%
\ifcat\noexpand~\noexpand#1\relax% active character
\expandafter\spx@boxes@breakable@casei@active
\else % some control sequence; if a LaTeX escape assumed followed by an empty
% brace pair {}. If a macro assumed to be one with exactly one argument...
\expandafter\spx@boxes@breakable@casei@b
\fi #1%
}%
% assume active character can ONLY come from utf-8 in pdflatex...
% ...if not we are doomed here
\def\spx@boxes@breakable@casei@active#1{%
\expandafter\spx@boxes@breakable@casei@active@a#1Z#1%
}%
% I use \def's not \let's only for easier debugging via log trace if needed
\def\spx@boxes@breakable@casei@active@a #1#2Z{%
\ifx\UTFviii@four@octets#1\def\next{\spx@boxes@breakable@four}\else
\ifx\UTFviii@three@octet#1\def\next{\spx@boxes@breakable@three}\else
\ifx\UTFviii@two@octets #1\def\next{\spx@boxes@breakable@two}\else
\def\next{\spx@boxes@breakable@mainloop}%
\fi\fi\fi
\next
}%
\def\spx@boxes@breakable@two #1#2{\spx@boxes@breakable@mainloop{#1#2}}%
\def\spx@boxes@breakable@three #1#2#3{\spx@boxes@breakable@mainloop{#1#2#3}}%
\def\spx@boxes@breakable@four #1#2#3#4{\spx@boxes@breakable@mainloop{#1#2#3#4}}%
%
\def\spx@boxes@breakable@casei@b #1#2{%
% **assume #1 is a one-argument** macro, probably some macro ending-up doing
% some \textit etc... OR some LaTeX escape of a character special to
% LaTeX (which I think is then always followed by {} from Sphinx
% mark-up. TODO: check if the case).
% CAVEAT: a \sphinxhref which has two arguments **will cause breakage**.
% TODO: check for \sphinxhref and handle it if possible.
\def\spx@tempa{#1}%
\def\spx@tempb{#2}%
\futurelet\spx@nexttoken\spx@boxes@breakable@casei@checkandloop
}
\def\spx@boxes@breakable@casei@checkandloop{%
\ifx\spx@nexttoken Z%
\def\spx@boxes@breakable@again Z{\endgroup}%
\def\spx@boxes@breakable@localsetup{%
\spx@boxes@shadowinbboxtrue
\spx@boxes@fcolorbox@setup@openleft
}%
\fi
\if\relax\detokenize\expandafter{\spx@tempb}\relax
% seems #1 is some latex escape of a special character, was followed by {}
{\spx@boxes@breakable@localsetup
\expandafter\spx@boxes@fcolorbox\expandafter{\spx@tempa\strut}}%

This comment has been minimized.

Copy link
@jfbu

jfbu Mar 14, 2023

Author Owner

should be \spx@tempa{}. For example \sphinxhyphen is always followed with {} but it defaults to \protected\def\sphinxhyphen#1{-\kern\z@} so gobbles next token . So we must reinsert the {}.

\else
% #1 was some macro with non-empty argument, try something crazy
% problematic if the macro argument #2 is a single character
% breakage if #1 is a multiple-argument macro
% should work if #1 is some \textit for example. Hopefully.
\spx@tempa{\begingroup
\let\spx@boxes@breakable@again\spx@boxes@breakable@@again
% inhibit the sub-thing to terminate with an openleft
\def\spx@boxes@fcolorbox@setup@openleft{\spx@boxes@fcolorbox@setup@openboth}%
% what a hack... let true be false
\def\spx@boxes@shadowinbboxtrue{\expandafter\let\csname
ifspx@boxes@shadowinbbox\expandafter\endcsname
\csname iffalse\endcsname}%
% we may start here in openright or already openboth state
\expandafter\spx@boxes@breakable@a\spx@tempb Z}%
\fi
\spx@boxes@breakable@again
}

\catcode`Z 11 %
%



%%%%%%%%%%%%%%%%
% MACROS
%
Expand Down

1 comment on commit e8efd18

@jfbu
Copy link
Owner Author

@jfbu jfbu commented on e8efd18 Mar 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two bugs commented here have since been corrected in cab4c19

Please sign in to comment.