I am writing a Latex document with pseudocode interspersed with theorems and discussion. Some of the comments in the pseudocode are long. I would like to automatically start (and end) each output line of the comment with a hash sign, or an asterisk or a percentage sign, the way people often do when, for example, they write C++ or Matlab. The only way I know how to do this is to use \obeylines and put the desired character into the latex source. However, this leads to lines that are undesirably short or long.

There are several ways but it depends a bit on how you are entering the rest of the stuff. Are you using one of the existing pseudocode environments such as algorithm2e package for example. It always helps to have a complete small document in the question.
–
David CarlisleDec 3 '12 at 12:36

I'm using alg. I have tried various pseudocode environments, but, of course, they never do exactly what I want. My main criterion is how easy is it to define my own control sequences within the given environment. alg is simple, and I've found no problem with writing my own macros. My experience with several other pseudocode packages has been that the insignificant progress is not worth the pain. I don't think I would have any trouble using your code with alg (but I haven't tried it). Would other pseudocode packages blow up with your code? What pseudocode package would you recommend?
–
David EpsteinDec 3 '12 at 16:16

% parameters of algcomment
% #1 "/* " start syntax
% #2 " * " continuation syntax
% #3 the comment text
% #4 " */" end syntax
\long\def\algcomment#1#2#3#4{%
% First use a fake display math to measure the line so far
\abovedisplayskip\z@
\belowdisplayskip\z@
\abovedisplayshortskip\z@
\belowdisplayshortskip\z@
$$\global\dimen1\predisplaysize$$%
% Back up so that the comment will appear to start on the
% already started line.
\vskip-2\baselineskip
% command to output the line number and the continuation marker
\def\addprefix{\alg@putlineno{#2}}%
% start collecting the comment
\setbox2\vbox\bgroup\bgroup
% Reduce the width for line brreaking by the width of #2 to allow for
% the insertion of the prefix string later.
\setbox0\hbox{{#2}}%
\advance\hsize-\wd0
\leavevmode\kern\dimen1\kern-\leftskip\kern-\wd\z@#1#3#4%
% close off the saving of box 2 started above.
\endgraf\egroup\egroup
% So at those point box 2 contains the body of the environment
% with lines broken to a short line length.
%
% count how many lines we're going to add
% need to do this first as we re-add them in reverse order so
% will be decrementing the line count
\dimen0\z@
\@tempcnta\c@algline
\loop
\advance\dimen@\baselineskip
\global\advance\c@algline\@ne
\ifdim\dimen@>\ht2
\else
\repeat
\@tempcntb\c@algline
% Clear box 1 ready to start collecting the modified lines
\global\setbox1\vbox{}%
% Use unbox box2 (onto itself)
\setbox2\vbox{%
\unvbox2
% at this point we are at the end of box 2 now
% loop backwards up the vertical list copying glue and penalties
% but modifying boxesto add the prefix.
\loop
%
% an e-tex primitive that reports the last item in the vertical list.
% type 1 is a box, so remove the box (a lien of text) and then
% put into box 1 a box that is this box together with the prefix which
% was saved in box 0
\ifnum\lastnodetype=1
\global\setbox3\lastbox
\global\setbox1\vbox{%
\hbox{\strut%
\global\advance\c@algline\m@ne
\kern\leftskip
\ifnum\c@algline>\@tempcnta
\addprefix
\else
\global\c@algline\@tempcntb
\global\advance\c@algline\m@ne
\fi
\kern-\leftskip
\box3}%
\unvbox1}%
\fi
%
% type 11 is glue so remove it from this list and add
% equivalent glue to box 1
\ifnum\lastnodetype=11
\skip0\lastskip\unskip
\global\setbox1\vbox{\vskip\skip0\unvbox1}%
\fi
%
% same for penalty
\ifnum\lastnodetype=13
\count0\lastpenalty\unpenalty
\global\setbox1\vbox{\penalty\count0 \unvbox1}%
\fi
%
% other node types are not handled here: either they won't happen
% or they can't be removed anyway so would break the loop \special
% for example would be bad.
%
% -1 means the vertical list is empty: we have reached the top of the box.
\ifnum\lastnodetype=-1
\else
\repeat}%
% Tip the modified box back onto the main list for the page, unbox
% it so that page breaking may still happen (if it could happen in the
% original context).
\vskip\dp\strutbox
\unvbox1
}

Original general version

\documentclass{article}
\usepackage{color}
% generate junk filler text for the example
\def\a{Red green blue yellow. }
\def\b{\a\a One two three four. \a\a}
% The code for the start of environment
\def\commentpara#1{%
% save the depth of the previous line (Normally
% TeX uses this automatically but would lose the
% informatiom due to the boxing/reboxing)
\dimen0\prevdepth
% Save the prefix text from `#1` in box 0.
% In this version make it red, probably real code
% should not do that and should just have `#1` you
% could always add colour or font changes in the argument.
\setbox0\hbox{\textcolor{red}{#1}}%
% start saving the paragraph in box 2
\setbox2\vbox\bgroup\bgroup
% by resetting the prevdepth to the saved value
% Tex will automatically insert glue to maintain even spacing
% before the first line.
\prevdepth\dimen0
% Reduce the width for line breaking by the width of box 0 to allow for
% the insertion of the prefix string later.
\advance\hsize-\wd0
% end of begin environment code
}
% The code for the end of the environment.
\def\endcommentpara{%
% close off the saving of box 2 started above.
\endgraf\egroup\egroup
% So at those point box 2 contains the body of the environment
% with lines broken to a short line length.
%
% Clear box 1 ready to start collecting the modified lines
\global\setbox1\vbox{}%
% Use unbox box2 (onto itself)
\setbox2\vbox{%
\unvbox2
% at this point we are at the end of box 2 now
% loop backwards up the vertical list copying glue and penalties
% but modifying boxes to add the prefix.
\loop
%
% an e-tex primitive that reports the last item in the vertical list.
% type 1 is a box, so remove the box (a line of text) and then
% put into box 1 a box that is this box together with the prefix which
% was saved in box 0
\ifnum\lastnodetype=1
\global\setbox3\lastbox
\global\setbox1\vbox{%
\hbox{\copy0\box3}%
\unvbox1}%
\fi
%
% type 11 is glue so remove it from this list and add
% equivalent glue to box 1
\ifnum\lastnodetype=11
\skip0\lastskip\unskip
\global\setbox1\vbox{\vskip\skip0\unvbox1}%
\fi
%
% same for penalty
\ifnum\lastnodetype=13
\count0\lastpenalty\unpenalty
\global\setbox1\vbox{\penalty\count0 \unvbox1}%
\fi
%
% other node types are not handled here: either they won't happen
% or they can't be removed anyway so would break the loop \special
% for example would be bad.
%
% -1 means the vertical list is empty: we have reached the top of the box.
\ifnum\lastnodetype=-1
\else
\repeat}%
% Tip the modified box back onto the main list for the page, unbox
% it so that page breaking may still happen (if it could happen in the
% original context).
\unvbox1
}
\begin{document}
\noindent X \dotfill X
\begin{commentpara}{\# this prefix: }
\b\b
\end{commentpara}
\noindent X \dotfill X
\end{document}

Within a box you can (as shown in this loop) dissect the box with \lastbox and measure the widths of boxes etc, but on the main vertical list you can not. Once a box is there it is there (until the output routine which is a story for another day) but there is one exception within display math the primitve register \predisplaysize records the length of the last line of text in the partial paragraph before the display.

So here the line if e==0 has already been set so the idea is to set the comment paragraph with a blank on the first line of that size and then move the whole box up -2\baselineskip so thet it "slots" into place.

In a slight change to the first version the "gap" left on the first line is reduced from
\predisplaysize by \wd0 which is the width of the continuation marker as that marker is not placed on the first line which was causing the first lien of the comment to be over-short.

Thanks a lot, David. The results are great, though I'm very puzzled by the code. Would it be possible to post again, with comments saying in English what is going on, or would that be too much work? I suppose I could try to work it out by looking up all the control sequences, or I could treat it like a black box, as I always do with latex packages. Also, how can I save it (using texlive) so that I can easily re-use your code? I have a private texmf where I could store your code, but not quite sure where to put it and what filename to use.
–
David EpsteinDec 3 '12 at 15:52

if you stick the code from \def\commentpar to the end of the preamble into a file say commentpar.sty then you could use \usepackage{commentpar} in any document where you needed this so long as the .sty was in the same directory or somewhere on the tex input path. I could add some description later as to what it's doing.
–
David CarlisleDec 3 '12 at 16:28

Very grateful for all your work. Could you explain the line $$\global\dimen1\predisplaysize$$ and how it is supposed to work? Is \predisplaysize a Tex macro? It seems to generate initial extra white space that is not desired.
–
David EpsteinDec 5 '12 at 8:37

When I followed your line by the horrible hack \advance\dimen1-23pt the undesired space disappeared (no surprise there).
–
David EpsteinDec 5 '12 at 8:50