Based on Werner's comment on his answer, I have defined \BoxedState, \BoxedIf, \BoxedWhile, etc., which set a mark at the beginning of the line and draw a box. The optional argument sets the style of the box. The command \EndBox sets the lower end of the box, \SetBoxEast can be used at the end of the longest line in the box to set the right end. If the last line is the longest one, \SetBoxEast can be ommited.
The counter tmkcount is used to keep the marks unique. The box is drawn before its contents, so it can be filled. Limitations include:
- The box does not adapt to very high first lines.
- It is assumed that no line within the box start further left than the first one.
Code and example:
\documentclass{article}
\usepackage{algpseudocode,tikz}
\usetikzlibrary{fit,tikzmark}
\newcounter{tmkcount}
\tikzset{%
tikzmark suffix={-\thetmkcount},%
defaultCodeBox/.style={draw=red}%
}
\newcommand{\drawCodeBox}[4]{%
\begin{tikzpicture}[remember picture,overlay]
\coordinate (start) at ([yshift=1.4ex]pic cs:#2);
\coordinate (middle) at (pic cs:#3);
\coordinate (end) at ([yshift=-0.2ex]pic cs:#4);
\node[inner sep=2pt,#1,fit=(start) (middle) (end)] {};
\end{tikzpicture}%
}
\newcommand{\BeginBox}[1]{%
\drawCodeBox{#1}{beginCB}{middleCB}{endCB}%
\tikzmark{beginCB}\tikzmark{middleCB}%
}
\newcommand{\SetBoxEast}{%
\unskip%
\tikzmark{middleCB}%
}
\newcommand{\EndBox}{%
\unskip%
\tikzmark{endCB}%
\stepcounter{tmkcount}%
}
\newcommand{\BoxedState}[1][defaultCodeBox]{\State\BeginBox{#1}\ignorespaces}
\algdef{S}[WHILE]{BoxedWhile}[2][defaultCodeBox]{\BeginBox{#1}\algorithmicwhile\ #2\ \algorithmicdo}%
\algdef{S}[FOR]{BoxedFor}[2][defaultCodeBox]{\BeginBox{#1}\algorithmicfor\ #2\ \algorithmicdo}%
\algdef{S}[FOR]{BoxedForAll}[2][defaultCodeBox]{\BeginBox{#1}\algorithmicforall\ #2\ \algorithmicdo}%
\algdef{S}[LOOP]{BoxedLoop}[1][defaultCodeBox]{\BeginBox{#1}\algorithmicloop}%
\algdef{S}[REPEAT]{BoxedRepeat}[1][defaultCodeBox]{\BeginBox{#1}\algorithmicrepeat}%
\algdef{S}[IF]{BoxedIf}[2][defaultCodeBox]{\BeginBox{#1}\algorithmicif\ #2\ \algorithmicthen}%
\algdef{C}[IF]{IF}{BoxedElsIf}[2][defaultCodeBox]{\BeginBox{#1}\algorithmicelse\ \algorithmicif\ #2\ \algorithmicthen}%
\algdef{Ce}[ELSE]{IF}{BoxedElse}{EndIf}[1][defaultCodeBox]{\BeginBox{#1}\algorithmicelse}%
\begin{document}
\begin{algorithmic}
\BoxedState $x \gets 0$
\State $y \gets x + 1$\EndBox
\If{$x < y$}
\State $x \gets x + 1$
\BoxedElse[fill=yellow]
\State do some complicated stuff\SetBoxEast
\State $y \gets y + 1$\EndBox
\EndIf
\end{algorithmic}
\end{document}

\algorithmicend\ \algorithmicifetc.? Ideally, one could then create a macro\tikzmarkLeftthat automatically positions the mark at the left of the current line. – Christian Matt Mar 15 '17 at 21:30\tikzmark{lmargin}against theleftmargin, and then calculate the difference between a placed\tikzmarkLeft{here}andlmarginusing some details in Extract x, y coordinate of an arbitrary point in TikZ. Alternative, use the page coordinates. I'm too unfamiliar withtikzto know how to do that... – Werner Mar 15 '17 at 21:42\tikzmarkEndIf{<mark>}macro that sets a mark just before setting\algorithmicend. That way you don't have to know anything about the current indentation. – Werner Mar 15 '17 at 21:44