How to automatically keep the indentation level when a line has to be broken

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:

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):

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

1. cam-thesis with pdfLaTeX:

2. article with XeLaTeX:

3. article with pdfLaTeX:

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

-

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}


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.

-
Thanks for the answer! However, I still have an issue. I'm using the cam-thesis class and when used with \documentclass{cam-thesis} your solution doesn't work. I'm new on TeX.SX and I don't know whether I should accept your answer and post a new question or resolve it all in one question? –  tjanez Aug 26 '13 at 17:06
@tjanez I just did a test, using the exact same code I posted but changing article to cam-thesis and everything worked as expected, so the problem must be elsewhere. At this point I would suggest you to produce a minimal document with your current settings and allowing us to reproduce the problem; edit your question, and add this minimal document there. Leave a comment here so I get notified. By the way, you should have mentioned that you were using some other class from the beginning. –  Gonzalo Medina Aug 26 '13 at 20:16
I apologize for not giving the full details in the beginning. The document I was writing is my PhD Thesis and it is way too complicated to post it all here, so I trimmed it down to a MWE. I just discovered that probably the reason it works for you with cam-thesis class is that you are using pdfLaTeX, whereas I use XeLaTeX. I edited the question and gave full details of my setup. –  tjanez Aug 26 '13 at 22:00
@tjanez thank you for providing the additional information. You're right, my code works using cam-thesis with pdfLaTeX, but not with XeLaTeX; in fact, XeLaTeX and linegoal seem not to like each other. I'll let you know if I can think of a solution for this case. –  Gonzalo Medina Aug 26 '13 at 22:08