% \iffalse %% skdoc documentation class %% %% Copyright (C) 2012-2020 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> {2020/11/16}{1.5d}{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.5d} % \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)} % \changes{1.5b}{Track \pkg{expl3} changes (thanks to Phelype Oleinik). Replace \pkg{opensans} option \opt{osfigures} with \opt{oldstyle} (\#40)} % \changes{1.5c}{Replace \pkg{scrpage} package with \pkg{scrlayer-scrpage} (thanks to Daniel Wunderlich)} % \changes{1.5d}{Use compatibiltiy levels for \pkg{scrartcl} (\#44)} % \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, abstract=true, bibliography=totocnumbered, index=totoc, version=3.32 ]{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{scrlayer-scrpage} \AtEndOfClass{% \RequirePackage[\skdoc@babel]{babel} \RequirePackage[english=british]{csquotes} \RequirePackage[font=small,labelfont=bf,textfont=it]{caption} \RequirePackage{PTSerif,sourcecodepro} \RequirePackage[defaultsans,oldstyle,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_int \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% {\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_int }{ \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