开发者

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

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 possibl开发者_StackOverflow社区e to specify a custom command so that I can use something like

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

instead?


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.


Try this:

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

% Usage example:
\dialogueline{Johnny}{Some dialogue.}  
\dialogueline{Jane}{I see.}  


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜