summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/latex/algpseudocodex/algpseudocodex.sty
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2020-08-17 20:58:45 +0000
committerKarl Berry <karl@freefriends.org>2020-08-17 20:58:45 +0000
commit6df02fac79cff54b64d93b90e234904331b6d7bf (patch)
treef1f2bba9cdba7c86bb2be98299615d416de40f1d /Master/texmf-dist/tex/latex/algpseudocodex/algpseudocodex.sty
parentca2a3cf1cffa8b48f35aaa7a5dac389c0a95a79b (diff)
algpseudocodex (17aug20)
git-svn-id: svn://tug.org/texlive/trunk@56125 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/algpseudocodex/algpseudocodex.sty')
-rw-r--r--Master/texmf-dist/tex/latex/algpseudocodex/algpseudocodex.sty735
1 files changed, 735 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/latex/algpseudocodex/algpseudocodex.sty b/Master/texmf-dist/tex/latex/algpseudocodex/algpseudocodex.sty
new file mode 100644
index 00000000000..e6da8cd0c9f
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/algpseudocodex/algpseudocodex.sty
@@ -0,0 +1,735 @@
+%% algpseudocodex.sty
+%% Copyright 2017, 2020 Christian Matt
+%
+% This work may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3
+% of this license or (at your option) any later version.
+% The latest version of this license is in
+% http://www.latex-project.org/lppl.txt
+% and version 1.3 or later is part of all distributions of LaTeX
+% version 2005/12/01 or later.
+%
+% This work has the LPPL maintenance status `maintained'.
+%
+% The Current Maintainer of this work is Christian Matt.
+%
+% This work consists of the files algpseudocodex.sty and documentation.tex.
+
+
+% Pseudocodex algorithmic style
+% Based on Szasz Janos' algpseudocode.sty
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{algpseudocodex}[2020-08-16 v1.0 pseudocode typesetting]
+\RequirePackage{kvoptions}
+\RequirePackage{algorithmicx}
+\RequirePackage{etoolbox}
+\RequirePackage{fifo-stack}
+\RequirePackage{varwidth}
+\RequirePackage{tabto}
+\RequirePackage{tikz}
+\usetikzlibrary{calc,fit,tikzmark}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Package options
+%
+\SetupKeyvalOptions{%
+ family=algpx,%
+ prefix=algpx@%
+}
+
+\DeclareBoolOption[true]{noEnd}% don't print end if etc.
+\DeclareBoolOption[true]{indLines}% show indent guide lines
+\DeclareBoolOption[true]{spaceRequire}% adds vertical space before \Require if not in first line
+\DeclareBoolOption[true]{italicComments}% italicise comments
+\DeclareBoolOption[true]{rightComments}% right justify comments
+\DeclareStringOption[gray]{commentColor}% color of comments
+\DeclareStringOption[$\triangleright$~]{beginComment}% print at beginning of comment
+\DeclareStringOption[]{endComment}% print at end of comment
+\DeclareStringOption[$\triangleright$~]{beginLComment}% print at beginning of long comment
+\DeclareStringOption[~$\triangleleft$]{endLComment}% print at end of long comment
+\ProcessLocalKeyvalOptions*
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Styles
+%
+\tikzset{%
+ algpxDefaultBox/.style={draw},%
+ algpxIndentLine/.style={draw=gray,very thin}%
+}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Declarations
+%
+\algnewlanguage{pseudocodex}
+\alglanguage{pseudocodex}
+
+% \tikzmark is only available on next compilation; the following command immediately after using it
+\newcommand{\@tikzmarkNow}[2][]{\tikz[overlay,remember picture] \node[#1] (#2) {};}
+
+\long\def\@ifnodedefined#1#2#3{%
+ \@ifundefined{pgf@sh@ns@#1}{#3}{#2}%
+}
+
+\newlength{\algpx@codeBoxInnerSep}% distance between box and its content
+\newlength{\algpx@codeBoxSep}% distance between nested boxes
+\newlength{\algpx@codeBoxOuterSep}% additional space before and after box
+\newlength{\algpx@minIndDist}% minimum distance between start and end of indent line to draw line
+\newlength{\algpx@oldPos}
+\newlength{\algpx@newPos}
+\newlength{\algpx@tmpLen}% length to be used for various things
+\newlength{\algpx@tmpLenA}% another tmp length
+\newlength{\algpx@indStartY}
+\newlength{\algpx@indEndY}
+\newlength{\algpx@indStartX}% x coordinate of indent line
+
+\setlength{\algpx@codeBoxInnerSep}{2pt}
+\setlength{\algpx@codeBoxSep}{3pt}
+\setlength{\algpx@codeBoxOuterSep}{1pt}
+
+\newbool{algpx@firstLine}
+\newbool{algpx@setNorth}
+\newbool{algpx@executeEndVarwidth}
+\newbool{algpx@adjustHeight}
+\newbool{algpx@restorePrevdepth}
+\newbool{algpx@indJustEnded}% true after end with noend
+
+\newcounter{algpx@codeBoxCount}% number of already created code boxes. Used to fill algpx@startNewCodeBoxQueue
+\newcounter{algpx@nestedCBoxCount}
+\newcounter{algpx@startedBoxesCount}
+\newcounter{algpx@endedBoxesCount}
+\newcounter{algpx@nestedBoxedStringCount}
+\newcounter{algpx@nestedBoxedStringMaxCount}
+\newcounter{algpx@indentCount}
+\newcounter{algpx@justUsedIndentCount}
+
+\FSCreate{algpx@startNewCodeBoxQueue}{0}% queue of code boxes to be created on next \State, \If etc. Only stores index of box (0 is value of top if empty; should not be relevant)
+\FSCreate{algpx@codeBoxStack}{0}
+\FSCreate{algpx@codeBoxStackTmp}{0}
+\FSCreate{algpx@indentStack}{0}
+
+\newsavebox{\algpx@boxedStringBox}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Macros for boxes around code
+%
+% Draw a box. First parameter is style, others are coordinates (north, west, east, south)
+\newcommand{\algpx@drawCodeBox}[5]{%
+ \tikz[overlay,remember picture]{%
+ \node[inner sep=\algpx@codeBoxInnerSep,#1,fit={(pic cs:#2) (pic cs:#3) (pic cs:#4) (pic cs:#5)}] {};%
+ }%
+}
+
+% execute after \State, \If etc.
+\newcommand{\algpx@startCodeCommand}{%
+ \algpx@startCodeCommandX{}{}%
+}
+
+% extended version of \algpx@startCodeCommand
+% first argument is printed before content
+% second argument is used to reserve space after contents (for end symbol of long comments)
+\newcommand{\algpx@startCodeCommandX}[2]{%
+ \setbool{algpx@indJustEnded}{false}%
+ \setcounter{algpx@startedBoxesCount}{0}%
+ \setcounter{algpx@endedBoxesCount}{0}%
+ \setcounter{algpx@nestedBoxedStringMaxCount}{0}%
+ \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@startNewCodeBoxQueue}}}}{%
+ \FSPush{algpx@codeBoxStack}{\FSTop{algpx@startNewCodeBoxQueue}}%
+ \algpx@drawCodeBox{algpx@codeBoxStyle\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxNorth-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxWest-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxEast-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxSouth-\FSTop{algpx@startNewCodeBoxQueue}}%
+ \FSPop{algpx@startNewCodeBoxQueue}%
+ \setbool{algpx@setNorth}{true}%
+ \stepcounter{algpx@startedBoxesCount}%
+ }%
+ \algpx@setCodeBoxWest%
+ \setbool{algpx@firstLine}{false}%
+ \setbool{algpx@executeEndVarwidth}{true}%
+ #1%
+ % create box from here to end of line, leaving space for #2
+ \settowidth{\algpx@tmpLen}{#1}%
+ \settowidth{\algpx@tmpLenA}{#2}%
+ \begin{varwidth}[t]{\dimexpr \linewidth - \algpx@tmpLen - \algpx@tmpLenA - \algorithmicindent * \numexpr \value{ALG@nested} - 1 \relax \relax}%
+}
+
+% executed before \State, \If etc., i.e., at end of previous line
+% first argument 1 if after \EndIf etc. and noend
+\newcommand{\algpx@endCodeCommand}[1][0]{%
+ \ifbool{algpx@executeEndVarwidth}{%
+ \par\xdef\algpx@pdtemp{\the\prevdepth}% see https://tex.stackexchange.com/a/34982
+ \end{varwidth}\setbox0=\lastbox\usebox0%
+ \setbool{algpx@executeEndVarwidth}{false}%
+ \setbool{algpx@adjustHeight}{true}%
+ \setbool{algpx@restorePrevdepth}{true}%
+ }{}%
+ \ifbool{algpx@setNorth}{%
+ % todo: north should not be set again if highest element in current line is BoxedString
+ \algpx@setCodeBoxNorth{\the\ht0}% set north here shifted by height of current line
+ \setbool{algpx@setNorth}{false}%
+ }{}%
+ \algpx@setCodeBoxEast%
+ \ifbool{algpx@adjustHeight}{%
+ % todo: if highest or deepest element in current line is BoxedString, \ht0 or \dp0 should be adjusted for different sep values
+ \algpx@addBoxSpacing{\value{algpx@startedBoxesCount}}{\the\ht0}{\value{algpx@endedBoxesCount}}{\the\dp0}%
+ \setbool{algpx@adjustHeight}{false}%
+ }{}%
+ \ifboolexpr{bool{algpx@restorePrevdepth} and test{\ifstrequal{#1}{0}}}{%
+ \par\prevdepth\algpx@pdtemp%
+ \setbool{algpx@restorePrevdepth}{false}%
+ }{}%
+}
+
+% set algpx@codeBoxNorthMax of current box and all ancestors; argument is amount to shift up from current baseline
+\newcommand{\algpx@setCodeBoxNorth}[1]{%
+ \setcounter{algpx@nestedCBoxCount}{0}%
+ \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStack}}}}{%
+ \FSPush{algpx@codeBoxStackTmp}{\FSTop{algpx@codeBoxStack}}% copy stack to tmp
+ \@ifnodedefined{algpx@codeBoxNorthMax-\FSTop{algpx@codeBoxStack}}{%
+ % get current position; shift according to nest-level to ensure nested boxes don't collide
+ \@tikzmarkNow[yshift=\dimexpr #1 + \algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxNorthHere}%
+ % extract y-coordinate of previously stored north
+ \tikz[overlay,remember picture]{%
+ \pgfextracty{\algpx@oldPos}{\pgfpointanchor{algpx@codeBoxNorthMax-\FSTop{algpx@codeBoxStack}}{center}}%
+ \pgfextracty{\algpx@newPos}{\pgfpointanchor{algpx@codeBoxNorthHere}{center}}%
+ \global\algpx@oldPos=\algpx@oldPos%
+ \global\algpx@newPos=\algpx@newPos%
+ }%
+ \ifdimcomp{\algpx@oldPos}{<}{\algpx@newPos}{%
+ % new y is greater than old one, so set it
+ \@tikzmarkNow[yshift=\dimexpr #1 + \algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxNorthMax-\FSTop{algpx@codeBoxStack}}%
+ }{%
+ \@tikzmarkNow{algpx@codeBoxNorthDummy}% set something to keep in sync
+ }%
+ }{%
+ \@tikzmarkNow[yshift=\dimexpr #1 + \algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxNorthMax-\FSTop{algpx@codeBoxStack}}%
+ }%
+ \FSPop{algpx@codeBoxStack}%
+ \stepcounter{algpx@nestedCBoxCount}%
+ }%
+ % restore stack from tmp
+ \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStackTmp}}}}{%
+ \FSPush{algpx@codeBoxStack}{\FSTop{algpx@codeBoxStackTmp}}%
+ \FSPop{algpx@codeBoxStackTmp}%
+ }%
+}
+
+
+% set algpx@codeBoxSouthMax of current box and all ancestors; argument is amount to shift down from current baseline
+\newcommand{\algpx@setCodeBoxSouth}[1]{%
+ \setcounter{algpx@nestedCBoxCount}{0}%
+ \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStack}}}}{%
+ \FSPush{algpx@codeBoxStackTmp}{\FSTop{algpx@codeBoxStack}}% copy stack to tmp
+ \@ifnodedefined{algpx@codeBoxSouthMax-\FSTop{algpx@codeBoxStack}}{%
+ % get current position; shift according to nest-level to ensure nested boxes don't collide
+ \@tikzmarkNow[yshift=\dimexpr -#1 -\algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxSouthHere}%
+ % extract y-coordinate of previously stored south
+ \tikz[overlay,remember picture]{%
+ \pgfextracty{\algpx@oldPos}{\pgfpointanchor{algpx@codeBoxSouthMax-\FSTop{algpx@codeBoxStack}}{center}}%
+ \pgfextracty{\algpx@newPos}{\pgfpointanchor{algpx@codeBoxSouthHere}{center}}%
+ \global\algpx@oldPos=\algpx@oldPos%
+ \global\algpx@newPos=\algpx@newPos%
+ }%
+ \ifdimcomp{\algpx@oldPos}{>}{\algpx@newPos}{%
+ % new y is less than old one, so set it
+ \@tikzmarkNow[yshift=\dimexpr -#1 -\algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxSouthMax-\FSTop{algpx@codeBoxStack}}%
+ }{%
+ \@tikzmarkNow{algpx@codeBoxSouthDummy}% set something to keep in sync
+ }%
+ }{%
+ \@tikzmarkNow[yshift=\dimexpr -#1 -\algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxSouthMax-\FSTop{algpx@codeBoxStack}}%
+ }%
+ \FSPop{algpx@codeBoxStack}%
+ \stepcounter{algpx@nestedCBoxCount}%
+ }%
+ % restore stack from tmp
+ \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStackTmp}}}}{%
+ \FSPush{algpx@codeBoxStack}{\FSTop{algpx@codeBoxStackTmp}}%
+ \FSPop{algpx@codeBoxStackTmp}%
+ }%
+}
+
+% set algpx@codeBoxWestMax of current box and all ancestors; argument is amount to shift left from current position
+\newcommand{\algpx@setCodeBoxWest}[1][0pt]{%
+ \setcounter{algpx@nestedCBoxCount}{0}%
+ \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStack}}}}{%
+ \FSPush{algpx@codeBoxStackTmp}{\FSTop{algpx@codeBoxStack}}% copy stack to tmp
+ \@ifnodedefined{algpx@codeBoxWestMax-\FSTop{algpx@codeBoxStack}}{%
+ % get current position; shift according to nest-level to ensure nested boxes don't collide
+ \@tikzmarkNow[xshift=\dimexpr -#1 -\algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxWestHere}%
+ % extract x-coordinate of previously stored west
+ \tikz[overlay,remember picture]{%
+ \pgfextractx{\algpx@oldPos}{\pgfpointanchor{algpx@codeBoxWestMax-\FSTop{algpx@codeBoxStack}}{center}}%
+ \pgfextractx{\algpx@newPos}{\pgfpointanchor{algpx@codeBoxWestHere}{center}}%
+ \global\algpx@oldPos=\algpx@oldPos%
+ \global\algpx@newPos=\algpx@newPos%
+ }%
+ \ifdimcomp{\algpx@oldPos}{>}{\algpx@newPos}{%
+ % new x is smaller than old one, so set it
+ \@tikzmarkNow[xshift=\dimexpr -#1 -\algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxWestMax-\FSTop{algpx@codeBoxStack}}%
+ }{%
+ \@tikzmarkNow{algpx@codeBoxWestDummy}% set something to keep in sync
+ }%
+ }{%
+ \@tikzmarkNow[xshift=\dimexpr -#1 -\algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxWestMax-\FSTop{algpx@codeBoxStack}}%
+ }%
+ \FSPop{algpx@codeBoxStack}%
+ \stepcounter{algpx@nestedCBoxCount}%
+ }%
+ % restore stack from tmp
+ \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStackTmp}}}}{%
+ \FSPush{algpx@codeBoxStack}{\FSTop{algpx@codeBoxStackTmp}}%
+ \FSPop{algpx@codeBoxStackTmp}%
+ }%
+}
+
+% set algpx@codeBoxEastMax of current box and all ancestors
+\newcommand{\algpx@setCodeBoxEast}{%
+ \setcounter{algpx@nestedCBoxCount}{0}%
+ \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStack}}}}{%
+ \FSPush{algpx@codeBoxStackTmp}{\FSTop{algpx@codeBoxStack}}% copy stack to tmp
+ \@ifnodedefined{algpx@codeBoxEastMax-\FSTop{algpx@codeBoxStack}}{%
+ % get current position; shift according to nest-level to ensure nested boxes don't collide
+ \@tikzmarkNow[xshift=\dimexpr \algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxEastHere}%
+ % extract x-coordinate of previously stored east
+ \tikz[overlay,remember picture]{%
+ \pgfextractx{\algpx@oldPos}{\pgfpointanchor{algpx@codeBoxEastMax-\FSTop{algpx@codeBoxStack}}{center}}%
+ \pgfextractx{\algpx@newPos}{\pgfpointanchor{algpx@codeBoxEastHere}{center}}%
+ \global\algpx@oldPos=\algpx@oldPos%
+ \global\algpx@newPos=\algpx@newPos%
+ }%
+ \ifdimcomp{\algpx@oldPos}{<}{\algpx@newPos}{%
+ % new x is greater than old one, so set it
+ \@tikzmarkNow[xshift=\dimexpr \algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxEastMax-\FSTop{algpx@codeBoxStack}}%
+ }{%
+ \@tikzmarkNow{algpx@codeBoxEastDummy}% set something to keep in sync
+ }%
+ }{%
+ \@tikzmarkNow[xshift=\dimexpr \algpx@codeBoxSep * \value{algpx@nestedCBoxCount}\relax]{algpx@codeBoxEastMax-\FSTop{algpx@codeBoxStack}}%
+ }%
+ \FSPop{algpx@codeBoxStack}%
+ \stepcounter{algpx@nestedCBoxCount}%
+ }%
+ % restore stack from tmp
+ \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStackTmp}}}}{%
+ \FSPush{algpx@codeBoxStack}{\FSTop{algpx@codeBoxStackTmp}}%
+ \FSPop{algpx@codeBoxStackTmp}%
+ }%
+}
+
+% Set coordinates of box on top of algpx@codeBoxStack to maximal reported values.
+% This ensures, e.g., that the right edge of the box is after the longest line inside.
+\newcommand{\algpx@setBoxesToStoredMax}{%
+ \tikz[overlay,remember picture]{%
+ \tikzmark{algpx@codeBoxNorth-\FSTop{algpx@codeBoxStack}}{(algpx@codeBoxNorthMax-\FSTop{algpx@codeBoxStack})}%
+ \tikzmark{algpx@codeBoxSouth-\FSTop{algpx@codeBoxStack}}{(algpx@codeBoxSouthMax-\FSTop{algpx@codeBoxStack})}%
+ \tikzmark{algpx@codeBoxWest-\FSTop{algpx@codeBoxStack}}{(algpx@codeBoxWestMax-\FSTop{algpx@codeBoxStack})}%
+ \tikzmark{algpx@codeBoxEast-\FSTop{algpx@codeBoxStack}}{(algpx@codeBoxEastMax-\FSTop{algpx@codeBoxStack})}%
+ }%
+}
+
+% add some space above and below box; more if several boxes are nested
+% first argument: number of boxes above
+% second argument: height of content
+% third argument: number of boxes below
+% fourth argument: depth of content
+\newcommand{\algpx@addBoxSpacing}[4]{%
+ \ifnumcomp{0}{<}{#1}{%
+ \rule{0pt}{\dimexpr #2 + \algpx@codeBoxInnerSep + \algpx@codeBoxOuterSep + (\algpx@codeBoxSep * (#1 - 1))\relax}%
+ }{}%
+ \ifnumcomp{0}{<}{#3}{%
+ \rule[\dimexpr -#4 - \algpx@codeBoxInnerSep - \algpx@codeBoxOuterSep - (\algpx@codeBoxSep * (#3 - 1))\relax]{0pt}{\dimexpr #4 + \algpx@codeBoxInnerSep + \algpx@codeBoxOuterSep + (\algpx@codeBoxSep * (#3 - 1))\relax}% negative offset equal to height to draw line down from baseline
+ }{}%
+}
+
+% Begin a new code box here.
+% Must be followed by \State, \If, \For etc.
+% (optional) argument is style of box
+\newcommand{\BeginBox}[1][algpxDefaultBox]{%
+ \ignorespaces%
+ \FSUnshift{algpx@startNewCodeBoxQueue}{\thealgpx@codeBoxCount}% add to queue; processed by \algpx@startCodeCommand
+ %globally set tikz style (https://tex.stackexchange.com/a/47918)
+ \begingroup%
+ \globaldefs=1\relax%
+ \pgfqkeys{/tikz}{algpx@codeBoxStyle\thealgpx@codeBoxCount/.style={#1}}%
+ \endgroup%
+ \stepcounter{algpx@codeBoxCount}%
+ \ignorespaces%
+}
+
+% End one open code box. Fails if no box open (i.e., if algpx@codeBoxStack is empty).
+\newcommand{\EndBox}{%
+ \ignorespaces%
+ \ifnumcomp{0}{<}{\FSSize{algpx@startNewCodeBoxQueue}}{%
+ \PackageError{algpseudocodex}{BeginBox must be followed by State, If, For, etc. Use BoxedString instead}{}%
+ \FSClear{algpx@startNewCodeBoxQueue}%
+ }{%
+ \ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStack}}{%
+ \unskip%
+ \ifbool{algpx@executeEndVarwidth}{%
+ \par\xdef\algpx@pdtemp{\the\prevdepth}% see https://tex.stackexchange.com/a/34982
+ \end{varwidth}\setbox0=\lastbox\usebox0%
+ \setbool{algpx@executeEndVarwidth}{false}%
+ \setbool{algpx@adjustHeight}{true}%
+ \setbool{algpx@restorePrevdepth}{true}%
+ }{}%
+ \ifbool{algpx@setNorth}{%
+ \algpx@setCodeBoxNorth{\the\ht0}% set north here shifted by height of current line
+ \setbool{algpx@setNorth}{false}%
+ }{}%
+ \algpx@setCodeBoxEast%
+ \ifbool{algpx@indJustEnded}{%
+ \algpx@setCodeBoxSouth{0pt}% set south here, don't shift after end with noEnd
+ % add space after boxes. Otherwise done by endCodeCommand, but this is not executed after End with noEnd
+ \algpx@addBoxSpacing{\value{algpx@startedBoxesCount}}{0pt}{\numexpr \value{algpx@endedBoxesCount} + 1 \relax}{0pt}%
+ }{%
+ \algpx@setCodeBoxSouth{\the\dp0}% set south here shifted by depth of current line
+ }%
+ %adjust stored prevdepth for ended boxes
+ \ifnumcomp{0}{<}{\value{algpx@endedBoxesCount}}{%
+ \edef\algpx@pdtemp{\dimexpr \algpx@pdtemp + \algpx@codeBoxSep \relax}%
+ }{%
+ \edef\algpx@pdtemp{\dimexpr \algpx@pdtemp + \algpx@codeBoxInnerSep + \algpx@codeBoxOuterSep \relax}%
+ }%
+ \algpx@setBoxesToStoredMax%
+ \FSPop{algpx@codeBoxStack}%
+ \stepcounter{algpx@endedBoxesCount}%
+ }{%
+ \PackageError{algpseudocodex}{No box to end}{}%
+ }%
+ }%
+ \ignorespaces%
+}
+
+% Draw box within a single line of code.
+% (Optional) first argument is style of the box.
+% Second argument is the string to print inside the box.
+\newcommand{\BoxedString}[2][algpxDefaultBox]{%
+ \ifnumcomp{\value{algpx@nestedBoxedStringCount}}{=}{0}{%
+ \setcounter{algpx@nestedBoxedStringMaxCount}{0}% reset max count for new boxes
+ }{}%
+ \stepcounter{algpx@nestedBoxedStringCount}%
+ \ifnumcomp{\value{algpx@nestedBoxedStringMaxCount}}{<}{\value{algpx@nestedBoxedStringCount}}{%
+ \setcounter{algpx@nestedBoxedStringMaxCount}{\value{algpx@nestedBoxedStringCount}}%
+ }{}%
+ \algpx@drawCodeBox{#1}{algpx@codeBoxNorth-\thealgpx@codeBoxCount}{algpx@codeBoxWest-\thealgpx@codeBoxCount}{algpx@codeBoxEast-\thealgpx@codeBoxCount}{algpx@codeBoxSouth-\thealgpx@codeBoxCount}%
+ \FSPush{algpx@codeBoxStack}{\thealgpx@codeBoxCount}%
+ \stepcounter{algpx@codeBoxCount}%
+ \algpx@setCodeBoxWest%
+ \ifmmode%
+ % This works in equation but not in align / displaystyle etc. gets lost
+ \savebox{\algpx@boxedStringBox}{$\m@th#2$}%
+ \usebox{\algpx@boxedStringBox}%
+ \else%
+ \savebox{\algpx@boxedStringBox}{#2}%
+ \usebox{\algpx@boxedStringBox}%
+ \fi%
+ \algpx@setCodeBoxEast%
+ \algpx@setCodeBoxNorth{\the\ht\algpx@boxedStringBox}%
+ \algpx@setCodeBoxSouth{\the\dp\algpx@boxedStringBox}%
+ \algpx@setBoxesToStoredMax%
+ \FSPop{algpx@codeBoxStack}%
+ \addtocounter{algpx@nestedBoxedStringCount}{-1}% BoxedString ends here
+ \ifnumcomp{\value{algpx@nestedBoxedStringCount}}{=}{0}{%
+ \algpx@addBoxSpacing{\value{algpx@nestedBoxedStringMaxCount}}{\the\ht\algpx@boxedStringBox}{\value{algpx@nestedBoxedStringMaxCount}}{\the\dp\algpx@boxedStringBox}%
+ }{}%
+}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Macros for indentation lines
+%
+% start indented block
+\newcommand{\algpx@startIndent}{%
+ \ifbool{algpx@indLines}{%
+ \@tikzmarkNow{algpx@indentStart-\thealgpx@indentCount}%
+ \FSPush{algpx@indentStack}{\thealgpx@indentCount}%
+ \stepcounter{algpx@indentCount}%
+ }{}%
+}
+
+% end of indented block; optional argument 1 means that only interrupted by else, 2 means ended with until
+\newcommand{\algpx@endIndent}[1][0]{%
+ \ifbool{algpx@indLines}{%
+ \ifboolexpr{bool{algpx@noEnd} and test{\ifstrequal{#1}{0}}}{%
+ \setlength{\algpx@minIndDist}{1ex}% set mininum drawing distance to 1ex if ending without text
+ }{% otherwise, factor in additional line for end, else, or until
+ \setlength{\algpx@minIndDist}{\dimexpr \baselineskip + 1ex \relax}%
+ }%
+ \@tikzmarkNow{algpx@indentEnd-\FSTop{algpx@indentStack}}%
+ \tikz[overlay,remember picture]{%
+ \pgfextractx{\algpx@indStartX}{\pgfpointanchor{algpx@indentStart-\FSTop{algpx@indentStack}}{center}}%
+ \ifbool{algpx@indJustEnded}{%
+ % use same coordinates as for previous end
+ \pgfextracty{\algpx@indEndY}{\pgfpointanchor{algpx@indentEnd-\thealgpx@justUsedIndentCount}{center}}%
+ \draw[algpxIndentLine] ($(algpx@indentStart-\FSTop{algpx@indentStack})+(0.12em,-0.8ex)$) -- ($(\algpx@indStartX,\algpx@indEndY)+(0.12em,0ex)$) -- +(0.5em,0);%
+ }{%
+ % only draw if at least one line between start and end
+ \pgfextracty{\algpx@indStartY}{\pgfpointanchor{algpx@indentStart-\FSTop{algpx@indentStack}}{center}}%
+ \pgfextracty{\algpx@indEndY}{\pgfpointanchor{algpx@indentEnd-\FSTop{algpx@indentStack}}{center}}%
+ \ifdimcomp{\algpx@indStartY-\algpx@minIndDist}{>}{\algpx@indEndY}{%
+ \ifboolexpr{bool{algpx@noEnd} and test{\ifstrequal{#1}{0}}}{%
+ % x of end is at end of line, extract x of start and use that instead
+ \pgfextractx{\algpx@indStartX}{\pgfpointanchor{algpx@indentStart-\FSTop{algpx@indentStack}}{center}}%
+ % draw additional line to right if noend and line is not interrupted
+ \draw[algpxIndentLine] ($(algpx@indentStart-\FSTop{algpx@indentStack})+(0.12em,-0.8ex)$) -- ($(\algpx@indStartX,\algpx@indEndY)+(0.12em,0ex)$) -- +(0.5em,0);%
+ }{%
+ \draw[algpxIndentLine] ($(algpx@indentStart-\FSTop{algpx@indentStack})+(0.12em,-0.8ex)$) -- ($(algpx@indentEnd-\FSTop{algpx@indentStack})+(0.12em,2.0ex)$);%
+ }%
+ }{}%
+ }%
+ }%
+ }{}%
+ % set indJustEnded even if indLines are not drawn; also used for EndBox
+ \ifboolexpr{not bool{algpx@indJustEnded} and bool{algpx@noEnd} and test{\ifstrequal{#1}{0}}}{%
+ \setbool{algpx@indJustEnded}{true}%
+ \setcounter{algpx@justUsedIndentCount}{\FSTop{algpx@indentStack}}%
+ }{}%
+ \ifbool{algpx@indLines}{%
+ \FSPop{algpx@indentStack}%
+ \ifstrequal{#1}{1}{%
+ \algpx@startIndent% start new line if only interrupted
+ }{}%
+ }{}%
+}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Keywords
+%
+\algnewcommand\algorithmicend{\textbf{end}}
+\algnewcommand\algorithmicdo{\textbf{do}}
+\algnewcommand\algorithmicwhile{\textbf{while}}
+\algnewcommand\algorithmicfor{\textbf{for}}
+\algnewcommand\algorithmicforall{\textbf{for all}}
+\algnewcommand\algorithmicloop{\textbf{loop}}
+\algnewcommand\algorithmicrepeat{\textbf{repeat}}
+\algnewcommand\algorithmicuntil{\textbf{until}}
+\algnewcommand\algorithmicprocedure{\textbf{procedure}}
+\algnewcommand\algorithmicfunction{\textbf{function}}
+\algnewcommand\algorithmicif{\textbf{if}}
+\algnewcommand\algorithmicthen{\textbf{then}}
+\algnewcommand\algorithmicelse{\textbf{else}}
+\algnewcommand\algorithmicrequire{\textbf{Require:}}
+\algnewcommand\algorithmicensure{\textbf{Ensure:}}
+\algnewcommand\algorithmicreturn{\textbf{return}}
+\algnewcommand\algorithmicoutput{\textbf{output}}
+\algnewcommand\textproc{\textsc}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Loops, conditional statements, and functions
+%
+\algdef{SE}[WHILE]{While}{EndWhile}[1]{%
+ \algpx@startIndent\algpx@startCodeCommand\algorithmicwhile\ #1\ \algorithmicdo%
+}{%
+ \algpx@endIndent\algpx@startCodeCommand\algorithmicend\ \algorithmicwhile%
+}
+\algdef{SE}[FOR]{For}{EndFor}[1]{%
+ \algpx@startIndent\algpx@startCodeCommand\algorithmicfor\ #1\ \algorithmicdo%
+}{%
+ \algpx@endIndent\algpx@startCodeCommand\algorithmicend\ \algorithmicfor%
+}
+\algdef{S}[FOR]{ForAll}[1]{%
+ \algpx@startIndent\algpx@startCodeCommand\algorithmicforall\ #1\ \algorithmicdo%
+}
+\algdef{SE}[LOOP]{Loop}{EndLoop}{%
+ \algpx@startIndent\algpx@startCodeCommand\algorithmicloop%
+}{%
+ \algpx@endIndent\algpx@startCodeCommand\algorithmicend\ \algorithmicloop%
+}
+\algdef{SE}[REPEAT]{Repeat}{Until}{%
+ \algpx@startIndent\algpx@startCodeCommand\algorithmicrepeat%
+}[1]{%
+ \algpx@endIndent[2]\algpx@startCodeCommand\algorithmicuntil\ #1%
+}
+\algdef{SE}[IF]{If}{EndIf}[1]{%
+ \algpx@startIndent\algpx@startCodeCommand\algorithmicif\ #1\ \algorithmicthen%
+}{%
+ \algpx@endIndent\algpx@startCodeCommand\algorithmicend\ \algorithmicif%
+}
+\algdef{C}[IF]{IF}{ElsIf}[1]{%
+ \algpx@endIndent[1]\algpx@startCodeCommand\algorithmicelse\ \algorithmicif\ #1\ \algorithmicthen%
+}
+\algdef{Ce}[ELSE]{IF}{Else}{EndIf}{%
+ \algpx@endIndent[1]\algpx@startCodeCommand\algorithmicelse%
+}
+\algdef{SE}[PROCEDURE]{Procedure}{EndProcedure}[2]{%
+ \algpx@startIndent\algpx@startCodeCommand\algorithmicprocedure\ \textproc{#1}\ifstrempty{#2}{}{(#2)}%
+}{%
+ \algpx@endIndent\algpx@startCodeCommand\algorithmicend\ \algorithmicprocedure%
+}
+\algdef{SE}[FUNCTION]{Function}{EndFunction}[2]{%
+ \algpx@startIndent\algpx@startCodeCommand\algorithmicfunction\ \textproc{#1}\ifstrempty{#2}{}{(#2)}%
+}{%
+ \algpx@endIndent\algpx@startCodeCommand\algorithmicend\ \algorithmicfunction%
+}
+
+\ifbool{algpx@noEnd}{%
+ \algtext*{EndWhile}%
+ \algtext*{EndFor}%
+ \algtext*{EndLoop}%
+ \algtext*{EndIf}%
+ \algtext*{EndProcedure}%
+ \algtext*{EndFunction}%
+ %
+ % end indent line after (not before), to get correct y position for multiline text in last command
+ \apptocmd{\EndWhile}{\algpx@endIndent}{}{}%
+ \apptocmd{\EndFor}{\algpx@endIndent}{}{}%
+ \apptocmd{\EndLoop}{\algpx@endIndent}{}{}%
+ \apptocmd{\EndIf}{\algpx@endIndent}{}{}%
+ \apptocmd{\EndProcedure}{\algpx@endIndent}{}{}%
+ \apptocmd{\EndFunction}{\algpx@endIndent}{}{}%
+}{}%
+
+% execute \algpx@endCodeCommand before \State, \If etc.
+\pretocmd{\State}{\algpx@endCodeCommand}{}{}
+\pretocmd{\While}{\algpx@endCodeCommand}{}{}
+\pretocmd{\For}{\algpx@endCodeCommand}{}{}
+\pretocmd{\ForAll}{\algpx@endCodeCommand}{}{}
+\pretocmd{\Loop}{\algpx@endCodeCommand}{}{}
+\pretocmd{\Repeat}{\algpx@endCodeCommand}{}{}
+\pretocmd{\Until}{\algpx@endCodeCommand}{}{}
+\pretocmd{\If}{\algpx@endCodeCommand}{}{}
+\pretocmd{\ElsIf}{\algpx@endCodeCommand}{}{}
+\pretocmd{\Else}{\algpx@endCodeCommand}{}{}
+\pretocmd{\Procedure}{\algpx@endCodeCommand}{}{}
+\pretocmd{\Function}{\algpx@endCodeCommand}{}{}
+
+% for end commands that may not be printed, tell endCodeCommand whether we are using noEnd
+\ifbool{algpx@noEnd}{%
+ \pretocmd{\EndWhile}{\algpx@endCodeCommand[1]}{}{}%
+ \pretocmd{\EndFor}{\algpx@endCodeCommand[1]}{}{}%
+ \pretocmd{\EndLoop}{\algpx@endCodeCommand[1]}{}{}%
+ \pretocmd{\EndIf}{\algpx@endCodeCommand[1]}{}{}%
+ \pretocmd{\EndProcedure}{\algpx@endCodeCommand[1]}{}{}%
+ \pretocmd{\EndFunction}{\algpx@endCodeCommand[1]}{}{}%
+}{%
+ \pretocmd{\EndWhile}{\algpx@endCodeCommand[0]}{}{}%
+ \pretocmd{\EndFor}{\algpx@endCodeCommand[0]}{}{}%
+ \pretocmd{\EndLoop}{\algpx@endCodeCommand[0]}{}{}%
+ \pretocmd{\EndIf}{\algpx@endCodeCommand[0]}{}{}%
+ \pretocmd{\EndProcedure}{\algpx@endCodeCommand[0]}{}{}%
+ \pretocmd{\EndFunction}{\algpx@endCodeCommand[0]}{}{}%
+}%
+
+% execute \algpx@startCodeCommand after \State (this is done for loops etc. inside the definitions above)
+\apptocmd{\State}{\algpx@startCodeCommand}{}{}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Other declarations
+%
+
+% dirty hack: execute drawing in argument of item and rest of \algpx@startCodeCommand outside
+% argument: text in item[.]
+\newcommand{\algpx@drawInItem}[1]{%
+ \item[%
+ \whileboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@startNewCodeBoxQueue}}}}{%
+ \FSPush{algpx@codeBoxStack}{\FSTop{algpx@startNewCodeBoxQueue}}%
+ \algpx@drawCodeBox{algpx@codeBoxStyle\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxNorth-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxWest-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxEast-\FSTop{algpx@startNewCodeBoxQueue}}{algpx@codeBoxSouth-\FSTop{algpx@startNewCodeBoxQueue}}%
+ \FSPop{algpx@startNewCodeBoxQueue}%
+ \stepcounter{algpx@startedBoxesCount}%
+ }%
+ #1%
+ ]%
+ \setbool{algpx@indJustEnded}{false}%
+ \setcounter{algpx@startedBoxesCount}{0}%
+ \setcounter{algpx@endedBoxesCount}{0}%
+ \setcounter{algpx@nestedBoxedStringMaxCount}{0}%
+ \settowidth{\algpx@tmpLen}{#1}%
+ \algpx@setCodeBoxWest[\dimexpr \labelsep + \algpx@tmpLen \relax]%
+ \setbool{algpx@firstLine}{false}%
+ \setbool{algpx@executeEndVarwidth}{true}%
+ \begin{varwidth}[t]{\dimexpr \linewidth - \labelsep - \algpx@tmpLen + \leftmargin \relax}%
+ \settoheight{\algpx@tmpLen}{#1}%
+ \rule{0pt}{\algpx@tmpLen}%
+}
+
+\algnewcommand\Require{%
+ \algpx@endCodeCommand%
+ \ifnumcomp{0}{<}{\FSSize{algpx@startNewCodeBoxQueue}}{\setbool{algpx@setNorth}{true}}{}%
+ \ifboolexpr{bool{algpx@spaceRequire} and not bool{algpx@firstLine}}{%
+ \medskip%
+ }{}%
+ \algpx@drawInItem{\algorithmicrequire}%
+}
+
+\algnewcommand\Ensure{%
+ \algpx@endCodeCommand%
+ \ifnumcomp{0}{<}{\FSSize{algpx@startNewCodeBoxQueue}}{\setbool{algpx@setNorth}{true}}{}%
+ \algpx@drawInItem{\algorithmicensure}%
+}
+
+\algnewcommand\Return{\algorithmicreturn{} }
+\algnewcommand\Output{\algorithmicoutput{} }
+\algnewcommand\Call[2]{\textproc{#1}\ifstrempty{#2}{}{(#2)}}
+
+%% internal methods to format comment
+% format according to comment format
+\newcommand{\algpx@commentFormat}[1]{%
+ \ifbool{algpx@italicComments}{%
+ \textit{\textcolor{\algpx@commentColor}{#1}}%
+ }{%
+ \textcolor{\algpx@commentColor}{#1}%
+ }%
+}
+
+% get string for inline comment including begin and end markers
+\newcommand{\algpx@commentString}[1]{%
+ \algpx@commentFormat{\algpx@beginComment#1\algpx@endComment}%
+}
+
+% redefine \Comment
+\algrenewcomment[1]{%
+ \ifbool{algpx@rightComments}{%
+ \settowidth{\algpx@tmpLen}{\algpx@commentString{#1}}% set temp variable to width of comment
+ \tabto{\CurrentLineWidth}% this saves current position in \TabPrevPos and fixes spacing up to here
+ \ifdimcomp{\algpx@tmpLen}{<}{\dimexpr \linewidth - \TabPrevPos \relax}{% check whether comment fits on line
+ \tabto{\dimexpr \linewidth - \algpx@tmpLen \relax}% move position to right justify text
+ \algpx@commentString{#1}% print comment
+ }{%
+ \algpx@commentString{#1}% if it doesn't fit, just print normally, allowing line break
+ }%
+ }{%
+ \algpx@commentString{#1}% just print normally if not right justified
+ }%
+ \ignorespaces%
+}%
+
+% Long comment starting on new line.
+% Can span several lines and in contrast to \Comment, never right justified.
+\algdef{SL}[LCOMMENT]{LComment}{0}[1]{%
+ \algpx@startCodeCommandX{\algpx@commentFormat{\algpx@beginLComment}}{\algpx@commentFormat{\algpx@endLComment}}%
+ \algpx@commentFormat{#1}% print actual comment
+ \tabto{\CurrentLineWidth}% this saves current position in \TabPrevPos and fixes spacing up to here
+ \setlength{\algpx@tmpLen}{\dimexpr \linewidth - \TabPrevPos \relax}% set to remaining space on line
+ \makebox[0pt][l]{% start box here that takes no space (otherwise impacts spacing of text before)
+ \rule{\algpx@tmpLen}{0pt}% draw invisible rule from beginning of line until end of comment text
+ \algpx@commentFormat{\algpx@endLComment}% print end comment at the end
+ \algpx@setCodeBoxEast% since this takes 0 space, we have to set east of code box here explicitly
+ }%
+}%
+
+\pretocmd{\LComment}{\algpx@endCodeCommand}{}{}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Execute at beginning and end of algorithmic environment
+%
+\AtBeginEnvironment{algorithmic}{%
+ \setbool{algpx@firstLine}{true}%
+ \setbool{algpx@setNorth}{false}%
+ \setbool{algpx@executeEndVarwidth}{false}%
+ \setbool{algpx@adjustHeight}{false}%
+ \setbool{algpx@restorePrevdepth}{false}%
+ \setcounter{algpx@startedBoxesCount}{0}%
+ \setcounter{algpx@endedBoxesCount}{0}%
+}
+
+\AtEndEnvironment{algorithmic}{%
+ \algpx@endCodeCommand%
+ % Error checking
+ \ifboolexpr{test{\ifnumcomp{0}{<}{\FSSize{algpx@codeBoxStack}}} or test {\ifnumcomp{0}{<}{\FSSize{algpx@startNewCodeBoxQueue}}}}{%
+ \PackageError{algpseudocodex}{Some boxes have not ended}{}%
+ }{}%
+}