From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- macros/latex/contrib/skdoc/Makefile | 59 + macros/latex/contrib/skdoc/README | 38 + macros/latex/contrib/skdoc/skdoc.dtx | 3326 ++++++++++++++++++++++++++++++++++ macros/latex/contrib/skdoc/skdoc.pdf | Bin 0 -> 271754 bytes 4 files changed, 3423 insertions(+) create mode 100644 macros/latex/contrib/skdoc/Makefile create mode 100644 macros/latex/contrib/skdoc/README create mode 100644 macros/latex/contrib/skdoc/skdoc.dtx create mode 100644 macros/latex/contrib/skdoc/skdoc.pdf (limited to 'macros/latex/contrib/skdoc') diff --git a/macros/latex/contrib/skdoc/Makefile b/macros/latex/contrib/skdoc/Makefile new file mode 100644 index 0000000000..6a247013d9 --- /dev/null +++ b/macros/latex/contrib/skdoc/Makefile @@ -0,0 +1,59 @@ +TEXMFHOME ?= $(shell kpsewhich -var-value TEXMFHOME) +.PHONY: all clean distclean install dist test clean-test +all: skdoc.dtx skdoc.cls skdoc.pdf README +clean: clean-test + rm -f *.gl? *.id? *.aux # problematic files + rm -f *.bbl *.bcf *.bib *.blg *.xdy # biblatex + rm -f *.fls *.log *.out *.run.xml *.toc # junk +distclean: clean + rm -f *.cls *.sty *.clo *.tar.gz *.tds.zip README + git reset --hard + +%.cls: %.dtx + tex $< + +%.pdf: %.dtx + pdflatex -interaction=nonstopmode -halt-on-error $< + makeglossaries $* + biber $* + pdflatex -interaction=nonstopmode -halt-on-error $< + makeglossaries $* + pdflatex -interaction=nonstopmode -halt-on-error $< + +README: README.md + sed -e '1,4d;$$d' $< > $@ + +install: all + install -m 0644 skdoc.cls $(TEXMFHOME)/tex/latex/skdoc/skdoc.cls + install -m 0644 skdoc.pdf $(TEXMFHOME)/doc/latex/skdoc/skdoc.pdf + install -m 0644 skdoc.tex $(TEXMFHOME)/source/latex/skdoc/skdoc.dtx + install -m 0644 README $(TEXMFHOME)/doc/latex/skdoc/README + -mktexlsr + +skdoc.tds.zip: all + mkdir -p skdoc/tex/latex/skdoc + cp skdoc.cls skdoc/tex/latex/skdoc/skdoc.cls + mkdir -p skdoc/doc/latex/skdoc + cp skdoc.pdf skdoc/doc/latex/skdoc/skdoc.pdf + mkdir -p skdoc/source/latex/skdoc + cp skdoc.dtx skdoc/source/latex/skdoc/skdoc.dtx + cp README skdoc/doc/latex/skdoc/README + cd skdoc && zip -r ../skdoc.tds.zip * + rm -rf skdoc + +skdoc.tar.gz: all skdoc.tds.zip + mkdir -p skdoc + cp skdoc.dtx skdoc/skdoc.dtx + cp skdoc.pdf skdoc/skdoc.pdf + cp README skdoc/README + cp Makefile skdoc/Makefile + tar -czf $@ skdoc skdoc.tds.zip + rm -rf skdoc + +dist: skdoc.tar.gz + +test: +# $(MAKE) -C tests + +clean-test: +# $(MAKE) -C tests clean diff --git a/macros/latex/contrib/skdoc/README b/macros/latex/contrib/skdoc/README new file mode 100644 index 0000000000..ffa816f402 --- /dev/null +++ b/macros/latex/contrib/skdoc/README @@ -0,0 +1,38 @@ +%% skdoc documentation class +%% +%% Copyright (C) 2012-2018 by Simon Sigurdhsson +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.3 +%% of this license or (at your option) any later version. +%% The latest version of this license is in +%% http://www.latex-project.org/lppl.txt +%% and version 1.3 or later is part of all distributions of LaTeX +%% version 2005/12/01 or later. +%% +%% This work has the LPPL maintenance status `maintained'. +%% +%% The Current Maintainer of this work is Simon Sigurdhsson. +%% +%% This work consists of the files skdoc.dtx +%% and the derived filebase skdoc.cls. + +This is version 1.5a of the skdoc document class. It is designed to +generate both documentation and derivative files using only LaTeX, +i.e. without using docstrip and ins/dtx files. + +The following files are enclosed. + + README - This file + Makefile - GNU Makefile for making the package and documentation + skdoc.dtx - LaTeX source code of the package + skdoc.pdf - PDF version of the documentation + +Installation notes: +The easiest way to install this package, assuming you have obtained the +source code from Github or CTAN, is to simply run `make install`. This +will generate package code and documentation, install it into TEXMFHOME +and run `mktexlsr`. If you wish to compile the package but not install +it, run `make all` instead. If you insist on doing it manually, remember +to run `tex` to generate the code, and `pdflatex` (or `latex`, if you +don't fancy PDFs) to generate the documentation. diff --git a/macros/latex/contrib/skdoc/skdoc.dtx b/macros/latex/contrib/skdoc/skdoc.dtx new file mode 100644 index 0000000000..d0eff7eea0 --- /dev/null +++ b/macros/latex/contrib/skdoc/skdoc.dtx @@ -0,0 +1,3326 @@ +% \iffalse +%% skdoc documentation class +%% +%% Copyright (C) 2012-2018 by Simon Sigurdhsson +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.3 +%% of this license or (at your option) any later version. +%% The latest version of this license is in +%% http://www.latex-project.org/lppl.txt +%% and version 1.3 or later is part of all distributions of LaTeX +%% version 2005/12/01 or later. +%% +%% This work has the LPPL maintenance status `maintained'. +%% +%% The Current Maintainer of this work is Simon Sigurdhsson. +%% +%% This work consists of the files skdoc.dtx +%% and the derived filebase skdoc.cls. +% +%<*ignore> +\begingroup + \catcode123=1 % + \catcode125=2 % + \def\x{LaTeX2e}% +\expandafter\endgroup +\ifcase 0\ifx\install y1\fi\expandafter + \ifx\csname processbatchFile\endcsname\relax\else1\fi + \ifx\fmtname\x\else 1\fi\relax +\else\csname fi\endcsname +% +%<*install> +\input docstrip.tex + +\preamble +\endpreamble + +\keepsilent +\askforoverwritefalse + +\generate{% + \file{skdoc.cls}{\from{skdoc.dtx}{class}}% +} + +\begingroup +\obeyspaces +\Msg{*************************************************************}% +\Msg{* *}% +\Msg{* To finish the installation you have to move the following *}% +\Msg{* file into a directory searched by TeX: *}% +\Msg{* *}% +\Msg{* skdoc.cls *}% +\Msg{* *}% +\Msg{* To produce the documentation run the file skdoc.dtx *}% +\Msg{* through LaTeX. *}% +\Msg{* *}% +\Msg{* Happy TeXing! *}% +\Msg{* *}% +\Msg{*************************************************************}% +\endgroup% + +\endbatchfile +% +%<*ignore> +\fi +% +%<*class> +\RequirePackage{expl3} +% +%<*driver> +\RequirePackage{xparse} +\ProvidesExplFile{skdoc.dtx} +% +%\ProvidesExplClass{skdoc} +%<*class> + {2018/04/18}{1.5a}{skdoc documentation class} +% +% +%<*driver> +\msg_new:nnn{skdoc-dtx}{not-installed} + {Run~`tex'~on~skdoc.dtx~before~generating~the~documentation!} +\IfFileExists{skdoc.cls}{}{ + \msg_fatal:nn{skdoc-dtx}{not-installed} +} +\cs_set_protected_nopar:Npn\ExplHack{ + \char_set_catcode_letter:n{ 58 } + \char_set_catcode_letter:n{ 95 } +} +\ExplSyntaxOff +\DeclareDocumentCommand\MakePercentIgnore{}{\catcode`\%9\relax} +\DeclareDocumentCommand\MakePercentComment{}{\catcode`\%14\relax} +\DeclareDocumentCommand\DocInput{m}{ + \MakePercentIgnore\input{#1}\MakePercentComment +} +\documentclass[highlight=false]{skdoc} +\usepackage{hologo} +\usepackage{booktabs} +\usepackage{csquotes} +\usepackage[style=authoryear,backend=biber]{biblatex} +%%\usepackage{chslacite} +\begin{filecontents}{skdoc.bib} +@online{Lazarides12, + author = {Yannis Lazarides}, + title = {Different approach to literate programming for \LaTeX}, + year = {2012}, + url = {http://tex.stackexchange.com/q/47237/66} +} +@online{Talbot13, + author = {Nicola Talbot}, + title = {Answer to \enquote{Distinct formatted page numbers with glossaries and Xindy}}, + year = {2013}, + url = {http://tex.stackexchange.com/a/89830/66} +} +@manual{Rahtz10, + author = {Sebastian Rahtz and Herbert Vo\ss}, + title = {The \enquote{\textsf{fancyvrb}} package}, + subtitle = {Fancy Verbatims in \LaTeX}, + date = {2012-05-15}, + version = {2.8}, + url = {http://mirrors.ctan.org/macros/latex/contrib/fancyvrb/fancyvrb.pdf} +} +\end{filecontents} +\addbibresource{skdoc.bib} +\OnlyDescription +\begin{document} + \DocInput{skdoc.dtx} +\end{document} +% \fi +% +% \deftripstyle{skdoc-class}{}{}{}% +% {\small The~\textbf{\thepkg}~document~class,~\theversion}% +% {}{\small\pagemark} +% \pagestyle{skdoc-class} +% +% \version{1.5a} +% \changes{1.0}{Initial version} +% \changes{1.1}{Added support for syntax highlighting using \pkg{minted}} +% \changes{1.1a}{Deprecate the use of \pkg{bibtex} in favour of \pkg{biblatex}} +% \changes{1.2}{Use \pkg{l3prg} booleans instead of toggles} +% \changes{1.2b}{Use \pkg{inconsolata}. Don't use \pkg{ascii}} +% \changes{1.3}{Allow multiple targets per \env{MacroCode}} +% \changes{1.3b}{Use \pkg{sourcecodepro} instead of \pkg{inconsolata}. Fix issue with index entries of different types with same name} +% \changes{1.4}{Added option to control \pkg{babel}. Allow optional default value arguments in \env{macro} and friends. Fix spacing issue in \env{option} and friends} +% \changes{1.4a}{Fix various compatibility issues with latest \pkg{glossaries}} +% \changes{1.4b}{Track \pkg{expl3} changes (thanks to Joseph Wright)} +% \changes{1.5}{Fix incompatibilities with \pkg{minted}} +% \changes{1.5a}{Track \pkg{expl3} changes (thanks to Felix Faltin)} +% \iffalse +%%% Don't forget to update the version number and release date of +%%% the package declaration on line 76! +% \fi +% +% \package[ctan=skdoc,vcs=https://github.com/urdh/skdoc]{skdoc} +% \repository{https://github.com/urdh/skdoc} +% \title{The \thepkg{} document class} +% \author{Simon Sigurdhsson} +% \email{sigurdhsson@gmail.com} +% \maketitle +% +% \begin{abstract} +% The \thepkg{} class provides macros to document the functionality +% and implementation of \LaTeX\ packages and document classes. It is +% loosely based on the \pkg{ydoc} and \pkg{ltxdoc} classes, but has +% a number of incompatible differences. +% +% The class defines a \env{MacroCode} environment which substitutes +% the usual \pkg{docstrip} method of installing packages. It has the +% ability to generate both documentation and code in a single run of +% a single file. +% \end{abstract} +% +% \tableofcontents +% +% \section{Introduction} +% This document class, inspired by a question on the \TeX\ Stack +% Exchange\footcite{Lazarides12}, aims to provide an alternative to +% the standard \pkg{docstrip} method of literate programming for +% \LaTeX\ packages. It also aims to provide a more modern, appealing +% style for \LaTeX\ package documentation. +% +% In order to achieve this, it builds upon already existing features +% of the \pkg{expl3}, \pkg{verbatim} and \pkg{ydoc} packages as well +% as the KOMA-script document classes. +% +% So far it is mainly intended to be an experiment to explore a less +% cumbersome way of writing \LaTeX\ packages, and as such I give no +% guarantee that this package will continue to exist in a working +% state (\emph{i.e.} future users may not be able to extract code from +% package documentation based on \thepkg) or that its public API +% (commands and environments described by this documentation; consider +% undocumented macros part of a private API) will be stable. +% +% The documentation of \thepkg\ is in fact typeset using the class +% itself. It does not, however, make use of the main feature of this +% class (the \env{MacroCode} environment), because bootstrapping the +% class to generate itself is more complicated than it is useful. +% +% \section{Documentation} +% Since \thepkg\ is based on \pkg{ydoc} many of the macros and +% environment present in that package are also available in \thepkg, +% in a possibly redefined incanation. However, any macros or +% environment present in \pkg{ydoc} but not described in this +% documentation should be considered part of the private API of +% \thepkg. In the future, the removal of the \pkg{ydoc} dependency +% may result in such macros being unavailable, and at present changes +% made by \thepkg\ may break such macros without notice. +% +% \subsection{Options} +% \Option{load}\WithValues{\meta{package}}\AndDefault{\cs{jobname}} +% \label{ssec:options:load} The \opt{load} +% option declares that if the package specified exists, it should +% be loaded. This is intended to load any package provided in the +% implementation, but requires that the documentation provides +% stub variants of the macros used in the documentation so that +% \LaTeX\ still completes its first run. +% +% \Option{highlight}\WithValues{true,false}\AndDefault{true} +% \label{ssec:option:highlight} +% The \opt{highlight} option enables or disabled syntax highlighting +% of the implementation code. Highlighting is performed using +% \pkg{minted}, and falls back to no highlighting if there is no +% \cs{write18} access, if \pkg{minted} is unavailable or if the +% \texttt{pygmentize} binary can't be found. +% \Notice{On non-unix platforms, the test for \texttt{pygmentize} +% will likely fail. Therefore, syntax highlighting is not supported +% on such platforms.} +% +% Generally, there should be no reason to disable syntax highlighting +% unless the documentation describes a very large package, and the +% repeated calls to \texttt{pygmentize} take too long. +% +% \Option{babel} +% The \opt{babel} option allows you to specify what languages are loaded +% by the \pkg{babel} package. It is a key-value option, and its content +% is passed as options to the \pkg{babel} \cs*{usepackage} declaration. +% +% \subsection{General macros} +% The document class defines a number of general macros intended for +% use in parts of the document not strictly considered +% \enquote{documentation} or \enquote{implementation}, in addition to +% being used in those parts. These \enquote{general} macros include +% macros that define metadata, generate the title page, typeset +% notices or warnings and those that refer to macros, environments, +% packages and such. +% +% \subsubsection{Metadata} +% Several macros for defining metadata (\emph{i.e.} information about +% the package and its documentation) are made available. These mostly +% set an internal variable which is used to typeset the title page, +% and to insert PDF metadata whenever \hologo{pdfLaTeX} is used to +% generate the documentation. +% +% \DescribeMacro\package['ctan='',vcs=']{} +% The \cs{package} macro defines the package name used by \cs{thepkg}, +% \cs{maketitle} and similar macros. It also calls \cs{title} to set +% a sensible default title based on the package name. The optional +% key-value argument takes two keys: \texttt{ctan} and \texttt{vcs}. +% The first one accepts an optional value \meta{identifier}, which +% should be the identifier the package has on CTAN (the default is +% \cs{jobname}), while the other takes a mandatory argument \meta{url} +% specifying the URL of a VCS repository where development versions +% of the package are available. The two optional keys imply calls to +% the \cs{ctan} and \cs{repository} macros, respectively. +% +% \DescribeMacro\version{} +% Sets the version number of the package the documentation describes. +% Here, \meta{version} should not include the initial \enquote{v}, +% \emph{i.e.} the argument should be the same as that given to +% \emph{e.g.} the \LaTeX3 \cs{ProvidesExplPackage} or the standard +% \pkg{ltxdoc} \cs{changes}. +% +% \DescribeMacro\ctan{} +% As detailed above, this macro defines the CTAN identifier of the +% package, which is (optionally) used in the \cs{maketitle} macro. +% +% \DescribeMacro\repository{} +% Again, as detailed above this macro defines the URL of a source code +% repository containing a development version of the package, which +% is optionally used by \cs{maketitle}. +% +% \DescribeMacro\author{} +% Defines the name of the package author. This is used by +% \cs{maketitle} and is mandatory if \cs{maketitle} is used. +% +% \DescribeMacro\email{} +% Defines the email of the package author. This is used by +% \cs{maketitle} and is mandatory if \cs{maketitle} is used. +% +% \DescribeMacro\title{} +% Defines the package title. By default, the \cs{package} macro sets +% a sensible title that should suit most packages, but using \cs{title} +% will override this title (useful for \emph{e.g.} document classes or +% \hologo{BibTeX} styles). +% +% Three macros retrieving the set metadata are also available. They +% can be used to typeset the current version of the package, and the +% package name, respectively. +% +% \DescribeMacro\theversion +% Returns the version as defined by \cs{version}, with a leading +% \enquote{v}. That is, issuing \Macro\version{1.0} makes +% \cs{theversion} print \enquote{v1.0}. +% +% \DescribeMacro\thepackage +% \DescribeMacro\thepkg +% The \cs{thepackage} and \cs{thepkg} macros return the package name +% as defined by the \cs{package} macro, enclosed in \cs{pkg*}. That is, +% the package name is typeset as a package but not indexed. +% +% \subsubsection{The preamble} +% The preamble of any documentation most often consists of a title page +% containing an abstract, and possibly a table of contents. The \thepkg +% \ package provides macros and environments that typeset such things, +% and these should be fully compatible with most other document classes. +% +% \DescribeMacro\maketitle +% The \cs{maketitle} macro typesets a title page. This title page uses +% the metadata defined by the macros described earlier, and typesets +% them in a manner which is illustrated by the documentation of this +% class. This style is inspired by \pkg{skrapport}, which is in turn +% inspired by the title pages of the Prac\TeX\ Journal. +% +% \DescribeEnv[<package abstract>]{abstract} +% The \env{abstract} environment typesets an abstract of the package. +% Again, its style is illustrated by this document and it is inspired +% by the \pkg{skrapport} package as well as the Prac\TeX\ Journal. +% +% \DescribeMacro\tableofcontents +% Finally, a Table of Contents may be printed. The actual table of +% contents is provided by the \pkg{scrartcl} document class, but \thepkg +% \ redefines a couple of the internal macros to style the Table of +% Contents in a manner similar to that of the \pkg{microtype} manual. +% +% \subsubsection{The LPPL license} +% \DescribeMacro\PrintLPPL +% If the LPPL license is present in a directory where \LaTeX\ can find +% it, in a file called \file{lppl.tex}, then \cs{PrintLPPL} will +% include the entire LPPL license in the document, and typeset it in +% a fairly compact manner. +% +% \subsubsection{Notices and warnings} +% The document class provides macros to indicate information that may +% be of extra importance in the documentation. Such information is +% categorized as either notices or warnings, which are treated +% differently. +% +% \DescribeMacro\Notice{<notice>} +% A notice is a short piece of text that contains information that may +% explain some unexpected but unharmful behaviour of a macro or similar. +% It is typeset inline, emphasized and in parantheses --- as such, the +% sequence \Macro\Notice{a notice} yields \Notice{a notice}. +% +% \DescribeMacro\Warning{<warning>} +% A warning is a short comment that conveys information that the user +% must be aware of. This includes unexpected potentially harmful +% behaviour, deprecation notices and so on. It is typeset in its own +% \cs{fbox} --- the sequence \Macro\Warning{a warning} yields the +% following: \Warning{a warning} +% +% \DescribeMacro\LongWarning{<warning>} +% The \cs{LongWarning} macro is a variant of \cs{Warning} that has been +% adapted for longer texts, possibly including paragraph breaks. Like +% \cs{Warning}, it is typeset in a box: \LongWarning{a long warning} +% +% \subsubsection{Referential macros}\label{sec:ref-macros} +% The family of macros originating from \cs{cs} are used to typeset +% various concepts in running text. In addition to adhering to the +% general format of the corresponding concept, they index their +% argument. Each of these macros have a starred variant which does +% not index its argument; use these when appropriate. +% +% \DescribeMacro\cs{<command sequence>} +% Typesets a command sequence, or macro. The argument should be +% provided without the leading backslash, and the command sequence +% will be typeset in a monospaced font. +% +% \DescribeMacro\env{<environment name>} +% Typesets an environment name, which will be typeset in a monospace +% font. +% +% \DescribeMacro\pkg{<package name>} +% Typesets a package, document class or bundle name. The name will +% be typeset in a sans-serif font. +% +% \DescribeMacro\opt{<option>} +% Typesets a package or document class option. As of \theversion, +% options are typeset using a monospace font. +% +% \DescribeMacro\bib{<\hologo{BibTeX} entry type>} +% Typesets a \hologo{BibTeX} entry type. The agument should be provided +% without the leading \texttt{@} sign. The entry type will be typeset +% in a monospace font. +% +% \DescribeMacro\thm{<theme name>} +% Typesets a theme name. As of \theversion, the theme name will be +% typeset in an upright serif font. +% +% \DescribeMacro\file{<filename>} +% Typesets a filename. As of \theversion, the filename will be typeset +% in a monospace font. +% +% \subsection{Documenting the package}\label{sec:doc-macros} +% The documentation part of any \LaTeX\ manual is arguably the most +% important one, and to facilitate proper typesetting of the +% documentation \thepkg\ povides a number of different macros, all +% inspired by or inherited from \pkg{ydoc}. The first of these +% macros that will be discussed are the macros that typeset differen +% kinds of arguments in running text. +% +% \DescribeMacro\meta{<meta text>} +% The \cs{meta} macro typesets a placeholder to be placed in an +% argument. This can be used to refer to arguments and contents of +% macros and environments described by commands discussed later in +% this documentation. It is typeset in brackets: \meta{meta text}. +% +% \DescribeMacro\marg{<mandatory argument>} +% \DescribeMacro\oarg{<optional argument>} +% \DescribeMacro\parg{<picture-style argument>} +% \DescribeMacro\aarg{<beamer-style argument>} +% \DescribeMacro\sarg +% These macros typeset different kinds of arguments (mandatory, +% optional, picture-style, beamer-style and star arguments, +% respetively). These can be used to describe arguments, but +% are mostly used internally. See table~\ref{tab:args} for +% examples of how these macros are typeset. +% +% \begin{table}[tb] +% \centering +% \caption{Typesetting arguments} +% \label{tab:args} +% \begin{tabular}{ll} +% \toprule +% Invokation & Result \\ +% \midrule +% \Macro\marg{argument} & \marg{argument} \\ +% \Macro\oarg{argument} & \oarg{argument} \\ +% \Macro\parg{argument} & \parg{argument} \\ +% \Macro\aarg{argument} & \aarg{argument} \\ +% \Macro\sarg & \sarg \\ +% \bottomrule +% \end{tabular} +% \end{table} +% +% \subsubsection{Examples} +% \DescribeEnv[<example code>]{example} +% Perhaps the most powerful way to illustrate features of a package +% is to show their function by examples. This is made possible by +% the \env{example} environment. By enclosing example code in this +% environment, the actual code is typeset next to the result it would +% produce, as seen below\footnote{Note that the showcased \env{example} +% environment doesn't contain another \env{example} environment --- the +% environment is not intended to be nested inside itself.}\footnote{The +% percent characters in the example are caused by the \pkg{docstrip} +% requirement of prefixing the documentation with them.}: +% \begin{example} +% Simply typesetting a +% \emph{paragraph} may +% be simple enough, but +% it should showcase +% the utility of the +% environment well enough. +% \end{example} +% +% Note that for this to work the package obviously needs to be loaded. +% As such, it is probably a good idea to combine the use of \env{example} +% with the \opt{load} option, so be sure to read up on the caveats of +% using that option (see page \pageref{ssec:options:load}). +% +% Since the \env{example} environment is based on the same mechanisms +% as \env{MacroCode}, (mostly) the same typesetting properties apply. +% In particular, the code will be highlighted if \pkg{minted} is +% available. \Notice{Since the backend utilizes \cs{verbatim}, the +% usual caveats apply. In particular, leaving whitespace before +% \cs{end}\marg{example} will result in an extra newline at the end +% of the displayed code.} +% +% \subsubsection{Options} +% Package options are of course important to describe, and to this +% end four macros are provided. They aid in describing options of +% both regular boolean and the more modern key-value syntax. They +% are intended to be used in a sequence: \\ +% \mbox{\Macro\Option{...} +% \AlsoMacro\WithValues{...} +% \AlsoMacro\AndDefault{...}} +% +% \DescribeMacro\Option{<option>} +% \DescribeMacro\Options{<option>,...} +% These macros typeset an option, and may be followed by the +% \cs{WithValues} macro \Notice{the with \cs{Options}, only the +% first option in the list will work with \cs{WithValues}}. +% +% \DescribeMacro\WithValues{<value>,...} +% This macro typesets a comma-separated list of values a specific +% option can take. It may be followed by the \cs{AndDefault} macro. +% +% \DescribeMacro\AndDefault{<default value>} +% This macro typesets the default value of an option. It may follow +% either \cs{Options} or \cs{WithValues}. +% +% Common constructs using these macros include: +% \begin{itemize} +% \item \mbox{\small +% \Macro\Option{<option>} +% \AlsoMacro\WithValues{<value>,...} +% \AlsoMacro\AndDefault{<default>}} +% \item \mbox{\small +% \Macro\Options{<option>,no\meta{option}} +% \AlsoMacro\AndDefault{no\meta{option}}} +% \end{itemize} +% +% \subsubsection{Macros} +% The \thepkg\ class inherits a number of macros for describing the +% package macros from the \pkg{ydoc} package. Only four of them are +% to be considered stable. +% \LongWarning{ +% The macros \cs{MakeShortMacroArgs} and \cs{DeleteShortMacroArgs} +% and the environments \env{DescribeMacros} and \env{DescribeMacrosTab} +% provided by \pkg{ydoc} are unsupported as of \thepkg\ \theversion. +% They may work, but this is +% not a guarantee and they are most likely broken or may break other +% features of \thepkg. +% } +% +% \DescribeMacro\DescribeMacro<\textbackslash macro><macro arguments> +% The \cs{DescribeMacro} macro documents a macro along with its +% arguments. Any number of \meta{macro arguments} may follow the macro, +% and \cs{DescribeMacro} will stop reading arguments on the first +% non-argument token. The macro will be indexed. +% \LongWarning{Although \meta{\textbackslash macro} can include +% \texttt{@} signs, it is not possible to document \LaTeX3-style +% macros (with underscores and colons) without the following hack: +% \par \medskip \begingroup +% \cs*{ExplSyntaxOn} \\ +% \cs*{cs\_set\_protected\_nopar:Npn}\cs*{ExplHack}\texttt{\{} \\ +% \hspace*{2ex}\cs*{char\_set\_catcode\_letter:n}\texttt{\{~58~\}} \\ +% \hspace*{2ex}\cs*{char\_set\_catcode\_letter:n}\texttt{\{~95~\}} \\ +% \texttt{\}} \\ +% \cs*{ExplSyntaxOff} \\ +% \cs*{ExplHack} \\ +% \endgroup } +% +% \DescribeMacro\Macro<\textbackslash macro><macro arguments> +% This is simply a variant of \cs{DescribeMacro} for use in running +% text. It is equivalent to \cs{MacroArgs}\cs{AlsoMacro}. +% +% \DescribeMacro\MacroArgs<macro aguments> +% This macro formats \meta{macro arguments} the same way +% \cs{DescribeMacro} does. As with \cs{Macro}, it is used in +% running text. +% +% \DescribeMacro\AlsoMacro<\textbackslash macro><further arguments> +% This macro should be used inside \meta{macro arguments} of the macros +% described above, and typesets an additional macro as part of the +% syntax of the described macro. For instance, the \cs{csname} macro +% could be described with the sequence +% \cs*{Macro}\cs*{csname}\texttt{<command sequence name>} +% \cs*{AlsoMacro}\cs{endcsname}, which would be rendered as +% \Macro\csname<command sequence name>\AlsoMacro\endcsname\relax. +% +% \subsubsection{Environments} +% In addition to the macros describing macros, \thepkg\ also inherits +% one environment and one macro to describe environments. These are +% similar to the macros described previously in both form and function, +% but lack equivalents for running text. +% +% \DescribeMacro\DescribeEnv[<body content>]{<name>}<arguments> +% This macro describes an environment, in the same way +% \cs{DescribeMacro} does for macros. The \meta{body content}, which +% is optional, may be used to indicate what kind of content the +% environment is designed to contain. The \cs{MacroArgs} +% macro is automatically inserted before \meta{body content}. +% +% \subsubsection{Other entities} +% The document class also provides macros to describe \hologo{BibTeX} +% entries and generic themes. The \hologo{BibTeX} entries are described +% using the \cs{BibEntry} and \cs{WithFields} macros, while themes are +% described using the \cs{Theme} macro. +% +% \DescribeMacro\BibEntry{<entry name>} +% \AlsoMacro\WithFields[<optional fields>]{<mandatory fields>} +% These two macros describe a \hologo{BibTeX} entry named +% \meta{entry name} (\emph{i.e.}, \bib*{\meta{entry name}}) along with +% its optional and mandatory fields. +% +% \DescribeMacro\Theme{<theme name>} +% This macro describes a theme named \meta{theme name}. These could be +% used to describe any kind of theme, such as color themes of a +% document class. +% +% \DescribeMacro\DescribeFile{<filename>} +% This macro describes a special file named \meta{filename}. This +% could be a configuration file or similar that is either part of +% the package or something the package reads if available. +% +% \subsection{Describing the implementation} +% In true \TeX\ (and literal programming) fashion the document class +% also provides ways to describe, in detail, parts of the +% implementation. The most essential of the implementation environments, +% without which \thepkg\ doesn't generate any files, is the +% \env{MacroCode} environment. Other than that, the implementation +% environments should be compatible with or analogous to the standard +% \pkg{ltxdoc} document class. +% +% \subsubsection{Implementation environments}\label{sec:impl-env} +% The environments described in this section indicate the +% implementation of different concepts including macros, environments +% and options. They each have a starred variant which doesn't print +% the concept name (only indexes it), and a non-starred variant which +% does \Notice{inside these environments, \cs{changes} will refer to +% the relevant entity instead of logging \enquote{general} changes}. +% +% Some of the following environment can typeset descriptions of the +% internal arguments (\texttt{\#1}, \texttt{\#2} \emph{etc.}) to +% improve readability of the implementation code. +% +% \DescribeEnv[<description>]{macro}{<\textbackslash macro>} +% [<\# of args>]{<arg 1 description>}[<default value>]'...' +% {<arg n description>}[<default value>] +% With this environment, the implementation of a macro is described. +% Note that as with \cs{DescribeMacro}, \LaTeX3-style macros can not +% be used in \meta{\textbackslash macro} without the catcode hack +% mentioned earlier. +% +% \DescribeEnv[<description>]{environment}{<environment>} +% [<\# of args>]{<arg 1 description>}[<default value>]'...' +% {<arg n description>}[<default value>] +% This environment describes the implementation of an environment. +% +% \DescribeEnv[<description>]{option}{<option>} +% This environment describes the implementation of an option. +% +% \DescribeEnv[<description>]{bibentry}{<@entry>} +% This environment describes the implementation of a \hologo{BibTeX} +% entry type. +% +% \DescribeEnv[<description>]{theme}{<theme>} +% This environment describes the implementation of a theme. +% +% \subsubsection{The \env{MacroCode} environment} +% The \enquote{main event} of the \thepkg\ document class is the +% \env{MacroCode} environment. It has roughly the same role the +% \env{macrocode} environment has in the \pkg{docstrip} system, except +% that it in addition to typesetting the implementation also saves it +% to the target files. +% +% The workflow is simple; before using \env{MacroCode} to export code +% to a file the file must be declared using \cs{DeclareFile}, which +% also assigns a key to the file (the default is the filename). This +% key is passed to the \env{MacroCode} environment, which saves the +% code to the specified file. +% +% \DescribeMacro\DeclareFile['key='<key>',preamble='<preamble>]{<filename>} +% The \cs{DeclareFile} macro declares a file for future use with +% \env{MacroCode}. The optional argument is a comma separated list of +% key-value options, where the possible keys are \texttt{key} and +% \texttt{preamble}. Here \meta{key} is a key that is used instead +% of the filename in \env{MacroCode}, and \meta{preamble} is a +% token or command sequence expanding to a preamble which will be +% prepended to the file on output. +% +% \DescribeMacro\PreambleTo{<\textbackslash token>}{<filename>} +% Reads the preamble from \meta{filename}. Lines from the file are +% appended to \meta{\textbackslash token} until a line which does not +% begin with \texttt{\%\%} is encountered. +% +% \DescribeMacro\SelfPreambleTo{<\textbackslash token>} +% This reads the preamble from the curent file. It is equivalent to +% the sequence +% \Macro\PreambleTo{<\textbackslash token>}{\cs*{jobname}.tex}. +% +% \DescribeEnv[<implementation>]{MacroCode}{<key>',...'} +% The \env{MacroCode} environment typesets and exports +% \meta{implementation} verbatim to the file associated with \meta{key}. +% As such, it is the analogue of the \env{macrocode} environment from +% \pkg{ltxdoc}, but does not suffer from some of its drawbacks (the +% sensitivity to whitespace, for instance). As detailed by the +% description of the \opt{highlight} option (on page +% \pageref{ssec:option:highlight}), the environment will highlight +% the code using \pkg{minted} if possible. Multiple \meta{key}s are +% allowed, and the code will be written to all corresponding files. +% +% \subsubsection{Hiding the implementation} +% For lagre packages it may be of interest to hide the implementation +% from the documentation. This is accomplished using the two marker +% macros \cs{Implementation} and \cs{Finale} (which should be present +% even if not hiding the implementation), and the switch macro +% \cs{OnlyDescription}. +% +% \DescribeMacro\Implementation +% This macro indicates the start of the implementation. Normally, this +% would directly precede the \cs{section} under which the implementation +% is organized. +% +% \DescribeMacro\Finale +% This macro indicates the end of the implementation. Usually the only +% things happening after this is the printing of indices, the change +% log, bibliographies and the end of the \env{document} environment. +% +% \DescribeMacro\OnlyDescription +% This macro, which should be issued in the preamble, indicates that the +% implementation should be hidden. \Warning{this has the side effect +% that a page break is inserted where the implementation would normally +% reside.} +% +% \subsection{Documenting changes} +% One type of useful information you should provide in your +% documentation is a list of changes. The \thepkg\ document class +% provides a change list system based on the \pkg{glossaries} package. +% As such, including a change list in your documentation requires you +% to run \texttt{makeglossaries} between the first and second \LaTeX\ +% run. +% +% \DescribeMacro\changes{<version>}{<description>} +% The \cs{changes} macro provides the main interface to the change +% list system, and adds changes to the change list. Each change is +% added with a \emph{context}; if the macro is issued inside one of +% the macros described in section~\ref{sec:impl-env}, the concept +% currenly being described will be the context. Outside these +% environment, the context is \enquote{general}. For every context +% and \meta{version}, only one change may be recorded, otherwise +% \pkg{glossaries} will issue a warning. +% +% \DescribeMacro\PrintChanges +% This macro prints the list of changes. As explained earlier, this +% requires you to run \texttt{makeglossaries} between the two \LaTeX\ +% runs. +% +% \subsection{Producing an index} +% The macros previously discussed in sections~\ref{sec:ref-macros}, +% \ref{sec:doc-macros} and \ref{sec:impl-env} automatically index their +% aguments using \pkg{glossaries}. By running \texttt{makeglossaries} +% you can include an index of all macros, environments, packages and +% such that are discussed, documented or implemented in your package. +% +% \DescribeMacro\PrintIndex +% Much like the \cs{PrintChanges} macro, this prints the index. As with +% the list of changes, this requires that you run +% \texttt{makeglossaries} between the two \LaTeX\ runs. +% +% \section{Known issues} +% A list of current issues is available in the Github repository of this +% package\footnote{\url{https://github.com/urdh/skdoc/issues}}, but as +% of the release of \theversion, there are two known issues. +% \begin{description} +% \item[\#30] The use of \pkg{expl3}-style macros in \cs{cs} may cause +% issues when generating a glossary. Since such macros are in general +% implementation details, a workaround may be to omit the +% implementation from the output by using \cs{OnlyDescription}. +% \item[\#34] When generating examples utilizing the documented package, +% if a previous version of this package is installed on the machine +% where this generation is done, the installed version will be used +% instead of the version being documented. This may cause incorrect +% output or compiler errors. A workaround is to temporarily remove +% the installed version while generating documentation for the more +% recent version. +% \end{description} +% +% If you discover any bugs in this package, please report them to the +% issue tracker in the \thepackage\ Github repository. +% +% \Implementation \ExplHack +% \section{Implementation} +% \iffalse +%</driver> +%<*class> +% \fi +% \subsection{Require packages} +% We begin with loading the \pkg{scrartcl} KOMA-script class and a +% few packages we'll be needing. +% \begin{macrocode} +\PassOptionsToPackage{log-declarations=false}{xparse} +\LoadClass[ DIV7, + headings=big, + numbers=noenddot, + abstracton, + bibliography=totocnumbered, + index=totoc + ]{scrartcl} +% \end{macrocode} +% These packages are basic low-level things that we use to declare +% commands, work with strings and so on. +% \begin{macrocode} +\RequirePackage{etoolbox,xstring,xparse,atbegshi,kvoptions,pdftexcmds,everyhook} +% \end{macrocode} +% Now, higher-level packages we use in our definitions. +% \begin{macrocode} +\RequirePackage{verbatim,needspace,marginnote,calc,hyperref,multicol,hologo} +\RequirePackage[nomain,xindy,numberedsection,order=letter, + sanitizesort=false]{glossaries} +% \end{macrocode} +% We also include the \pkg{ydoc} packages we'll be extending. +% \begin{macrocode} +\RequirePackage{ydoc-code,ydoc-desc} +% \end{macrocode} +% The rest is basically just styling. +% \begin{macrocode} +\RequirePackage{scrpage2} +\AtEndOfClass{% + \RequirePackage[\skdoc@babel]{babel} + \RequirePackage[english=british]{csquotes} + \RequirePackage[font=small,labelfont=bf,textfont=it]{caption} + \RequirePackage{PTSerif,sourcecodepro} + \RequirePackage[defaultsans,osfigures,scale=0.95]{opensans} + \RequirePackage[babel]{microtype} +} +% \end{macrocode} +% +% \subsection{Error messages} +% Set up some error message texts for later use. +% \begin{macrocode} +\msg_new:nnn{skdoc}{key-exists}{File~key~"#1"~already~declared!} +\msg_new:nnn{skdoc}{key-nexists}{File~key~"#1"~hasn't~been~declared!} +\msg_new:nnn{skdoc}{wrote-file}{Writing~things~to~file~"#1".} +\msg_new:nnn{skdoc}{read-preamble}{Reading~preamble~from~file~"#1".} +\msg_new:nnn{skdoc}{no-lppl}{Could~not~include~LPPL:~lppl.tex~does~not~exist!} +\msg_new:nnn{skdoc}{no-minted}{Syntax~highlighting~disabled:~couldn't~find~minted.sty!} +\msg_new:nnn{skdoc}{no-shell-escape}{Syntax~highlighting~disabled:~running~without~unrestricted~\string\write18.} +\msg_new:nnn{skdoc}{no-pygments}{Syntax~highlighting~disabled:~couldn't~find~"pygmentize".} +\msg_new:nnnn{skdoc}{bibtex-unsupported}{The `bibtex` package is unsupported: continue at own risk!}{Use a more modern bibliography system (i.e. `biblatex`) instead.} +% \end{macrocode} +% +% \subsection{Booleans} +% Set up some booleans used throughout the code. +% \begin{macro}{\g__skdoc_use_minted_bool} +% The \texttt{use_minted} boolean keeps track of wether we're using +% \pkg{minted} or not. The default value is \emph{false}. +% \begin{macrocode} +\bool_new:N\g__skdoc_use_minted_bool +\bool_gset_false:N\g__skdoc_use_minted_bool +% \end{macrocode} +% \end{macro} +% \begin{macro}{\g__skdoc_no_index_bool} +% The \texttt{no_index} boolean keeps track of wether the indexing +% macros should write things to the index or not. The default value is +% \emph{false} (don't not write things to the index). +% \begin{macrocode} +\bool_new:N\g__skdoc_no_index_bool +\bool_gset_false:N\g__skdoc_no_index_bool +% \end{macrocode} +% \end{macro} +% \begin{macro}{\g__skdoc_in_example_bool} +% The \texttt{in_example} boolean keeps track of wether we are currently +% inside an example or not (used mainly by \cs{skdoc@verbatim}). The +% default value is of course \emph{false}. +% \begin{macrocode} +\bool_new:N\g__skdoc_in_example_bool +\bool_gset_false:N\g__skdoc_in_example_bool +% \end{macrocode} +% \end{macro} +% \begin{macro}{\g__skdoc_with_implementation_bool} +% The \texttt{with_implementation} boolean keeps track of wether we are +% going to typeset the implementation or not. The default value is +% \emph{true}, and this is only changed by \cs{OnlyDescription}. +% \begin{macrocode} +\bool_new:N\g__skdoc_with_implementation_bool +\bool_gset_true:N\g__skdoc_with_implementation_bool +% \end{macrocode} +% \end{macro} +% \begin{macro}{\g__skdoc_in_implementation_bool} +% The \texttt{in_implementation} boolean keeps track of wether we are +% in the implementation part of the documentation or not. It defaults +% to \emph{false}, and is changed by \cs{Implementation} and \cs{Finale}. +% \begin{macrocode} +\bool_new:N\g__skdoc_in_implementation_bool +\bool_gset_false:N\g__skdoc_in_implementation_bool +% \end{macrocode} +% \end{macro} +% \begin{macro}{\g__skdoc_negative_space_bool} +% This boolean keeps track of the negative spacing added by description +% environments, allowing \env{MacroCode} to offset it if it follows the +% start of these environments directly. Bit of a hack, really. +% \begin{macrocode} +\bool_new:N\g__skdoc_negative_space_bool +\bool_gset_false:N\g__skdoc_negative_space_bool +% \end{macrocode} +% \end{macro} +% +% Finally, we define a helpful conditional based on the last two +% booleans. It decides wether code in \cs{skdoc@verbatim} is typeset +% or just output to a file. +% \begin{macro*}{\__skdoc_if_print_code_p:} +% \begin{macro*}{\__skdoc_if_print_code:T} +% \begin{macro*}{\__skdoc_if_print_code:F} +% \begin{macro}{\__skdoc_if_print_code:TF} +% \begin{macrocode} +\prg_new_conditional:Nnn\__skdoc_if_print_code:{p,T,F,TF}{ + \bool_if:nTF{ + \g__skdoc_in_implementation_bool && + !\g__skdoc_with_implementation_bool + }{ + \prg_return_false: + }{ + \prg_return_true: + } +} +% \end{macrocode} +% \end{macro} +% \end{macro*} +% \end{macro*} +% \end{macro*} +% +% \subsection{Options} +% Define the all options, and process them. +% \begin{macrocode} +\SetupKeyvalOptions{ + family=skdoc, + prefix=skdoc@ +} +\DeclareStringOption{load}[\jobname] +\DeclareStringOption[british]{babel} +\DeclareBoolOption[true]{highlight} +\ProcessKeyvalOptions* +% \end{macrocode} +% If the \opt{load} option was used, load the given package if it exists. +% \begin{macrocode} +\IfStrEq{\skdoc@load}{}{}{% + \IfFileExists{\skdoc@load.sty}{% + \RequirePackage{\skdoc@load} + }{} +} +% \end{macrocode} +% +% \subsection{Special case: syntax highlighting} +% We support syntax highlighting through \pkg{minted}, but only if +% we're running with unrestricted \cs{write18} access \emph{and} +% there exists a suitable executable (\texttt{pygmentize}). Since +% \pkg{minted} bails out without \cs{write18} access, we have to test +% that before even loading it. +% +% \subsubsection{A simple \cs{write18} test} +% Using the \cs{pdf@shellescape} macro from \pkg{pdftexcmds}, we +% can define a new conditional that decides if we have unrestricted +% \cs{write18} or not. +% \begin{macro*}{\__skdoc_if_shellescape:T} +% \begin{macro*}{\__skdoc_if_shellescape:F} +% \begin{macro}{\__skdoc_if_shellescape:TF} +% \begin{macrocode} +\prg_new_conditional:Nnn\__skdoc_if_shellescape:{T,F,TF}{ + \if_cs_exist:N\pdf@shellescape +% \end{macrocode} +% If the command sequence exists (it really should), we test to see +% if it is equal to one. The \cs{pdf@shellescape} macro will be zero +% if no \cs{write18} access is available, two if we have restricted +% access and one if access is unrestricted. +% \begin{macrocode} + \if_int_compare:w\pdf@shellescape=\c_one + \prg_return_true: + \else: + \prg_return_false: + \fi: +% \end{macrocode} +% If the command sequence doesn't exist, we assume that we have +% unrestricted \cs{write18} access (we probably don't), and let +% \LaTeX\ complain about it later. +% \begin{macrocode} + \else: + \prg_return_true: + \fi: +} +% \end{macrocode} +% \end{macro} +% \end{macro*} +% \end{macro*} +% +% \subsubsection{Testing for an application} +% In order to find out wether \texttt{pygmentize} is installed, we +% have to test for its binary. This is done by shelling out to +% \texttt{which} and reading a temporary file, which means we need +% a way to delete that file. +% \begin{macro}{\__skdoc_rm:n}[1] +% {The file to be removed} +% \begin{macrocode} +\cs_new:Npn\__skdoc_rm:n#1{ + \immediate\write18{rm~#1} +} +% \end{macrocode} +% \end{macro} +% Now, let's define the actual test. Note that this test will fail +% on non-unixy platforms (\emph{i.e.} Windows). Deal with it for now. +% \begin{macro*}{\__skdoc_if_pygmentize:nT} +% \begin{macro*}{\__skdoc_if_pygmentize:nF} +% \begin{macro}{\__skdoc_if_pygmentize:nTF}[1] +% {The name of the binary to check existence of} +% \begin{macrocode} +\prg_new_conditional:Nnn\__skdoc_if_pygmentize:{T,F,TF}{ +% \end{macrocode} +% First, run \texttt{which} to create the temporary file. +% \begin{macrocode} + \immediate\write18{which~pygmentize~&&~touch~\jobname.aex} +% \end{macrocode} +% A temporary boolean is defined to hold the result of the test (this +% is a bit of carco cult programming, any clues as to why placing the +% result inside \cs{file_if_exists:nTF} doesn't work are welcome), and +% if the test is successful we remove the temporary file. +% \begin{macrocode} + \bool_set:Nn\l_tmpa_bool{\c_false_bool} + \file_if_exist:nT{\jobname.aex}{ + \__skdoc_rm:n{\jobname.aex} + \bool_set:Nn\l_tmpa_bool{\c_true_bool} + } +% \end{macrocode} +% Finally, the temporary boolean is used to return a result. +% \begin{macrocode} + \if_bool:N\l_tmpa_bool + \prg_return_true: + \else: + \prg_return_false: + \fi: +} +% \end{macrocode} +% \end{macro} +% \end{macro*} +% \end{macro*} +% +% Using the macros defined above, we can test for both \cs{write18} +% and \texttt{pygmentize}, loading \pkg{minted} and setting a flag +% if both exist. If the option \opt{highlight} was supplied and set +% to \texttt{false}, we do nothing. +% \begin{macrocode} +\ifskdoc@highlight + \IfFileExists{\skdoc@load.sty}{ + \__skdoc_if_shellescape:TF{ + \__skdoc_if_pygmentize:TF{ + \bool_gset_true:N\g__skdoc_use_minted_bool +% \end{macrocode} +% Since \pkg{minted} (through \pkg{fancyvrb}) loads \pkg{lineno}, and something +% above already defines \cs{c@linenumber}, we have to resort to a bit of a hack +% before we actually load \pkg{minted}. +% \begin{macrocode} + \cs_undefine:N\c@linenumber + \cs_undefine:N\cl@linenumber + \cs_undefine:N\p@linenumber + \cs_undefine:N\thelinenumber + \RequirePackage{minted} +% \end{macrocode} +% Now that we have \pkg{minted}, we redefine the style of the line +% numbers to match what we have further down for the non-highlighted +% mode. +% \begin{macrocode} + \renewcommand{\theFancyVerbLine}{ + \sffamily\tiny\textcolor{lightgray}{ + \oldstylenums{\arabic{FancyVerbLine}}} + } +% \end{macrocode} +% We also define our own Pygments style, to match the \thepackage% +% color theme. This is a bunch of code generated by running +% \texttt{pygmentize -S default -f latex}, with modifications. Note +% the abundancy of \verb|#| characters; this is somewhat black magic, +% but apparently \LaTeX\ expands them one more time than I'd expect +% in this context. Probably a \LaTeX3 artifact. Also, the macro names +% somehow correspond to Pygments entities (see \emph{e.g.} +% \texttt{pygmentize -S default -f html}), but it's not entirely +% apparent which macro corresponds to what entity. +% \begin{macrocode} + \def\PY@reset{\let\PY@it=\relax \let\PY@bf=\relax% + \let\PY@ul=\relax \let\PY@tc=\relax% + \let\PY@bc=\relax \let\PY@ff=\relax} + \def\PY@tok##1{\csname PY@tok@##1\endcsname} + \def\PY@toks##1+{\ifx\relax##1\empty\else% + \PY@tok{##1}\expandafter\PY@toks\fi} + \def\PY@do##1{\PY@bc{\PY@tc{\PY@ul{% + \PY@it{\PY@bf{\PY@ff{##1}}}}}}} + \def\PY##1##2{\PY@reset\PY@toks##1+\relax+\PY@do{##2}} + \expandafter\def\csname PY@tok@gd\endcsname{% + \def\PY@tc####1{\textcolor{scriptcolor}{####1}}} + \expandafter\def\csname PY@tok@gu\endcsname{% + \let\PY@bf=\textbf% + \def\PY@tc####1{\textcolor{optioncolor}{####1}}} + \expandafter\def\csname PY@tok@gt\endcsname{% + \def\PY@tc####1{\textcolor{scriptcolor}{####1}}} + \expandafter\def\csname PY@tok@gs\endcsname{% + \let\PY@bf=\textbf} + \expandafter\def\csname PY@tok@gr\endcsname{% + \def\PY@tc####1{\textcolor{scriptcolor}{####1}}} + \expandafter\def\csname PY@tok@cm\endcsname{% + \let\PY@it=\textit% + \def\PY@tc####1{\textcolor{lightgray}{####1}}} + \expandafter\def\csname PY@tok@vg\endcsname{% + \def\PY@tc####1{\textcolor{scriptcolor}{####1}}} + \expandafter\def\csname PY@tok@m\endcsname{% + \def\PY@tc####1{\textcolor{meta}{####1}}} + \expandafter\def\csname PY@tok@mh\endcsname{% + \def\PY@tc####1{\textcolor{meta}{####1}}} + \expandafter\def\csname PY@tok@cs\endcsname{% + \let\PY@it=\textit% + \def\PY@tc####1{\textcolor{macroimpl}{####1}}} + \expandafter\def\csname PY@tok@ge\endcsname{% + \let\PY@it=\textit} + \expandafter\def\csname PY@tok@vc\endcsname{% + \def\PY@tc####1{\textcolor{scriptcolor}{####1}}} + \expandafter\def\csname PY@tok@il\endcsname{% + \def\PY@tc####1{\textcolor{meta}{####1}}} + \expandafter\def\csname PY@tok@go\endcsname{% + \def\PY@tc####1{\textcolor{gray}{####1}}} + \expandafter\def\csname PY@tok@cp\endcsname{% + \def\PY@tc####1{\textcolor{sharp!75}{####1}}} + \expandafter\def\csname PY@tok@gi\endcsname{% + \def\PY@tc####1{\textcolor{bright}{####1}}} + \expandafter\def\csname PY@tok@gh\endcsname{% + \let\PY@bf=\textbf% + \def\PY@tc####1{\textcolor{section}{####1}}} + \expandafter\def\csname PY@tok@ni\endcsname{% + \let\PY@bf=\textbf% + \def\PY@tc####1{\textcolor{keydesc}{####1}}} + \expandafter\def\csname PY@tok@nn\endcsname{% + \let\PY@ul=\underline% + \def\PY@tc####1{\textcolor{black}{####1}}} + \expandafter\def\csname PY@tok@no\endcsname{% + \def\PY@tc####1{\textcolor{scriptcolor}{####1}}} + \expandafter\def\csname PY@tok@na\endcsname{% + \def\PY@tc####1{\textcolor{meta!50}{####1}}} + \expandafter\def\csname PY@tok@nb\endcsname{% + \def\PY@tc####1{\textcolor{black}{####1}}} + \expandafter\def\csname PY@tok@nc\endcsname{% + \let\PY@ul=\underline% + \def\PY@tc####1{\textcolor{bright}{####1}}} + \expandafter\def\csname PY@tok@nd\endcsname{% + \def\PY@tc####1{\textcolor{gray}{####1}}} + \expandafter\def\csname PY@tok@si\endcsname{% + \def\PY@tc####1{\textcolor{sharp}{####1}}} + \expandafter\def\csname PY@tok@nf\endcsname{% + \def\PY@tc####1{\textcolor{bright}{####1}}} + \expandafter\def\csname PY@tok@s2\endcsname{% + \def\PY@tc####1{\textcolor{sharp}{####1}}} + \expandafter\def\csname PY@tok@vi\endcsname{% + \def\PY@tc####1{\textcolor{scriptcolor}{####1}}} + \expandafter\def\csname PY@tok@nt\endcsname{% + \let\PY@bf=\textbf% + \def\PY@tc####1{\textcolor{meta!50}{####1}}} + \expandafter\def\csname PY@tok@nv\endcsname{% + \def\PY@tc####1{\textcolor{scriptcolor}{####1}}} + \expandafter\def\csname PY@tok@s1\endcsname{% + \def\PY@tc####1{\textcolor{sharp}{####1}}} + \expandafter\def\csname PY@tok@gp\endcsname{% + \def\PY@tc####1{\textcolor{gray}{####1}}} + \expandafter\def\csname PY@tok@sh\endcsname{% + \def\PY@tc####1{\textcolor{sharp}{####1}}} + \expandafter\def\csname PY@tok@ow\endcsname{% + \def\PY@tc####1{\textcolor{macroimpl}{####1}}} + \expandafter\def\csname PY@tok@sx\endcsname{% + \def\PY@tc####1{\textcolor{sharp}{####1}}} + \expandafter\def\csname PY@tok@bp\endcsname{% + \def\PY@tc####1{\textcolor{black}{####1}}} + \expandafter\def\csname PY@tok@c1\endcsname{% + \let\PY@it=\textit% + \def\PY@tc####1{\textcolor{lightgray}{####1}}} + \expandafter\def\csname PY@tok@kc\endcsname{% + \def\PY@tc####1{\textcolor{macroimpl}{####1}}} + \expandafter\def\csname PY@tok@c\endcsname{% + \let\PY@it=\textit% + \def\PY@tc####1{\textcolor{lightgray}{####1}}} + \expandafter\def\csname PY@tok@mf\endcsname{% + \def\PY@tc####1{\textcolor{meta}{####1}}} + \expandafter\def\csname PY@tok@err\endcsname{% + \def\PY@tc####1{\textcolor{intlink}{####1}}% + \def\PY@bc####1{\setlength{\fboxsep}{0pt}% + \colorbox{bright}{\strut ####1}}} + \expandafter\def\csname PY@tok@kd\endcsname{% + \def\PY@tc####1{\textcolor{macroimpl}{####1}}} + \expandafter\def\csname PY@tok@ss\endcsname{% + \def\PY@tc####1{\textcolor{macroimpl}{####1}}} + \expandafter\def\csname PY@tok@sr\endcsname{% + \def\PY@tc####1{\textcolor{meta}{####1}}} + \expandafter\def\csname PY@tok@mo\endcsname{% + \def\PY@tc####1{\textcolor{meta}{####1}}} + \expandafter\def\csname PY@tok@mi\endcsname{% + \def\PY@tc####1{\textcolor{meta}{####1}}} + \expandafter\def\csname PY@tok@kn\endcsname{% + \def\PY@tc####1{\textcolor{macroimpl}{####1}}} + \expandafter\def\csname PY@tok@kr\endcsname{% + \def\PY@tc####1{\textcolor{macroimpl}{####1}}} + \expandafter\def\csname PY@tok@s\endcsname{% + \def\PY@tc####1{\textcolor{sharp}{####1}}} + \expandafter\def\csname PY@tok@kp\endcsname{% + \def\PY@tc####1{\textcolor{macroimpl}{####1}}} + \expandafter\def\csname PY@tok@w\endcsname{% + \def\PY@tc####1{\textcolor{lightgray}{####1}}} + \expandafter\def\csname PY@tok@kt\endcsname{% + \def\PY@tc####1{\textcolor{black}{####1}}} + \expandafter\def\csname PY@tok@sc\endcsname{% + \def\PY@tc####1{\textcolor{sharp}{####1}}} + \expandafter\def\csname PY@tok@sb\endcsname{% + \def\PY@tc####1{\textcolor{sharp}{####1}}} + \expandafter\def\csname PY@tok@k\endcsname{% + \def\PY@tc####1{\textcolor{macroimpl}{####1}}} + \expandafter\def\csname PY@tok@se\endcsname{% + \def\PY@tc####1{\textcolor{sharp}{####1}}} + \expandafter\def\csname PY@tok@sd\endcsname{% + \def\PY@tc####1{\textcolor{sharp}{####1}}} + \expandafter\def\csname PY@tok@nl\endcsname{% + \def\PY@tc####1{\textcolor{bright}{####1}}} + \expandafter\def\csname PY@tok@ne\endcsname{% + \def\PY@tc####1{\textcolor{bright}{####1}}} + \expandafter\def\csname PY@tok@o\endcsname{% + \def\PY@tc####1{\textcolor{macroimpl}{####1}}} + \def\PYZbs{\char`\\} + \def\PYZus{\char`\_} + \def\PYZob{\char`\{} + \def\PYZcb{\char`\}} + \def\PYZca{\char`\^} + \def\PYZam{\char`\&} + \def\PYZlt{\char`\<} + \def\PYZgt{\char`\>} + \def\PYZsh{\char`\#} + \def\PYZpc{\char`\%} + \def\PYZdl{\char`\$} + \def\PYZhy{\char`\-} + \def\PYZsq{\char`\'} + \def\PYZdq{\char`\"} + \def\PYZti{\char`\~} + \def\PYZat{@} + \def\PYZlb{[} + \def\PYZrb{]} +% \end{macrocode} +% If there's no \texttt{pygmentize}, no \cs{write18} or no \pkg{minted}, +% we display a warning message and proceed without highlighting. +% \begin{macrocode} + }{ + \msg_warning:nn{skdoc}{no-pygments} + } + }{ + \msg_warning:nn{skdoc}{no-shell-escape} + } + }{ + \msg_warning:nn{skdoc}{no-minted} + } +\fi +% \end{macrocode} +% \subsection{The \env{MacroCode} environment} +% We need a token list and input/output. +% \begin{macrocode} +\tl_new:N\skdoc@temptl +\ior_new:N\skdoc@input +\iow_new:N\skdoc@output +% \end{macrocode} +% \begin{macro}{\DeclareFile}[2] +% {A list of key-value parameters} +% {Filename of the file being declared} +% This declares a file as part of the bundle, which means we will be +% writing things to it. +% \changes{1.1a}{Don't create a new token list until we know the +% key isn't a duplicate} +% \begin{macrocode} +\DeclareDocumentCommand\DeclareFile{om}{ + \group_begin: + \keys_define:nn{skdoc@declarefile}{% + preamble .value_required:n = true, + preamble .code:n = \edef\skdoc@preamble{##1}, + key .value_required:n = true, + key .code:n = \def\skdoc@key{##1} + }% + \def\skdoc@preamble{}% + \def\skdoc@key{#2}% + \IfNoValueTF{#1}{}{\keys_set:nn{skdoc@declarefile}{#1}} + \int_if_exist:cTF{skdoc@output@\skdoc@key @line}{ + \msg_critical:nnx{skdoc}{key-exists}{\skdoc@key} + }{ + \int_zero_new:c{skdoc@output@\skdoc@key @line} + } + \tl_new:c{skdoc@output@\skdoc@key} + \IfStrEq{\skdoc@preamble}{}{ + \def\skdoc@preamble@extra{} + }{ + \tl_set:Nx\l_tmpa_tl{\skdoc@preamble} + \edef\skdoc@temp{\tl_head:N\l_tmpa_tl} + \def\skdoc@preamble@extra{ + \skdoc@temp\skdoc@temp\space~This~is~file~`#2',~generated~from~`\c_sys_jobname_str.tex'~(key~`\skdoc@key'). + } + } + \expandafter\xdef\csname skdoc@write@#2\endcsname{% + \noexpand\msg_log:nnn{skdoc}{wrote-file}{#2} + \noexpand\iow_open:Nn\noexpand\skdoc@output{#2} + \noexpand\IfStrEq{\skdoc@preamble}{}{}{ + \noexpand\iow_now:Nx\noexpand\skdoc@output{\skdoc@preamble@extra} + \noexpand\iow_now:Nx\noexpand\skdoc@output{\skdoc@preamble} + } + \noexpand\iow_now:Nx\noexpand\skdoc@output{\noexpand\tl_to_str:c{skdoc@output@\skdoc@key}} + \noexpand\iow_close:N\noexpand\skdoc@output + } + \AfterEndDocument{\csname skdoc@write@#2\endcsname} + \group_end: +} +% \end{macrocode} +% \end{macro} +% \begin{environment}{skdoc@verbatim}[1] +% {The key of the file being described} +% \changes{1.1}{Introducing syntax highlighting} +% \changes{1.1a}{Test for key existence before bumping counter, +% use \cs{Needspace*} to prevent code label from +% staying on the wrong page in some situations} +% \changes{1.2}{Hide line numbers when inside \env{example}} +% \changes{1.3}{Allow multiple (comma-separated) targets} +% \changes{1.3a}{Fix critical bug} +% This environment does all the actual work for \env{MacroCode}. +% \begin{macrocode} +\clist_new:N\l__skdoc_keys +\DeclareDocumentEnvironment{skdoc@verbatim}{m}{% + \clist_set:Nn\l__skdoc_keys{#1} +% \end{macrocode} +% If the file we're supposed to write to hasn't been initialized yet, +% we error out with a critical error. +% \begin{macrocode} + \clist_map_inline:Nn\l__skdoc_keys{ + \int_if_exist:cTF{skdoc@output@##1@line}{}{ + \msg_critical:nnn{skdoc}{key-nexists}{##1} + }% +% \end{macrocode} +% Before doing anything, set create or increment a counter keeping +% track of the line number of the file we're writing to. +% \begin{macrocode} + \int_compare:nNnT{\int_use:c{skdoc@output@##1@line}}=\c_zero% + {\int_gincr:c{skdoc@output@##1@line}}% + } +% \end{macrocode} +% Now, if we're supposed to print code, we set a few things up. +% \begin{macrocode} + \__skdoc_if_print_code:T{ + \bool_if:NTF\g__skdoc_use_minted_bool{ +% \end{macrocode} +% If we're using \pkg{minted}, we set a few options ans open the +% output file. +% \begin{macrocode} + \bool_if:NF\g__skdoc_in_example_bool{ + \setkeys{minted@opt@g}{linenos} + }% + \exp_args:Nnx\setkeys{FV}{ + firstnumber=\int_use:c{skdoc@output@#1@line} + }% + \iow_open:Nn\minted@code{\jobname.pyg}% + \Needspace*{2\baselineskip}% + }{ +% \end{macrocode} +% Otherwise, we hack spaces with \cs{@bsphack} (unless we're in an +% \env{example} environment). +% \begin{macrocode} + \bool_if:NF\g__skdoc_in_example_bool{\@bsphack}% + } + \bool_if:NF\g__skdoc_in_example_bool{ +% \end{macrocode} +% In all non-example code, \pkg{minted} or not, we output a small +% marker showing what file we are writing to. +% \begin{macrocode} + \marginnote{ + \leavevmode + \llap{ + \scriptsize\color{gray} + $\langle$#1$\rangle$ + \makebox[2ex]{\strut} + } + } + } + } +% \end{macrocode} +% Otherwise, we set up the \env{verbatim} line processor. +% \begin{macrocode} + \def\verbatim@processline{% +% \end{macrocode} +% We alsays append the line to the appropriate token list, so that it +% is saved to the output file. +% \begin{macrocode} + \clist_map_inline:Nn\l__skdoc_keys{ + \tl_gput_right:cx{skdoc@output@####1}{\the\verbatim@line\iow_newline:}% + } +% \end{macrocode} +% If we're supposed to print code, we do a lot more... +% \begin{macrocode} + \__skdoc_if_print_code:T{ + \bool_if:NTF\g__skdoc_use_minted_bool{ +% \end{macrocode} +% ...but if we're using minted, \enquote{a lot more} consists of also +% writing the line to the file used by \pkg{minted}. +% \begin{macrocode} + \iow_now:Nx\minted@code{\the\verbatim@line}% + }{ +% \end{macrocode} +% Otherwise, we actually do a lot of stuff. We typeset the line number +% (unless we're in an example): +% \begin{macrocode} + \noindent\leavevmode% + \bool_if:NF\g__skdoc_in_example_bool{\hspace*{-5ex}} + \begin{minipage}[c][1ex]{\textwidth} + \bool_if:nF{ + \g__skdoc_in_example_bool && + !\int_compare_p:nNn{\clist_count:N\l__skdoc_keys}>\c_one + }{ + \makebox[4ex]{% + \leavevmode + \sffamily\tiny\color{lightgray}\hfill% + \clist_map_inline:Nn\l__skdoc_keys{ + \oldstylenums{\int_use:c{skdoc@output@####1@line}}% + } + }% + \hspace*{1ex}% + } +% \end{macrocode} +% We also typeset the actual line: +% \begin{macrocode} + { + \verbatim@font + \the\verbatim@line + } + \end{minipage} +% \end{macrocode} +% Both of them in the same one-line-high minipage covering the page +% width. Note the use of \cs{llap} for line numbers in the margin. +% We end with a \cs{par} for the next line. +% \begin{macrocode} + \par + } + } +% \end{macrocode} +% Finally, the line number counter is incremented. +% \begin{macrocode} + \clist_map_inline:Nn\l__skdoc_keys{ + \int_gincr:c{skdoc@output@####1@line}% + } + }% +% \end{macrocode} +% Now the \env{verbatim} catcode magic begins. +% \begin{macrocode} + \group_begin: + \let\do\@makeother\dospecials\catcode`\^^M\active% + \bool_if:nT{ + \__skdoc_if_print_code_p: && + !\g__skdoc_use_minted_bool + }{ + \frenchspacing\@vobeyspaces + } + \verbatim@start% +}{% + \group_end: +% \end{macrocode} +% The catcode magic is over! Now, if we're printing code, there are +% a few things left to do. +% \begin{macrocode} + \__skdoc_if_print_code:T{ + \bool_if:NTF\g__skdoc_use_minted_bool{ +% \end{macrocode} +% If we're using \pkg{minted}, we still have to actually print the code. +% We begin with closing the output file. +% \begin{macrocode} + \iow_close:N\minted@code% +% \end{macrocode} +% A few spacing fixes are applied. Since \pkg{minted} uses +% \pkg{fancyvrb}, these negative \cs{vspace}s are derived from the +% \pkg{fancyvrb} documentation \parencite[pp.~46--47]{Rahtz10}. What +% we want to do is to offset the spacing produced by \pkg{minted}, so +% that we are in control. +% \begin{macrocode} + \bool_if:NF\g__skdoc_in_example_bool{ + \vspace*{-\topsep} + \vspace*{-\partopsep} + \vspace*{-\parskip} + } +% \end{macrocode} +% Now, the internal \pkg{minted} macro \cs{minted@pygmentize} is called +% to highlight and typeset the code, and the temporary file is removed. +% \begin{macrocode} + \minted@pygmentize{latex}% + \DeleteFile{\jobname.pyg}% +% \end{macrocode} +% This is followed by more space-offsetting. +% \begin{macrocode} + \vspace*{-\topsep} + \vspace*{-\partopsep} + }{ +% \end{macrocode} +% If we aren't using \pkg{minted}, we hack spaces with \cs{@esphack} +% instead. +% \begin{macrocode} + \bool_if:NF\g__skdoc_in_example_bool{\@esphack}% + } + }% +} +% \end{macrocode} +% \end{environment} +% \begin{environment}{MacroCode}[1] +% {The key of the file being described} +% \changes{1.1}{Minor changes due to syntax highlighting} +% \changes{1.3b}{Offset negative spacing from the description environments} +% \begin{macrocode} +\DeclareDocumentEnvironment{MacroCode}{m}{ + \__skdoc_if_print_code:T{ + \bool_if:NT\g__skdoc_negative_space_bool{\vspace{\baselineskip}} + \vspace{.2\baselineskip} + \bool_if:NF\g__skdoc_use_minted_bool{\par\noindent} + } + \skdoc@verbatim{#1} +}{ + \endskdoc@verbatim + \__skdoc_if_print_code:T{ + \vspace{.5\baselineskip} + } +} +% \end{macrocode} +% \end{environment} +% +% \subsubsection{Reading a preamble} +% \begin{macro}{\PreambleTo}[2] +% {A token to which we will save the preamble} +% {File to read the preamble from} +% Read preamble from a document and store in variable. +% \begin{macrocode} +\DeclareDocumentCommand\PreambleTo{mm}{% + \group_begin: + \msg_info:nnn{skdoc}{read-preamble}{#2} + \ior_open:Nn\skdoc@input{#2} + \bool_until_do:nn{\ior_if_eof_p:N\skdoc@input}{% + \tl_if_empty:NTF\skdoc@temptl{}{% + \tl_put_right:Nx\skdoc@temptl{\iow_newline:} + } + \tl_clear:N\l_tmpb_tl + \ior_str_get:NN\skdoc@input\l_tmpa_tl + \tl_put_right:Nx\l_tmpb_tl{\tl_head:N\l_tmpa_tl} + \IfStrEq{\tl_to_str:N\l_tmpb_tl}{\@percentchar}{% + \tl_set_eq:NN\l_tmpb_tl\skdoc@temptl + \tl_concat:NNN\skdoc@temptl\l_tmpb_tl\l_tmpa_tl + }{% + \ior_close:N\skdoc@input + } + } + \xdef#1{\tl_to_str:N\skdoc@temptl} + \group_end: +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\SelfPreambleTo}[1] +% {A token to which we will save the preamble} +% \changes{1.4c}{Fix mis-spelling of \cs{c_sys_jobname_str}} +% Shorthand to read preamble from current document. +% \begin{macrocode} +\DeclareDocumentCommand\SelfPreambleTo{m}{% + \PreambleTo{#1}{\c_sys_jobname_str}% +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Styling} +% \subsubsection{Colors} +% First, we redefine a couple of colors from \pkg{ydoc} as well as +% defining a couple for ourselves. +% \begin{macrocode} +\definecolorset{RGB}{}{}{ + section,11,72,107; + extlink,73,10,61; + intlink,140,35,24; + sharp,250,105,0; + bright,198,229,217; + macrodesc,73,10,61; + keydesc,140,35,24; + macroimpl,73,10,61; + meta,11,72,107; + scriptcolor,140,35,24; + optioncolor,73,10,61; + opt,73,10,61 +} +% \end{macrocode} +% \subsubsection{Fonts} +% Then we redefine a couple of the KOMA-script font commands to use +% our newly defined colors, along with other fixes. +% \begin{macrocode} +\RenewDocumentCommand\descfont{}{\sffamily\fontseries{sb}} +\RenewDocumentCommand\sectfont{}{\sffamily\fontseries{sb}} +\addtokomafont{minisec}{\bfseries} +\addtokomafont{paragraph}{\color{section}} +\addtokomafont{section}{\color{section}} +\addtokomafont{subsection}{\color{section}} +\addtokomafont{subsubsection}{\color{section}} +\addtokomafont{descriptionlabel}{\color{section}} +\addtokomafont{sectionentry}{\rmfamily\bfseries} +\addtokomafont{sectionentrypagenumber}{\rmfamily\bfseries} +% \end{macrocode} +% \subsubsection{Configuring \pkg{hyperref}} +% Finally, we set up \pkg{hyperref} to also use our colors. +% \begin{macrocode} +\hypersetup{ + colorlinks=true, + linkcolor=intlink, + anchorcolor=intlink, + citecolor=black, + urlcolor=extlink +} +% \end{macrocode} +% +% \subsection{Documentation macros} +% We can now start defining the documentation macros. +% +% \subsubsection{Inline referencing} +% We introduce a couple of macros for referencing various constructs +% in running text, \emph{i.e.} \cs{cs}-like macros. The starred +% variants will not index the use, the non-starred variants will. +% \begin{macro}{\cs}[2] +% {True if this is the starred variant} +% {The macro name to be typeset} +% The \cs{cs} macro typesets a macro. +% \begin{macrocode} +\DeclareDocumentCommand\cs{sm}{ + \texttt{\char`\\#2} + \bool_if:NF\g__skdoc_no_index_bool{ + \IfBooleanTF{#1}{}{\index@macro{#2}} + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\env}[2] +% {True if this is the starred variant} +% {The environment name to be typeset} +% The \cs{env} macro typesets an environment. +% \begin{macrocode} +\DeclareDocumentCommand\env{sm}{ + \texttt{#2} + \bool_if:NF\g__skdoc_no_index_bool{ + \IfBooleanTF{#1}{}{\index@environment{#2}} + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\pkg}[2] +% {True if this is the starred variant} +% {The package name to be typeset} +% The \cs{pkg} macro typesets a package. +% \begin{macrocode} +\DeclareDocumentCommand\pkg{sm}{ + \textsf{#2} + \bool_if:NF\g__skdoc_no_index_bool{ + \IfBooleanTF{#1}{}{\index@package{#2}} + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\opt}[2] +% {True if this is the starred variant} +% {The option name to be typeset} +% The \cs{opt} macro typesets an option +% \begin{macrocode} +\DeclareDocumentCommand\opt{sm}{ + \texttt{#2} + \bool_if:NF\g__skdoc_no_index_bool{ + \IfBooleanTF{#1}{}{\index@option{#2}} + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\bib}[2] +% {True if this is the starred variant} +% {The \hologo{BibTeX} entry type name to be typeset} +% The \cs{bib} macro typesets a \hologo{BibTeX} entry type. +% \begin{macrocode} +\DeclareDocumentCommand\bib{sm}{ + \texttt{@#2} + \bool_if:NF\g__skdoc_no_index_bool{ + \IfBooleanTF{#1}{}{\index@bibentry{#2}} + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\thm}[2] +% {True if this is the starred variant} +% {The theme name to be typeset} +% The \cs{thm} macro typesets a theme of some sort. +% \begin{macrocode} +\DeclareDocumentCommand\thm{sm}{ + \textrm{#2} + \bool_if:NF\g__skdoc_no_index_bool{ + \IfBooleanTF{#1}{}{\index@theme{#2}} + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\file}[2] +% {True if this is the starred variant} +% {The file name to be typeset} +% The \cs{file} macro typesets a file name. +% \begin{macrocode} +\DeclareDocumentCommand\file{sm}{ + \texttt{#2} + \bool_if:NF\g__skdoc_no_index_bool{ + \IfBooleanTF{#1}{}{\index@file{#2}} + } +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Descriptional macros} +% A range of descriptional macros are made available by the \pkg{ydoc} +% package, but we need to redefine and extend them. +% +% We begin with extending. +% \begin{macro}{\Describe@Macro}[1] +% {The macro name, including leading backslash} +% The \cs{Describe@Macro} macro is changed to typeset its agument in +% a \cs{marginnote} instead of an \cs{fbox}. +% \begin{macrocode} +\def\Describe@Macro#1{% + \endgroup + \edef\name{\expandafter\@gobble\string#1}% + \global\@namedef{href@desc@\name}{}% + \immediate\write\@mainaux{% + \global\noexpand\@namedef{href@desc@\name}{}% + }% + \hbox\y@bgroup + \@ifundefined{href@impl@\name}{}{\hyperlink{impl:\name}}% + {% + \hbox{ + \vbox to 0pt{ + \vss\hbox{ + \raisebox{4ex}{\hypertarget{desc:\name}{} + } + } + }% + \marginnote{\llap{\PrintMacroName{#1}}} + }% + }% + \ydoc@macrocatcodes + \macroargsstyle + \read@Macro@arg +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\descframe}[1] +% {Contents to be framed} +% Similarly, \cs{descframe} is changed to produce an \cs{mbox} +% instead of an \cs{fbox}. +% \begin{macrocode} +\def\descframe#1{% + \mbox{\hspace*{1.5\descsep}#1\hspace*{2\descsep}}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PrintMacroName}[1] +% {Macro name to be printed} +% \cs{PrintMacroName} is hooked to also index the macro name while +% printing it. +% \begin{macrocode} +\let\old@PrintMacroName\PrintMacroName +\DeclareDocumentCommand\PrintMacroName{m}{% + \index@macro*{\expandafter\@gobble\string#1} + \old@PrintMacroName{#1} +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PrintEnvName}[2] +% {Either \cs{end} or \cs{begin}} +% {Name of the environment to be printed} +% Similarly to \cs{PrintMacroName}, the \cs{PrintEnvName} is hooked +% to index the environment when printing the \cs{begin} part of the +% environment. +% \begin{macrocode} +\let\old@PrintEnvName\PrintEnvName +\def\PrintEnvName#1#2{ + \ifx#1\begin + \edef\skdoc@temp{\noexpand\index@environment*{#2}} + \skdoc@temp + \fi + \old@PrintEnvName{#1}{#2} +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\DescribeEnv}[2] +% {Environment body or \cs{NoValue}} +% {Environment name} +% \begin{macrocode} +\DeclareDocumentCommand\DescribeEnv{om}{ + \medskip\par\noindent + \marginnote{ + \envcodestyle + \hfill\llap{\PrintEnvName{\begin}{#2}}\mbox{}\\ + \IfNoValueTF{#1}{}{\hfill\llap{\MacroArgs#1}\mbox{}\\} + \hfill\llap{\PrintEnvName{\end}{#2}}\mbox{}\\ + } + \begingroup + \def\after@Macro@args{\endDescribeEnv} + \y@bgroup + \ydoc@macrocatcodes + \macroargsstyle + \read@Macro@arg +} +\DeclareDocumentCommand\endDescribeEnv{}{ + \endgroup + \smallskip\par\noindent +} +% \end{macrocode} +% \end{macro} +% +% Then we add a few of our own. For instance, we add macros to +% typeset descriptions of options. We also undefine the \cs{optpar} +% macro defined by \pkg{ydoc}, since we supersede it with \cs{Option}. +% \begin{macrocode} +\let\optpar\relax +% \end{macrocode} +% \begin{macro}{\Options}[1] +% {A comma-separated list of options} +% \begin{macrocode} +\DeclareDocumentCommand\Options{m}{ + \clist_set:Nn\l_tmpa_clist{#1} + \marginnote{ + \clist_map_inline:Nn\l_tmpa_clist{ + \index@option*{####1} + \hfill + \llap{\textcolor{opt}{\opt{####1}}} + \mbox{}\\ + } + } + \nobreak +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\Option}[1] +% {And option} +% \begin{macrocode} +\DeclareDocumentCommand\Option{m}{ + \Options{#1} +} +% \end{macrocode} +% \end{macro} +% \begin{macro*}{\skdoc@WithValues@peek} +% \changes{1.2a}{Add \cs{ignorespaces} to fix spacing bug} +% \begin{macrocode} +\def\skdoc@WithValues@peek{ + \ifx\@let@token\AndDefault\else\par\noindent\nobreak\ignorespaces\fi +} +% \end{macrocode} +% \end{macro*} +% \begin{macro}{\WithValues}[1] +% {Values of a key-value option} +% The \cs{WithValues} macro peeks ahead to see if there's an +% \cs{AndDefault} macro further down. It typesets the values of +% a key-vaue option +% \begin{macrocode} +\DeclareDocumentCommand\WithValues{m}{ + \noindent\makebox[\linewidth][l]{\texttt{#1}} + \futurelet\@let@token\skdoc@WithValues@peek +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\AndDefault}[1] +% {The value of a key-value option} +% Typesets the default value of a key-value option. To the far +% right of the line. +% \changes{1.2a}{Add \cs{ignorespaces} to fix spacing bug} +% \begin{macrocode} +\DeclareDocumentCommand\AndDefault{m}{ + \llap{\textcolor{gray}{\texttt{(#1)}}}\par\noindent\nobreak\ignorespaces +} +% \end{macrocode} +% \end{macro} +% +% Similar macros are provided for \hologo{BibTeX} entries. +% \begin{macro}{\BibEntry}[1] +% {The name of the \hologo{BibTeX} entry} +% \begin{macrocode} +\DeclareDocumentCommand\BibEntry{m}{ + \marginnote{ + \index@bibentry*{#1} + \hfill\llap{\textcolor{macrodesc}{\bib{#1}}} + } + \nobreak +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\WithFields}[2] +% {Optional fields} +% {Mandatory fields} +% \changes{1.2a}{Add \cs{ignorespaces} to fix spacing bug} +% \begin{macrocode} +\DeclareDocumentCommand\WithFields{om}{ + \noindent\makebox[\linewidth]{ + \texttt{#2} + \IfNoValueTF{#1}{}{ + \textcolor{gray}{\texttt{,#2}} + } + } + \par\noindent\nobreak\ignorespaces +} +% \end{macrocode} +% \end{macro} +% +% A macro for describing themes is supplied. +% \begin{macro}{\Theme}[1] +% {The theme name} +% \changes{1.2a}{Add \cs{ignorespaces} to fix spacing bug} +% \begin{macrocode} +\DeclareDocumentCommand\Theme{m}{ + \marginnote{ + \index@theme*{#1} + \hfill\llap{\textcolor{macrodesc}{\thm{#1}}} + } + \nobreak\par\noindent\nobreak\ignorespaces +} +% \end{macrocode} +% \end{macro} +% +% And finally, a macro for describing files is provided. +% \begin{macro}{\DescribeFile}[1] +% {The filename} +% \changes{1.2a}{Add \cs{ignorespaces} to fix spacing bug} +% \begin{macrocode} +\DeclareDocumentCommand\DescribeFile{m}{ + \marginnote{ + \index@file*{#1} + \hfill\llap{\textcolor{macrodesc}{\file{#1}}} + } + \nobreak\par\noindent\nobreak\ignorespaces +} +% \end{macrocode} +% \end{macro} +% +% Lastly, we define an envionment for showing examples. It's quite +% complex, utilizing (and kind of hacking) \cs{skdoc@verbatim} and +% typesetting the content using \pkg{l3coffins}. +% +% First, three dimensions used in constructing the side-by-side boxes. +% \begin{macro}{\c__skdoc_example_margin_dim} +% This dimension, set to half of \cs{baselineskip}, dictates the margin +% between the content of the coffins and the dividing ruler. +% \begin{macrocode} +\dim_const:Nn\c__skdoc_example_margin_dim{0.5\baselineskip} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\c__skdoc_example_linewidth_dim} +% This dimension sets the width of the dividing ruler. +% \begin{macrocode} +\dim_const:Nn\c__skdoc_example_linewidth_dim{1pt} +% \end{macrocode} +% \end{macro} +% +% Next, three coffins used by the \env{example} environment are defined. +% One for code, one for the divider and one for the result. +% \begin{macro}{\l__skdoc_example_code_coffin} +% \begin{macrocode} +\coffin_new:N\l__skdoc_example_code_coffin +% \end{macrocode} +% \end{macro} +% \begin{macro}{\l__skdoc_example_divider_coffin} +% \begin{macrocode} +\coffin_new:N\l__skdoc_example_divider_coffin +% \end{macrocode} +% \end{macro} +% \begin{macro}{\l__skdoc_example_result_coffin} +% \begin{macrocode} +\coffin_new:N\l__skdoc_example_result_coffin +% \end{macrocode} +% \end{macro} +% +% Finally, we can define the actual \env{example} environment! +% \begin{environment}{example} +% \changes{1.2}{Print example code next to the result} +% \begin{macrocode} +\DeclareDocumentEnvironment{example}{}{ +% \end{macrocode} +% The environment starts by priting a small header indicating that +% the content is in fact an example. It also sets a couple of counters +% and IO variables to trick \cs{skdoc@verbatim} into thinking that it's +% actually writing to a defined output file. +% \begin{macrocode} + \bool_gset_true:N\g__skdoc_in_example_bool% + \minisec{Example:}% + \int_zero_new:c{skdoc@output@skdoc@private@example@line}% + \tl_if_exist:cTF{skdoc@output@skdoc@private@example}{ + \tl_clear:c{skdoc@output@skdoc@private@example} + }{ + \tl_new:c{skdoc@output@skdoc@private@example} + } +% \end{macrocode} +% Next, we calculate the coffin width. We do this locally, not in a +% global constant, since we may be somewhere where \cs{textwidth} +% might have changed. +% \begin{macrocode} + \dim_set:Nn\l_tmpa_dim{ \textwidth/2 + -\c__skdoc_example_margin_dim + -\c__skdoc_example_linewidth_dim/2} +% \end{macrocode} +% The code coffin is now filled, after clearing it. It'll get filled +% with the contents of the verbatim environment, typeset like other +% \env{MacroCode} environments in the document (\emph{i.e.} \pkg{minted} +% if possible). +% \begin{macrocode} + \coffin_clear:N\l__skdoc_example_code_coffin + \vcoffin_set:Nnw\l__skdoc_example_code_coffin{\l_tmpa_dim} + \skdoc@verbatim{skdoc@private@example} +}{ + \endskdoc@verbatim + \vcoffin_set_end: +% \end{macrocode} +% Next comes the example result coffin. After clearing it, it gets +% filled by writing the contents of the token list defined previously +% (the one \cs{skdoc@verbatim} is tricked into writing to) to a +% temporary file, then reading that temporary file using \cs{input}. +% We leave the temporary file behind; cleaning up requires \cs{write18}. +% Also: Meh. +% \begin{macrocode} + \coffin_clear:N\l__skdoc_example_result_coffin + \vcoffin_set:Nnw\l__skdoc_example_result_coffin{\l_tmpa_dim} + \iow_open:Nn\skdoc@output{\jobname.skdoc.tmp} + \iow_now:Nx\skdoc@output{\tl_to_str:c{skdoc@output@skdoc@private@example}} + \iow_close:N\skdoc@output + \input{\jobname.skdoc.tmp} + \vcoffin_set_end: +% \end{macrocode} +% The divider coffin, being dependent on the height of the two previous +% coffins, is also reset every time. After clearing, we calculate the +% maximum height of the two coffins, and add two margins (top and +% bottom). This value is used to typeset a (gray) rule of the width +% specified earlier (by \cs{c__skdoc_example_linewidth_dim}). Margins +% are also added to either side of this rule. +% \begin{macrocode} + \coffin_clear:N\l__skdoc_example_divider_coffin + \dim_set:Nn\l_tmpa_dim{ + \dim_max:nn{\coffin_ht:N\l__skdoc_example_code_coffin}% + {\coffin_ht:N\l__skdoc_example_result_coffin} + + 2\c__skdoc_example_margin_dim} + \hcoffin_set:Nn\l__skdoc_example_divider_coffin{ + \color{lightgray} + \hspace*{\c__skdoc_example_margin_dim} + \rule{\c__skdoc_example_linewidth_dim}{\l_tmpa_dim} + \hspace*{\c__skdoc_example_margin_dim} + } +% \end{macrocode} +% It's finally time to join and typeset the coffins. We clear a temporary +% coffin, copy the divider into it, and proceed to attach the example +% result coffin to the left and the code to the right (vertical centers +% touching, so that they are \enquote{centered} vertically). The +% temporary coffin is then typeset. +% \begin{macrocode} + \coffin_clear:N\l_tmpa_coffin + \coffin_set_eq:NN\l_tmpa_coffin\l__skdoc_example_divider_coffin + \coffin_join:NnnNnnnn\l_tmpa_coffin{l}{vc}% + \l__skdoc_example_result_coffin{r}{vc}% + {0pt}{0pt} + \coffin_join:NnnNnnnn\l_tmpa_coffin{r}{vc}% + \l__skdoc_example_code_coffin{l}{vc}% + {0pt}{0pt} + \coffin_typeset:Nnnnn\l_tmpa_coffin{T}{l}{0pt}{0pt} + \bool_gset_false:N\g__skdoc_in_example_bool% + \vspace*{\c__skdoc_example_margin_dim}\par +} +% \end{macrocode} +% \end{environment} +% +% \subsubsection{Implementation environment} +% We define environments that encase the implementation of macros, +% environments, options, \hologo{BibTeX} entry types and themes. +% Watch out---there's a lot of duplicate code here. +% \begin{environment}{macro}[3] +% {True if this is the starred variant} +% {Name of the macro being implemented} +% {If given, the number of arguments that +% \cs{macro@impl@args} will read} +% \begin{macrocode} +\DeclareDocumentEnvironment{macro}{smo}{% + \IfBooleanTF{#1}{}{\@bsphack} + \index@macro!{\expandafter\@gobble\string#2} + \@macroname{#2}% + \IfBooleanTF{#1}{ + \IfNoValueTF{#3}{}{ + \int_compare:nNnTF{#3}>{0}{ + \use:c{use_none:\prg_replicate:nn{#3}{n}} + }{} + } + }{ + \PrintMacroImpl{#2} + \IfNoValueTF{#3}{ + \macro@impl@argline@noarg{(no~arguments)} + }{\macro@impl@args[#3]} + }% +}{ + \let\skdoc@macroname@key\@empty + \IfBooleanTF{#1}{}{\par\@esphack} +} +% \end{macrocode} +% \end{environment} +% \begin{environment}{environment}[3] +% {True if this is the starred variant} +% {Name of the environment being implemented} +% {If given, the number of arguments that +% \cs{macro@impl@args} will read} +% \begin{macrocode} +\DeclareDocumentEnvironment{environment}{smo}{% + \IfBooleanTF{#1}{}{\@bsphack} + \index@environment!{#2} + \@environmentname{#2}% + \IfBooleanTF{#1}{ + \IfNoValueTF{#3}{}{ + \int_compare:nNnTF{#3}>{0}{ + \use:c{use_none:\prg_replicate:nn{#3}{n}} + }{} + } + }{ + \PrintEnvImplName{#2} + \IfNoValueTF{#3}{ + \macro@impl@argline@noarg{(no~arguments)} + }{\macro@impl@args[#3]} + }% +}{ + \let\skdoc@macroname@key\@empty + \IfBooleanTF{#1}{}{\par\@esphack} +} +% \end{macrocode} +% \end{environment} +% \begin{environment}{option}[3] +% {True if this is the starred variant} +% {Name of the option being implemented} +% {Values this key-value option can take} +% \begin{macrocode} +\DeclareDocumentEnvironment{option}{smg}{% + \IfBooleanTF{#1}{}{\@bsphack} + \index@option!{#2} + \@optionname{#2}% + \IfBooleanTF{#1}{}{ + \vspace{\baselineskip} + \PrintEnvImplName{#2} + \IfNoValueTF{#3}{ + \macro@impl@argline@noarg{(option)} + }{ + \macro@impl@argline@noarg{ + Option~with~values~\texttt{\textcolor{gray}{#3}} + } + } + }% +}{ + \let\skdoc@macroname@key\@empty + \IfBooleanTF{#1}{}{\par\@esphack} +} +% \end{macrocode} +% \end{environment} +% \begin{environment}{bibentry}[2] +% {True if this is the starred variant} +% {Name of the \hologo{BibTeX} entry type being implemented} +% \begin{macrocode} +\DeclareDocumentEnvironment{bibentry}{sm}{% + \IfBooleanTF{#1}{}{\@bsphack} + \index@bibentry!{\expandafter\@gobble\string#2} + \@bibentryname{#2}% + \IfBooleanTF{#1}{}{ + \vspace{\baselineskip} + \PrintEnvImplName{#2} + \macro@impl@argline@noarg{(\hologoRobust{BibTeX}~entry~type)} + }% +}{ + \let\skdoc@macroname@key\@empty + \IfBooleanTF{#1}{}{\par\@esphack} +} +% \end{macrocode} +% \end{environment} +% \begin{environment}{theme}[2] +% {True if this is the starred variant} +% {Name of the theme being implemented} +% \begin{macrocode} +\DeclareDocumentEnvironment{theme}{sm}{% + \IfBooleanTF{#1}{}{\@bsphack} + \index@theme!{#2} + \@themename{#2}% + \IfBooleanTF{#1}{}{ + \vspace{\baselineskip} + \PrintEnvImplName{#2} + \macro@impl@argline@noarg{(theme)} + }% +}{ + \let\skdoc@macroname@key\@empty + \IfBooleanTF{#1}{}{\par\@esphack} +} +% \end{macrocode} +% \end{environment} +% We also provide starred variants of the environments, which will +% add the implementation to the index but not print anything. +% \begin{environment}{macro*}[2] +% {Name of the macro being implemented} +% {If given, the number of arguments that +% \cs{macro@impl@args} will read} +% \begin{macrocode} +\DeclareDocumentEnvironment{macro*}{mo}% + {\begin{macro}*{#1}[#2]}{\end{macro}} +% \end{macrocode} +% \end{environment} +% \begin{environment}{environment*}[2] +% {Name of the environment being implemented} +% {If given, the number of arguments that +% \cs{macro@impl@args} will read} +% \begin{macrocode} +\DeclareDocumentEnvironment{environment*}{mo}% + {\begin{environment}*{#1}[#2]}{\end{environment}} +% \end{macrocode} +% \end{environment} +% \begin{environment}{option*}[2] +% {Name of the option being implemented} +% {Values this key-value option can take} +% \begin{macrocode} +\DeclareDocumentEnvironment{option*}{mg}% + {\begin{option}*{#1}{#2}}{\end{option}} +% \end{macrocode} +% \end{environment} +% \begin{environment}{bibentry*}[1] +% {Name of the \hologo{BibTeX} entry type being implemented} +% \begin{macrocode} +\DeclareDocumentEnvironment{bibentry*}{m}% + {\begin{bibentry}*{#1}}{\end{bibentry}} +% \end{macrocode} +% \end{environment} +% \begin{environment}{theme*}[1] +% {Name of the theme being implemented} +% \begin{macrocode} +\DeclareDocumentEnvironment{theme*}{m}% + {\begin{theme}*{#1}}{\end{theme}} +% \end{macrocode} +% \end{environment} +% And finally, we redefine some of the underlying \pkg{ydoc} macros +% to behave the way we want them to. +% For instance, we redefine the commands that print environment and +% macro implementation names so that they typeset the name i a +% \cs{marginnote} rather than in an \cs{fbox}. +% \begin{macro}{\PrintEnvImplName}[1] +% {The environment name to be printed} +% \changes{1.3}{Fixed incorrect spacing} +% \begin{macrocode} +\def\PrintEnvImplName#1{% + \par\leavevmode\null + \hbox{% + \marginnote{\llap{\implstyle{#1\strut}}}% + } + \null +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PrintMacroImpl}[1] +% {The macro name to be printed} +% \begin{macrocode} +\def\PrintMacroImpl#1{% + \par + \hbox{% + \edef\name{\expandafter\@gobble\string#1}% + \global\@namedef{href@impl@\name}{}% + \immediate\write\@mainaux{% + \global\noexpand\@namedef{href@impl@\name}{}% + }% + \raisebox{4ex}[4ex]{\hypertarget{impl:\name}{}}% + \@ifundefined{href@desc@\name}{}{\hyperlink{desc:\name}}% + \marginnote{\llap{\PrintMacroImplName{#1}}}% + }% + \par +} +% \end{macrocode} +% \end{macro} +% We also redefine the utility macros belonging to \cs{macro@impl@arg}. +% \begin{macro*}{\macro@impl@argline}[2] +% {The argument number} +% {Description of the argument} +% \begin{macrocode} +\def\macro@impl@argline#1#2{% + \par\noindent{\texttt{\##1}:~#2\strut}% +} +% \end{macrocode} +% \end{macro*} +% \begin{macro*}{\macro@impl@args}[1] +% {The number of arguments to read} +% \begin{macrocode} +\def\macro@impl@args[#1]{% + \vspace*{-\baselineskip} + \begingroup + \let\macro@impl@argcnt\@tempcnta + \let\macro@impl@curarg\@tempcntb + \macro@impl@argcnt=#1\relax + \macro@impl@curarg=0\relax + \ifnum\macro@impl@curarg<\macro@impl@argcnt\relax + \expandafter\macro@impl@arg + \else + \expandafter\macro@impl@endargs + \fi +} +% \end{macrocode} +% \end{macro*} +% \begin{macro*}{\macro@impl@arg@noopt} +% \begin{macrocode} +\def\macro@impl@arg@noopt#1{% + \macro@impl@argline{\the\macro@impl@curarg}{#1} + \ifnum\macro@impl@curarg<\macro@impl@argcnt\relax + \expandafter\macro@impl@arg + \else + \expandafter\macro@impl@endargs + \fi +} +% \end{macrocode} +% \end{macro*} +% \begin{macro*}{\macro@impl@arg@opt} +% \begin{macrocode} +\def\macro@impl@arg@opt#1[#2]{% + \macro@impl@argline{\the\macro@impl@curarg} + {#1\hfill\AndDefault{#1}\vspace{-\baselineskip}} + \ifnum\macro@impl@curarg<\macro@impl@argcnt\relax + \expandafter\macro@impl@arg + \else + \expandafter\macro@impl@endargs + \fi +} +% \end{macrocode} +% \end{macro*} +% \begin{macro*}{\macro@impl@arg} +% \begin{macrocode} +\def\macro@impl@arg#1{% + \advance\macro@impl@curarg by\@ne\relax + \@ifnextchar[%] + {\macro@impl@arg@opt{#1}}% + {\macro@impl@arg@noopt{#1}}% +} +% \end{macrocode} +% \end{macro*} +% \begin{macro*}{\macro@impl@endargs} +% \changes{1.3b}{Conditionally don't add space if another environment follows} +% \begin{macrocode} +\def\macro@impl@endargs{ + \endgroup + \peek_meaning_ignore_spaces:NTF\begin + { + \vspace{-\baselineskip} + \bool_gset_true:N\g__skdoc_negative_space_bool + \PushPreHook{par}{ + \bool_gset_false:N\g__skdoc_negative_space_bool + \PopPreHook{par} + } + } + {\par\medskip}% +} +% \end{macrocode} +% \end{macro*} +% \begin{macro*}{\macro@impl@argline@noarg}[1] +% {The line to print instead of an argument line} +% \changes{1.3b}{Conditionally don't add space if another environment follows} +% This last macro is a replacement used when there are no arguments +% or if the implementation is an option or something like that. It +% behaves pretty much like \cs{macro@impl@args}, but with only one +% argument to read. +% \begin{macrocode} +\def\macro@impl@argline@noarg#1{% + \vspace*{-\baselineskip} + \par\noindent{#1\strut} + \peek_meaning_ignore_spaces:NTF\begin + { + \vspace{-\baselineskip} + \bool_gset_true:N\g__skdoc_negative_space_bool + \PushPreHook{par}{ + \bool_gset_false:N\g__skdoc_negative_space_bool + \PopPreHook{par} + } + } + {\par\medskip}% +} +% \end{macrocode} +% \end{macro*} +% +% \subsection{The index} +% \begin{macro*}{\__skdoc_if_do_index:T} +% \begin{macro*}{\__skdoc_if_do_index:F} +% \begin{macro*}{\__skdoc_if_do_index:TF} +% \begin{macro}{\__skdoc_if_do_index_p:} +% \begin{macrocode} +\prg_new_conditional:Nnn\__skdoc_if_do_index:{p,T,F,TF}{ + \bool_if:nTF{ + \__skdoc_if_print_code_p: && + !\g__skdoc_no_index_bool + }{ + \prg_return_true: + }{ + \prg_return_false: + } +} +% \end{macrocode} +% \end{macro} +% \end{macro*} +% \end{macro*} +% \end{macro*} +% The index is based on \pkg{glossaries}, and as such the whole +% process of adding entries to the index is reduced to adding +% glossary entries. This is done through two wrapper macros around +% the \cs{newglossaryentry} macro. +% \begin{macro}{\@index@}[1] +% {The key of the index entry} +% {The text of the index entry} +% What \cs{@index@} does is to decide wether we are hiding the +% implementation part of the documentation (discussed later), and +% wether we are in the actual implementation or not. If we are in +% the implementation and aren't printing it, we shouldn't add an +% index entry. +% \begin{macrocode} +\DeclareDocumentCommand\@index@{mm}{ + \__skdoc_if_do_index:T{ + \@index@@{#1}{#2} + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\@index@@}[2] +% {The key of the index entry} +% {The text of the index entry} +% This macro does the actual adding to the glossary. +% \begin{macrocode} +\DeclareDocumentCommand\@index@@{mm}{ + \newglossaryentry{index-#1}{ + type=index, + name={#2}, + description={\nopostdesc}, + sort={#1} + } +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Adding index entries} +% These macros add an index entry with different contents depending +% on the thing (macro, environment, etc.) that is being indexed. They +% all have non-starred variants which are used by the referring +% macros (\cs{cs} \emph{et. al}), and starred variants used by the +% description macros (the star affects the style of the page number). +% Each environment first test wether the given entry key exists, and +% defines a new entry if it doesn't. Then, a usage of the entry is +% recorded. +% There is also a exclamation variant that is used by the implementation +% environments, that typesets a normal use of the entity. +% +% Note the duplicate use of \cs{ifglsentryexists} --- this is needed +% since \cs{@index@} doesn't always add the entity to the index +% \emph{i.e.} nothing in the implementation is added when we're hiding +% the implementation. +% \begin{macro}{\index@macro}[3] +% {True if this is the starred variant} +% {True if this is the exclamation variant} +% {The name of the macro being indexed, without backslash} +% \begin{macrocode} +\DeclareDocumentCommand\index@macro{st!m}{ + \def\skdoc@temp{#3-macro} + \ifglsentryexists{index-\skdoc@temp}{}{ + \@index@{#3-macro}{\cs*{#3}} + } + \__skdoc_if_do_index:T{ + \IfBooleanTF{#2}{ + \glsadd[types=index,format=hyperul]{index-\skdoc@temp} + }{ + \IfBooleanTF{#1}{ + \glsadd[types=index,format=hyperit]{index-\skdoc@temp} + }{ + \glsadd[types=index]{index-\skdoc@temp} + } + } + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\index@environment}[3] +% {True if this is the starred variant} +% {True if this is the exclamation variant} +% {The name of the environment being indexed} +% \begin{macrocode} +\DeclareDocumentCommand\index@environment{st!m}{ + \def\skdoc@temp{\string#3-env} + \ifglsentryexists{index-\skdoc@temp}{}{ + \@index@{\string#3-env}{\env*{\string#3}~(environment)} + } + \__skdoc_if_do_index:T{ + \IfBooleanTF{#2}{ + \glsadd[types=index,format=hyperul]{index-\skdoc@temp} + }{ + \IfBooleanTF{#1}{ + \glsadd[types=index,format=hyperit]{index-\skdoc@temp} + }{ + \glsadd[types=index]{index-\skdoc@temp} + } + } + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\index@option}[3] +% {True if this is the starred variant} +% {True if this is the exclamation variant} +% {The name of the option being indexed} +% \begin{macrocode} +\DeclareDocumentCommand\index@option{st!m}{ + \def\skdoc@temp{\string#3-opt} + \ifglsentryexists{index-\skdoc@temp}{}{ + \@index@{\string#3-opt}{\opt*{\string#3}~(option)} + } + \__skdoc_if_do_index:T{ + \IfBooleanTF{#2}{ + \glsadd[types=index,format=hyperul]{index-\skdoc@temp} + }{ + \IfBooleanTF{#1}{ + \glsadd[types=index,format=hyperit]{index-\skdoc@temp} + }{ + \glsadd[types=index]{index-\skdoc@temp} + } + } + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\index@bibentry}[3] +% {True if this is the starred variant} +% {True if this is the exclamation variant} +% {The name of the \hologo{BibTeX} entry type +% being indexed, without initial \texttt{@} sign} +% \begin{macrocode} +\DeclareDocumentCommand\index@bibentry{st!m}{ + \def\skdoc@temp{#3-bib} + \ifglsentryexists{index-\skdoc@temp}{}{ + \@index@{#3-bib}{\bib*{#3}~(\hologoRobust{BibTeX}~entry~type)} + } + \__skdoc_if_do_index:T{ + \IfBooleanTF{#2}{ + \glsadd[types=index,format=hyperul]{index-\skdoc@temp} + }{ + \IfBooleanTF{#1}{ + \glsadd[types=index,format=hyperit]{index-\skdoc@temp} + }{ + \glsadd[types=index]{index-\skdoc@temp} + } + } + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\index@theme}[3] +% {True if this is the starred variant} +% {True if this is the exclamation variant} +% {The name of the theme being indexed} +% \begin{macrocode} +\DeclareDocumentCommand\index@theme{st!m}{ + \def\skdoc@temp{\string#3-theme} + \ifglsentryexists{index-\skdoc@temp}{}{ + \@index@{\string#3-theme}{\thm*{\string#3}~(theme)} + } + \__skdoc_if_do_index:T{ + \IfBooleanTF{#2}{ + \glsadd[types=index,format=hyperul]{index-\skdoc@temp} + }{ + \IfBooleanTF{#1}{ + \glsadd[types=index,format=hyperit]{index-\skdoc@temp} + }{ + \glsadd[types=index]{index-\skdoc@temp} + } + } + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\index@package}[3] +% {True if this is the starred variant} +% {True if this is the exclamation variant} +% {The name of the package being indexed} +% \begin{macrocode} +\DeclareDocumentCommand\index@package{st!m}{ + \def\skdoc@temp{\string#3-pkg} + \ifglsentryexists{index-\skdoc@temp}{}{ + \@index@{\string#3-pkg}{\pkg*{\string#3}~(package)} + } + \__skdoc_if_do_index:T{ + \IfBooleanTF{#2}{ + \glsadd[types=index,format=hyperul]{index-\skdoc@temp} + }{ + \IfBooleanTF{#1}{ + \glsadd[types=index,format=hyperit]{index-\skdoc@temp} + }{ + \glsadd[types=index]{index-\skdoc@temp} + } + } + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\index@file}[3] +% {True if this is the starred variant} +% {True if this is the exclamation variant} +% {The name of the file being indexed} +% \begin{macrocode} +\DeclareDocumentCommand\index@file{st!m}{ + \def\skdoc@temp{\string#3-file} + \ifglsentryexists{index-\skdoc@temp}{}{ + \@index@{\string#3-file}{\file*{\string#3}~(file)} + } + \__skdoc_if_do_index:T{ + \IfBooleanTF{#2}{ + \glsadd[types=index,format=hyperul]{index-\skdoc@temp} + }{ + \IfBooleanTF{#1}{ + \glsadd[types=index,format=hyperit]{index-\skdoc@temp} + }{ + \glsadd[types=index]{index-\skdoc@temp} + } + } + } +} +% \end{macrocode} +% \end{macro} +% +% Notice the references to \cs{hyperul}? We need to define that as +% well. It's simple enough. Note that \cs{GlsAddXdyAttribute} isn't +% called until later. +% \begin{macro}{\hyperul}[1] +% {Word to underline and link} +% \begin{macrocode} +\ProvideDocumentCommand\hyperul{m}{ + \underline{\hyperup{#1}} +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Displaying the index} +% Displaying the index is very simple. We begin by defining +% our own \pkg{glossaries} style. +% \begin{macrocode} +\newglossarystyle{docindex}{ + \glossarystyle{indexgroup} + \renewcommand*{\glspostdescription}{\unskip\leaders\hbox to 2.9mm{\hss.}\hfill\strut} + \renewenvironment{theglossary}{ + \bool_gset_true:N\g__skdoc_no_index_bool + \begin{multicols}{2} + \setlength{\parindent}{0pt} + \setlength{\parskip}{0pt plus 0.3pt} + \let\item\@idxitem + }{ + \end{multicols} + \bool_gset_false:N\g__skdoc_no_index_bool + } + \renewcommand*{\glossaryentryfield}[5]{ + \item\glsentryitem{##1}\glstarget{##1}{##2} + \ifx\relax##4\relax\else\space(##4)\fi + ##3\glspostdescription\space ##5} + \renewcommand*{\glsgroupheading}[1]{ + \IfStrEq{##1}{default}{ + \item{\descfont\glssymbolsgroupname} + }{ + \item{\descfont\glsgetgrouptitle{##1}} + } + } + \renewcommand*{\glsgroupskip}{ + \par\vspace{15\p@}\relax + } +} +% \end{macrocode} +% We follow that up by defining the actual glossay, and making sure +% to run \cs{makeglossaries} when the preamble is complete. +% \begin{macrocode} +\newglossary{index}{ids}{ido}{Index} +\AtBeginDocument{\makeglossaries} +% \end{macrocode} +% \begin{macro}{\PrintIndex} +% \changes{1.2}{Fixed incorrect reference to boldfaced text} +% Finally, we define a command \cs{PrintIndex} that prints the index. +% Note the preamble that describes how the index page numbers work. +% \begin{macrocode} +\providecommand*\PrintIndex{% + \begingroup + \renewcommand*{\glossarypreamble}{ + Numbers~written~in~italic~refer~to~the~page~where~the~ + corresponding~entry~is~described;~numbers~underlined~refer~ + to~the~page~were~the~implementation~of~the~corresponding~ + entry~is~discussed.~Numbers~in~roman~refer~to~other~ + mentions~of~the~entry.\par + } + \printglossary[type=index,style=docindex] + \endgroup +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Hacking \pkg{glossaries}} +% The following redefinition of an internal \pkg{glossaries} macro, +% provided by \textcite{Talbot13}, makes sure that the underlined +% and italic page numbers in the index have precedence over the plain +% nubmer format. In the event that a macro is described and implemented +% on the same page, the description format (italic) is used. +% \begin{macro}{\@gls@addpredefinedattributes} +% \changes{1.4a}{Add Xdy attribute \texttt{@gobble}} +% \begin{macrocode} +\RenewDocumentCommand\@gls@addpredefinedattributes{}{ + \GlsAddXdyAttribute{hyperit} + \GlsAddXdyAttribute{hyperul} + \GlsAddXdyAttribute{glsnumberformat} + \GlsAddXdyAttribute{@gobble} +} +% \end{macrocode} +% \end{macro} +% +% \subsection{The changelog} +% The changelog is implemented as a glossary using the +% \pkg{glossaries} package. We begin by defining a name +% for general changes, and commands that save the name of +% the current macro, environment or similar for use by the +% \cs{changes} macro. +% \begin{macro}{\generalname} +% \begin{macrocode} +\DeclareDocumentCommand\generalname{}{General} +% \end{macrocode} +% \end{macro} +% \begin{macro*}{\@macroname}[1] +% {Name of the macro being described} +% \begin{macrocode} +\DeclareDocumentCommand\@macroname{m}{ + \def\skdoc@macroname@stylized{\cs*{\expandafter\@gobble\string#1}} + \def\skdoc@macroname@key{macro-\expandafter\@gobble\string#1} +} +% \end{macrocode} +% \end{macro*} +% \begin{macro*}{\@environmentname}[1] +% {Name of the environment being described} +% \begin{macrocode} +\DeclareDocumentCommand\@environmentname{m}{ + \def\skdoc@macroname@stylized{\env*{\string#1}} + \def\skdoc@macroname@key{env-#1} +} +% \end{macrocode} +% \end{macro*} +% \begin{macro*}{\@optionname}[1] +% {Name of the option being described} +% \begin{macrocode} +\DeclareDocumentCommand\@optionname{m}{ + \def\skdoc@macroname@stylized{\opt*{\string#1}} + \def\skdoc@macroname@key{opt-#1} +} +% \end{macrocode} +% \end{macro*} +% \begin{macro*}{\@ebibentryname}[1] +% {Name of the \hologo{BibTeX} entry being described} +% \begin{macrocode} +\DeclareDocumentCommand\@bibentryname{m}{ + \def\skdoc@macroname@stylized{\bib*{\expandafter\@gobble\string#1}} + \def\skdoc@macroname@key{bibentry-\expandafter\@gobble\string#1} +} +% \end{macrocode} +% \end{macro*} +% \begin{macro*}{\@themename}[1] +% {Name of the theme being described} +% \begin{macrocode} +\DeclareDocumentCommand\@themename{m}{ + \def\skdoc@macroname@stylized{\thm*{\string#1}} + \def\skdoc@macroname@key{thm-#1} +} +% \end{macrocode} +% \end{macro*} +% Along with these we also define the variables they affect as empty. +% \begin{macrocode} +\def\skdoc@macroname@stylized{} +\let\skdoc@macroname@key\@empty +% \end{macrocode} +% +% \subsubsection{Adding changes} +% Since the changelog is based on \pkg{glossaries}, adding changes +% amounts to simply adding a glossary entry. +% \begin{macro}{\changes}[2] +% {The version in which the changes were made} +% {A short description of the changes} +% \changes{1.4a}{Unconditionally add version \enquote{parent} to +% circumvent strange behaviour by \pkg{glossaries}. Also, gobble +% page numbers for similar reasons} +% \begin{macrocode} +\DeclareDocumentCommand\changes{mm}{% + \@bsphack + \newglossaryentry{#1}{ + type=changes, + name={v#1}, + description={\nopostdesc}, + nonumberlist=true + } + \ifx\skdoc@macroname@key\@empty + \newglossaryentry{#1-general}{ + type=changes, + description={\generalname{}:~#2}, + parent={#1}, + sort={0}, + nonumberlist=true + } + \glsadd[types=changes,format=@gobble]{#1-general} + \else + \newglossaryentry{#1-\skdoc@macroname@key}{ + type=changes, + description={\skdoc@macroname@stylized{}:~#2}, + parent={#1}, + sort={\skdoc@macroname@key}, + nonumberlist=true + } + \glsadd[types=changes,format=@gobble]{#1-\skdoc@macroname@key} + \fi + \@esphack +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Displaying the changelog} +% Displaying the changelog is equally simple. We begin by defining +% our own \pkg{glossaries} style. +% \begin{macrocode} +\newglossarystyle{changelog}{ + \glossarystyle{altlist} + \renewenvironment{theglossary}{ + \bool_gset_true:N\g__skdoc_no_index_bool + \begin{multicols}{2}\begin{description} + }{ + \end{description}\end{multicols} + \bool_gset_false:N\g__skdoc_no_index_bool + } + \renewcommand*{\glossaryentryfield}[5]{ + \par\vspace{5\p@}\relax + \item[\glsentryitem{##1}\glstarget{##1}{##2}] + \mbox{}\par\nobreak\@afterheading + } + \renewcommand{\glossarysubentryfield}[6]{% + \par\hspace*{\itemindent} + \glssubentryitem{##2}% + \glstarget{##2}{\strut}##4\glspostdescription\space ##6 + } +} +% \end{macrocode} +% We follow that up by defining the actual glossary, and making sure +% to run \cs{makeglossaries} when the preamble is complete. +% \begin{macrocode} +\newglossary{changes}{gls}{glo}{Changes} +\AtBeginDocument{\makeglossaries} +% \end{macrocode} +% \begin{macro}{\PrintChanges} +% Finally, we define a command \cs{PrintChanges} that prints the +% list of changes. +% \begin{macrocode} +\DeclareDocumentCommand\PrintChanges{}{% + \begingroup + \printglossary[type=changes,style=changelog] + \endgroup +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Hiding the implementation} +% We define commands to hide the implementation from the documentation. +% Here, the ``implementation'' is understood to be everything between +% the \cs{Implementation} and \cs{Finale} macros. What we do is disable +% and/or reset page and section counters for the duration of the +% implementation, and set a shipout hook that simply discards the pages +% while we are in the implementation. A consquence of this is that we +% must force a page break between what's before the implementation and +% what's after, which might look horrible. +% +% We define a counter in which we save the page number we had when +% the implementation started. +% \begin{macrocode} +\newcounter{skdoc@impl@page} +% \end{macrocode} +% Then we define the shipout hook. Fairly straight-forward. +% \begin{macrocode} +\AtBeginShipout{ + \__skdoc_if_print_code:F{\AtBeginShipoutDiscard} +} +% \end{macrocode} +% \begin{macro}{\OnlyDescription} +% The \cs{OnlyDescription} macro simply toggles the appropriate toggle. +% \begin{macrocode} +\DeclareDocumentCommand\OnlyDescription{}{ + \bool_gset_false:N\g__skdoc_with_implementation_bool +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\Implementation} +% \changes{1.1a}{Hide references used in the hidden implementation} +% The \cs{Implementation} macro defines all the sectioning commands +% to be empty (saving the old ones), clears the page, saves the page +% number and toggles the appropriate toggle. If \pkg{biblatex} is +% loaded, we start a new \env{refsection} so that we can hide +% references used in the implementation from the final bibliography. +% \begin{macrocode} +\DeclareDocumentCommand\Implementation{}{ + \bool_if:NF\g__skdoc_with_implementation_bool{ + \clearpage + \bool_gset_true:N\g__skdoc_in_implementation_bool + \let\skdoc@old@part\part + \DeclareDocumentCommand\part{som}{} + \let\skdoc@old@section\section + \DeclareDocumentCommand\section{som}{} + \let\skdoc@old@subsection\subsection + \DeclareDocumentCommand\subsection{som}{} + \let\skdoc@old@subsubsection\subsubsection + \DeclareDocumentCommand\subsubsection{som}{} + \let\skdoc@old@paragraph\paragraph + \DeclareDocumentCommand\paragraph{som}{} + \let\skdoc@old@subparagraph\subparagraph + \DeclareDocumentCommand\subparagraph{som}{} + \cs_if_exist:NTF\refsection{\refsection}{} + \setcounter{skdoc@impl@page}{\value{page}} + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\Finale} +% \changes{1.1a}{Hide references used in the hidden implementation} +% The \cs{Finale} macro basically just undoes what the +% \cs{Implementation} macro did. If \pkg{biblatex} is used, the +% \env{refsection} environment is ended and the (local) bibliography +% is printed. +% \begin{macrocode} +\DeclareDocumentCommand\Finale{}{ + \bool_if:NF\g__skdoc_with_implementation_bool{ + \cs_if_exist:NTF\refsection{\printbibliography\endrefsection}{} + \clearpage + \bool_gset_false:N\g__skdoc_in_implementation_bool + \let\part\skdoc@old@part + \let\section\skdoc@old@section + \let\subsection\skdoc@old@subsection + \let\subsubsection\skdoc@old@subsubsection + \let\paragraph\skdoc@old@paragraph + \let\subparagraph\skdoc@old@subparagraph + \setcounter{page}{\value{skdoc@impl@page}} + } +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Document metadata} +% \subsubsection{Setting metadata} +% We override a bunch of the general titlepage macros and add a few +% of our own. First, we initialize the underlying variables. +% \begin{macrocode} +\let\@ctan\@empty% +\let\@repository\@empty% +\let\@plainemail\@empty% +\let\@email\@empty% +\let\@version\@empty% +% \end{macrocode} +% Then, we define the actual macros. +% \begin{macro}{\package}[2] +% {A list of key-value options} +% {The package name} +% The \cs{package} macro sets the package name of the documentation. +% The key-value options are \opt{vcs} and \opt{ctan}. +% \begin{macrocode} +\DeclareDocumentCommand\package{om}{% + \keys_define:nn{skdoc@package}{% + vcs .value_required:n = true,% + vcs .code:n = \repository{##1},% + ctan .code:n = \ctan{##1},% + ctan .default:n = #2% + }% + \IfNoValueTF{#1}{}{\keys_set:nn{skdoc@package}{#1}}% + \def\@package{#2}% + \title{The~\textbf{\pkg*{\@package}}~package}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\ctan}[1] +% {The name of a package or bundle on CTAN} +% \begin{macrocode} +\DeclareDocumentCommand\ctan{m}{% + \def\@ctan{\url{http://www.ctan.org/pkg/#1}}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\repository}[1] +% {The URI of an online repository} +% \begin{macrocode} +\DeclareDocumentCommand\repository{m}{% + \def\@repository{\url{#1}}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\email}[1] +% {The email address of the author} +% \begin{macrocode} +\DeclareDocumentCommand\email{m}{% + \def\@plainemail{#1}% + \def\@email{\href{mailto:\@plainemail}{\@plainemail}}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\version}[1] +% {The version of the package, with no leading ``v''} +% \begin{macrocode} +\DeclareDocumentCommand\version{m}{% + \def\@version{#1}% +} +% \end{macrocode} +% \end{macro} +% Finally, we set the default package name to \cs{jobname}. +% \begin{macrocode} +\package{\jobname} +% \end{macrocode} +% +% \subsubsection{Using metadata} +% We define two macros that read useful metadata; \cs{theversion} +% and \cs{thepackage}. These are used internally by \cs{maketitle}. +% \begin{macro}{\theversion} +% \begin{macrocode} +\DeclareDocumentCommand\theversion{}{v\@version} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\thepackage} +% \begin{macrocode} +\DeclareDocumentCommand\thepackage{}{\pkg*{\@package}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\thepkg} +% \begin{macrocode} +\DeclareDocumentCommand\thepkg{}{\thepackage} +% \end{macrocode} +% \end{macro} +% Additionally we define \cs{skdocpdfsettings}, which is also used +% by \cs{maketitle}, to include PDF metadata if the documentation +% is being compiled using \hologo{pdfLaTeX}. +% \begin{macrocode} +\ifpdf + \def\skdocpdfsettings{% + \hypersetup{% + pdfauthor = {\@author\space<\@plainemail>}, + pdftitle = {\@title}, + pdfsubject = {Documentation~of~LaTeX~package~\@package}, + pdfkeywords = {\@package,~LaTeX,~TeX} + }% + }% +\else + \let\skdocpdfsettings\empty% +\fi +% \end{macrocode} +% +% \subsection{General document commands} +% Most of the general document commands are defined by the +% \pkg{scrartcl} document class we base ourselves on, but a few +% of them have to be redefined. +% +% \subsubsection{Notices and warnings} +% We define macros to typeset notices and warnings in the documentation +% text. Notices are typeset as \Notice{this is a notice}, and warnings +% are typeset as follows: \Warning{this is a warning} +% A macro for longer warnings is also available: +% \LongWarning{This is a longer warning.} +% +% \begin{macro}{\Notice}[1] +% {Notice text} +% \begin{macrocode} +\DeclareDocumentCommand\Notice{m}{ + (\emph{\textbf{Note:}~#1}) +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\Warning}[1] +% {Warning text} +% \changes{1.5}{Fix spacing to consider \cs{fboxsep} and \cs{fboxrule}} +% \begin{macrocode} +\DeclareDocumentCommand\Warning{+m}{ + \vspace{\baselineskip} + \par\noindent + \fbox{\begin{minipage}[c]{\textwidth-2\fboxsep-2\fboxrule} + \centering + \textbf{Warning:}~#1 + \end{minipage}} + \vspace{\baselineskip} + \par +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\LongWarning}[1] +% {Warning text} +% \changes{1.5}{Fix spacing to consider \cs{fboxsep} and \cs{fboxrule}} +% \begin{macrocode} +\DeclareDocumentCommand\LongWarning{+m}{ + \Warning{ + \par\noindent + \begin{minipage}{\textwidth-2\fboxsep-2\fboxrule} + #1 + \end{minipage} + } +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{The title page} +% The title page consists of the \cs{maketitle} and the \env{abstract}. +% We redefine both, inspired slightly by the Prac\TeX\ journal and the +% \pkg{skrapport} document class. +% \begin{macro}{\@maketitle} +% \changes{1.5}{Get rid of a superfluous \cs{newpage}} +% \begin{macrocode} +\def\@maketitle{% + \null + \begin{flushleft}% + {% + \Huge\sectfont\@title% + \ifx\@ctan\@empty\else% + \footnote{Available~on~\@ctan.}% + \fi + \ifx\@repository\@empty\else% + \footnote{Development~version~available~on~\@repository.}% + \fi% + \par% + }% + \vskip 1em + {% + \Large\@author + \ifx\@email\@empty\else% + \space + \newlength\skdoc@minipage@ew% + \settowidth{\skdoc@minipage@ew}{% + \normalsize{$\lceil${\@email}$\rfloor$}} + \begin{minipage}[b]{\skdoc@minipage@ew} + \normalsize{$\lceil${\@email}$\rfloor$} + \end{minipage}\par% + \fi% + }% + \ifx\@version\@empty\else + \vskip .5em + {% + \large Version~\@version\par% + }% + \fi + \end{flushleft}% + \par\bigskip% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\maketitle} +% \begin{macrocode} +\def\maketitle{% + \begingroup + \skdocpdfsettings + \renewcommand\thefootnote{\@fnsymbol\c@footnote} + \@maketitle + \setcounter{footnote}{0} + \skdocpdfsettings + \endgroup +} +% \end{macrocode} +% \end{macro} +% \begin{environment}{abstract} +% \begin{macrocode} +\DeclareDocumentEnvironment{abstract}{}{ + \newlength\skdoc@abstract@tw% + \newlength\skdoc@abstract@aw% + \settowidth{\skdoc@abstract@tw}{\descfont\abstractname}% + \setlength{\skdoc@abstract@aw}{\the\textwidth-\the\skdoc@abstract@tw-2em}% + \begin{minipage}{\textwidth} + \begin{minipage}[t]{\skdoc@abstract@tw}% + \begin{flushright}% + \leavevmode\descfont\abstractname% + \end{flushright}% + \end{minipage}% + \hspace{1em}% + \begin{minipage}[t]{\skdoc@abstract@aw}% +}{ + \end{minipage} + \end{minipage} +} +% \end{macrocode} +% \end{environment} +% +% \subsubsection{Table of contents} +% The table of contents are redefined to imitate the excellent table +% of contents of the \pkg{microtype} manual. +% \begin{macro*}{\l@section} +% \begin{macrocode} +\let\l@section@\l@section +\def\l@section{\vskip -.75ex\l@section@} +% \end{macrocode} +% \end{macro*} +% \begin{macro*}{\l@subsection} +% \begin{macrocode} +\def\l@subsection{\vskip.35ex\penalty\@secpenalty\@dottedtocline{2}{1.5em}{2.7em}} +% \end{macrocode} +% \end{macro*} +% \begin{macro*}{l@subsubsection} +% \begin{macrocode} +\def\l@subsubsection#1#2{ + \leftskip 4.2em + \parindent 0pt + {\let\numberline\@gobble{\small #1~[#2]}} +} +% \end{macrocode} +% \end{macro*} +% \begin{macro*}{\l@table} +% \begin{macrocode} +\def\l@table{\@dottedtocline{1}{0pt}{1.5em}} +% \end{macrocode} +% \end{macro*} +% \begin{macro*}{\l@figure} +% \begin{macrocode} +\def\l@figure{\@dottedtocline{1}{0pt}{1.5em}} +% \end{macrocode} +% \end{macro*} +% \begin{macrocode} +\def\@pnumwidth{1.7em} +\AtEndDocument{\addtocontents{toc}{\par}} +% \end{macrocode} +% \begin{macro}{\tableofcontents} +% \begin{macrocode} +\let\old@tableofcontents\tableofcontents +\DeclareDocumentCommand\tableofcontents{}{ + \bool_gset_true:N\g__skdoc_no_index_bool + \microtypesetup{protrusion=false} + \old@tableofcontents + \microtypesetup{protrusion=true} + \bool_gset_false:N\g__skdoc_no_index_bool +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Including the LPPL license} +% A helper macro that includes the LPPL license is also provided. +% \begin{macro}{\PrintLPPL} +% \begin{macrocode} +\DeclareDocumentCommand\PrintLPPL{}{ + \begingroup + \IfFileExists{lppl.tex}{ + \let\old@verbatim@font\verbatim@font + \def\verbatim@font{ + \old@verbatim@font\tiny + } + \def\LPPLicense{\begingroup\small} + \def\endLPPLicense{\endmulticols\endgroup} + \DeclareDocumentCommand\LPPLsection{m}{ + \section{####1} + } + \DeclareDocumentCommand\skdoc@lppl@hack{m}{ + \end{multicols} + \begin{multicols}{2} + [\subsection*{####1}][6\baselineskip] + } + \DeclareDocumentCommand\LPPLsubsection{m}{ + \subsection*{####1} + \let\LPPLsubsection\skdoc@lppl@hack + \begin{multicols}{2} + } + \DeclareDocumentCommand\LPPLsubsubsection{m}{ + \subsubsection*{####1} + } + \DeclareDocumentCommand\LPPLparagraph{m}{\paragraph*{####1}} + \DeclareDocumentCommand\LPPLfile{m}{\file{####1}} + \let\oldmakeatletter\makeatletter + \long\def\makeatletter####1\makeatother{ + \let\makeatletter\oldmakeatletter + } + \setlength\leftmargini{15pt} + \setlength\leftmarginii{12.5pt} + \setlength\leftmarginiii{10pt} + \newenvironment{enum}[1][0]{ + \list\labelenumi{ + \usecounter{enumi} + \setcounter{enumi}{####1} + \addtocounter{enumi}{-1} + \leftmargin 30pt + \itemindent-15pt + \labelwidth 15pt + \labelsep 0pt + \def\makelabel########1{########1\hss}} + }{\endlist} + \input{lppl} + }{ + \msg_warning:nn{skdoc}{no-lppl} + } + \endgroup +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Cosmetic changes} +% We perform a couple of cosmetic changes to existing features as +% well. First, we set a new header/footer style using the KOMA-script +% \cs{deftripstyle} macro. +% \begin{macrocode} +\deftripstyle{skdoc}% + {}{}{}% + {\small The~\textbf{\pkg*{\@package}}~package,~v\@version}{}{\small\pagemark} +\AfterBeginDocument{\pagestyle{skdoc}} +% \end{macrocode} +% We also redefine the section level format to set the section numbers +% in the margin, much like the \pkg{microtype} manual. +% \begin{macrocode} +\RenewDocumentCommand{\othersectionlevelsformat}{m}{% + \makebox[0pt][r]{% + \fontfamily{fos}\mdseries\selectfont + \csname the#1\endcsname\enskip}% +} +% \end{macrocode} +% Finally, we actually use \pkg{microtype} in the document class, and +% make sure to disable it in the verbatim environments. +% Set up microtype properly +% \begin{macrocode} +\g@addto@macro\@verbatim{\microtypesetup{activate=false}} +\AtEndOfClass{% + \microtypesetup{expansion,kerning,spacing,tracking}% + \DisableLigatures{family = tt*}% +} +% \end{macrocode} +% We also want numbers on the bibliography headings, if we are loading +% \pkg{biblatex}. If we happen to be loading \pkg{bibtex}, we issue a +% warning instead. +% \begin{macrocode} +\AtBeginDocument{ + \ifdefined\defbibheading + \defbibheading{bibliography}[\bibname]{\section{#1}} + \fi + \@ifpackageloaded{bibtex}{\msg_warning:nn{skdoc}{bibtex-unsupported}}{} +} +% \end{macrocode} +% Oh, and we want \cs{marginpar}s on the left, not on the right. +% \begin{macrocode} +\AtBeginDocument{\reversemarginpar} +% \end{macrocode} +% +% That's it, we're done! +% \begin{macrocode} +\endinput +% \end{macrocode} +% \iffalse +%</class> +% \fi +% \Finale +% \section{Installation} +% The easiest way to install this package is using the package +% manager provided by your \LaTeX\ installation if such a program +% is available. Failing that, provided you have obtained the package +% source (\file{skdoc.dtx} and \file{Makefile}) from either CTAN +% or Github, running \texttt{make install} inside the source directory +% works well. This will extract the documentation and code from +% \file{skdoc.dtx}, install all files into the TDS tree at +% \texttt{TEXMFHOME} and run \texttt{mktexlsr}. +% +% If you want to extract code and documentation without installing +% the package, run \texttt{make all} instead. If you insist on not +% using \texttt{make}, remember that \file{skdoc.cls} is generated +% by running \texttt{tex}, while the documentation is generated by +% running \texttt{pdflatex}. +% +% \PrintChanges +% \PrintIndex +% \printbibliography +% \endinput diff --git a/macros/latex/contrib/skdoc/skdoc.pdf b/macros/latex/contrib/skdoc/skdoc.pdf new file mode 100644 index 0000000000..432f58a336 Binary files /dev/null and b/macros/latex/contrib/skdoc/skdoc.pdf differ -- cgit v1.2.3