[Tex/LaTex] How to automatically keep the indentation level when a line has to be broken

algorithmicxalgorithmsindentationline-breaking

I'm using the algpseudocode package with two custom commands, \Let and \LongState to handle automatic indentation of (broken) long lines in the spirit of Werner's answer, which uses \parbox to wrap the long line's content.

However, the following approach does not work well when the indentation level is more than one. Here is an example:

\documentclass{article}

\usepackage{algorithm}
\usepackage[noend]{algpseudocode}
\usepackage{calc}

% A command for defining assignments within the algorithmic environment which
% supports automatic indentation when the second argument is too long to fit
% on one line
\newcommand*{\Let}[2]{\State #1 $\gets$
\parbox[t]{\linewidth-\algorithmicindent-\widthof{ #1 $\gets$}}{#2\strut}}
% A \State command that supports automatic indentation when the argument's
% content is too long to fit on one line
\newcommand*{\LongState}[1]{\State
\parbox[t]{\linewidth-\algorithmicindent}{#1\strut}}

\begin{document}

\begin{algorithm}
\caption{This is some testing pseudo-code showing what happens with nested long
lines}

\begin{algorithmic}[1]
  \Function{test}{$(x, y)$}
    \Let{$a$}{some math expression}
    \Let{$b$}{some very very long expression that doesn't fit on one line and is
    even longer and longer}
    \For{each $e$ in a list}
        \Let{$l(e)$}{the length of element $e$}
        \If{some condition on $l(e)$}
            \LongState{run some complex sub-routine and get the result and this
            description is very very long, long indeed...}
            \Let{$a$}{some math expression}
            \Let{$b$}{some very very long expression that doesn't fit on one
            line and is even longer and longer}
            \If{some other condition}
                \Let{$c$}{another math expression}
            \EndIf
        \EndIf
    \EndFor
  \EndFunction
\end{algorithmic}

\end{algorithm}

\end{document}

The following renders as:
enter image description here

Line 3 is an example of a well broken long line, whereas lines 7 and 9 stretch out too far.

Edit: I initially encountered this problem when writing my PhD Thesis using the cam-thesis class and XeLaTeX. My setup is Fedora 17 with TeXLive 2013 as packaged by Jindrich Novy.

If I use Gonzalo Medina's answer and change the document's class to \documentclass{cam-thesis} (following is a MWE):

\documentclass{cam-thesis}
\usepackage{algorithm}
\usepackage[noend]{algpseudocode}
\usepackage{calc}
\usepackage{linegoal}

% A command for defining assignments within the algorithmic environment which
% supports automatic indentation when the second argument is too long to fit
% on one line
\newcommand*{\Let}[2]{\State #1 $\gets$
\parbox[t]{\linegoal}{#2\strut}}
% A \State command that supports automatic indentation when the argument's
% content is too long to fit on one line
\newcommand*{\LongState}[1]{\State
\parbox[t]{\linegoal}{#1\strut}}

\begin{document}

\begin{algorithm}
\caption{This is some testing pseudo-code showing what happens with nested long
lines}

\begin{algorithmic}[1]
  \Function{test}{$(x, y)$}
    \Let{$a$}{some math expression}
    \Let{$b$}{some very very long expression that doesn't fit on one line and is
    even longer and longer}
    \For{each $e$ in a list}
        \Let{$l(e)$}{the length of element $e$}
        \If{some condition on $l(e)$}
            \LongState{run some complex sub-routine and get the result and this
            description is very very long, long indeed...}
            \Let{$a$}{some math expression}
            \Let{$b$}{some very very long expression that doesn't fit on one
            line and is even longer and longer}
            \If{some other condition}
                \Let{$c$}{another math expression}
            \EndIf
        \EndIf
    \EndFor
  \EndFunction
\end{algorithmic}

\end{algorithm}

\end{document}

I get the following (cam-thesis with XeLaTeX):
enter image description here

Debugging this further, however, I found that the following combinations work:

  1. cam-thesis with pdfLaTeX:
    enter image description here

  2. article with XeLaTeX:
    enter image description here

  3. article with pdfLaTeX:
    enter image description here

All three of the above options work fine, but I really need to use cam-thesis with XeLaTeX.

Best Answer

One option is to use \linegoal (from the linegoal package) as the width of the \parboxes; \linegoal expands to the dimension of the remainder of the line:

\documentclass{article}
\usepackage{algorithm}
\usepackage[noend]{algpseudocode}
\usepackage{calc}
\usepackage{linegoal}

% A command for defining assignments within the algorithmic environment which
% supports automatic indentation when the second argument is too long to fit
% on one line
\newcommand*{\Let}[2]{\State #1 $\gets$
\parbox[t]{\linegoal}{#2\strut}}
% A \State command that supports automatic indentation when the argument's
% content is too long to fit on one line
\newcommand*{\LongState}[1]{\State
\parbox[t]{\linegoal}{#1\strut}}

\begin{document}

\begin{algorithm}
\caption{This is some testing pseudo-code showing what happens with nested long
lines}

\begin{algorithmic}[1]
  \Function{test}{$(x, y)$}
    \Let{$a$}{some math expression}
    \Let{$b$}{some very very long expression that doesn't fit on one line and is
    even longer and longer}
    \For{each $e$ in a list}
        \Let{$l(e)$}{the length of element $e$}
        \If{some condition on $l(e)$}
            \LongState{run some complex sub-routine and get the result and this
            description is very very long, long indeed...}
            \Let{$a$}{some math expression}
            \Let{$b$}{some very very long expression that doesn't fit on one
            line and is even longer and longer}
            \If{some other condition}
                \Let{$c$}{another math expression}
            \EndIf
        \EndIf
    \EndFor
  \EndFunction
\end{algorithmic}

\end{algorithm}

\end{document}

enter image description here

Addendum

With XeLaTeX and the cam-thesis document class (link to the class appears in the question) used by tjanez, there's a problem with \linegoal; the problem doesn't appear with the standard classes (see edit to the question). A quick work-around is to use a shorter value:

\documentclass{cam-thesis}
\usepackage{algorithm}
\usepackage[noend]{algpseudocode}
\usepackage{calc}
\usepackage{linegoal}

% A command for defining assignments within the algorithmic environment which
% supports automatic indentation when the second argument is too long to fit
% on one line
\newcommand*{\Let}[2]{\State #1 $\gets$
\parbox[t]{-52,29pt+\linegoal}{#2\strut}}
% A \State command that supports automatic indentation when the argument's
% content is too long to fit on one line
\newcommand*{\LongState}[1]{\State
\parbox[t]{-52,29pt+\linegoal}{#1\strut}}

\begin{document}

\begin{algorithm}
\caption{This is some testing pseudo-code showing what happens with nested long
lines}

\begin{algorithmic}[1]
  \Function{test}{$(x, y)$}
    \Let{$a$}{some math expression}
    \Let{$b$}{some very very long expression that doesn't fit on one line and is
    even longer and longer}
    \For{each $e$ in a list}
        \Let{$l(e)$}{the length of element $e$}
        \If{some condition on $l(e)$}
            \LongState{run some complex sub-routine and get the result and this
            description is very very long, long indeed...}
            \Let{$a$}{some math expression}
            \If{some condition on $l(e)$}
            \Let{$b$}{some very very long expression that doesn't fit on one
            line and is even longer and longer}
            \If{some other condition}
                \Let{$c$}{another math expression}
              \EndIf
            \EndIf
        \EndIf
    \EndFor
  \EndFunction
\end{algorithmic}
\end{algorithm}

\end{document}

I suggest you to get in touch with the author/maintainer of cam-thesis to comment this problem.

Related Question