I am writing the documentation to a package implemented in expl3 using ltxdoc, and the relevant part would look like

% \begin{macro}{\conteq_args_once}
% Some explanation
%    \begin{macrocode}
\cs_new:Npn \conteq_args_once:Nn #1#2 {
   \exp_not:o {#1 {#2}}
\cs_generate_variant:Nn \conteq_args_once:Nn {NV}
%    \end{macrocode}
% \end{macro}

Unfortunately, this give me

! Missing $ inserted.
<inserted text> 
l.385 % \begin{macro}{\conteq_args_once}

but \conteq\_args\_once:Nnn does not work either. How do I correctly annotate the documentation for such a function?

3 Answers 3


While you can start form ltxdoc and 'roll your own', the recommended approach is to use l3doc, which is the class used the the LaTeX team for expl3 itself. This is currently a rather large collection of hacks, but does deal correctly with things like _ in names, and also provides a richer set of documentation environments than ltxdoc. Regrettably, l3doc is lacking really comprehensive documentation: as I say, it's not exactly perfect internally! You can typeset l3doc.dtx to at least get some information, however.

Perhaps the best way to get the hang of things is to take a look at some of the LaTeX3 sources. I'd recommend avoiding l3doc.dtx itself and probably l3bootstrap.dtx, l3names,dtx and l3basics.dtx as they are atypical: something like l3clist.dtx is probably a rather better place to look. (As well as the use of l3doc, the sources show the 'house style' the team have standardised on. We are keen to encourage that as a more general 'expl3 code style': while you might not totally agree with every decision, in the long term it would be good if most expl3 code looks the same irrespective of author, as this will aid with maintenance.)

  • @JoachimBreitner Please register your prefix(es) :-)
    – Joseph Wright
    May 23, 2013 at 19:38
  • 3
    You might also take a look at my xpeek; it attempts to use l3doc, but it’s a much smaller package than the LaTeX3 team’s stuff. May 23, 2013 at 20:36
  • Note particularly the use of l3docstrip, which helps keep your internal functions within your reserved namespace by translating @@ within macro code to your chosen prefix. May 23, 2013 at 20:45

What I do is use skdoc (which I've written, although since it's based on ydoc presumably this'll work with at least ydoc as well assuming you load expl3), and issue the following before the implementation part of the documentation:

    \char_set_catcode_letter:n{ 58 }
    \char_set_catcode_letter:n{ 95 }

This makes the macro environments (as well as \cs and friends) read underscores and colons as “letters” (i.e. part of the macro name) as appropriate in LaTeX3 code.


I recently stumbled over the same problem and came across this post. Although it's probably best to adopt l3doc or another more advanced class, for now I needed a quick fix since I did not have time to dive into another documentation class. For those that are in the same situation: You can add


into the preamble of the driver code in the dtx file and then expl3 names should not be a problem anymore.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .