diff options
author | Karl Berry <karl@freefriends.org> | 2007-05-22 17:49:29 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2007-05-22 17:49:29 +0000 |
commit | b7e7419f2fbc20f964ebd505f4c9d35c4b37d6e7 (patch) | |
tree | 81f166fc88d80a1bc49c16f7de6aff4d4250cdec /Master/texmf-dist/source | |
parent | 51266997b22750d1cef71d44b0785cc31337f0d5 (diff) |
new package xbase, subsuming some others?
git-svn-id: svn://tug.org/texlive/trunk@4337 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source')
-rw-r--r-- | Master/texmf-dist/source/latex/xbase/ldcsetup.dtx | 335 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/xbase/template.dtx | 2446 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/xbase/xbase.ins | 73 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/xbase/xparse.dtx | 2167 |
4 files changed, 5021 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/xbase/ldcsetup.dtx b/Master/texmf-dist/source/latex/xbase/ldcsetup.dtx new file mode 100644 index 00000000000..7ebb1d59830 --- /dev/null +++ b/Master/texmf-dist/source/latex/xbase/ldcsetup.dtx @@ -0,0 +1,335 @@ +% \iffalse +%% File: ldcsetup.dtx (C) Copyright 1999 Frank Mittelbach, Chris Rowley, David Carlisle +%% (C) Copyright 2004-2006 Frank Mittelbach, LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``xbase bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +%<package>\RequirePackage{l3names} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +\GetIdInfo$Id: ldcsetup.dtx 574 2006-08-21 23:30:10Z morten $ + {coding conventions and stuff} +% +% \iffalse +%<*driver> +\documentclass{ltxdoc} +\begin{document} +\DocInput{ldcsetup.dtx} +\end{document} +%</driver> +% \fi +% +% \CheckSum{0} +% +% \title{The \textsf{ldcsetup} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}} +% \author{DPC, FMi} +% \date{\filedate} +% \maketitle +% +% \begin{abstract} +% Basic code shared by several other packages currently under development. +% \end{abstract} +% +% \StopEventually{} +% +% \begin{macrocode} +%<*package> +% \end{macrocode} +% |\CodeStart| is in effect here so we better stop it again. +% \begin{macrocode} +\CodeStop +\RequirePackage{keyval,calc} +\makeatletter +% \end{macrocode} +% +% \section{Ignoring White Space} +% Within a package, or in a document preamble, you can use +% |\IgnoreWhiteSpace| this makes white space ignored, and |@| +% a letter, and |~| a space character. It lasts until the end of the +% current package or preamble. +% +%% Puts an ignored space at the end of the line, so `|\ |' does the right +% thing. (Perhaps should instead just change catcode of |^^M|) +% \begin{macrocode} +\def\IgnoreWhiteSpace{% + \edef\@tempa{% + \catcode`\noexpand\~=\the\catcode`\~\relax + \catcode`\noexpand\ =\the\catcode`\ \relax + \catcode`\noexpand\^^I=\the\catcode`\^^I\relax + \catcode`\noexpand\@=\the\catcode`\@\relax + \endlinechar=\the\endlinechar\relax + }% + \ifx\@currname\@empty + \expandafter\AtBeginDocument\expandafter{\@tempa}% + \else + \expandafter\AtEndOfPackage\expandafter{\@tempa}% + \fi + \catcode`\~=10\relax + \catcode`\ =9\relax + \catcode`\^^I=9\relax + \makeatletter + \endlinechar=` % + \relax +} +% \end{macrocode} +% The new syntax requires |:| and |_| to be letters; instead of +% putting that into |\IgnoreWhiteSpace| we make a new command which +% helps to gradually change packages from old to new syntax. +% \begin{macrocode} +\def\InternalSyntaxOn{% + \edef\@tempa{% + \catcode`\noexpand\~=\the\catcode`\~\relax + \catcode`\noexpand\ =\the\catcode`\ \relax + \catcode`\noexpand\^^I=\the\catcode`\^^I\relax + \catcode`\noexpand\@=\the\catcode`\@\relax + \catcode`\noexpand\:=\the\catcode`\:\relax + \catcode`\noexpand\_=\the\catcode`\_\relax + \endlinechar=\the\endlinechar\relax +%FMi fix is not properly reset + \endlinechar=13\relax + }% +%%% ???? +% this needs further work, don't think it is working + \ifx\InternalSyntaxOff\relax + \expandafter\def\expandafter\InternalSyntaxOff\expandafter + {\@tempa\let\InternalSyntaxOff\relax}% + \fi + \ifx\@currname\@empty + \expandafter\AtBeginDocument\expandafter{\@tempa}% + \else + \expandafter\AtEndOfPackage\expandafter{\@tempa}% + \fi + \catcode`\~=10\relax + \catcode`\ =9\relax + \catcode`\^^I=9\relax + \makeatletter + \catcode`\_=11\relax + \catcode`\:=11\relax + \endlinechar=` % + \relax +} +\let\InternalSyntaxOff\relax +% \end{macrocode} +% +% Do it for this package. +% \begin{macrocode} +\IgnoreWhiteSpace +% \end{macrocode} +% +% \section{KV fixes} +% Allow\footnote{Not needed now?} key names to start with |\|. +% \begin{macrocode} +\def\define@key#1#2{% + \@ifnextchar[ + {\KV@def{#1}{\string#2}} + {\@namedef{KV@#1@\string#2}####1}} +\def\setkeys#1#2{% + \def\KV@prefix{KV@#1@\expandafter\string}% + \KV@do#2,\relax,} +% \end{macrocode} +% +% Make KV |#| safe. +% \begin{macrocode} +% \end{macrocode} +% +% \begin{macrocode} +\newtoks\KV@toks +% \end{macrocode} +% +% \begin{macrocode} +\def\KV@@sp@c#1\@nil#2\relax#3{\KV@toks{#1}\edef#3{\the\KV@toks}} +% \end{macrocode} +% +% Generate error messages on missing `,'. +% +% More exactly if two `=' appear after a key generate an error. +% The current KV just silently ignores everything after the second `='. +% \begin{macrocode} +\def\KV@equal{=} +% \end{macrocode} +% +% \begin{macrocode} +\def\KV@split#1=#2=#3\relax{% + \KV@@sp@def\@tempa{#1}% + \def\@tempd{#3}% + \ifx\@tempa\@empty\else + \expandafter\let\expandafter\@tempc + \csname\KV@prefix\@tempa\endcsname + \ifx\@tempc\relax + \KV@error{\@tempa\space \expandafter\@gobbletwo\string\@undefined}\@eha + \else + \ifx\@tempd\@empty + \KV@default + \else + \KV@@sp@def\@tempb{#2}% + \ifx\@tempd\KV@equal + \expandafter\@tempc\expandafter{\@tempb}\relax + \else + \KV@error{Extra~=~ sign~ after~ `#1'}\KV@erry + \fi + \fi + \fi + \fi} +% \end{macrocode} +% +% \begin{macrocode} +\def\KV@erry{\expandafter\KV@errx\meaning\@tempd\relax ignored\MessageBreak + missing~comma~in~`\expandafter\strip@prefix\meaning\@tempb'~?} +% \end{macrocode} +% +% \begin{macrocode} +\def\KV@errx#1>#2==\relax{% + `#2' } +% \end{macrocode} +% +% \begin{macrocode} +\def\KV@default{% + \expandafter\let\expandafter\@tempb + \csname\KV@prefix\@tempa @default\endcsname + \ifx\@tempb\relax + \KV@error{No value specified for \@tempa}\@eha + \else + \@tempb\relax + \fi} +% \end{macrocode} +% +% \LaTeX\ style error message. +% \begin{macrocode} +\def\KV@error#1#2{\PackageError{keyval}{#1}{#2}} +% \end{macrocode} +% +% Instead of doing a full KV parse, and evaluating all the keys, +% you might want to parse a parameter list, even for undefined keys, +% removing spaces, splitting up the `,` and `=' and resolving cases +% where no value is supplied. This is used in |\DeclareGenericFunction| +% which \emph{defines} a set of keys via such a KV parse. +% +% A setting of |, key = value ,| will result in |\KV@elt{key}{value}| +% being added to the list, a seting of |, key ,| will result in +% |\KV@default@elt{key}| being added. At the end of the parse the list +% is executed. No keys are checked at this stage (so no csnames are used +% up) the two |\KV|\ldots|@elt| commands must be defined as appropriate. +% +% \begin{macrocode} +\def\KV@parse#1{ + \begingroup +% \end{macrocode} +% +% Locally fudge |\KV@@def| to just add to a token register +% rather than make a definition. +% \begin{macrocode} +\def\KV@@sp@c##1\@nil##2\relax##3{\addto@hook##3{{##1}}} +% \end{macrocode} +% +% Locally fudge |\KV@split| to just add to a token register +% rather than execute the code for the found keys. +% \begin{macrocode} +\def\KV@split##1=##2=##3\relax{% + \def\@tempd{##3}% + \expandafter\ifx\expandafter=\@firstofone##1=\else + \ifx\@tempd\@empty + \addto@hook\KV@toks\KV@default@elt + \KV@@sp@def\KV@toks{##1}% + \else + \ifx\@tempd\KV@equal + \addto@hook\KV@toks\KV@elt + \KV@@sp@def\KV@toks{##1}% + \KV@@sp@def\KV@toks{##2}% + \else + \KV@err{Extra `=' after `##1'}\@ehd + \fi + \fi + \fi} +% \end{macrocode} +% +% Initialise +% \begin{macrocode} + \KV@toks{} +% \end{macrocode} +% Do the parse +% \begin{macrocode} + \KV@do#1,\relax, +% \end{macrocode} +% Evaluate the token register outside the group. +% \begin{macrocode} + \expandafter + \endgroup + \the\KV@toks} +% \end{macrocode} +% +% \section{Calc fixes} +% +% Count Register assignments via calc. Here we also provide some +% global versions since a normal global prefix won't have any effect. +% \begin{macrocode} +\let\SetInternalCounter\calc@assign@count +\def\GsetInternalCounter#1{\SetInternalCounter{\global#1}} +\def\gsetlength#1{\setlength{\global#1}} +% \end{macrocode} +% +% +% \section{Misc code that is best collected in one place} +% +% This section will receive odd code that would be of potential use to +% other packages and should eventually made it to the kernel +% (perhaps). +% +% \begin{macro}{\UndeclareRobustCommand} +% Remove a robust command from memory if it isn't used any +% longer. Of course this doesn't free the hash table but at least +% the space gets reclaimed. +% \begin{macrocode} +\def\UndeclareRobustCommand#1{% + \global\let#1\undefined + \global\expandafter + \let\csname\expandafter\@gobble\string#1~\endcsname\undefined +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \Finale +% diff --git a/Master/texmf-dist/source/latex/xbase/template.dtx b/Master/texmf-dist/source/latex/xbase/template.dtx new file mode 100644 index 00000000000..3e6a4050454 --- /dev/null +++ b/Master/texmf-dist/source/latex/xbase/template.dtx @@ -0,0 +1,2446 @@ +% \iffalse +%% File: template.dtx (C) Copyright 1999-2001 David Carlisle, Frank Mittelbach +%% (C) Copyright 2004-2006 Frank Mittelbach, LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``xbase bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +%<package>\RequirePackage{l3names} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +\GetIdInfo$Id: template.dtx 584 2006-12-12 17:29:34Z morten $ + {template} +% \iffalse +% +% +%<*driver> +\documentclass{ltxdoc} +\makeatletter + \newenvironment{decl}[1][]% + {\par\small\addvspace{4.5ex plus 1ex}% + \vskip -\parskip + \ifx\relax#1\relax + \def\@decl@date{}% + \else + \def\@decl@date{\NEWfeature{#1}}% + \fi + \noindent\hspace{-\leftmargini}% + \begin{tabular}{|l|}\hline\ignorespaces}% + {\\\hline\end{tabular}\nobreak\@decl@date\par\nobreak + \vspace{2.3ex}\vskip -\parskip\@afterheading} +\makeatother + + \begin{document} + \catcode`\_=11 + \catcode`\:=11 + \DocInput{template.dtx} + \end{document} +%</driver> +% +% +% \fi +% +% +% \CheckSum{0} +% +% \title{The \textsf{template} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}} +% \author{DPC, FMi} +% \date{\filedate} +% \maketitle +% +% \changes{0.06}{1998/12/17}{generic functions reborn as templates} +% +% \tableofcontents +% +% \section{Introduction} +% A \emph{Template} is a named `function' that has a fixed number +% of \emph{mandatory arguments} and an additional set of \emph{keys} +% or `named attributes' that are set in a `key value list'. That is, +% a comma separated set of assignments of the form:\\ +% \meta{key$_1$} |=| \meta{value$_1$} |,| +% \meta{key$_2$} |=| \meta{value$_2$} \ldots +% +% More specific instances of the template may be declared by +% specifying settings of the parameters. The key value list is parsed +% at the time the instance is declared, and an `internal' set of +% parameter assignments is passed to the template code. It is normally +% not parsed at run-time, though it is possible to enforce this +% behaviour. +% +% Templates have a \emph{type} and a \emph{name}. Templates +% of the same type have the same argument and parameter +% structure. That is, templates of the same type are expected to be +% exchangeable semantically. (However, except for checking that +% templates of the same type always have the same number of arguments +% this is not enforced by the code.) +% +% A template type is declared via the |\DeclareTemplateType| +% declaration which takes two arguments: the name for the type and the +% number of arguments a template of this type requires. +% +% Templates are declared via the |\DeclareTemplate| +% command which takes five arguments +% \begin{itemize} +% \item The \emph{type} of the template (no |\|). +% \item The \emph{name} of the template (no |\|). +% \item The number of arguments for the template (same as on type +% declaration). +% \item A list declaring the keys accepted by the template, +% with information about the action to take when the key is specified +% with a value. +% \item The code for the template. This may be arbitrary \TeX\ +% code. At some point it should execute |\DoParameterAssignments| +% to run the parameter assigments. +% +% The mandatory arguments are accessed via |#1|, |#2|, \ldots +% \end{itemize} +% +% +% Each element of the key specification list is of the form: +% \begin{flushleft} +% \meta{key name} |=| +% \meta{key type} \meta{optional default} \meta{internal code} +% \end{flushleft} +% +% The \meta{key types} are essentially specified by giving a symbolic +% representation of the assignment function to be used by \TeX. +% +% Currently the possibilities are +% +% \begin{center}\catcode`|=12 +% \begin{tabular}{l|ll|l} +% key type& letter& internal code& argument form\\\hline +% Command & f\emph{n}&command name & command definition\\ +% name & n & command name & command definition\\ +% length & l & length register& calc length syntax\\ +% fake length & L & command name & calc length syntax\\ +% count & c & count register& calc count syntax\\ +% fake count & C & command name & calc count syntax\\ +% boolean & b & name of \verb|\newif| switch& true or false\\ +% switch & s & \marg{true code}\marg{false code}& true or false\\ +% instance& i\marg{type}& command name& instance of this \emph{type}\\ +% direct & x & Internal code& any\\ +% general & g & general code & any +% \end{tabular} +% \end{center} +% +% In addition, any of these types may be prefixed by |+| to +% denote a global assignment (described below). +% |f| takes a digit from 0--9 to denote the number of arguments. +% |n| is in fact the same as |f0|. When an instance is declared +% The value assigned to the key should be the definition of +% the command, using |#1|\ldots|#9| to denote the specified arguments. +% +% |c| takes an internal form a count register, +% not a \LaTeX\ counter name. +% +% For |f|, |n|, |l|, and |c|, the assignment is done twice, once +% at the time an instance is \emph{declared}. (This may involve +% using \textsf{calc} expresions. Then the `primitive assignment' +% of the value (not using calc) is copied to the internal parameter +% list, to be executed when an instance is run. Sometimes you need the +% expression to be evaluated at the time an instance is run rather +% than the time it is declared. For example it may be an expression +% involving some values that are not fixed throughout a document. +% In this case the instance declaration may give a value in the +% form |\DelayedEvaluation|\marg{calc expression}. In this case +% the value is not evaluated when the instance is declared, and +% instead the entire expression is copied to the `internal parameter +% list' and is evaluated whenever the instance is used. +% +% |L| and |C| take the same value types as |l| and |c| but the internal +% assignments are to macros not registers. +% +% Keys declared with |b| and |s| each take values either \emph{true} or +% \emph{false}. if the key zzz is declared with |b| then specifying +% |zzz=true| will essentially pass |\zzztrue| to the internal parameter +% list (although in fact |\zzztrue| need not be defined) . If instead +% zzz had been declared via |s|, then |zzz=true| would pass the tokens +% of the \marg{true code} to the internal parameter list. +% +% If a key is specified as |x|, then when used the \emph{internal code} +% will be copied to the internal parameter lists. This code may use |#1| +% to denote the value supplied to the key in the instance declaration. +% Note that this code is \emph{only} copied at the time the instance is +% declared. It is not executed at this time. It is executed when the +% instance is executed.\footnote{Despite the question of whether or +% not x and g are still necessary these days, they have the wrong +% `names' since x is the one that is not executed during delcaration +% while g is.} +% +% If a key is declared with |g| then the code is run at the time the +% instance is declared. By default \emph{nothing} is passed to the +% internal parameter list. This code may use |#1| to denote the +% value that will be supplied when an instance is declared. +% Any code that should be run when an instance is executed should +% be explicitly passed to the internal parameter list using +% |\toks_add_right:Nn\l_TP_KV_assignments_toks{|\ldots|}| +% +% A key declared with |i|\marg{type} takes as value the name of a +% declared instance of that type. The command token associated with +% the key will store a command essentially equivalent to a call +% to |\UseInstance|\marg{type}\marg{name}, but in a slightly optimised +% internal form. +% As an exception to this rule the replacement code may be of the form +% |\UseTemplate| followed by the key settings for the template +% but without the mandatory arguments. In this case the `inner' +% instance declaration is `pre compiled' and the token assigned to +% the store the value assigned to this key will execute an instance +% of the template directly, it will not re-parse the keyword settings +% each time the instance is used. +% +% \section{Commands} +% +% +% \subsection{Template declaration commands} +% +% \begin{decl} +% |\DeclareTemplateType| \marg{type}\marg{num} +% \end{decl} +% Declare a template type. +% +% \begin{decl} +% |\DeclareTemplate| +% \marg{type}\marg{tname}\marg{num}\marg{keyspec}\marg{code} +% \end{decl} +% Declare a template \meta{tname} of type \meta{type} with the set of +% keys as defined by \meta{keyspec}. From this template instances can +% be declared using |\DeclareInstance| At runtime such instances will run +% \meta{code} and expect \meta{num} mandatory arguments (same number +% for all templates of one type).\footnote{The \meta{num} argument is +% redundent as it can be deduced from the type. However, for practical +% reasons it seems better to keep that information with each +% individual template declaration.} +% +% \begin{decl} +% |\DeclareRestrictedTemplate| +% \marg{type}\marg{new-tname}\marg{old-tname}\marg{keyvals} +% \end{decl} +% Declare as new template \meta{new-tname} for type \meta{type} by +% taking template \meta{old-tname} as the basis and setting one or +% more of its keys to specific values. +% +% \begin{decl} +% |\DoParameterAssignments| +% \end{decl} +% The list of key value assignments made (and saved) during template +% declaration is evaluated at this point in the template code. +% +% +% \subsection{Instance declaration commands} +% +% \begin{decl} +% |\DeclareInstance| \marg{type}\marg{iname}\marg{tname}\marg{keyvals} +% \end{decl} +% Declare an instance of type \meta{type} named \meta{iname} build +% from using template \meta{tname} with key settings as given by +% \meta{keyvals}. +% +% \begin{decl} +% |\DeclareCollectionInstance| +% \marg{collection}\marg{type}\marg{iname}\marg{tname}\marg{keyvals} +% \end{decl} +% Same as |\DeclareInstance| except that this instance is only active +% when for the type \meta{type} the collection \meta{collection} was +% selected via |\UseCollection|. E.g., within the frontmatter one +% could make all headings behave differently by defining collection +% instances for template type `head'. +% +% \subsection{Key value commands} +% +% \begin{decl} +% |\DelayEvaluation|\marg{code} +% \end{decl} +% Used in the value spec for an instance to declare that the value +% \meta{code} should not be evaluated at declaration time but at +% run-time. Can also be used in the defaults for keys (given in square +% brackets) in the declaration of templates. +% +% \begin{decl} +% |\MultiSelection| \meta{counter} \marg{cases} \marg{else} +% \end{decl} +% Used in the value spec for an instance key to declare that the value of +% this key depends on the current setting of \meta{counter} at run-time. +% The \meta{cases} argument is a comma-separated list of ``values'', +% the \meta{else} argument a single ``value''. If at run-time +% \meta{counter} has the value $i$ then the $i$-th element of the +% \meta{cases} list is selected. If that does not exist the +% \meta{else} case is returned. +% +% +% \subsection{Processing commands} +% +% \begin{decl} +% |\UseTemplate| \marg{type}\marg{tname}\marg{keyval} +% \end{decl} +% Execute a template \meta{tname} of type \meta{type} at run-time +% using \meta{keyvals} as the value assignments for its keys. In this +% case the keys are evaluated at run-time thus this method is far +% slower than using a predeclared instance of this template (see +% below). This command can also appear as the value for a key of type +% `i' in which case the evaluation happens at declaration time of the +% template that contains this key! +% +% +% \begin{decl} +% |\UseInstance| \marg{type}\marg{iname} +% \end{decl} +% Run the instance \meta{iname} of template type \meta{type}. If a +% collection is in force see if there is a collection instance of name +% \meta{iname} and if so run that instead. +% +% \begin{decl} +% |\UseCollection| \marg{type}\marg{collection} +% \end{decl} +% Declare that from now on (normal scoping rules) the collection +% \meta{collection} for template type \meta{type} is in force. This +% means that a call to |\UseInstance| will first check if there is a +% collection instance defined, and if so use that instance, otherwise +% use the normal instance. +% +% +% \subsection{Test commands} +% +% \begin{decl} +% |\IfExistsInstanceTF| \marg{type}\marg{iname}\marg{true}\marg{false} +% \end{decl} +% Test if for template type \meta{type} an instance with name +% \meta{iname} exists. Select \meta{true} or \meta{false} code +% accordingly. +% +% +% +% \section{Examples of template key types} +% +% The general syntax for key specification in templates (fourth argument +% of the command |\DeclareTemplate|) is: +%\begin{flushleft} +%| {| \\ +%| | \meta{key-name$_1$} |=|\meta{key-type$_1$} +% \meta{optional-default$_1$} \meta{storage-bin$_1$}|,|\\ +%| | \meta{key-name$_2$} |=|\meta{key-type$_2$} +% \meta{optional-default$_2$} \meta{storage-bin$_2$}|,|\\ +%| ...|\\ +%| }| +%\end{flushleft} +% In this section we look at all possible key types and give examples +% for them. +% +% +% \subsection{Attributes that receive names as values} +% +% The type |n| expects to receive a \LaTeX{} name as a value. Used, +% for example, to specify the name of a \LaTeX{} counter to use. +%\begin{verbatim} +% heading-id =n \heading@id, +% counter-id =n [\DelayEvaluation{\heading@id}] \heading@counter, +%\end{verbatim} +% Notice the use of |\DelayEvaluation| in the default of +% |counter-id|. It is necessary to make the default the token +% |\heading@id| if we want to inherit the value from the |heading-id| +% key. Otherwise it gets value of |\heading@id| at the time the +% instance is declared. +% +% +% \subsection{Attributes that receive functions as values} +% +% +% The type |f|\meta{num} expects a function with \meta{num} arguments +% as a value. The arguments are denoted by |#1|, |#2|, etc. In most +% cases either |f0| (for declarations) or |f1| (to format one argument) are +% needed. +%\begin{verbatim} +% initial-font =f0 \initial@font, +% initial-format =f1 [#1] \initial@boxhandling, +%\end{verbatim} +% +% \subsection{Attributes that receive dimensions as values} +% +% As far as specifying instances the |l| and |L| type behave +% identically. They differ only in the type of internal storage-bin +% they need: |l| expects a length register while |L| expects an +% ordinary macro name and assigns its value via |\def:Npn |. +%\begin{verbatim} +% pre-sep =l \topsep, +% post-sep =L \botsep, +%\end{verbatim} +% +% +% +% \subsection{Attributes that receive integers as values} +% +% The |c| and |C| type receive integers as values. Again either of +% them can be transparently used. In case of |c| the +% \meta{storage-bin} has to be a \TeX{} count register not a \LaTeX{} +% counter name, i.e., set up via |\newcount|. (\LaTeX{} counters can +% be used as well if they are accessed via their internal name, i.e., +% via |\c@|\meta{\LaTeX-counter}) +%\begin{verbatim} +% pre-penalty =c \@beginparpenalty, +% penalty =C \hmaterial@penalty, +%\end{verbatim} +% +% +% +% \subsection{Attributes that receive template instances as values} +% +% The type |i|\marg{type} takes as value the name of a declared +% instance of that type. The \meta{storage-bin} associated with the +% key will store a command essentially equivalent to a call to +% |\UseInstance|\marg{type}\marg{name}, but in a slightly optimised +% internal form. +% +% As an exception to this rule the replacement code may be of the form +% |\UseTemplate| followed by the key settings for the template but +% without the mandatory arguments. In this case the `inner' instance +% declaration is `pre compiled' and the token assigned to the store +% the value assigned to this key will execute an instance of the +% template directly, it will not re-parse the keyword settings each +% time the instance is used. +%\begin{verbatim} +% justification-setup =i{justification} \list@justification, +%\end{verbatim} +% +% Usage within an instance declaration is either +%\begin{verbatim} +% justification-setup = raggedright, +%\end{verbatim} +% i.e., name of a declared instance or a call to |\UseTemplate| +%\begin{verbatim} +% justification-setup = \UseTemplate{justification}{TeX} +% { startskip = 0pt, ... }, +%\end{verbatim} +% +% +% +% \subsection{Attributes that receive true or false values} +% +% The type |s| expects the strings |true| or |false| as values. In +% this case the declaration has no \meta{storage-bin}. Instead the +% declaration consists of two brace groups containing code. Depending +% on the value one of the groups gets copied verbatim into the +% internal parameter list of the instance and gets executed at +% run-time at the point where |\DoParameterAssignments| is seen. +%\begin{verbatim} +% item-implicit-boolean =s +% { \def:Npn \item@implicit@code{\item\relax} }{}, +% numbered-boolean =b [true] @heading@nums, +%\end{verbatim} +% +% +% \subsection{Attributes that accept any value} +% +% The type |g| is a low-level specification which contains arbitrary +% code in place of the \meta{storage-bin}. This code is evaluated at +% declaration time of the instance and by default \emph{nothing} is +% passed to the internal parameter list (this has to happen explicitly +% from within the code). |#1| may be used to access the value +% specified. + +% The main purpose for this type is of historical nature (originally +% most of the other types have been implemented internally using |g|). +% +% The type |x| also requires code in place of the \meta{storage-bin}. +% However with this type all of the code is copied unevaluated to the +% internal parameter list. There are some applications for this type +% when implementing customisable defaults. However, it is likely that +% it will not survive a final release. +%\begin{verbatim} +% generic-key =g \typeout{#1}, +% extra-assigns =x \typeout{#1}, +%\end{verbatim} +% +% +% +% +% +% +% \section{A complete example} +% +% The following example shows a sketch of a template for typesetting +% captions to be used as part of a larger mechanism setting whole +% floats.\footnote{I made it up while I went along so if you spot the +% ``missing brace'' or some other blunder tell me, FMi.} +% +% We declare a template type \texttt{caption} then define an example +% template for that type and finally produce some instances from that. +% +% \subsection{Declaring the template type} +% +% To define the template type we first have to ask ourselves what +% information would be varying each time such a template is used? A +% potential answer could be the following: +% \begin{itemize} +% \item +% The float name, e.g., `Table' or `Fig.' etc. +% \item +% The float +% number e.g., `10' or `3--c' etc. +% \item +% The actual caption text as specified in the document. +% \end{itemize} +% Since the above items would be differed in each instantiation of +% such a template we would pass them as mandatory argument to the +% template. +% +% Are there others? Possibly. Here are two more that seem to be +% useful, at least in a number of cases: +% \begin{itemize} +% \item +% The text of the legend in document classes that distinguish +% between caption text (heading to the figure/table) and legend +% (explanatory material) +% \item +% Measure to which the caption should be typeset. +% \end{itemize} +% The last one of these might need some extra explanation. Suppose a +% design requires that the caption width is decided depending on the +% width of the table of figure, e.g., the caption is supposed to +% typeset below some illustration and should not be wider than that +% illustration, or the caption is typeset aside to the illustration +% using the remaining space. In that case the process that formats the +% whole float needs to communicate with the current template to pass +% that (varying) information along. Of course, that could happen by +% using global variables, e.g., the outer process sets the measure as +% desired before calling the caption formatting template. What makes +% more sense is likely to be a matter of taste but it also has to do +% with the precise semantics of the template type. Staying with our +% example: if the the semantics of the template type \texttt{caption} +% is supposed to produce a formatted box (in \TeX{} terms) then we +% should pass the measure as an argument if we ever intend to allow +% for variations. If on the other hand the semantics are to format a +% certain set of text into the current galley (which has measure of +% its own) then a measure argument would not belong to this template +% type. +% +% Are there other variations sensible? Yes, for example, instead of +% passing a fixed string like ``Fig.'' as the first argument one could +% pass an abstract float type identifier and let the template worry to +% deduce from that information what fixed string to produce. +% +% Another question: why should we pass the fixed text (or an abstract +% identifier from which it can be deduced) and the number as separate +% arguments to the template instead of passing a combined string (like +% it is done in the |\@makecaption| command of \LaTeXe{})? Answer: +% because this allows to build templates that can individually +% manipulate both bits of information, e.g., to format the number in a +% different font, etc. +% +% So what are the conclusions of this discussion? Defining the +% semantics of a template type is difficult and often needs several +% trials to come up with something that is covering the anticipated +% use. There is clearly not a cardinal way for defining template +% types; how the overall separation into smaller units is done is +% partly a matter of taste and partly a matter of the major layout +% characteristics that one tries to support. +% +% Returning to our example: let's assume we settle for the first four +% arguments, i.e., the calling template is responsible for setting the +% measure for the caption text if necessary. +% +% What we also have to do is to define (at least for ourselves) what +% data the arguments accept and what their semantics are. An informal +% summary of that could be the following: +% \begin{center} +% \begin{tabular}{rrl} +% \textit{Arg} & \textit{Data Type} & \textit{Description} \\[3pt] +% 1 & text & fixed float description +% \\ +% 2 & text/|\NoValue| & float number +% \\ +% 3 & text & caption text +% \\ +% 4 & text/|\NoValue| & legend text +% \\ +% \end{tabular} +% \end{center} +% The second and the fourth argument are allowed to be missing (i.e., +% can get |\NoValue| passed as a value). Note that the empty string in +% case of a text argument is different from |\NoValue|. +% +% We further declare that it is permissible for a template of this +% type to ignore the information provided by all arguments except 3, +% i.e., the caption text. +% +% Finally the result of the template formatting should is to typeset +% text into a current galley (paragraph mode in \LaTeX{} lingua). +% +% All the above is semantic information that (at least right now) is +% not being enforced by declaring a template type (except for the +% number of arguments) but each template of a certain type is supposed +% to conform to this specification nonetheless.\footnote{To make this +% even clearer we are thinking of extending the template type +% declaration with another argument in which one has to formally or +% informally (?) specifies information like the one in the table +% above.} +% +% This finally leads to the following declaration: +%\begin{verbatim} +%\DeclareTemplateType{caption}{4} +%\end{verbatim} +% +% \subsection{Defining a first template} +% +% We start by defining a simple template of type \texttt{caption} +% which roughly formats a caption like those being presented in +% \LaTeXe{}'s article class, i.e., the caption is typeset as a +% paragraph if it is longer than a single line, otherwise it is +% centered. The legend even if present is ignored. Above and below we +% give the designer the possibility to add some space. +% +% In fact the examples is more or less identical in code to +% |\@makecaption| except that if the second argument (i.e., the +% number) is |\NoValue| it and its preceding space\footnote{For those +% who wonder: spaces are by default ignored within definitions when +% the new packages are used due to a command \texttt{\textbackslash +% InternalSyntaxOn}, do get a normal space one has to use +% \texttt{\textasciitilde} and to obtain an unbreakable space +% \texttt{\textbackslash nobreakspace}.} gets ignored. +% +% We start by declaring the template \texttt{toosimple} of type +% \texttt{caption} having four mandatory arguments (as described in +% the discussion of the template type). +%\begin{verbatim} +%\DeclareTemplate{caption}{toosimple}{4} +%\end{verbatim} +% The next argument of |\DeclareTemplate| lists all keys for the +% template. In this case we have keys for the vertical spaces above +% and below. We make them type |L| to save on registers but with a bit +% of care we could also have used scratch registers like |\@tempskipa| +% etc. Their default values are both zero. +%\begin{verbatim} +% { +% above-skip =L [0pt] \caption@above@skip , +% below-skip =L [0pt] \caption@below@skip , +% } +%\end{verbatim} +% The final argument of |\DeclareTemplate| contains the actual +% processing code. We start with looking at the second mandatory +% argument (caption number) to find out if it is |\NoValue| and +% depending on the result define a helper command |\caption@start|. +%\begin{verbatim} +% { +% \IfNoValueTF{#2} +% { \def:Npn \caption@start{#1:~} } +% { \def:Npn \caption@start{#1~#2:~} } +%\end{verbatim} +% Having dealt with the prelims we now run |\DoParameterAssigments| at +% which point the keys of the template are made available, e.g., at +% this point all those right hand containers such as +% |\caption@above@skip| get assigned the value specified in an +% instantiation of the template. (That scheme allows to do preliminary +% processing up front, e.g., defaults for the keys could be assigned +% prior to that point in which case they are overwritten if the +% template instance specifies a different value. the use of specifying +% defaults via the |[..]| syntax as done above is slightly faster at +% run-time but needs more memory.) +%\begin{verbatim} +% \DoParameterAssigments +%\end{verbatim} +% The rest of the code should look familiar to anybody who ever looked +% at \texttt{article.cls}. The only point worth mentioning are the +% |\relax| commands after |\caption@above@skip| and +% |\caption@below@skip|. Since we have decided to use |L| as key type +% these commands are macros and not registers containing the +% dimensions as strings. This means that we have to be careful to +% ensure that \TeX{} knows where the dimension ends. In certain cases +% text following such a command might be mistaken as being part of the +% dimension (e.g., if followed by the word \texttt{plus}, etc.). In +% the code below this could only happen for the second |\vskip| but it +% is good practice to always add a terminating |\relax| to avoid such +% hidden traps. +%\begin{verbatim} +% \vskip \caption@above@skip \relax +% \sbox \@tempboxa {\caption@start #3} +% \ifdim \wd\@tempboxa >\hsize +% \caption@start #3\par +% \else +% \global \@minipagefalse +% \hb@xt@\hsize{\hfil\box\@tempboxa\hfil} +% \fi +% \vskip \caption@below@skip \relax +% } +%\end{verbatim} +% +% Why is the above template of not much use? Simply because it doesn't +% offer any flexibility to declare different designs. The only +% alteration offered to the designer is to modify the space above and +% below the caption, e.g., the following declaration would mimic the +% definition within the \texttt{article.cls} class of \LaTeXe : +%\begin{verbatim} +%\DeclareInstance{caption}{article}{toosimple} +% { +% above-skip = 0pt, +% below-skip = 10pt, +% } +%\end{verbatim} +% And that's all that can be manipulated. All items that people asking +% to change, e.g., not having a colon after the number, using +% different fonts and font sizes, etc.\ are still hard-wired and thus +% inaccessible. So we have to do better if we want to make use of the +% power the template mechanism offers. +% +% +% +% \subsection{Defining a better template} +% +% First step in defining better templates is to ask ourselves a couple +% of questions: +% \begin{itemize} +% \item What are the main characteristics of the layout the template +% is supposed to support? +% \item What are the elements that we want to allow (or can allow) the +% designer to modify? +% \end{itemize} +% +% Take the first question first: the layout supported by the template +% of the previous section had as its main characteristics that it +% would center the caption if it would fit in a single line in the +% current measure. We could consider this being an unchangable +% characteristic of the layout this template produces (and a designer +% would need to use a different template of type \texttt{caption} if a +% design compatible with this restriction is desired) or we could try +% to make our template smarter by adding bells and wistles that allow +% the designer to say stuff like: +%\begin{verbatim} +% one-line-format = \hfil #1 \hfil, +%\end{verbatim} +% or +%\begin{verbatim} +% one-line-action = center, +%\end{verbatim} +% depending on how we intend to offer changing the behavior of the +% template. Like when trying to define sensible template types we have +% no single road to heaven (and probably as many to hell) --- it has a +% lot to do with how we think about design. +% +% My advice, after having tried to work with these concepts for a +% while, is to keep templates simple in so far as that most of not all +% attribute for a template should be relevant for the design. In other +% words, if you have attributes that, depending on their setting, make +% half of the other attributes not applicable then it may be +% appropriate to think about providing several templates instead. To +% give an example from \LaTeXe : instead of having |\@startsection| +% deal with both vertical heads and run-in heads provide individual +% templates. (|\@startsection| is this famous command where design +% switches are build in by making dimensions negative to signal +% something and afterwards use the absolute value.) +% Another way to look at this is to say that a template should +% normally not contain large amounts of code which is only selected in +% a subset of attribute settings. +% +% As said before there are no golden rules, it is perfectly possible +% to make hugely complicated templates that solve every possible +% aspect of layout one could think of in one go --- it is just that +% with keeping it more simple one can get the same functionality with +% less headaches for the template writer as well as the template user +% later on. +% +% Returning to our example: allowing to handle the case of a single +% line caption specially could well be considered part of the +% template. In contrast: layouts that would put the caption number +% sideways, i.e., which would need totally different internal coding +% should probably be coded as a separate template of type +% \texttt{caption}. +% +% So for our next example template we settle for the fixed caption +% text plus number (if any) being at the beginning of the variable +% caption text (coming from the document) and being together formatted +% as some sort of a pargraph. In case of the whole caption being a +% single line we allow the designer to specify how to lay it out +% (e.g., centered, flush left, etc.). If there is a legend it will get +% formatted by a vertical space followed by the legend formatted as +% another paragraph. +% +% More precisely we allow for the following bells and wistles: +%\begin{verbatim} +%\DeclareTemplate{caption}{lesssimple}{4} +% { +%\end{verbatim} +% The designer can specify the space above and below the caption like +% we did in our first example. +%\begin{verbatim} +% above-skip =L [0pt] \caption@above@skip , +% below-skip =L [0pt] \caption@below@skip , +%\end{verbatim} +% Regarding the caption number we support the case where no number is +% present (the value being |\NoValue|) as well as the number being +% present. For both cases the designer has to specify what formatting +% should be attached. By default all is being typeset in the font the +% whole caption is presented but if there is a need for it the +% designer can use the following keys to attach special formatting +% devices to each particular item beside specifying special spacing +% information or replacing the default colon after the number with +% something else. +%\begin{verbatim} +% number-format =f2 [#1~#2:~] \caption@number@format, +% nonumber-format =f1 [#1:~] \caption@nonumber@format, +%\end{verbatim} +% If the caption is fitting onto a single line we make it possible +% for the designer to specify how this single line should be +% positioned (the default is to center the line). +%\begin{verbatim} +% single-line-format =f1 [\hfil#1\hfil] \caption@single@line@format, +%\end{verbatim} +% The font for the caption (including the fixed text and the number +% unless specified differently above) is going to be the one decided +% by the next key. +%\begin{verbatim} +% caption-font =f0 [\normalfont] \caption@font, +%\end{verbatim} +% The next attribute deserves some extra explanation: here we make use +% of an interface which is explained in more detail when we reveil the +% support for galley formatting.\footnote{Guess I have to apologize +% for the fact that i partly make use of that interface in this +% example while on other occasions (like the use of vertical spacing) +% within the example I do not---consistency around midnight is not my +% strength I fear (FMi).} In a nutshell the template type \texttt{hj} +% (hyphenation \& justification) allows one to define a) the +% justification concepts applied to the upcoming paragraphs, e.g., +% whether they should be set flush left, adjusted, first line +% centered, etc.\ b) the linebreaking strategy used and c) the +% hyphenation rules which should apply. All this is done by selecting +% an appropriate (predefined) instance of this type as will hopefully +% become somewhat clearer in the example instances shown below. +%\begin{verbatim} +% caption-hj-setup =i {hj} [default] \caption@hj@instance, +%\end{verbatim} +% In case there is a legend to format we give the designer the +% possibility to specify by how much vertical space it should be +% separated from the preceding paragraph (i.e., the caption text). The +% attributes for font and hj setup are comparable to those for the +% caption text itself (except that they will only apply to the +% legend). The only addition is the key \texttt{legend-text} which is +% allowed to take a fixed text (plus any formating and spacing for it) +% which will be added to the front of the legend in case it is +% provided at all (by default it is empty). +%\begin{verbatim} +% legend-sep =L [0pt] \caption@legend@sep , +% legend-text =f0 [] \caption@legend@text, +% legend-font =f0 [\normalfont] \caption@legend@font, +% legend-hj-setup =i {hj} [default] \caption@legend@hj@instance, +% } +%\end{verbatim} +% The actual code for the template should hold few if any +% surprises. In fact it is more or less identical to the one of the +% first template example, except that now we have now taken out some +% of the hardwired decisions and placed them into attributes. +%\begin{verbatim} +% { +% \IfNoValueTF{#2} +% { \def:Npn \caption@start{\caption@number@format{#1}{#2}} } +% { \def:Npn \caption@start{\caption@nonumber@format{#1}} } +% \DoParameterAssigments +% \vskip \caption@above@skip \relax +%\end{verbatim} +% To properly measure the caption to determine if it fits a single +% line we have to set it in the right font, so here as well as below +% we have to apply |\caption@font|. +%\begin{verbatim} +% \sbox \@tempboxa {\caption@font \caption@start #3} +% \ifdim \wd\@tempboxa >\hsize +% \begingroup +% \caption@font \caption@hj@instance +% \caption@start #3\par +% \endgroup +% \else +% \global \@minipagefalse +% \hb@xt@\hsize{\caption@single@line@format{\box\@tempboxa}} +% \fi +%\end{verbatim} +% To decide whether or not we have to set any legend we have to test +% |#4| for being |\NoValue|. This part of the code was not present in +% the previous example but otherwise should be straight forward. +%\begin{verbatim} +% \IfNoValueF{#4} +% { +% \vskip \caption@legend@sep \relax +% \begingroup +% \caption@legend@font \caption@legend@hj@instance +% \caption@legend@text +% #4\par +% \endgroup +% } +% \vskip \caption@below@skip \relax +% } +%\end{verbatim} +% +% I wouldn't claim the the above template is good or contains +% everything that would be desired and I'm sure that in the end we +% will have several such template for typesetting the caption part and +% perhaps decide on a different template type in the first place. So +% this is only to give a glimpse of how the template interface could +% be applied and I hope that reading it can see a) how they can apply +% it to other areas as well as see what is wrong with the example +% itself. +% +% To just note one point that i thought of being wrong after writing +% the above paragraphs: the key \texttt{single-line-format} was +% declared to be a function with one argument with the idea that +% besides specifying the single line should be centered (|\hfil|) on +% both sides, or flush left, or flush right (|\hfil| on one side) one +% could also specify something like +%\begin{verbatim} +% single-line-format = \hspace{10pt}#1\hfil, +%\end{verbatim} +% that is a fixed indentation on the left in case where the caption is +% a single line. However, of course one can't. Or at least it is not +% safe to do so since our test in the code tests the width of the line +% without taking into account such a finite fixed space and guess what +% might happen? So in summary, flexibility needs some thought and +% often some afterthoughts as well --- happy thinking :-) +% +% +% +% \subsection{Defining a few instances} +% +% So let us conclude this example with a few sample instances. We +% start with one that repeats what current \LaTeXe{} provides in the +% article class. It shows all keys with values. However in fact only +% the first key is actually needed since all others are the same as +% the default values in the template (and of course a legend is not +% specifiable in standard \LaTeX{} coding so those settings simply do +% not apply anyway). +%\begin{verbatim} +%\DeclareInstance{caption}{article}{lesssimple} +% { +% above-skip = 10pt, +% below-skip = 0pt, +% number-format = #1~#2:~, +% nonumber-format = #1:~, +% single-line-format = \hfil#1\hfil, +% caption-font = \normalfont, +% caption-hj-setup = default, +% legend-sep = 0pt, +% legend-text = , +% legend-font = \normalfont, +% legend-hj-setup = default, +% } +%\end{verbatim} +% +% The next examples are taken from books on the shelf essentially a +% random selection I fear. This one is from \emph{Introduction to +% Database Design} by C.~J.~Date and it uses Helvetica for the caption +% text with the caption flush left, with the figure and the fixed +% string (e.g., `Fig.' in bold face) separated by a quad of space. No +% legend either so this is not set up. The \texttt{hj} instance +% \texttt{noindentflushleft} is supposed to produce a ragged right paragraph +% without any indentation. It would have to be set up elsewhere +% (instance to the template of type \texttt{hj}). +%\begin{verbatim} +%\DeclareInstance{caption}{DATE}{lesssimple} +% { +% above-skip = 10pt, +% below-skip = 0pt, +% number-format = \textbf{#1~#2}\quad, +% nonumber-format = \textbf{#1}\quad, +% single-line-format = #1\hfil, +% caption-font = \fontfamily{phv} \normalfont, +% caption-hj-setup = noindentflushleft, +% } +%\end{verbatim} +% +% The final example is from the book ``Methods of Book Design'' by +% H.~Williamson which sets the caption centered if it fits a single +% line but adjusted as a paragraph without any indentation if longer +% than a single line. It uses old style numerals followed by a period +% for the number (though the example isn't quite right as i guess the +% text font used already has oldstyle numerals as default, so +% |\oldstylenums| is in fact not necessary). +%\begin{verbatim} +%\DeclareInstance{caption}{WILLIAMSON}{lesssimple} +% { +% above-skip = 10pt, +% below-skip = 0pt, +% number-format = #1~\oldstylenums{#2}.~, +% nonumber-format = #1~, +% single-line-format = \hfil#1\hfil, +% caption-font = \normalfont, +% caption-hj-setup = noindentadjusted, +% } +%\end{verbatim} +% +% +% +% \section{Notes} +% +% \subsection{Note on multi-valued parameters} +% +% +% The following code\footnote{docu taken from trial implementation in +% xlists.dtx, FMi} implements for registers (ie L,l,C,c keys) and +% for names (ie n key) a multi-selection mechanism of the following +% form: +% \begin{verbatim} +% key = \MultiSelection \ListDepth { +% \DelayEvaluation {2.5em}, +% 20pt + 34pt } +% { \DelayEvaluation {1em} }, +% \end{verbatim} +% where the first argument to |\MultiSelection| is a counter, the +% second argument is a comma separated list of values denoting the +% values for the cases 1, 2,\ldots, and the third argument contains +% the value for all other cases. +% +% The values are evaluated at declaration time in case of registers +% and therefore can contain calc expressions as well as +% |\DelayEvaluation|. +% +% Due to the implementation the case list is not allowed to have a +% trailing comma! And of course no checks are made whatsoever :-( +% +% A probably much nicer syntax would be something like this: +% \begin{verbatim} +% key = \MultiSelection { +% selector = \ListDepth, +% 1 = \DelayEvaluation {2.5em}, +% 2 = 20pt + 34pt, +% else = \DelayEvaluation {1em} +% }, +% \end{verbatim} +% but i found that too difficult to implement right now. +% +% I think it should also be considered if this kind of thing should be +% a generally available feature on all key types especially on the +% f\meta{number} ones. +% +% Anyway it is what i need for lists right now and as such it is +% sufficient. +% +% +% \subsection{Notes on template restriction} +% +% Possible semantics: +% +% a: just:-) changes the defaults ie the new template has as +% defaults those of its source as modified by the supplied +% keyvals; +% +% b: similar to a: but also removes some keywords ie the new template +% will not accept the keywods whose values are set by the suppied +% keyvals; +% +% c: plan C. +% +% +% Towards an implementation of b: but without a restriction on what +% keys appear where. +% +% +% +% +% \subsection{Open issues} +% +% In this section unresolved issues or ideas to think about and +% perhaps implement are collected. There is no particular order to +% them. +% +% \begin{itemize} +% \item The order of arguments in |\UseCollection| is illogical in my +% eyes! A collection typically modifies the behavior of several +% types and thus should perhaps be first (as it is in the +% |\DeclareCollectionInstance| case). Or not, or what? +% +% \item How should |\IfExistsInstanceTF| behave for Collection +% instances? Do we need a special check for those or a default +% action? Or do we need an additional test for the existence of +% collection instances? +% +% \item It was suggested that the template type declaration should get +% another argument in which (in?)formally the semantics for the +% template types are described, e.g., data type of arguments, +% resulting output, \ldots{} (somewhat like the description arguments +% for functions and variables in Emacs-Lisp). The advantage being +% that this helps employing the templates better as well as perhaps +% guiding context sensitive editors to support the work with such +% templates (e.g., providing help texts). +% +% \item The same might be of interest for the keys of individual +% templates though here syntax support is already available to some +% extend by the declaration of key types. +% +% \item There might be a need to distinguish between \TeX's dimen and +% skip registers. Right now this is not done and both |l| and |L| +% accepts what \LaTeX{} calls ``rubber length'' specifications. +% +% \item The type |b| can probably vanish. It is equivalent to +% specifying the mutators of a |\newif| command in the brace groups, +% e.g. +%\begin{verbatim} +% numbered-boolean =b [true] @heading@nums, +% numbered-boolean =s [true] {\@heading@numstrue} +% {\@heading@numsfalse}, +%\end{verbatim} +% +% \item See issue raised about syntax (and semantics) for +% |\Multiselection|. +% +% \item |f0| keys should perhaps support |\UseTemplate| by replacing +% it with its internal form. or perhaps this is a rubbish idea? +% +% \item Marcin Wolinski suggested to use |\EvalOnUse| instead or in +% addition to |\DelayEvalutation|. +% +% \end{itemize} +% +% \StopEventually{} +% +% \section{Implementation} +% \begin{macrocode} +%<*package> +% \end{macrocode} +% +% \begin{macrocode} +\RequirePackage{ldcsetup,xparse} +\RequirePackage{l3toks,l3tlp,l3skip,l3int,l3clist,l3token} +% \end{macrocode} +% +% Ignore white space in this package. +% \begin{macrocode} +\CodeStart +% \end{macrocode} +% +% Declare a private token register for building parameter lists. +% Having the number saves a few expandafters +% (probably not needed in the end). +% \begin{macrocode} +\toks_new:N\l_TP_KV_assignments_toks +\toks_new:N\l_TP_default_assignments_toks +% \end{macrocode} +% +% +% +% \begin{macro}{\TP_declare_instance:Nnn} +% \begin{macro}{\TP_declare_instance:cnn} +% Declare a command name to be an instance of a template +% ie with a particular setting of the parameters.\\ +% |#1| internal command name for instance to be (globally) declared\\ +% |#2| template type/template name\\ +% |#3| key value assignments for parameters of |#2| +% \begin{macrocode} +\def_new:NNn \TP_declare_instance:Nnn 3{ + \group_begin: + \TP_instdecl_generate_assignments:nn {#2}{#3} + \gdef:Npx #1 { + \tlp_if_eq:cNTF { TP>/#2 } \c_TP_doparameterassignments_tlp +% \end{macrocode} +% If the body of the template consists only of the token +% |\DoParameterAssignments|, then we insert the list of parameter +% assignments directly. Otherwise we have push them onto the stack +% and prepare to execute the body code (which in turn will pop them +% again when it reaches |\DoParameterAssignments| inside). +% \begin{macrocode} + { \toks_use:N \l_TP_KV_assignments_toks } + { + \exp_not:N \TP_push_assignments:n + {\toks_use:N\l_TP_KV_assignments_toks} + \exp_not:c {TP>/#2} + } + } + \group_end:} +\def_new:Npn \TP_declare_instance:cnn{\exp_args:Nc\TP_declare_instance:Nnn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\c_TP_doparameterassignments_tlp} +% \begin{macrocode} +\tlp_set:Nn \c_TP_doparameterassignments_tlp {\DoParameterAssignments} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\UseTemplate} +% |{type}{templatename}{keyval}| +% Directly use a template with a particular parameter setting. +% This is also picked up if used in a nested fashion inside a parameter +% list.\\ +% |#1| type of a template.\\ +% |#2| name of a template.\\ +% |#3| key value assignments for parameters of |#1|. +% \begin{macrocode} +\def_new:NNn \UseTemplate 3{ + \TP_instdecl_generate_assignments:nn {#1/#2}{#3} + \TP_push_assignments: + \cs_use:c { TP>/#1/#2 } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\DoParameterAssignments} +% Access the parameter assignment list that was once stored in +% |\l_TP_KV_assignments_toks| and then moved onto the +% |\g_TP_assignments_stack_toks|. +% \begin{macrocode} +\def_new:Npn \DoParameterAssignments{ + \exp_after:NN + \TP_pop_and_execute_assignments:nw + \toks_use:N \g_TP_assignments_stack_toks \q_stop +} +% \end{macrocode} +% +% \end{macro} +% +% \begin{macro}{\TP_pop_and_execute_assignments:nw} +% \begin{macrocode} +\def_new:Npn \TP_pop_and_execute_assignments:nw#1#2\q_stop{ + \toks_gset:Nn \g_TP_assignments_stack_toks {#2} + #1} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\g_TP_assignments_stack_toks} +% \begin{macrocode} +\toks_new:N \g_TP_assignments_stack_toks +\toks_gset:Nn \g_TP_assignments_stack_toks {\scan_stop:}% avoid brace loss +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_push_assignments:n} +% Store a list of parameter assignments given as an argument +% in |\l_TP_KV_assignments_toks| and +% then push it +% onto the |\g_TP_assignments_stack_toks|. (My assumption is that +% the somewhat strange +% way to do this is in fact neccesary to preserve the |#| marks +% which would otherwise need doubling --- check). +% \begin{macrocode} +\def_new:Npn \TP_push_assignments:n{ + \tex_afterassignment:D \TP_push_assignments: + \l_TP_KV_assignments_toks} +% \end{macrocode} +% +% \end{macro} +% +% \begin{macro}{\TP_push_assignments:} +% Pushes the parameter assignment list stored in +% |\l_TV_KV_assignments_toks| onto the stack +% |\g_TP_assignments_stack_toks|. +% \begin{macrocode} +\def_new:Npn \TP_push_assignments:{ + \toks_gset:No \g_TP_assignments_stack_toks + {\exp_after:NN +% \end{macrocode} +% this misuses the fact that |\toks_use:N| is really |\the| so expands +% a little strangely (fix). +% \begin{macrocode} + {\toks_use:N\exp_after:NN\l_TP_KV_assignments_toks\exp_after:NN} + \toks_use:N\g_TP_assignments_stack_toks}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\DeclareTemplateType} +% |{type}{nofarg}| +% \begin{macrocode} +\def_new:NNn \DeclareTemplateType 2{ + \tlp_set:cn {TP@<#1>} {{}#2}} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\TP_get_csname_prefix:n} +% |{type}| returns prefix for csnames for template type, +% based on current collection. +% \begin{macrocode} +\def_new:Npn \TP_get_csname_prefix:n#1{ + <\exp_after:NN\exp_after:NN\exp_after:NN + \use_arg_i:nn + \cs:w TP@<#1>\cs_end:>#1/ +} +% \end{macrocode} +% +% \end{macro} +% +% \begin{macro}{\TP_get_arg_count:n} +% |{type}| returns arg count for the template type. +% \begin{macrocode} +\def_new:Npn \TP_get_arg_count:n#1{ + \exp_after:NN\exp_after:NN\exp_after:NN + \use_arg_ii:nn + \cs:w TP@<#1>\cs_end: +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\DeclareTemplate} +% |{type}{templatename}{nofarg}{keywordspec}{code}| +% \begin{macrocode} +\def_long_new:NNn\DeclareTemplate 5{ + \cs_if_free:cTF{TP@<#1>} + {\undefinedtype\DeclareTemplateType{#1}#3} + { + \int_compare:nNnF{#3}={\TP_get_arg_count:n{#1}} + { \BadArgCount } + } +% \end{macrocode} +% Parse the key declaration, and execute the list with a suitable +% definition of |\KV@elt|. +% \begin{macrocode} + \let:NN \KV_elt:nn \TP_templdecl_process_KV:nn + \def:Npn \KV_default_elt:n##1{ + \PackageError{template}{Missing~ =~ after~ ##1}\@ehd} + \let:NN\KV@elt\KV_elt:nn + \let:NN\KV@default@elt\KV_default_elt:n + \tlp_set:Nn \l_TP_curr_name_tlp {#1/#2} + \toks_clear:N\l_TP_default_assignments_toks +% \end{macrocode} +% At this point there should be a test for which catcode regime we are +% in. We just test if spaces are ignored. +% \begin{macrocode} + %\int_compare:nNnTF{\char_value_catcode:n{`\ }}=\c_nine + %\KV_parse_picky_no_space_removal_no_sanitize:n + %\KV_parse_picky_space_removal_no_sanitize:n + \KV@parse{#4} +% \end{macrocode} +% +% Define the defaults: the setting for |TPD>/\l_TP_curr_name_tlp| is a +% tricky since |\l_TP_default_assignments_toks| may contain |#|. We +% have to use an |x| expansion rather than +% |o| since that will hide those during the assignment. +% \begin{macrocode} + \tlp_set:cx { TPD>/\l_TP_curr_name_tlp } + {\toks_use:N\l_TP_default_assignments_toks} + + \tlp_clear:c {TPR>/\l_TP_curr_name_tlp} + + \tlp_set_eq:cN {TPO>/\l_TP_curr_name_tlp}\l_TP_curr_name_tlp +% \end{macrocode} +% +% Define the template (using |\def_new:Npn| means that one can't +% redefine a template easily). +% \begin{macrocode} + \def:cNn {TP>/\l_TP_curr_name_tlp}{#3}{#5} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_templdecl_process_KV:nn} +% The list of undefined keys and values is put in the list of the form\\ +% |\KV_elt:nn|\marg{key1}\marg{val1}%^^A +% |\KV_elt:nn|\marg{key2}\marg{val2}\ldots\\ +% So just need to give this macro a suitable definition. We just need +% to look at the first token of the value, to see what sort of key +% it is, so call a helper function to split that off. +% \begin{macrocode} +\def_new:Npn \TP_templdecl_process_KV:nn#1#2{% + \let:NN \TP_templdecl_add_global_or_nothing: \use_noop: + \bool_set_false:N\l_TP_global_assignment_bool + \tlp_set:Nn\l_TP_currkey_tlp{#1} + \TP_templdecl_parse_KV:N#2\q_stop} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_templdecl_parse_KV:N} +% Case switch on the possible key types. +% \begin{macrocode} +\def_new:Npn \TP_templdecl_parse_KV:N#1{ +% \end{macrocode} +% In |#1| we have key, in |#2| the first character after the equal +% sign and in |#3| the remainder of the line. We now have to parse +% that remainder to find out if it contains a default value (in +% brackets) and then set up the key declaration needed to parse +% instance declarations. The method is similar in most cases: we call +% |\TP_parse_optional_key_default:nw| which parses for the default +% and pass it already found key name as first argument, what to do in +% the end as second argument, and the remainder delimited by |\q_stop| +% so that it becomes parseable. +% +% Note that the code in the second argument to +% |\TP_parse_optional_key_default:nw| normally calls on a macro with +% one more argument than actually provided: the reason being that the +% missing argument will be the remainder of the line (added by +% |\TP_parse_optional_key_default:nw| after the default has be +% removed (if present)). +% \begin{macrocode} + \cs_if_free:cTF{TP_use_arg_type_#1:w} + {\PackageError{template}{Unknown~key~type~ (#1)~for~\l_TP_currkey_tlp}\@eha} + {\cs_use:c{TP_use_arg_type_#1:w}} +% \end{macrocode} +% The |f| and |i| keys are somewhat different since there we first +% have to parse for an additional argument (a digit in case of |f| +% or an template type name in case of |i|): +% \begin{macrocode} +% \end{macrocode} +% One more alternative: a |+| after the equal sign signals global +% so we change |\TP_templdecl_add_global_or_nothing:| to append a +% |\pref_global:D| to the assignment toks and then reparse the rest. +% \begin{macrocode} +% \def:Npn \TP_templdecl_add_global_or_nothing: +% {\toks_put_right:Nn \l_TP_KV_assignments_toks {\pref_global:D} } +% \TP_templdecl_parse_KV:nw{#1}#3\TP_templdecl_parse_KV:nnw +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\l_TP_global_assignment_bool} +% For keeping track of the assignments. +% \begin{macrocode} +\bool_new:N \l_TP_global_assignment_bool +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_use_arg_type_+:w} +% The |+| does two things: Sets a boolean true to be used by the +% types that can't simply be prefixed with |\pref_global:D| and +% defines |\TP_templdecl_add_global_or_nothing:| to put the prefix +% onto the list. After that we simply call the big switch +% again.\footnote{It should probably all be changed to not rely on +% the prefix working}. +% \begin{macrocode} +\def_new:cpn{TP_use_arg_type_+:w} { + \bool_set_true:N\l_TP_global_assignment_bool + \def:Npn \TP_templdecl_add_global_or_nothing: + {\toks_put_right:Nn \l_TP_KV_assignments_toks {\pref_global:D} } + \TP_templdecl_parse_KV:N +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_use_arg_type_l:w} +% The |l| sets a length register. We disable the prefix and insert +% either |\gsetlength| or |\setlength| depending on whether a |+| +% was seen or not. +% \begin{macrocode} +\def_new:Npn\TP_use_arg_type_l:w { + \TP_parse_optional_key_default:nw + { + \let:NN \TP_templdecl_add_global_or_nothing: \use_noop: + \bool_if:NTF \l_TP_global_assignment_bool + {\TP_templdecl_setup_register_key:Nn\gsetlength} + {\TP_templdecl_setup_register_key:Nn\setlength} + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_use_arg_type_L:w} +% The |L| sets a fake length register. +% \begin{macrocode} +\def_new:Npn\TP_use_arg_type_L:w { + \TP_parse_optional_key_default:nw + {\TP_templdecl_setup_fakeregister_key:NNn\setlength\l_tmpa_skip} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_use_arg_type_c:w} +% The |c| sets a count register. +% \begin{macrocode} +\def_new:Npn\TP_use_arg_type_c:w { + \TP_parse_optional_key_default:nw + { + \let:NN\TP_templdecl_add_global_or_nothing:\use_noop: + \bool_if:NTF \l_TP_global_assignment_bool + {\TP_templdecl_setup_register_key:Nn\GSetInternalCounter} + {\TP_templdecl_setup_register_key:Nn\SetInternalCounter} + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_use_arg_type_C:w} +% The |C| sets a fake count register. +% \begin{macrocode} +\def_new:Npn\TP_use_arg_type_C:w { + \TP_parse_optional_key_default:nw + {\TP_templdecl_setup_fakeregister_key:NNn + \SetInternalCounter\l_tmpa_int} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_use_arg_type_n:w} +% The |n| sets a token list pointer. +% \begin{macrocode} +\def_new:Npn\TP_use_arg_type_n:w { + \TP_parse_optional_key_default:nw + {\TP_templdecl_setup_n_key:N} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_use_arg_type_f:w} +% \begin{macro}{\TP_templdecl_parse_f_arg:nw} +% The |f| defines a command with between 0 and 9 arguments. +% \begin{macrocode} +\def_new:Npn\TP_use_arg_type_f:w #1{ + %\TP_templdecl_parse_f_arg:nw {#1} + \TP_parse_optional_key_default:nw{\TP_templdecl_setup_f_key:Nn{#1}} +} +% \end{macrocode} +% Helper for |\TP_templdecl_parse_KV:nnw|. +% \begin{macrocode} +\def_new:Npn \TP_templdecl_parse_f_arg:nw#1#2{ +% \end{macrocode} +% The third argument of |\TP_templdecl_setup_f_key:Nn|, i.e., the +% macro name, is the remaining data up to |\q_stop| which is picked up +% by |\TP_parse_optional_key_default:nw|. +% \begin{macrocode} + \TP_parse_optional_key_default:nw{\TP_templdecl_setup_f_key:Nn{#1}{#2}} +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\TP_use_arg_type_b:w} +% \begin{macro}{\TP_templdecl_setup_b_key:nn} +% The |b| uses access to the |\if_true:| and |\if_false:| +% primitives. Needed? +% \begin{macrocode} +\def_new:Npn\TP_use_arg_type_b:w { + \TP_parse_optional_key_default:nw + {\TP_templdecl_setup_b_key:n} +} +% \end{macrocode} +% +% \begin{macrocode} +\def_new:Npn \TP_templdecl_setup_b_key:n#1{ + \let:cN { if#1 } \if_true: + \TP_templdecl_define_key:n + { \TP_templdecl_eval_b_key_value:nn {#1}{##1} } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\TP_templdecl_eval_b_key_value:nn} +% Modify so the boolean does not need to have been +% declared with |\newif| +% \begin{macrocode} +\def_new:Npn \TP_templdecl_eval_b_key_value:nn#1#2{ + \cs_if_free:cTF {if#2} + { \PackageError{template}{Bad~boolean~setting~#1=#2}\@eha } + { \tlp_set_eq:cc {if_#1:}{if_#2:} + \toks_put_right:Nf \l_TP_KV_assignments_toks + { \tlp_set_eq:cc {if_#1:}{if_#2:} } + } +} +% \end{macrocode} +% +% \end{macro} +% +% \begin{macro}{\TP_use_arg_type_s:w} +% \begin{macro}{\TP_templdecl_setup_s_key:n} +% The |s| chooses between true and false. +% \begin{macrocode} +\def_new:Npn\TP_use_arg_type_s:w { + \TP_parse_optional_key_default:nw + {\TP_templdecl_setup_s_key:n} +} +% \end{macrocode} +% \begin{macrocode} +\def_new:Npn \TP_templdecl_setup_s_key:n #1 { + \TP_templdecl_define_key:n + { \TP_templdecl_eval_s_key_value:nnn{##1}#1 } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% +% +% +% +% +% \begin{macro}{\TP_use_arg_type_i:w} +% The |i| expects an instance. +% \begin{macrocode} +\def_new:Npn\TP_use_arg_type_i:w #1{ + \TP_parse_optional_key_default:nw{\TP_templdecl_setup_i_key:nnn{#1}} +} +% \end{macrocode} +% +% declaration |hd =i{head} \fooo| \\ +% use |hd = mine|\\ +% makes |\fooo| shorthand for |\UseInstance{head}{mine}| +% +% also allowed: |hd = \UseTemplate{head}{...}{...}|\\ +% in case you want to use an unnamed instance of type |head| +% in this place. +% \end{macro} +% +% \begin{macro}{\TP_templdecl_setup_i_key:nnn} +% MH change: do either local or global. +% \begin{macrocode} +\def_new:Npn \TP_templdecl_setup_i_key:nnn#1#2{ + \TP_templdecl_define_key:n + { + \TP_templdecl_eval_i_key_value:Nnn #2 {#1}{##1} + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_templdecl_eval_i_key_value:Nnn} +% MH change: Add extra argument for local or global. +% \begin{macrocode} +\def_new:Npn \TP_templdecl_eval_i_key_value:Nnn #1#2#3 { + \tlist_if_head_eq_meaning:nNTF {#3.}\UseTemplate + { + \io_put_term:x{\token_to_string:N\UseTemplate\space seen} +% \end{macrocode} +% +% Code below from |\TP_templdecl_setup_f_key:Nn| (should be +% combined and cleaned up) +% at this point one should also check if first arg of |\UseTemplate| +% corresponds to |#2| and if not complain (not done) +% +% \begin{macrocode} + {\TP_templdecl_declare_tmp_instance:nnnn #3 } + \toks_put_right:No \l_TP_KV_assignments_toks + { \exp_after:NN \KV@toks \exp_after:NN {\g_tmpa_tlp} } + %\TP_templdecl_add_global_or_nothing: + %\toks_put_right:Nn \l_TP_KV_assignments_toks + % { \def:Npx #1{ \toks_use:N \KV@toks} } + \bool_if:NTF \l_TP_global_assignment_bool + {\toks_put_right:Nn \l_TP_KV_assignments_toks + {\gdef:Npx #1 { \toks_use:N \KV@toks}} + } + {\toks_put_right:Nn \l_TP_KV_assignments_toks + {\def:Npx #1 { \toks_use:N \KV@toks}} + } + } + { + \TP_let_instance:Nnn#1{#2}{#3} +% \end{macrocode} +% We want the |\let:Nc| hiding in |\TP_let_instance:Nnn| to expand +% fully to two csnames so we put a |\tex_romannumeral:D 0| (which in +% itself expands to nothing) in front. This expands the |\let:Nc| fully +% before finding out that |\let:NwN| is not expandable. +% \begin{macrocode} + \toks_put_right:Nf \l_TP_KV_assignments_toks + { \TP_let_instance:Nnn#1{#2}{#3} } + } +} +% \end{macrocode} +% \end{macro} +% +% +% +% +% +% +% +% +% \begin{macro}{\TP_use_arg_type_x:w} +% \begin{macro}{\TP_templdecl_setup_x_key:nn} +% The |x| runs internal code. +% \begin{macrocode} +\def_new:Npn\TP_use_arg_type_x:w { + \TP_parse_optional_key_default:nw + {\TP_templdecl_setup_x_key:n} +} +% \end{macrocode} +% +% \begin{macrocode} +\def_new:Npn \TP_templdecl_setup_x_key:n#1{ + \TP_templdecl_define_key:n + { \toks_put_right:Nn\l_TP_KV_assignments_toks{#1} } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% +% +% +% \begin{macro}{\TP_use_arg_type_g:w} +% \begin{macro}{\TP_templdecl_setup_g_key:nn} +% The |g| runs any code. +% \begin{macrocode} +\def_new:Npn\TP_use_arg_type_g:w { + \TP_parse_optional_key_default:nw + {\TP_templdecl_setup_g_key:n} +} +% \end{macrocode} +% +% \begin{macrocode} +\def_new:Npn \TP_templdecl_setup_g_key:n #1 { + \TP_templdecl_define_key:n{#1}} +% \end{macrocode} +% +% \end{macro} +% \end{macro} +% +% +% +% +% \begin{macro}{\TP_templdecl_define_key:n} +% Here we define the key in the current template. +% \begin{macrocode} +\def_new:Npn \TP_templdecl_define_key:n#1{ + \tlp_set:Nx \l_tmpa_tlp { + \exp_not:N \TP_templdecl_remove_from_default_assignments:N + \exp_not:c{KV@\l_TP_curr_name_tlp @\l_TP_currkey_tlp} + \exp_not:o {\TP_templdecl_add_global_or_nothing: } + } + \exp_args:NcNo \def:NNn {KV@\l_TP_curr_name_tlp @\l_TP_currkey_tlp} 1 + { \l_tmpa_tlp #1 } +} +% \end{macrocode} +% \end{macro} +% +% +% +% +% +% +% +% +% +% +% \begin{macro}{\TP_parse_optional_key_default:nw} +% Look for default value. The |t| argument type here is one we +% define for template so we can change it easily. Currently I just +% set it to be a regular optional argument in brackets. |#1| is what +% we are carrying over, |#2| the optional argument. +% \begin{macrocode} +\def_long:Npn \TP_ignore_leading_space_in_arg_ii:nn#1#2{ + \exp_args:Nf\TP_ignore_leading_space_in_arg_ii_aux:nn + {\exp_not:N #2}{#1} +} +\def_long:Npn \TP_ignore_leading_space_in_arg_ii_aux:nn#1#2{#2{#1}} + + +\DeclareArgumentType t[{meaning}{}{\NoValue}{#1[#2]}{#2} +\DeclareDocumentCommand\TP_parse_optional_key_default:nw{mt}{ + \IfNoValueTF{#2} + {\TP_templdecl_finish_key_setup:nw{#1}} + {\TP_templdecl_finish_key_setup_with_default:nnw{#1}{#2}} +} +%\show\TP_parse_optional_key_default:nw +%\exp_args:Nc\show{\string\TP_parse_optional_key_default:nw} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_templdecl_finish_key_setup:nw} +% After having parsed the line and not found any default value it +% remains to actually define the key for the instance parsing by +% executing the setup code (in |#1|) giving it |#2| (i.e., the +% remainder of the line) as an argument. +% \begin{macrocode} +\def_new:Npn \TP_templdecl_finish_key_setup:nw#1#2\q_stop{ + \TP_ignore_leading_space_in_arg_ii:nn{#1}{#2} + %%%#1{#2} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_templdecl_finish_key_setup_with_default:nnw} +% If there is a default the situation is more complicated since we +% not only have to set up the key for the instance but also have to +% add the default value to |\l_TP_default_assignments_toks| in an +% appropriate way. +% +% First set up the the key itself: +% \begin{macrocode} +\def_new:Npn \TP_templdecl_finish_key_setup_with_default:nnw#1#2#3\q_stop{ + \TP_ignore_leading_space_in_arg_ii:nn{#1}{#3} + %%% #1 {#3} +% \end{macrocode} +% Now we run the new key code (which is stored in |\KV@...| hopefully) +% and give it the default found. By doing this in a group and by +% locally emptying |\l_TP_KV_assignments_toks| we will get the +% resulting assignment code into that register. +% +% (We set |\TP_templdecl_remove_from_default_assignments:N| to +% |\use_none:n| since this is a temporary operation and we don't want +% to change the default really.) +% \begin{macrocode} + \group_begin: + \toks_clear:N \l_TP_KV_assignments_toks + \let:NN \TP_templdecl_remove_from_default_assignments:N \use_none:n + \cs_use:c{KV@\l_TP_curr_name_tlp @\l_TP_currkey_tlp}{#2} +% \end{macrocode} +% And now for a final trick: before closing the group again and losing +% our local changes we run |\exp_after:NN| several times to get the +% value of |\l_TP_KV_assignments_toks| into +% |\l_TP_default_assignments_toks| outside that group! +% \begin{macrocode} + \exp_after:NN + \group_end: + \exp_after:NN + \toks_set:Nn + \exp_after:NN + \l_TP_default_assignments_toks + \exp_after:NN + { \cs:w KV@\l_TP_curr_name_tlp @\l_TP_currkey_tlp \exp_after:NN \cs_end: + \exp_after:NN + { \toks_use:N \exp_after:NN \l_TP_KV_assignments_toks + \exp_after:NN + } + \toks_use:N\l_TP_default_assignments_toks + } +} +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\c_TP_true_tlp} +% \begin{macrocode} +\tlp_new:Nn \c_TP_true_tlp {true} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_templdecl_eval_s_key_value:nnn} +% \begin{macrocode} +\def_new:Npn \TP_templdecl_eval_s_key_value:nnn#1#2#3 { +% no error check on this yet. + \tlp_set:Nn \l_tmpa_tlp {#1} + \tlp_if_eq:NNTF \l_tmpa_tlp \c_TP_true_tlp + { \toks_put_right:Nn \l_TP_KV_assignments_toks {#2} } + { \toks_put_right:Nn \l_TP_KV_assignments_toks {#3} } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_templdecl_setup_register_key:Nnn} +% This is normally called automatically by |\DeclareTemplate|. +% +% Command for setting a template attribute whose name +% corresponds directly to a \TeX{} count or length register\\ +% |#1| the function to set the value eg \setlength.\\ +% |#2| key name.\\ +% |#3| the register to set. +% +% This command \emph{fully evaluates} the argument at declare time, +% and assigns the value to the register. It also passes an assignment +% of the register to the final value into the parameter list for the +% template. +% +% If the value is a call to |\DelayEvaluation|, don't evaluate it now, +% just pass the whole assignment to the template. Remember to remove +% the |\DelayEvaluation|. +% \begin{macrocode} +\def_new:Npn \TP_templdecl_setup_register_key:Nn #1#2{ + \TP_templdecl_define_key:n{ + \tlist_if_head_eq_meaning:nNTF{##1}\DelayEvaluation + { +% \end{macrocode} +% Old line commented out. Remove |\DelayEvaluation| and also remove +% the braces surrounding its argument. +% \begin{macrocode} + \toks_put_right:Nn \l_TP_KV_assignments_toks {#1#2{##1}} + %\toks_set:No\l_tmpa_toks{\use_arg_ii:nn ##1} + %\toks_put_right:Nx \l_TP_KV_assignments_toks + % {\exp_not:n{#1#2}{\toks_use:N \l_tmpa_toks}} + } +% \end{macrocode} +% +% +% check for |\MultiSelection| creeping up and if so add something like +% +% \begin{verbatim} +% \setlength\register{\ifcase\selector \or value1 \or value2 +% ... \else valueotherwise \fi} +% \end{verbatim} +% to |\l_TP_KV_assignments_toks|. +% +% \begin{macrocode} + { + \tlist_if_head_eq_meaning:nNTF{##1..}\MultiSelection + { + \group_begin: + \TP_multiselection_add:nnnnnn #1#2##1 + \group_end: +% \end{macrocode} +% +% +% there are probably better ways to do this (:-) +% +% \begin{macrocode} + \tlist_if_in:onTF{\toks_use:N\g_TP_multiselection_toks}\DelayEvaluation + { + \toks_put_right:No\l_TP_KV_assignments_toks + { + \exp_after:NN#1\exp_after:NN#2\exp_after:NN + {\toks_use:N\g_TP_multiselection_toks} + } + } + { + \toks_put_right:No\l_TP_KV_assignments_toks + { + \exp_after:NN #2 + \exp_after:NN= \toks_use:N\g_TP_multiselection_toks\scan_stop: + } + } +% \end{macrocode} +% +% +% otherwise do as before +% +% \begin{macrocode} + } + { + #1#2{##1} + \toks_put_right:No\l_TP_KV_assignments_toks { + \exp_after:NN #2 \exp_after:NN = \tex_the:D #2\scan_stop: + } + } + } + } +} +% \end{macrocode} +% \end{macro} +% +% +% +% +% +% +% \begin{macro}{\DelayEvaluation} +% \begin{macro}{\MultiSelection} +% Since we are testing explicitly for |\DelayEvaluation| and +% |\MultiSelection| a few places we better give them unique +% meanings! +% \begin{macrocode} +\def_new:NNn\DelayEvaluation 1{\use_none:n{\DelayEvaluation}#1} +\def_new:NNn\MultiSelection 1{\use_none:n{\MultiSelection}#1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\TP_templdecl_remove_from_default_assignments:N} +% Note: the toks register is more or less a plists and should +% perhaps be implemented as such as this would make far more +% readable code. +% \begin{macrocode} +\def_new:Npn \TP_templdecl_remove_from_default_assignments:N#1{ + \def:Npn \tmp:w ##1#1##2##3#1##4\q_stop{ + \l_TP_default_assignments_toks{##1##3} + } + \exp_after:NN \tmp:w + \toks_use:N\l_TP_default_assignments_toks #1\scan_stop:#1\q_stop} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_templdecl_setup_f_key:Nn} +% Same for macro names. Again usually called automatically when +% declaring a new template.\\ +% |#1| Determines how many arguments the function should have.\\ +% |#2| The macro to be defined. +% +% If the `|##1|`, the value passed as the argument of the key +% to the macro |#2| is invoked starts with |\FunctionInstance|, then a +% special procedure is taken. Instead of defining a macro with the +% specified number of arguments, the paramater list of the nested +% function instance is parsed, and |#2| is defined to be a macro +% expanding to that instance. In this case the specified template +% is responsible for picking up the requested number of +% arguments. (This is \emph{not} checked.) +% \begin{macrocode} +\def_new:Npn \TP_templdecl_setup_f_key:Nn#1#2{ +% \end{macrocode} +% +% |##1| can either be arbitrary inline code, in which case it will be +% defined with something similar to |\newcommand[val]| so it needs to +% use |#1| -- |#val|. +% +% define it locally here (why this, David???) +% \begin{macrocode} + \TP_templdecl_define_key:n + { \TP_templdecl_define_function:NNn#1#2{##1} } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\TP_templdecl_define_function:NNn} +% |\def:Npn | setup with a latex style `number of arguments' argument. +% \begin{macrocode} +\def_new:Npn \TP_templdecl_define_function:NNn#1#2#3{ + \def:NNn #2 #1 {#3} + \toks_put_right:Nf \l_TP_KV_assignments_toks { \def:NNn #2 #1 {#3} } +} +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\TP_templdecl_setup_n_key:N} +% Here is the extended version that tries to deal with +% |\MultiSelection|. +% +% In case of `n' keys there is no evaluation at declaration time so it +% is not sensible to look for |\DelayEvaluation|. For this reason as +% well as for the fact that |\TP_multiselection_add:nnnnnn| above +% assumes that it deals +% with registers that can be accessed via |\toks_use:N| we have to use a +% different command to handle the |\MultiSelection| args but +% it is essentially doing the same. +% +% \begin{macrocode} +\def_new:Npn \TP_templdecl_setup_n_key:N#1{ + \TP_templdecl_define_key:n{ + \tlist_if_head_eq_meaning:nNTF{##1..}\MultiSelection + { + \group_begin: + \TP_templdecl_multiselection:nnnn ##1 + \group_end: + \toks_put_right:Nx\l_TP_KV_assignments_toks { + \exp_not:n{\tlp_set:No #1} { \toks_use:N \g_TP_multiselection_toks} + } + } + { + \def:Npn #1{##1} % setting it? + \toks_put_right:Nn \l_TP_KV_assignments_toks + { \tlp_set:Nn #1{##1} } + } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_templdecl_multiselection:nnnn} +% Start the |\if_case:w| +% \begin{macrocode} +\def_new:Npn \TP_templdecl_multiselection:nnnn #1#2#3#4{ + \toks_gset:Nn \g_TP_multiselection_toks {\if_case:w #2} + \clist_map_inline:nn {#3}{ \TP_multiselection_add_or_case:n {##1} } + \toks_gput_right:Nn\g_TP_multiselection_toks { \else: #4\fi: } +} +% \end{macrocode} +% \end{macro} +% +% +% +% +% +% +% +% +% \begin{macro}{\DeclareInstance} +% |{type}{instname}{templatename}{keyval}| +% \begin{macrocode} +\def_new:Npn \DeclareInstance { \DeclareCollectionInstance{} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\DeclareCollectionInstance} +% |{collection}{type}{instname}{templatename}{keyval}| +% The fifth argument is picked up implicitly. +% \begin{macrocode} +\def_long_new:Npn \DeclareCollectionInstance#1#2#3#4{ + \TP_declare_instance:cnn { <#1>#2/#3 }{ #2/#4 } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\UseCollection} +% |{type}{collection}| +% \begin{macrocode} +\def_new:Npn \UseCollection#1#2{ + \tlp_set:cx { TP@<#1> } + { {#2} \TP_get_arg_count:n{#1} } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_let_instance:Nnn} +% |\internalcommand{type}{instname}| +% +% The way this macro is used, it must result in |\let:NwN| |<csname1>| +% |<csname2>| after exactly two expansions as it is used this way +% in |\TP_templdecl_eval_i_key_value:nnn|! +% \begin{macrocode} +\def_new:Npn \TP_let_instance:Nnn#1#2#3{ + \let:Nc #1 + { + \cs_if_free:cTF { \TP_get_csname_prefix:n{#2} #3 } + { <>#2/ } + { \TP_get_csname_prefix:n{#2} } + #3 + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\UseInstance} +% |{type}{instname}| +% \begin{macrocode} +\def_new:Npn \UseInstance#1#2{ + \TP_let_instance:Nnn \l_tmpa_tlp {#1}{#2} + \tlp_if_eq:NNTF \l_tmpa_tlp \scan_stop: + \INSTANCEundefined + \l_tmpa_tlp +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_templdecl_declare_tmp_instance:nnnn} +% This macro is called when we have seen a |\UseTemplate| +% declaration as part of an |i| key value. Therefore the +% first argument will be dropped (it contains the token +% |\UseTemplate|) the second and third will be combined to refer to +% the template and the fourth argument will be implictly picked up +% by |\TP_declare_instance:Nnn|. +% \begin{macrocode} +\def_long_new:Npn \TP_templdecl_declare_tmp_instance:nnnn#1#2#3{% + \TP_declare_instance:Nnn \g_tmpa_tlp {#2/#3} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ShowTemplate} +% Some extension to |\ShowTemplate| so that we also get to see the +% restrictions if any +% \begin{macrocode} +\def_new:Npn \ShowTemplate#1#2{ + \io_put_term:x{*******~ Template:~ #1/#2~ *******} + \io_put_term:x{*} + \io_put_term:x{*~ Defaults:} + \io_put_term:x{*} + \io_put_term:x{\token_to_string:N\TPD>/#1/#2= + \cs_meaning:c{TPD>/#1/#2}} + \io_put_term:x{*} + \io_put_term:x{*~ Restrictions:} + \io_put_term:x{*} + \io_put_term:x{\token_to_string:N\TPR>/#1/#2= + \cs_meaning:c{TPR>/#1/#2}} + \io_put_term:x{*} + \io_put_term:x{*~ Body:} + \io_put_term:x{*} + \cs_show:c {TP>/#1/#2}} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\ShowCollectionInstance} +% \begin{macrocode} +\def_new:Npn \ShowCollectionInstance#1#2#3{ + \io_put_term:x{*******~ Instance:~ <#1>#2/#3~ *******} + \io_put_term:x{*} + \cs_show:c {<#1>#2/#3}} +\def_new:Npn \ShowInstance{\ShowCollectionInstance{}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_templdecl_setup_fakeregister_key:NNn} +% |{setcomand}{privateregister}{key}{internalcode}| +% \begin{macrocode} +\def_new:Npn \TP_templdecl_setup_fakeregister_key:NNn#1#2#3{ + \TP_templdecl_define_key:n{ + \tlist_if_head_eq_meaning:nNTF{##1..}\DelayEvaluation + { +% \end{macrocode} +% In the v0.08 version of \texttt{template.dtx} a +% |\DelayEvaluation| for a faked register would simply be equiv to +% a |\def:Npn | (code is below commented out). The negative side effect +% of this is that something like |=L| used with |\DelayEvaluation| +% would not allow for calc syntax since it would end up as +% |\def:Npn |\allowbreak|\foo|\allowbreak|{a+b}|. The code below changes +% this to first assign to a scratch register (at runtime) and then +% do an |\edef|. Could be coded differently to save space (at cost +% of time) +% \begin{macrocode} +% \toks_put_right:Nn \l_TP_KV_assignments_toks {\def:Npn #3{##1}} +% \toks_put_right:Nn \l_TP_KV_assignments_toks +% {#1#2{##1}\def:Npx #3{\toks_use:N#2}} + \toks_set:No \l_tmpa_toks {\use_arg_ii:nn ##1} + \toks_put_right:Nx \l_TP_KV_assignments_toks { + {\exp_not:n{#1#2}{\toks_use:N \l_tmpa_toks} + \exp_not:n{ \def:Npx #3{\toks_use:N#2} } + } + } + } +% \end{macrocode} +% +% +% Otherwise same game for fake registers except that instead of +% passing the register to |\TP_multiselection_add:nnnnnn| we pass a +% temp fake one and +% doing a def instead of using |\setlength| or |\setcounter| +% +% and i haven't done the |\DelayEvaluation| bit for that case! as +% i'm not sure what the best approach is for those +% things\footnote{we might disallow it for that case in general --- +% not a nice rule but an explainable one} +% +% \begin{macrocode} + { + \tlist_if_head_eq_meaning:nNTF{##1..}\MultiSelection + { + \group_begin: + \TP_multiselection_add:nnnnnn#1#2##1 + \group_end: + \toks_put_right:Nx\l_TP_KV_assignments_toks + {\exp_not:n{\def:Npn #3} {\toks_use:N\g_TP_multiselection_toks}} + } + { + #1#2{##1} + \toks_put_right:Nx\l_TP_KV_assignments_toks + {\exp_not:n{\def:Npn#3} {\toks_use:N#2}} + } + } + } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\g_TP_multiselection_toks} +% \begin{macrocode} +\toks_new:N \g_TP_multiselection_toks +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\TP_multiselection_add:nnnnnn} +% \marg{operation} \marg{register} |\MultiSelection| +% \marg{selector} \marg{case-list} \marg{else-case} +% +% This command builds up the |\if_case:w| code from the three arguments +% of |\MultiSelection| and stores it in +% |\g_TP_multiselection_toks|. This code is supposed to be run in +% a group so a) we don't have to initialise +% |\g_TP_multiselection_toks| and b) all changes to the used +% registers not affecting the outside. +% +% \begin{macrocode} +\def_new:Npn \TP_multiselection_add:nnnnnn #1#2#3#4#5#6{ + \toks_gset:Nn \g_TP_multiselection_toks {\if_case:w #4} + \clist_map_inline:nn {#5}{ + \tlist_if_head_eq_meaning:nNTF{##1..}\DelayEvaluation + { + \TP_multiselection_add_or_case:n {##1} + } + { + #1#2{##1} + \TP_multiselection_add_or_case:n { \toks_use:N #2 } + } + } + \toks_gput_right:Nn \g_TP_multiselection_toks { \else: #6\fi: } +} +% \end{macrocode} +% +% \end{macro} +% +% \begin{macro}{\TP_multiselection_add_or_case:o} +% Since we intend to add |\or:| to |\g_TP_multiselection_toks| +% within the |\_for| loop we have to hide it carefully or else we +% will get some unmatched conditionals. +% +% Actually the |:o| is a slight lie here since the expanion happens +% when we add things to the toks register inside. +% \begin{macrocode} +\def_new:Npn \TP_multiselection_add_or_case:n #1 { + \toks_gput_right:Nn \g_TP_multiselection_toks { \or: #1 } +} +\def_new:Npn \TP_multiselection_add_or_case:o { + \exp_args:NNo \TP_multiselection_add_or_case:n +} +% \end{macrocode} +% \end{macro} +% +% Since i like to set things like |item-label-text| using this +% mechanism i need to handle the `n' key specially. +% +% Actually i could have probably extended +% |\TP_templdecl_setup_f_key:nnN| thus making +% this generally available to all f\meta{number} keys but was too lazy +% (or too stupid) to get it right first time so settled for the simple +% solution. +% +% So |\TP_templdecl_parse_KV:nnw| now calls +% |\TP_templdecl_setup_n_key:nN| for the `n' key. looks like +% this thus be fixed some time soon +% +% +% +% +% +% +% +% \begin{macro}{\IfExistsInstanceTF} +% tests that there is a \emph{default} definition +% taken from xinitials.dtx: +% \begin{macrocode} +\def_new:Npn \IfExistsInstanceTF#1#2{ + \cs_if_exist:cTF{<>#1/#2} +} +% \end{macrocode} +% +% FMi: what happens if we are in collection FOO and there exists an +% instance I for type T within this collection but there doesn't exist +% an instance in the empty collection? +% +% What would happen if \ldots\ --- not clear to me what the sematics +% really should be. The code below is not better only different( and +% slower).\footnote{fix semantics} +% \begin{macrocode} +\def:Npn \IfExistsInstanceTF#1#2{ + \TP_let_instance:Nnn \l_tmpa_tlp {#1}{#2} +% next is not \tlp_if_eq:NNTF but ...FT so done manually + \if_meaning:NN\l_tmpa_tlp\scan_stop: + \exp_after:NN\use_arg_ii:nn + \else: + \exp_after:NN\use_arg_i:nn + \fi:} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\DeclareRestrictedTemplate} +% Setting it up: +% +%| \DeclareRestrictedTemplate|\\ +% |{T-type} {new-T-name} {source-T-name} {keyvals}| +% +% This uses the same code as {T-type} {source-T-name} but adds +% settings from {keyvals} +% \begin{macrocode} +\def_new:Npn \DeclareRestrictedTemplate#1#2#3#4{ + % CCC do we need a group here?? + \tlp_set_eq:cc { TPD>/#1/#2 } { TPD>/#1/#3 } + \tlp_set_eq:cc { TP>/#1/#2 } { TP>/#1/#3 } + + \toks_set:Nd \l_TP_KV_assignments_toks + {\cs:w TPR>/#1/#3\cs_end:} + +% adds stuff to \l_TP_KV_assignments_toks + \setkeys {\cs:w TPO>/#1/#3\cs_end:}{#4} + + \tlp_set:co { TPR>/#1/#2 } + { \toks_use:N \l_TP_KV_assignments_toks } + \cs_if_free:cTF { TPO>/#1/#3 } + { \tlp_set:cn {TPO>/#1/#2}{#1/#3} } + { \tlp_set_eq:cc {TPO>/#1/#2}{TPO>/#1/#3} } +} +% \end{macrocode} +% \end{macro} +% +% +% Internals: +% +% \begin{macro}{\TP_instdecl_generate_assignments:nn} +% These could probably be inlined, even when they do something! +% +% Assumption: setkeys fully expands its first argument. +% +% \begin{macrocode} +\def_new:Npn \TP_instdecl_generate_assignments:nn#1#2 { + % Returns to \l_TP_KV_assignments_toks + % the restrictions + % stored in the TP-structure (at present + % in YAM) of the template #1 + + \toks_set:Nd \l_TP_default_assignments_toks + {\cs:w TPD>/#1\cs_end:\scan_stop:\scan_stop:} + + \toks_set:Nd \l_TP_KV_assignments_toks + {\cs:w TPR>/#1\cs_end:} + + \setkeys { \cs:w TPO>/#1 \cs_end: } + { #2 } % adds stuff to \l_TP_KV_assignments_toks + +% prepends stuff to \l_TP_KV_assignments_toks : + \exp_after:NN\TP_instdecl_add_default_recurse:nn + \toks_use:N\l_TP_default_assignments_toks + +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\TP_instdecl_add_default_recurse:nn} +% [ 2001/06/10 Think about doing this properly with explicit plists! --- but +% this means that one has to think about whether or not plists should be +% implemented as token registers and not as tlps as they are now. ] +% \begin{macrocode} +\def_new:Npn \TP_instdecl_add_default_recurse:nn#1#2{ + \token_if_eq_meaning:NNF #1\scan_stop: + { + \l_tmpa_toks{#2} + \tlp_set:Nx \l_tmpa_tlp { + {\toks_use:N \l_tmpa_toks \toks_use:N \l_TP_KV_assignments_toks} + } + \l_TP_KV_assignments_toks \l_tmpa_tlp + \TP_instdecl_add_default_recurse:nn + } +} +% \end{macrocode} +% \end{macro} +% +% +% +% |TPD>/type/name| stores the default parameter assignments. +% +% |TPR>/type/name| stores the parameter assignments that have been +% made for a restricted template otherwise it is undefined (or |\scan_stop:|). +% +% +% |TPO>/type/name| stores the full name (i.e. as |type/name|) +% of the template a restricted +% template is coming from originally. +% +% +% +% +% \begin{macro}{\TP_split_finite_skip_value:nnNN} +% This macro is for use in error checking template values like +% "text-float-sep" that can't contain infinite glue and needs the +% shrink and/or stretch components. First argument is the skip +% register (which is likely to be user input), second is a template +% key name, and the last two are the \meta{dimen} registers that +% stores the stretch and shrink components. Assignments are global. +% \begin{macrocode} +\def_new:Npn \TP_split_finite_skip_value:nnNN #1#2{ + \skip_split_finite_else_action:nnNN {#1} { + \PackageError{template}{Value~ for~ key~ #2~ contains~ `fil(ll)'} + {Only~ finite~ minus~ or~ plus~ parts~ are~ allowed~ for~ this~ key.} + } +} +% \end{macrocode} +% \end{macro} +% +% +% +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \Finale +% diff --git a/Master/texmf-dist/source/latex/xbase/xbase.ins b/Master/texmf-dist/source/latex/xbase/xbase.ins new file mode 100644 index 00000000000..742a1aa8dc3 --- /dev/null +++ b/Master/texmf-dist/source/latex/xbase/xbase.ins @@ -0,0 +1,73 @@ +% \iffalse +%% +%% This file will generate fast loadable files and documentation +%% driver files from the dtx files in this package when run through +%% LaTeX or TeX. +%% +%% (C) Copyright 2000-2005 LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3a of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``xbase bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +%% $Id: xbase.ins 302 2005-03-01 22:49:14Z morten $ +%% +% \fi +% + +\input docstrip +\keepsilent +\askforoverwritefalse + +\preamble + +(C) Copyright The LaTeX3 Project and any individual authors +listed elsewhere in this file. + +This is a generated file. + +This file was generated from file(s) of the xbase bundle. +--------------------------------------------------------- + +This file may only be distributed together with a copy of this bundle. +You may however distribute the bundle without such generated files. + +====================================================================== + +\endpreamble + + +\generate{% + \file{ldcsetup.sty}{\from{ldcsetup.dtx}{package}} + \file{template.sty}{\from{template.dtx}{package,trace}} + \file{xparse.sty}{\from{xparse.dtx}{package}} +} + +\endbatchfile diff --git a/Master/texmf-dist/source/latex/xbase/xparse.dtx b/Master/texmf-dist/source/latex/xbase/xparse.dtx new file mode 100644 index 00000000000..90346556975 --- /dev/null +++ b/Master/texmf-dist/source/latex/xbase/xparse.dtx @@ -0,0 +1,2167 @@ +% \iffalse +%% File: xparse.dtx (C) Copyright 1999 Frank Mittelbach, Chris Rowley, David Carlisle +%% (C) Copyright 2004-2006 Frank Mittelbach, LaTeX3 Project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``xbase bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%% +%<package>\RequirePackage{l3names} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +\GetIdInfo$Id: xparse.dtx 574 2006-08-21 23:30:10Z morten $ + {generic document command parser} +% \iffalse +%<*driver> + \documentclass{ltxdoc} + \usepackage[T1]{fontenc} + \usepackage{textcomp} + \makeatletter + \providecommand*\eTeX{% + \if b\expandafter\@car\f@series\@nil\boldmath\fi + $\m@th\varepsilon$-\TeX} + \makeatother +% \usepackage{ldcdoc} + \begin{document} + \catcode`\_=11 + \catcode`\:=11 + \DocInput{xparse.dtx} + \end{document} +%</driver> +% \fi +% +% \CheckSum{621} +% +% +% \title{The \textsf{xparse} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}} +% \author{FMi, CAR, DPC, MH} +% \date{\copyright~\filedate} +% \maketitle +% +% \begin{abstract} +% The interfaces described in this document are not meant to be final +% but only as a basis for discussion. Building productive applications +% using the current code is discouraged. +% \end{abstract} +% +% \section{Interface} +% +% This package implements high-level interface commands for class file +% writers which allows the separation of formatting commands +% (typically instances of so-called `templates') and their arguments +% from the signature of document-level commands. +% +% This works by declaration commands that provide a general +% specification method for the typical \LaTeX{} syntax, e.g., +% star-form, optional arguments, and mandatory arguments. A command +% (or environment) declared in this way parses the input according to +% its spec and presents its findings in a normalized way for further +% processing. +% +% \subsection{Argument spec} +% +% +% An argument specification is a list of letters each representing a +% type of argument, i.e., |m| is a mandatory argument (surrounded by +% braces), |o| an optional argument (surrounded by brackets if +% present), and |s| represents a star (which might be present or not). +% Thus the argument spec for headings as implemented by +% |\@startsection| in standard \LaTeX{} would be represented by the +% three letters |som|. Other argument types are available and can be +% added at will. For a complete list of built-in argument types see +% the next section. +% +% There is one important argument specifier worth taking note of. The +% |P| does not behave as a normal argument specifier but allows the +% next argument to take an argument containing the |\par| token which +% is not allowed by default. +% +% +% \subsection{Parsing results} +% +% To normalise the result of parsing the input according to an +% argument specification it is important to uniquely identify all +% arguments found. For this reason each parsing operation initiated by +% one of the argument spec letters will result in an identifiable +% output as follows: +% \begin{description} +% \item[m] will return the parsed argument surrounded by a brace +% pair, i.e., will normally be the identity; +% \item[o] will return the parsed argument surrounded by a brace pair +% if present. Otherwise it will return the token |\NoValue|; +% \item[O\{default\}] will return the parsed argument surrounded by a +% brace pair if present. Otherwise it will return the |{default}| +% as specified above. +% \item[S\{\meta{symbol}\}] will return either the token |\c_true| or +% |\c_false| depending on whether or not the next token is +% \meta{symbol}. +% \item[s] will return either the token |\c_true| or |\c_false| +% depending on whether or not a star was parsed. This is just a +% shorthand for |S{*}|. +% \item[c] will parse the syntax |(|\meta{x}|,|\meta{y}|)|, i.e., a +% coordinate pair and will return |{{|\meta{x}|}{|\meta{y}|}}| as +% the result. If no open parentheses is scanned an error is +% signalled. +% \item[C\{\{x-default\}\{y-default\}\}] behaves like |c|, i.e., +% parses a coordinate pair if present. If the coordinate pair is +% missing it returns the default values instead. +% \item[l] Reads everything up to the first left brace as the +% argument. +% \end{description} +% For example, given the spec |soomO{default}| the input +% |*[Foo]{Bar}| would be parsed as +% |\c_true{Foo}\NoValue{Bar}{default}|. In other words there will be +% always exactly the same number of brace groups or tokens as the +% number of letters in the argument spec. +% +% There are a few exceptions to this rule as the r\^ole of following +% letters is to affect how the next argument is read. +% \begin{description} +% \item[>] takes a mandatory argument like |{P}| or |{PW}| and +% inserts these extra argument specifiers so that they act on the +% next regular argument type. See below. +% \item[P] will cause the next argument to allow |\par| in it's +% argument. Thus the specification |m>{P}mm| will cause the command to +% read three mandatory arguments but only the second can contain the +% |\par| token. +% \item[W] will cause the next argument to \emph{not} ignore a space +% when trying to scan ahead for a special symbol such as a |*| or an +% optional argument. This is mostly useful when the last argument(s) +% of a document command are optional (see example later on). +% \end{description} +% +% +% \subsection{Applying the parsing results} +% +% Since the result of the parsing is a well defined number of tokens or +% brace groups it is easy to pass them on in any order to any +% processing function. To this end the tokens or brace groups are +% associated with the standard argument specifiers in \TeX{} macros, +% i.e., |#1|, |#2|, and so forth. This limits the argument +% specification to a maximum number of 9 letters, but for practical +% applications this should be sufficient. +% +% \subsection{The class designer interface} +% +% This package provides commands for declaring commands +% and environments to be used within the document body. +% +% \DescribeMacro\DeclareDocumentCommand +% The |\DeclareDocumentCommand| declaration takes three arguments. The +% first argument is the name of the command to be declared, the second +% is the argument specification in the syntax described above, and the +% third is the action to be carried out once the arguments are +% parsed. Within the third argument |#1|, |#2|, etc.\ denote the +% result of the parsing, e.g., +% \begin{verbatim} +% \DeclareDocumentCommand{\chapter}{som} +% { \IfBooleanTF {#1} +% { \typesetnormalchapter {#2}{#3} } +% { \typesetstarchapter {#3} } +% } +% \end{verbatim} +% would be a way to define a |\chapter| command which would +% essentially behave like the current \LaTeX{} command (except that it +% would accept an optional argument even when a |*| was parsed). The +% |\typesetnormalchapter| could test its first argument for being +% |\NoValue| to see if an optional argument was present. +% +% Of course something like the |\IfNoValueTF| test could also be +% placed inside a function that would process all three arguments, thus +% using the templates and their instances as provided by the +% \texttt{template} package such a declaration would probably look +% more like the following example: +% \begin{verbatim} +% \DeclareDocumentCommand{\chapter}{som} +% { \UseInstance {head} {A-head-main} {#1} {#2} {#3} } +% \end{verbatim} +% +% Using the |\DeclareDocumentCommand| interface it is easy to modify +% the document-level syntax while still applying the same +% layout-generating functions, e.g., a class that would not support +% optional arguments or star forms for the heading commands could +% define |\chapter| like this: +% \begin{verbatim} +% \DeclareDocumentCommand{\chapter}{m} +% { \UseInstance {head} {A-head-main} \BooleanFalse \NoValue {#1} } +% \end{verbatim} +% while a class that would allow for an additional optional argument +% (for whatever reason) could define it like that: +% \begin{verbatim} +% \DeclareDocumentCommand{\chapter}{somo} +% { \doSomethingWithTheExtraOptionalArg {#4} +% \UseInstance {head} {A-head-main} {#1} {#2} {#3} } +% \end{verbatim} +% \DescribeMacro\ReDeclareDocumentCommand +% \DescribeMacro\ProvideDocumentCommand +% The commands |\ReDeclareDocumentCommand| and +% |\ProvideDocumentCommand| work just like |\DeclareDocumentCommand| +% with the exception that |\Re..| can only redefine an existing +% command and |\Provide...| will only define the command if it is +% already free. +% +% +% \DescribeMacro\DeclareDocumentEnvironment +% \DescribeMacro\ReDeclareDocumentEnvironment +% \DescribeMacro\ProvideDocumentEnvironment The +% |\DeclareDocumentEnvironment| declaration is similar to +% |\DeclareDocumentCommand| except that it takes four arguments: the +% first being the environment name (without a backslash), the second +% again the argument-spec, and the third and forth are the actions +% taken at start aqnd end of the environment. The parsed arguments are +% available to both the start and the finish as |#1|, |#2|, etc. +% +% All commands and environments defined with the above commands are +% automatically robust. +% +% +% +% \subsection{A different interface (for class design?)} +% +% Combining signature and top-level definition of a command |\foo| as +% in +% \begin{verbatim} +% \DeclareDocumentCommand \foo { m c m } +% { \typeout{1:#1} +% \typeout{2:#2} +% \typeout{3:#3} +% } +% \end{verbatim} +% is fine in certain cases, e.g., if the user wants to declare a few +% commands this way in the preamble of a document. However in a class +% file it probably better to completely separate signature (i.e., +% argument \#1 and \#2) from top-level implementation (i.e., argument +% \#3). +% +% +% \begin{verbatim} +% \DeclareDocumentCommandInterface \foo {bar} { m c m } +% \end{verbatim} +% The above now declare only the signature of the command |\foo| and +% states that the implementation is to be found under the label |bar|. +% +% A bunch of such statements would then for the first time clearly +% define a document class (i.e., what a document class instance needs +% to define to be compliant). +% +% An instance would then consist of a lot of declarations of the type +% \begin{verbatim} +% \DeclareDocumentCommandImplementation {bar} {3} +% { \typeout{1:#1} +% \typeout{2:#2} +% \typeout{3:#3} +% } +% \end{verbatim} +% i.e., defining how to format things being referenced as part of the +% signature. +% +% The functions |\DeclareDocumentCommandInterface| and +% |\DeclareDocumentCommandImplementation| are implemented for now but +% it is not sure if they will stay. If a document command is defined +% with |\DeclareDocumentCommandInterface| but there is no matching +% interface it prints the label in quotes as |``bar''|. +% +% +% +% +% \subsection{Checking for a value or boolean} +% +% It would make perfect sense to make |\NoValue| a \LaTeX3 quark but +% as there is a real danger of it getting executed by accident it is +% best not to as it would result in an infinite loop. +% +% \DescribeMacro\NoValue +% For this reason |\NoValue| is defined to expand to the string +% |-NoValue-| which would get typeset if ever executed thus clearly +% indicating the type of error the writer made. +% +% However this makes testing for this token slightly complicated as in +% that case the test +% \begin{verbatim} +% \tlp_set:Nn \l_seen_tlp {#1} +% \tlp_set:Nn \l_hidden_novalue_tlp {\NoValue} +% \tlp_if_eq:NNTF \l_seen_tlp \l_hidden_novalue_tlp +% \end{verbatim} +% will be true if |#1| was |\NoValue| but false if |#1| itself +% contains a macro which contains |\NoValue|; a case that happens +% unfortunately very often in practice. Using an unguarded |x| type +% expansion to define |\l_seen_tlp| is out of the question as |#1| is +% typically either |\NoValue| or arbitrary user input for which we +% can't properly guard it unless we are sure people only use robust +% commands. When running a pure \LaTeX3 format where all document +% commands are robust this is perhaps something to be looked at again +% but when running on top of \LaTeXe{} we have to be careful. +% +% Therefore we use a somewhat different procedure here, which goes +% like this: +% \begin{enumerate} +% \item Store |#1| in a temporary variable and check if it equals a +% variable containing |\NoValue|. If true, execute the \meta{true} +% code, otherwise go to~2. +% \item Peek at the first token in |#1|. If this is a macro taking no +% arguments expand |#1| once and go to~1. Otherwise execute the +% \meta{false} code. +% \end{enumerate} +% The reason for the careful peeking ahead is that |#1| may very well +% be a macro taking arguments and it is not certain that these +% arguments are present! Hence this could lead to the well-known +% \begin{verbatim} +% Argument of \XXX has an extra } +% \end{verbatim} +% and we wouldn't want that\dots{} Goes without saying that this +% procedure is quite tedious but usually it will exit after the first +% time |#1| has been inspected. One additional test could be added, +% namely that |#1| should also contain exactly one token but I don't +% think that is going to matter much. +% +% \DescribeMacro\IfNoValueTF +% \DescribeMacro\IfNoValueT +% \DescribeMacro\IfNoValueF +% \DescribeMacro\IfValueTF +% \DescribeMacro\IfValueT +% \DescribeMacro\IfValueF +% These macros are used for checking if an optional argument was +% present as in the example below. +% \begin{verbatim} +% \DeclareDocumentCommand\testcmd{om}{ +% \IfNoValueTF{#1}{``#2''}{#1,#2} +% } +% \end{verbatim} +% +% +% +% \DescribeMacro\IfBooleanTF +% \DescribeMacro\IfBooleanT +% \DescribeMacro\IfBooleanF +% As mentioned earlier, the parsing result for a symbol argument like +% |s| or |S{+}| is represented as the one of the tokens |\c_true| or +% |\c_false| respectively. To test for these values the macro +% |\IfBooleanTF| can be used. It expects as its first argument either +% |\c_true| or |\c_false| and executes its second or third argument +% depending on this value. |\IfBooleanT| and |\IfBooleanF| are +% obvious shortcuts. +% +% At one point in time I thought that one can represent everything +% using |\NoValue|, e.g., for the star case either return |*| or +% |\NoValue|. However, this slows down processing of commands like +% |\\*| considerably since they would then have to use a slower +% internal test instead of a fast two-way switch. +% +% +% \subsection{New argument types and shorthands} +% +% New argument types can be added at in a fairly straight forward +% manner with the command +% |\DeclareArgumentType|\DescribeMacro\DeclareArgumentType. This +% command takes seven arguments: |#1| is a symbol denoting the +% argument type, |#2| is the token the scanner should look for, |#3| +% is one of the words |meaning|, |charcode| or |catcode| which is +% handed down to the underlying |\peek_meaning:NTF| or +% |\peek_charcode:NTF| etc. functions. For instance you can use the +% |charcode| version if you want to pick up a literal |*| and not +% just something that has the same \emph{meaning} as a regular +% |*|. |#4| is for executing a special action (like an error message) +% if no argument is found, |#5| is the default value in case of a +% missing argument, |#6| is what the scanner will encounter, and +% finally |#7| is what the scanner grabs from the argument type. This +% is perhaps clearer with an example\dots{} This is how the |o| type +% is implemented: +% \begin{verbatim} +% \DeclareArgumentType o [ {meaning} {} {\NoValue} {#1[#2]} {#2} +% \end{verbatim} +% In a similar fashion a |b| type expecting its argument inside |<| +% and |>| would be defined as +% \begin{verbatim} +% \DeclareArgumentType b < {meaning} {} {\NoValue} {#1<#2>} {#2} +% \end{verbatim} +% +% \DescribeMacro\DeclareArgumentTypeWithDefault +% |\DeclareArgumentTypeWithDefault| is even simpler as this type +% expects the default value to be input at the time of argument +% specification. Thus arguments |#3| and |#4| from above are +% unnecessary and are simply absent. Thus the |O| type is +% implemented\footnote{I would say it is at best wishful thinking +% that the interface could be something like +% \texttt{\cs{DeclareArgumentTypeWithDefault} +% C\{2\}\{meaning\}\{(\#1,\#2)\}\{\{\#1\}\{\#2\}\}} as it would +% be quite troublesome implementation-wise and the current syntax +% isn't that difficult to use.} as +% \begin{verbatim} +% \DeclareArgumentTypeWithDefault O [ {meaning}{#1[#2]} {#2} +% \end{verbatim} +% and again a similar |B| type could be implemented as +% \begin{verbatim} +% \DeclareArgumentTypeWithDefault B < {meaning}{#1<#2>} {#2} +% \end{verbatim} +% +% +% There is also a possibility to define a shorthand for a specific +% sequence of arguments with the command +% \DescribeMacro\DeclareArgumentTypeShorthand +% |\DeclareArgumentTypeShorthand|. As an example the |s| argument +% type is just a different way of saying |S{*}| so it's simply +% implemented as +% \begin{verbatim} +% \DeclareArgumentTypeShorthand s {S{*}} +% \end{verbatim} +% Similarly one could add a shorthand |M| for inserting five +% mandatory arguments where the latter is allowed to take |\par| in +% its argument: +% \begin{verbatim} +% \DeclareArgumentTypeShorthand M {mmmm>{P}m} +% \end{verbatim} +% +% Finally there is also the command +% \DescribeMacro\DeclareSymbolArgument|\DeclareSymbolArgument| which +% defines the low level interface to looking ahead for specific +% symbols and removing them. For instance the |S| type argument is +% declared as +% \begin{verbatim} +% \DeclareSymbolArgument S{meaning} +% \end{verbatim} +% So symbols picked up by this type will compare the meaning of the +% tokens. One could do a +% \begin{verbatim} +% \DeclareSymbolArgument A{charcode} +% \end{verbatim} +% and then the |A| type would compare character codes instead. For +% instance a command which expects a |+| symbol would return +% \meta{true} if a |+| of any catcode is detected, not just catcode +% 12 as is usual. +% +% \subsection{Some comments on the need for the \texttt{O} specifier} +% +% With |\newcommand| there is the possibility of specifying a default +% for an optional argument which is stored away in a more or less +% efficient manner. For example below is the old definition of +% |\linebreak| as can be found in the \LaTeX2e kernel: +%\begin{verbatim} +%\def\linebreak{\@testopt{\@no@lnbk-}4} +%\def\@no@lnbk #1[#2]{% +% \ifvmode +% \@nolnerr +% \else +% \@tempskipa\lastskip +% \unskip +% \penalty #1\@getpen{#2}% +% \ifdim\@tempskipa>\z@ +% \hskip\@tempskipa +% \ignorespaces +% \fi +% \fi} +%\end{verbatim} +% Ignoring for the moment that the above is slightly optimised an +% expansion of this code under |\tracingall| will result in about 90 +% lines of tracing output. If we reimplement this using +% |\DeclarDocumentCommand\linebreak{o}| we have to use |\IfNoValueTF| +% to find out if an argument was present which (because of the careful +% expansion we do internally) results in about twice as much of +% tracing lines. In contrast using |O{4}| as below we end up with 110 +% lines, which seems roughly the price we have to pay for the extra +% generality available (though this could perhaps even be reduced by a +% better implementation of the parsing machine as originally done by +% David, before i talked him into adding support for arguments in the +% end code of an environment).\footnote{These comments were made +% before the extensive changes in expl3 and xparse in 2005.} +% +%\begin{verbatim} +%\DeclareDocumentCommand\linebreak { O{4} } +% { +% \ifvmode +% \@nolnerr +% \else +% \@tempskipa\lastskip +% \unskip +% % \IfNoValueTF{#1} +% % {\break} +% % {\penalty -\@getpen{#1}} +% \penalty -\@getpen{#1} +% \ifdim\@tempskipa>\z@ +% \hskip\@tempskipa +% \ignorespaces +% \fi +% \fi +% } +%\end{verbatim} +% +% +% \subsection{A somewhat complicated example} +% +% This example reimplements the |\makebox| and |\framebox| interface +% of \LaTeX{} both of which are unfortunately quite overloaded +% syntactically. For this reason the example isn't meant to show good +% coding practice but to show the power of the interface even though +% applied in a somewhat bad way. +% +% |\makebox| and |\framebox| support the following different document +% syntax forms: +% \begin{itemize} +% \item +% |\makebox{A}|: only a single mandatory argument. +% +% \item +% |\makebox[20pt]{B}|: one optional argument specify the box width. +% +% +% \item +% |\makebox[30pt][r]{C}|: two optional arguments the second specifying +% the text position within the box being made (l,c,r being allowed +% with c being the default). +% +% \item +% |\makebox(20,30){D}|: within picture mode the width is specified not +% as an optional argument in brackets but as a coordinate pair. +% +% \item +% |\makebox(0,0)[lt]{E}|: in that case an optional argument following +% coordinate pair denotes the placement within the box which can have +% different values compared to case C above. +% \end{itemize} +% +% To cater for this overloaded structure we can define |\makebox| to +% be something like the following: +%\begin{verbatim} +%\DeclareDocumentCommand \makebox { C{\NoValue} o O{c} m} +% { \IfNoValueTF{#1} +% { \ltx@maketextbox{#2}{#3}{#4} } +% { \ltx@makepicbox #1 {#2}{#4} } } +%\end{verbatim} +% In other words: if we do not see a coordinate pair first (i.e., +% first argument is |\NoValue| then we expect up to two optional +% arguments (the width of the box or |\NoValue| if not given and the +% placement specifier with a default of |c| if not given) and one +% mandatory one which is the text. In that case we pass argument 2 to +% 4 to an internal function |\ltx@maketextbox| which builds the text +% box. +% +% Otherwise, if the first argument is a coordinate pair we parse an +% optional argument denoting the placement specifier. Since +% \texttt{xparse} doesn't support variant syntax we actually parse for +% another optional argument (which has no meaning in that case and is +% in fact ignored if present) followed by a mandatory one containing +% the box text. In that case we pass the coordinate pair (|#1|), the +% specifier (|#2|), and the text (|#4|) to the function +% |\ltx@makepicbox| which builds the picture box. Note the special +% handling of the coordinatesD: which are passed without surrounding +% braces to |\ltx@makepicbox|: since the coordinate argument looks +% like |{x-val}{y-val}| the receiving function |\ltx@makepicbox| gets +% the |x-val| as argument one and the |y-val| as argument two. +% +% A definition for |\framebox| would look more or less identical +% except that we would need to pass the arguments to slightly +% different internal functions. The alternative is to give the +% internal functions an extra argument that controls whether or not a +% frame is bying built. +% +% \begin{macro}{\ltx@makepicbox} +% So here is a possible implementation of |\ltx@makepicbox| that +% builds a picture box with or without frame. It takes the following +% mandatory arguments: +% \begin{enumerate} +% \item x-part of coordinate +% \item y-part of coordinate +% \item placement specifier, e.g., |lt| or |\NoValue| +% \item text of box +% \item the token |\frame| (if a frame should surround the box) or the +% token |\@firstofone| --- not pretty i agree +% \end{enumerate} +%\begin{verbatim} +%\def\ltx@makepicbox#1#2#3#4#5 +% { +% #5{ +% \vbox to#2\unitlength +% {\let\mb@b\vss \let\mb@l\hss\let\mb@r\hss +% \let\mb@t\vss +% \IfNoValueF{#3} +% { +% \@tfor\reserved@a :=#3\do{ +% \if s\reserved@a +% \let\mb@l\relax\let\mb@r\relax +% \else +% \expandafter\let\csname mb@\reserved@a\endcsname\relax +% \fi}% +% } +% \mb@t +% \hb@xt@ #1\unitlength{\mb@l #4\mb@r} +% \mb@b +% \kern\z@} +% } +% } +%\end{verbatim} +% \end{macro} +% +% +% +% \begin{macro}{\ltx@maketextbox} +% For the text case the internal function could take the following +% mandatory arguments: +% \begin{enumerate} +% \item width of the box or |\NoValue| (denoting to build the box at +% natural width) +% \item placement specifier, e.g., |l|. (No test for |\NoValue| being undertaken) +% \item text of box +% \item the token |\fbox| (if a frame should surround the box) or the +% token |\mbox| +% \end{enumerate} +% The actual code is taken straight from the current \LaTeX{} kernel +% and looks kind of scary. +%\begin{verbatim} +%\def\ltx@maketextbox#1#2#3#4 +% { +% \IfNoValueTF{#1} +% {#4{#3}} +% { +% \leavevmode +% \@begin@tempboxa\hbox{#3} +% \setlength\@tempdima{#1} +% \ifx#4\fbox +% \setbox\@tempboxa\hb@xt@\@tempdima +% {\kern\fboxsep\csname bm@#2\endcsname\kern\fboxsep} +% \@frameb@x{\kern-\fboxrule} +% \else +% \hb@xt@\@tempdima{\csname bm@#2\endcsname} +% \fi +% \@end@tempboxa +% } +% } +%\end{verbatim} +% \end{macro} +% +% \begin{macro}{\makebox} +% \begin{macro}{\framebox} +% Given the above internal functions the declarations of |\makebox| +% and |\framebox| would then look like this: +%\begin{verbatim} +%\DeclareDocumentCommand \makebox { C{\NoValue} o O{c} m} +% { \IfNoValueTF{#1} +% { \ltx@maketextbox{#2}{#3}{#4}\mbox } +% { \ltx@makepicbox #1 {#2}{#4}\@firstofone } } +% +%\DeclareDocumentCommand \framebox { C{\NoValue} o O{c} m} +% { \IfNoValueTF{#1} +% { \ltx@maketextbox{#2}{#3}{#4}\fbox } +% { \ltx@makepicbox #1 {#2}{#4}\frame } } +%\end{verbatim} +% \end{macro} +% \end{macro} +% +% +% +% Here's another example which shows how one can use the |W| specifier. +% The \textsf{amsmath} environments use their own definition of |\\| +% which goes under the name |\math@cr|. As there is a good chance the +% next line of math begins with either an asterisk or something in +% square brackets this often leads to errors. The following example +% definition works (I \emph{did} try it). +% \begin{verbatim} +% \CodeStart +% \cs_gundefine:N \math@cr +% \DeclareDocumentCommand\math@cr{>{W}s >{W}O{\z@}}{ +% \IfBooleanTF{#1} +% { \global\@eqpen\@M }{ +% \global\@eqpen +% \ifnum\dspbrk@lvl <\z@ +% \interdisplaylinepenalty +% \else +% -\@getpen\dspbrk@lvl +% \fi +% } +% \math@cr@@@ +% \noalign{\vskip#2\relax} +% } +% \CodeStop +% \end{verbatim} +% Note that this definition automatically avoids problems within the +% alignments even if it is called as |\\&|. +% +% +% +% +% \subsection{Open issues} +% +% In this section unresolved issues or ideas to think about and +% perhaps implement are collected. There is no particular order to +% them. +% +% \begin{itemize} +% \item +% Support for parsing verbatim type of arguments was considered (and +% actually implemented at one stage. E.g., +% |g{|\meta{prepare-parsing}|}| where |g| first run +% \meta{prepare-parsing} (which might involve |catcode| +% changes)\footnote{urg horror!}, then look at the next token: if +% that would be a |{| it would scan a brace delimited argument +% (reverting catcodes of |{| and |}| if needed) otherwise would scan +% for an argument delimited by that token so that something like +% |\verb+%\+| would scan |%\| as its argument assuming that the +% \meta{prepare-parsing} turned |%| and |\| into non-letters. +% +% All kind of nasty problems lurking especially no proper error +% checks possible and of course as we all know such commands would +% then not work inside arguments of other commands. At least they +% would have some restrictions. +% +% Also no way to make the parsing smart by not accepting newlines as +% part of the code (|\verb| does this right now and this is really +% helpful as it catches runaways nicely). +% +% +% \item +% \textsf{xparse} should probably go into the \LaTeX3 kernel in which +% case it should also provide the definitions of |\begin| and |\end| +% and this raises a few questions: Will environments be defined as +% control sequences |\foo| and |\endfoo|? If they are do we then want +% to include support for a separate command |\foo| and if so what +% about using the environment forms in special scanner mechanisms +% where we \emph{can't} use |\begin{foo}|? In those cases one could +% use a special command like what the \textsf{fancyvrb} package +% provides with the command |\VerbatimEnvironment| and all packages +% that define such special arguments should then also make sure that +% the |\foo| command issued on its own should cause an error. +% Another solution would be to simply define environments as +% |\beginfoo| and |\endfoo| and then let |\begin| check if it was +% used to call an environment or a command. If the latter is the +% case then insert grouping as that could be handled by |\beginfoo| +% itself. When |\end| is reached check if |\endfoo| exists. If it +% does then use that, otherwise we were probably using a normal +% command which should just close the group. +% \end{itemize} +% +% +% \subsection{Rejected ideas---and why} +% +% Let's say the document command |\testmo| has signature |mo|. If we +% call it as |\testmo{arg} [opt]| a following space will be obeyed. +% However calling it with the mandatory argument only as in +% |\testmo{arg}| will gobble a following space because the peek ahead +% in the |o| type ignores spaces. We can record that a space has been +% gobbled when peeking ahead and we can also put it back in if needed +% but I have only ever seen one request for this and in that case the +% better solution was to use a signature |mWo| so that no spaces are +% allowed between the mandatory and the optional argument. One could +% even argue that this is the most appropriate thing to do if the user +% is really that sensitive to spaces! In any case it is not +% implemented here as it creates an unnecessary overhead for something +% that is never used and a simple solution exists. +% +% \subsection{Experimental features} +% +% Experimental features in an experimental packages\dots{} Needless to +% say that you can't rely on them staying! +% +% +% One new feature is what I decided to call ``pseudo +% arguments''. Strictly speaking these aren't real arguments but +% instead read by removing a begin group token and then using +% |\tex_aftergroup:D| to regain control. The definition of |\footnote| +% in plain \TeX\ uses this so that people can use +% |\verb| and the like inside the footnotes. The command +% |\DeclarePseudoArgument|\DescribeMacro{\DeclarePseudoArgument} takes +% four arguments: |#1| is a name for the pseudo argument, |#2| is the +% number of arguments it takes, |#3| is the action to be taken right +% before the left brace is removed and |#4| is what to be done when +% the right brace has been read and we regain control. Note that both +% |#3| and |#4| may use arguments! Here is a silly example: +% \begin{verbatim} +% \DeclarePseudoArgument{boxtest}{1} +% {Before:~`#1',\hbox_set_inline_begin:N \l_tmpa_box } +% {\hbox_set_inline_end: \text_put_sp: the~ box:~ +% \hbox_unpack_and_clear:N\l_tmpa_box ,~ +% After:~`#1'} +% \end{verbatim} +% Now when you want to use it, you simply call it with the macro +% |\UsePseudoArgument|\DescribeMacro{\UsePseudoArgument}, which as its +% first argument takes a name and the remaining depend on how many +% arguments the pseudo argument was defined to have. Hence we could +% use our |boxtest| definition like this: +% \begin{verbatim} +% \DeclareDocumentCommand\sillyboxtest{m}{ +% Testing~#1:~\UsePseudoArgument{boxtest}{#1} +% } +% \end{verbatim} +% Then calling |\sillyboxtest{AB}{a\verb*+% $%&\+b}| produces +% \begin{quote} +% Testing AB: Before: `AB', the box: +% a\verb*+% $%&\+b, After: `AB' +% \end{quote} +% |\UsePseudoArgument| should always come last in the document +% command definition. +% +% \StopEventually{} +% +% \section{Implementation} +% +% Versions prior to and including 1.19 contained several different +% implementations. These are gone now but can be looked at by +% getting an older version of the package from the CVS repository. +% +% First the required packages. +% \begin{macrocode} +%<*package> +\RequirePackage{l3tlp,l3num,l3toks,l3prg,l3int,l3seq,l3token} +% \end{macrocode} +% +% +% +% \subsection{Error and warning messages} +% +% Here we define the error message we're going to use in this package. +% +% \begin{macro}{\xparse_already_defined_error_msg:N} +% \begin{macro}{\xparse_not_yet_defined_error_msg:N} +% \begin{macro}{\xparse_begins_with_end_error_msg:N} +% \begin{macro}{\xparse_unknown_arg_type_error_msg:N} +% \begin{macro}{\xparse_number_of_arguments_error_msg:Nn} +% \begin{macro}{\xparse_no_command_implementation_warning:n} +% The names should give the function's purpose away. +% \begin{macrocode} +\def_new:NNn \xparse_already_defined_error_msg:N 1 { + \xparse_error:x { + Command~name~`\token_to_string:N #1'~ already~defined! + } +} +\def_new:NNn \xparse_not_yet_defined_error_msg:N 1 { + \xparse_error:x { + Command~`\token_to_string:N #1'~ not~ yet~defined! + } +} +\def_new:NNn \xparse_begins_with_end_error_msg:N 1 { + \xparse_error:x { + Command~`\token_to_string:N #1'~begins~with~ + `\token_to_string:N \end'! + } +} +% \end{macrocode} +% This one is for when we've encountered an unknown argument type in +% the argument specification. We can try to recover by putting in an +% |m| type instead and hope for the best. +% \begin{macrocode} +\def_new:NNn \xparse_unknown_arg_type_error_msg:N 1{ + \xparse_error:x { + Unknown~ argument~ type~ `#1'~ + I'll~ substitute~ it~ with~ `m'~ for~ now.~ Fingers~ crossed... + } +} +% \end{macrocode} +% A message for people using the wrong number of arguments. +% \begin{macrocode} +\def_new:NNn \xparse_no_command_implementation_warning:n 1 { + \xparse_warning:x {No~ implementation~ for~ `#1'~ defined} +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\xparse_error:x} +% \begin{macro}{\xparse_warning:x} +% Here's how we produce the error messages and warnings currently. +% This awaits a proper error message module! +% \begin{macrocode} +\def_new:NNn \xparse_error:x 1{\tex_errmessage:D {xparse~error:~#1}} +\def_new:NNn \xparse_warning:x 1{\io_put_term:x{xparse~warning:~#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% +% \subsection{Checking for valid command names} +% +% +% \begin{macro}{\xparse_if_definable:NT} +% \begin{macro}{\xparse_if_definable:cT} +% A definable command is either |\c_undefined| or |\scan_stop:| and +% furthermore we won't allow it to start with |\end|. +% If the command is definable we do what was asked for otherwise +% we give an appropriate error message. +% \begin{macrocode} +\def_new:NNn \xparse_if_definable:NTF 1 { +% \end{macrocode} +% First check if the control sequence is free. +% \begin{macrocode} + \cs_free:NTF #1 +% \end{macrocode} +% If free check if it begins with |\end|. +% \begin{macrocode} + { + \xparse_begins_with_end:NTF #1 + { \xparse_begins_with_end_error_msg:N #1 \use_arg_ii:nn } + \use_arg_i:nn + } +% \end{macrocode} +% If not free give an error message. +% \begin{macrocode} + { \xparse_already_defined_error_msg:N #1 \use_arg_ii:nn } +} +\def_new:NNn \xparse_if_definable:cTF 0 { + \exp_args:Nc \xparse_if_definable:NTF +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\xparse_if_redefinable:NTF} +% \begin{macro}{\xparse_if_redefinable:cTF} +% A re-definable command is almost the same as above but here we +% demand that it already exists. +% \begin{macrocode} +\def_new:NNn \xparse_if_redefinable:NTF 1 { + \cs_free:NTF #1 + { \xparse_not_yet_defined_error_msg:N #1 \use_arg_ii:nn } + { + \xparse_begins_with_end:NTF #1 + { \xparse_begins_with_end_error_msg:N #1 \use_arg_ii:nn } + \use_arg_i:nn + } +} +\def_new:NNn \xparse_if_redefinable:cTF 0 { + \exp_args:Nc \xparse_if_redefinable:NTF +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\xparse_begins_with_end:NTF} +% \begin{macro}{\xparse_begins_with_end_aux:N} +% Finally we need the magic function for checking if the control +% sequence begins with |\end|. +% We wish to determine if the control sequence in question begins with +% |\end| which is forbidden. The end goal is to get a control sequence +% consisting of the first three letters to test against |\end| with +% |\cs_if_eq_name_p:NN|. The function |\cs_to_str:N| will remove the |\| +% from a command name and return the rest of the characters with +% category code 12. Thus using an |f| type expansion to get the first +% three characters is perfectly safe as it'll stop right there. Then +% we turn these three letters into a control sequence with a simple +% expansion which is then tested with |\xparse_begins_with_end_aux:N|. +% \begin{macrocode} +\def_new:NNn \xparse_begins_with_end:NTF 1 { +% \end{macrocode} +% We do it all in a group as there is no need to fill up the hash +% table with weird three letter control sequences. +% \begin{macrocode} + \group_begin: + \exp_args:Nc \xparse_begins_with_end_aux:N { + \tlist_head_iii:f { \cs_to_str:N #1 ??} + } +} +% \end{macrocode} +% After the above expansion tricks we now have a real control sequence +% to test against |\end|. We end the group again. +% \begin{macrocode} +\def_new:NNn \xparse_begins_with_end_aux:N 1 { + \if:w \cs_if_eq_name_p:NN #1 \end + \group_end: + \exp_after:NN \use_arg_i:nn + \else: + \group_end: + \exp_after:NN \use_arg_ii:nn + \fi: +} +% \end{macrocode} +% Note that these definitions make no use of temporary variables. +% \end{macro} +% \end{macro} +% +% +% +% \subsection{The high level commands} +% +% +% Here we set up the functions for defining and redefining document +% commands and environments. It's all rather straight forward here so +% I've saved on the comments. +% +% \begin{macro}{\DeclareDocumentCommand} +% \begin{macro}{\ReDeclareDocumentCommand} +% In case we can't do what the user wanted we gobble the next +% arguments from the input stream. For commands there are two +% arguments waiting. +% \begin{macrocode} +\def_new:NNn \DeclareDocumentCommand 1 { + \xparse_if_definable:NTF #1 + { \xparse_declare_document_command:Nnn #1 } + \use_none:nn +} +\def_new:NNn \ReDeclareDocumentCommand 1 { + \xparse_if_redefinable:NTF #1 + { \xparse_declare_document_command:Nnn #1 } + \use_none:nn +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\DeclareDocumentEnvironment} +% \begin{macro}{\ReDeclareDocumentEnvironment} +% Three arguments for environments. +% \begin{macrocode} +\def_new:NNn \DeclareDocumentEnvironment 1 { + \xparse_if_definable:cTF {#1} + { \xparse_declare_document_environment:nnnn {#1} } + \use_none:nnn +} +\def_new:NNn \ReDeclareDocumentEnvironment 1 { + \xparse_if_redefinable:cTF {#1} + { \xparse_declare_document_environment:nnnn {#1} } + \use_none:nnn +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\ProvideDocumentCommand} +% \begin{macro}{\ProvideDocumentEnvironment} +% When providing a command we just check if the control sequence is +% free. If it is let |\DeclareDocument...| do the rest, otherwise +% gobble the next arguments. +% \begin{macrocode} +\def_new:NNn \ProvideDocumentCommand 1{ + \cs_free:NTF #1 + { \DeclareDocumentCommand #1} + \use_none:nn +} +\def_new:NNn \ProvideDocumentEnvironment 1{ + \cs_free:cTF {#1} + { \DeclareDocumentEnvironment {#1} } + \use_none:nnn +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% +% \subsection{The low level definitions} +% +% +% First some helper functions +% \begin{macro}{\l_xparse_grabbed_args_toks} +% \begin{macro}{\l_xparse_end_environment_args_toks} +% \begin{macro}{\l_xparse_mandatory_args_int} +% \begin{macro}{\l_xparse_total_args_int} +% We need some \meta{token} registers to keep track of things. We also +% allocate an \meta{int} register to keep track of the number of +% arguments. +% \begin{macrocode} +\toks_new:N \l_xparse_grabbed_args_toks +\toks_new:N \l_xparse_end_environment_args_toks +\int_new:N \l_xparse_mandatory_args_int +\int_new:N \l_xparse_total_args_int +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\xparse_declare_document_command:Nnn} +% \begin{macro}{\xparse_declare_document_command:cnn} +% |\xparse_declare_document_command:Nnn| is a two step procedure. The +% user level command |\|\meta{cmd} contains the argument grabbers +% while the internal command |\\|\meta{cmd} holds the actual +% definition of what to do with the arguments. Naturally this calls +% for every such user level command to be robust which is done using +% the \eTeX{} protection feature. +% \begin{macrocode} +\def_long:NNn \xparse_declare_document_command:Nnn 3{ +% \end{macrocode} +% First we prepare the signature. +% \begin{macrocode} + \xparse_prepare_signature:n {#2} +% \end{macrocode} +% Now for the document command. Make it robust and make sure it starts +% with |\toks_set:Nn \l_xparse_grabbed_args_toks {\\|\meta{cmd}|}|. +% \begin{macrocode} + \def_protected:Npx #1 { + \exp_not:n { \toks_set:Nn \l_xparse_grabbed_args_toks } + {\exp_not:c {\token_to_string:N #1}} +% \end{macrocode} +% Then add the argument grabbers which contain code gathered when +% preparing the signature. +% \begin{macrocode} + \toks_use:N \l_xparse_grabbed_args_toks +% \end{macrocode} +% Finally execute |\toks_use:N \l_xparse_grabbed_args_toks| which now +% holds the grabbed arguments enclosed in braces and starts with the +% internal command |\\|\meta{cmd}. +% \begin{macrocode} + \exp_not:n{ \toks_use:N \l_xparse_grabbed_args_toks} + } +% \end{macrocode} +% Define the internal command by making it a |\long| macro with number +% of arguments equal to |\l_xparse_total_args_int| and definition as +% given by |#3|. Even though this internal macro allows |\par| in its +% argument the decision is left to the individual argument grabbers. +% \begin{macrocode} + \def_long:cNn {\token_to_string:N #1}\l_xparse_total_args_int{#3} +} +\def_new:Npn \xparse_declare_document_command:cnn { + \exp_args:Nc \xparse_declare_document_command:Nnn +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\xparse_declare_document_environment:nnnn} +% |\xparse_declare_document_environment:nnnn| is almost the same. In +% order to use the grabbed arguments we take them from +% |\l_xparse_grabbed_args_toks| just before they are executed. We +% also insert a |\group_begin:| as it will otherwise fail miserably +% in case a user tries to use it without |\begin ... \end|. +% \begin{macrocode} +\def_long_new:NNn \xparse_declare_document_environment:nnnn 4 { + \xparse_declare_document_command:cnn {#1}{#2} + { \group_begin: + \toks_set_eq:NN \l_xparse_end_environment_args_toks + \l_xparse_grabbed_args_toks + #3 + } +% \end{macrocode} +% We let |\end|\meta{envir} equal to a standard version which will do +% all the work. +% \begin{macrocode} + \let:cN {end #1} \xparse_parsed_end_environment: +% \end{macrocode} +% Now define |\end\\|\meta{envir}. +% \begin{macrocode} + \def_long:cNn {end \token_to_string:N \\ #1} + \l_xparse_total_args_int{#4} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\xparse_parsed_end_environment:} +% \begin{macro}{\xparse_parsed_end_environment_aux:N} +% |\end|\meta{envir} is set equal to |\xparse_parsed_end_environment:| +% which then executes |\end\\|\meta{envir}. The |\\|\meta{envir} comes +% from the argument grabbing. The remainder of the token list is the +% grabbed arguments. We better make this robust as well. +% \begin{macrocode} +\def_protected_new:NNn \xparse_parsed_end_environment: 0{ + \exp_after:NN \xparse_parsed_end_environment_aux:N + \toks_use:N \l_xparse_end_environment_args_toks + \group_end: +} +\def_new:NNn \xparse_parsed_end_environment_aux:N 1{ + \cs_use:c {end \token_to_string:N #1 } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \subsubsection{A class designer interface} +% +% Below is the implementation of |\DeclareDocumentCommandInterface| +% and the close cousin |\DeclareDocumentCommandImplementation|. +% It is an open issue whether this concept should be supported. +% +% \begin{macro}{\DeclareDocumentCommandInterface} +% With this macro we define the document command |#1| to have +% signature |#3| which does the argument grabbing. The arguments are +% passed on to the internal command |\impl-#2|. +% \begin{macrocode} +\def_long_new:NNn \DeclareDocumentCommandInterface 3{ + \xparse_prepare_signature:n {#3} + \def_protected:Npx #1 { + \exp_not:n { \toks_set:Nn \l_xparse_grabbed_args_toks } + {\exp_not:c {impl-#2}} + \toks_use:N\l_xparse_grabbed_args_toks + \exp_not:n{ \toks_use:N \l_xparse_grabbed_args_toks} + } +% \end{macrocode} +% Define the internal command by making it a |\long| macro as we did +% for |\DeclareDocumentCommand| but give it just a default definition +% instead (usually an error message). +% \begin{macrocode} + \def_long:cNn {impl-#2} \l_xparse_total_args_int + {\xparse_undefined_command_implementation:n{#2}} +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\xparse_undefined_command_implementation:n} +% What to do if no implementation is made and the command is +% called. Let's just typeset the name in quotes indicating that +% something is wrong. +% \begin{macrocode} +\def_new:NNn \xparse_undefined_command_implementation:n 1{ + ``#1'' +% \ensuremath{\langle\textit{#1}\rangle} + \xparse_no_command_implementation_warning:n {#1} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\DeclareDocumentCommandImplementation} +% Defines the internal command |\impl-#1| with |#2| arguments +% and definition |#3|. +% \begin{macrocode} +\def_long_new:NNn \DeclareDocumentCommandImplementation 3{ + \def_long:cNn {impl-#1}#2{#3} +} +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Creating the signature} +% +% +% \begin{macro}{\xparse_prepare_signature:n} +% The actual preparation of the signature is always the same but we +% have different ways of handling it afterwards, so we make it a +% separate function. +% \begin{macrocode} +\def_new:NNn \xparse_prepare_signature:n 1 { +% \end{macrocode} +% Initialize the counter taking care of the number of arguments. In +% case we reach more than nine we will give an error message later on. +% \begin{macrocode} + \int_zero:N \l_xparse_total_args_int +% \end{macrocode} +% Clear the token register we use when building the signature and the +% number of ``normal'' mandatory arguments. Also clear out the special +% markers and initialize the two booleans to \meta{false}. +% \begin{macrocode} + \toks_clear:N \l_xparse_grabbed_args_toks + \int_zero:N \l_xparse_mandatory_args_int + \bool_gset_false:N \g_xparse_insert_marker_bool + \bool_gset_false:N \g_xparse_allow_par_bool + \tlp_gset_eq:NN \g_xparse_ignore_marker_tlp + \g_xparse_ignore_spaces_marker_tlp +% \end{macrocode} +% Then call |\xparse_parse_signature:n|. +% \begin{macrocode} + \xparse_parse_signature:n #1 \q_nil +} +% \end{macrocode} +% \end{macro} +% +% +% \subsection{The argument types} +% +% +% +% All argument types must be denoted by single letters.\footnote{You +% can use a multi-letter sequence to denote a shorthand but it +% requires you to put two brace groups around it in the signature and +% it's not officially supported.} We have three categories of letters: +% Special markers, basic argument types, and shorthands. +% +% For certain argument types where we peek ahead in the token stream +% we have a multitude of choices for how the macro should work: +% Should it ignore spaces or other tokens? Which test should it use +% for comparing tokens: meaning, catcode or charcode? Because of +% these difficulties every argument that require peeking ahead must +% be declared as one of the three test types. +% +% \subsubsection{Special markers} +% +% Since there are different markers that may be used at the same +% time, we use the a special ``insert'' marker |>| to do this. +% +% \begin{macro}{\g_xparse_ignore_marker_tlp} +% The current ignore marker is contained in this string. +% \begin{macrocode} +\tlp_new:Nn \g_xparse_ignore_marker_tlp {} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\g_xparse_ignore_marker_seq} +% We start out by declaring a new sequence to contain all the +% different types of ignore functions. Each element should be the +% missing part of a |\peek_meaning|\meta{text}|:NTF| function. +% \begin{macrocode} +\seq_new:N \g_xparse_ignore_marker_seq +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\g_xparse_insert_marker_bool} +% A boolean to check if we just saw an insert marker. +% \begin{macrocode} +\bool_new:N \g_xparse_insert_marker_bool +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\xparse_add_arg_type_>:} +% The insert marker is called when this is seen. Is has a funny +% definition but it works. |#1| is some test in the loop function +% and |#2| is the list of markers. +% \begin{macrocode} +\def_new:cpn {xparse_add_arg_type_>:} #1 + \xparse_read_arg_type_or_grab_default:n #2{ +% \end{macrocode} +% Insert pending |m| args first. +% \begin{macrocode} + \xparse_add_remaining_m_args: +% \end{macrocode} +% Then we set the boolean true and subtract one from the argument +% count. +% \begin{macrocode} + \bool_gset_true:N \g_xparse_insert_marker_bool + \int_decr:N \l_xparse_total_args_int +% \end{macrocode} +% Then go through the list and call each subtype if it exists. +% \begin{macrocode} + \tlist_map_inline:nn{#2}{ + \xparse_check_and_add_argument_type:N ##1 + } +% \end{macrocode} +% Finally call the loop again. +% \begin{macrocode} + \xparse_parse_signature:n +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\xparse_add_ignore_marker:Nnn} +% A small function for adding a new ignore type marker. +% \begin{macrocode} +\def_new:NNn \xparse_add_ignore_marker:Nnn 3{ + \tlp_new:cn {g_xparse #2 _marker_tlp}{#3} + \seq_gpush:NC \g_xparse_ignore_marker_seq {g_xparse #2 _marker_tlp} + \def_new:cpn {xparse_add_arg_type_#1:}{ + \tlp_gset_eq:Nc \g_xparse_ignore_marker_tlp {g_xparse #2 _marker_tlp} + } +} +% \end{macrocode} +% \end{macro} +% Here we add some ignore markers. +% \begin{macrocode} +\xparse_add_ignore_marker:Nnn W{_ignore_nothing}{} +\xparse_add_ignore_marker:Nnn i{_ignore_spaces}{_ignore_spaces} +\xparse_add_ignore_marker:Nnn I{_ignore_pars}{_ignore_pars} +% \end{macrocode} +% +% \begin{macro}{\xparse_add_arg_type_P:} +% This is simple, just set a boolean. +% \begin{macrocode} +\def_new:NNn \xparse_add_arg_type_P: 0{ + \bool_gset_true:N \g_xparse_allow_par_bool +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\g_xparse_allow_par_bool} +% The boolean for allowing the |\par| token. +% \begin{macrocode} +\bool_new:N \g_xparse_allow_par_bool +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\xparse_parse_signature:n} +% |\xparse_parse_signature:n| reads the signature one token/brace +% group at a time and builds a list of argument grabbers which is +% stored in |\l_xparse_grabbed_args_toks|. The function is recursive +% which is why we use a quark to delimit it. +% \begin{macrocode} +\def_new:NNn \xparse_parse_signature:n 1{ +% \end{macrocode} +% Check if we reached the end of the signature. +% \begin{macrocode} + \quark_if_nil:NTF #1 +% \end{macrocode} +% If we did we may have pending |m| type arguments so we clear them +% out here. Also check if the insert marker is true because if it is, +% something is wrong. Otherwise we just continue. +% \begin{macrocode} + { + \xparse_add_remaining_m_args: + } +% \end{macrocode} +% Then proceed with adding arguments. +% \begin{macrocode} + { + \int_incr:N \l_xparse_total_args_int + \xparse_check_and_add_argument_type:N #1 +% \end{macrocode} +% If the insert marker is true at this point we reset it again and +% also disallow |\par| in arguments and make all |\peek| functions use +% the |_ignore_spaces| versions. +% \begin{macrocode} + \bool_if:NT \g_xparse_insert_marker_bool + { + \bool_gset_false:N \g_xparse_insert_marker_bool + \bool_gset_false:N \g_xparse_allow_par_bool + \tlp_gset_eq:NN \g_xparse_ignore_marker_tlp + \g_xparse_ignore_spaces_marker_tlp + } +% \end{macrocode} +% After adding arguments we better set the boolean false in case we +% don't have an insert marker. +% \begin{macrocode} +% \end{macrocode} +% First we add the remaining |m| arguments. +% \begin{macrocode} +% \end{macrocode} +% Then we run the loop again. +% \begin{macrocode} + \xparse_read_arg_type_or_grab_default:n + } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\xparse_check_and_add_argument_type:N} +% This function checks if the argument type actually exists and gives +% an error if it doesn't. +% \begin{macrocode} +\def_new:NNn \xparse_check_and_add_argument_type:N 1 { + \cs_free:cTF {xparse_add_arg_type_#1:} + { \xparse_unknown_arg_type_error_msg:N #1 + \int_incr:N \l_xparse_mandatory_args_int + } +% \end{macrocode} +% Otherwise we just add it with its dedicated function. +% \begin{macrocode} + { \cs_use:c {xparse_add_arg_type_#1:} } +} +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\xparse_read_arg_type_or_grab_default:n} +% \begin{macro}{\xparse_grab_default_arg:n} +% \begin{macro}{\xparse_grab_default_arg_allow_par:n} +% The function for grabbing a default value. The default setting is +% just to tun the loop again. However, some argument types need to +% add a default argument so we add these as well. +% \begin{macrocode} +\let_new:NN \xparse_read_arg_type_or_grab_default:n + \xparse_parse_signature:n +\def_new:NNn \xparse_grab_default_arg:n 1{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks {{#1}} + \let:NN \xparse_read_arg_type_or_grab_default:n + \xparse_parse_signature:n + \xparse_parse_signature:n +} +\def_long_new:NNn \xparse_grab_default_arg_allow_par:n 1{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks {{#1}} + \let:NN \xparse_read_arg_type_or_grab_default:n + \xparse_parse_signature:n + \xparse_parse_signature:n +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% +% +% +% \subsubsection{The default argument types} +% +% +% +% When scanning the signature we need to add the argument type which +% is done by a function |\xparse_add_arg_type_|\meta{X}|:|, where +% \meta{X} is the letter denoting the argument type. If not found an +% error message is issued ny |\xparse_unknown_arg_type_error_msg:N|. +% +% By default the package implements the argument types |m|, |S|, |c|, +% |C|, |o|, and |O| argument types as low level ones. The |s| type is +% a shorthand as we shall see later. +% +% As we don't make every single |m| argument a separate grabber all +% other types must clear out any pending |m|s. +% +% \paragraph{Mandatory arguments} +% +% Below follows the implementation of mandatory arguments. +% +% \begin{macro}{\xparse_add_arg_type_m:} +% Check if the user asked for an |m| argument allowing |\par| +% tokens and insert it. Otherwise increment the number of +% non-|\long| argument grabbers. +% \begin{macrocode} +\def_new:Npn \xparse_add_arg_type_m: { + \bool_if:NTF \g_xparse_allow_par_bool + { + \toks_put_right:Nn \l_xparse_grabbed_args_toks {\xparse_allow_par_m:w} + } + { \int_incr:N \l_xparse_mandatory_args_int } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\xparse_add_remaining_m_args:} +% And here is the function for clearing out normal pending |m| +% arguments. There is little point in adding any arguments if none +% are required. +% \begin{macrocode} +\def_new:Npn \xparse_add_remaining_m_args: { + \int_compare:nNnF \l_xparse_mandatory_args_int = \c_zero + { + \toks_put_right:Nx \l_xparse_grabbed_args_toks { + \exp_not:c{xparse_m + \int_use:N \l_xparse_mandatory_args_int + :w } + } + \int_zero:N \l_xparse_mandatory_args_int + } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\xparse_m1:w} +% \begin{macro}{\xparse_m2:w} +% \begin{macro}{\xparse_m3:w} +% \begin{macro}{\xparse_m4:w} +% \begin{macro}{\xparse_m5:w} +% \begin{macro}{\xparse_m6:w} +% \begin{macro}{\xparse_m7:w} +% \begin{macro}{\xparse_m8:w} +% \begin{macro}{\xparse_m9:w} +% Grabbing 1--9 mandatory arguments. The one grabbing nine arguments +% will automatically end with +% |\toks_use:N \l_xparse_grabbed_args_toks| anyway so we avoid +% problems with that one. +% \begin{macrocode} +\def_new:cpn {xparse_m1:w} #1 \l_xparse_grabbed_args_toks#2{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks{{#2}} + #1 \l_xparse_grabbed_args_toks +} +\def_new:cpn {xparse_m2:w} #1 \l_xparse_grabbed_args_toks #2#3{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks{{#2}{#3}} + #1 \l_xparse_grabbed_args_toks +} +\def_new:cpn {xparse_m3:w} #1 \l_xparse_grabbed_args_toks #2#3#4{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks{{#2}{#3}{#4}} + #1 \l_xparse_grabbed_args_toks +} +\def_new:cpn {xparse_m4:w} #1 \l_xparse_grabbed_args_toks #2#3#4#5{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks{{#2}{#3}{#4}{#5}} + #1 \l_xparse_grabbed_args_toks +} +\def_new:cpn {xparse_m5:w} #1 \l_xparse_grabbed_args_toks #2#3#4#5#6{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks{{#2}{#3}{#4}{#5}{#6}} + #1 \l_xparse_grabbed_args_toks +} +\def_new:cpn {xparse_m6:w} #1 \l_xparse_grabbed_args_toks #2#3#4#5#6#7{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks + {{#2}{#3}{#4}{#5}{#6}{#7}} + #1 \l_xparse_grabbed_args_toks +} +\def_new:cpn {xparse_m7:w} #1 \l_xparse_grabbed_args_toks#2#3#4#5#6#7#8{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks + {{#2}{#3}{#4}{#5}{#6}{#7}{#8}} + #1 \l_xparse_grabbed_args_toks +} +\def_new:cpn {xparse_m8:w} #1\l_xparse_grabbed_args_toks + #2#3#4#5#6#7#8#9{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks + {{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}} + #1 \l_xparse_grabbed_args_toks +} +\def_new:cpn {xparse_m9:w} \toks_use:N \l_xparse_grabbed_args_toks + #1#2#3#4#5#6#7#8#9{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks + {{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}} + \toks_use:N \l_xparse_grabbed_args_toks +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\xparse_allow_par_m:w} +% The |m| type allowing |\par| tokens. We only define one of them as +% two in a row would be quite rare. +% \begin{macrocode} +\def_long_new:Npn \xparse_allow_par_m:w #1 \l_xparse_grabbed_args_toks#2{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks{{#2}} + #1 \l_xparse_grabbed_args_toks +} +% \end{macrocode} +% \end{macro} +% +% \paragraph{Arguments delimited by a left brace} +% +% \begin{macro}{\xparse_add_arg_type_l:} +% \begin{macro}{\xparse_l:w} +% \begin{macro}{\xparse_allow_par_l:w} +% This is almost exactly the same as the |m| type except we read +% everything up to the first left brace. +% \begin{macrocode} +\def_new:Npn \xparse_add_arg_type_l: { + \xparse_add_remaining_m_args: + \bool_if:NTF \g_xparse_allow_par_bool + { + \toks_put_right:Nn \l_xparse_grabbed_args_toks {\xparse_allow_par_l:w} + } + { \toks_put_right:Nn \l_xparse_grabbed_args_toks {\xparse_l:w} } +} +\def_new:Npn \xparse_l:w #1 \l_xparse_grabbed_args_toks#2#{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks{{#2}} + #1 \l_xparse_grabbed_args_toks +} +\def_long_new:Npn \xparse_allow_par_l:w #1 \l_xparse_grabbed_args_toks#2#{ + \toks_put_right:Nn \l_xparse_grabbed_args_toks{{#2}} + #1 \l_xparse_grabbed_args_toks +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \paragraph{Adding a symbol argument type} +% +% +% \begin{macro}{\DeclareSymbolArgument} +% The actual grabber functions just issue a |\peek_meaning_remove:NTF| +% or similar on the symbol chosen. If found, we put a |\c_true| on the +% argument stack and |\c_false| otherwise. +% \begin{macrocode} +\def_new:NNn \DeclareSymbolArgument 2{ + \seq_map_variable:NNn \g_xparse_ignore_marker_seq \l_tmpa_tlp { + \def:cpx {xparse \l_tmpa_tlp _#1:w}##1##2\l_xparse_grabbed_args_toks{ + \exp_not:c{peek_ #2 _remove \l_tmpa_tlp :NTF} ##1 + { + \exp_not:N \toks_put_right:Nn \exp_not:N + \l_xparse_grabbed_args_toks \exp_not:N \c_true + ##2 \exp_not:N\l_xparse_grabbed_args_toks + } + { + \exp_not:N \toks_put_right:Nn \exp_not:N + \l_xparse_grabbed_args_toks \exp_not:N \c_false + ##2 \exp_not:N\l_xparse_grabbed_args_toks + } + } + } +% \end{macrocode} +% Implementing a symbol type is fairly straight forward. It needs to +% grab a default argument. First we must clear out any pending |m| +% arguments. +% \begin{macrocode} + \def:cpn {xparse_add_arg_type_#1:} { + \xparse_add_remaining_m_args: + \toks_put_right:Nx \l_xparse_grabbed_args_toks + { \exp_not:c {xparse \g_xparse_ignore_marker_tlp _#1:w } } +% \end{macrocode} +% Nothing special when building the signature: We always grab a single +% default argument. +% \begin{macrocode} + \let:NN \xparse_read_arg_type_or_grab_default:n \xparse_grab_default_arg:n + } +} +% \end{macrocode} +% It is this easy now: +% \begin{macrocode} +\DeclareSymbolArgument S{meaning} +% \end{macrocode} +% \end{macro} +% +% +% \paragraph{Adding delimited arguments} +% +% +% \begin{macro}{\DeclareArgumentType} +% Argument types that read their argument delimited as the |o| type +% can be defined with this function. |#1| is the letter associated +% with the type, |#3| is the test type we should use, i.e., +% meaning, charcode or catcode. |#2| is the left delimiter \LaTeX{} +% will look for, |#4| can be used for an error message or such in +% case of a missing value, and |#5| the value inserted in case the +% optional argument is missing. The last two arguments control how +% the arguments are picked up and parsed on to the inner parsing. +% \begin{macrocode} +\def_new:NNn \DeclareArgumentType 7{ +% \end{macrocode} +% For instance, we want |\DeclareArgumentType a{charcode}[...| to +% define the function |\xparse_ignore_spaces_a:w| with meaning +% |\peek_charcode_ignore_spaces:NTF [{...}{...}|. We want to define a +% series of functions for each of these delimited argument types. One +% for each of the |ignore| types plus an identical version of each of +% these allowing the |\par| token in the argument. All the different +% ignore types are stored in the sequence +% |\g_xparse_ignore_marker_seq| so we go through that when doing the +% definitions. +% \begin{macrocode} + \seq_map_variable:NNn \g_xparse_ignore_marker_seq \l_tmpa_tlp { + \def:cpx {xparse \l_tmpa_tlp _#1:w}##1\l_xparse_grabbed_args_toks{ + \exp_not:c{peek_#3 \l_tmpa_tlp :NTF} \exp_not:N #2 + { \exp_not:c{xparse_#1_#3_help:nw}{##1} } + { + \exp_not:n { + #4 \toks_put_right:Nn \l_xparse_grabbed_args_toks {#5} + } + ##1 \exp_not:N\l_xparse_grabbed_args_toks + } + } +% \end{macrocode} +% And now an almost identical version which allows the |\par| token. +% \begin{macrocode} + \def_long:cpx {xparse_allow_par \l_tmpa_tlp _#1:w}##1 + \l_xparse_grabbed_args_toks{ + \exp_not:c{peek_#3 \l_tmpa_tlp :NTF} \exp_not:N #2 + { \exp_not:c{xparse_allow_par_#1_#3_help:nw}{##1} } + { + \exp_not:n { + #4 \toks_put_right:Nn \l_xparse_grabbed_args_toks {#5} + } + ##1 \exp_not:N\l_xparse_grabbed_args_toks + } + } + } +% \end{macrocode} +% Here is the function for building the argument grabbing. We clear +% out the remaining |m| arguments first. +% \begin{macrocode} + \def:cpn {xparse_add_arg_type_#1:} { + \xparse_add_remaining_m_args: + \toks_put_right:Nx \l_xparse_grabbed_args_toks { + \exp_not:c {xparse +% \end{macrocode} +% Insert |_allow_par| in the csname if needed. This also applies to +% the argument grabber (although this should probably just be the +% default). +% \begin{macrocode} + \bool_if:NT \g_xparse_allow_par_bool {_allow_par} + \g_xparse_ignore_marker_tlp + _#1:w + } + } + \let:NN \xparse_read_arg_type_or_grab_default:n \xparse_parse_signature:n + } +% \end{macrocode} +% Now all we need to do is to define the helper functions. +% \begin{macrocode} + \xparse_define_helper:Nnnn #1{#3}{#6}{#7} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\DeclareArgumentTypeDefaultValue} +% The same as above but expects a default value in the signature. +% Therefore it doesn't have the arguments of the default value and +% what to do if it is missing like the above. +% \begin{macrocode} +\def_new:NNn \DeclareArgumentTypeDefaultValue 5{ + \seq_map_variable:NNn \g_xparse_ignore_marker_seq \l_tmpa_tlp { + \def:cpx {xparse \l_tmpa_tlp _#1:w}##1##2\l_xparse_grabbed_args_toks{ + \exp_not:c{peek_#3 \l_tmpa_tlp :NTF} \exp_not:N #2 + { \exp_not:c{xparse_#1_#3_help:nw}{##2} } + { + \exp_not:N \toks_put_right:Nn + \exp_not:N \l_xparse_grabbed_args_toks {{##1}} + ##2 \exp_not:N \l_xparse_grabbed_args_toks + } + } +% \end{macrocode} +% And now an almost identical version which allows the |\par| token. +% \begin{macrocode} + \def_long:cpx {xparse_allow_par \l_tmpa_tlp _#1:w}##1##2 + \l_xparse_grabbed_args_toks{ + \exp_not:c{peek_#3 \l_tmpa_tlp :NTF} \exp_not:N #2 + { \exp_not:c{xparse_allow_par_#1_#3_help:nw}{##2} } + { + \exp_not:N \toks_put_right:Nn + \exp_not:N \l_xparse_grabbed_args_toks {{##1}} + ##2 \exp_not:N \l_xparse_grabbed_args_toks + } + } + } +% \end{macrocode} +% Here is the function for building the argument grabbing. We clear +% out the remaining |m| arguments first. +% \begin{macrocode} + \def:cpn {xparse_add_arg_type_#1:} { + \xparse_add_remaining_m_args: + \toks_put_right:Nx \l_xparse_grabbed_args_toks { + \exp_not:c {xparse +% \end{macrocode} +% Insert |_allow_par| in the csname if needed. This also applies to +% the argument grabber (although this should probably just be the +% default). +% \begin{macrocode} + \bool_if:NT \g_xparse_allow_par_bool {_allow_par} + \g_xparse_ignore_marker_tlp + _#1:w + } + } + \let:Nc \xparse_read_arg_type_or_grab_default:n + {xparse_grab_default_arg + \bool_if:NT \g_xparse_allow_par_bool {_allow_par} + :n + } + } +% \end{macrocode} +% Now all we need to do is to define the helper functions. +% \begin{macrocode} + \xparse_define_helper:Nnnn #1{#3}{#4}{#5} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\xparse_define_helper:Nnnn} +% All we need now is the helper functions. We define a generic +% interface that should be fairly easy to use. +% \begin{macrocode} +\def_new:NNn \xparse_define_helper:Nnnn 4{ + \toks_set:Nn \l_tmpa_toks + { + #3 + { +% \end{macrocode} +% Remember to add an extra set of braces here. +% \begin{macrocode} + \toks_put_right:Nn \l_xparse_grabbed_args_toks {{#4}} + ##1 \l_xparse_grabbed_args_toks + } + } +% \end{macrocode} +% The next bit looks a little ugly but that's life. +% \begin{macrocode} + \toks_set:Nx \l_tmpa_toks { + \exp_not:n {\def:cpn{xparse_#1_#2_help:nw}} + \toks_use:N \l_tmpa_toks + \exp_not:n {\def:cpn{xparse_allow_par_#1_#2_help:nw}} + \toks_use:N\l_tmpa_toks + } + \toks_use:N \l_tmpa_toks +} +% \end{macrocode} +% \end{macro} +% +% All the above may seem like an awful lot of trouble but it is +% general and it allows the following simple definitions: +% \begin{macrocode} +\DeclareArgumentType o[{meaning}{}{\NoValue}{#1[#2]}{#2} +% \end{macrocode} +% For the |c| type we add give an error message. +% \begin{macrocode} +\DeclareArgumentType c({meaning}{ + \xparse_error:x{ + Missing~ coordinate~ argument.~ A~ value~ of~ (0,0)~ is~ assumed} + } + {{00}} + {#1(#2,#3)}{{#2}{#3}} +\DeclareArgumentTypeDefaultValue O[{meaning}{#1[#2]}{#2} +\DeclareArgumentTypeDefaultValue C({meaning}{#1(#2,#3)}{{#2}{#3}} +% \end{macrocode} +% One could also do +% \begin{verbatim} +% \DeclareArgumentTypeDefaultValue O[{charcode}{#1#2#3]}{#3} +% \end{verbatim} +% where argument |#2| is the bracket but not requiring it to have +% catcode~12. However we can't use the same trick for reading the end +% of the argument. +% +% Another interesting one could be +% \begin{verbatim} +% \DeclareArgumentType a\c_group_begin_token{catcode}{}{\NoValue}{#1#2}{#2} +% \end{verbatim} +% which would basically be an optional argument in braces. +% +% +% +% \subsubsection{Argument shorthands} +% +% +% \begin{macro}{\DeclareArgumentTypeShorthand} +% Letting a letter or symbol be a shorthand for a more complicated +% structure is rather easy actually. All we need to do is to gobble +% the remainder of the main loop in the signature creation until +% |\xparse_parse_signature:n|, decrement the argument counter, put +% in the replacement argument specifiers and start the loop +% again. The disadvantage of this scheme is that we have to cheat +% and give it the wrong name as it should have a |w| argument +% specification but I hope you can forgive this little white lie. +% \begin{macrocode} +\def_new:NNn \DeclareArgumentTypeShorthand 2{ + \def_new:cpn {xparse_add_arg_type_#1:} + ##1 \xparse_read_arg_type_or_grab_default:n { + \int_decr:N \l_xparse_total_args_int + \xparse_read_arg_type_or_grab_default:n #2 + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\xparse_add_arg_type_s:} +% Defining the |s| type is easy now since it really means |S{*}|. +% \begin{macrocode} +\DeclareArgumentTypeShorthand s {S{*}} +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Checking for optional values} +% +% +% \begin{macro}{\IfBooleanTF} +% \begin{macro}{\IfBooleanT} +% \begin{macro}{\IfBooleanF} +% The logical \meta{true} and \meta{false} statements are just our +% normal |\c_true| and |\c_false| so testing for them is done with +% our usual |\prg_if_predicate:nTF| functions from \textsf{l3prg}. +% \begin{macrocode} +\let_new:NN \IfBooleanTF \prg_if_predicate:nTF +\let_new:NN \IfBooleanT \prg_if_predicate:nT +\let_new:NN \IfBooleanF \prg_if_predicate:nF +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\NoValue} +% \begin{macro}{\c_xparse_hidden_no_value_tlp} +% |\NoValue| is just a text string and we define it as a token list +% pointer. However we will actually test for token list pointers +% with \emph{meaning} |\NoValue|. Hence if an argument is really +% |-NoValue-| it will not be detected but that shouldn't happen. +% \begin{macrocode} +\tlp_new:Nn \NoValue {-NoValue-} +\tlp_new:Nn \c_xparse_hidden_no_value_tlp {\NoValue} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\xparse_if_no_value:nTF} +% The test start by making a token list pointer out of the first +% argument and then check if it is equal to +% |\c_xparse_hidden_no_value_tlp| which contains |\NoValue|. +% \begin{macrocode} +\def_long_new:Npn \xparse_if_no_value:nTF #1{ + \tlp_set:Nx \l_tmpa_tlp{\exp_not:n{#1}} + \tlp_if_eq:NNTF \l_tmpa_tlp \c_xparse_hidden_no_value_tlp +% \end{macrocode} +% If they are equal we just exit and execute the \meta{true} code. +% \begin{macrocode} + { \use_arg_i:nn } +% \end{macrocode} +% If not, take a closer look at |#1|. Peek ahead at the first token in +% |#1| and then call the function |\xparse_if_no_value_aux:| but only +% if |#1| is not empty or a blank space: in that case we can execute +% the \meta{false} code immediately. We must use this test at some +% point otherwise the macros for checking tokens will break since the +% argument may be empty. +% \begin{macrocode} + { \tlist_if_blank:nTF {#1} + { \use_arg_ii:nn } + {\peek_after:NN \xparse_if_no_value_aux: #1 \q_nil {#1} } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\xparse_if_no_value_aux:} +% Now we simply check the argument specification of the token. If +% it is not a macro the function |\token_get_arg_spec:N| returns +% |\scan_stop:|. +% \begin{macrocode} +\def_long_new:Npn \xparse_if_no_value_aux: { + \tlp_set:Nx \l_tmpa_tlp{\token_get_arg_spec:N \l_peek_token } +% \end{macrocode} +% Then check if |\l_tmpa_tlp| is empty, because this means we have a +% macro taking zero arguments and we can expand it once +% safely. Otherwise we just exit and execute the false code. Remember +% that we have the sequence |{#1}| waiting after the |\q_nil| in +% |\xparse_if_no_value:nTF| above. +% \begin{macrocode} + \tlp_if_empty:NTF \l_tmpa_tlp + {\use_arg_i_delimit_by_q_nil:nw {\exp_args:No\xparse_if_no_value:nTF}} + {\use_arg_i_delimit_by_q_nil:nw {\use_arg_iii:nnn}} +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\IfNoValueTF} +% \begin{macro}{\IfNoValueT} +% \begin{macro}{\IfNoValueF} +% \begin{macro}{\IfValueTF} +% \begin{macro}{\IfValueT} +% \begin{macro}{\IfValueF} +% |\IfNoValueTF| and its varieties are implemented as subcases of +% |\xparse_if_no_value:nTF|. +% \begin{macrocode} +\let_new:NN \IfNoValueTF \xparse_if_no_value:nTF +\def_long_new:NNn \IfNoValueT 2 {\xparse_if_no_value:nTF{#1}{#2}{}} +\def_long_new:NNn \IfNoValueF 1 {\xparse_if_no_value:nTF {#1}{}} +% \end{macrocode} +% For |\IfValueTF| we just reverse the arguments. +% \begin{macrocode} +\def_long_new:NNn \IfValueTF 3{\xparse_if_no_value:nTF {#1}{#3}{#2}} +\let_new:NN \IfValueT \IfNoValueF +\let_new:NN \IfValueF \IfNoValueT +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \subsection{Pseudo arguments} +% +% \begin{macro}{\l_xparse_pseudo_post_arg_tlp} +% A temporary token list pointer to store the post-arguments. +% \begin{macrocode} +\tlp_new:Nn \l_xparse_pseudo_post_arg_tlp {} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\DeclarePseudoArgument} +% Must be called at the end of the replacement text. Can use the +% parameters picked up so far. |#1| is a name for it, |#2| is the +% number of arguments, |#3| is the pre-argument definition, |#4| is +% the post-argument definition. The idea here is to define two +% functions: One to execute before the special pseudo argument is +% found and one to to it afterwards. Hence we define such two +% functions with |#2| arguments and definitions |#3| and |#4| +% respectively. +% \begin{macrocode} +\def_long_new:NNn \DeclarePseudoArgument 4{ + \def_long:cNn {xparse_pseudo_pre_arg_#1:\prg_replicate:nn{#2}{n}}#2{#3} + \def_long:cNn {xparse_pseudo_post_arg_#1:\prg_replicate:nn{#2}{n}}#2{#4} +% \end{macrocode} +% In case the user doesn't put the argument in braces, it must be a +% single token which we just grab and then execute the +% post-argument. Surely it won't be a |\par| token! +% \begin{macrocode} + \def:cNn {xparse_pseudo_nobrace_arg_#1:N} 1 { + ##1 \l_xparse_pseudo_post_arg_tlp + } +% \end{macrocode} +% The regular version of the command is then this: +% \begin{enumerate} +% \item Execute the pre-code at level $n$. +% \item Store the post-code in a token list pointer at level $n$. +% \item Look for a begin-group token. +% \item[4a] If found, remove it, start a group (level $n+1$) and make +% sure the token list pointer from 2) is executed after the group +% has ended (at level $n$). +% \item[4b] If not found, call the |nobrace_arg| version which also +% executes the token list pointer from 2) at level $n$. +% \end{enumerate} +% This scheme enables these commands to be nested since they all +% appear at different grouping levels. +% +% Next we define the function. Also make sure that it gets all the +% arguments carried over to the post-argument. +% \begin{macrocode} + \def_long:cNx {xparse_pseudo_arg_#1:w} #2 + { + \exp_not:c { + xparse_pseudo_pre_arg_#1: \prg_replicate:nn{#2}{n} + } + \cs_use:c{def_aux_use_\int_use:N \int_eval:n{#2}_parameter:} + \exp_not:n {\tlp_set:Nn \l_xparse_pseudo_post_arg_tlp} + { + \exp_not:c {xparse_pseudo_post_arg_#1:\prg_replicate:nn{#2}{n}} + \cs_use:c{def_aux_use_\int_use:N \int_eval:n{#2}_parameter:} + } + \exp_not:n{ \peek_catcode_remove_ignore_spaces:NTF \c_group_begin_token } + { +% \end{macrocode} +% Here we insert the left brace token which was removed removed. +% In case you're wondering then yes, I know that |\c_group_begin_token| +% and |\group_execute_after:N| are unexpandable but I prefer this method +% because I don't want to remember which commands are expandable and +% which are not. +% \begin{macrocode} + \exp_not:n { + \c_group_begin_token + \group_execute_after:N \l_xparse_pseudo_post_arg_tlp + } + } + { + \exp_not:c{xparse_pseudo_nobrace_arg_#1:N} + } + } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\UsePseudoArgument} +% Just a nice wrapper for calling such an argument. +% \begin{macrocode} +\def_new:NNn \UsePseudoArgument 1{\cs_use:c{xparse_pseudo_arg_#1:w}} +% \end{macrocode} +% \end{macro} +% +% +% +% +% \Finale +% +\endinput +% +% $Log$ +% Revision 1.25 2006/07/17 22:25:53 morten +% Minor change to reflect change in l3basics.dtx +% +% Revision 1.24 2006/07/08 22:44:29 morten +% Fixed two lurking problems in \xparse_if_no_value:nTF. +% +% Revision 1.23 2006/07/06 14:56:04 morten +% Change to use new \def:NNn syntax +% +% Revision 1.22 2006/01/17 23:04:08 morten +% Added `l' type argument for reading up to a left brace. +% +% Revision 1.21 2006/01/04 02:42:35 morten +% Changed RCS information retrieval. Rewrote \DeclareArgumentType and +% its relatives in order for them to work properly with the new \peek_ +% functions. Changed how special markers are inserted into the +% signature. Added `pseudo arguments'. Updated documentation to reflect +% all these changes. And more which I can't remember right now :-) +% +% Revision 1.20 2005/04/06 21:24:47 morten +% Total rewrite - there is only one implementation in the package +% now. Documentation updated to match the changes. +% +% +% |