%% algpseudocodex.sty
%% Copyright 2017, 2020-2021 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}[2021-12-05 v1.0.1 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{}{}%
}

% execute before printing end if etc.
\newcommand{\algpx@startEndBlockCommand}{%
	% add space for indentation because of how ALG@nested is computed
	\algpx@startCodeCommandX{}{\hspace*{\algorithmicindent}}%
}

% 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@startEndBlockCommand\algorithmicend\ \algorithmicwhile%
}
\algdef{SE}[FOR]{For}{EndFor}[1]{%
	\algpx@startIndent\algpx@startCodeCommand\algorithmicfor\ #1\ \algorithmicdo%
}{%
	\algpx@endIndent\algpx@startEndBlockCommand\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@startEndBlockCommand\algorithmicend\ \algorithmicloop%
}
\algdef{SE}[REPEAT]{Repeat}{Until}{%
	\algpx@startIndent\algpx@startCodeCommand\algorithmicrepeat%
}[1]{%
	\algpx@endIndent[2]\algpx@startEndBlockCommand\algorithmicuntil\ #1%
}
\algdef{SE}[IF]{If}{EndIf}[1]{%
	\algpx@startIndent\algpx@startCodeCommand\algorithmicif\ #1\ \algorithmicthen%
}{%
	\algpx@endIndent\algpx@startEndBlockCommand\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@startEndBlockCommand\algorithmicend\ \algorithmicprocedure%
}
\algdef{SE}[FUNCTION]{Function}{EndFunction}[2]{%
	\algpx@startIndent\algpx@startCodeCommand\algorithmicfunction\ \textproc{#1}\ifstrempty{#2}{}{(#2)}%
}{%
	\algpx@endIndent\algpx@startEndBlockCommand\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}{}%
	}{}%
}
