%! Package: algxpar
%! Author: Jander Moreira
%! Email =  moreira.jander@gmail.com

%! suppress = FileNotFound

\NeedsTeXFormat{LaTeX2e}[2005/12/01]
\ProvidesPackage{algxpar}[2024/10/23 v0.99.2 Algorithms with multi-line/paragraph support and some enhancements]

%% Documentation
\NewDocumentCommand{\AlgVersion}{}{0.99.2}
\NewDocumentCommand{\AlgDate}{}{2024/10/23}


%% Required packages
\RequirePackage{algorithmicx}
\RequirePackage{algpseudocode}
\RequirePackage{ragged2e}
\RequirePackage{xcolor}
\RequirePackage{fancyvrb} % to load verbatim preserving tabs
\RequirePackage{pgfopts}
\RequirePackage{amssymb}
\RequirePackage{pgfmath}
\RequirePackage{varwidth}
% \RequirePackage{ifthen}
\RequirePackage{tikz}
\usetikzlibrary{calc, arrows}
\RequirePackage{etoolbox}
% \RequirePackage{listings} % to load verbatim with tabs
% \RequirePackage{tcolorbox} % to save verbatim

%%% Internal commands
\ExplSyntaxOn

% set_keyword:nnn creates or update a keyword in a language
% #1: language (e.g., brazilian)
% #2: keyword (e.g. while)
% #3: value (e.g, enquanto)
\cs_new:Npn \set_keyword:nnn #1#2#3 {
    \tl_clear_new:c { g_keyword_#1_#2_tl }
    \tl_set:cn { g_keyword_#1_#2_tl } { #3 }
}

% get_keyword:nn returs a keyword in a language
% #1: language (e.g., brazilian)
% #2: keyword (e.g. while)
% returns: keyword text (e.g. enquanto)
\cs_new:Npn \get_keyword:nn #1#2 {
    \cs_if_exist_use:cTF { g_keyword_#1_#2_tl } { } {
        \cs_if_exist_use:cTF { g_keyword_english_#2_tl } { } {
            \msg_new:nnn { algxpar } { keyword-not-found } {
                Keyword~'#2'~not~found.
            }
            \msg_fatal:nn { algxpar } { keyword-not-found }
        }
    }
}

%%% User commands

% SetKeyword: create or update a keyword in a language
% #1: language (e.g., brazilian)
% #2: keyword (e.g. while)
% #3: value (e.g, enquanto)
\NewDocumentCommand{\SetKeyword}{ O{\axp@Language} m m }{
    \set_keyword:nnn { #1 } { #2 } { #3 }
}

% Keyword: returns a formatted keyword in the current language
% #1: keyword (e.g. while)
\NewDocumentCommand{\Keyword} { O{\axp@Language} m }{
    \mbox{\textcolor{\axp@KeywordColor}{\axp@KeywordFont\get_keyword:nn{#1}{#2}}}
}

% Constant: returns a formatted constant in the current language
% #1: keyword (e.g. True)
\NewDocumentCommand{\Constant} { m }{
    \mbox{\textcolor{\axp@ConstantColor}{\axp@ConstantFont\get_keyword:nn{\axp@Language}{#1}}}
}

% Module: returns a formatted name for a procedure ou function
% #1: name
\NewDocumentCommand{\Module} { m }{
    \mbox{\textcolor{\axp@ModuleColor}{\axp@ModuleFont#1}}
}

% CommentSymbol: returns the formatted comment symbol
\NewDocumentCommand{\CommentSymbol} { }{
    \mbox{\textcolor{\axp@CommentColor}{\axp@CommentFont\axp@CommentSymbol}}
}

% CommentSymbol: returns the formatted comment symbol right
\NewDocumentCommand{\CommentSymbolRight} { }{
    \mbox{\textcolor{\axp@CommentColor}{\axp@CommentFont\axp@CommentSymbolRight}}
}


% axp@RenewFullyExpandedDocumentCommand: fully expands argument before
%   renewing document command
% #1: macro
% #2: value
\NewDocumentCommand{\axp@RenewFullyExpandedDocumentCommand} { m m }{
    \exp_args:NNnV \RenewDocumentCommand #1 { } { #2 }
}

\ExplSyntaxOff

%% Settings
\newif\ifaxp@NoEnd\axp@NoEndfalse  % whether line with 'end' is used or not
\newif\ifaxp@IsStatement\axp@IsStatementfalse  % set in \Statep
\newif\ifaxp@ShowBoxes\axp@ShowBoxesfalse  % show parboxes for debugging
\newif\ifaxp@LineBalanceAuto  % true for 'auto'; false for 'fixed'
\newif\ifaxp@IndentLines\axp@IndentLinesfalse % draw lines in blocks


\NewDocumentCommand{\axp@DisableEnds}{}{%
    \axp@NoEndtrue%
    \RenewDocumentCommand{\ALG@noend}{}{t}%
    \algtext*{EndWhile}%
    \algtext*{EndFor}%
    \algtext*{EndLoop}%
    \algtext*{EndIf}%
    \algtext*{EndProcedure}%
    \algtext*{EndFunction}%
    \algtext*{EndSwitch}%
    \algtext*{EndCase}%
    \algtext*{EndOtherwise}%
}

\NewDocumentCommand{\axp@EnableEnds}{}{%
    \axp@NoEndfalse%
    \RenewDocumentCommand{\ALG@noend}{}{f}%
    \algrenewtext{EndWhile}{\Keyword{endwhile}}%
    \algrenewtext{EndFor}{\Keyword{endfor}}%
    \algrenewtext{EndLoop}{\Keyword{endloop}}%
    \algrenewtext{EndIf}{\Keyword{endif}}%
    \algrenewtext{EndProcedure}{\Keyword{endprocedure}}%
    \algrenewtext{EndFunction}{\Keyword{endfunction}}%
    \algrenewtext{EndSwitch}{\Keyword{endswitch}}%
    \algrenewtext{EndCase}{\Keyword{endcase}}%
    \algrenewtext{EndOtherwise}{\Keyword{endotherwise}}%
}
\axp@EnableEnds  % update end-line texts

%% General options
\pgfkeys{
    /algxpar/options/.cd,
% language
    language/.store in = \axp@Language,
% styles
    text font/.store in = \axp@TextFont,
    text color/.store in = \axp@TextColor,
    text style/.store in = \axp@TextStyle,
    comment font/.store in = \axp@CommentFont,
    comment color/.store in = \axp@CommentColor,
    comment style/.store in = \axp@CommentStyle,
    keyword font/.store in = \axp@KeywordFont,
    keyword color/.store in = \axp@KeywordColor,
    constant font/.store in = \axp@ConstantFont,
    constant color/.store in = \axp@ConstantColor,
    module font/.store in = \axp@ModuleFont,
    module color/.store in = \axp@ModuleColor,
%
    comment symbol/.store in = \axp@CommentSymbol,
    comment symbol right/.store in = \axp@CommentSymbolRight,
    comment separator width/.store in = \axp@CommentSeparatorWidth,
%
    noend/.code = {\axp@DisableEnds},
    no end/.code = {\axp@DisableEnds},
    end/.code = {\axp@EnableEnds},
%
% keywords/.code = {\pgfkeysalso{/algxpar/languages/.cd, \trim@spaces{#1}}},
    keywords/.code = {\axp@LanguageSet{#1}},
%
    algorithmic indent/.store in = \algorithmicindent,
    statement indent/.store in = \axp@StatementIndent,
    parameter indent/.store in = \axp@ParameterIndent,
%
    indent lines/.is if = axp@IndentLines,
    line style/.code = {\tikzset{line style/.style = {#1}}},
%
    show boxes/.is if = axp@ShowBoxes,
%
    comment width/.code = {%
        \axp@LineBalanceAutotrue%
        \ifthenelse{\equal{auto}{#1}}{%
            \axp@LineBalanceAutotrue%
        }{%
            \axp@LineBalanceAutofalse%
            \ifthenelse{\equal{nice}{#1}}{%
                \DeclareDocumentCommand{\axp@CommentFixedWidth}{}{0.4\linewidth}%
            }{%
                \DeclareDocumentCommand{\axp@CommentFixedWidth}{}{#1}%
            }%
        }%
    },
%
% style/.style = {\pgfkeysalso{/algxpar/styles/#}},
}

\NewDocumentCommand{\AlgSet}{ > { \TrimSpaces } m }{%
    \pgfkeys{%
        /algxpar/options/.cd,
        /utils/exec = \pgfkeysalsofrom{#1},
    }%
}


% %% Styles
% \NewDocumentCommand{\AlgStyle}{ > { \TrimSpaces } m > { \TrimSpaces m }{%
%     \pgfkeys{
%         /algxpar/style/.cd,
%         #1/.style = {#2}
%     }
% }

%% Languages and translations
\pgfkeys{
    /algxpar/languages/.cd,
    .unknown/.code = {\SetKeyword{\pgfkeyscurrentname}{#1}}
}

\NewDocumentCommand{\AlgLanguageSet}{ > { \TrimSpaces } m > { \TrimSpaces } m }{%
    \AlgSet{language = #1}%
    \pgfkeys{
        /algxpar/languages/.cd,
        #2
    }%
}
\NewDocumentCommand{\axp@LanguageSet}{ > { \TrimSpaces } m }{%
    \pgfkeys{
        /algxpar/languages/.cd,
        #1
    }
}

\input{algxpar-english.kw}  % always loads default language


% general settings defaults
\AlgSet{
    language = english,
    text font = ,
    text color = .,
    text style = \RaggedRight,
    comment font = \slshape,
    comment color = .!70,
    comment style = \RaggedRight,
    keyword font = \bfseries,
    keyword color = .,
    constant font = \scshape,
    constant color = .,
    module font = \scshape,
    module color = .,
    comment symbol = $\triangleright$,
    comment symbol right = $\triangleleft$,
    comment separator width = 1em,
    algorithmic indent = 1.5em,
    statement indent = 1em,
    parameter indent = 0pt,
    indent lines = false,
    line style = {lightgray, thick},
    show boxes = false,
    comment width = auto,
}


%% Package options
\pgfkeys{
    /algxpar/.cd,
    language/.store in = \axp@Language,
    noend/.is if = axp@NoEnd,
    .unknown/.code = {
        \axp@RenewFullyExpandedDocumentCommand{\axp@Language}{\pgfkeyscurrentname}
        \input{algxpar-\pgfkeyscurrentname.kw}
    }
}
\pgfkeys{
    /algxpar/.cd,
    language = english,
    noend = false,
}
\ProcessPgfOptions{/algxpar}
\ifaxp@NoEnd\axp@DisableEnds\fi%  globally disable 'ends'


% axp@SetToWidth: \settowidth allowing multi-line text
% #1: existing length
% #2: text
\NewDocumentCommand{\axp@SetToWidth}{ m m }{%
    \settowidth{#1}{%
        \begin{varwidth}{500cm}%  5 meters = infinity
            #2
        \end{varwidth}%
    }%
}

% axp@DefineCommand: defines command structure
% #1: keyword (e.g, while)
% #2: block text (e.g. a > 0)
% #3: complement keyword (e.g. do)
% #4: comment text
% #5: options
\NewDocumentCommand{\axp@DefineCommand}{ m m m m m }{%
    \DeclareDocumentCommand{\axp@CommandKeyword}{}{#1}%
    \DeclareDocumentCommand{\axp@CommandText}{}{#2}%
    \DeclareDocumentCommand{\axp@CommandComplementKeyword}{}{#3}%
    \DeclareDocumentCommand{\axp@CommentText}{}{#4}%
    \def\axp@CommandOptions{#5}% def: to be accepeted in \pgfkeysalsofrom
}


% axp@MakeSingleToken: texto before and after only if token has some width
% #1: text before toke
% #2: token
% #3: text after token
\newlength{\axp@TokenWidth}
\NewDocumentCommand{\axp@MakeSingleToken}{ m m m }{%
    \axp@SetToWidth{\axp@TokenWidth}{#2}%
    \ifdimcomp{\axp@TokenWidth}{>}{0pt}{#1}{}%
    #2%
    \ifdimcomp{\axp@TokenWidth}{>}{0pt}{#3}{}%
}

\newif\ifaxp@NoCommentPresent
\newlength{\axp@TextWidth}
\newlength{\axp@CommentWidth}

%%%%%%%% LINES

\NewDocumentCommand{\axp@MarkLineBegin}{}{%
    \ifbool{axp@IndentLines}{%
        \stepcounter{axp@BlockLevelCounter}%
        \tikz[remember picture] \coordinate (axp-block-start-\theaxp@BlockLevelCounter) (0, 0);%
    % \tikz[remember picture, overlay] \draw[<-] (axp-block-start-\theaxp@BlockLevelCounter) -- ++ (-4em, 0.5ex) node[anchor = east] {B:\theaxp@BlockLevelCounter};%
    }{}%
}%

\NewDocumentCommand{\axp@MarkLineEndShort}{}{%
    \ifbool{axp@IndentLines}{%
        \tikz[remember picture] \coordinate (axp-block-end-\theaxp@BlockLevelCounter) (0, 0);%
        \begin{tikzpicture}[remember picture, overlay]
            \draw[line style]
            ($ (axp-block-start-\theaxp@BlockLevelCounter) + (0.3ex, -1ex) $)
            --
            ($ (axp-block-end-\theaxp@BlockLevelCounter) +  (0.3ex, 1em) $);
        \end{tikzpicture}%
        \addtocounter{axp@BlockLevelCounter}{-1}%
    }%
}

\NewDocumentCommand{\axp@MarkLineEndCont}{}{%
    \ifbool{axp@IndentLines}{%
        \tikz[remember picture] \coordinate (axp-block-end-\theaxp@BlockLevelCounter) (0, 0);%
        \begin{tikzpicture}[remember picture, overlay]
            \draw[line style]
            ($ (axp-block-start-\theaxp@BlockLevelCounter) + (0.3ex, -1ex) $)
            --
            ($ (axp-block-end-\theaxp@BlockLevelCounter) +  (0.3ex, 1em) $);
        \end{tikzpicture}%
        \addtocounter{axp@BlockLevelCounter}{-1}%
    }%
}

\NewDocumentCommand{\axp@MarkLineEndFinal}{}{%
    \ifbool{axp@IndentLines}{%
        \tikz[remember picture] \coordinate (axp-block-end-\theaxp@BlockLevelCounter) (0, 0);%
        \begin{tikzpicture}[remember picture, overlay]
            \draw[line style]
            ($ (axp-block-start-\theaxp@BlockLevelCounter) + (0.3ex, -1ex) $)
            --
            ($ (axp-block-end-\theaxp@BlockLevelCounter)  + (0.3ex, 0) $)
            |- ++ (1ex, 0);
        \end{tikzpicture}%
        \addtocounter{axp@BlockLevelCounter}{-1}%
    }%
}

% % ***********************************************
% % For debugging!
\NewDocumentCommand{\msg}{ m O{-1} }{%
    \begin{tikzpicture}[overlay]
        \draw[black!30] (0, 0.1) -- (#2, 0.3) node[fill=black!5, anchor=east] {\scriptsize\color{darkgray}#1};
    \end{tikzpicture}%
}


% axp@CalculateDimensions: evaluate space needed for text and comments
% #1: nesting ajustment (1 when openning a block; 0 when closing)
% #2: text
% #3: comment
% sets:
% \axp@TextWidth
% \axp@CommentWidth, when needed
\newlength{\axp@FullTextWidth}
\newlength{\axp@FullCommentWidth}
\newlength{\axp@CommentSymbolWidth}
\newlength{\axp@CurrentLineWidth}
\newlength{\axp@RemainingWidth}
\NewDocumentCommand{\axp@CalculateDimensions}{ m m m }{%
    \booltrue{axp@NoCommentPresent}%
    \axp@SetToWidth{\axp@FullTextWidth}{\axp@TextFont#2}% text
    \axp@SetToWidth{\axp@FullCommentWidth}{\axp@CommentFont#3}% comment
    \ifdimcomp{\axp@FullCommentWidth}{=}{0pt}{%
    % No comments present
    % \msg{no comment!}%
        \global\booltrue{axp@NoCommentPresent}%
        % \ifbool{axp@LineBalanceAuto}{%
        \setlength{\axp@TextWidth}{
            \dimexpr \linewidth - \axp@CurrentTokenWidth - (\algorithmicindent)*(\theALG@nested - #1)
        }%
        \ifdimcomp{\axp@FullTextWidth}{<}{\axp@TextWidth}{%
            \axp@TextWidth\axp@FullTextWidth%  makes the parbox fit the actual text width
        }{}%
    % }{}
    }{%
    % Yep, we have a comment in this line
    % \msg{got a comment!}%
        \global\boolfalse{axp@NoCommentPresent}%
        \axp@SetToWidth{\axp@CommentSymbolWidth}{\hspace{\axp@CommentSeparatorWidth}\CommentSymbol~}%
        \deflength{\axp@CurrentLineWidth}{
            \linewidth - \axp@CurrentTokenWidth - (\algorithmicindent)*(\theALG@nested - #1)
        }%
        \ifbool{axp@LineBalanceAuto}{%
        % 'auto': decide here how to balance text and comment widths
            \setlength{\axp@RemainingWidth}{
                \dimexpr \axp@CurrentLineWidth - \axp@FullTextWidth - \axp@FullCommentWidth - \axp@CommentSymbolWidth
            }%
            \null%  I don't understand the difference this null makes here!
            % \msg{\the\axp@RemainingWidth}%
            \ifdimcomp{\axp@RemainingWidth}{>}{0pt}{%
            % Both text and comment fit the line
                \axp@TextWidth\axp@FullTextWidth%
                \axp@CommentWidth\axp@FullCommentWidth%
            % \msg{fits \the\axp@RemainingWidth}%
            }{%
            % Text/comment will go multi-line
            % \msg{not fit \the\axp@RemainingWidth}%
                \pgfmathsetmacro{\axp@CurrentRatio}{
                    int(round(\axp@FullTextWidth/(\axp@FullTextWidth + \axp@FullCommentWidth) * 100))
                }%
                \ifnumcomp{\axp@CurrentRatio}{<}{25}{%  never less than 0.25
                    \edef\axp@CurrentRatio{25}%
                }{%
                    \ifnumcomp{\axp@CurrentRatio}{>}{75}{%  never more than 0.75
                        \edef\axp@CurrentRatio{75}%
                    }{}%
                }%
                \pgfmathparse{
                    (100 - \axp@CurrentRatio)/100 * \axp@CurrentLineWidth - \axp@CommentSymbolWidth
                }%
                \setlength{\axp@CommentWidth}{\pgfmathresult pt}%
                \pgfmathparse{\axp@CurrentLineWidth - \axp@CommentWidth - \axp@CommentSymbolWidth}%
                \setlength{\axp@TextWidth}{\pgfmathresult pt}%
                % fine tunning the widths
                \axp@SetToWidth{\axp@CommentWidth}{%
                    \begin{varwidth}[t]{\axp@CommentWidth}%
                        \axp@CommentStyle%
                        \textcolor{\axp@CommentColor}{\axp@CommentFont#3}\strut%
                    \end{varwidth}%
                }%
                \pgfmathparse{\axp@CurrentLineWidth - \axp@CommentWidth - \axp@CommentSymbolWidth}%
                \setlength{\axp@TextWidth}{\pgfmathresult pt}%
                % \msg{\the\axp@TextWidth}%
            }%
        }{%
        % 'fixed': limit comment width
        % todo: think about using \axp@CurrentLineWidth instead of \linewidth
            \setlength{\axp@CommentWidth}{\axp@CommentFixedWidth}%
            \setlength{\axp@TextWidth}{
                \dimexpr \axp@CurrentLineWidth - \axp@CommentWidth - \axp@CommentSymbolWidth
            }%
        }%
        \setlength{\axp@RemainingWidth}{
            \dimexpr \linewidth - \axp@CurrentTokenWidth -
            (\algorithmicindent)*(\theALG@nested - #1) -
            \axp@CommentWidth - \axp@CommentSymbolWidth
        }%
    }%
}

\newcounter{cont}
\newif\ifaxp@CloseBlock
% axp@MakeCommand: builds the command (see axp@DefineCommand)
% #1 (star): star = end block; no star = begin block
\NewDocumentCommand{\axp@MakeCommand}{ s }{%
\IfBooleanTF{#1}{%
    \axp@MarkLineEndShort%
}{%
    \ifaxp@CloseBlock%
    \axp@MarkLineEndCont%
    \axp@CloseBlockfalse%
    \fi%
    \axp@MarkLineBegin%
}%
\axp@DoCommand{%  ajustment for opening/closing blocks
    \IfBooleanTF{#1}{0}{1}%
}{%  command or module+name
\axp@MakeSingleToken{}{\axp@CommandKeyword}{\ifaxp@IsModule(\else\ \fi}%
}{%  text or module arguments
\axp@CommandText\ifaxp@IsModule)\fi%
}{%  command complement
\axp@MakeSingleToken{ }{\axp@CommandComplementKeyword}{}%
}{%  comment
\axp@CommentText%
}{%  options
\axp@CommandOptions%
}%
}

%! formatter = off
\newsavebox{\axp@SaveBox}
\NewDocumentEnvironment{axp@FBox}{}{%
    \begin{lrbox}{\axp@SaveBox}%
}{%
    \end{lrbox}%
    \ifaxp@ShowBoxes%
        \begingroup%
        \setlength{\fboxrule}{0.001pt}%
        \setlength{\fboxsep}{0pt}%
        \color{.!20}\fbox{\color{.}\usebox{\axp@SaveBox}}%
        \endgroup%
    \else%
        \usebox{\axp@SaveBox}%
    \fi%
}


% axp@DoCommand: builds the command (see axp@DefineCommand)
% #1: 1 when openning block; 0 when closing
% #2: command
% #3: text
% #4: command complement
% #5: comment
% #6: options
\newlength{\axp@CurrentTokenWidth}
\NewDocumentCommand{\axp@DoCommand}{ m m m m m m }{%
\AlgSet{#6}%
% Dimensions
\axp@SetToWidth{\axp@CurrentTokenWidth}{#2}%
\axp@CalculateDimensions{#1}{{\axp@TextStyle\axp@TextFont#3}#4}{#5}%
%
% Making the line: body
#2%
    \begin{axp@FBox}%
        \ifbool{axp@IsModule}{\hspace{\axp@ParameterIndent}}{}%
        \parbox[t]{\axp@TextWidth}{%
            \ifaxp@IsStatement%
                \setlength{\hangindent}{\axp@StatementIndent}%
            \fi%
            \axp@TextStyle%
            \textcolor{\axp@TextColor}{\axp@TextFont{#3}}#4\strut%
        }%
    \end{axp@FBox}%
    % Making the line: comment
    \ifbool{axp@NoCommentPresent}{}{%
        \hspace{\axp@CommentSeparatorWidth}\hfill\CommentSymbol~%
        \begin{axp@FBox}%
            \ifbool{axp@LineBalanceAuto}{%
                \begin{varwidth}[t]{\axp@CommentWidth}%
                    \axp@CommentStyle%
                    \textcolor{\axp@CommentColor}{\axp@CommentFont#5}\strut%
                \end{varwidth}%
            }{%
                \parbox[t]{\axp@CommentWidth}{%
                    \axp@CommentStyle%
                    \textcolor{\axp@CommentColor}{\axp@CommentFont#5}\strut%
                }%
            }%
        \end{axp@FBox}%
    }%
}


%% Keyword quick references
\NewDocumentCommand{\To}{}{\axp@MakeSingleToken{}{\Keyword{to}}{ }}
\NewDocumentCommand{\DownTo}{}{\axp@MakeSingleToken{}{\Keyword{downto}}{ }}
\NewDocumentCommand{\Step}{}{\axp@MakeSingleToken{}{\Keyword{step}}{ }}
\NewDocumentCommand{\Continue}{}{\Keyword{continue}}
\NewDocumentCommand{\Break}{}{\Keyword{break}}
\RenewDocumentCommand{\Return}{}{\axp@MakeSingleToken{}{\Keyword{return}}{ }}

\NewDocumentCommand{\ByRef}{}{\Constant{byref}}
\NewDocumentCommand{\ByValue}{}{\Constant{byvalue}}

\NewDocumentCommand{\True}{}{\Constant{true}}
\NewDocumentCommand{\False}{}{\Constant{false}}
\NewDocumentCommand{\Nil}{}{\Constant{nil}}

\newcommand{\Id}[1]{\ensuremath{\emph{\rmfamily#1}}}
% \newcommand{\TextString}[1]{\textrm{\normalfont``{\ttfamily\mbox{#1}}''}}
% \algnewcommand{\VisibleSpace}{\textrm{\color{black!70}\textvisiblespace}}

%% Headings
\NewDocumentCommand{\Description}{}{\item[\Keyword{description}:]}
\NewDocumentCommand{\Input}{}{\item[\Keyword{input}:]}
\NewDocumentCommand{\Output}{}{\item[\Keyword{output}:]}
\RenewDocumentCommand{\Ensure}{}{\item[\Keyword{ensure}:]}
\RenewDocumentCommand{\Require}{}{\item[\Keyword{require}:]}

% Read, write
\NewDocumentCommand{\Set}{ m m }{%
\PackageWarning{alxpar}{The macro \string\Set\ is no longer supported.}%
\Id{#1} \gets #2%
}
\NewDocumentCommand{\Read}{}{\Keyword{read} }
\NewDocumentCommand{\Write}{}{\Keyword{write} }

% %% Comments
\algnewcommand{\CommentIn}[1]{%
\begin{axp@FBox}
\textcolor{\axp@CommentColor}{\CommentSymbol~\axp@CommentFont#1~\CommentSymbolRight}%
\end{axp@FBox}%
}
\NewDocumentCommand{\Commentl}{ m D<>{} }{%
\begingroup%
\AlgSet{#2}%
\textcolor{\axp@CommentColor}{\CommentSymbol~\axp@CommentFont#1\strut}%
\endgroup%
}
\RenewDocumentCommand{\Comment}{ m D<>{} }{%
\hfill\Commentl{#1}<#2>%
}

\newlength{\axp@CurrentIndent}

\newcounter{axp@BlockCounter}
\newcounter{axp@BlockLevelCounter}
\NewDocumentCommand{\axp@BeginGroup}{}{%
\begingroup%
}
\NewDocumentCommand{\axp@EndGroup}{}{%
\global\edef\axp@SaveIndent{\the\ALG@tlm}%
\endgroup%
\setlength{\ALG@tlm}{\axp@SaveIndent}%
}


%% Statep: statement
% #1: old style comment
% #2: text
% #3: comments
% #4: options
\NewDocumentCommand{\Statep}{ O{} +m O{} D<>{} }{%
\axp@IsStatementtrue%
\State\axp@DoCommand{1}{}{#2}{}{#1#3}{#4}%
\axp@IsStatementfalse%
}
\RenewDocumentCommand{\Statex}{}{%
\item[]\strut%
}


%% While
\algblockdefx[While]{While}{EndWhile}{\axp@MakeCommand}{\axp@MakeCommand*}
% #1: old style comment
% #2: text
% #3: comment
% #4: options
\RenewDocumentCommand{\While}{ O{} m O{} D<>{} }{%
\axp@BeginGroup%
\axp@DefineCommand{\Keyword{while}}{#2}{\Keyword{do}}{#1#3}{#4}%
\ALG@makeentity{While}%
}
% #1: comment
% #2: options
\RenewDocumentCommand{\EndWhile}{ O{} D<>{} }{%
\axp@DefineCommand{\Keyword{endwhile}}{}{}{#1}{#2}%
\ALG@makeentity{EndWhile}%
\ifaxp@NoEnd\axp@MarkLineEndFinal\fi%
\axp@EndGroup%
}


%% Repeat
\algblockdefx[Repeat]{Repeat}{Until}{\axp@MakeCommand}{\axp@MakeCommand*}
% #1: comments
% #2: options
\RenewDocumentCommand{\Repeat}{ O{} D<>{} }{%
\axp@BeginGroup%
\axp@DefineCommand{\Keyword{repeat}}{}{}{#1}{#2}%
\ALG@makeentity{Repeat}%
}
% #1: old style comment
% #2: text
% #3: comment
% #4: options
\RenewDocumentCommand{\Until}{ O{} m O{} D<>{} }{%
\axp@DefineCommand{\Keyword{until}}{#2}{}{#1#3}{#4}%
\ALG@makeentity{Until}%
\ifaxp@NoEnd\axp@MarkLineEndFinal\fi%
\axp@EndGroup%
}

%% Loop
\algblockdefx[Loop]{Loop}{EndLoop}{\axp@MakeCommand}{\axp@MakeCommand*}
% #1: comment
% #2: options
\RenewDocumentCommand{\Loop}{ O{} D<>{} }{%
\axp@BeginGroup%
\axp@DefineCommand{\Keyword{loop}}{}{}{#1}{#2}%
\ALG@makeentity{Loop}%
}
% #1: comment
% #2: options
\RenewDocumentCommand{\EndLoop}{ O{} D<>{} }{%
\axp@DefineCommand{\Keyword{endloop}}{}{}{#1}{#2}%
\ALG@makeentity{EndLoop}%
\ifaxp@NoEnd\axp@MarkLineEndFinal\fi%
\axp@EndGroup%
}


%% If
\algblockdefx[If]{If}{EndIf}{\axp@MakeCommand}{\axp@MakeCommand*}
% + else if
\algcblockdefx[If]{If}{ElsIf}{EndIf}{\axp@MakeCommand}{\axp@MakeCommand*}
% + else
\algcblockdefx[If]{If}{Else}{EndIf}[1][]{\axp@MakeCommand}{\axp@MakeCommand*}
% #1: old style comment
% #2: text
% #3: comment
% #4: options
\RenewDocumentCommand{\If}{ O{} m O{} D<>{} }{%
\axp@BeginGroup%
\axp@DefineCommand{\Keyword{if}}{#2}{\Keyword{then}}{#1#3}{#4}%
\ALG@makeentity{If}%
}
% #1: old style comment
% #2: text
% #3: comment
% #4: options
\RenewDocumentCommand{\ElsIf}{ O{} m O{} D<>{} }{%
\axp@DefineCommand{\Keyword{else}~\Keyword{if}}{#2}{\Keyword{then}}{#1#3}{#4}%
\axp@CloseBlocktrue%
\ALG@makeentity{ElsIf}%
}
% #1: comment
% #2: options
\RenewDocumentCommand{\Else}{ O{} D<>{} }{%
\axp@DefineCommand{\Keyword{else}}{}{}{#1}{#2}%
\axp@CloseBlocktrue%
\ALG@makeentity{Else}%
}
% #1: comment
% #2: options
\RenewDocumentCommand{\EndIf}{ O{} D<>{} }{%
\axp@DefineCommand{\Keyword{endif}}{}{}{#1}{#2}%
\ALG@makeentity{EndIf}%
\ifaxp@NoEnd\axp@MarkLineEndFinal\fi%
\axp@EndGroup%
}


%% Switch
\algblockdefx[Switch]{Switch}{EndSwitch}{\axp@MakeCommand}{\axp@MakeCommand*}
% + case
\algblockdefx[Case]{Case}{EndCase}{\axp@MakeCommand}{\axp@MakeCommand*}
% + otherwise
\algblockdefx[Otherwise]{Otherwise}{EndOtherwise}{\axp@MakeCommand}{\axp@MakeCommand*}
% #1: old style comment
% #2: text
% #3: comment
% #4: options
\RenewDocumentCommand{\Switch}{ O{} m O{} D<>{} }{%
\axp@BeginGroup
\axp@DefineCommand{\Keyword{switch}}{#2}{}{#1#3}{#4}%
\ALG@makeentity{Switch}%
}
% #1: comment
% #2: options
\RenewDocumentCommand{\EndSwitch}{ O{} D<>{} }{%
\axp@DefineCommand{\Keyword{endswitch}}{}{}{#1}{#2}%
\ALG@makeentity{EndSwitch}%
\ifaxp@NoEnd\axp@MarkLineEndFinal\fi%
\axp@EndGroup
}
% #1: old style comment
% #2: text
% #3: comment
% #4: options
\RenewDocumentCommand{\Case}{ O{} m O{} D<>{} }{%
\axp@BeginGroup
\axp@DefineCommand{\Keyword{case}}{#2}{\Keyword{do}}{#1#3}{#4}%
\ALG@makeentity{Case}%
}
% #1: comment
% #2: options
\RenewDocumentCommand{\EndCase}{ O{} D<>{} }{%
\axp@DefineCommand{\Keyword{endcase}}{}{}{#1}{#2}%
\ALG@makeentity{EndCase}%
\ifaxp@NoEnd\axp@MarkLineEndFinal\fi%
\axp@EndGroup
}
% #1: comment
% #2: options
\RenewDocumentCommand{\Otherwise}{ O{} D<>{} }{%
\axp@BeginGroup
\axp@DefineCommand{\Keyword{otherwise}}{}{}{#1}{#2}%
\ALG@makeentity{Otherwise}%
}
% #1: comment
% #2: options
\RenewDocumentCommand{\EndOtherwise}{ O{} D<>{} }{%
\axp@DefineCommand{\Keyword{endotherwise}}{}{}{#1}{#2}%
\ALG@makeentity{EndOtherwise}%
\ifaxp@NoEnd\axp@MarkLineEndFinal\fi%
\axp@EndGroup
}


% \newcommand{\Range}[3][]{%
%     \ensuremath{%
%         #2%
%         \def\temp{#1}%
%         \mathcal{\ldotp\ldotp}#3
%         \ifx\temp\empty\relax\else{\ensuremath{\mathcal{:}#1}}\fi%
%     }%
% }


%% For, for each, for all
\algblockdefx[For]{For}{EndFor}{\axp@MakeCommand}{\axp@MakeCommand*}
\algblockdefx[For]{ForEach}{EndFor}{\axp@MakeCommand}{\axp@MakeCommand*}
\algblockdefx[For]{ForAll}{EndFor}{\axp@MakeCommand}{\axp@MakeCommand*}
% #1: old style comment
% #2: text
% #3: comment
% #4: options
\RenewDocumentCommand{\For}{ O{} m O{} D<>{} }{%
\axp@BeginGroup
\axp@DefineCommand{\Keyword{for}}{#2}{\Keyword{do}}{#1#3}{#4}%
\ALG@makeentity{For}%
}
% #1: old style comment
% #2: text
% #3: comment
% #4: options
\RenewDocumentCommand{\ForEach}{ O{} m O{} D<>{} }{%
\axp@BeginGroup
\axp@DefineCommand{\Keyword{foreach}}{#2}{\Keyword{do}}{#1#3}{#4}%
\ALG@makeentity{ForEach}%
}
% #1: old style comment
% #2: text
% #3: comment
% #4: options
\RenewDocumentCommand{\ForAll}{ O{} m O{} D<>{} }{%
\axp@BeginGroup
\axp@DefineCommand{\Keyword{forall}}{#2}{\Keyword{do}}{#1#3}{#4}%
\ALG@makeentity{For}%
}
% #1: comment
% #2: options
\RenewDocumentCommand{\EndFor}{ O{} D<>{} }{%
\axp@DefineCommand{\Keyword{endfor}}{}{}{#1}{#2}%
\ALG@makeentity{EndFor}%
\ifaxp@NoEnd\axp@MarkLineEndFinal\fi%
\axp@EndGroup
}


%% Procedure, function, calls
\newif\ifaxp@IsModule
\algblockdefx[Procedure]{Procedure}{EndProcedure}{\axp@MakeCommand}{\axp@MakeCommand*}
% #1: old style comment
% #2: name
% #3: arguments
% #4: comment
% #5: options
\RenewDocumentCommand{\Procedure}{ O{} m m O{} D<>{} }{%
\axp@BeginGroup
\axp@IsModuletrue%
\axp@DefineCommand{\Keyword{procedure}~\Module{#2}}{#3}{}{#1#4}{#5}%
\ALG@makeentity{Procedure}%
\axp@IsModulefalse%
}
% #1: comment
% #2: options
\RenewDocumentCommand{\EndProcedure}{ O{} D<>{} }{%
\axp@DefineCommand{\Keyword{endprocedure}}{}{}{#1}{#2}%
\axp@MarkLineEndFinal%
\ALG@makeentity{EndProcedure}%
\axp@EndGroup
}

\algblockdefx[Function]{Function}{EndFunction}{\axp@MakeCommand}{\axp@MakeCommand*}
% #1: old style comment
% #2: name
% #3: arguments
% #4: comment
% #5: options
\RenewDocumentCommand{\Function}{ O{} m m O{} D<>{} }{%
\axp@BeginGroup
\axp@IsModuletrue%
\axp@DefineCommand{\Keyword{function}~\Module{#2}}{#3}{}{#1#4}{#5}%
\ALG@makeentity{Function}%
\axp@IsModulefalse%
}
% #1: comment
% #2: options
\RenewDocumentCommand{\EndFunction}{ O{} D<>{} }{%
\axp@DefineCommand{\Keyword{endfunction}}{}{}{#1}{#2}%
\axp@MarkLineEndFinal%
\ALG@makeentity{EndFunction}%
\axp@EndGroup
}

\RenewDocumentCommand{\Call}{ m m D<>{} }{%
\begingroup%
\AlgSet{#3}%
\Module{#1}\textcolor{\axp@TextColor}{\axp@TextFont(#2)}%
\endgroup%
}


%% NewLine
\newcommand{\NewLine}{\\}

% %% DefineCode, UseCode, \ShowCode
% \newenvironment{DefineCode}[1]
% {\begingroup\tcbverbatimwrite{\jobname_code_#1.tmp}}
% {\endtcbverbatimwrite\endgroup}
% \newcommand{\UseCode}[1]{\input{\jobname_code_#1.tmp}}
% \newcommand{\ShowCode}[2][]{{\small\VerbatimInput[tabsize=4, #1]%
% {\jobname_code_#2.tmp}}}
%
% \algrenewcommand{\alglinenumber}[1]{%
%     \hspace{-1.5em}\color{black!35}{\scriptsize#1}\raisebox{0.2ex}{\tiny$\blacktriangleright$}%
% }
%
%% axp@algparbox

%% Adding options to the 'algorithmic' environment
\NewCommandCopy{\axp@AlgorithmicxAlgorithmic}{\algorithmic}
\NewCommandCopy{\axp@AlgorithmicxEndAlgorithmic}{\endalgorithmic}
\RenewDocumentCommand{\algorithmic}{ O{} D<>{} }{%
\begingroup%
\AlgSet{#2}%
\axp@AlgorithmicxAlgorithmic[#1]%
}
\RenewDocumentCommand{\endalgorithmic}{}{%
\axp@AlgorithmicxEndAlgorithmic%
\endgroup%
}

\endinput
