Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom command for '\begin{environment}...\end{environment}'

Tags:

latex

To enter a bit of dialogue using the screenplay package, I have to use

\begin{dialogue}{Johnny} Some dialogue. \end{dialogue}
\begin{dialogue}{Jane} I see. \end{dialogue}

It gets a bit tedious after a while. Is it possible to specify a custom command so that I can use something like

\dialogue{Johnny} Some dialogue.
\dialogue{Jane} I see.

instead?

like image 575
njt Avatar asked Apr 28 '10 23:04

njt


3 Answers

You can in fact get exactly what you want:

\newcommand{\dialogueline}{\begingroup\catcode`\^^M=12 \dialogueline@EOL}
{\catcode`\^^M=12\gdef\dialogueline@EOL#1#2^^M{\begin{dialogue}{#1}#2\end{dialogue}\endgroup}}

This code needs to be \makeatletter-protected—either surrounded by \makeatletter/\makeatother (edit: this means that you put \makeatletter before the definition, and \makeatother after it), or in a .sty file. Note that an environment named dialogue defines a command named \dialogue, so you need a different name. Do not change the formatting!

The way it works is that \dialogueline is a command which takes no arguments, but instead expands to multiple sequences. First, a group-opening token, to put whatever follows in its own scope. Second, the \catcode`^^M=12 sequence. LaTeX assigns each letter a catcode: a number which says what type it is. For instance, the backslash is catcode 0, the command-name constructor; letters are catcode 11; and non-letter printing characters, such as the at sign, are catcode 12. This sequence makes ^^M, the newline character, have catcode 12, so we can interact with it. Finally, we write out the command \dialogueline@EOL, which does the heavy lifting.

Next, we define \dialogueline@EOL. We do so within a group where the newline character is catcode 12, just as it will be where \dialogueline is expanded. Note that this is why you cannot break the second line with a newline—it would be interpreted as text. Next, we define \dialogueline@EOL to take two arguments, ending with a newline; it expands by taking the first argument (which you pass in braces) and passing it as an argument to the dialogue environment, and passing the second argument (everything after the first and before the end of line) as the body of the environment. Finally, \dialogueline@EOL ends the group opened in \dialogueline, so that the change to the catcode of ^^M is not visible anywhere else. Given this, you can write

\dialogueline{Johnny} Some dialogue.
\dialogueline{Jane}   I see.

and everything should work.

like image 84
Antal Spector-Zabusky Avatar answered Nov 20 '22 21:11

Antal Spector-Zabusky


Try this:

\newcommand{\dialogueline}[2]{\begin{dialogue}{#1} #2 \end{dialogue}}

% Usage example:
\dialogueline{Johnny}{Some dialogue.}  
\dialogueline{Jane}{I see.}  
like image 27
In silico Avatar answered Nov 20 '22 21:11

In silico


If you assume that each dialog occupies one paragraph (usually, it starts and ends with a double-line paragraph break), then there is another way to have \dialogue take just one argument:

\newif\indialog \indialogfalse
\def\dialogue#1{\ifindialog \end{dialogue}#1\begin{dialog}\else 
                \everypar={\end{dialogue}\indialogfalse \everypar={}}#1\indialogtrue\begin{dialogue} 
                \fi}

That code is kind of dirty and un-Latexy —it sets \everypar without caring about its existing content— and Latex has cleaner abstractions for doing it, which I have forgotten, but the principle should be clear.

like image 30
Charles Stewart Avatar answered Nov 20 '22 21:11

Charles Stewart