## LATEX-L@LISTSERV.UNI-HEIDELBERG.DE

 Options: Use Classic View Use Monospaced Font Show Text Part by Default Condense Mail Headers Topic: [<< First] [< Prev] [Next >] [Last >>]

 Sender: Mailing list for the LaTeX3 project <[log in to unmask]> Subject: Editing galley contents From: Lars Hellström <[log in to unmask]> Date: Mon, 13 Nov 2000 18:22:02 +0100 Reply-To: Mailing list for the LaTeX3 project <[log in to unmask]> Parts/Attachments: text/plain (254 lines) Lately I've been working on a set of macros which edit the contents of a galley vertical list; in particular they remove some and add other things to the lines of a paragraph that has already been broken. So far I have only used this for the paragraphs of a macrocode-like environment which additionally tries to break codelines that are too long to fit on one printed line, but now it occurs to me that this mechanism might be useful in more general contexts. Environments like macrocode are convenient in that one can have full control over which commands get executed and thus also full control over what gets put in the vertical list; in particular one can ensure that only removeable items (such as boxes, penalties, and glue; kerns are oc course also removeable, but TeX doesn't automatically insert these so I might just as well forbid them as well) appear on the vertical list. This means that I can use a \lastbox recursion (similar to that of the \removehboxes macro on p. 399 of The TeXbook) to pop all boxes (lines) off the vlist and then do something to them before I put them back. In the present case this "do something" consists of appending a backslash to each line and possibly changing the justification. (A backslash at the end of a line escapes the following newline, which would otherwise have been a command separator, in the language I want to typeset code from.) Of course this means one has to start a new vbox to do these tricks in since material cannot be removed from the main vertical list and one has to be careful about the \prevdepth and a couple of other things, but those are minor technicalities. I have included a code example in an appendix below, just in case anyone is interested. Outside such special environments things are less nice, since the user can insert non-removable material anywhere between the lines of a paragraph using for example \mark or \insert; one would have to go to great lengths to ensure nothing of this kind will appear between the lines of the paragraph. What makes all this relevant to LaTeX-L however is that LaTeX2e* already does quite a lot to control what gets put on the vertical list, so in a fully developed 2e* system it might not be that hard to impose the condition that the contents of a galley should be removable/editable. It is probably too much to ask for direct support in the kernel (or is that kernel packages?), but perhaps some kind of interface for mechanisms like the one described above could be offered? (That's the main point in this letter, just in case anyone wonders.) There are two more things which might need pointing out. The first is that the prohibition of non-removable items in the vertical list that is to be edited does not prohibit them from being there in the edited vertical list; the trick is to hide them inside a vbox which is unboxed when the edited material is put back on the list. Thus instead of saying \mark{} somewhere in the paragraph one might say \vadjust{\vbox{\mark{}}}. The second is that there is an application in "real" typography of editing the contents of galleys. In Omega there are two primitives \localleftbox and \localrightbox which insert fixed-width material to the right and left respectively of the lines of a paragraph; this is employed for quoted material in French typography. With editing of galley contents one could instead insert that material after the paragraph is broken, no matter what kind of breakpoint is chosen (if all breakpoints in the quote are explicitly specified then it is of course much easier to use \discretionary), but one also has to determine the shape of the paragraph minus this inserted material (this can be done automatically too, but it might require breaking the paragraph several times). It is certainly not as elegant as in Omega, but it _can_ be done with a standard TeX. Lars Hellström PS: I'm still waiting for the reaction to my letter on xparse of 2000/08/03. APPENDIX: Code example of macros that edit galley contents. % \begin{macro}{\TD@reformat@lines} % The |\TD@reformat@lines| macro calls itself recursively to reformat % all lines on the current vertical list. The first line will remain % flush left, but all other lines will be reset flush right. The % visible material on the last line will be left as it is, but the % last box in all other lines will be replaced by a non-macro font % backslash. % % It is very important that the current vertical list is not the main % vertical list. % It is assumed that the current vertical list consists of a sequence % of \meta{box}, \meta{penalty}, \meta{glue}, with an extra glue item % at the top of the list. It is OK if some penalty or glue item is % missing. In case the list contains other material as well the line % reformatting may be stopped prematurely, but there is a trick that % allows one to put arbitrary material between the lines of the % reformatted paragraph: rather than doing e.g. % \begin{quote} % |\mark|\marg{text} % \end{quote} % in the paragraph, do % \begin{quote} % |\vadjust{\vbox{\mark{|\meta{text}|}}}| % \end{quote} % The |\vbox| will be recognised by the paragraph reformatting % mechanism as a container for vertical mode material that appears % between the lines of the paragraph, so it will simply be unboxed. % \changes{2.12}{2000/11/11}{\cs{vbox} containers for vertical % material are allowed between the lines of a reformatted % paragraph. (LH)} % % Each line's horizontal list ends with % \begin{itemize} % \item a box (which contains the space that is to be replaced by a % backlsash), % \item a penalty (at which the paragraph was broken), and % \item a glue item (the |\rightskip|). % \end{itemize} % % A tricky feature in the implementation is that the % |\bgroup|--|\egroup| nesting will be off by one. The |\bgroup| at % the beginning of a |\TD@reformat@line| will be matched by the % |\egroup| at the end of the |\TD@reformat@line| that the first one % calls! % \begin{macrocode} \def\TD@reformat@lines{%    \bgroup    \unskip    \count@=\lastpenalty \unpenalty    \setbox\z@=\lastbox    \ifvoid\z@ % \end{macrocode} % The recursion had already decended down to the last line of the % paragraph, and it is now time to reformat it. % \begin{macrocode}       \egroup       \prevdepth=\TD@prevdepth       \hbox{%          \unhbox\z@          \unskip \unpenalty          \setbox\z@=\lastbox          \copy\TD@backslash@box       }%    \else % \end{macrocode} % Else there may be another line, and the |\TD@reformat@lines| recursion % must continue to descend. Upon return the box currently in box % register zero must be reformatted as a non-first line (flush % right) and it cannot be the last line in the paragraph, so it is % always correct to replace the last box by a backslash. % \begin{macrocode}       \TD@reformat@lines       \ifvbox\z@ \unvbox\z@ \else          \hb@xt@\dimen@{%             \hfill             \unhbox\z@             \unskip \unpenalty             \setbox\z@=\lastbox             \copy\TD@backslash@box          }%       \fi    \fi    \ifnum \count@=\z@ \else \penalty\count@ \fi    \egroup } % \end{macrocode} % \end{macro} % % \begin{macro}{\TD@reformat@par} % The |\TD@reformat@par| macro reformats all lines (they're supposed % to constitute a paragraph, but that isn't so important) in the % current vertical list. The restrictions of |\TD@reformat@lines| on % what may appear in the list apply. |\dimen@| is used to hold the % desired width of reformatted paragraphs. % % More precisely |\TD@reformat@par| takes care of the last line of % the paragraph and the possible |\vbox| containers for vertical % material that may follow it. Everything in the paragraph that comes % before the last line is handled by |\TD@[log in to unmask] % \changes{2.12}{2000/11/11}{\cs{vbox} containers for vertical % material are allowed after the last line of a reformatted % paragraph. (LH)} % \begin{macrocode} \def\TD@reformat@par{%    \unskip    \count@=\lastpenalty \unpenalty    \setbox\z@=\lastbox    \ifvbox\z@       \bgroup       \TD@reformat@par       \egroup       \unvbox\z@    \else\ifnum \prevgraf>\@ne       \dimen@=\@totalleftmargin       \advance \dimen@ \linewidth       \bgroup       \unskip       \count@=\lastpenalty \unpenalty       \setbox\z@=\lastbox       \TD@reformat@lines       \hb@xt@\dimen@{\hfill \unhbox\z@ \unskip}%    \else       \unskip       \prevdepth=\TD@prevdepth       \box\z@    \fi\fi    \ifnum \count@=\z@ \else \penalty\count@ \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\TD@prevdepth} % |\TD@prevdepth| is a macro which is used for storing the value of % |\prevdepth| at times where \TeX\ modifies this special dimen in % unwanted ways. It should always be set globally. % \end{macro} % % % \begin{macro}{\TD@begin@tclpar} % The |\TD@begin@tclpar| macro is called when a paragraph in a % \texttt{tcl} or \texttt{tcl*} environment is about to start. It % takes care of setting up things so that the paragraph can later be % reformatted using |\TD@reformat@par|, but it also has to make sure % that this reformatting doesn't affect the way the paragraph blends % in with vertical material before and after it. % % Reformatting requires that the paragraph is first built in % restricted vertical mode, i.e., it has to be built in an explicit % |\vbox|. A problem with this is however that it changes the value of % |\prevdepth|, which must therefore be explicitly restored. % \begin{macrocode} \def\TD@begin@tclpar{%    \xdef\TD@prevdepth{\the\prevdepth}%    \setbox\z@=\vbox\bgroup       \color@begingroup       \prevdepth=\TD@prevdepth       \indent } % \end{macrocode} % \end{macro} % % \begin{macro}{\TD@end@tclpar} % The |\TD@end@tclpar| macro ends a paragraph begun by % |\TD@begin@tclpar|, reformats it (|\TD@reformat@par|), and % contributes it to the surrounding vertical list. The |\begingroup| % and |\endgroup| are there to sort things out in case the recursion % in |\TD@reformat@par| fails to match as intended. The second % |\@@par| sees to that the page builder is exercised (without it, % several pages may go onto the main vertical list without anything % being shipped out). % \begin{macrocode} \def\TD@end@tclpar{%       \@@par       \begingroup          \skip@=\lastskip          \TD@reformat@par          \vskip\skip@       \endgroup       \xdef\TD@prevdepth{\the\prevdepth}%       \color@endgroup    \egroup    \unvbox\z@    \prevdepth=\TD@prevdepth    \@@par } % \end{macrocode} % \end{macro}