%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \iffalse %%%% % % % Copyright (c) 2012 - Michiel Helvensteijn (www.mhelvens.net) % % % % http://latex-concepts.googlecode.com % % % % This work may be distributed and/or modified under the conditions % % of the LaTeX Project Public License, either version 1.3 of this % % license or (at your option) any later version. The latest version % % of this license is in http://www.latex-project.org/lppl.txt % % and version 1.3 or later is part of all distributions of LaTeX % % version 2005/12/01 or later. % % % % This work has the LPPL maintenance status `author-maintained'. % % % % The Current Maintainer of this work is Michiel Helvensteijn. % % % % This work consists of the files concepts.dtx and concepts.sty. % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \fi %%%% % \CheckSum{175} % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \subsection{Package Info} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \begin{codeframe}\begin{macrocode} \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{concepts}[2012/12/08 0.0.4 managing names and symbols of document specific formal concepts] % \end{macrocode}\end{codeframe} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \subsection{Packages} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % These are the packages we'll need. % % \begin{codeframe}\begin{macrocode} \RequirePackage{etextools} \RequirePackage{nth} \RequirePackage{xspace} \RequirePackage{xparse} % 1 \RequirePackage{ltxkeys}[2012/11/17] % 2 \RequirePackage{xstring} % \end{macrocode}\end{codeframe} % % We need a very recent version of |ltxkeys| in order to properly handle % list-values. Note that |xparse| needs to be loaded before |ltxkeys| or % things go wrong somehow. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \subsection{Facilitating Easy Data Access} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \begin{macro}{\cnc@d} \marg{identifier} %%% \begin{macro}{\cnc@g} \marg{identifier}\\ % % This package needs to store and retrieve a lot of data. To make the rest of % the code more readable, we define the following commands. They allow a more % freeform description of the data. % % |\cnc@d| returns a control sequence name that resolves % to a specific piece of data in |\csname| context. % We can get access to the data itself by using |\cnc@g|. % % \begin{codeframe}\begin{macrocode} \newcommand*{\cnc@d}[1]{cnc@data@#1} \newcommand*{\cnc@g}[1]{\csuse{\cnc@d{#1}}} % \end{macrocode}\end{codeframe} % % Both take an identifier of one the following shapes: % \begin{itemize} % \item |concepts| % \item |concept|\parg{name}|.option|\parg{name} % \item |concept|\parg{name}|.option|\parg{name}|.given| % \item |concept|\parg{name}|.option|\parg{name}|.count| % \item |concept|\parg{name}|.option|\parg{name}|.index|\parg{number} % \item |symbol|\parg{name}|.concept| % \end{itemize} % %\end{macro}\end{macro}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \subsection{Private General Purpose Macros and Toggles} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% \begin{macro}{\cnc@upper} \marg{string}\\ % % We're going to need a command that capitalizes the first letter of a string % which fully expands its argument. So here it is. % % \begin{codeframe}\begin{macrocode} \newcommand*{\cnc@upper}[1]{\ExpandAftercmds\MakeUppercase{#1}} % \end{macrocode}\end{codeframe} % %\end{macro}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% \begin{macro}{\cnc@grabnumber} \marg{token sequence containing \#1} \momarg{number}\\ % % This is a command we're going to use for the automatically defined short % symbol macros later. It has one 'real' mandatory argument and then it % captures all numerals (0\ldots 9) that follow it. These numerals are then substituted % for all occurrences of \#1 in the mandatory argument which is then `returned'. % % \begin{codeframe}\begin{macrocode} \newcommand{\cnc@grabnumber}[1]{% \def\cnc@dowithnum##1{#1}% \futuredef[0123456789]{\cnc@@n}{\cnc@dowithnum{\cnc@@n}}% } % \end{macrocode}\end{codeframe} % %\end{macro}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \subsection{Private Specific-purpose Macros} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \begin{macro}{\cnc@conceptname} \marg{plural} \marg{capitalized} %%% \marg{plural} \marg{concept key}\\ % % This typesets the name of a specific concept in one of four forms. It % can be capitalized or not; and it can be singular or plural. We define % this private macro because there will be two public macros with this % functionality and we want to define the behavior in only one place. % % The first three arguments are |xparse| style booleans. The first and % third are the same because the public macros allow both orders between % the |*| and |^| modifiers and we want to have a simple one-to-one % mapping between their arguments and the arguments of this private macro. % % \begin{codeframe}\begin{macrocode} \newcommand{\cnc@conceptname}[4]{% % \end{macrocode}\end{codeframe} % % We test if \emph{both} the first and third arguments are true, meaning % that the public command has two |*| modifiers. If it does, we give a % package error. % % \begin{codeframe}\begin{macrocode} \ifboolexpr{ test{\IfBooleanTF{#1}} and test{\IfBooleanTF{#3}} }{% \PackageError{concepts}% {You used the * modifier twice; once is enough}% {I will pretend you just used one *.}% }{}% % \end{macrocode}\end{codeframe} % % And then we simply typeset the correct value from our datastore. % % \begin{codeframe}\begin{macrocode} \ifboolexpr{ test{\IfBooleanTF{#1}} or test{\IfBooleanTF{#3}} }{% \IfBooleanTF{#2}% {\cnc@g{concept(#4).option(Plural)}}% {\cnc@g{concept(#4).option(plural)}}% }{% \IfBooleanTF{#2}% {\cnc@g{concept(#4).option(Name)}}% {\cnc@g{concept(#4).option(name)}}% }% % \end{macrocode}\end{codeframe} % % We end with an |\xspace| because the public command may need one. % % \begin{codeframe}\begin{macrocode} \xspace% % \end{macrocode}\end{codeframe} % \begin{uninterestingcodeframe}\begin{macrocode} } % \end{macrocode}\end{uninterestingcodeframe} % %\end{macro}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% \begin{macro}{\cnc@conceptsymbol} \marg{concept key} \marg{index}\\ % % This is the private macro which takes a concept key and an index and returns % the corresponding symbol from our data-store. We use it in the public macros % that offer this functionality. % % \begin{codeframe}\begin{macrocode} \newcommand*{\cnc@conceptsymbol}[2]{% % \end{macrocode}\end{codeframe} % % We check if an actual numerical value was passed. % % \begin{codeframe}\begin{macrocode} \IfInteger{#2}{% % \end{macrocode}\end{codeframe} % % If we got one, we check whether it is larger than the number of symbols % allocated to the concept. % % \begin{codeframe}\begin{macrocode} \edef\cnc@symbolcount{\cnc@g{concept(#1).option(symbols).count}}% \ifnumcomp{#2}{>}{\cnc@symbolcount}{% % \end{macrocode}\end{codeframe} % % If it is, we report an `index out of bounds' error. We first prepare an % appropriate sentence fragment so the error message becomes more readable. % % \begin{codeframe}\begin{macrocode} \edef\cnc@nth{#2\nthSuff0#2\delimiter}% \ExpandNext\IfStrEq{\cnc@symbolcount}{0}{% \edef\cnc@somany{no symbols}% }{\ExpandNext\IfStrEq{\cnc@symbolcount}{1}{% \edef\cnc@somany{only 1 symbol}% }{% \edef\cnc@somany{only \cnc@symbolcount\space symbols}% }}% \PackageError{concepts}% {You asked for the \cnc@nth\space '#1' symbol, but\MessageBreak the '#1' concept has \cnc@somany\space allocated}% {I will pretend you didn't ask for a symbol here.}% % \end{macrocode}\end{codeframe} % \begin{uninterestingcodeframe}\begin{macrocode} }% % \end{macrocode}\end{uninterestingcodeframe} % % But if the number is within bounds, great! We just return the stored symbol. % % \begin{codeframe}\begin{macrocode} {% \cnc@g{concept(#1).option(symbols).index(#2)}% }% % \end{macrocode}\end{codeframe} % \begin{uninterestingcodeframe}\begin{macrocode} }% % \end{macrocode}\end{uninterestingcodeframe} % % Now follows the `else' branch: we didn't get a numerical index. % % \begin{codeframe}\begin{macrocode} {% % \end{macrocode}\end{codeframe} % % If there is only one symbol allocated to this concept, we don't care % and return that symbol. % % \begin{codeframe}\begin{macrocode} \edef\cnc@symbolcount{\cnc@g{concept(#1).option(symbols).count}}% \ifnumcomp{\cnc@symbolcount}{=}{1}{% \cnc@g{concept(#1).option(symbols).index(1)}% }% % \end{macrocode}\end{codeframe} % % If there are multiple symbols, the lack of an index is ambiguous and % we report a package error. % % \begin{codeframe}\begin{macrocode} {% \PackageError{concepts}% {You didn't specify a number, but the '#1' \MessageBreak concept has more than one symbol allocated; please\MessageBreak specify a number to typeset a specific symbol}% {I will pretend you didn't ask for a symbol here.}% }% % \end{macrocode}\end{codeframe} % \begin{uninterestingcodeframe}\begin{macrocode} }% } % \end{macrocode}\end{uninterestingcodeframe} % %\end{macro}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \subsection{Public Macros} % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % We now implement the macros that will be used directly by package users. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% \begin{macro}{\NewConcept} \marg{concept key} \oarg{options}\\ % % The |\NewConcept| macro is defined using |xparse|, since we want the % optional argument after the mandatory one (it's just nicer). % % \begin{codeframe}\begin{macrocode} \NewDocumentCommand{\NewConcept}{m O{}}{% % \end{macrocode}\end{codeframe} % % Is this concept key already defined? If so, we report a package error. % % \begin{codeframe}\begin{macrocode} \xifinlist{#1}{\cnc@g{concepts}}{% \PackageError{concepts}% {The concept key '#1' is already taken}% {I will pretend that this '\protect\newconcept'% didn't happen.}% }% % \end{macrocode}\end{codeframe} % % Otherwise, we start the actual processing of this new concept. % % \begin{codeframe}\begin{macrocode} {% % \end{macrocode}\end{codeframe} % % We add the concept to the concepts list in our datastore. % % \begin{codeframe}\begin{macrocode} \listcsxadd{\cnc@d{concepts}}{#1}% % \end{macrocode}\end{codeframe} % % We then check which options were explicitly specified by the user. % This results in a set of toggles in our datastore, which may % be used by other code. % % \begin{codeframe}\begin{macrocode} \DeclareRobustCommand*{\cnc@registertoggle}[1]{% \newtoggle{\cnc@d{concept(#1).option(##1).given}}% \togglefalse{\cnc@d{concept(#1).option(##1).given}}% \ltxkeys@newordkey[cnc@toggle]{#1}{##1}[]% {\toggletrue{\cnc@d{concept(#1).option(##1).given}}}% } \cnc@registertoggle{name}% \cnc@registertoggle{Name}% \cnc@registertoggle{plural}% \cnc@registertoggle{Plural}% \cnc@registertoggle{namecmd}% \cnc@registertoggle{symbols}% \cnc@registertoggle{symbolcmd}% \ltxkeys@setkeys*[cnc@toggle]{#1}{#2}% % \end{macrocode}\end{codeframe} % % We now register the concept name options |name|, |Name|, % |plural| and |Plural|. This is also where we set their default values. % % \begin{codeframe}\begin{macrocode} \ltxkeys@newordkey[cnc]{#1}{name}% [#1]% {\csdef{\cnc@d{concept(#1).option(name)}}{##1}}% \ltxkeys@newordkey[cnc]{#1}{Name}% [\cnc@upper{\cnc@g{concept(#1).option(name)}}]% {\csdef{\cnc@d{concept(#1).option(Name)}}{##1}}% \ltxkeys@newordkey[cnc]{#1}{plural}% [\cnc@g{concept(#1).option(name)}s]% {\csdef{\cnc@d{concept(#1).option(plural)}}{##1}}% \ltxkeys@newordkey[cnc]{#1}{Plural}% [\cnc@upper{\cnc@g{concept(#1).option(plural)}}]% {\csdef{\cnc@d{concept(#1).option(Plural)}}{##1}}% % \end{macrocode}\end{codeframe} % % We next register the |namecmd| option. Its default value is the % concept key with a |\| in front of it. Unlike most other options, % though, we require the option name to be explicitly given by the % user to actually define the macro. The following code also % contains the test. % % \begin{codeframe}\begin{macrocode} \expandaftercmds{\ltxkeys@newordkey[cnc]{#1}{namecmd}% [}{\csname#1\endcsname}]{% \iftoggle{\cnc@d{concept(#1).option(namecmd).given}}{% % \end{macrocode}\end{codeframe} % % We register the option value as given. % % \begin{codeframe}\begin{macrocode} \csdef{\cnc@d{concept(#1).option(namecmd)}}{\noexpand##1} % \end{macrocode}\end{codeframe} % %%% \vphantom{x}\marginnote{\meta{namecmd}} |[*]| |[^]| |[*]|\\ % % \noindent If the option is processed, we define the concept-specific % name command with the following code: % % \begin{codeframe}\begin{macrocode} \NewDocumentCommand{##1}{t* t^ t*}{% \cnc@conceptname{####1}{####2}{####3}{#1}% }% % \end{macrocode}\end{codeframe} % \begin{uninterestingcodeframe}\begin{macrocode} }{}% }% % \end{macrocode}\end{uninterestingcodeframe} % % We now register the |symbols| option. This option expects a list. % The callback of the following code processes it one symbol at a time. % And we first initialize the symbol counter to 0 in case the list is % empty % % \begin{codeframe}\begin{macrocode} \csdef{\cnc@d{concept(#1).option(symbols).count}}{0}% \ltxkeys@newlistkey[cnc]{#1}{symbols}[]{% % \end{macrocode}\end{codeframe} % % We check if this particular symbol is already defined. We don't want % a symbol allocated to different concepts. Or allocated twice to the % same concept, for that matter. If all is fine, we update the symbol % counter for this concept, we add the symbol itself and we update % the reverse map we use for checking duplicates. % % \begin{codeframe}\begin{macrocode} \ifcsundef{\cnc@d{symbol(\detokenize{##1}).concept}}{% \csedef{\cnc@d{concept(#1)% .option(symbols)% .count}}{\ltxkeys@listcount}% \csdef{\cnc@d{concept(#1)% .option(symbols)% .index(\ltxkeys@listcount)}}{##1}% \csedef{\cnc@d{symbol(\detokenize{##1}).concept}}{#1}% }% % \end{macrocode}\end{codeframe} % % If the symbol is already in use we report a package error. % % \begin{codeframe}\begin{macrocode} {% \PackageError{concepts}% {The symbol '\detokenize{##1}' is already allocated to the '\cnc@g{symbol(\detokenize{##1}).concept}' concept}% {I will pretend that you did not try to add this symbol.}% }% % \end{macrocode}\end{codeframe} % \begin{uninterestingcodeframe}\begin{macrocode} }% % \end{macrocode}\end{uninterestingcodeframe} % % We register the |symbolcmd| option. It does not really have a default, % but we give an empty default so we can test for the empty string inside. % % \begin{codeframe}\begin{macrocode} \ltxkeys@newordkey[cnc]{#1}{symbolcmd}[]{% \ifblank{##1}{}{% % \end{macrocode}\end{codeframe} % % We register the option value as given. % % \begin{codeframe}\begin{macrocode} \csdef{\cnc@d{concept(#1).option(symbolcmd)}}{\noexpand##1} % \end{macrocode}\end{codeframe} % %%% \vphantom{x}\marginnote{\meta{symbolcmd}} \momarg{index}\\ % % \noindent If the option is processed, we now define the concept-specific % `short' command used to typeset one of the allocated symbols. It doesn't have a % conventional argument, but it grabs all numerals following it and uses that % as an index to the symbol. % % \begin{codeframe}\begin{macrocode} \newrobustcmd*{##1}{% \cnc@grabnumber{% \cnc@conceptsymbol{#1}{########1}% }% }% % \end{macrocode}\end{codeframe} % \begin{uninterestingcodeframe}\begin{macrocode} }% }% % \end{macrocode}\end{uninterestingcodeframe} % % Finally, we issue the command to parse and process all options. % % \begin{codeframe}\begin{macrocode} \ltxkeys@launchkeys[cnc]{#1}{#2}% % \end{macrocode}\end{codeframe} % \begin{uninterestingcodeframe}\begin{macrocode} }% } % \end{macrocode}\end{uninterestingcodeframe} % %\end{macro}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% \begin{macro}{\ConceptOption} \marg{concept key} \marg{option key}\\ % % The point of this command is that it can retrieve any option value % in an expandable way. That means we can't use |xparse|, but we don't % need it. % % \begin{codeframe}\begin{macrocode} \newcommand*{\ConceptOption}[2]{% \cnc@g{concept(#1).option(#2)}% } % \end{macrocode}\end{codeframe} % % Unfortunately, as of writing this, not all options are stored in a % fully expandable way yet. But they will be in a later version. % %\end{macro}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% \begin{macro}{\ConceptName} |[*]| |[^]| |[*]| \marg{concept key}\\ % % This implementation simply calls our private macro for retrieving % the name in one of four forms. % % \begin{codeframe}\begin{macrocode} \NewDocumentCommand{\ConceptName}{t* t^ t* m}{% \cnc@conceptname{#1}{#2}{#3}{#4}% } % \end{macrocode}\end{codeframe} % %\end{macro}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% \begin{macro}{\ConceptSymbol} \marg{concept key} \oarg{index}\\ % % This implementation simply calls our private macro for retrieving % the symbol with the given index. The index is optional (as it is % in the `short' version) and defaults to 1. % % \begin{codeframe}\begin{macrocode} \NewDocumentCommand{\ConceptSymbol}{m O{1}}{% \cnc@conceptsymbol{#1}{#2}% } % \end{macrocode}\end{codeframe} % %\end{macro}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%