diff options
author | Norbert Preining <preining@logic.at> | 2013-05-27 01:20:56 +0000 |
---|---|---|
committer | Norbert Preining <preining@logic.at> | 2013-05-27 01:20:56 +0000 |
commit | bddefbf234bbe8889456b2e1b09cce68cf590891 (patch) | |
tree | 76869528777f4951ab78a9b15d1e15f593721418 /Master/texmf-dist/source | |
parent | f07b7c015a77f69963eb08048aba8c5621cdb0c1 (diff) |
skdoc 5/27
git-svn-id: svn://tug.org/texlive/trunk@30697 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source')
-rw-r--r-- | Master/texmf-dist/source/latex/skdoc/skdoc.dtx | 1046 |
1 files changed, 892 insertions, 154 deletions
diff --git a/Master/texmf-dist/source/latex/skdoc/skdoc.dtx b/Master/texmf-dist/source/latex/skdoc/skdoc.dtx index e8fea60711c..afd57482a03 100644 --- a/Master/texmf-dist/source/latex/skdoc/skdoc.dtx +++ b/Master/texmf-dist/source/latex/skdoc/skdoc.dtx @@ -1,7 +1,7 @@ % \iffalse %% skdoc documentation class %% -%% Copyright (C) 2012 by Simon Sigurdhsson <sigurdhsson@gmail.com> +%% Copyright (C) 2012-2013 by Simon Sigurdhsson <sigurdhsson@gmail.com> %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3 @@ -73,7 +73,7 @@ %</driver> %<class>\ProvidesExplClass{skdoc} %<*class> - {2012/12/26}{1.0}{skdoc documentation class} + {2013/05/24}{1.3a}{skdoc documentation class} %</class> % %<*driver> @@ -82,15 +82,20 @@ \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{skdoc} +\documentclass[highlight=false]{skdoc} \usepackage{hologo} \usepackage{booktabs} +\usepackage{csquotes} \usepackage[style=authoryear,backend=biber]{biblatex} %%\usepackage{chslacite} \begin{filecontents}{skdoc.bib} @@ -106,6 +111,14 @@ 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 @@ -119,10 +132,15 @@ % {}{\small\pagemark} % \pagestyle{skdoc-class} % -% \version{1.0} +% \version{1.3a} % \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}} % -% \package[ctan=skbundle,vcs=https://github.com/urdh/skdoc]{skdoc} +% \package[ctan=skdoc,vcs=https://github.com/urdh/skdoc]{skdoc} % \repository{https://github.com/urdh/skdoc} % \title{The \thepkg{} document class} % \author{Simon Sigurdhsson} @@ -179,13 +197,27 @@ % % \subsection{Options} % \Option{load}\WithValues{\meta{package}}\AndDefault{\cs{jobname}} -% The \thepkg\ document class has only one option. The \opt{load} +% \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. \Warning{The \opt{load} -% option will likely disappear in a future version.} +% \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. % % \subsection{General macros} % The document class defines a number of general macros intended for @@ -383,7 +415,7 @@ % \label{tab:args} % \begin{tabular}{ll} % \toprule -% Invokation % Result \\ +% Invokation & Result \\ % \midrule % \Macro\marg{argument} & \marg{argument} \\ % \Macro\oarg{argument} & \oarg{argument} \\ @@ -394,6 +426,39 @@ % \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 @@ -534,16 +599,16 @@ % improve readability of the implementation code. % % \DescribeEnv[<description>]{macro}{<\textbackslash macro>} -% <\# of args>{<arg 1 description>}'...' -% {<arg n description>} +% [<\# of args>]{<arg 1 description>}'...' +% {<arg n description>} % 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>}'...' -% {<arg n description>} +% [<\# of args>]{<arg 1 description>}'...' +% {<arg n description>} % This environment describes the implementation of an environment. % % \DescribeEnv[<description>]{option}{<option>} @@ -588,12 +653,16 @@ % the sequence % \Macro\PreambleTo{<\textbackslash token>}{\cs*{jobname}.tex}. % -% \DescribeEnv[<implementation>]{MacroCode}{<key>} +% \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). +% 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 @@ -653,17 +722,19 @@ % 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 no known issues. % \iffalse -% \section{Planned improvements} -% Planned improvements of this class include -% \begin{itemize} -% \item Do things the \LaTeX3 way, rename the variables properly -% and generally conform to \pkg{expl3} guidelines when -% applicable. (Way future thing.) -% \end{itemize} +% \begin{description} +% \item[\#?] ??? +% \end{description} % \fi +% If you discover any bugs in this package, please report them to the +% issue tracker in the \thepackage\ Github repository. % -% \Implementation +% \Implementation \ExplHack % \section{Implementation} % \iffalse %</driver> @@ -685,11 +756,11 @@ % 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} +\RequirePackage{etoolbox,xstring,xparse,atbegshi,kvoptions,pdftexcmds} % \end{macrocode} % Now, higher-level packages we use in our definitions. % \begin{macrocode} -\RequirePackage{verbatim,marginnote,calc,hyperref,multicol,hologo} +\RequirePackage{verbatim,needspace,marginnote,calc,hyperref,multicol,hologo} \RequirePackage[nomain,xindy,numberedsection,order=letter, sanitize={description=false,sort=false}]{glossaries} % \end{macrocode} @@ -702,10 +773,12 @@ \RequirePackage[british]{babel} \RequirePackage[english=british]{csquotes} \RequirePackage[font=small,labelfont=bf,textfont=it]{caption} -\RequirePackage{scrpage2,PTSerif,ascii} +\RequirePackage{scrpage2,PTSerif} +\usepackage[scaled=1.03]{inconsolata} \RequirePackage[defaultsans,osfigures,scale=0.95]{opensans} \RequirePackage[babel]{microtype} % \end{macrocode} +% % \subsection{Error messages} % Set up some error message texts for later use. % \begin{macrocode} @@ -714,18 +787,95 @@ \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} +% +% 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 (as of version 1.0) only option, and process it. +% Define the all options, and process them. % \begin{macrocode} \SetupKeyvalOptions{ family=skdoc, prefix=skdoc@ } \DeclareStringOption{load}[\jobname] +\DeclareBoolOption[true]{highlight} \ProcessKeyvalOptions* % \end{macrocode} -% If the option was used, load the given package if it exists. +% If the \opt{load} option was used, load the given package if it exists. % \begin{macrocode} \IfStrEq{\skdoc@load}{}{}{% \IfFileExists{\skdoc@load.sty}{% @@ -733,6 +883,305 @@ }{} } % \end{macrocode} +% +% \subsection{Special case: syntax highlighting} +% We support syntax highlighting through \pkg{minted}, but only if +% we're running with unrestricted \cs{write18} access \emph{and} +% there exists a suitable executable (\texttt{pygmentize}). Since +% \pkg{minted} bails out without \cs{write18} access, we have to test +% that before even loading it. +% +% \subsubsection{A simple \cs{write18} test} +% Using the \cs{pdf@shellescape} macro from \pkg{pdftexcmds}, we +% can define a new conditional that decides if we have unrestricted +% \cs{write18} or not. +% \begin{macro*}{\__skdoc_if_shellescape:T} +% \begin{macro*}{\__skdoc_if_shellescape:F} +% \begin{macro}{\__skdoc_if_shellescape:TF} +% \begin{macrocode} +\prg_new_conditional:Nnn\__skdoc_if_shellescape:{T,F,TF}{ + \if_cs_exist:N\pdf@shellescape +% \end{macrocode} +% If the command sequence exists (it really should), we test to see +% if it is equal to one. The \cs{pdf@shellescape} macro will be zero +% if no \cs{write18} access is available, two if we have restricted +% access and one if access is unrestricted. +% \begin{macrocode} + \if_int_compare:w\pdf@shellescape=\c_one + \prg_return_true: + \else: + \prg_return_false: + \fi: +% \end{macrocode} +% If the command sequence doesn't exist, we assume that we have +% unrestricted \cs{write18} access (we probably don't), and let +% \LaTeX\ complain about it later. +% \begin{macrocode} + \else: + \prg_return_true: + \fi: +} +% \end{macrocode} +% \end{macro} +% \end{macro*} +% \end{macro*} +% +% \subsubsection{Testing for an application} +% In order to find out wether \texttt{pygmentize} is installed, we +% have to test for its binary. This is done by shelling out to +% \texttt{which} and reading a temporary file, which means we need +% a way to delete that file. +% \begin{macro}{\__skdoc_rm:n}[1] +% {The file to be removed} +% \begin{macrocode} +\cs_new:Npn\__skdoc_rm:n#1{ + \immediate\write18{rm~#1} +} +% \end{macrocode} +% \end{macro} +% Now, let's define the actual test. Note that this test will fail +% on non-unixy platforms (\emph{i.e.} Windows). Deal with it for now. +% \begin{macro*}{\__skdoc_if_pygmentize:nT} +% \begin{macro*}{\__skdoc_if_pygmentize:nF} +% \begin{macro}{\__skdoc_if_pygmentize:nTF}[1] +% {The name of the binary to check existence of} +% \begin{macrocode} +\prg_new_conditional:Nnn\__skdoc_if_pygmentize:{T,F,TF}{ +% \end{macrocode} +% First, run \texttt{which} to create the temporary file. +% \begin{macrocode} + \immediate\write18{which~pygmentize~&&~touch~\jobname.aex} +% \end{macrocode} +% A temporary boolean is defined to hold the result of the test (this +% is a bit of carco cult programming, any clues as to why placing the +% result inside \cs{file_if_exists:nTF} doesn't work are welcome), and +% if the test is successful we remove the temporary file. +% \begin{macrocode} + \bool_set:Nn\l_tmpa_bool{\c_false_bool} + \file_if_exist:nT{\jobname.aex}{ + \__skdoc_rm:n{\jobname.aex} + \bool_set:Nn\l_tmpa_bool{\c_true_bool} + } +% \end{macrocode} +% Finally, the temporary boolean is used to return a result. +% \begin{macrocode} + \if_bool:N\l_tmpa_bool + \prg_return_true: + \else: + \prg_return_false: + \fi: +} +% \end{macrocode} +% \end{macro} +% \end{macro*} +% \end{macro*} +% +% Using the macros defined above, we can test for both \cs{write18} +% and \texttt{pygmentize}, loading \pkg{minted} and setting a flag +% if both exist. If the option \opt{highlight} was supplied and set +% to \texttt{false}, we do nothing. +% \begin{macrocode} +\ifskdoc@highlight + \IfFileExists{\skdoc@load.sty}{ + \__skdoc_if_shellescape:TF{ + \__skdoc_if_pygmentize:TF{ + \bool_gset_true:N\g__skdoc_use_minted_bool + \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} + \renewcommand\minted@usedefaultstyle{} + \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} @@ -745,6 +1194,8 @@ % {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: @@ -757,13 +1208,15 @@ \def\skdoc@preamble{}% \def\skdoc@key{#2}% \IfNoValueTF{#1}{}{\keys_set:nn{skdoc@declarefile}{#1}} - \tl_new:c{skdoc@output@\skdoc@key} \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} } - \IfStrEq{\skdoc@preamble}{}{}{ + \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{ @@ -787,67 +1240,212 @@ % \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}{% - \iftoggle{skdoc@impl}{\@bsphack}{} - \def\skdoc@key{#1} - \int_if_exist:cTF{skdoc@output@\skdoc@key @line}{}{ - \msg_critical:nnx{skdoc}{key-nexists}{\skdoc@key} - }% - \marginnote{ - \leavevmode - \llap{ - \scriptsize\color{gray} - $\langle$\skdoc@key$\rangle$ - \makebox[2ex]{\strut} + \clist_set:Nn\l__skdoc_keys{#1} +% \end{macrocode} +% If the file we're supposed to write to hasn't been initialized yet, +% we error out with a critical error. +% \begin{macrocode} + \clist_map_inline:Nn\l__skdoc_keys{ + \int_if_exist:cTF{skdoc@output@##1@line}{}{ + \msg_critical:nnn{skdoc}{key-nexists}{##1} + }% +% \end{macrocode} +% Before doing anything, set create or increment a counter keeping +% track of the line number of the file we're writing to. +% \begin{macrocode} + \int_compare:nNnT{\int_use:c{skdoc@output@##1@line}}=\c_zero% + {\int_gincr:c{skdoc@output@##1@line}}% + } +% \end{macrocode} +% Now, if we're supposed to print code, we set a few things up. +% \begin{macrocode} + \__skdoc_if_print_code:T{ + \bool_if:NTF\g__skdoc_use_minted_bool{ +% \end{macrocode} +% If we're using \pkg{minted}, we set a few options ans open the +% output file. +% \begin{macrocode} + \minted@resetoptions% + \exp_args:Nnx\setkeys{minted@opt}{ + \int_compare:nNnF{\clist_count:N\l__skdoc_keys}>\c_one{ + \bool_if:NF\g__skdoc_in_example_bool{linenos,} + 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{% - \tl_gput_right:cx{skdoc@output@\skdoc@key}{\the\verbatim@line\iow_newline:}% - \int_gincr:c{skdoc@output@\skdoc@key @line}% - \iftoggle{skdoc@impl}{ - \noindent\leavevmode% - \hspace*{-5ex} - \begin{minipage}[c][1ex]{\textwidth} - \makebox[4ex]{% - \leavevmode - \tiny\color{lightgray}\hfill% - \int_use:c{skdoc@output@\skdoc@key @line}% - }% - \hspace*{1ex}% - { - \verbatim@font\footnotesize - \the\verbatim@line - } - \end{minipage} - \vskip-.75ex\par - }{} +% \end{macrocode} +% We alsays append the line to the appropriate token list, so that it +% is saved to the output file. +% \begin{macrocode} + \clist_map_inline:Nn\l__skdoc_keys{ + \tl_gput_right:cx{skdoc@output@####1}{\the\verbatim@line\iow_newline:}% + } +% \end{macrocode} +% If we're supposed to print code, we do a lot more... +% \begin{macrocode} + \__skdoc_if_print_code:T{ + \bool_if:NTF\g__skdoc_use_minted_bool{ +% \end{macrocode} +% ...but if we're using minted, \enquote{a lot more} consists of also +% writing the line to the file used by \pkg{minted}. +% \begin{macrocode} + \iow_now:Nx\minted@code{\the\verbatim@line}% + }{ +% \end{macrocode} +% Otherwise, we actually do a lot of stuff. We typeset the line number +% (unless we're in an example): +% \begin{macrocode} + \noindent\leavevmode% + \bool_if:NF\g__skdoc_in_example_bool{\hspace*{-5ex}} + \begin{minipage}[c][1ex]{\textwidth} + \bool_if:nF{ + \g__skdoc_in_example_bool && + !\int_compare_p:nNn{\clist_count:N\l__skdoc_keys}>\c_one + }{ + \makebox[4ex]{% + \leavevmode + \sffamily\tiny\color{lightgray}\hfill% + \clist_map_inline:Nn\l__skdoc_keys{ + \oldstylenums{\int_use:c{skdoc@output@####1@line}}% + } + }% + \hspace*{1ex}% + } +% \end{macrocode} +% We also typeset the actual line: +% \begin{macrocode} + { + \verbatim@font + \the\verbatim@line + } + \end{minipage} +% \end{macrocode} +% Both of them in the same one-line-high minipage covering the page +% width. Note the use of \cs{llap} for line numbers in the margin. +% We end with a \cs{par} for the next line. +% \begin{macrocode} + \par + } + } +% \end{macrocode} +% Finally, the line number counter is incremented. +% \begin{macrocode} + \clist_map_inline:Nn\l__skdoc_keys{ + \int_gincr:c{skdoc@output@####1@line}% + } }% +% \end{macrocode} +% Now the \env{verbatim} catcode magic begins. +% \begin{macrocode} + \group_begin: \let\do\@makeother\dospecials\catcode`\^^M\active% - \iftoggle{skdoc@impl}{ + \bool_if:nT{ + \__skdoc_if_print_code_p: && + !\g__skdoc_use_minted_bool + }{ \frenchspacing\@vobeyspaces - }{} + } \verbatim@start% }{% - \iftoggle{skdoc@impl}{\@esphack}{}% + \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} % \begin{macrocode} \DeclareDocumentEnvironment{MacroCode}{m}{ - \iftoggle{skdoc@impl}{ + \__skdoc_if_print_code:T{ \vspace{.2\baselineskip} - \par\noindent - }{} + \bool_if:NF\g__skdoc_use_minted_bool{\par\noindent} + } \skdoc@verbatim{#1} }{ \endskdoc@verbatim - \iftoggle{skdoc@impl}{ + \__skdoc_if_print_code:T{ \vspace{.5\baselineskip} - }{} + } } % \end{macrocode} % \end{environment} @@ -945,13 +1543,6 @@ % 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. -% -% First, though, we introduce a toggle letting us permanently disable -% indexing inside \emph{e.g.} the table of contents and index. -% \begin{macrocode} -\newtoggle{skdoc@noindex} -\togglefalse{skdoc@noindex} -% \end{macrocode} % \begin{macro}{\cs}[2] % {True if this is the starred variant} % {The macro name to be typeset} @@ -959,7 +1550,7 @@ % \begin{macrocode} \DeclareDocumentCommand\cs{sm}{ \texttt{\char`\\#2} - \iftoggle{skdoc@noindex}{}{ + \bool_if:NF\g__skdoc_no_index_bool{ \IfBooleanTF{#1}{}{\index@macro{#2}} } } @@ -972,7 +1563,7 @@ % \begin{macrocode} \DeclareDocumentCommand\env{sm}{ \texttt{#2} - \iftoggle{skdoc@noindex}{}{ + \bool_if:NF\g__skdoc_no_index_bool{ \IfBooleanTF{#1}{}{\index@environment{#2}} } } @@ -985,7 +1576,7 @@ % \begin{macrocode} \DeclareDocumentCommand\pkg{sm}{ \textsf{#2} - \iftoggle{skdoc@noindex}{}{ + \bool_if:NF\g__skdoc_no_index_bool{ \IfBooleanTF{#1}{}{\index@package{#2}} } } @@ -998,7 +1589,7 @@ % \begin{macrocode} \DeclareDocumentCommand\opt{sm}{ \texttt{#2} - \iftoggle{skdoc@noindex}{}{ + \bool_if:NF\g__skdoc_no_index_bool{ \IfBooleanTF{#1}{}{\index@option{#2}} } } @@ -1011,7 +1602,7 @@ % \begin{macrocode} \DeclareDocumentCommand\bib{sm}{ \texttt{@#2} - \iftoggle{skdoc@noindex}{}{ + \bool_if:NF\g__skdoc_no_index_bool{ \IfBooleanTF{#1}{}{\index@bibentry{#2}} } } @@ -1024,7 +1615,7 @@ % \begin{macrocode} \DeclareDocumentCommand\thm{sm}{ \textrm{#2} - \iftoggle{skdoc@noindex}{}{ + \bool_if:NF\g__skdoc_no_index_bool{ \IfBooleanTF{#1}{}{\index@theme{#2}} } } @@ -1037,7 +1628,7 @@ % \begin{macrocode} \DeclareDocumentCommand\file{sm}{ \texttt{#2} - \iftoggle{skdoc@noindex}{}{ + \bool_if:NF\g__skdoc_no_index_bool{ \IfBooleanTF{#1}{}{\index@file{#2}} } } @@ -1177,9 +1768,10 @@ % \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\fi + \ifx\@let@token\AndDefault\else\par\noindent\nobreak\ignorespaces\fi } % \end{macrocode} % \end{macro*} @@ -1199,9 +1791,10 @@ % {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 + \llap{\textcolor{gray}{\texttt{(#1)}}}\par\noindent\nobreak\ignorespaces } % \end{macrocode} % \end{macro} @@ -1222,6 +1815,7 @@ % \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]{ @@ -1230,7 +1824,7 @@ \textcolor{gray}{\texttt{,#2}} } } - \par\noindent\nobreak + \par\noindent\nobreak\ignorespaces } % \end{macrocode} % \end{macro} @@ -1238,13 +1832,14 @@ % 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 + \nobreak\par\noindent\nobreak\ignorespaces } % \end{macrocode} % \end{macro} @@ -1252,28 +1847,147 @@ % 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 + \nobreak\par\noindent\nobreak\ignorespaces } % \end{macrocode} % \end{macro} % -% \paragraph{Missing commands} -% Descriptional commands for \hologo{BibTeX} entry types and themes -% are not yet implemented. +% 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} % -% Lastly, we define an envionment for showing examples. It's -% rediculously simple, really. +% 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}{}{ - \minisec{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} % @@ -1294,7 +2008,7 @@ \IfBooleanTF{#1}{ \IfNoValueTF{#3}{}{ \int_compare:nNnTF{#3}>{0}{ - \cs:w use_none:\prg_replicate:nn{#3}{n}\cs_end: + \use:c{use_none:\prg_replicate:nn{#3}{n}} }{} } }{ @@ -1322,7 +2036,7 @@ \IfBooleanTF{#1}{ \IfNoValueTF{#3}{}{ \int_compare:nNnTF{#3}>{0}{ - \cs:w use_none:\prg_replicate:nn{#3}{n}\cs_end: + \use:c{use_none:\prg_replicate:nn{#3}{n}} }{} } }{ @@ -1447,11 +2161,14 @@ % \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\mbox{} - \marginnote{\llap{\implstyle{#1}}} - \par + \par\leavevmode\null + \hbox{% + \marginnote{\llap{\implstyle{#1\strut}}}% + } + \null } % \end{macrocode} % \end{macro} @@ -1524,19 +2241,26 @@ % \end{macro*} % % \subsection{The index} -% \begin{macrocode} -\prg_new_conditional:Nnn\__skdoc_do_index:{p}{ - \iftoggle{skdoc@impl}{ +% \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: }{ - \iftoggle{skdoc@in@impl}{ - \prg_return_false: - }{ - \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 @@ -1551,9 +2275,9 @@ % index entry. % \begin{macrocode} \DeclareDocumentCommand\@index@{mm}{ - \if_predicate:w\__skdoc_do_index_p: + \__skdoc_if_do_index:T{ \@index@@{#1}{#2} - \fi: + } } % \end{macrocode} % \end{macro} @@ -1599,7 +2323,7 @@ \ifglsentryexists{index-\skdoc@temp}{}{ \@index@{#3}{\cs*{#3}} } - \if_predicate:w\__skdoc_do_index_p: + \__skdoc_if_do_index:T{ \IfBooleanTF{#2}{ \glsadd[types=index,format=hyperul]{index-\skdoc@temp} }{ @@ -1609,7 +2333,7 @@ \glsadd[types=index]{index-\skdoc@temp} } } - \fi: + } } % \end{macrocode} % \end{macro} @@ -1623,7 +2347,7 @@ \ifglsentryexists{index-\skdoc@temp}{}{ \@index@{\string#3}{\env*{\string#3}~(environment)} } - \if_predicate:w\__skdoc_do_index_p: + \__skdoc_if_do_index:T{ \IfBooleanTF{#2}{ \glsadd[types=index,format=hyperul]{index-\skdoc@temp} }{ @@ -1633,7 +2357,7 @@ \glsadd[types=index]{index-\skdoc@temp} } } - \fi: + } } % \end{macrocode} % \end{macro} @@ -1647,7 +2371,7 @@ \ifglsentryexists{index-\skdoc@temp}{}{ \@index@{\string#3}{\opt*{\string#3}~(option)} } - \if_predicate:w\__skdoc_do_index_p: + \__skdoc_if_do_index:T{ \IfBooleanTF{#2}{ \glsadd[types=index,format=hyperul]{index-\skdoc@temp} }{ @@ -1657,7 +2381,7 @@ \glsadd[types=index]{index-\skdoc@temp} } } - \fi: + } } % \end{macrocode} % \end{macro} @@ -1672,7 +2396,7 @@ \ifglsentryexists{index-\skdoc@temp}{}{ \@index@{#3}{\bib*{#3}~(\hologoRobust{BibTeX}~entry~type)} } - \if_predicate:w\__skdoc_do_index_p: + \__skdoc_if_do_index:T{ \IfBooleanTF{#2}{ \glsadd[types=index,format=hyperul]{index-\skdoc@temp} }{ @@ -1682,7 +2406,7 @@ \glsadd[types=index]{index-\skdoc@temp} } } - \fi: + } } % \end{macrocode} % \end{macro} @@ -1696,7 +2420,7 @@ \ifglsentryexists{index-\skdoc@temp}{}{ \@index@{\string#3}{\thm*{\string#3}~(theme)} } - \if_predicate:w\__skdoc_do_index_p: + \__skdoc_if_do_index:T{ \IfBooleanTF{#2}{ \glsadd[types=index,format=hyperul]{index-\skdoc@temp} }{ @@ -1706,7 +2430,7 @@ \glsadd[types=index]{index-\skdoc@temp} } } - \fi: + } } % \end{macrocode} % \end{macro} @@ -1720,7 +2444,7 @@ \ifglsentryexists{index-\skdoc@temp}{}{ \@index@{\string#3}{\pkg*{\string#3}~(package)} } - \if_predicate:w\__skdoc_do_index_p: + \__skdoc_if_do_index:T{ \IfBooleanTF{#2}{ \glsadd[types=index,format=hyperul]{index-\skdoc@temp} }{ @@ -1730,7 +2454,7 @@ \glsadd[types=index]{index-\skdoc@temp} } } - \fi: + } } % \end{macrocode} % \end{macro} @@ -1744,7 +2468,7 @@ \ifglsentryexists{index-\skdoc@temp}{}{ \@index@{\string#3}{\file*{\string#3}~(file)} } - \if_predicate:w\__skdoc_do_index_p: + \__skdoc_if_do_index:T{ \IfBooleanTF{#2}{ \glsadd[types=index,format=hyperul]{index-\skdoc@temp} }{ @@ -1754,7 +2478,7 @@ \glsadd[types=index]{index-\skdoc@temp} } } - \fi: + } } % \end{macrocode} % \end{macro} @@ -1779,14 +2503,14 @@ \glossarystyle{indexgroup} \renewcommand*{\glspostdescription}{\unskip\leaders\hbox to 2.9mm{\hss.}\hfill\strut} \renewenvironment{theglossary}{ - \toggletrue{skdoc@noindex} + \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} - \togglefalse{skdoc@noindex} + \bool_gset_false:N\g__skdoc_no_index_bool } \renewcommand*{\glossaryentryfield}[5]{ \item\glsentryitem{##1}\glstarget{##1}{##2} @@ -1811,13 +2535,14 @@ \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~boldface~refer~to~the~page~where~the~ + 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~ @@ -1955,11 +2680,11 @@ \newglossarystyle{changelog}{ \glossarystyle{altlist} \renewenvironment{theglossary}{ - \toggletrue{skdoc@noindex} + \bool_gset_true:N\g__skdoc_no_index_bool \begin{multicols}{2}\begin{description} }{ \end{description}\end{multicols} - \togglefalse{skdoc@noindex} + \bool_gset_false:N\g__skdoc_no_index_bool } \renewcommand*{\glossaryentryfield}[5]{ \par\vspace{5\p@}\relax @@ -2001,42 +2726,37 @@ % must force a page break between what's before the implementation and % what's after, which might look horrible. % -% Anyway, we define two toggles that keep track of things. One keeps -% track of wether to (not) hide the implementation, and one keeps track -% of wether we are in the implementation or not. These are provided with -% sensible defaults (\emph{i.e.} true and false, respectively). -% We also define a counter in which we save the page number we had when +% We define a counter in which we save the page number we had when % the implementation started. % \begin{macrocode} -\newtoggle{skdoc@impl} -\newtoggle{skdoc@in@impl} -\toggletrue{skdoc@impl} -\togglefalse{skdoc@in@impl} \newcounter{skdoc@impl@page} % \end{macrocode} % Then we define the shipout hook. Fairly straight-forward. % \begin{macrocode} \AtBeginShipout{ - \iftoggle{skdoc@impl}{}{ - \iftoggle{skdoc@in@impl}{\AtBeginShipoutDiscard}{} - } + \__skdoc_if_print_code:F{\AtBeginShipoutDiscard} } % \end{macrocode} % \begin{macro}{\OnlyDescription} % The \cs{OnlyDescription} macro simply toggles the appropriate toggle. % \begin{macrocode} -\DeclareDocumentCommand\OnlyDescription{}{\togglefalse{skdoc@impl}} +\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. +% 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{}{ - \iftoggle{skdoc@impl}{}{ + \bool_if:NF\g__skdoc_with_implementation_bool{ \clearpage - \toggletrue{skdoc@in@impl} + \bool_gset_true:N\g__skdoc_in_implementation_bool \let\skdoc@old@part\part \DeclareDocumentCommand\part{som}{} \let\skdoc@old@section\section @@ -2049,19 +2769,24 @@ \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. +% \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{}{ - \iftoggle{skdoc@impl}{}{ + \bool_if:NF\g__skdoc_with_implementation_bool{ + \cs_if_exist:NTF\refsection{\printbibliography\endrefsection}{} \clearpage - \togglefalse{skdoc@in@impl} + \bool_gset_false:N\g__skdoc_in_implementation_bool \let\part\skdoc@old@part \let\section\skdoc@old@section \let\subsection\skdoc@old@subsection @@ -2348,11 +3073,11 @@ % \begin{macrocode} \let\old@tableofcontents\tableofcontents \DeclareDocumentCommand\tableofcontents{}{ - \toggletrue{skdoc@noindex} + \bool_gset_true:N\g__skdoc_no_index_bool \microtypesetup{protrusion=false} \old@tableofcontents \microtypesetup{protrusion=true} - \togglefalse{skdoc@noindex} + \bool_gset_false:N\g__skdoc_no_index_bool } % \end{macrocode} % \end{macro} @@ -2443,12 +3168,14 @@ \DisableLigatures{family = tt*} % \end{macrocode} % We also want numbers on the bibliography headings, if we are loading -% \pkg{biblatex}. +% \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. @@ -2464,10 +3191,21 @@ %</class> % \fi % \Finale -% -% \iffalse -% \section{Known issues} -% \fi +% \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 |