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.
精彩评论