I have spent a couple of hours rethinking the literate style tools we have for LaTeX
, which are essentially doc
, docstrip
and ltxdoc
. Although the traditional workflow with a good editor can be less of a pain, imprisoning the code in guards and percentage marks can be disruptive to the flow of writing code, especially to newcomers. With this in mind and also to try and improve the typography and the functionality of the code, I came up with an alternative.
The central idea is to be able to use any class as the base class (in the MWE I have used the tufte-book) and to be able to have pretty printing using a package such as listings
. The approach is to use only one .tex
file which when compiled produces the documentation as well as the class, package or files.
Essentially it saves code verbatim when is defined. The MWE example only outputs to one .sty
file, but it is possible to save to as many files as one needs (simulating the docstrip
guards). A small installation script can be incorporated and self generated with LuaLaTeX
if one wants to also simulate docstrip
s ability to install files in different directories.
What precautions should one take in developing such a code and are there any essential features of the doc/docstrip
approach that cannot be incorporated in my approach?
\documentclass{tufte-book}
\usepackage{microtype,soul}
\makeatletter
\usepackage[charter]{mathdesign}
\def\rmdefault{bch} % not scaled
\def\ttdefault{blg}
\usepackage{xcolor,filecontents,ragged2e}
\usepackage[listings, theorems]{tcolorbox}
\definecolor{theblue} {rgb}{0.02,0.04,0.48}
\definecolor{thered} {rgb}{0.65,0.04,0.07}
\definecolor{thegreen}{rgb}{0.06,0.44,0.08}
\definecolor{thegrey} {gray}{0.5}
\definecolor{theshade}{gray}{0.94}
\definecolor{theframe}{gray}{0.75}
\lstloadlanguages{[LaTeX]TeX, [primitive]TeX}
% Emphasis
\newcommand\emphasis[2][thered]{\lstset{emph={newcommand,def,gdef,#2},
emphstyle={\ttfamily\textcolor{#1}}}}%
\lstset{language={[LaTeX]TeX},
escapeinside={{(*@}{@*)}},
numbers=left, gobble=2,
stepnumber=1,numbersep=5pt,
numberstyle={\footnotesize\color{gray}},firstnumber=last,
breaklines=true,
framesep=5pt,
basicstyle=\small\ttfamily,
showstringspaces=false,
% keywordstyle=\ttfamily\textcolor{thegreen},
stringstyle=\color{orange},
commentstyle=\color{black},
rulecolor=\color{theshade},
breakatwhitespace=true,
showspaces=false, % shows spacing symbol
xleftmargin=0pt,
xrightmargin=5pt,
aboveskip=3pt plus1pt minus1pt, % compact the code looks ugly in type
belowskip=7pt plus1pt minus1pt, % user responsible to insert any skips
backgroundcolor=\color{theshade}
}
\lst@RequireAspects{writefile}
\lstnewenvironment{Macro}[1][Test]
{\emphasis{#1}\marginpar{\vskip0.5\baselineskip\footnotesize\color{thered}\texttt{\string#1}}
\lst@BeginAlsoWriteFile{textsamples.sty}}
{\endgroup}
\newcommand\lorem{Fusce adipiscing justo nec ante. Nullam in enim.
Pellentesque felis orci, sagittis ac, malesuada et, facilisis in,
ligula. Nunc non magna sit amet mi aliquam dictum. In mi. Curabitur
sollicitudin justo sed quam et quadd. \par}
\DeclareRobustCommand{\todo}[1]{\sidenote{\hl{#1}}}
\author{Y Lazarides}\publisher{Camel Press}
\title{\parindent0pt A New Approach in\\ Documenting Macros}
\begin{document}
\backmatter
\maketitle
\parindent0pt
\mainmatter
\tableofcontents
\chapter{The Approach}
\section{User Documentation}
The user documentation can be styled a bit better. The user should be able to
write the package or class in a more natural style.\todo{Write a few more notes here.}
\medskip
\begin{tcblisting}{colframe=thegreen,boxrule=1pt,colback=thered!5,listing options={style=tcblatex}}
The macro \verb+\LaTeXe+, typesets the \LaTeXe logo.
\end{tcblisting}
\section{Implementation}
\lorem
\Macro[\ProvidesPackage]
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{textsamples}[2012/02/13 v1.0 sample texts]
\endMacro
\lorem
\begin{Macro}[\lorem]
\newcommand\lorem{\leavevmode
Fusce adipiscing justo nec ante. Nullam in enim.
Pellentesque felis orci, sagittis ac, malesuada et, facilisis in,
ligula. Nunc non magna sit amet mi aliquam dictum.
In mi. Curabitur sollicitudin justo sed quam et quadd.
\par
}
\end{Macro}
\lorem
\emphasis{\tex}
\begin{Macro}[\tex]
\gdef{\tex}{%
\TeX\xspace (*@\sidenote{You can even place sidenotes.%
These notes have no impact on the %
code being written to the file.} @*)
}
\end{Macro}
% closes the open file
\begingroup\lst@EndWriteFile
\section{Full listing of {textsamples.sty}}
\lstinputlisting{textsamples.sty}
\end{document}
Note, I have used listings
for the verbatim writes and tcolorbox
for the example self-running box. It also omits doc's
many useful macros which would still need to be adapted.
Best Answer
As discussed in earlier in the comments, it is quite possible to solve the problem of defining classes with this method. Granted, as you said, it takes two runs, but it is possible to make a document that will deal with the writing (and some minimal printing) on the first run, and that will process class-defined commands on the second run only (if correctly marked up, obviously).
In order to perform this check, I rely on the existence (or lack thereof) of an
.aux
file, because it is both easy – most IDEs can delete it in one click, it allows for overwrites, etc. – and user friendly in case of problem – as I expect most users to try to delete this file first if something goes wrong.The only requirement is that we store the code in a class file instead of a package. The following MWE implements this solution, and also a macro-based solution to the problem of multiple files (you should write one file after the other, not mix them up haphazardly). Due to the fact that I am using comma-separated lists for the macros, it might make things easier to index, e.g. adding an optional argument for the type of thing created (macro, environment, counter, etc.).
The
.cls
file:And the
.tex
example of a self-documented class + package:Requires 2 runs of LaTeX to print the documentation + one run of MakeIndex and one final run of LaTeX.
Edit (April 3): Added an
AfterEndEnvironment
hook so the new macro names are set globally after the firstcode
environment (fixes a bug in syntax highlighting).Edit (April 10): Added several new things:
A macro for adding some control sequences to
listings
' colouring, without indexing them:\addcs{}
, which takes a CSV list as its argument.An environment that writes a copyright file and prints it at the beginning of every new file:
\begin{copywrite}
.A command that inputs the listings of all created files, with a "heading" that can be customised via
\renewcommand{\listingshead}
– by default, I have set it to print a section title and a short sentence. (Could be made more customisable I suppose…)Semi-automatic indexing (see below).
Some error messages, because wrong indexing commands are easy to produce and the LaTeX error message was really, really unhelpful.
Several macros that automatically index the marked content of every
code
environment based on its type. It also works with@
characters in macro names. By default, it is assumed that the string is a macro but you can change it using the optional argument (e.g.\begin{code}[e]{myenv}
for an environment).I have defined macros (
m
, default), environments (e
), floats (f
), lengths (l
), dimensions (d
), counters (c
), packages (p
) and options (o
). New types can be defined implicitly:in which case they will be treated as macros. They can also be defined explicitly in the preamble with:
In the main file, you then need to write
\docindex{mymacro}
for control sequences, or\docindex[c]{mycounter}
for everything else. This is made necessary by the fact that, while you can have only one control sequence with a given name, you can have several strings of other types with the same name (say the\chapter
command vs thechapter
counter and perhaps achapter
colour).I will try to set up a repository with the complete file (which includes options at class selection), and try to work on some documentation as things are getting a bit complex now.
And I would indeed be very happy to get any feedback regarding bugs and possible features or improvements – in the hope that it can become a package once tested and cleaned up.