diff options
author | Karl Berry <karl@freefriends.org> | 2020-08-17 20:58:45 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2020-08-17 20:58:45 +0000 |
commit | 6df02fac79cff54b64d93b90e234904331b6d7bf (patch) | |
tree | f1f2bba9cdba7c86bb2be98299615d416de40f1d | |
parent | ca2a3cf1cffa8b48f35aaa7a5dac389c0a95a79b (diff) |
algpseudocodex (17aug20)
git-svn-id: svn://tug.org/texlive/trunk@56125 c570f23f-e606-0410-a88d-b1316a301751
-rw-r--r-- | Master/texmf-dist/doc/latex/algpseudocodex/README.md | 4 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/algpseudocodex/documentation.pdf | bin | 0 -> 363697 bytes | |||
-rw-r--r-- | Master/texmf-dist/doc/latex/algpseudocodex/documentation.tex | 683 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/algpseudocodex/algpseudocodex.sty | 735 | ||||
-rwxr-xr-x | Master/tlpkg/bin/tlpkg-ctan-check | 3 | ||||
-rw-r--r-- | Master/tlpkg/tlpsrc/algpseudocodex.tlpsrc | 0 | ||||
-rw-r--r-- | Master/tlpkg/tlpsrc/collection-mathscience.tlpsrc | 1 |
7 files changed, 1425 insertions, 1 deletions
diff --git a/Master/texmf-dist/doc/latex/algpseudocodex/README.md b/Master/texmf-dist/doc/latex/algpseudocodex/README.md new file mode 100644 index 00000000000..67a4fe8a716 --- /dev/null +++ b/Master/texmf-dist/doc/latex/algpseudocodex/README.md @@ -0,0 +1,4 @@ +# algpseudocodex +This package allows typesetting pseudocode in LaTeX. It is based on algpseudocode from the algorithmicx package and uses the same syntax, but adds several new features and improvements. Notable features include customizable indent guide lines and the ability to draw boxes around parts of the code for highlighting differences. This package also has better support for long code lines spanning several lines and improved comments. + +This material is subject to the LATEX Project Public License 1.3c. diff --git a/Master/texmf-dist/doc/latex/algpseudocodex/documentation.pdf b/Master/texmf-dist/doc/latex/algpseudocodex/documentation.pdf Binary files differnew file mode 100644 index 00000000000..f83ae1c374f --- /dev/null +++ b/Master/texmf-dist/doc/latex/algpseudocodex/documentation.pdf diff --git a/Master/texmf-dist/doc/latex/algpseudocodex/documentation.tex b/Master/texmf-dist/doc/latex/algpseudocodex/documentation.tex new file mode 100644 index 00000000000..fed9558e4ad --- /dev/null +++ b/Master/texmf-dist/doc/latex/algpseudocodex/documentation.tex @@ -0,0 +1,683 @@ +%% documentation.tex +%% Copyright 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. + +\documentclass[11pt,a4paper,USenglish]{article} +\usepackage[T1]{fontenc} +\usepackage{babel} +\usepackage[utf8]{inputenc} +\usepackage[margin=1.0in]{geometry} +\usepackage{microtype} +\usepackage{xcolor} +\usepackage{algpseudocodex} + +\usepackage[colorlinks,allcolors=blue!70!black]{hyperref} +\usepackage[capitalise,nameinlink,noabbrev,compress]{cleveref} + +\title{\bf{Algpseudocodex Package Documentation}} +\author{Christian Matt \\ \url{https://github.com/chrmatt/algpseudocodex}} +\date{\today\\v1.0} + +\begin{document} + +\maketitle + +\begin{abstract} + This package allows typesetting pseudocode in \LaTeX. It is based on \texttt{algpseudocode} from the \texttt{algorithmicx} package and uses the same syntax, but adds several new features and improvements. Notable features include customizable indent guide lines and the ability to draw boxes around parts of the code for highlighting differences. This package also has better support for long code lines spanning several lines and improved comments. +\end{abstract} + +\newpage + +\tableofcontents + +\newpage + +\section{Basic Usage} +To use the package, load it in your preamble: +\begin{verbatim} + \usepackage{algpseudocodex} +\end{verbatim} + +Basic usage is identical to \texttt{algpseudocode} from the \texttt{algorithmicx} package. Pseudocode written for that package should also be compatible with \texttt{algpseudocodex}. + +\subsection{Algorithmic Block} +Pseudocode can be typeset inside a algorithmic blocks: +\begin{verbatim} + \begin{algorithmic}[line numbering] + ... + \end{algorithmic} +\end{verbatim} +The optional argument specifies how lines are numbered. $0$ means no numbering, $n > 0$ means every $n$th line gets a number. The default is $0$, i.e., no line numbers will be typeset if no optional argument is provided. + +\subsection{Simple Statements and Commands} +Statements start with \verb|\State|. The command \verb|\Statex| can be used to start a new line that does not get a new line number. + +The commands \verb|\Return| and \verb|\Output| can be used for return values of functions and outputs. They do not start a new line on their own, so they need to be used together with \verb|\State|. + +The \verb|\Call| command is used for procedure calls. It takes two arguments: The first one is the name of the procedure and the second one are the arguments. + +\subsubsection*{Example} +\begin{minipage}[t]{0.45\textwidth} + \begin{verbatim} + \begin{algorithmic}[1] + \State first line + \Statex continuing first line + \State \Call{Proc}{a1, a2} + \State \Output Hello World! + \end{algorithmic} + \end{verbatim} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \begin{algorithmic}[1] + \State first line + \Statex continuing first line + \State \Call{Proc}{a1, a2} + \State \Output Hello World! + \end{algorithmic} +\end{minipage} + + +\subsection{Blocks} +Blocks are used for loops, conditional statements, and functions. Blocks can also be nested within other blocks. + +\subsubsection{While Loop} +\begin{minipage}[t]{0.45\textwidth} + \begin{verbatim} + \While{condition} + \State body + \EndWhile + \end{verbatim} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \begin{algorithmic} + \While{condition} + \State body + \EndWhile + \end{algorithmic} +\end{minipage} + + +\subsubsection{For Loop} +\begin{minipage}[t]{0.45\textwidth} + \begin{verbatim} + \For{$n = 1, \dots, 10$} + \State body + \EndFor + \end{verbatim} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \begin{algorithmic} + \For{$n = 1, \dots, 10$} + \State body + \EndFor + \end{algorithmic} +\end{minipage} + +\subsubsection{For-All Loop} +\begin{minipage}[t]{0.45\textwidth} + \begin{verbatim} + \ForAll{$n \in \{1, \dots, 10\}$} + \State body + \EndFor + \end{verbatim} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \begin{algorithmic} + \ForAll{$n \in \{1, \dots, 10\}$} + \State body + \EndFor + \end{algorithmic} +\end{minipage} + +\subsubsection{Loop} +\begin{minipage}[t]{0.45\textwidth} + \begin{verbatim} + \Loop + \State body + \EndLoop + \end{verbatim} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \begin{algorithmic} + \Loop + \State body + \EndLoop + \end{algorithmic} +\end{minipage} + +\subsubsection{Repeat-Until Loop} +\begin{minipage}[t]{0.45\textwidth} + \begin{verbatim} + \Repeat + \State body + \Until{$n > 10$} + \end{verbatim} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \begin{algorithmic} + \Repeat + \State body + \Until{$n > 10$} + \end{algorithmic} +\end{minipage} + +\subsubsection{If Statement} +\begin{minipage}[t]{0.45\textwidth} + \begin{verbatim} + \If{condition} + \State body + \ElsIf{condition} + \State body + \Else + \State body + \EndIf + \end{verbatim} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \begin{algorithmic} + \If{condition} + \State body + \ElsIf{condition} + \State body + \Else + \State body + \EndIf + \end{algorithmic} +\end{minipage} + +\bigskip +The \verb|\ElsIf| and \verb|\Else| parts are optional. + + +\subsubsection{Procedure} +\begin{minipage}[t]{0.45\textwidth} + \begin{verbatim} + \Procedure{name}{parameters} + \State body + \EndProcedure + \end{verbatim} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \begin{algorithmic} + \Procedure{name}{parameters} + \State body + \EndProcedure + \end{algorithmic} +\end{minipage} + + +\subsubsection{Function} +\begin{minipage}[t]{0.45\textwidth} + \begin{verbatim} + \Function{name}{parameters} + \State body + \EndFunction + \end{verbatim} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \begin{algorithmic} + \Function{name}{parameters} + \State body + \EndFunction + \end{algorithmic} +\end{minipage} + + +\subsection{Require and Ensure} +To specify conditions on the inputs and outputs of an algorithm, \verb|\Require| and \verb|\Ensure| can be used. + +\subsubsection*{Example} +\begin{minipage}[t]{0.45\textwidth} + \begin{verbatim} + \begin{algorithmic}[1] + \Require $x \in \{0,1\}$ + \Ensure $y \in \{1,2\}$ + \State $y \gets x+1$ + \State \Return $y$ + \end{algorithmic} + \end{verbatim} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \begin{algorithmic}[1] + \Require $x \in \{0,1\}$ + \Ensure $y \in \{1,2\}$ + \State $y \gets x+1$ + \State \Return $y$ + \end{algorithmic} +\end{minipage} + + +\subsection{Comments} +There are two ways to typeset code comments: The command \verb|\Comment| can be used to add shorts comments to the end of the current line. The command \verb|\LComment| can be used to typeset long comments that can span multiple lines. Comments with \verb|\LComment| start on a new line. + +\subsubsection*{Example} +\begin{minipage}[t]{0.45\textwidth} + \begin{verbatim} + \begin{algorithmic}[1] + \State $x \gets y^2$ + \LComment{The next two lines + increment both $x$ and $y$.} + \State $x \gets x + 1$ + \Comment{Increment $x$.} + \State $y \gets y + 1$ + \Comment{Increment $y$.} + \end{algorithmic} + \end{verbatim} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \begin{algorithmic}[1] + \State $x \gets y^2$ + \LComment{The next two lines + increment both $x$ and $y$.} + \State $x \gets x + 1$ + \Comment{Increment $x$.} + \State $y \gets y + 1$ + \Comment{Increment $y$.} + \end{algorithmic} +\end{minipage} + + +\section{Boxes} +A unique feature of the \texttt{algpseudocodex} package is the ability to draw boxes around pieces of code. There are two different methods to do so: One for drawing boxes around multiple lines of code, and another one for drawing a box around a string on a single line of code. + +\subsection{Boxes Around Multiple Lines of Code} +The command \verb|\BeginBox[style]| is used to set the beginning of the box. The optional argument determines the style of the drawn box. The boxes are drawn using TikZ, so any TikZ style can be used. The default style can be changed as described in \cref{sec:defBoxStyle}. +The command \verb|\EndBox| is used to set the end of the last started box. Boxes can be nested arbitrarily, but every \verb|\BeginBox| needs a matching \verb|\EndBox|. + +\subsubsection*{Example} +\begin{minipage}[t]{0.45\textwidth} + \begin{verbatim} + \begin{algorithmic} + \BeginBox + \State first line + \BeginBox[fill=yellow] + \State second line + \State another line + \EndBox + \EndBox + \BeginBox[draw=blue,dashed] + \State last line + \EndBox + \end{algorithmic} + \end{verbatim} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \begin{algorithmic} + \BeginBox + \State first line + \BeginBox[fill=yellow] + \State second line + \State another line + \EndBox + \EndBox + \BeginBox[draw=blue,dashed] + \State last line + \EndBox + \end{algorithmic} +\end{minipage} + + +\subsection{Boxes Inside Single Line} +The command \verb|\BoxedString[style]{text}| is used to typeset text with a box around it. The optional argument determines the style of the box, as in \verb|\BeginBox|. The default style is the same as for \verb|\BeginBox|. + +\subsubsection*{Example} +\begin{minipage}[t]{0.45\textwidth} + \begin{verbatim} + \begin{algorithmic} + \State first line + \State second line with + \BoxedString[fill=yellow]{box} + \State last line + \end{algorithmic} + \end{verbatim} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \begin{algorithmic} + \State first line + \State second line with + \BoxedString[fill=yellow]{box} + \State last line + \end{algorithmic} +\end{minipage} + + +\section{Package Options} +When loading \texttt{algpseudocodex} the options describe in this section can be set. They syntax for setting \verb|option1| to \verb|value1| and \verb|option2| to \verb|value2| is: +\begin{verbatim} + \usepackage[option1=value1,option2=value2]{algpseudocodex} +\end{verbatim} + +\subsection{noEnd} +\begin{description} + \item[possible values:] \verb|true|, \verb|false| + \item[default:] \verb|true| +\end{description} +If \verb|false|, the end of blocks are marked with the expression ``end'' followed by the name of the block. + +\subsubsection*{Example} +\begin{minipage}[t]{0.45\textwidth} + \verb|noEnd=false|: + \begin{algorithmic} + \makeatletter + \setbool{algpx@noEnd}{false}% + \algtext{EndIf}{\algpx@endIndent\algpx@startCodeCommand\algorithmicend\ \algorithmicif% + \algpx@startIndent% \EndIf ends another indent. Start fake one here to handle that. + } + \makeatother + \If{$x > 0$} + \State $x \gets x - 1$ + \EndIf + \end{algorithmic} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \verb|noEnd=true|: + \begin{algorithmic} + \If{$x > 0$} + \State $x \gets x - 1$ + \EndIf + \end{algorithmic} +\end{minipage} + + +\subsection{indLines} +\begin{description} + \item[possible values:] \verb|true|, \verb|false| + \item[default:] \verb|true| +\end{description} +If \verb|true|, indent guide lines are drawn. The style of the lines can be customized as described in \cref{sec:indStyle}. + +\subsubsection*{Example} +\begin{minipage}[t]{0.45\textwidth} + \verb|indLines=false|: + \begin{algorithmic} + \makeatletter + \setbool{algpx@indLines}{false}% + \makeatother + \If{$x > 0$} + \State $x \gets x - 1$ + \EndIf + \end{algorithmic} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \verb|indLines=true|: + \begin{algorithmic} + \If{$x > 0$} + \State $x \gets x - 1$ + \EndIf + \end{algorithmic} +\end{minipage} + + +\subsection{spaceRequire} +\begin{description} + \item[possible values:] \verb|true|, \verb|false| + \item[default:] \verb|true| +\end{description} +If \verb|true|, vertical space is added before every \verb|\Require| except the one on the first line. This is useful for specifying different behaviors depending on the provided input. + +\subsubsection*{Example} +\begin{minipage}[t]{0.45\textwidth} + \verb|spaceRequire=false|: + \begin{algorithmic} + \makeatletter + \setbool{algpx@spaceRequire}{false}% + \makeatother + \Require $x \in \{0,1\}$ + \State \Return $x$ + \Require $x \in \{1,2\}$ + \State \Return $x-1$ + \end{algorithmic} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \verb|spaceRequire=true|: + \begin{algorithmic} + \Require $x \in \{0,1\}$ + \State \Return $x$ + \Require $x \in \{1,2\}$ + \State \Return $x-1$ + \end{algorithmic} +\end{minipage} + + +\subsection{italicComments} +\begin{description} + \item[possible values:] \verb|true|, \verb|false| + \item[default:] \verb|true| +\end{description} +If \verb|true|, all comments are typeset in italic font. If \verb|false|, comments are typeset in roman font. + +\subsubsection*{Example} +\begin{minipage}[t]{0.45\textwidth} + \verb|italicComments=false|: + \begin{algorithmic} + \makeatletter + \setbool{algpx@italicComments}{false}% + \makeatother + \LComment{Long comment.} + \State $x \gets 0$ \Comment{Short comment.} + \end{algorithmic} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \verb|italicComments=true|: + \begin{algorithmic} + \LComment{Long comment.} + \State $x \gets 0$ \Comment{Short comment.} + \end{algorithmic} +\end{minipage} + + +\subsection{rightComments} +\begin{description} + \item[possible values:] \verb|true|, \verb|false| + \item[default:] \verb|true| +\end{description} +If \verb|true|, comments typeset with \verb|\Comment| are right justified on the current line. If a comment does not fit on the current line, no justification is applied. If \verb|false|, all comments are typeset right after the end of the current line. + +Does not affect long comments typeset with \verb|\LComment|. + +\subsubsection*{Example} +\begin{minipage}[t]{0.45\textwidth} + \verb|rightComments=false|: + \begin{algorithmic} + \makeatletter + \setbool{algpx@rightComments}{false}% + \makeatother + \LComment{No effect on long comments.} + \State $x \gets 0$ \Comment{Short comment.} + \State $x \gets x^2$ \Comment{Does not fit on the current line and is thus not justified.} + \end{algorithmic} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \verb|rightComments=true|: + \begin{algorithmic} + \LComment{No effect on long comments.} + \State $x \gets 0$ \Comment{Short comment.} + \State $x \gets x^2$ \Comment{Does not fit on the current line and is thus not justified.} + \end{algorithmic} +\end{minipage} + + +\subsection{commentColor} +\begin{description} + \item[possible values:] Any color that can be used in \verb|\textcolor|. + \item[default:] \verb|gray| +\end{description} +Defines the color in which comments are typeset. + +\subsubsection*{Example} +\begin{minipage}[t]{0.45\textwidth} + \verb|commentColor=black|: + \begin{algorithmic} + \makeatletter + \renewcommand{\algpx@commentColor}{black}% + \makeatother + \LComment{Long comment.} + \State $x \gets 0$ \Comment{Short comment.} + \end{algorithmic} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \verb|commentColor=blue|: + \begin{algorithmic} + \makeatletter + \renewcommand{\algpx@commentColor}{blue}% + \makeatother + \LComment{Long comment.} + \State $x \gets 0$ \Comment{Short comment.} + \end{algorithmic} +\end{minipage} + + +\subsection{beginComment and endComment} +\begin{description} + \item[possible values:] Any string that can be typeset in text mode. + \item[default:] \verb|$\triangleright$~| and (empty) +\end{description} +Used to indicate the beginning and end of comments typeset with \verb|\Comment|, respectively. + +\subsubsection*{Example} +\begin{minipage}[t]{0.45\textwidth} + \verb|beginComment=//~|: + \begin{algorithmic} + \makeatletter + \renewcommand{\algpx@beginComment}{//~}% + \makeatother + \LComment{Long comment.} + \State $x \gets 0$ \Comment{Short comment.} + \end{algorithmic} +\end{minipage} +\hfill +\begin{minipage}[t]{0.45\textwidth} + \verb|beginComment=/*~|, \verb|endComment=~*/|: + \begin{algorithmic} + \makeatletter + \renewcommand{\algpx@beginComment}{/*~}% + \renewcommand{\algpx@endComment}{~*/}% + \makeatother + \LComment{Long comment.} + \State $x \gets 0$ \Comment{Short comment.} + \end{algorithmic} +\end{minipage} + +\subsection{beginLComment and endLComment} +\begin{description} + \item[possible values:] Any string that can be typeset in text mode. + \item[default:] \verb|$\triangleright$~| and \verb|~$\triangleleft$| +\end{description} +Used to indicate the beginning and end of long comments typeset with \verb|\LComment|, respectively. +\subsubsection*{Example} +\begin{minipage}[t]{0.45\textwidth} + \verb|beginLComment=/*~|, \verb|endLComment=~*/|: + \begin{algorithmic} + \makeatletter + \renewcommand{\algpx@beginLComment}{/*~}% + \renewcommand{\algpx@endLComment}{~*/}% + \makeatother + \LComment{Long comment.} + \State $x \gets 0$ \Comment{Short comment.} + \end{algorithmic} +\end{minipage} + + +\section{Customization} +\subsection{Style of Indent Guide Lines}\label{sec:indStyle} +Indent guide lines are drawn using TikZ and consequently any TikZ style can be used. To set the style, use: +\begin{verbatim} + \tikzset{algpxIndentLine/.style={style}} +\end{verbatim} +The default style is \verb|draw=gray,very thin|. + +\subsubsection*{Example} +\verb|algpxIndentLine/.style={draw=blue,dashed}|: +\begin{algorithmic} + \tikzset{algpxIndentLine/.style={draw=blue,dashed}} + \If{$x > 0$} + \State $x \gets x - 1$ + \EndIf +\end{algorithmic} + + +\subsection{Default Style of Boxes}\label{sec:defBoxStyle} +Boxes are drawn using TikZ and consequently any TikZ style can be used. To set the default style, use: +\begin{verbatim} + \tikzset{algpxDefaultBox/.style={style}} +\end{verbatim} +The default style is \verb|draw|. + + +\subsection{Changing Keywords} +As in the \texttt{algorithmicx} package, keywords can be renamed using the syntax: +\begin{verbatim} + \algrenewcommand\keyword{new name} +\end{verbatim} +The following keywords can be customized: +\begin{itemize} + \item \verb|\algorithmicend| + \hfill Default: \verb|\textbf{end}| + \item \verb|\algorithmicdo| + \hfill Default: \verb|\textbf{do}| + \item \verb|\algorithmicwhile| + \hfill Default: \verb|\textbf{while}| + \item \verb|\algorithmicfor| + \hfill Default: \verb|\textbf{for}| + \item \verb|\algorithmicforall| + \hfill Default: \verb|\textbf{for all}| + \item \verb|\algorithmicloop| + \hfill Default: \verb|\textbf{loop}| + \item \verb|\algorithmicrepeat| + \hfill Default: \verb|\textbf{repeat}| + \item \verb|\algorithmicuntil| + \hfill Default: \verb|\textbf{until}| + \item \verb|\algorithmicprocedure| + \hfill Default: \verb|\textbf{procedure}| + \item \verb|\algorithmicfunction| + \hfill Default: \verb|\textbf{function}| + \item \verb|\algorithmicif| + \hfill Default: \verb|\textbf{if}| + \item \verb|\algorithmicthen| + \hfill Default: \verb|\textbf{then}| + \item \verb|\algorithmicelse| + \hfill Default: \verb|\textbf{else}| + \item \verb|\algorithmicrequire| + \hfill Default: \verb|\textbf{Require:}| + \item \verb|\algorithmicensure| + \hfill Default: \verb|\textbf{Ensure:}| + \item \verb|\algorithmicreturn| + \hfill Default: \verb|\textbf{return}| + \item \verb|\algorithmicoutput| + \hfill Default: \verb|\textbf{output}| +\end{itemize} + + +\end{document} 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}{}% + }{}% +} diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check index bffb2336174..63ee0fb014d 100755 --- a/Master/tlpkg/bin/tlpkg-ctan-check +++ b/Master/tlpkg/bin/tlpkg-ctan-check @@ -32,7 +32,8 @@ my @TLP_working = qw( adrconv adtrees advdate ae aeguill afparticle afthesis aguplus aiaa aichej ajl akktex akletter akshar alegreya alertmessage - alg algobox algolrevived algorithm2e algorithmicx algorithms algxpar + alg algobox algolrevived + algorithm2e algorithmicx algorithms algpseudocodex algxpar aligned-overset alkalami allrunes almendra almfixed alnumsec alpha-persian alphalph diff --git a/Master/tlpkg/tlpsrc/algpseudocodex.tlpsrc b/Master/tlpkg/tlpsrc/algpseudocodex.tlpsrc new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/Master/tlpkg/tlpsrc/algpseudocodex.tlpsrc diff --git a/Master/tlpkg/tlpsrc/collection-mathscience.tlpsrc b/Master/tlpkg/tlpsrc/collection-mathscience.tlpsrc index 526832577a5..fe6398a3f06 100644 --- a/Master/tlpkg/tlpsrc/collection-mathscience.tlpsrc +++ b/Master/tlpkg/tlpsrc/collection-mathscience.tlpsrc @@ -13,6 +13,7 @@ depend algobox depend algorithm2e depend algorithmicx depend algorithms +depend algpseudocodex depend algxpar depend aligned-overset depend amscdx |