[Tex/LaTex] How would you typeset this type of programming documentation

automationindentationlistingssectioning

Consider, for example, this pdf document which defines the standard for the C programming language. The description of the library functions follows a fixed structure composed of three sections, as shown in the picture below: synopsis, description and returns with numbered paragraphs.

Description of an example function

To reproduce this structure, I would:

  1. Define a subsection (or subsubsection) heading with no numbering and bold title.
  2. Use the package listings to typeset the synopsis.
  3. I don't know how to typeset the paragraph numbers in the margins, but for my specific document I'm not interested in this feature.

According to the above plan, here is a working code which reproduces the given example page (without paragraph numbering to which I'm not interested):

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{listings}

\renewcommand{\ttfamily}{\usefont{T1}{lmtt}{b}{n}}
\newcommand{\func}[1]{\texttt{#1}}

\setcounter{secnumdepth}{1}

\begin{document}
\lstset{basicstyle=\ttfamily,tabsize=8}

\section{The \func{rand} function}
\subsection{Synopsis}
\begin{lstlisting}
    #include <stdlib.h>
    int rand(void);
\end{lstlisting}

\subsection{Description}
The \func{rand} function computes a sequence of pseudo-random integers in the range 0 to \func{RAND\_MAX}.

The \func{rand} function is not required to avoid data races with other calls to pseudo-random sequence generation functions. The implementation shall behave as if no library function calls the rand function.

\subsection{Returns}
The \func{rand} function returns a pseudo-random integer.
\subsection{Environmental limits}
The value of the \func{RAND\_MAX} macro shall be at least 32767.
\end{document}

The above code yields:

Rendered code

This result is ok for me, but I'm wondering:

If you were to write a manual for a library of functions, which has from a few to many sections similar to that above, with the same sequence of subsections and with the same indentation of the code (here realized with a tab character), would you do it in a different, maybe better, way?

In the above, better might mean by defining an environment (e.g. a list) with a parameter for the code and items which generate the correct sequence of headings.

Best Answer

You write

[...] would you do it in a different, maybe better, way? [...] better might mean by defining an environment (e.g. a list) with a parameter for the code and items which generate the correct sequence of headings.

Make your life easier

Strive for automation, consistency, and maintainability. (Note that those desiderata are all a bit intertwined and not strictly independent.) Here are some tips.

  1. You should define an environment (called fun below) for typesetting the entire section dedicated to a function. This environment should

    • accept one mandatory argument, corresponding to the name of the function of interest, and define a macro for easily typesetting the function's name;
    • typeset the section heading;
    • define a number of "subenvironments" for Description, Returns, etc. that typeset the corresponding subsection headings.

    What's nice about that last point (defining those four three environments within the fun environment, as opposed to globally) is that it provides some encapsulation, insofar as those environments can only be invoked within a fun environment. If, for instance, you try to write

    \begin{fundesc}
    ...
    \end{fundesc}
    

    outside a fun environment (where it wouldn't make sense), you will get a compilation error. This prevents you from typesetting stuff where it doesn't belong.

    Edit: Unfortunately, listings mechanism for defining a custom environment (\lstnewenvironment) does so at the global scope; therefore, encapsulation is not possible for the environment dedicated to synopses.

  2. Without countermeasures, any indentation inside an lstlisting environment is typeset verbatim in the output. See my remark in How can I automatically prepend a prompt (e.g. $) to each line of a listing?.

    To free yourself from inconsistent indentation in the input, you should use either Martin Scharrer's lstautogobble package or my experimental lstautodedent package, and let listings's xleftmargin key take care of listings' left margin for you:

    \usepackage{lstautodedent}
    %...
    \lstset{
      %...
      autodedent,
      xleftmargin = 4em, % (for instance)
    }
    

Implementation

\documentclass{article}

\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{listings}
\usepackage{lstautodedent}

\renewcommand{\ttfamily}{\usefont{T1}{lmtt}{b}{n}}
\newcommand{\func}[1]{\texttt{#1}}

\setcounter{secnumdepth}{1}

% `Synopsis' environment
\lstnewenvironment{funsynop}{
  \subsection{Synopsis}
  \lstset{
    basicstyle  = \ttfamily,
    tabsize     = 8,
    autodedent,
    xleftmargin = 4em,
  }%
}{}

% Custom environment for typesetting everything related to a function
\newenvironment{fun}[1]{%
  \newcommand\funname{\func{#1}}
  \section{The \funname{} function}
  % `Description' environment
  \newenvironment{fundesc}{%
    \subsection{Description}
  }{}
  % `Returns' environment
  \newenvironment{funret}{%
    \subsection{Returns}
  }{}
  % `Environmental limits' environment
  \newenvironment{funlim}{%
    \subsection{Environmental limits}
  }{}
}{}


\begin{document}

\begin{fun}{rand}
  \begin{funsynop}
    #include <stdlib.h>
    int rand(void);
  \end{funsynop}
  %
  \begin{fundesc}
    The \funname{} function computes a sequence of pseudo-random integers
    in the range 0 to \func{RAND\_MAX}.

    The \funname{} function is not required to avoid data races with other calls
    to pseudo-random sequence generation functions.
    The implementation shall behave as if no library function calls the
  \funname{} function.
  \end{fundesc}
  %
  \begin{funret}
    The \funname{} function returns a pseudo-random integer.
  \end{funret}
  %
  \begin{funlim}
    The value of the \func{RAND\_MAX} macro shall be at least 32767.
  \end{funlim}
\end{fun}

\begin{fun}{foo}
  \begin{funsynop}
               foo = foo : foos  <--- messed up indentation
                                      (but output is fine)
  \end{funsynop}
  %
  \begin{fundesc}
    The \funname{} function blah blah blah
  \end{fundesc}
  %
  \begin{funret}
    The \funname{} function returns a foo.
  \end{funret}
  %
  \begin{funlim}
    The \funname{} function is limited to \func{bar}.
  \end{funlim}
\end{fun}
\end{document}

enter image description here


Possible improvements

  • Enforce the order in which the four "subenvironments" are meant to appear.
  • (If needed) Throw a compilation error if one or more of those "subenvironments" are missing.
Related Question