We describe two stages: adding a new delimiter type to an existing class of delim- iters and writing a new class. Each class has its name; currently exist Comment, String, andDelim. As you know, the latter and the first both provide the type l, but there is no string which starts with the given delimiter and ends at end of line. So we’ll add it now!
First of all we extend the list of string types by
% \lst@AddTo\lst@stringtypes{,l}
Then we must provide the macro which takes the user supplied delimiter and makes appropriate definitions. The command name consists of the prefix\lst@, the delimiter name,DMfor using dynamic modes, and@followed by the type.
% \gdef\lst@StringDM@l#1#2\@empty#3#4#5{%
% \lst@CArg #2\relax\lst@DefDelimB{}{}{}#3{#1}{#5\lst@Lmodetrue}}
You can put these three lines into a.sty-file or surround them by\makeatletter and\makeatotherin the preamble of a document. And that’s all!
// T h i s i s a s t r i n g . T h i s i s n ’ t a s t r i n g .
\lstset{string=[l]//}
\begin{lstlisting}
// This is a string.
This isn’t a string.
\end{lstlisting}
You want more details, of course. Let’s begin with the arguments.
• The first argumentafter\@emptyis used to start the delimiter. It’s provided by the delimiter class.
• The second argument after \@emptyis used to end the delimiter. It’s also provided by the delimiter class. We didn’t need it in the example, see the explanation below.
• The third argument after \@empty is {hstylei}hstart tokensi. This with a preceding \def\lst@currstyle is used as argument to \lst@EnterMode.
The delimiter class also provides it. In the example we ‘extended’ #5 by
\lst@Lmodetrue (line mode true). The mode automatically ends at end of line, so we didn’t need the end-delimiter argument.
And now for the other arguments. In case of dynamic modes, the first argument is the mode number. Then follow the user supplied delimiter(s) whose number must match the remaining arguments up to \@empty. For non-dynamic modes, you must either allocate a static mode yourself or use a predefined mode number.
The delimiters then start with the first argument.
Eventually let’s look at the replacement text of the macro. The sequence
\lst@CArg #2\relax puts two required arguments after \lst@DefDelimB. The syntax of the latter macro is
\lst@DefDelimB
{h1stih2ndi{hresti}} {//{}}
hsave 1sti \lst@c/0
{hexecutei} {}
{hdelim exe modetruei} {}
{hdelim exe modefalsei} {}
hstart-delimiter macroi #3
hmode numberi {#1}
{{hstylei}hstart tokensi} {#5\lst@Lmodetrue}
defines h1stih2ndihresti as starting-delimiter. hexecutei is executed when the package comes toh1sti. hdelim exe modetrueiandhdelim exe modefalsei are executed only if the whole delimiter h1stih2ndihrestiis found. Exactly one of them is called depending on\lst@ifmode.
By default the package enters the mode if the delimiter is found and
\lst@ifmode is false. Internally we make an appropriate definition of
\lst@bnext, which can be gobbled by placing\@gobblethree at the very end ofhdelim exe modefalsei. One can provide an own definition (and gobble the default).
hsave 1sti must be an undefined macro and is used internally to store the previous meaning of h1sti. The arguments h2ndi and/orhresti are empty if the delimiter has strictly less than three characters. All characters of h1stih2ndihrestimust already be active (if not empty). That’s not a problem since the macro \lst@CArgXdoes this job.
\lst@DefDelimE
{h1stih2ndi{hresti}}
hsave 1sti
{hexecutei}
{hdelim exe modetruei}
{hdelim exe modefalsei}
hend-delimiter macroi hmode numberi
Ditto for ending-delimiter with slight differences: hdelim exe modetrueiand hdelim exe modefalseiare executed depending on whether\lst@modeequals hmodei.
The package ends the mode if the delimiter is found and\lst@modeequals hmodei. Internally we make an appropriate definition of \lst@enext (not
\lst@bnext), which can be gobbled by placing\@gobblethreeat the very end of hdelim exe modetruei.
\lst@DefDelimBE
followed by the same eight arguments as for\lst@DefDelimBand . . . hend-delimiter macroi
This is a combination of\lst@DefDelimBand\lst@DefDelimEfor the case of starting and ending delimiter being the same.
We finish the first stage by examining two easy examples. d-type strings are defined by
% \gdef\lst@StringDM@d#1#2\@empty#3#4#5{%
% \lst@CArg #2\relax\lst@DefDelimBE{}{}{}#3{#1}{#5}#4}
(and an entry in the list of string types). Not a big deal. Dittod-type comments:
% \gdef\lst@CommentDM@s#1#2#3\@empty#4#5#6{%
% \lst@CArg #2\relax\lst@DefDelimB{}{}{}#4{#1}{#6}%
% \lst@CArg #3\relax\lst@DefDelimE{}{}{}#5{#1}}
Here we just need to use both\lst@DefDelimBand\lst@DefDelimE.
So let’s get to the second stage. For illustration, here’s the definition of the Delimclass. The respective first argument to the service macro makes it delete all delimiters of the class, add the delimiter, or delete the particular delimiter only.
% \lst@Key{delim}\relax{\lst@DelimKey\@empty{#1}}
% \lst@Key{moredelim}\relax{\lst@DelimKey\relax{#1}}
% \lst@Key{deletedelim}\relax{\lst@DelimKey\@nil{#1}}
The service macro itself calls another macro with appropriate arguments.
% \gdef\lst@DelimKey#1#2{%
% \lst@Delim{}#2\relax{Delim}\lst@delimtypes #1%
% {\lst@BeginDelim\lst@EndDelim}
% i\@empty{\lst@BeginIDelim\lst@EndIDelim}}
We have to look at those arguments. Above you can see the actual arguments for the Delim class, below are the Comment class ones. Note that the user supplied value covers the second and third line of arguments.
changed \lst@Delim
hdefault style macroi \lst@commentstyle
[*[*]][htypei][[hstylei][[htype optioni]]]
hdelimiter(s)i\relax #2\relax
{hdelimiter namei} {Comment}
hdelimiter types macroi \lst@commenttypes
\@empty|\@nil|\relax #1
{hbegin- and end-delim macroi} {\lst@BeginComment\lst@EndComment}
hextra prefixi i
hextra conversioni \@empty
{hbegin- and end-delim macroi} {\lst@BeginIComment\lst@EndIComment}
Most arguments should be clear. We’ll discuss the last four. Both {hbegin- and end-delim macroi} must contain exactly two control sequences, which are given to \lst@hnamei[DM]@htypei to begin and end a delimiter. These are the arguments #3 and #4 in our first example of \lst@StringDM@l.
Depending on whether the user chosen type starts with hextra prefixi, the first two or the last control sequences are used.
By default the package takes the delimiter(s), makes the characters active, and places them after \lst@hnamei[DM]@htypei. If the user type starts with hextra prefixi,hextra conversionimight change the definition of\lst@next to choose a different conversion. The default is equivalent to\lst@XConvert with\lst@false.
Note that htypei never starts withhextra prefixi since it is discarded. The functionality must be fully implemented by choosing a different{hbegin- and end-delim macroi}pair.
You might need to know the syntaxes of thehbegin- and end-delim macrois. They are called as follows.
\lst@Beginhwhateveri
{hmodei} {{hstylei}hstart tokensi}hdelimiteri\@empty
\lst@Endhwhateveri
{hmodei}hdelimiteri\@empty
The existing macros are internally defined in terms of \lst@DelimOpen and
\lst@DelimClose, see the implementation.