diff options
Diffstat (limited to 'macros/latex/contrib/stex/source')
22 files changed, 12590 insertions, 0 deletions
diff --git a/macros/latex/contrib/stex/source/Makefile b/macros/latex/contrib/stex/source/Makefile new file mode 100644 index 0000000000..c4af5ba15d --- /dev/null +++ b/macros/latex/contrib/stex/source/Makefile @@ -0,0 +1,5 @@ +# recurse into the directories. +MAKEDIRS = stex extensions + +all package doc: + @for d in $(MAKEDIRS); do (cd $$d && $(MAKE) -$(MAKEFLAGS) $@) || exit $$?; done diff --git a/macros/latex/contrib/stex/source/extensions/Makefile b/macros/latex/contrib/stex/source/extensions/Makefile new file mode 100644 index 0000000000..6a6b18a4c8 --- /dev/null +++ b/macros/latex/contrib/stex/source/extensions/Makefile @@ -0,0 +1,24 @@ +DTX = $(shell ls *.dtx) +DOC = $(DTX:%.dtx=%.pdf) +INS = extensions.ins + +PDFLATEX = pdflatex -interaction=batchmode +TEXDIR = ../../tex +TEXINPUTS = $(TEXDIR)//: + +all: package doc + +doc: $(DOC) + +package: $(DTX) $(INS) + $(PDFLATEX) $(INS) + mv *.sty *.cls $(TEXDIR) + +$(DOC): %.pdf: %.dtx + $(PDFLATEX) $< + biber -q $(basename $<) + $(PDFLATEX) $< + + +echo: + @echo $(DTX) diff --git a/macros/latex/contrib/stex/source/extensions/document-structure.dtx b/macros/latex/contrib/stex/source/extensions/document-structure.dtx new file mode 100644 index 0000000000..80c95d643b --- /dev/null +++ b/macros/latex/contrib/stex/source/extensions/document-structure.dtx @@ -0,0 +1,922 @@ +% \iffalse meta-comment +% A LaTeX Class and Package for OMDoc Document Structures +% Copyright (c) 2019 Michael Kohlhase, all rights reserved +% this file is released under the +% LaTeX Project Public License (LPPL) +% +% The original of this file is in the public repository at +% http://github.com/sLaTeX/sTeX/ +% +% +%<*driver> +\def\bibfolder{../../lib/bib} +\input{../../doc/docheader} + +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% %^^A \changes{v0.1}{2006/1/17}{First Version} +% +% \title{document-structure: Semantic Markup for Open Mathematical Documents in {\LaTeX} +% \thanks{Version {\fileversion} (last revised {\filedate})} +% } +% +% \author{Michael Kohlhase, Dennis Müller\\ +% FAU Erlangen-Nürnberg\\ +% \url{http://kwarc.info/} +% } +% +% \maketitle +% +%\ifinfulldoc\else +% This is the documentation for the \pkg{document-structure} package. +% For a more high-level introduction, +% see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the +% \href{\basedocurl/stex.pdf}{full \sTeX documentation}. +% +% \input{../../doc/packages/document-structure} +% \fi +% +% +% \begin{documentation}\label{pkg:documentstructure:doc} +% +% The |document-structure| package is part of the \sTeX collection, a version of {\TeX/\LaTeX} that +% allows to markup {\TeX/\LaTeX} documents semantically without leaving the document +% format, essentially turning {\TeX/\LaTeX} into a document format for mathematical +% knowledge management (MKM). +% +% This package supplies an infrastructure for writing {\omdoc} documents in {\LaTeX}. +% This includes a simple structure sharing mechanism for \sTeX that allows to to move +% from a copy-and-paste document development model to a copy-and-reference model, which +% conserves space and simplifies document management. The augmented structure can be +% used by MKM systems for added-value services, either directly from the \sTeX +% sources, or after translation. +% \begin{sfragment}[id=sec:STR]{Introduction} +% +% \sTeX is a version of {\TeX/\LaTeX} that allows to markup {\TeX/\LaTeX} documents +% semantically without leaving the document format, essentially turning {\TeX/\LaTeX} +% into a document format for mathematical knowledge management (MKM). The package +% supports direct translation to the {\omdoc} format~\cite{Kohlhase:OMDoc1.2} +% +% The |document-structure| package supplies macros and environments that allow to label document +% fragments and to reference them later in the same document or in other documents. In +% essence, this enhances the document-as-trees model to +% documents-as-directed-acyclic-graphs (DAG) model. This structure can be used by MKM +% systems for added-value services, either directly from the \sTeX sources, or after +% translation. Currently, trans-document referencing provided by this package can only be +% used in the \sTeX collection. +% +% DAG models of documents allow to replace the ``Copy and Paste'' in the source document +% with a label-and-reference model where document are shared in the document source and +% the formatter does the copying during document +% formatting/presentation.\ednote{integrate with latexml's XMRef in the Math mode.} +% \end{sfragment} +% +% \begin{sfragment}[id=sec:user]{The User Interface} +% +% The |document-structure| package generates two files: |document-structure.cls|, and |document-structure.sty|. The {\omdoc} +% class is a minimally changed variant of the standard |article| class that includes the +% functionality provided by |document-structure.sty|. The rest of the documentation pertains to the +% functionality introduced by |document-structure.sty|. +% +% \begin{sfragment}[id=sec:user:options]{Package and Class Options} +% +% The |document-strcture| class accept the following options: +% \begin{center} +% \begin{tabular}{|l|p{10cm}|}\hline +% \texttt{class=\meta{name}} & load \meta{name}|.cls| instead of |article.cls|\\\hline +% \texttt{topsect=\meta{sect}} & The top-level sectioning level; the default for +% \meta{sect} is \texttt{section}\\\hline +% \texttt{showignores} & show the the contents of the |ignore| environment after all \\\hline +% \texttt{showmeta} & show the metadata; see |metakeys.sty|\\\hline +% \texttt{showmods} & show modules; see |modules.sty|\\\hline +% \texttt{extrefs} & allow external references; see |sref.sty|\\\hline +% \texttt{defindex} & index definienda; see |statements.sty|\\\hline +% \texttt{minimal} & for testing; do not load any \sTeX packages\\\hline +% \end{tabular} +% \end{center} +% The |document-structure| package accepts the same except the first two. +% \end{sfragment} +% +% \begin{sfragment}[id=sec:user:struct]{Document Structure} +% +% The top-level \DescribeEnv{document}|document| environment can be given key/value +% information by the \DescribeMacro{\documentkeys}|\documentkeys| macro in the +% preamble\footnote{We cannot patch the document environment to accept an optional +% argument, since other packages we load already do; pity.}. This can be used to give +% metadata about the document. For the moment only the \DescribeMacro{id}|id| key is +% used to give an identifier to the \texttt{omdoc} element resulting from the {\latexml} +% transformation. +% +% The structure of the document is given by the \DescribeEnv{sfragment}|omgroup| +% environment just like in {\omdoc}. In the {\LaTeX} route, the |omgroup| environment is +% flexibly mapped to sectioning commands, inducing the proper sectioning level from the +% nesting of |omgroup| environments. Correspondingly, the |omgroup| environment takes an +% optional key/value argument for metadata followed by a regular argument for the +% (section) title of the omgroup. The optional metadata argument has the keys +% \DescribeMacro{id}|id| for an identifier, \DescribeMacro{creators}|creators| and +% \DescribeMacro{contributors}|contributors| for the Dublin Core +% metadata~\cite{DCMI:dmt03}; see~\cite{Kohlhase:dcm:git} for details of the format. The +% \DescribeMacro{short}|short| allows to give a short title for the generated +% section. If the title contains semantic macros, they need to be protected by +% |\protect|, and we need to give the \DescribeMacro{loadmodules}|loadmodules| key it +% needs no value. For instance we would have +% \begin{verbatim} +% \begin{smodule}{foo} +% \symdef{bar}{B^a_r} +% ... +% \begin{sfragment}[id=sec.barderiv,loadmodules]{Introducing $\protect\bar$ Derivations} +% \end{verbatim} +% +% \sTeX automatically computes the sectioning level, from the nesting of |omgroup| +% environments. But sometimes, we want to skip levels (e.g. to use a subsection* as an +% introduction for a chapter). Therefore the |document-structure| package provides a variant +% \DescribeEnv{blindfragment}|blindomgroup| that does not produce markup, but increments +% the sectioning level and logically groups document parts that belong together, but +% where traditional document markup relies on convention rather than explicit +% markup. The |blindomgroup| environment is useful e.g. for creating frontmatter at the +% correct level. Example~\ref{fig:docstruct} shows a typical setup for the outer +% document structure of a book with parts and chapters. We use two levels of +% |blindomgroup|: +% \begin{itemize} +% \item The outer one groups the introductory parts of the book (which we assume to have +% a sectioning hierarchy topping at the part level). This |blindomgroup| makes sure +% that the introductory remarks become a ``chapter'' instead of a ``part''. +% \item Th inner one groups the frontmatter\footnote{We shied away from redefining the +% |frontmatter| to induce a blindomgroup, but this may be the ``right'' way to go in +% the future.} and makes the preface of the book a section-level construct. Note that +% here the |display=flow| on the |omgroup| environment prevents numbering as is +% traditional for prefaces. +% \end{itemize} +% \begin{exfig} +% \begin{verbatim} +% \begin{document} +% \begin{blindfragment} +% \begin{blindfragment} +% \begin{frontmatter} +% \maketitle\newpage +% \begin{sfragment}[display=flow]{Preface} +% ... <<preface>> ... +% \end{sfragment} +% \clearpage\setcounter{tocdepth}{4}\tableofcontents\clearpage +% \end{frontmatter} +% \end{blindfragment} +% ... <<introductory remarks>> ... +% \end{blindfragment} +% \begin{sfragment}{Introduction} +% ... <<intro>> ... +% \end{sfragment} +% ... <<more chapters>> ... +% \bibliographystyle{alpha}\bibliography{kwarc} +% \end{document} +% \end{verbatim} +% \vspace*{-2em} +% \caption{A typical Document Structure of a Book}\label{fig:docstruct} +% \end{exfig} +% +% The \DescribeMacro{\skipomgroup}|\skipomgroup| ``skips an |omgroup|'', i.e. it just +% steps the respective sectioning counter. This macro is useful, when we want to keep two +% documents in sync structurally, so that section numbers match up: Any section that is +% left out in one becomes a |\skipomgroup|. +% +% The \DescribeMacro{\currentsectionlevel}|\currentsectionlevel| macro supplies the name +% of the current sectioning level, e.g. ``chapter'', or +% ``subsection''. \DescribeMacro{\CurrentSectionLevel}|\CurrentSectionLevel| is the +% capitalized variant. They are useful to write something like ``In this +% |\currentsectionlevel|, we will\ldots'' in an |omgroup| environment, where we do not +% know which sectioning level we will end up. +% \end{sfragment} +% +% \begin{sfragment}[id=sec:user:ignore]{Ignoring Inputs} +% +% The \DescribeEnv{ignore}|ignore| environment can be used for hiding text parts from the +% document structure. The body of the environment is not PDF or DVI output unless the +% \DescribeMacro{showignores}|showignores| option is given to the |document-structure| class or +% |package|. But in the generated {\omdoc} result, the body is marked up with a |ignore| +% element. This is useful in two situations. For +% \begin{description} +% \item[editing] One may want to hide unfinished or obsolete parts of a document +% \item[narrative/content markup] In {\stex} we mark up narrative-structured documents. In +% the generated {\omdoc} documents we want to be able to cache content objects that are +% not directly visible. For instance in the |statements| +% package~\cite{Kohlhase:smms:git} we use the |\inlinedef| macro to mark up phrase-level +% definitions, which verbalize more formal definitions. The latter can be hidden by an +% ignore and referenced by the |verbalizes| key in |\inlinedef|. +% \end{description} +% +% For prematurely stopping the formatting of a document, \sTeX provides the +% \DescribeMacro{\prematurestop}|\prematurestop| macro. It can be used everywhere in a +% document and ignores all input after that -- backing out of the omgroup environment as +% needed. After that -- and before the implicit |\end{document}| it calls the internal +% \DescribeMacro{\afterprematurestop}|\afterprematurestop|, which can be customized to do +% additional cleanup or e.g. print the bibliography. +% +% |\prematurestop| is useful when one has a driver file, e.g. for a course taught multiple +% years and wants to generate course notes up to the current point in the lecture. Instead +% of commenting out the remaining parts, one can just move the |\prematurestop| macro. +% This is especially useful, if we need the rest of the file for processing, e.g. to +% generate a theory graph of the whole course with the already-covered parts marked up as +% an overview over the progress; see |import_graph.py| from the |lmhtools| +% utilities~\cite{lmhtools:github:on}. +% \end{sfragment} +% +% \begin{sfragment}[id=sec:user:sharing]{Structure Sharing} +% +% The \DescribeMacro{\STRlabel}|\STRlabel| macro takes two arguments: a label and the +% content and stores the the content for later use by +% \DescribeMacro{\STRcopy}|\STRcopy[|\meta{URL}|]{|\meta{label}|}|, which expands to the +% previously stored content. If the |\STRlabel| macro was in a different file, then we +% can give a URL \meta{URL} that lets {\latexml} generate the correct reference. +% +% \DescribeMacro{\STRsemantics} The |\STRlabel| macro has a variant |\STRsemantics|, +% where the label argument is optional, and which takes a third argument, which is +% ignored in {\LaTeX}. This allows to specify the meaning of the content (whatever that +% may mean) in cases, where the source document is not formatted for presentation, but +% is transformed into some content markup format.\ednote{document LMID und LMXREf here +% if we decide to keep them.} +% \end{sfragment} +% +% \begin{sfragment}[id=sec:user:gvars]{Global Variables} +% +% Text fragments and modules can be made more re-usable by the use of global +% variables. For instance, the admin section of a course can be made course-independent +% (and therefore re-usable) by using variables (actually token registers) +% |courseAcronym| and |courseTitle| instead of the text itself. The variables can then +% be set in the \sTeX preamble of the course notes file. +% \DescribeMacro{\setSGvar}|\setSGvar{|\meta{vname}|}{|\meta{text}|}| to set the global +% variable \meta{vname} to \meta{text} and +% \DescribeMacro{\useSGvar}|\useSGvar{|\meta{vname}|}| to reference it. +% +% With \DescribeMacro{\ifSGvar}|\ifSGvar| we can test for the contents of a global +% variable: the macro call |\ifSGvar{|\meta{vname}|}{|\meta{val}|}{|\meta{ctext}|}| +% tests the content of the global variable \meta{vname}, only if (after expansion) it is +% equal to \meta{val}, the conditional text \meta{ctext} is formatted. +% \end{sfragment} +% +% \begin{sfragment}[id=sec:user:colors]{Colors} +% +% For convenience, the |document-structure| package defines a couple of color macros for the |color| +% package: For instance \DescribeMacro{\blue}|\blue| abbreviates |\textcolor{blue}|, so +% that |\blue{|\meta{something}|}| writes \meta{something} in blue. The macros +% \DescribeMacro{\red}|\red| \DescribeMacro{...}|\green|, |\cyan|, |\magenta|, |\brown|, +% |\yellow|, |\orange|, |\gray|, and finally \DescribeMacro{\black}|\black| are +% analogous. +% \end{sfragment} +% \end{sfragment} +% +% \begin{sfragment}[id=sec:limitations]{Limitations} +% +% In this section we document known limitations. If you want to help alleviate them, +% please feel free to contact the package author. Some of them are currently discussed in +% the \sTeX GitHub repository~\cite{sTeX:github:on}. +% \begin{enumerate} +% \item when option |book| which uses |\pagestyle{headings}| is given and semantic macros +% are given in the |omgroup| titles, then they sometimes are not defined by the time the +% heading is formatted. Need to look into how the headings are made. +% \end{enumerate} +% \end{sfragment} +% +% \end{documentation} +% +% \begin{implementation}\label{pkg:documentstructure:impl} +% +% \begin{sfragment}{document-structure.sty Implementation} +% +% \begin{sfragment}[id=sec:impl:cls]{The document-structure Class} +% +% The functionality is spread over the |document-structure| class and package. The class provides the +% |document| environment and the |document-structure| element corresponds to it, whereas the +% package provides the concrete functionality. +% +% \begin{macrocode} +%<*cls> +%<@@=document_structure> +\ProvidesExplClass{document-structure}{2022/02/24}{3.0.0}{Modular Document Structure Class} +\RequirePackage{l3keys2e} +% \end{macrocode} +% +% \begin{sfragment}[id=sec:impl:cls:options]{Class Options} +% To initialize the |document-structure| class, we declare and process the necessary options using +% the |kvoptions| package for key/value options handling. For +% |omdoc.cls| this is quite simple. We have options |report| and |book|, which set the +% \DescribeMacro{\omdoc@cls@class}|\omdoc@cls@class| macro and pass on the macro to |omdoc.sty| +% for further processing. +% +% \begin{macrocode} +\keys_define:nn{ document-structure / pkg }{ + class .str_set_x:N = \c_document_structure_class_str, + minimal .bool_set:N = \c_document_structure_minimal_bool, + report .code:n = { + \ClassWarning{document-structure}{the option 'report' is deprecated, use 'class=report', instead} + \str_set:Nn \c_document_structure_class_str {report} + }, + book .code:n = { + \ClassWarning{document-structure}{the option 'book' is deprecated, use 'class=book', instead} + \str_set:Nn \c_document_structure_class_str {book} + }, + bookpart .code:n = { + \ClassWarning{document-structure}{the option 'bookpart' is deprecated, use 'class=book,topsect=chapter', instead} + \str_set:Nn \c_document_structure_class_str {book} + \str_set:Nn \c_document_structure_topsect_str {chapter} + }, + docopt .str_set_x:N = \c_document_structure_docopt_str, + unknown .code:n = { + \PassOptionsToPackage{ \CurrentOption }{ document-structure } + } +} +\ProcessKeysOptions{ document-structure / pkg } +\str_if_empty:NT \c_document_structure_class_str { + \str_set:Nn \c_document_structure_class_str {article} +} +\exp_after:wN\LoadClass\exp_after:wN[\c_document_structure_docopt_str] + {\c_document_structure_class_str} + +% \end{macrocode} +% \end{sfragment} +% +% \begin{sfragment}[id=sec:impl:cls:document]{Beefing up the \texttt{document} environment} +% +% Now, -- unless the option |minimal| is defined -- we include the |stex| package +% +% \begin{macrocode} +\RequirePackage{document-structure} +\bool_if:NF \c_document_structure_minimal_bool { +% \end{macrocode} +% +% And define the environments we need. The top-level one is the |document| environment, +% which we redefined so that we can provide keyval arguments. +% +% \begin{environment}{document} +% For the moment we do not use them on the {\LaTeX} level, but the document identifier +% is picked up by {\latexml}.\ednote{faking documentkeys for now. @HANG, please implement} +% \begin{macrocode} +\keys_define:nn { document-structure / document }{ + id .str_set_x:N = \c_document_structure_document_id_str +} +\let\_@@_orig_document=\document +\renewcommand{\document}[1][]{ + \keys_set:nn{ document-structure / document }{ #1 } + \stex_ref_new_doc_target:n { \c_document_structure_document_id_str } + \_@@_orig_document +} +% \end{macrocode} +% \end{environment} +% +% Finally, we end the test for the |minimal| option. +% +% \begin{macrocode} +} +%</cls> +% \end{macrocode} +% \end{sfragment} +% \end{sfragment} +% +% \begin{sfragment}[id=sec:impl:sty]{Implementation: document-structure Package} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage{document-structure}{2022/02/24}{3.0.0}{Modular Document Structure} +\RequirePackage{l3keys2e} +% \end{macrocode} +% +% \begin{sfragment}[id=sec:impl:options]{Package Options} +% +% We declare some switches which will modify the behavior according to the package +% options. Generally, an option |xxx| will just set the appropriate switches to true +% (otherwise they stay false). +% +% +% \begin{macrocode} + +\keys_define:nn{ document-structure / pkg }{ + class .str_set_x:N = \c_document_structure_class_str, + topsect .str_set_x:N = \c_document_structure_topsect_str, +% showignores .bool_set:N = \c_document_structure_showignores_bool, +} +\ProcessKeysOptions{ document-structure / pkg } +\str_if_empty:NT \c_document_structure_class_str { + \str_set:Nn \c_document_structure_class_str {article} +} +\str_if_empty:NT \c_document_structure_topsect_str { + \str_set:Nn \c_document_structure_topsect_str {section} +} +% \end{macrocode} +% +% Then we need to set up the packages by requiring the |sref| package to be loaded, +% and set up triggers for other languages +% +% \begin{macrocode} +\RequirePackage{xspace} +\RequirePackage{comment} +\AddToHook{begindocument}{ + \ltx@ifpackageloaded{babel}{ + \clist_set:Nx \l_tmpa_clist {\bbl@loaded} + \clist_if_in:NnT \l_tmpa_clist {ngerman}{ + \makeatletter\input{omdoc-ngerman.ldf}\makeatother + } + }{} +} +% \end{macrocode} +% +% Finally, we set the \DescribeMacro{\section@level}|\section@level| macro that governs +% sectioning. The default is two (corresponding to the |article| class), then we set the +% defaults for the standard classes |book| and |report| and then we take care of the +% levels passed in via the |topsect| option. +% +% \begin{macrocode} +\int_new:N \l_document_structure_section_level_int +\str_case:VnF \c_document_structure_topsect_str { + {part}{ + \int_set:Nn \l_document_structure_section_level_int {0} + } + {chapter}{ + \int_set:Nn \l_document_structure_section_level_int {1} + } +}{ + \str_case:VnF \c_document_structure_class_str { + {book}{ + \int_set:Nn \l_document_structure_section_level_int {0} + } + {report}{ + \int_set:Nn \l_document_structure_section_level_int {0} + } + }{ + \int_set:Nn \l_document_structure_section_level_int {2} + } +} +% \end{macrocode} +% +% \end{sfragment} +% +% \begin{sfragment}[id=sec:impl:struct]{Document Structure} +% +% The structure of the document is given by the |omgroup| environment just like in +% OMDoc. The hierarchy is adjusted automatically according to the {\LaTeX} class in +% effect. +% \begin{macro}{\currentsectionlevel} +% For the |\currentsectionlevel| and |\Currentsectionlevel| macros we use an internal +% macro |\current@section@level| that only contains the keyword (no markup). We +% initialize it with ``document'' as a default. In the generated OMDoc, we only generate +% a text element of class |omdoc_currentsectionlevel|, wich will be instantiated by CSS +% later.\ednote{MK: we may have to experiment with the more powerful uppercasing macro +% from \texttt{mfirstuc.sty} once we internationalize.} +% \begin{macrocode} +\def\current@section@level{document}% +\newcommand\currentsectionlevel{\lowercase\expandafter{\current@section@level}\xspace}% +\newcommand\Currentsectionlevel{\expandafter\MakeUppercase\current@section@level\xspace}% +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\skipomgroup} +% \begin{macrocode} +\cs_new_protected:Npn \skipomgroup { + \ifcase\l_document_structure_section_level_int + \or\stepcounter{part} + \or\stepcounter{chapter} + \or\stepcounter{section} + \or\stepcounter{subsection} + \or\stepcounter{subsubsection} + \or\stepcounter{paragraph} + \or\stepcounter{subparagraph} + \fi +} +% \end{macrocode} +% \end{macro} +% +% \begin{environment}{blindfragment} +% \begin{macrocode} +\newcommand\at@begin@blindomgroup[1]{} +\newenvironment{blindfragment} +{ + \int_incr:N\l_document_structure_section_level_int + \at@begin@blindomgroup\l_document_structure_section_level_int +}{} +% \end{macrocode} +% \end{environment} +% +% \begin{macro}{\omgroup@nonum} +% convenience macro: |\omgroup@nonum{|\meta{level}|}{|\meta{title}|}| makes an unnumbered +% sectioning with title \meta{title} at level \meta{level}. +% \begin{macrocode} +\newcommand\omgroup@nonum[2]{ + \ifx\hyper@anchor\@undefined\else\phantomsection\fi + \addcontentsline{toc}{#1}{#2}\@nameuse{#1}*{#2} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\omgroup@num} +% convenience macro: |\omgroup@nonum{|\meta{level}|}{|\meta{title}|}| makes numbered +% sectioning with title \meta{title} at level \meta{level}. We have to check the |short| +% key was given in the |omgroup| environment and -- if it is use it. But how to do that +% depends on whether the |rdfmeta| package has been loaded. In the end we call +% |\sref@label@id| to enable crossreferencing. +% \begin{macrocode} +\newcommand\omgroup@num[2]{ + \tl_if_empty:NTF \l_@@_omgroup_short_tl { + \@nameuse{#1}{#2} + }{ + \cs_if_exist:NTF\rdfmeta@sectioning{ + \@nameuse{rdfmeta@#1@old}[\l_@@_omgroup_short_tl]{#2} + }{ + \@nameuse{#1}[\l_@@_omgroup_short_tl]{#2} + } + } +%\sref@label@id@arg{\omdoc@sect@name~\@nameuse{the#1}}\omgroup@id +} +% \end{macrocode} +% \end{macro} +% +% \begin{environment}{sfragment} +% \begin{macrocode} +\keys_define:nn { document-structure / omgroup }{ + id .str_set_x:N = \l_@@_omgroup_id_str, + date .str_set_x:N = \l_@@_omgroup_date_str, + creators .clist_set:N = \l_@@_omgroup_creators_clist, + contributors .clist_set:N = \l_@@_omgroup_contributors_clist, + srccite .tl_set:N = \l_@@_omgroup_srccite_tl, + type .tl_set:N = \l_@@_omgroup_type_tl, + short .tl_set:N = \l_@@_omgroup_short_tl, + display .tl_set:N = \l_@@_omgroup_display_tl, + intro .tl_set:N = \l_@@_omgroup_intro_tl, + loadmodules .bool_set:N = \l_@@_omgroup_loadmodules_bool +} +\cs_new_protected:Nn \_@@_omgroup_args:n { + \str_clear:N \l_@@_omgroup_id_str + \str_clear:N \l_@@_omgroup_date_str + \clist_clear:N \l_@@_omgroup_creators_clist + \clist_clear:N \l_@@_omgroup_contributors_clist + \tl_clear:N \l_@@_omgroup_srccite_tl + \tl_clear:N \l_@@_omgroup_type_tl + \tl_clear:N \l_@@_omgroup_short_tl + \tl_clear:N \l_@@_omgroup_display_tl + \tl_clear:N \l_@@_omgroup_intro_tl + \bool_set_false:N \l_@@_omgroup_loadmodules_bool + \keys_set:nn { document-structure / omgroup } { #1 } +} +% \end{macrocode} +% we define a switch for numbering lines and a hook for the beginning of groups: The +% \DescribeMacro{\at@begin@omgroup}|\at@begin@omgroup| macro allows customization. It is +% run at the beginning of the |omgroup|, i.e. after the section heading. +% \begin{macrocode} +\newif\if@mainmatter\@mainmattertrue +\newcommand\at@begin@omgroup[3][]{} +% \end{macrocode} +% +% Then we define a helper macro that takes care of the sectioning magic. It comes with its +% own key/value interface for customization. +% +% \begin{macrocode} +\keys_define:nn { document-structure / sectioning }{ + name .str_set_x:N = \l_@@_sect_name_str , + ref .str_set_x:N = \l_@@_sect_ref_str , + clear .bool_set:N = \l_@@_sect_clear_bool , + clear .default:n = {true} , + num .bool_set:N = \l_@@_sect_num_bool , + num .default:n = {true} +} +\cs_new_protected:Nn \_@@_sect_args:n { + \str_clear:N \l_@@_sect_name_str + \str_clear:N \l_@@_sect_ref_str + \bool_set_false:N \l_@@_sect_clear_bool + \bool_set_false:N \l_@@_sect_num_bool + \keys_set:nn { document-structure / sectioning } { #1 } +} +\newcommand\omdoc@sectioning[3][]{ + \_@@_sect_args:n {#1 } + \let\omdoc@sect@name\l_@@_sect_name_str + \bool_if:NT \l_@@_sect_clear_bool { \cleardoublepage } + \if@mainmatter% numbering not overridden by frontmatter, etc. + \bool_if:NTF \l_@@_sect_num_bool { + \omgroup@num{#2}{#3} + }{ + \omgroup@nonum{#2}{#3} + } + \def\current@section@level{\omdoc@sect@name} + \else + \omgroup@nonum{#2}{#3} + \fi +}% if@mainmatter +% \end{macrocode} +% and another one, if redefines the |\addtocontentsline| macro of {\LaTeX} to import the +% respective macros. It takes as an argument a list of module names. +% \begin{macrocode} +\newcommand\omgroup@redefine@addtocontents[1]{% +%\edef\@@import{#1}% +%\@for\@I:=\@@import\do{% +%\edef\@path{\csname module@\@I @path\endcsname}% +%\@ifundefined{tf@toc}\relax% +% {\protected@write\tf@toc{}{\string\@requiremodules{\@path}}}} +%\ifx\hyper@anchor\@undefined% hyperref.sty loaded? +%\def\addcontentsline##1##2##3{% +%\addtocontents{##1}{\protect\contentsline{##2}{\string\withusedmodules{#1}{##3}}{\thepage}}} +%\else% hyperref.sty not loaded +%\def\addcontentsline##1##2##3{% +%\addtocontents{##1}{\protect\contentsline{##2}{\string\withusedmodules{#1}{##3}}{\thepage}{\@currentHref}}}% +%\fi +}% hypreref.sty loaded? +% \end{macrocode} +% now the |omgroup| environment itself. This takes care of the table of contents via the +% helper macro above and then selects the appropriate sectioning command from +% |article.cls|. It also registeres the current level of omgroups in the |\omgroup@level| +% counter. +% \begin{macrocode} +\newenvironment{sfragment}[2][]% keys, title +{ + \_@@_omgroup_args:n { #1 }%\sref@target% +% \end{macrocode} +% If the |loadmodules| key is set on |\begin{sfragment}|, we redefine the |\addcontetsline| +% macro that determines how the sectioning commands below construct the entries for the +% table of contents. +% \begin{macrocode} + \bool_if:NT \l_@@_omgroup_loadmodules_bool { + \omgroup@redefine@addtocontents{ + %\@ifundefined{module@id}\used@modules% + %{\@ifundefined{module@\module@id @path}{\used@modules}\module@id} + } + } +% \end{macrocode} +% now we only need to construct the right sectioning depending on the value of +% |\section@level|. +% \begin{macrocode} + \int_incr:N\l_document_structure_section_level_int + \ifcase\l_document_structure_section_level_int + \or\omdoc@sectioning[name=\omdoc@part@kw,clear,num]{part}{#2} + \or\omdoc@sectioning[name=\omdoc@chapter@kw,clear,num]{chapter}{#2} + \or\omdoc@sectioning[name=\omdoc@section@kw,num]{section}{#2} + \or\omdoc@sectioning[name=\omdoc@subsection@kw,num]{subsection}{#2} + \or\omdoc@sectioning[name=\omdoc@subsubsection@kw,num]{subsubsection}{#2} + \or\omdoc@sectioning[name=\omdoc@paragraph@kw,ref=this \omdoc@paragraph@kw]{paragraph}{#2} + \or\omdoc@sectioning[name=\omdoc@subparagraph@kw,ref=this \omdoc@subparagraph@kw]{paragraph}{#2} + \fi + \at@begin@omgroup[#1]\l_document_structure_section_level_int{#2} + \str_if_empty:NF \l_@@_omgroup_id_str { + \stex_ref_new_doc_target:n\l_@@_omgroup_id_str + } +}% for customization +{} +% \end{macrocode} +% \end{environment} +% +% and finally, we localize the sections +% \begin{macrocode} +\newcommand\omdoc@part@kw{Part} +\newcommand\omdoc@chapter@kw{Chapter} +\newcommand\omdoc@section@kw{Section} +\newcommand\omdoc@subsection@kw{Subsection} +\newcommand\omdoc@subsubsection@kw{Subsubsection} +\newcommand\omdoc@paragraph@kw{paragraph} +\newcommand\omdoc@subparagraph@kw{subparagraph} +% \end{macrocode} +% +% \end{sfragment} +% +% \begin{sfragment}[id=sec:user:docmatter]{Front and Backmatter} +% +% Index markup is provided by the |omtext| package~\cite{Kohlhase:smmtf:git}, so in the +% |document-structure| package we only need to supply the corresponding |\printindex| command, if it +% is not already defined +% \begin{macro}{\printindex} +% \begin{macrocode} +\providecommand\printindex{\IfFileExists{\jobname.ind}{\input{\jobname.ind}}{}} +% \end{macrocode} +% \end{macro} +% +% some classes (e.g. |book.cls|) already have |\frontmatter|, |\mainmatter|, and +% |\backmatter| macros. As we want to define |frontmatter| and |backmatter| environments, +% we save their behavior (possibly defining it) in |orig@*matter| macros and make them +% undefined (so that we can define the environments). +% \begin{macrocode} +\cs_if_exist:NTF\frontmatter{ + \let\_@@_orig_frontmatter\frontmatter + \let\frontmatter\relax +}{ + \tl_set:Nn\_@@_orig_frontmatter{ + \clearpage + \@mainmatterfalse + \pagenumbering{roman} + } +} +\cs_if_exist:NTF\backmatter{ + \let\_@@_orig_backmatter\backmatter + \let\backmatter\relax +}{ + \tl_set:Nn\_@@_orig_backmatter{ + \clearpage + \@mainmatterfalse + \pagenumbering{roman} + } +} +% \end{macrocode} +% +% Using these, we can now define the |frontmatter| and |backmatter| environments +% +% \begin{environment}{frontmatter} +% we use the |\orig@frontmatter| macro defined above and |\mainmatter| if it exists, +% otherwise we define it. +% \begin{macrocode} +\newenvironment{frontmatter}{ + \_@@_orig_frontmatter +}{ + \cs_if_exist:NTF\mainmatter{ + \mainmatter + }{ + \clearpage + \@mainmattertrue + \pagenumbering{arabic} + } +} +% \end{macrocode} +% \end{environment} +% +% \begin{environment}{backmatter} +% As backmatter is at the end of the document, we do nothing for |\endbackmatter|. +% \begin{macrocode} +\newenvironment{backmatter}{ + \_@@_orig_backmatter +}{ + \cs_if_exist:NTF\mainmatter{ + \mainmatter + }{ + \clearpage + \@mainmattertrue + \pagenumbering{arabic} + } +} +% \end{macrocode} +% +% finally, we make sure that page numbering is arabic and we have main matter as the default +% +% \begin{macrocode} +\@mainmattertrue\pagenumbering{arabic} +% \end{macrocode} +% \end{environment} +% \end{sfragment} +% +% \begin{macro}{\prematurestop} +% We initialize |\afterprematurestop|, and provide +% |\prematurestop@endomgroup| which looks up |\omgroup@level| and recursively ends +% enough |{sfragment}|s. +% \begin{macrocode} +\def \c_@@_document_str{document} +\newcommand\afterprematurestop{} +\def\prematurestop@endomgroup{ + \unless\ifx\@currenvir\c_@@_document_str + \expandafter\expandafter\expandafter\end\expandafter\expandafter\expandafter{\expandafter\@currenvir\expandafter} + \expandafter\prematurestop@endomgroup + \fi +} +\providecommand\prematurestop{ + \message{Stopping~sTeX~processing~prematurely} + \prematurestop@endomgroup + \afterprematurestop + \end{document} +} +% \end{macrocode} +% \end{macro} +% +% \iffalse +% \begin{sfragment}[id=sec:impl:share]{Structure Sharing} +% \ednote{The following is simply copied over from the |latexml| package, which we +% eliminated, we should integrate better.} +% \begin{macrocode} +\iffalse +\providecommand{\lxDocumentID}[1]{}% +\def\LXMID#1#2{\expandafter\gdef\csname xmarg#1\endcsname{#2}\csname xmarg#1\endcsname} +\def\LXMRef#1{\csname xmarg#1\endcsname} +% \end{macrocode} +% +% \begin{macro}{\STRlabel} +% The main macro, it it used to attach a label to some text expansion. Later on, using the +% |\STRcopy| macro, the author can use this label to get the expansion originally assigned. +% \begin{macrocode} +\long\def\STRlabel#1#2{\STRlabeldef{#1}{#2}{#2}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\STRcopy} +% The |\STRcopy| macro is used to call the expansion of a given label. In case the label +% is not defined it will issue a warning.\ednote{MK: we need to do something about the +% ref!} +% \begin{macrocode} +\newcommand\STRcopy[2][]{\expandafter\ifx\csname STR@#2\endcsname\relax +\message{STR warning: reference #2 undefined!} +\else\csname STR@#2\endcsname\fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\STRsemantics} +% if we have a presentation form and a semantic form, then we can use +% \begin{macrocode} +\newcommand\STRsemantics[3][]{#2\def\@test{#1}\ifx\@test\@empty\STRlabeldef{#1}{#2}\fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\STRlabeldef} +% This is the macro that does the actual labeling. Is it called inside |\STRlabel| +% \begin{macrocode} +\def\STRlabeldef#1{\expandafter\gdef\csname STR@#1\endcsname} +\fi +% \end{macrocode} +% \end{macro} +% \end{sfragment} +%\fi +% +% \begin{sfragment}[id=sec:impl:gvars]{Global Variables} +% +% \begin{macro}{\setSGvar} +% set a global variable +% \begin{macrocode} +\RequirePackage{etoolbox} +\newcommand\setSGvar[1]{\@namedef{sTeX@Gvar@#1}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\useSGvar} +% use a global variable +% \begin{macrocode} +\newrobustcmd\useSGvar[1]{% + \@ifundefined{sTeX@Gvar@#1} + {\PackageError{document-structure} + {The sTeX Global variable #1 is undefined} + {set it with \protect\setSGvar}} +\@nameuse{sTeX@Gvar@#1}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ifSGvar} +% execute something conditionally based on the state of the global variable. +% \begin{macrocode} +\newrobustcmd\ifSGvar[3]{\def\@test{#2}% + \@ifundefined{sTeX@Gvar@#1} + {\PackageError{document-structure} + {The sTeX Global variable #1 is undefined} + {set it with \protect\setSGvar}} + {\expandafter\ifx\csname sTeX@Gvar@#1\endcsname\@test #3\fi}} +% \end{macrocode} +% \end{macro} +% +% \end{sfragment} +% \end{sfragment} +% \end{sfragment} +% +% \end{implementation} +\endinput +% \iffalse +%%% Local Variables: +%%% mode: doctex +%%% TeX-master: t +%%% End: +% \fi +% LocalWords: GPL structuresharing STR omdoc dtx stex CPERL LoadClass url dc filedate om +% LocalWords: RequirePackage RegisterNamespace namespace xsl DocType ltxml dtd DAG hline +% LocalWords: ltx DefEnvironment beforeDigest AssignValue inPreamble getGullet rangle +% LocalWords: afterDigest keyval omgroup DefKeyVal Semiverbatim KeyVal srcf frontmatter +% LocalWords: OptionalKeyVals DefParameterType IfBeginFollows skipSpaces CMP rangle xdef +% LocalWords: ifNext DefMacro needwrapper unlist DefConstructor omtext bgroup showmods +% LocalWords: useCMPItemizations RefStepItemCounter egroup beginItemize li di pathsuris +% LocalWords: beforeDigestEnd dt autoclose ul ol dl env showignores srcref Cwd rdfmeta +% LocalWords: afterOpen LastSeenCMP autoClose DefCMPEnvironment proto ToString st@flow +% LocalWords: addAttribute nlex nlcex omdocColorMacro args tok MergeFont qw setion@level +% LocalWords: TokenizeInternal toString isMath foreach maybeCloseElement id'd Backmatter +% LocalWords: autoOpen minipage footnotesize scriptsize numberIt whatsit href endinput +% LocalWords: getAttribute setAttribute OMDoc RelaxNGSchema noindex xml lec KeyVals +% LocalWords: Subsubsection useDefaultItemizations refundefinedtrue sblockquote defindex +% LocalWords: DefCMPConstructor sinlinequote idx idt ide idp emph extrefs sref Tokenize +% LocalWords: flushleft flushright DeclareOption PassOptions undef cls iffalse noauxreq +% LocalWords: ProcessOptions subparagraph ignoresfalse ignorestrue texttt ttin behavior +% LocalWords: texttt latexml fileversion maketitle newpage tableofcontents cwd srccite +% LocalWords: newpage ednote ctancite dmt03 smms inlinedef STRlabel STRcopy loadmodules +% LocalWords: STRlabel STRsemantics STRsemantics textcolor printbibliography loadmodules +% LocalWords: textsf langle textsf langle respetively orig renewcommand cdir capitalized +% LocalWords: baseuri baseuri baselocal baselocal SOURCEFILE cooluri newif ifx tf@toc +% LocalWords: SOURCEBASE chapterfalse partfalse newcount ifshow chaptertrue initialize +% LocalWords: parttrue srefaddidkey newenvironment textbf compactenum showmeta tf@toc +% LocalWords: noindent noindent ignorespaces ifnum thepart thechapter regexp color.sty +% LocalWords: thesection thesubsection thesubsubsection needswrapper itshape xmarg xmarg +% LocalWords: textgreater renewenvironment excludecomment STRlabeldef csname Section,num +% LocalWords: expandafter endcsname xref newcommand gdef doctex metakeys Hacky arabic +% LocalWords: metasetkeys addmetakey printindex providecommand jobname.ind importmodules +% LocalWords: jobname.ind tocdepth hateq ensuremath xspace hatequiv equiv NeedsTeXFormat +% LocalWords: textleadsto leadsto etoolbox blindomgroup blindomgroup docstruct setSGvar +% LocalWords: compactitem exfig vspace currentsectionlevel currentsectionlevel setSGvar +% LocalWords: ldots URLBASE ifclass bookfalse booktrue currentsetionlevel thedocument@ID +% LocalWords: nonum phantomsection nameuse numtrue numfalse contentsline unnum vname +% LocalWords: thepage hypreref.sty ifcase cleardoublepage frontmatterfalse customization +% LocalWords: frontmattertrue pagenumbering setcounter hyperref.sty addcontetsline ctext +% LocalWords: mfirstuc.sty internationalize documentkeys withusedmodules Part,clear,num +% \endinput +% Local Variables: +% mode: doctex +% TeX-master: t +% End: +% LocalWords: crossreferencing Chapter,clear,num Subsection,num Subsubsection,num cslet +% LocalWords: Paragraph,ref Subparagraph,ref useSGvar useSGvar ifSGvar ifSGvar topsect +% LocalWords: sTeX@Gvar kvoptions omdoc@cls,prefix book,topsect xappto omdoc@sty,prefix +% LocalWords: ifdefstring ifcsdef cslet localization ngerman omdoc-ngerman.ldf omgroups +% LocalWords: Kohlhase:smmtf endbackmatter prematurestop prematurestop clear,num +% LocalWords: prematurestop@endomgroup textbackslash import_graph.py lmhtools bibfolder +% LocalWords: stepcounter jobname.dtx clist_set:Nx l_tmpa_clist clist_if_in:NnT +% LocalWords: ExplSyntaxOff stex_ref_new_doc_target:n diff --git a/macros/latex/contrib/stex/source/extensions/extensions.ins b/macros/latex/contrib/stex/source/extensions/extensions.ins new file mode 100644 index 0000000000..e3594e88cf --- /dev/null +++ b/macros/latex/contrib/stex/source/extensions/extensions.ins @@ -0,0 +1,39 @@ + %% +%% This file generates files required to use the ed package. +%% At your command prompt write +%% +%% latex extensions.ins +%% +%% Copyright (c) 2021 Michael Kohlhase +%% +%% This file is distributed under the terms of the LaTeX Project Public +%% License from CTAN archives in directory macros/latex/base/lppl.txt. +%% Either version 1.0 or, at your option, any later version. +%% +\input docstrip +\preamble +\endpreamble + +\keepsilent +\askforoverwritefalse + +\generate{ + \file{document-structure.cls}{\from{document-structure.dtx}{cls}} + \file{document-structure.sty}{\from{document-structure.dtx}{package}} + \file{notesslides.cls}{\from{notesslides.dtx}{cls}} + \file{notesslides.sty}{\from{notesslides.dtx}{package}} + \file{tikzinput.sty}{\from{tikzinput.dtx}{package}} + \file{stex-tikzinput.sty}{\from{tikzinput.dtx}{stex}} + \file{problem.sty}{\from{problem.dtx}{package}} + \file{hwexam.sty}{\from{hwexam.dtx}{package}} + \file{hwexam.cls}{\from{hwexam.dtx}{cls}} +} + +\Msg{*} +\Msg{* You probably need to move the generated style files into a directory searched by TeX.} +\Msg{*} +\Msg{* And don't forget to refresh your filename database} +\Msg{* if your TeX distribution uses such a database.} +\Msg{*} + +\endbatchfile diff --git a/macros/latex/contrib/stex/source/extensions/hwexam.dtx b/macros/latex/contrib/stex/source/extensions/hwexam.dtx new file mode 100644 index 0000000000..3136f488d7 --- /dev/null +++ b/macros/latex/contrib/stex/source/extensions/hwexam.dtx @@ -0,0 +1,684 @@ +% \iffalse meta-comment +% An Infrastructure for marking up Assignments +% Copyright (c) 2019 Michael Kohlhase, all rights reserved +% this file is released under the +% LaTeX Project Public License (LPPL) +% The original of this file is in the public repository at +% http://github.com/sLaTeX/sTeX/ +% \fi +% +% \iffalse +% +%<*driver> +\def\bibfolder{../../lib/bib} +\input{../../doc/docheader} + +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +%\iffalse\CheckSum{464}\fi +% +% ^^A\changes{v0.9}{2006/09/18}{First Version with Documentation} +% +% \GetFileInfo{hwexam.sty} +% +% \MakeShortVerb{\|} +% \def\scsys#1{{{\sc #1}}\index{#1@{\sc #1}}} +% \def\latexml{\scsys{LaTeXML}} +% +% \title{\texttt{hwexam.sty/cls}: An Infrastructure for formatting Assignments +% and Exams\thanks{Version {\fileversion} (last revised {\filedate})}} +% \author{Michael Kohlhase\\ +% FAU Erlangen-N\"urnberg\\ +% \url{http://kwarc.info/kohlhase}} +% \maketitle +% +%\ifinfulldoc\else +% This is the documentation for the \pkg{hwexam} package. +% For a more high-level introduction, +% see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the +% \href{\basedocurl/stex.pdf}{full \sTeX documentation}. +% +% \input{../../doc/packages/hwexam} +% \fi +% +% \begin{documentation} +% +% The |hwexam| package and class allows individual course assignment sheets and +% compound assignment documents using problem files marked up with the |problem| package. +% \setcounter{tocdepth}{2}\tableofcontents\newpage +% +%\section{Introduction}\label{sec:intro} +% +% The |hwexam| package and class supplies an infrastructure that allows to format +% nice-looking assignment sheets by simply including problems from problem files marked up +% with the |problem| package~\cite{Kohlhase:problem}. It is designed to be +% compatible with |problems.sty|, and inherits some of the functionality. +% +% \section{The User Interface} +% +% \subsection{Package and Class Options}\label{sec:user:options} +% +% The |hwexam| package and class take the options |solutions|, |notes|, |hints|, |gnotes|, +% |pts|, |min|, and |boxed| that are just passed on to the |problems| package (cf. its +% documentation for a description of the intended behavior). +% +% If the \DescribeMacro{showmeta}|showmeta| option is set, then the metadata keys are +% shown (see~\cite{Kohlhase:metakeys} for details and customization options). +% +% The |hwexam| class additionally accepts the options |report|, |book|, |chapter|, |part|, +% and |showignores|, of the |omdoc| package~\cite{Kohlhase:smomdl} on which it is +% based and passes them on to that. For the |extrefs| option +% see~\cite{Kohlhase:sref}. +% +% \subsection{Assignments} +% +% This package supplies the \DescribeEnv{assignment}|assignment| environment that groups +% problems into assignment sheets. It takes an optional KeyVal argument with the keys +% \DescribeMacro{number}|number| (for the assignment number; if none is given, 1 is +% assumed as the default or --- in multi-assignment documents --- the ordinal of the +% |assignment| environment), \DescribeMacro{title}|title| (for the assignment title; this +% is referenced in the title of the assignment sheet), \DescribeMacro{type}|type| (for the +% assignment type; e.g. ``quiz'', or ``homework''), \DescribeMacro{given}|given| (for the +% date the assignment was given), and \DescribeMacro{due}|due| (for the date the +% assignment is due). +% +% \subsection{Typesetting Exams} +% +% Furthermore, the |hwexam| package takes the option +% \DescribeMacro{multiple}|multiple| that allows to combine multiple assignment sheets into +% a compound document (the assignment sheets are treated as section, there is a table of +% contents, etc.). +% +% Finally, there is the option \DescribeMacro{test}|test| that modifies the behavior to +% facilitate formatting tests. Only in |test| mode, the macros |\testspace|, +% |\testnewpage|, and |\testemptypage| have an effect: they generate space for the +% students to solve the given problems. Thus they can be left in the {\LaTeX} source. +% +% \DescribeMacro{\testspace}|\testspace| takes an argument that expands to a dimension, +% and leaves vertical space accordingly. \DescribeMacro{\testnewpage}|\testnewpage| makes +% a new page in |test| mode, and \DescribeMacro{\testemptypage}|\testemptypage| generates +% an empty page with the cautionary message that this page was intentionally left empty. +% +% Finally, the \DescribeEnv{testheading}|\testheading| takes an optional keyword argument +% where the keys \DescribeMacro{duration}|duration| specifies a string that specifies the +% duration of the test, \DescribeMacro{min}|min| specifies the equivalent in number of +% minutes, and \DescribeMacro{reqpts}|reqpts| the points that are required for a perfect +% grade. +% \begin{exfig}[ht] +% \makeatletter +% \@problem{1.1}{4}{10} +% \@problem{2.1}{4}{8} +% \@problem{2.2}{6}{10} +% \@problem{2.3}{6}{10} +% \@problem{3.1}{4}{8} +% \@problem{3.2}{4}{8} +% \@problem{3.3}{2}{4} +% \makeatother +% \begin{verbatim} +% \title{320101 General Computer Science (Fall 2010)} +% \begin{testheading}[duration=one hour,min=60,reqpts=27] +% Good luck to all students! +% \end{testheading} +% \end{verbatim} +% \vspace*{-3ex}\hrule\vspace*{.5ex} formats to\vspace*{1ex} +% \hrule\par\noindent\vspace*{2ex} +% \title{320101 General Computer Science (Fall 2010)} +% \begin{testheading}[duration=one hour,min=60,reqpts=27] +% good luck +% \end{testheading} +% \caption{A generated test heading.}\label{fig:testheading} +% \end{exfig} +% +% \subsection{Including Assignments} +% +% The \DescribeMacro{\inputassignment}|\inputassignment| macro can be used to input +% an assignment from another file. It takes an optional KeyVal argument and a second +% argument which is a path to the file containing the problem (the macro assumes that +% there is only one |assignment| environment in the included file). The keys +% \DescribeMacro{number}|number|, \DescribeMacro{title}|title|, +% \DescribeMacro{type}|type|, \DescribeMacro{given}|given|, and \DescribeMacro{due}|due| +% are just as for the |assignment| environment and (if given) overwrite the ones specified +% in the |assignment| environment in the included file. +% +% \section{Limitations}\label{sec:limitations} +% +% In this section we document known limitations. If you want to help alleviate them, +% please feel free to contact the package author. Some of them are currently discussed in +% the \sTeX GitHub repository~\cite{sTeX:github:on}. +% \begin{enumerate} +% \item none reported yet. +% \end{enumerate} +% +% \end{documentation} +% +%\begin{implementation} +% \section{Implementation: The hwexam Class}\label{sec:impl:cls} +% +% The functionality is spread over the |hwexam| class and package. The class provides +% the |document| environment and pre-loads some convenience packages, whereas the package +% provides the concrete functionality. +% +% \subsection{Class Options}\label{sec:impl:cls:options} +% +% To initialize the |hwexam| class, we declare and process the necessary options by +% passing them to the respective packages and classes they come from. +% +% \begin{macrocode} +%<@@=hwexam> +%<*cls> +\ProvidesExplClass{hwexam}{2022/02/24}{3.0.0}{homework assignments and exams} +\RequirePackage{l3keys2e} +\DeclareOption*{ + \PassOptionsToClass{\CurrentOption}{document-structure} + \PassOptionsToPackage{\CurrentOption}{stex} + \PassOptionsToPackage{\CurrentOption}{hwexam} + \PassOptionsToPackage{\CurrentOption}{tikzinput} +} +\ProcessOptions +% \end{macrocode} +% +% We load |omdoc.cls|, and the desired packages. For the {\latexml} bindings, we make +% sure the right packages are loaded. +% +% \begin{macrocode} +\LoadClass{document-structure} +\RequirePackage{stex} +\RequirePackage{hwexam} +\RequirePackage{tikzinput} +\RequirePackage{graphicx} +\RequirePackage{a4wide} +\RequirePackage{amssymb} +\RequirePackage{amstext} +\RequirePackage{amsmath} +% \end{macrocode} +% Finally, we register another keyword for the |document| environment. We give a default +% assignment type to prevent errors +% \begin{macrocode} +\newcommand\assig@default@type{\hwexam@assignment@kw} +\def\document@hwexamtype{\assig@default@type} +%<@@=document_structure> +\keys_define:nn { document-structure / document }{ + id .str_set_x:N = \c_document_structure_document_id_str, + hwexamtype .tl_set:N = \document@hwexamtype +} +%<@@=hwexam> +%</cls> +% \end{macrocode} +% +% \section{Implementation: The hwexam Package} +% +% \subsection{Package Options} +% +% The first step is to declare (a few) package options that handle whether certain +% information is printed or not. Some come with their own conditionals that are set by the +% options, the rest is just passed on to the |problems| package. +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage{hwexam}{2022/02/24}{3.0.0}{homework assignments and exams} +\RequirePackage{l3keys2e} + +\newif\iftest\testfalse +\DeclareOption{test}{\testtrue} +\newif\ifmultiple\multiplefalse +\DeclareOption{multiple}{\multipletrue} +\DeclareOption*{\PassOptionsToPackage{\CurrentOption}{problem}} +\ProcessOptions +% \end{macrocode} +% Then we make sure that the necessary packages are loaded (in the right versions). +% \begin{macrocode} +\RequirePackage{keyval}[1997/11/10] +\RequirePackage{problem} +% \end{macrocode} +% +% \begin{macro}{\hwexam@*@kw} +% For multilinguality, we define internal macros for keywords that can be specialized in +% |*.ldf| files. +% \begin{macrocode} +\newcommand\hwexam@assignment@kw{Assignment} +\newcommand\hwexam@given@kw{Given} +\newcommand\hwexam@due@kw{Due} +\newcommand\hwexam@testemptypage@kw{This~page~was~intentionally~left~ + blank~for~extra~space} + \def\hwexam@minutes@kw{minutes} +\newcommand\correction@probs@kw{prob.} +\newcommand\correction@pts@kw{total} +\newcommand\correction@reached@kw{reached} +\newcommand\correction@sum@kw{Sum} +\newcommand\correction@grade@kw{grade} +\newcommand\correction@forgrading@kw{To~be~used~for~grading,~do~not~write~here} +% \end{macrocode} +% \end{macro} +% +% For the other languages, we set up triggers +% \begin{macrocode} +\AddToHook{begindocument}{ + \ltx@ifpackageloaded{babel}{ + \makeatletter + \clist_set:Nx \l_tmpa_clist {\bbl@loaded} + \clist_if_in:NnT \l_tmpa_clist {ngerman}{ + \input{hwexam-ngerman.ldf} + } + \clist_if_in:NnT \l_tmpa_clist {finnish}{ + \input{hwexam-finnish.ldf} + } + \clist_if_in:NnT \l_tmpa_clist {french}{ + \input{hwexam-french.ldf} + } + \clist_if_in:NnT \l_tmpa_clist {russian}{ + \input{hwexam-russian.ldf} + } + \makeatother + }{} +} + +% \end{macrocode} +% \subsection{Assignments} +% +% Then we set up a counter for problems and make the problem counter inherited from +% |problem.sty| depend on it. Furthermore, we specialize the |\prob@label| macro to take +% the assignment counter into account. +% \begin{macrocode} +\newcounter{assignment} +\numberproblemsin{assignment} +\renewcommand\prob@label[1]{\assignment@number.#1} +% \end{macrocode} +% +% We will prepare the keyval support for the |assignment| environment. +% +% \begin{macrocode} +\keys_define:nn { hwexam / assignment } { + id .str_set_x:N = \l_@@_assign_id_str, + number .int_set:N = \l_@@_assign_number_int, + title .tl_set:N = \l_@@_assign_title_tl, + type .tl_set:N = \l_@@_assign_type_tl, + given .tl_set:N = \l_@@_assign_given_tl, + due .tl_set:N = \l_@@_assign_due_tl, + loadmodules .code:n = { + \bool_set_true:N \l_@@_assign_loadmodules_bool + } +} +\cs_new_protected:Nn \_@@_assignment_args:n { + \str_clear:N \l_@@_assign_id_str + \int_set:Nn \l_@@_assign_number_int {-1} + \tl_clear:N \l_@@_assign_title_tl + \tl_clear:N \l_@@_assign_type_tl + \tl_clear:N \l_@@_assign_given_tl + \tl_clear:N \l_@@_assign_due_tl + \bool_set_false:N \l_@@_assign_loadmodules_bool + \keys_set:nn { hwexam / assignment }{ #1 } +} +% \end{macrocode} +% +% The next three macros are intermediate functions that handle the case gracefully, where +% the respective token registers are undefined. +% +% The |\given@due| macro prints information about the given and due status of the +% assignment. Its arguments specify the brackets. +% +% \begin{macrocode} +\newcommand\given@due[2]{ + \bool_lazy_all:nF { + {\tl_if_empty_p:V \l_@@_inclassign_given_tl} + {\tl_if_empty_p:V \l_@@_assign_given_tl} + {\tl_if_empty_p:V \l_@@_inclassign_due_tl} + {\tl_if_empty_p:V \l_@@_assign_due_tl} + }{ #1 } + + \tl_if_empty:NTF \l_@@_inclassign_given_tl { + \tl_if_empty:NF \l_@@_assign_given_tl { + \hwexam@given@kw\xspace\l_@@_assign_given_tl + } + }{ + \hwexam@given@kw\xspace\l_@@_inclassign_given_tl + } + + \bool_lazy_or:nnF { + \bool_lazy_and_p:nn { + \tl_if_empty_p:V \l_@@_inclassign_due_tl + }{ + \tl_if_empty_p:V \l_@@_assign_due_tl + } + }{ + \bool_lazy_and_p:nn { + \tl_if_empty_p:V \l_@@_inclassign_due_tl + }{ + \tl_if_empty_p:V \l_@@_assign_due_tl + } + }{ ,~ } + + \tl_if_empty:NTF \l_@@_inclassign_due_tl { + \tl_if_empty:NF \l_@@_assign_due_tl { + \hwexam@due@kw\xspace \l_@@_assign_due_tl + } + }{ + \hwexam@due@kw\xspace \l_@@_inclassign_due_tl + } + + \bool_lazy_all:nF { + { \tl_if_empty_p:V \l_@@_inclassign_given_tl } + { \tl_if_empty_p:V \l_@@_assign_given_tl } + { \tl_if_empty_p:V \l_@@_inclassign_due_tl } + { \tl_if_empty_p:V \l_@@_assign_due_tl } + }{ #2 } +} +% \end{macrocode} +% +% \begin{macro}{\assignment@title} +% This macro prints the title of an assignment, the local title is overwritten, if there +% is one from the |\inputassignment|. |\assignment@title| takes three arguments the +% first is the fallback when no title is given at all, the second and third go around +% the title, if one is given. +% \begin{macrocode} +\newcommand\assignment@title[3]{ + \tl_if_empty:NTF \l_@@_inclassign_title_tl { + \tl_if_empty:NTF \l_@@_assign_title_tl { + #1 + }{ + #2\l_@@_assign_title_tl#3 + } + }{ + #2\l_@@_inclassign_title_tl#3 + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\assignment@number} +% Like |\assignment@title| only for the number, and no around part. +% \begin{macrocode} +\newcommand\assignment@number{ + \int_compare:nNnTF \l_@@_inclassign_number_int = {-1} { + \int_compare:nNnTF \l_@@_assign_number_int = {-1} { + \arabic{assignment} + } { + \int_use:N \l_@@_assign_number_int + } + }{ + \int_use:N \l_@@_inclassign_number_int + } +} +% \end{macrocode} +% \end{macro} +% +% With them, we can define the central |assignment| environment. This has two forms +% (separated by |\ifmultiple|) in one we make a title block for an assignment sheet, and +% in the other we make a section heading and add it to the table of contents. We first +% define an assignment counter +% +% \begin{environment}{assignment} +% For the |assignment| environment we delegate the work to the |@assignment| environment +% that depends on whether |multiple| option is given. +% \begin{macrocode} +\newenvironment{assignment}[1][]{ + \_@@_assignment_args:n { #1 } + %\sref@target + \int_compare:nNnTF \l_@@_assign_number_int = {-1} { + \global\stepcounter{assignment} + }{ + \global\setcounter{assignment}{\int_use:N\l_@@_assign_number_int} + } + \setcounter{problem}{0} + \def\current@section@level{\document@hwexamtype} + %\sref@label@id{\document@hwexamtype \thesection} + \begin{@assignment} +}{ + \end{@assignment} +} +% \end{macrocode} +% In the multi-assignment case we just use the |omdoc| environment for suitable +% sectioning. +% \begin{macrocode} +\def\ass@title{ + \protect\document@hwexamtype~\arabic{assignment} + \assignment@title{}{\;(}{)\;} -- \given@due{}{} +} +\ifmultiple + \newenvironment{@assignment}{ + \bool_if:NTF \l_@@_assign_loadmodules_bool { + \begin{sfragment}[loadmodules]{\ass@title} + }{ + \begin{sfragment}{\ass@title} + } + }{ + \end{sfragment} + } +% \end{macrocode} +% for the single-page case we make a title block from the same components. +% \begin{macrocode} +\else + \newenvironment{@assignment}{ + \begin{center}\bf + \Large\@title\strut\\ + \document@hwexamtype~\arabic{assignment}\assignment@title{\;}{:\;}{\\} + \large\given@due{--\;}{\;--} + \end{center} + }{} +\fi% multiple +% \end{macrocode} +% \end{environment} +% +% \subsection{Including Assignments} +% +% \begin{macro}{\in*assignment} +% This macro is essentially a glorified |\include| statement, it just sets some internal +% macros first that overwrite the local points Importantly, it resets the |inclassig| +% keys after the input. +% \begin{macrocode} +\keys_define:nn { hwexam / inclassignment } { + %id .str_set_x:N = \l_@@_assign_id_str, + number .int_set:N = \l_@@_inclassign_number_int, + title .tl_set:N = \l_@@_inclassign_title_tl, + type .tl_set:N = \l_@@_inclassign_type_tl, + given .tl_set:N = \l_@@_inclassign_given_tl, + due .tl_set:N = \l_@@_inclassign_due_tl, + mhrepos .str_set_x:N = \l_@@_inclassign_mhrepos_str +} +\cs_new_protected:Nn \_@@_inclassignment_args:n { + \int_set:Nn \l_@@_inclassign_number_int {-1} + \tl_clear:N \l_@@_inclassign_title_tl + \tl_clear:N \l_@@_inclassign_type_tl + \tl_clear:N \l_@@_inclassign_given_tl + \tl_clear:N \l_@@_inclassign_due_tl + \str_clear:N \l_@@_inclassign_mhrepos_str + \keys_set:nn { hwexam / inclassignment }{ #1 } +} +\_@@_inclassignment_args:n {} + +\newcommand\inputassignment[2][]{ + \_@@_inclassignment_args:n { #1 } + \str_if_empty:NTF \l_@@_inclassign_mhrepos_str { + \input{#2} + }{ + \stex_in_repository:nn{\l_@@_inclassign_mhrepos_str}{ + \input{\mhpath{\l_@@_inclassign_mhrepos_str}{#2}} + } + } + \_@@_inclassignment_args:n {} +} +\newcommand\includeassignment[2][]{ + \newpage + \inputassignment[#1]{#2} +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Typesetting Exams} +% +% \begin{macro}{\quizheading} +% \begin{macrocode} +\ExplSyntaxOff +\newcommand\quizheading[1]{% + \def\@tas{#1}% + \large\noindent NAME: \hspace{8cm} MAILBOX:\\[2ex]% + \ifx\@tas\@empty\else% + \noindent TA:~\@for\@I:=\@tas\do{{\Large$\Box$}\@I\hspace*{1em}}\\[2ex]% + \fi% +} +\ExplSyntaxOn +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\testheading} +% \begin{macrocode} + +\def\hwexamheader{\input{hwexam-default.header}} + +\def\hwexamminutes{ + \tl_if_empty:NTF \testheading@duration { + {\testheading@min}~\hwexam@minutes@kw + }{ + \testheading@duration + } +} + +\keys_define:nn { hwexam / testheading } { + min .tl_set:N = \testheading@min, + duration .tl_set:N = \testheading@duration, + reqpts .tl_set:N = \testheading@reqpts, + tools .tl_set:N = \testheading@tools +} +\cs_new_protected:Nn \_@@_testheading_args:n { + \tl_clear:N \testheading@min + \tl_clear:N \testheading@duration + \tl_clear:N \testheading@reqpts + \tl_clear:N \testheading@tools + \keys_set:nn { hwexam / testheading }{ #1 } +} +\newenvironment{testheading}[1][]{ + \_@@_testheading_args:n{ #1 } + \newcount\check@time\check@time=\testheading@min + \advance\check@time by -\theassignment@totalmin + \newif\if@bonuspoints + \tl_if_empty:NTF \testheading@reqpts { + \@bonuspointsfalse + }{ + \newcount\bonus@pts + \bonus@pts=\theassignment@totalpts + \advance\bonus@pts by -\testheading@reqpts + \edef\bonus@pts{\the\bonus@pts} + \@bonuspointstrue + } + \edef\check@time{\the\check@time} + + \makeatletter\hwexamheader\makeatother +}{ + \newpage +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\testspace} +% \begin{macrocode} +\newcommand\testspace[1]{\iftest\vspace*{#1}\fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\testnewpage} +% \begin{macrocode} +\newcommand\testnewpage{\iftest\newpage\fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\testemptypage} +% \begin{macrocode} +\newcommand\testemptypage[1][]{\iftest\begin{center}\hwexam@testemptypage@kw\end{center}\vfill\eject\else\fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@problem} +% This macro acts on a problem's record in the |*.aux| file. Here we redefine it (it was +% defined to do nothing in |problem.sty|) to generate the correction table. +% \begin{macrocode} +%<@@=problems> +\renewcommand\@problem[3]{ + \stepcounter{assignment@probs} + \def\@@pts{#2} + \ifx\@@pts\@empty\else + \addtocounter{assignment@totalpts}{#2} + \fi + \def\@@min{#3}\ifx\@@min\@empty\else\addtocounter{assignment@totalmin}{#3}\fi + \xdef\correction@probs{\correction@probs & #1}% + \xdef\correction@pts{\correction@pts & #2} + \xdef\correction@reached{\correction@reached &} +} +%<@@=hwexam> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\correction@table} +% This macro generates the correction table +% \begin{macrocode} +\newcounter{assignment@probs} +\newcounter{assignment@totalpts} +\newcounter{assignment@totalmin} +\def\correction@probs{\correction@probs@kw} +\def\correction@pts{\correction@pts@kw} +\def\correction@reached{\correction@reached@kw} +\stepcounter{assignment@probs} +\newcommand\correction@table{ + \resizebox{\textwidth}{!}{% +\begin{tabular}{|l|*{\theassignment@probs}{c|}|l|}\hline% +&\multicolumn{\theassignment@probs}{c||}%| +{\footnotesize\correction@forgrading@kw} &\\\hline +\correction@probs & \correction@sum@kw & \correction@grade@kw\\\hline +\correction@pts &\theassignment@totalpts & \\\hline +\correction@reached & & \\[.7cm]\hline +\end{tabular}}} +%</package> +% \end{macrocode} +% \end{macro} +% +% \subsection{Leftovers} +% +% at some point, we may want to reactivate the logos font, then we use +% \begin{verbatim} +% here we define the logos that characterize the assignment +% \font\bierfont=../assignments/bierglas +% \font\denkerfont=../assignments/denker +% \font\uhrfont=../assignments/uhr +% \font\warnschildfont=../assignments/achtung +% +% \newcommand\bierglas{{\bierfont\char65}} +% \newcommand\denker{{\denkerfont\char65}} +% \newcommand\uhr{{\uhrfont\char65}} +% \newcommand\warnschild{{\warnschildfont\char 65}} +% \newcommand\hardA{\warnschild} +% \newcommand\longA{\uhr} +% \newcommand\thinkA{\denker} +% \newcommand\discussA{\bierglas} +% \end{verbatim} +% \end{implementation} +\endinput +% \iffalse + +%%% Local Variables: +%%% mode: doctex +%%% TeX-master: t +%%% End: +% \fi +% LocalWords: texttt scsys sc latexml fileversion filedate maketitle setcounter newpage +% LocalWords: tocdepth tableofcontents pts showmeta showmeta showignores omdoc extrefs +% LocalWords: testspace testnewpage testemptypage testheading testheading reqpts reqpts +% LocalWords: exfig makeatletter makeatother vspace hrule vspace vspace noindent textsf +% LocalWords: includeassignment includeassignment HorIacJuc cscpnrr11 importmodule baz +% LocalWords: includemhassignment includemhassignment importmhmodule foobar ldots sref +% LocalWords: mhcurrentrepos mh-variants mh-variant compactenum printbibliography Cwd +% LocalWords: langle rangle langle rangle ltxml.cls ltxml.sty respetively metakeys qw +% LocalWords: cwd stex graphicx amssymb amstext amsmath newif iftest testfalse testtrue +% LocalWords: ifsolutions solutionsfalse ifmultiple multiplefalse multipletrue keyval +% LocalWords: ltxml assig srefaddidkey addmetakey ifx assignment@titleblock stepcounter +% LocalWords: document@hwexamtype importmodules metasetkeys inclassig@title inclassig +% LocalWords: inclassig@title inclassig@type inclassig@type inclassig@number xspace kv +% LocalWords: inclassig@number inclassig@due inclassig@due inclassig@given ignorespaces +% LocalWords: inclassig@given newenvironment currentsectionlevel OptionalKeyVals kvi +% LocalWords: omgroup vals hwexamtype ednote textbackslash newcommand inputassignment +% LocalWords: unlist quizheading tas hspace hfill textbf newcount vfill addtocounter +% LocalWords: theassignment@totalmin theassignment@totalpts assignment@probs xdef hline +% LocalWords: assignment@totalpts assignment@totalmin correction@probs correction@probs +% LocalWords: newcounter theassignment@probs footnotesize mh@currentrepos endinput +% LocalWords: inclassig@mhrepos inclassig@mhrepos doctex inputmhassignment +% LocalWords: GPL structuresharing STR iffalse cls NeedsTeXFormat hwexam hwexam.dtx sc diff --git a/macros/latex/contrib/stex/source/extensions/notesslides.dtx b/macros/latex/contrib/stex/source/extensions/notesslides.dtx new file mode 100644 index 0000000000..a6ff395377 --- /dev/null +++ b/macros/latex/contrib/stex/source/extensions/notesslides.dtx @@ -0,0 +1,1078 @@ +% \iffalse meta-comment +% A LaTeX Class for Semantic Lectures Slides (originally developed for Michael Kohlhase) +% Copyright (c) 2019 Michael Kohlhase, all rights reserved +% this file is released under the +% Gnu Library Public Licences (LGPL) +% +% The original of this file is in the public repository at +% http://github.com/sLaTeX/sTeX/ +% \fi +% +% \iffalse +% +%<*driver> +\providecommand\bibfolder{../../lib/bib} +\input{../../doc/docheader} + +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% ^^A\changes{v0.1}{2005/12/06}{Initial Version} +% +% \GetFileInfo{notesslides.cls} +% \MakeShortVerb{\|} +% +% \def\twin#1#2{\index{#1!#2}\index{#2!#1}} +% \def\twintoo#1#2{{#1 #2}\twin{#1}{#2}} +% \def\atwin#1#2#3{\index{#1!#2!#3}\index{#3!#2 (#1)}} +% \def\atwintoo#1#2#3{{#1 #2 #3}\atwin{#1}{#2}{#3}} +% +% \def\scsys#1{{{\sc #1}}\index{#1@{\sc #1}}} +% \def\stex{\hbox{\raisebox{-.5ex}S\kern-.5ex\TeX}} +% \def\sTeX{\stex} +% \def\cnxml{\scshape{CNXml}} +% \def\connexions{\scshape{Connexions}} +% \def\element#1{{\ttfamily{#1}}} +% \def\snippet#1{{\ttfamily{#1}}} +% \def\cnxlatex{CNX\LaTeX\xspace} +% \def\mathml{{\scshape{MathML}}\xspace} +% \def\omdoc{OMDoc\xspace} +% \def\activemath{{\scshape{ActiveMath}}\xspace} +% \def\textwarning{\includegraphics[width=1.2em]{dangerous-bend}\xspace} +% +% \title{NotesSlides -- Slides and Course Notes\thanks{Version {\fileversion} +% (last revised {\filedate})}} +% \author{Michael Kohlhase\\ +% FAU Erlangen-N\"urnberg\\ +% \url{http://kwarc.info/kohlhase}} +% \maketitle +% +%\ifinfulldoc\else +% This is the documentation for the \pkg{notesslides} package. +% For a more high-level introduction, +% see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the +% \href{\basedocurl/stex.pdf}{full \sTeX documentation}. +% +% \input{../../doc/packages/slides} +% \fi +% +% \begin{documentation}\label{pkg:notesslides:doc} +% +% We present a document class from which we can generate both course slides and course +% notes in a transparent way. +% +%\section{Introduction} +% +% The |notesslides| document class is derived from |beamer.cls|~\cite{beamerclass:on}, it +% adds a ``notes version'' for course notes derived from the |omdoc| +% class~\cite{Kohlhase:smomdl} that is more suited to printing than the one supplied by +% |beamer.cls|. +% +% +%\section{The User Interface}\label{sec:user} +% +% The |notesslides| class takes the notion of a slide frame from Till Tantau's excellent +% |beamer| class and adapts its notion of frames for use in the \sTeX and \omdoc. To +% support semantic course notes, it extends the notion of mixing frames and explanatory +% text, but rather than treating the frames as images (or integrating their contents into +% the flowing text), the |notesslides| package displays the slides as such in the course +% notes to give students a visual anchor into the slide presentation in the course (and to +% distinguish the different writing styles in slides and course notes). +% +% In practice we want to generate two documents from the same source: the slides for +% presentation in the lecture and the course notes as a narrative document for home +% study. To achieve this, the |notesslides| class has two modes: \emph{slides mode} and +% \emph{notes mode} which are determined by the package option. +% +% \subsection{Package Options}\label{sec:user:options} +% +% The |notesslides| class takes a variety of class options:\ednote{leaving out noproblems +% for the moment until we decide what to do with it.} +% \begin{itemize} +% \item The options \DescribeMacro{slides}|slides| and \DescribeMacro{notes}|notes| switch +% between slides mode and notes mode (see Section~\ref{sec:user:notesslides}). +% \item If the option \DescribeMacro{sectocframes}|sectocframes| is given, then for the +% |omgroup|s, special frames with the |omgroup| title (and number) are generated. +% \item \DescribeMacro{showmeta}|showmeta|. If this is set, then the metadata keys are +% shown (see~\cite{Kohlhase:metakeys:git} for details and customization options). +% \item If the option \DescribeMacro{frameimages}|frameimages| is set, then slide mode +% also shows the |\frameimage|-generated frames (see +% section~\ref{sec:user:frameimage}). If also the \DescribeMacro{fiboxed}|fiboxed| +% option is given, the slides are surrounded by a box. +% \item \DescribeMacro{topsect}|topsect=|\meta{sect} can be used to specify the +% top-level sectioning level; the default for \meta{sect} is |section|. +% \end{itemize} +% +% \subsection{Notes and Slides}\label{sec:user:notesslides} +% +% Slides are represented with the \DescribeEnv{frame}|frame| just like in the |beamer| +% class, see~\cite{Tantau:ugbc} for details. The |notesslides| class adds the +% \DescribeEnv{note}|note| environment for encapsulating the course note +% fragments.\footnote{MK: it would be very nice, if we did not need this environment, and +% this should be possible in principle, but not without intensive LaTeX trickery. Hints to +% the author are welcome.} +% +% \textwarning Note that it is essential to start and end the |notes| environment at the +% start of the line -- in particular, there may not be leading blanks -- else {\LaTeX} +% becomes confused and throws error messages that are difficult to decipher. +% +% \begin{exfig} +% \begin{verbatim} +% \ifnotes\maketitle\else +% \frame[noframenumbering]\maketitle\fi +% +% \begin{note} +% We start this course with ... +% \end{note} +% +% \begin{frame} +% \frametitle{The first slide} +% ... +% \end{frame} +% \begin{note} +% ... and more explanatory text +% \end{note} +% +% \begin{frame} +% \frametitle{The second slide} +% ... +% \end{frame} +% ... +% \end{verbatim} +% \caption{A typical Course Notes File}\label{fig:notesfile} +% \end{exfig} +% +% By interleaving the |frame| and |note| environments, we can build course notes as shown +% in Figure~\ref{fig:notesfile}. +% +% Note the use of the \DescribeMacro{\ifnotes}|\ifnotes| conditional, which allows +% different treatment between |notes| and |slides| mode -- manually setting |\notestrue| +% or |\notesfalse| is strongly discouraged however. +% +% \textwarning: We need to give the title frame the |noframenumbering| option so that the +% frame numbering is kept in sync between the slides and the course notes. +% +% \textwarning: The |beamer| class recommends not to use the |allowframebreaks| option on +% frames (even though it is very convenient). This holds even more in the |notesslides| +% case: At least in conjunction with |\newpage|, frame numbering behaves funnily (we have +% tried to fix this, but who knows). +% +% If we want to transclude a the contents of a file as a note, we can use a new variant +% \DescribeMacro{\inputref*}|\inputref*| of the |\inputref| macro from +% \cite{KohAmb:smmssl:git}: |\inputref*{foo}| is equivalent to +% |\begin{note}\inputref{foo}\end{note}|. +% +% There are some environments that tend to occur at the top-level of |note| +% environments. We make convenience versions of these: e.g. the +% \DescribeEnv{nparagraph}|nparagraph| environment is just an |sparagraph| inside a |note| +% environment (but looks nicer in the source, since it avoids one level of source +% indenting). Similarly, we have the \DescribeEnv{nfragment}|nomgroup|, +% \DescribeEnv{ndefinition}|ndefinition|, \DescribeEnv{nexample}|nexample|, +% \DescribeEnv{nsproof}|nsproof|, and \DescribeEnv{nassertion}|nassertion| environments. +% +% \subsection{Header and Footer Lines of the Slides}\label{sec:user:headfootlines} +% +% The default logo provided by the |notesslides| package is the {\sTeX} logo it can be +% customized using \DescribeMacro{\setslidelogo}|\setslidelogo{|\meta{logo name}|}|. +% +% The default footer line of the |notesslides| package mentions copyright and licensing. In +% the |beamer| class, |\source| stores the author's name as the copyright holder . By +% default it is {\it Michael Kohlhase} in the |notesslides| package since he is the main +% user and designer of this package. \DescribeMacro{\setsource}|\setsource{|\meta{name}|}| +% can change the writer's name. For licensing, we use the Creative Commons +% Attribuition-ShareAlike license by default to strengthen the public domain. If package +% |hyperref| is loaded, then we can attach a hyperlink to the license +% logo. \DescribeMacro{\setlicensing}|\setlicensing[|\meta{url}|]{|\meta{logo name}|}| is +% used for customization, where \meta{url} is optional. +% +% \subsection{Frame Images}\label{sec:user:frameimage} +% +% Sometimes, we want to integrate slides as images after all -- e.g. because we already +% have a PowerPoint presentation, to which we want to add \sTeX notes. In this case we can +% use \DescribeMacro{\frameimage}|\frameimage[|\meta{opt}|]{|\meta{path}|}|, where +% \meta{opt} are the options of |\includegraphics| from the |graphicx| +% package~\cite{CarRah:tpp99} and \meta{path} is the file path (extension can be left off +% like in |\includegraphics|). We have added the |label| key that allows to give a frame +% label that can be referenced like a regular |beamer| frame.\ednote{MK: the hyperref link +% does not seem to work yet. I wonder why but do not have the time to fix it.} +% +% The \DescribeMacro{\mhframeimage}|\mhframeimage| macro is a variant of |\frameimage| +% with repository support. Instead of writing +% \begin{verbatim} +% \frameimage{\MathHub{fooMH/bar/source/baz/foobar}} +% \end{verbatim} +% we can simply write (assuming that |\MathHub| is defined as above) +% \begin{verbatim} +% \mhframeimage[fooMH/bar]{baz/foobar} +% \end{verbatim} +% Note that the |\mhframeimage| form is more semantic, which allows more advanced document +% management features in \textsf{MathHub}. +% +% If |baz/foobar| is the ``current module'', i.e. if we are on the \textsf{MathHub} path +% \ldots|MathHub/fooMH/bar|\ldots, then stating the repository in the first optional +% argument is redundant, so we can just use +% \begin{verbatim} +% \mhframeimage{baz/foobar} +% \end{verbatim} +% +% \subsection{Colors and Highlighting}\label{sec:user:highlighting} +% The \DescribeMacro{\textwarning}|\textwarning| macro generates a warning +% sign: \textwarning +% +% \subsection{Front Matter, Titles, etc.}\label{sec:user:matter} +% +% \subsection{Excursions}\label{sec:user:excursions} +% +% In course notes, we sometimes want to point to an ``excursion'' -- material that is +% either presupposed or tangential to the course at the moment -- e.g. in an appendix. The +% typical setup is the following: +% +% \begin{verbatim} +% \excursion{founif}{../ex/founif}{We will cover first-order unification in} +% ... +% \begin{appendix}\printexcursions\end{appendix} +% \end{verbatim} +% +% The \DescribeMacro{\excursion}|\excursion{|\meta{ref}|}{|\meta{path}|}{|\meta{text}|}| is +% syntactic sugar for \DescribeMacro{\activateexcursion} +% +% \begin{verbatim} +% \begin{nparagraph}[title=Excursion] +% \activateexcursion{founif}{../ex/founif} +% We will cover first-order unification in \sref{founif}. +% \end{nparagraph} +% \end{verbatim} +% +% where \DescribeMacro{\activateexcursion}|\activateexcursion{|\meta{path}|}| augments the +% |\printexcursions| macro by a call |\inputref{|\meta{path}|}|. In this way, the3 +% \DescribeMacro{\printexcursions}|\printexcursions| macro (usually in the appendix) will +% collect up all excursions that are specified in the main text. +% +% Sometimes, we want to reference -- in an excursion -- part of another. We can use +% \DescribeMacro{\excursionref}|\excursionref{|\meta{label}|}| for that. +% +% Finally, we usually want to put the excursions into an |omgroup| environment and add an +% introduction, therefore we provide the a variant of the |\printexcursions| macro: +% \DescribeMacro{\excursiongroup}|\excursiongroup[id=|\meta{id}|,intro=|\meta{path}|]| is +% equivalent to +% \begin{verbatim} +% \begin{note} +% \begin{sfragment}[id=<id>]{Excursions} +% \inputref{<path>} +% \printexcursions +% \end{sfragment} +% \end{note} +% \end{verbatim} +% +% \subsection{Miscellaneous}\label{sec:user:misc} +% +% \section{Limitations}\label{sec:limitations} +% +% In this section we document known limitations. If you want to help alleviate them, +% please feel free to contact the package author. Some of them are currently discussed in +% the \sTeX GitHub repository~\cite{sTeX:github:on}. +% \begin{enumerate} +% \item when option |book| which uses |\pagestyle{headings}| is given and semantic macros +% are given in the |omgroup| titles, then they sometimes are not defined by the time the +% heading is formatted. Need to look into how the headings are made. This is a problem +% of the underlying |omdoc| package. +% \end{enumerate} +% +% \end{documentation} +% +% \begin{implementation}\label{pkg:notesslides:impl} +% +%\section{NotesSlides -- Implementation}\label{sec:impl} +% +%\subsection{Class and Package Options}\label{sec:impl:init} +% +% We define some Package Options and switches for the |notesslides| class and activate them +% by passing them on to |beamer.cls| and |omdoc.cls| and the |notesslides| package. We pass +% the |nontheorem| option to the |statements| package when we are not in notes mode, since +% the |beamer| package has its own (overlay-aware) theorem environments. +% +% \begin{macrocode} +%<*cls> +%<@@=notesslides> +\ProvidesExplClass{notesslides}{2022/02/24}{3.0.0}{notesslides Class} +\RequirePackage{l3keys2e} + +\keys_define:nn{notesslides / cls}{ + class .code:n = { + \PassOptionsToClass{\CurrentOption}{document-structure} + \str_if_eq:nnT{#1}{book}{ + \PassOptionsToPackage{defaulttopsec=part}{notesslides} + } + \str_if_eq:nnT{#1}{report}{ + \PassOptionsToPackage{defaulttopsec=part}{notesslides} + } + }, + notes .bool_set:N = \c_@@_notes_bool , + slides .code:n = { \bool_set_false:N \c_@@_notes_bool }, + unknown .code:n = { + \PassOptionsToClass{\CurrentOption}{document-structure} + \PassOptionsToClass{\CurrentOption}{beamer} + \PassOptionsToPackage{\CurrentOption}{notesslides} + } +} +\ProcessKeysOptions{ notesslides / cls } +\bool_if:NTF \c_@@_notes_bool { + \PassOptionsToPackage{notes=true}{notesslides} +}{ + \PassOptionsToPackage{notes=false}{notesslides} +} +%</cls> +% \end{macrocode} +% now we do the same for the |notesslides| package. +% \begin{macrocode} +%<*package> +\ProvidesExplPackage{notesslides}{2022/02/24}{3.0.0}{notesslides Package} +\RequirePackage{l3keys2e} + +\keys_define:nn{notesslides / pkg}{ + topsect .str_set_x:N = \c_@@_topsect_str, + defaulttopsect .str_set_x:N = \c_@@_defaulttopsec_str, + notes .bool_set:N = \c_@@_notes_bool , + slides .code:n = { \bool_set_false:N \c_@@_notes_bool }, + sectocframes .bool_set:N = \c_@@_sectocframes_bool , + frameimages .bool_set:N = \c_@@_frameimages_bool , + fiboxed .bool_set:N = \c_@@_fiboxed_bool , + noproblems .bool_set:N = \c_@@_noproblems_bool, + unknown .code:n = { + \PassOptionsToClass{\CurrentOption}{stex} + \PassOptionsToClass{\CurrentOption}{tikzinput} + } +} +\ProcessKeysOptions{ notesslides / pkg } +\newif\ifnotes +\bool_if:NTF \c_@@_notes_bool { + \notestrue +}{ + \notesfalse +} + +% \end{macrocode} +% we give ourselves a macro |\@@topsect| that needs only be evaluated once, so that the +% |\ifdefstring| conditionals work below. +% \begin{macrocode} +\str_if_empty:NTF \c_@@_topsect_str { + \str_set_eq:NN \@@topsect \c_@@_defaulttopsec_str +}{ + \str_set_eq:NN \@@topsect \c_@@_topsect_str +} +%</package> +% \end{macrocode} +% +% Depending on the options, we either load the |article|-based |document-structure| or the |beamer| +% class (and set some counters). +% \begin{macrocode} +%<*cls> +\bool_if:NTF \c_@@_notes_bool { + \LoadClass{document-structure} +}{ + \LoadClass[10pt,notheorems,xcolor={dvipsnames,svgnames}]{beamer} + \newcounter{Item} + \newcounter{paragraph} + \newcounter{subparagraph} + \newcounter{Hfootnote} + \RequirePackage{document-structure} +} +% \end{macrocode} +% now it only remains to load the |notesslides| package that does all the rest. +% \begin{macrocode} +\RequirePackage{notesslides} +%</cls> +% \end{macrocode} +% +% In |notes| mode, we also have to make the |beamer|-specific things available to +% |article| via the |beamerarticle| package. We use options to avoid loading theorem-like +% environments, since we want to use our own from the $\sTeX$ packages. The first batch +% of packages we want are loaded on |notesslides.sty|. These are the general ones, we will +% load the \sTeX-specific ones after we have done some work (e.g. defined the counters +% |m*|). Only the |stex-logo| package is already needed now for the default theme. +% +% \begin{macrocode} +%<*package> +\bool_if:NT \c_@@_notes_bool { + \RequirePackage{a4wide} + \RequirePackage{marginnote} + \PassOptionsToPackage{usenames,dvipsnames,svgnames}{xcolor} + \RequirePackage{mdframed} + \RequirePackage[noxcolor,noamsthm]{beamerarticle} + \RequirePackage[bookmarks,bookmarksopen,bookmarksnumbered,breaklinks,hidelinks]{hyperref} +} +\RequirePackage{stex-tikzinput} +\RequirePackage{etoolbox} +\RequirePackage{amssymb} +\RequirePackage{amsmath} +\RequirePackage{comment} +\RequirePackage{textcomp} +\RequirePackage{url} +\RequirePackage{graphicx} +\RequirePackage{pgf} +% \end{macrocode} +% +% \subsection{Notes and Slides}\label{sec:impl:noteslides} +% +% For the lecture notes cases, we also provide the |\usetheme| macro that would otherwise +% come from the the |beamer| class. While the latter loads +% |beamertheme|\meta{theme}{.sty}, the notes version loads +% |beamernotestheme|\meta{theme}|.sty|.\ednote{MK: This is not ideal, but I am not sure +% that I want to be able to provide the full theme functionality there.} +% \begin{macrocode} +\bool_if:NT \c_@@_notes_bool { + \renewcommand\usetheme[2][]{\usepackage[#1]{beamernotestheme#2}} +} +% \end{macrocode} +% We define the sizes of slides in the notes. Somehow, we cannot get by with the same +% here. +% +% \begin{macrocode} +\newcounter{slide} +\newlength{\slidewidth}\setlength{\slidewidth}{13.5cm} +\newlength{\slideheight}\setlength{\slideheight}{9cm} +% \end{macrocode} +% +% \begin{environment}{note} +% The |note| environment is used to leave out text in the |slides| mode. It does not have +% a counterpart in OMDoc. So for course notes, we define the |note| environment to be a +% no-operation otherwise we declare the |note| environment as a comment via the |comment| +% package. +% \begin{macrocode} +\bool_if:NTF \c_@@_notes_bool { + \renewenvironment{note}{\ignorespaces}{} +}{ + \excludecomment{note} +} +% \end{macrocode} +% \end{environment} +% +% We first set up the slide boxes in |article| mode. We set up sizes and provide a +% box register for the frames and a counter for the slides. +% +% \begin{macrocode} +\bool_if:NT \c_@@_notes_bool { + \newlength{\slideframewidth} + \setlength{\slideframewidth}{1.5pt} +% \end{macrocode} +% +% \begin{environment}{frame} +% We first define the keys. +% \begin{macrocode} + \cs_new_protected:Nn \_@@_do_yes_param:Nn { + \exp_args:Nx \str_if_eq:nnTF { \str_uppercase:n{ #2 } }{ yes }{ + \bool_set_true:N #1 + }{ + \bool_set_false:N #1 + } + } + \keys_define:nn{notesslides / frame}{ + label .str_set_x:N = \l_@@_frame_label_str, + allowframebreaks .code:n = { + \_@@_do_yes_param:Nn \l_@@_frame_allowframebreaks_bool { #1 } + }, + allowdisplaybreaks .code:n = { + \_@@_do_yes_param:Nn \l_@@_frame_allowdisplaybreaks_bool { #1 } + }, + fragile .code:n = { + \_@@_do_yes_param:Nn \l_@@_frame_fragile_bool { #1 } + }, + shrink .code:n = { + \_@@_do_yes_param:Nn \l_@@_frame_shrink_bool { #1 } + }, + squeeze .code:n = { + \_@@_do_yes_param:Nn \l_@@_frame_squeeze_bool { #1 } + }, + t .code:n = { + \_@@_do_yes_param:Nn \l_@@_frame_t_bool { #1 } + }, + } + \cs_new_protected:Nn \_@@_frame_args:n { + \str_clear:N \l_@@_frame_label_str + \bool_set_true:N \l_@@_frame_allowframebreaks_bool + \bool_set_true:N \l_@@_frame_allowdisplaybreaks_bool + \bool_set_true:N \l_@@_frame_fragile_bool + \bool_set_true:N \l_@@_frame_shrink_bool + \bool_set_true:N \l_@@_frame_squeeze_bool + \bool_set_true:N \l_@@_frame_t_bool + \keys_set:nn { notesslides / frame }{ #1 } + } +% \end{macrocode} +% We define the environment, read them, and construct the slide number and label. +% \begin{macrocode} + \renewenvironment{frame}[1][]{ + \_@@_frame_args:n{#1} + \sffamily + \stepcounter{slide} + \def\@currentlabel{\theslide} + \str_if_empty:NF \l_@@_frame_label_str { + \label{\l_@@_frame_label_str} + } +% \end{macrocode} +% We redefine the |itemize| environment so that it looks more like the one in |beamer|. +% \begin{macrocode} + \def\itemize@level{outer} + \def\itemize@outer{outer} + \def\itemize@inner{inner} + \renewcommand\newpage{\addtocounter{framenumber}{1}} + \newcommand\metakeys@show@keys[2]{\marginnote{{\scriptsize ##2}}} + \renewenvironment{itemize}{ + \ifx\itemize@level\itemize@outer + \def\itemize@label{$\rhd$} + \fi + \ifx\itemize@level\itemize@inner + \def\itemize@label{$\scriptstyle\rhd$} + \fi + \begin{list} + {\itemize@label} + {\setlength{\labelsep}{.3em} + \setlength{\labelwidth}{.5em} + \setlength{\leftmargin}{1.5em} + } + \edef\itemize@level{\itemize@inner} + }{ + \end{list} + } +% \end{macrocode} +% We create the box with the |mdframed| environment from the equinymous package. +% \begin{macrocode} + \begin{mdframed}[linewidth=\slideframewidth,skipabove=1ex,skipbelow=1ex,userdefinedwidth=\slidewidth,align=center]\sf + }{ + \medskip\miko@slidelabel\end{mdframed} + } +% \end{macrocode} +% \end{environment} +% +% Now, we need to redefine the frametitle (we are still in course notes mode). +% \begin{macro}{\frametitle} +% \begin{macrocode} + \renewcommand{\frametitle}[1]{{\Large\bf\sf\color{blue}{#1}}\medskip} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\pause} +% \ednote{MK: fake it in notes mode for now} +% \begin{macrocode} +\bool_if:NT \c_@@_notes_bool { + \newcommand\pause{} +} +% \end{macrocode} +% \end{macro} +% +% \begin{environment}{nparagraph} +% \begin{macrocode} +\bool_if:NTF \c_@@_notes_bool { + \newenvironment{nparagraph}[1][]{\begin{sparagraph}[#1]}{\end{sparagraph}} +}{ + \excludecomment{nparagraph} +} +% \end{macrocode} +% \end{environment} +% +% \begin{environment}{nfragment} +% \begin{macrocode} +\bool_if:NTF \c_@@_notes_bool { + \newenvironment{nfragment}[2][]{\begin{sfragment}[#1]{#2}}{\end{sfragment}} +}{ + \excludecomment{nfragment} +} +% \end{macrocode} +% \end{environment} +% +% \begin{environment}{ndefinition} +% \begin{macrocode} +\bool_if:NTF \c_@@_notes_bool { + \newenvironment{ndefinition}[1][]{\begin{sdefinition}[#1]}{\end{sdefinition}} +}{ + \excludecomment{ndefinition} +} +% \end{macrocode} +% \end{environment} +% +% \begin{environment}{nassertion} +% \begin{macrocode} +\bool_if:NTF \c_@@_notes_bool { + \newenvironment{nassertion}[1][]{\begin{sassertion}[#1]}{\end{sassertion}} +}{ + \excludecomment{nassertion} +} +% \end{macrocode} +% \end{environment} +% +% \begin{environment}{nsproof} +% \begin{macrocode} +\bool_if:NTF \c_@@_notes_bool { + \newenvironment{nproof}[2][]{\begin{sproof}[#1]{#2}}{\end{sproof}} +}{ + \excludecomment{nproof} +} +% \end{macrocode} +% \end{environment} +% +% \begin{environment}{nexample} +% \begin{macrocode} +\bool_if:NTF \c_@@_notes_bool { + \newenvironment{nexample}[1][]{\begin{sexample}[#1]}{\end{sexample}} +}{ + \excludecomment{nexample} +} +% \end{macrocode} +% \end{environment} +% +% \begin{macro}{\inputref@*skip} +% We customize the hooks for in |\inputref|. +% \begin{macrocode} +\def\inputref@preskip{\smallskip} +\def\inputref@postskip{\medskip} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\inputref*} +% \begin{macrocode} +\let\orig@inputref\inputref +\def\inputref{\@ifstar\ninputref\orig@inputref} +\newcommand\ninputref[2][]{ + \bool_if:NT \c_@@_notes_bool { + \orig@inputref[#1]{#2} + } +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Header and Footer Lines}\label{sec:impl:headfootlines} +% +% Now, we set up the infrastructure for the footer line of the slides, we use boxes for +% the logos, so that they are only loaded once, that considerably speeds up processing. +% +% \begin{macro}{\setslidelogo} +% The default logo is the {\sTeX} logo. Customization can be done by |\setslidelogo{|\meta{logo name}|}|. +% \begin{macrocode} +\newlength{\slidelogoheight} + +\bool_if:NTF \c_@@_notes_bool { + \setlength{\slidelogoheight}{.4cm} +}{ + \setlength{\slidelogoheight}{1cm} +} +\newsavebox{\slidelogo} +\sbox{\slidelogo}{\sTeX} +\newrobustcmd{\setslidelogo}[1]{ + \sbox{\slidelogo}{\includegraphics[height=\slidelogoheight]{#1}} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\setsource} +% |\source| stores the writer's name. By default it is {\it Michael Kohlhase} since he is the main user and designer of this package. |\setsource{|\meta{name}|}| can change the writer's name. +% \begin{macrocode} +\def\source{Michael Kohlhase}% customize locally +\newrobustcmd{\setsource}[1]{\def\source{#1}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\setlicensing} +% Now, we set up the copyright and licensing. By default we use the Creative Commons +% Attribuition-ShareAlike license to strengthen the public domain. If package |hyperref| +% is loaded, then we can attach a hyperlink to the license +% logo. |\setlicensing[|\meta{url}|]{|\meta{logo name}|}| is used for customization, +% where ||\meta{url}|| is optional. +% \begin{macrocode} +\def\copyrightnotice{\footnotesize\copyright :\hspace{.3ex}{\source}} +\newsavebox{\cclogo} +\sbox{\cclogo}{\includegraphics[height=\slidelogoheight]{cc_somerights}} +\newif\ifcchref\cchreffalse +\AtBeginDocument{ + \@ifpackageloaded{hyperref}{\cchreftrue}{\cchreffalse} +} +\def\licensing{ + \ifcchref + \href{http://creativecommons.org/licenses/by-sa/2.5/}{\usebox{\cclogo}} + \else + {\usebox{\cclogo}} + \fi +} +\newrobustcmd{\setlicensing}[2][]{ + \def\@url{#1} + \sbox{\cclogo}{\includegraphics[height=\slidelogoheight]{#2}} + \ifx\@url\@empty + \def\licensing{{\usebox{\cclogo}}} + \else + \def\licensing{ + \ifcchref + \href{#1}{\usebox{\cclogo}} + \else + {\usebox{\cclogo}} + \fi + } + \fi +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\slidelabel} +% Now, we set up the slide label for the |article| mode.\ednote{see that we can use the themes for the slides some day. This is all fake.} +% \begin{macrocode} +\newrobustcmd\miko@slidelabel{ + \vbox to \slidelogoheight{ + \vss\hbox to \slidewidth + {\licensing\hfill\copyrightnotice\hfill\arabic{slide}\hfill\usebox{\slidelogo}} + } +} +% \end{macrocode} +% \end{macro} +% \subsection{Frame Images}\label{sec:impl:frameimage} +% +% \begin{macro}{\frameimage} +% We have to make sure that the width is overwritten, for that we check the +% |\Gin@ewidth| macro from the |graphicx| package. We also add the |label| key. +% \begin{macrocode} +\def\Gin@mhrepos{} +\define@key{Gin}{mhrepos}{\def\Gin@mhrepos{#1}} +\define@key{Gin}{label}{\def\@currentlabel{\arabic{slide}}\label{#1}} +\newrobustcmd\frameimage[2][]{ + \stepcounter{slide} + \bool_if:NT \c_@@_frameimages_bool { + \def\Gin@ewidth{}\setkeys{Gin}{#1} + \bool_if:NF \c_@@_notes_bool { \vfill } + \begin{center} + \bool_if:NTF \c_@@_fiboxed_bool { + \fbox{ + \ifx\Gin@ewidth\@empty + \ifx\Gin@mhrepos\@empty + \mhgraphics[width=\slidewidth,#1]{#2} + \else + \mhgraphics[width=\slidewidth,#1,mhrepos=\Gin@mhrepos]{#2} + \fi + \else% Gin@ewidth empty + \ifx\Gin@mhrepos\@empty + \mhgraphics[#1]{#2} + \else + \mhgraphics[#1,mhrepos=\Gin@mhrepos]{#2} + \fi + \fi% Gin@ewidth empty + } + }{ + \ifx\Gin@ewidth\@empty + \ifx\Gin@mhrepos\@empty + \mhgraphics[width=\slidewidth,#1]{#2} + \else + \mhgraphics[width=\slidewidth,#1,mhrepos=\Gin@mhrepos]{#2} + \fi + \ifx\Gin@mhrepos\@empty + \mhgraphics[#1]{#2} + \else + \mhgraphics[#1,mhrepos=\Gin@mhrepos]{#2} + \fi + \fi% Gin@ewidth empty + } + \end{center} + \par\strut\hfill{\footnotesize Slide \arabic{slide}}% + \bool_if:NF \c_@@_notes_bool { \vfill } + } +} % ifmks@sty@frameimages +% \end{macrocode} +% \end{macro} +% +% \subsection{Colors and Highlighting}\label{sec:impl:highlighting} +% +% We first specify sans serif fonts as the default. +% +% \begin{macrocode} +\sffamily +% \end{macrocode} +% +% Now, we set up an infrastructure for highlighting phrases in slides. Note that we use +% content-oriented macros for highlighting rather than directly using color markup. +% The first thing to to is to adapt the green so that it is dark enough for most beamers +% \begin{macrocode} +\AddToHook{begindocument}{ + \definecolor{green}{rgb}{0,.5,0} + \definecolor{purple}{cmyk}{.3,1,0,.17} +} +% \end{macrocode} +% +% We customize the |\defemph|, |\symrefemph|, |\compemph|, and |\titleemph| macros with +% colors. Furthermore we customize the |\__omtextlec| macro for the appearance of line end +% comments in |\lec|. +% +% \begin{macrocode} +% \def\STpresent#1{\textcolor{blue}{#1}} +\def\defemph#1{{\textcolor{magenta}{#1}}} +\def\symrefemph#1{{\textcolor{cyan}{#1}}} +\def\compemph#1{{\textcolor{blue}{#1}}} +\def\titleemph#1{{\textcolor{blue}{#1}}} +\def\__omtext_lec#1{(\textcolor{green}{#1})} +% \end{macrocode} +% +% I like to use the dangerous bend symbol for warnings, so we provide it here. +% \begin{macro}{\textwarning} +% as the macro can be used quite often we put it into a box register, so that it is only +% loaded once. +% \begin{macrocode} +\pgfdeclareimage[width=.8em]{miko@small@dbend}{dangerous-bend} +\def\smalltextwarning{ + \pgfuseimage{miko@small@dbend} + \xspace +} +\pgfdeclareimage[width=1.2em]{miko@dbend}{dangerous-bend} +\newrobustcmd\textwarning{ + \raisebox{-.05cm}{\pgfuseimage{miko@dbend}} + \xspace +} +\pgfdeclareimage[width=2.5em]{miko@big@dbend}{dangerous-bend} +\newrobustcmd\bigtextwarning{ + \raisebox{-.05cm}{\pgfuseimage{miko@big@dbend}} + \xspace +} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\newrobustcmd\putgraphicsat[3]{ + \begin{picture}(0,0)\put(#1){\includegraphics[#2]{#3}}\end{picture} +} +\newrobustcmd\putat[2]{ + \begin{picture}(0,0)\put(#1){#2}\end{picture} +} +% \end{macrocode} +% +% \subsection{Sectioning} +% +% If the |sectocframes| option is set, then we make section frames. We first define +% counters for |part| and |chapter|, which |beamer.cls| does not have and we make the +% |section| counter which it does dependent on |chapter|. +% \begin{macrocode} +\bool_if:NT \c_@@_sectocframes_bool { + \str_if_eq:VnTF \@@topsect{part}{ + \newcounter{chapter}\counterwithin*{section}{chapter} + }{ + \str_if_eq:VnT\@@topsect{chapter}{ + \newcounter{chapter}\counterwithin*{section}{chapter} + } + } +} +% \end{macrocode} +% +% We set the \DescribeMacro{\section@level}|\section@level| counter that governs +% sectioning according to the class options. We also introduce the sectioning counters +% accordingly. +% +% \begin{macro}{\section@level} +% \begin{macrocode} +\def\part@prefix{} +\@ifpackageloaded{document-structure}{}{ + \str_case:VnF \@@topsect { + {part}{ + \int_set:Nn \l_document_structure_section_level_int {0} + \def\thesection{\arabic{chapter}.\arabic{section}} + \def\part@prefix{\arabic{chapter}.} + } + {chapter}{ + \int_set:Nn \l_document_structure_section_level_int {1} + \def\thesection{\arabic{chapter}.\arabic{section}} + \def\part@prefix{\arabic{chapter}.} + } + }{ + \int_set:Nn \l_document_structure_section_level_int {2} + \def\part@prefix{} + } +} + +\bool_if:NF \c_@@_notes_bool { % only in slides +% \end{macrocode} +% \end{macro} +% +% The new counters are used in the |omgroup| environment that choses the {\LaTeX} +% sectioning macros according to |\section@level|. +% +% \begin{environment}{sfragment} +% \begin{macrocode} + \renewenvironment{sfragment}[2][]{ + \__document_structure_omgroup_args:n { #1 } + \int_incr:N \l_document_structure_section_level_int + \bool_if:NT \c_@@_sectocframes_bool { + \stepcounter{slide} + \begin{frame}[noframenumbering] + \vfill\Large\centering + \red{ + \ifcase\l_document_structure_section_level_int\or + \stepcounter{part} + \def\@@label{\omdoc@part@kw~\Roman{part}} + \def\currentsectionlevel{\omdoc@part@kw} + \or + \stepcounter{chapter} + \def\@@label{\omdoc@chapter@kw~\arabic{chapter}} + \def\currentsectionlevel{\omdoc@chapter@kw} + \or + \stepcounter{section} + \def\@@label{\part@prefix\arabic{section}} + \def\currentsectionlevel{\omdoc@section@kw} + \or + \stepcounter{subsection} + \def\@@label{\part@prefix\arabic{section}.\arabic{subsection}} + \def\currentsectionlevel{\omdoc@subsection@kw} + \or + \stepcounter{subsubsection} + \def\@@label{\part@prefix\arabic{section}.\arabic{subsection}.\arabic{subsubsection}} + \def\currentsectionlevel{\omdoc@subsubsection@kw} + \or + \stepcounter{paragraph} + \def\@@label{\part@prefix\arabic{section}.\arabic{subsection}.\arabic{subsubsection}.\arabic{paragraph}} + \def\currentsectionlevel{\omdoc@paragraph@kw} + \else + \def\@@label{} + \def\currentsectionlevel{\omdoc@paragraph@kw} + \fi% end ifcase + \@@label%\sref@label@id\@@label + \quad #2% + }% + \vfill% + \end{frame}% + } + \str_if_empty:NF \l__document_structure_omgroup_id_str { + \stex_ref_new_doc_target:n\l__document_structure_omgroup_id_str + } + }{} +} +% \end{macrocode} +% \end{environment} +% +% We set up a |beamer| template for theorems like ams style, but without a block +% environment. +% \begin{macrocode} +\def\inserttheorembodyfont{\normalfont} +%\bool_if:NF \c_@@_notes_bool { +% \defbeamertemplate{theorem begin}{miko} +% {\inserttheoremheadfont\inserttheoremname\inserttheoremnumber +% \ifx\inserttheoremaddition\@empty\else\ (\inserttheoremaddition)\fi% +% \inserttheorempunctuation\inserttheorembodyfont\xspace} +% \defbeamertemplate{theorem end}{miko}{} +% \end{macrocode} +% and we set it as the default one. +% \begin{macrocode} +% \setbeamertemplate{theorems}[miko] +% \end{macrocode} +% The following fixes an error I do not understand, this has something to do with +% beamer compatibility, which has similar definitions but only up to 1. +% \begin{macrocode} +% \expandafter\def\csname Parent2\endcsname{} +%} + +\AddToHook{begindocument}{ % this does not work for some reasone + \setbeamertemplate{theorems}[ams style] +} +\bool_if:NT \c_@@_notes_bool { + \renewenvironment{columns}[1][]{% + \par\noindent% + \begin{minipage}% + \slidewidth\centering\leavevmode% + }{% + \end{minipage}\par\noindent% + }% + \newsavebox\columnbox% + \renewenvironment<>{column}[2][]{% + \begin{lrbox}{\columnbox}\begin{minipage}{#2}% + }{% + \end{minipage}\end{lrbox}\usebox\columnbox% + }% +} +% \end{macrocode} +% +% \begin{macrocode} +\bool_if:NTF \c_@@_noproblems_bool { + \newenvironment{problems}{}{} +}{ + \excludecomment{problems} +} +% \end{macrocode} +% +% \subsection{Excursions}\label{sec:impl:excursions} +% +% \begin{macro}{\excursion} +% The excursion macros are very simple, we define a new internal macro |\excursionref| and +% use it in |\excursion|, which is just an |\inputref| that checks if the new macro is +% defined before formatting the file in the argument. +% \begin{macrocode} +\gdef\printexcursions{} +\newcommand\excursionref[2]{% label, text + \bool_if:NT \c_@@_notes_bool { + \begin{sparagraph}[title=Excursion] + #2 \sref[fallback=the appendix]{#1}. + \end{sparagraph} + } +} +\newcommand\activate@excursion[2][]{ + \gappto\printexcursions{\inputref[#1]{#2}} +} +\newcommand\excursion[4][]{% repos, label, path, text + \bool_if:NT \c_@@_notes_bool { + \activate@excursion[#1]{#3}\excursionref{#2}{#4} + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\excursiongroup} +% \begin{macrocode} +\keys_define:nn{notesslides / excursiongroup }{ + id .str_set_x:N = \l_@@_excursion_id_str, + intro .tl_set:N = \l_@@_excursion_intro_tl, + mhrepos .str_set_x:N = \l_@@_excursion_mhrepos_str +} +\cs_new_protected:Nn \_@@_excursion_args:n { + \tl_clear:N \l_@@_excursion_intro_tl + \str_clear:N \l_@@_excursion_id_str + \str_clear:N \l_@@_excursion_mhrepos_str + \keys_set:nn {notesslides / excursiongroup }{ #1 } +} +\newcommand\excursiongroup[1][]{ + \_@@_excursion_args:n{ #1 } + \ifdefempty\printexcursions{}% only if there are excursions + {\begin{note} + \begin{sfragment}[#1]{Excursions}% + \ifdefempty\l_@@_excursion_intro_tl{}{ + \inputref[\l_@@_excursion_mhrepos_str]{ + \l_@@_excursion_intro_tl + } + } + \printexcursions% + \end{sfragment} + \end{note}} +} +\ifcsname beameritemnestingprefix\endcsname\else\def\beameritemnestingprefix{}\fi +%</package> +% \end{macrocode} +% \end{macro} +% +% \end{implementation} +\endinput +% \endinput +% Local Variables: +% mode: doctex +% TeX-master: t +% End: + +% LocalWords: bibfolder jobname.dtx omdoc.dtx mytwocolumns beamer.cls sectocframes rhd +% LocalWords: frameimage twintoo atwin atwintoo scsys scshape ttfamily cnxlatex xspace +% LocalWords: mathml omdoc beamerclass:on Kohlhase:smomdl noproblems frameimages exfig +% LocalWords: frameimages fiboxed fiboxed topsect topsect Tantau:ugbc ifnotes ifnotes +% LocalWords: noframenumbering allowframebreaks newpage inputref inputref inputref sref +% LocalWords: setsource setsource setlicensing setlicensing CarRah:tpp99 mhframeimage +% LocalWords: mhframeimage printexcursions excursionref excursionref excursiongroup +% LocalWords: excursiongroup sec:impl nontheorem mks@cls,prefix mks@cls mks@sty,prefix +% LocalWords: mks@sty 10pt,notheorems,xcolor dvipsnames,svgnames Hfootnote mdframed +% LocalWords: beamerarticle noxcolor,noamsthm metakeys addmetakey usetheme beamertheme +% LocalWords: bookmarks,bookmarksopen,bookmarksnumbered,breaklinks,hidelinks sproof +% LocalWords: beamernotestheme slideframewidth allowdisplaybreaks framenumber sproof +% LocalWords: miko@slidelabel inputref@preskip smallskip ninputref slidelogoheight +% LocalWords: copyrightnotice cclogo cc_somerights ifcchref cchreffalse cchreftrue +% LocalWords: Gin@ewidth mh@currentrepos mhrepos if@iswindows defemph notemph STpresent +% LocalWords: smalltextwarning miko@dbend bigtextwarning counterwithin ifsectocframes +% LocalWords: subsubsection mparagraph csname stex_ref_new_doc_target:n columnbox +% LocalWords: inserttheorembodyfont defbeamertemplate inserttheoremheadfont mhexcursion +% LocalWords: inserttheoremname inserttheoremnumber inserttheoremaddition srefaddidkey +% LocalWords: inserttheoremaddition inserttheorempunctuation setbeamertemplate +% LocalWords: mhexcursiongroup diff --git a/macros/latex/contrib/stex/source/extensions/problem.dtx b/macros/latex/contrib/stex/source/extensions/problem.dtx new file mode 100644 index 0000000000..b21b1c493d --- /dev/null +++ b/macros/latex/contrib/stex/source/extensions/problem.dtx @@ -0,0 +1,910 @@ +% \iffalse meta-comment +% An Infrastructure for Problems +% Copyright (c) 2019 Michael Kohlhase, all rights reserved +% this file is released under the +% LaTeX Project Public License (LPPL) +% The original of this file is in the public repository at +% http://github.com/sLaTeX/sTeX/ +% \fi +% +% \iffalse +% +%<*driver> +\def\bibfolder{../../lib/bib} +\input{../../doc/docheader} +\RequirePackage[hints,solutions,notes]{problem} + +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \iffalse\CheckSum{318}\fi +% +% ^^A\changes{v0.9}{2006/09/18}{First Version with Documentation} +% +% \GetFileInfo{problem.sty} +% +% \MakeShortVerb{\|} +% +% \title{\texttt{problem.sty}: An Infrastructure for formatting Problems\thanks{Version {\fileversion} (last revised +% {\filedate})}} +% \author{Michael Kohlhase\\ +% FAU Erlangen-N\"urnberg\\ +% \url{http://kwarc.info/kohlhase}} +% \maketitle +% +%\ifinfulldoc\else +% This is the documentation for the \pkg{problem} package. +% For a more high-level introduction, +% see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the +% \href{\basedocurl/stex.pdf}{full \sTeX documentation}. +% +% \input{../../doc/packages/problem} +% \fi +% +% \begin{documentation} +% The |problem| package supplies an infrastructure that allows specify problems and to +% reuse them efficiently in multiple environments. +% +%\section{Introduction}\label{sec:intro} +% +% The |problem| package supplies an infrastructure that allows specify problem. Problems +% are text fragments that come with auxiliary functions: hints, notes, and +% solutions\footnote{for the moment multiple choice problems are not supported, but may +% well be in a future version}. Furthermore, we can specify how long the solution to a +% given problem is estimated to take and how many points will be awarded for a perfect +% solution. +% +% Finally, the |problem| package facilitates the management of problems in small files, +% so that problems can be re-used in multiple environment. +% +% \section{The User Interface}\label{sec:ui} +% +% \subsection{Package Options} +% The |problem| package takes the options \DescribeMacro{solutions}|solutions| (should +% solutions be output?), \DescribeMacro{notes}|notes| (should the problem notes be +% presented?), \DescribeMacro{hints}|hints| (do we give the hints?), +% \DescribeMacro{gnotes}|gnotes| (do we show grading notes?), \DescribeMacro{pts}|pts| (do +% we display the points awarded for solving the problem?), \DescribeMacro{min}|min| (do we +% display the estimated minutes for problem soling). If theses are specified, then the +% corresponding auxiliary parts of the problems are output, otherwise, they remain +% invisible. +% +% The \DescribeMacro{boxed}|boxed| option specifies that problems should be formatted in +% framed boxes so that they are more visible in the text. Finally, the +% \DescribeMacro{test}|test| option signifies that we are in a test situation, so this +% option does not show the solutions (of course), but leaves space for the students to +% solve them. +% +% The \DescribeMacro{mh}|mh| option turns on MathHub support; see \cite{Kohlhase:mss}. +% +% Finally, if the \DescribeMacro{showmeta}|showmeta| is set, then the metadata keys are +% shown (see~\cite{Kohlhase:metakeys} for details and customization options). +% +% \subsection{Problems and Solutions}\label{sec:user:probsols} +% +% \DescribeEnv{problem} The main environment provided by the |problem| package is +% (surprise surprise) the |problem| environment. It is used to mark up problems and +% exercises. The environment takes an optional KeyVal argument with the keys +% \DescribeMacro{id}|id| as an identifier that can be reference later, +% \DescribeMacro{pts}|pts| for the points to be gained from this exercise in homework or +% quiz situations, \DescribeMacro{min}|min| for the estimated minutes needed to solve the +% problem, and finally \DescribeMacro{title}|title| for an informative title of the +% problem. For an example of a marked up problem see Figure~\ref{fig:problem} and the +% resulting markup see Figure~\ref{fig:result}. +% +%\begin{exfig} +% \begin{verbatim} +% \usepackage[solutions,hints,pts,min]{problem} +% \begin{document} +% \begin{sproblem}[id=elefants,pts=10,min=2,title=Fitting Elefants] +% How many Elefants can you fit into a Volkswagen beetle? +% \begin{hint} +% Think positively, this is simple! +% \end{hint} +% \begin{exnote} +% Justify your answer +% \end{exnote} +% \begin{solution}[for=elefants,height=3cm] +% Four, two in the front seats, and two in the back. +% \begin{gnote} +% if they do not give the justification deduct 5 pts +% \end{gnote} +% \end{solution} +% \end{sproblem} +% \end{document} +% \end{verbatim} +% \caption{A marked up Problem}\label{fig:problem} +% \end{exfig} +% +% \DescribeEnv{solution} The |solution| environment can be to specify a solution to a +% problem. If the \DescribeMacro{solutions}|solutions| option is set or |\solutionstrue| +% is set in the text, then the solution will be presented in the output. The |solution| +% environment takes an optional KeyVal argument with the keys \DescribeMacro{id}|id| for +% an identifier that can be reference \DescribeMacro{for}|for| to specify which problem +% this is a solution for, and \DescribeMacro{height}|height| that allows to specify the +% amount of space to be left in test situations (i.e. if the \DescribeMacro{test}|test| +% option is set in the |\usepackage| statement). +% +%\begin{exfig} +% \begin{minipage}{.9\linewidth} +% \begin{sproblem}[id=elefants.prob,title=Fitting Elefants] +% How many Elefants can you fit into a Volkswagen beetle? +% \begin{hint} +% Think positively, this is simple! +% \end{hint} +% \begin{exnote} +% Justify your answer +% \end{exnote} +% \smallskip\noindent\hrule\textbf{Solution:} +% Four, two in the front seats, and two in the back. +% \hrule +% \end{sproblem} +% \end{minipage} +% \caption{The Formatted Problem from Figure~\ref{fig:problem}}\label{fig:result} +% \end{exfig} +% +% \DescribeEnv{hint}\DescribeEnv{exnote} The |hint| and |exnote| environments can be used +% in a |problem| environment to give hints and to make notes that elaborate certain +% aspects of the problem. +% +% \DescribeEnv{gnote} The |gnote| (grading notes) environment can be used to document +% situtations that may arise in grading. +% +% Sometimes we would like to locally override the |solutions| option we have given to the +% package. To turn on solutions we use the +% \DescribeMacro{\startsolutions}|\startsolutions|, to turn them off, +% \DescribeMacro{\stopsolutions}|\stopsolutions|. These two can be used at any point in +% the documents. +% +% Also, sometimes, we want content (e.g. in an exam with master solutions) conditional on +% whether solutions are shown. This can be done with the +% \DescribeMacro{\ifsolutions}|\ifsolutions| conditional. +% +% \subsection{Multiple Choice Blocks}\label{sec:user:mcq} +% +% Multiple choice blocks can be formatted using the \DescribeMacro{mcb}|mcb| environment, +% in which single choices are marked up with +% \DescribeMacro{\mcc}|\mcc[|\meta{keyvals}|]{|\meta{text}|}| macro, which takes an +% optional key/value argument \meta{keyvals} for choice metadata and a required argument +% \meta{text} for the proposed answer text. The following keys are supported +% \begin{itemize} +% \item \DescribeMacro{T}|T| for true answers, \DescribeMacro{F}|F| for false ones, +% \item \DescribeMacro{Ttext}|Ttext| the verdict for true answers, +% \DescribeMacro{Ftext}|Ftext| for false ones, and +% \item \DescribeMacro{feedback}|feedback| for a short feedback text given to the student. +% \end{itemize} +% See Figure~\ref{fig: mcq} for an example +%\begin{exfig} +% \begin{verbatim} +% \begin{sproblem}[title=Functions] +% What is the keyword to introduce a function definition in python? +% \begin{mcb} +% \mcc[T]{def} +% \mcc[F,feedback=that is for C and C++]{function} +% \mcc[F,feedback=that is for Standard ML]{fun} +% \mcc[F,Ftext=Nooooooooo,feedback=that is for Java]{public static void} +% \end{mcb} +% \end{sproblem} +% \end{verbatim} +% \solutionsfalse\hrule +% \begin{sproblem}[title=Functions] +% What is the keyword to introduce a function definition in python? +% \begin{mcb} +% \mcc[T]{def} +% \mcc[F,feedback=that is for C and C++]{function} +% \mcc[F,feedback=that is for Standard ML]{fun} +% \mcc[F,Ftext=Nooooooooo,feedback=that is for Java]{public static void} +% \end{mcb} +% \end{sproblem} +% \solutionstrue\hrule +% \begin{sproblem}[title=Functions] +% What is the keyword to introduce a function definition in python? +% \begin{mcb} +% \mcc[T]{def} +% \mcc[F,feedback=that is for C and C++]{function} +% \mcc[F,feedback=that is for Standard ML]{fun} +% \mcc[F,Ftext=Nooooooooo,feedback=that is for Java]{public static void} +% \end{mcb} +% \end{sproblem} +% \caption{A Problem with a multiple choice block}\label{fig:mcq} +% \end{exfig} +% +% \subsection{Including Problems}\label{sec:user:includeproblem} +% +% The \DescribeMacro{\includeproblem}|\includeproblem| macro can be used to include a +% problem from another file. It takes an optional KeyVal argument and a second argument +% which is a path to the file containing the problem (the macro assumes that there is only +% one problem in the include file). The keys \DescribeMacro{title}|title|, +% \DescribeMacro{min}|min|, and \DescribeMacro{pts}|pts| specify the problem title, the +% estimated minutes for solving the problem and the points to be gained, and their values +% (if given) overwrite the ones specified in the |problem| environment in the included +% file. +% +% \subsection{Reporting Metadata}\label{sec:user:reporting} +% +% The sum of the points and estimated minutes (that we specified in the |pts| and |min| +% keys to the |problem| environment or the |\includeproblem| macro) to the log file and +% the screen after each run. This is useful in preparing exams, where we want to make sure +% that the students can indeed solve the problems in an allotted time period. +% +% The |\min| and |\pts| macros allow to specify (i.e. to print to the margin) the +% distribution of time and reward to parts of a problem, if the |pts| and |pts| package +% options are set. This allows to give students hints about the estimated time and the +% points to be awarded. +% +% \section{Limitations}\label{sec:limitations} +% +% In this section we document known limitations. If you want to help alleviate them, +% please feel free to contact the package author. Some of them are currently discussed in +% the \sTeX GitHub repository~\cite{sTeX:github:on}. +% \begin{enumerate} +% \item none reported yet +% \end{enumerate} +% +% \end{documentation} +% \begin{implementation} +% +% \section{The Implementation}\label{sec:implementation} +% +% \subsection{Package Options}\label{sec:impl:options} +% +% The first step is to declare (a few) package options that handle whether certain +% information is printed or not. They all come with their own conditionals that are set by +% the options. +% +% \begin{macrocode} +%<*package> +%<@@=problems> +\ProvidesExplPackage{problem}{2022/02/24}{3.0.0}{Semantic Markup for Problems} +\RequirePackage{l3keys2e} + +\keys_define:nn { problem / pkg }{ + notes .default:n = { true }, + notes .bool_set:N = \c_@@_notes_bool, + gnotes .default:n = { true }, + gnotes .bool_set:N = \c_@@_gnotes_bool, + hints .default:n = { true }, + hints .bool_set:N = \c_@@_hints_bool, + solutions .default:n = { true }, + solutions .bool_set:N = \c_@@_solutions_bool, + pts .default:n = { true }, + pts .bool_set:N = \c_@@_pts_bool, + min .default:n = { true }, + min .bool_set:N = \c_@@_min_bool, + boxed .default:n = { true }, + boxed .bool_set:N = \c_@@_boxed_bool, + unknown .code:n = {} +} +\newif\ifsolutions + +\ProcessKeysOptions{ problem / pkg } +\bool_if:NTF \c_@@_solutions_bool { + \solutionstrue +}{ + \solutionsfalse +} +% \end{macrocode} +% +% Then we make sure that the necessary packages are loaded (in the right versions). +% \begin{macrocode} +\RequirePackage{comment} +% \end{macrocode} +% +% The next package relies on the \LaTeX3 kernel, which \latexml only partially +% supports. As it is purely presentational, we only load it when the |boxed| option is +% given and we run {\latexml}. +% +% \begin{macrocode} +\bool_if:NT \c_@@_boxed_bool { \RequirePackage{mdframed} } +% \end{macrocode} +% +% \begin{macro}{\prob@*@kw} +% For multilinguality, we define internal macros for keywords that can be specialized in +% |*.ldf| files. +% \begin{macrocode} +\def\prob@problem@kw{Problem} +\def\prob@solution@kw{Solution} +\def\prob@hint@kw{Hint} +\def\prob@note@kw{Note} +\def\prob@gnote@kw{Grading} +\def\prob@pt@kw{pt} +\def\prob@min@kw{min} +% \end{macrocode} +% \end{macro} +% +% For the other languages, we set up triggers +% \begin{macrocode} +\AddToHook{begindocument}{ + \ltx@ifpackageloaded{babel}{ + \makeatletter + \clist_set:Nx \l_tmpa_clist {\bbl@loaded} + \clist_if_in:NnT \l_tmpa_clist {ngerman}{ + \input{problem-ngerman.ldf} + } + \clist_if_in:NnT \l_tmpa_clist {finnish}{ + \input{problem-finnish.ldf} + } + \clist_if_in:NnT \l_tmpa_clist {french}{ + \input{problem-french.ldf} + } + \clist_if_in:NnT \l_tmpa_clist {russian}{ + \input{problem-russian.ldf} + } + \makeatother + }{} +} +% \end{macrocode} +% +% \subsection{Problems and Solutions}\label{sec:impl:probsols} +% +% We now prepare the KeyVal support for problems. The key macros just set appropriate +% internal macros. +% +% \begin{macrocode} +\keys_define:nn{ problem / problem }{ + id .str_set_x:N = \l_@@_prob_id_str, + pts .tl_set:N = \l_@@_prob_pts_tl, + min .tl_set:N = \l_@@_prob_min_tl, + title .tl_set:N = \l_@@_prob_title_tl, + type .tl_set:N = \l_@@_prob_type_tl, + refnum .int_set:N = \l_@@_prob_refnum_int +} +\cs_new_protected:Nn \_@@_prob_args:n { + \str_clear:N \l_@@_prob_id_str + \tl_clear:N \l_@@_prob_pts_tl + \tl_clear:N \l_@@_prob_min_tl + \tl_clear:N \l_@@_prob_title_tl + \tl_clear:N \l_@@_prob_type_tl + \int_zero_new:N \l_@@_prob_refnum_int + \keys_set:nn { problem / problem }{ #1 } + \int_compare:nNnT \l_@@_prob_refnum_int = 0 { + \let\l_@@_prob_refnum_int\undefined + } +} +% \end{macrocode} +% +% Then we set up a counter for problems. +% \begin{macro}{\numberproblemsin} +% \begin{macrocode} +\newcounter{problem} +\newcommand\numberproblemsin[1]{\@addtoreset{problem}{#1}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\prob@label} +% We provide the macro |\prob@label| to redefine later to get context involved. +% \begin{macrocode} +\newcommand\prob@label[1]{#1} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\prob@number} +% We consolidate the problem number into a reusable internal macro +% \begin{macrocode} +\newcommand\prob@number{ + \int_if_exist:NTF \l_@@_inclprob_refnum_int { + \prob@label{\int_use:N \l_@@_inclprob_refnum_int } + }{ + \int_if_exist:NTF \l_@@_prob_refnum_int { + \prob@label{\int_use:N \l_@@_prob_refnum_int } + }{ + \prob@label\theproblem + } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\prob@title} +% We consolidate the problem title into a reusable internal macro as well. |\prob@title| +% takes three arguments the first is the fallback when no title is given at all, the +% second and third go around the title, if one is given. +% \begin{macrocode} +\newcommand\prob@title[3]{% + \tl_if_exist:NTF \l_@@_inclprob_title_tl { + #2 \l_@@_inclprob_title_tl #3 + }{ + \tl_if_exist:NTF \l_@@_prob_title_tl { + #2 \l_@@_prob_title_tl #3 + }{ + #1 + } + } +} +% \end{macrocode} +% \end{macro} +% +% With these the problem header is a one-liner +% +% \begin{macro}{\prob@heading} +% We consolidate the problem header line into a separate internal macro that can be +% reused in various settings. +% \begin{macrocode} +\def\prob@heading{ + {\prob@problem@kw}\ \prob@number\prob@title{~}{~(}{)\strut} + %\sref@label@id{\prob@problem@kw~\prob@number}{} +} +% \end{macrocode} +% \end{macro} +% +% With this in place, we can now define the |problem| environment. It comes in two shapes, +% depending on whether we are in boxed mode or not. In both cases we increment the problem +% number and output the points and minutes (depending) on whether the respective options +% are set. +% \begin{environment}{sproblem} +% \begin{macrocode} +\newenvironment{sproblem}[1][]{ + \_@@_prob_args:n{#1}%\sref@target% + \@in@omtexttrue% we are in a statement (for inline definitions) + \stepcounter{problem}\record@problem + \def\current@section@level{\prob@problem@kw} + \tl_if_exist:NTF \l_@@_inclprob_type_tl { + \tl_set_eq:NN \sproblemtype \l_@@_inclprob_type_tl + }{ + \tl_set_eq:NN \sproblemtype \l_@@_prob_type_tl + } + \str_if_exist:NTF \l_@@_inclprob_id_str { + \str_set_eq:NN \sproblemid \l_@@_inclprob_id_str + }{ + \str_set_eq:NN \sproblemid \l_@@_prob_id_str + } + + + \clist_set:No \l_tmpa_clist \sproblemtype + \tl_clear:N \l_tmpa_tl + \clist_map_inline:Nn \l_tmpa_clist { + \tl_if_exist:cT {_@@_sproblem_##1_start:}{ + \tl_set:Nn \l_tmpa_tl {\use:c{_@@_sproblem_##1_start:}} + } + } + \tl_if_empty:NTF \l_tmpa_tl { + \_@@_sproblem_start: + }{ + \l_tmpa_tl + } + \stex_ref_new_doc_target:n \sproblemid +}{ + \clist_set:No \l_tmpa_clist \sproblemtype + \tl_clear:N \l_tmpa_tl + \clist_map_inline:Nn \l_tmpa_clist { + \tl_if_exist:cT {_@@_sproblem_##1_end:}{ + \tl_set:Nn \l_tmpa_tl {\use:c{_@@_sproblem_##1_end:}} + } + } + \tl_if_empty:NTF \l_tmpa_tl { + \_@@_sproblem_end: + }{ + \l_tmpa_tl + } + + + \smallskip +} + + +\cs_new_protected:Nn \_@@_sproblem_start: { + \par\noindent\textbf\prob@heading\show@pts\show@min\\\ignorespacesandpars +} +\cs_new_protected:Nn \_@@_sproblem_end: {\par\smallskip} + +\newcommand\stexpatchproblem[3][] { + \str_set:Nx \l_tmpa_str{ #1 } + \str_if_empty:NTF \l_tmpa_str { + \tl_set:Nn \_@@_sproblem_start: { #2 } + \tl_set:Nn \_@@_sproblem_end: { #3 } + }{ + \exp_after:wN \tl_set:Nn \csname _@@_sproblem_#1_start:\endcsname{ #2 } + \exp_after:wN \tl_set:Nn \csname _@@_sproblem_#1_end:\endcsname{ #3 } + } +} + + +\bool_if:NT \c_@@_boxed_bool { + \surroundwithmdframed{problem} +} +% \end{macrocode} +% \end{environment} +% +% \begin{macro}{\record@problem} +% This macro records information about the problems in the |*.aux| file. +% \begin{macrocode} +\def\record@problem{ + \protected@write\@auxout{} + { + \string\@problem{\prob@number} + { + \tl_if_exist:NTF \l_@@_inclprob_pts_tl { + \l_@@_inclprob_pts_tl + }{ + \l_@@_prob_pts_tl + } + }% + { + \tl_if_exist:NTF \l_@@_inclprob_min_tl { + \l_@@_inclprob_min_tl + }{ + \l_@@_prob_min_tl + } + } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@problem} +% This macro acts on a problem's record in the |*.aux| file. It does not have any +% functionality here, but can be redefined elsewhere (e.g. in the |assignment| +% package). +% \begin{macrocode} +\def\@problem#1#2#3{} +% \end{macrocode} +% \end{macro} +% +% The \DescribeEnv{solution}|solution| environment is similar to the |problem| +% environment, only that it is independent of the boxed mode. It also has it's own keys +% that we need to define first. +% +% \begin{macrocode} +\keys_define:nn { problem / solution }{ + id .str_set_x:N = \l_@@_solution_id_str , + for .tl_set:N = \l_@@_solution_for_tl , + height .dim_set:N = \l_@@_solution_height_dim , + creators .clist_set:N = \l_@@_solution_creators_clist , + contributors .clist_set:N = \l_@@_solution_contributors_clist , + srccite .tl_set:N = \l_@@_solution_srccite_tl +} +\cs_new_protected:Nn \_@@_solution_args:n { + \str_clear:N \l_@@_solution_id_str + \tl_clear:N \l_@@_solution_for_tl + \tl_clear:N \l_@@_solution_srccite_tl + \clist_clear:N \l_@@_solution_creators_clist + \clist_clear:N \l_@@_solution_contributors_clist + \dim_zero:N \l_@@_solution_height_dim + \keys_set:nn { problem / solution }{ #1 } +} +% \end{macrocode} +% the next step is to define a helper macro that does what is needed to start a solution. +% \begin{macrocode} +\newcommand\@startsolution[1][]{ + \_@@_solution_args:n { #1 } + \@in@omtexttrue% we are in a statement. + \bool_if:NF \c_@@_boxed_bool { \hrule } + \smallskip\noindent + {\textbf\prob@solution@kw :\enspace} + \begin{small} + \def\current@section@level{\prob@solution@kw} + \ignorespacesandpars +} +% \end{macrocode} +% +% \begin{macro}{\startsolutions} +% for the |\startsolutions| macro we use the |\specialcomment| macro from the |comment| +% package. Note that we use the |\@startsolution| macro in the start codes, that parses +% the optional argument. +% \begin{macrocode} +\newcommand\startsolutions{ + \specialcomment{solution}{\@startsolution}{ + \bool_if:NF \c_@@_boxed_bool { + \hrule\medskip + } + \end{small}% + } + \bool_if:NT \c_@@_boxed_bool { + \surroundwithmdframed{solution} + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stopsolutions} +% \begin{macrocode} +\newcommand\stopsolutions{\excludecomment{solution}} +% \end{macrocode} +% \end{macro} +% +% so it only remains to start/stop solutions depending on what option was specified. +% +% \begin{macrocode} +\ifsolutions + \startsolutions +\else + \stopsolutions +\fi +% \end{macrocode} +% +% \begin{environment}{exnote} +% \begin{macrocode} +\bool_if:NTF \c_@@_notes_bool { + \newenvironment{exnote}[1][]{ + \par\smallskip\hrule\smallskip + \noindent\textbf{\prob@note@kw : }\small + }{ + \smallskip\hrule + } +}{ + \excludecomment{exnote} +} +% \end{macrocode} +% \end{environment} +% +% \begin{environment}{hint} +% \begin{macrocode} +\bool_if:NTF \c_@@_notes_bool { + \newenvironment{hint}[1][]{ + \par\smallskip\hrule\smallskip + \noindent\textbf{\prob@hint@kw :~ }\small + }{ + \smallskip\hrule + } + \newenvironment{exhint}[1][]{ + \par\smallskip\hrule\smallskip + \noindent\textbf{\prob@hint@kw :~ }\small + }{ + \smallskip\hrule + } +}{ + \excludecomment{hint} + \excludecomment{exhint} +} +% \end{macrocode} +% \end{environment} +% +% \begin{environment}{gnote} +% \begin{macrocode} +\bool_if:NTF \c_@@_notes_bool { + \newenvironment{gnote}[1][]{ + \par\smallskip\hrule\smallskip + \noindent\textbf{\prob@gnote@kw : }\small + }{ + \smallskip\hrule + } +}{ + \excludecomment{gnote} +} +% \end{macrocode} +% \end{environment} +% +% \subsection{Multiple Choice Blocks}\label{sec:impl:mcq} +% +% \begin{environment}{mcb} +% \ednote{MK: maybe import something better here from a dedicated MC package} +% \begin{macrocode} +\newenvironment{mcb}{ + \begin{enumerate} +}{ + \end{enumerate} +} +% \end{macrocode} +% \end{environment} +% we define the keys for the |mcc| macro +% \begin{macrocode} +\cs_new_protected:Nn \_@@_do_yes_param:Nn { + \exp_args:Nx \str_if_eq:nnTF { \str_lowercase:n{ #2 } }{ yes }{ + \bool_set_true:N #1 + }{ + \bool_set_false:N #1 + } +} +\keys_define:nn { problem / mcc }{ + id .str_set_x:N = \l_@@_mcc_id_str , + feedback .tl_set:N = \l_@@_mcc_feedback_tl , + T .default:n = { true } , + T .bool_set:N = \l_@@_mcc_t_bool , + F .default:n = { true } , + F .bool_set:N = \l_@@_mcc_f_bool , + Ttext .code:n = { + \_@@_do_yes_param:Nn \l_@@_mcc_Ttext_bool { #1 } + } , + Ftext .code:n = { + \_@@_do_yes_param:Nn \l_@@_mcc_Ftext_bool { #1 } + } +} +\cs_new_protected:Nn \l_@@_mcc_args:n { + \str_clear:N \l_@@_mcc_id_str + \tl_clear:N \l_@@_mcc_feedback_tl + \bool_set_true:N \l_@@_mcc_t_bool + \bool_set_true:N \l_@@_mcc_f_bool + \bool_set_true:N \l_@@_mcc_Ttext_bool + \bool_set_false:N \l_@@_mcc_Ftext_bool + \keys_set:nn { problem / mcc }{ #1 } +} +% \end{macrocode} +% +% \begin{macro}{\mcc} +% \begin{macrocode} +\newcommand\mcc[2][]{ + \l_@@_mcc_args:n{ #1 } + \item #2 + \ifsolutions + \\ + \bool_if:NT \l_@@_mcc_t_bool { + % TODO! + % \ifcsstring{mcc@T}{T}{}{\mcc@Ttext}% + } + \bool_if:NT \l_@@_mcc_f_bool { + % TODO! + % \ifcsstring{mcc@F}{F}{}{\mcc@Ftext}% + } + \tl_if_empty:NTF \l_@@_mcc_feedback_tl { + ! + }{ + \l_@@_mcc_feedback_tl + } + \fi +} %solutions +% \end{macrocode} +% \end{macro} +% +% \subsection{Including Problems}\label{sec:impl:includeproblem} +% +% \begin{macro}{\includeproblem} +% The |\includeproblem| command is essentially a glorified |\input| statement, it sets +% some internal macros first that overwrite the local points. Importantly, it resets the +% |inclprob| keys after the input. +% \begin{macrocode} + +\keys_define:nn{ problem / inclproblem }{ + id .str_set_x:N = \l_@@_inclprob_id_str, + pts .tl_set:N = \l_@@_inclprob_pts_tl, + min .tl_set:N = \l_@@_inclprob_min_tl, + title .tl_set:N = \l_@@_inclprob_title_tl, + refnum .int_set:N = \l_@@_inclprob_refnum_int, + type .tl_set:N = \l_@@_inclprob_type_tl, + mhrepos .str_set_x:N = \l_@@_inclprob_mhrepos_str +} +\cs_new_protected:Nn \_@@_inclprob_args:n { + \str_clear:N \l_@@_prob_id_str + \tl_clear:N \l_@@_inclprob_pts_tl + \tl_clear:N \l_@@_inclprob_min_tl + \tl_clear:N \l_@@_inclprob_title_tl + \tl_clear:N \l_@@_inclprob_type_tl + \int_zero_new:N \l_@@_inclprob_refnum_int + \str_clear:N \l_@@_inclprob_mhrepos_str + \keys_set:nn { problem / inclproblem }{ #1 } + \tl_if_empty:NT \l_@@_inclprob_pts_tl { + \let\l_@@_inclprob_pts_tl\undefined + } + \tl_if_empty:NT \l_@@_inclprob_min_tl { + \let\l_@@_inclprob_min_tl\undefined + } + \tl_if_empty:NT \l_@@_inclprob_title_tl { + \let\l_@@_inclprob_title_tl\undefined + } + \tl_if_empty:NT \l_@@_inclprob_type_tl { + \let\l_@@_inclprob_type_tl\undefined + } + \int_compare:nNnT \l_@@_inclprob_refnum_int = 0 { + \let\l_@@_inclprob_refnum_int\undefined + } +} + +\cs_new_protected:Nn \_@@_inclprob_clear: { + \let\l_@@_inclprob_id_str\undefined + \let\l_@@_inclprob_pts_tl\undefined + \let\l_@@_inclprob_min_tl\undefined + \let\l_@@_inclprob_title_tl\undefined + \let\l_@@_inclprob_type_tl\undefined + \let\l_@@_inclprob_refnum_int\undefined + \let\l_@@_inclprob_mhrepos_str\undefined +} +\_@@_inclprob_clear: + +\newcommand\includeproblem[2][]{ + \_@@_inclprob_args:n{ #1 } + \str_if_empty:NTF \l_@@_inclprob_mhrepos_str { + \input{#2} + }{ + \stex_in_repository:nn{\l_@@_inclprob_mhrepos_str}{ + \input{\mhpath{\l_@@_inclprob_mhrepos_str}{#2}} + } + } + \_@@_inclprob_clear: +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Reporting Metadata} +% +% For messages it is OK to have them in English as the whole documentation is, and we can +% therefore assume authors can deal with it. +% +% \begin{macrocode} +\AddToHook{enddocument}{ + \bool_if:NT \c_@@_pts_bool { + \message{Total:~\arabic{pts}~points} + } + \bool_if:NT \c_@@_min_bool { + \message{Total:~\arabic{min}~minutes} + } +} +% \end{macrocode} +% +% The margin pars are reader-visible, so we need to translate +% +% \begin{macrocode} +\def\pts#1{ + \bool_if:NT \c_@@_pts_bool { + \marginpar{#1~\prob@pt@kw} + } +} +\def\min#1{ + \bool_if:NT \c_@@_min_bool { + \marginpar{#1~\prob@min@kw} + } +} +% \end{macrocode} +% +% \begin{macro}{\show@pts} +% The |\show@pts| shows the points: if no points are given from the outside and also no +% points are given locally do nothing, else show and add. If there are outside points +% then we show them in the margin. +% \begin{macrocode} +\newcounter{pts} +\def\show@pts{ + \tl_if_exist:NTF \l_@@_inclprob_pts_tl { + \bool_if:NT \c_@@_pts_bool { + \marginpar{\l_@@_inclprob_pts_tl\ \prob@pt@kw\smallskip} + \addtocounter{pts}{\l_@@_inclprob_pts_tl} + } + }{ + \tl_if_exist:NT \l_@@_prob_pts_tl { + \bool_if:NT \c_@@_pts_bool { + \marginpar{\l_@@_prob_pts_tl\ \prob@pt@kw\smallskip} + \addtocounter{pts}{\l_@@_prob_pts_tl} + } + } + } +} +% \end{macrocode} +% \end{macro} +% and now the same for the minutes +% \begin{macro}{\show@min} +% \begin{macrocode} +\newcounter{min} +\def\show@min{ + \tl_if_exist:NTF \l_@@_inclprob_min_tl { + \bool_if:NT \c_@@_min_bool { + \marginpar{\l_@@_inclprob_pts_tl\ min} + \addtocounter{min}{\l_@@_inclprob_min_tl} + } + }{ + \tl_if_exist:NT \l_@@_prob_min_tl { + \bool_if:NT \c_@@_min_bool { + \marginpar{\l_@@_prob_min_tl\ min} + \addtocounter{min}{\l_@@_prob_min_tl} + } + } + } +} +%</package> +% \end{macrocode} +% \end{macro} +% \end{implementation} +\endinput +% LocalWords: GPL structuresharing STR dtx pts keyval xcomment CPERL DefKeyVal iffalse +%%% Local Variables: +%%% mode: doctex +%%% TeX-master: t +%%% End: +% \fi +% LocalWords: RequirePackage Semiverbatim DefEnvironment OptionalKeyVals soln texttt baz +% LocalWords: exnote DefConstructor inclprob NeedsTeXFormat omd.sty textbackslash exfig +% LocalWords: stopsolution fileversion filedate maketitle setcounter tocdepth newpage +% LocalWords: tableofcontents showmeta showmeta solutionstrue usepackage minipage hrule +% LocalWords: linewidth elefants.prob Elefants smallskip noindent textbf startsolutions +% LocalWords: startsolutions stopsolutions stopsolutions includeproblem includeproblem +% LocalWords: textsf HorIacJuc cscpnrr11 includemhproblem includemhproblem importmodule +% LocalWords: importmhmodule foobar ldots latexml mhcurrentrepos mh-variants mh-variant +% LocalWords: compactenum langle rangle langle rangle ltxml metakeys newif ifexnotes rm +% LocalWords: exnotesfalse exnotestrue ifhints hintsfalse hintstrue ifsolutions ifpts +% LocalWords: solutionsfalse ptsfalse ptstrue ifmin minfalse mintrue ifboxed boxedfalse +% LocalWords: boxedtrue sref mdframed marginpar prob srefaddidkey addmetakey refnum kv +% LocalWords: newcounter ifx thesection theproblem hfill newenvironment metasetkeys ltx +% LocalWords: stepcounter currentsectionlevel xspace ignorespaces surroundwithmdframed +% LocalWords: omdoc autoopen autoclose solvedinminutes kvi qw vals newcommand exhint +% LocalWords: specialcomment excludecomment mhrepos xref marginpar addtocounter doctex +% LocalWords: mh@currentrepos endinput + diff --git a/macros/latex/contrib/stex/source/extensions/tikzinput.dtx b/macros/latex/contrib/stex/source/extensions/tikzinput.dtx new file mode 100644 index 0000000000..51a3a7c06a --- /dev/null +++ b/macros/latex/contrib/stex/source/extensions/tikzinput.dtx @@ -0,0 +1,146 @@ +% \iffalse meta-comment +% An Infrastructure for Semantic Macros and Module Scoping +% Copyright (c) 2019 Michael Kohlhase, all rights reserved +% this file is released under the +% LaTeX Project Public License (LPPL) +% +% The original of this file is in the public repository at +% http://github.com/sLaTeX/sTeX/ +% +% TODO update copyright +% +%<*driver> +\providecommand\bibfolder{../../lib/bib} +\input{../../doc/docheader} + +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{Tikzinput +% \thanks{Version {\fileversion} (last revised {\filedate})} +% } +% +% \author{Michael Kohlhase, Dennis Müller\\ +% FAU Erlangen-Nürnberg\\ +% \url{http://kwarc.info/} +% } +% +% \maketitle +% +%\ifinfulldoc\else +% This is the documentation for the \pkg{tikzinput} package. +% For a more high-level introduction, +% see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the +% \href{\basedocurl/stex.pdf}{full \sTeX documentation}. +% +% \input{../../doc/packages/tikzinput} +% \fi +% +% \begin{documentation}\label{pkg:tikzinput:doc} +% +% +% \section{Macros and Environments}\label{pkg:tikzinput:doc:macros} +% +% \end{documentation} +% +% \begin{implementation}\label{pkg:tikzinput:impl} +% +% \section{Tikzinput Implementation} +% +% \begin{macrocode} +%<*package> + +%%%%%%%%%%%%% tikzinput.dtx %%%%%%%%%%%%% + +% \end{macrocode} +% +% \begin{macrocode} +\ProvidesExplPackage{tikzinput}{2022/02/24}{3.0.0}{tikzinput package} +\RequirePackage{l3keys2e} + +\keys_define:nn { tikzinput } { + image .bool_set:N = \c_tikzinput_image_bool, + image .default:n = false , + unknown .code:n = {} +} + +\ProcessKeysOptions { tikzinput } + +\bool_if:NTF \c_tikzinput_image_bool { + \RequirePackage{graphicx} + + \providecommand\usetikzlibrary[]{} + \newcommand\tikzinput[2][]{\includegraphics[#1]{#2}} +}{ + \RequirePackage{tikz} + \RequirePackage{standalone} + + \newcommand \tikzinput [2] [] { + \setkeys{Gin}{#1} + \ifx \Gin@ewidth \Gin@exclamation + \ifx \Gin@eheight \Gin@exclamation + \input { #2 } + \else + \resizebox{!}{ \Gin@eheight }{ + \input { #2 } + } + \fi + \else + \ifx \Gin@eheight \Gin@exclamation + \resizebox{ \Gin@ewidth }{!}{ + \input { #2 } + } + \else + \resizebox{ \Gin@ewidth }{ \Gin@eheight }{ + \input { #2 } + } + \fi + \fi + } +} + +\newcommand \ctikzinput [2] [] { + \begin{center} + \tikzinput [#1] {#2} + \end{center} +} + +\@ifpackageloaded{stex}{ + \RequirePackage{stex-tikzinput} +}{} + +% \end{macrocode} +% +% +% \begin{macrocode} +%</package> +%<*stex> +% \end{macrocode} +% +% \begin{macrocode} +\ProvidesExplPackage{stex-tikzinput}{2022/02/24}{3.0.0}{stex-tikzinput} +\RequirePackage{stex} +\RequirePackage{tikzinput} + +\newcommand\mhtikzinput[2][]{% + \def\Gin@mhrepos{}\setkeys{Gin}{#1}% + \stex_in_repository:nn\Gin@mhrepos{ + \tikzinput[#1]{\mhpath{##1}{#2}} + } +} +\newcommand\cmhtikzinput[2][]{\begin{center}\mhtikzinput[#1]{#2}\end{center}} +% \end{macrocode} +% +% \begin{macrocode} +%</stex> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex + +% LocalWords: bibfolder jobname.dtx tikzinput.dtx usetikzlibrary Gin@ewidth Gin@eheight +% LocalWords: resizebox ctikzinput mhtikzinput Gin@mhrepos mhpath diff --git a/macros/latex/contrib/stex/source/stex/Makefile b/macros/latex/contrib/stex/source/stex/Makefile new file mode 100644 index 0000000000..2b9a63750b --- /dev/null +++ b/macros/latex/contrib/stex/source/stex/Makefile @@ -0,0 +1,23 @@ +DTX = $(shell ls *.dtx) +DOC = $(DTX:%.dtx=%.pdf) +INS = stex.ins + +PDFLATEX = pdflatex -interaction=batchmode +TEXDIR = ../../tex +TEXINPUTS = $(TEXDIR)//: + +all: package doc + +doc: $(DOC) + +package: $(DTX) $(INS) + $(PDFLATEX) $(INS) + mv *.sty *.cls $(TEXDIR) + +$(DOC): %.pdf: %.dtx + $(PDFLATEX) $< + biber -q $(basename $<) + $(PDFLATEX) $< + +echo: + @echo $(TEXINPUTS) diff --git a/macros/latex/contrib/stex/source/stex/basics.dtx b/macros/latex/contrib/stex/source/stex/basics.dtx new file mode 100644 index 0000000000..c2047a39a2 --- /dev/null +++ b/macros/latex/contrib/stex/source/stex/basics.dtx @@ -0,0 +1,562 @@ +% \iffalse meta-comment +% An Infrastructure for Semantic Macros and Module Scoping +% Copyright (c) 2019 Michael Kohlhase, all rights reserved +% this file is released under the +% LaTeX Project Public License (LPPL) +% +% The original of this file is in the public repository at +% http://github.com/sLaTeX/sTeX/ +% +% TODO update copyright +% +%<*driver> +\providecommand\bibfolder{../../lib/bib} +\input{../../doc/docheader} + +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{ \sTeX-Basics +% \thanks{Version {\fileversion} (last revised {\filedate})} +% } +% +% \author{Michael Kohlhase, Dennis Müller\\ +% FAU Erlangen-Nürnberg\\ +% \url{http://kwarc.info/} +% } +% +% \maketitle +% +%\ifinfulldoc\else +% This is the documentation for the \pkg{stex-basics} package. +% For a more high-level introduction, +% see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the +% \href{\basedocurl/stex.pdf}{full \sTeX documentation}. +% \fi +% +% \begin{documentation}\label{pkg:basics:doc} +% +% This sub package provides general set up code, auxiliary methods +% and abstractions for |xhtml| annotations. +% +%\ifinfulldoc\else +% \input{../../doc/packages/basics} +% \fi +% +% +% \section{Macros and Environments}\label{pkg:basics:doc:macros} +% +% \begin{function}{\sTeX , \stex} +% Both print this \stex logo. +% \end{function} +% +% \begin{function}{\stex_debug:nn} +% \begin{syntax} +% \cs{stex_debug:nn} \Arg{log-prefix} \Arg{message} ^^A \meta{comma list} +% \end{syntax} +% Logs \meta{message}, if the package option |debug| contains \meta{log-prefix}. +% \end{function} +% +% \subsection{HTML Annotations} +% +% \begin{function}{\if@latexml} +% \LaTeX2e conditional for \latexml +% \end{function} +% +% \begin{function}[pTF]{\latexml_if:} +% \LaTeX3 conditionals for \latexml. +% \end{function} +% +% \begin{function}[pTF]{\stex_if_do_html:} +% Whether to currently produce any HTML annotations (can be false +% in some advanced structuring environments, for example) +% \end{function} +% +% \begin{function}{\stex_suppress_html:n} +% Temporarily disables HTML annotations in its argument code +% \end{function} +% +% +% We have four macros for annotating generated HTML (via \latexml +% or \rustex) with attributes: +% +% \begin{function}{\stex_annotate:nnn, \stex_annotate_invisible:nnn, +% \stex_annotate_invisible:n} +% \begin{syntax} \cs{stex_annotate:nnn} \Arg{property} \Arg{resource} \Arg{content} \end{syntax} +% Annotates the HTML generated by \meta{content} with\\ +% \begin{center} +% |property="stex:|\meta{property}|", resource="|\meta{resource}|"|. +% \end{center} +% +% \cs{stex_annotate_invisible:n} adds the attributes\\ +% \begin{center} +% |stex:visible="false", style="display:none"|. +% \end{center} +% +% \cs{stex_annotate_invisible:nnn} combines the functionality of both. +% \end{function} +% +% \begin{environment}{stex_annotate_env} +% \begin{syntax} \cs{begin}|{stex_annotate_env}|\Arg{property}\Arg{resource} +% \meta{content} +% \cs{end}|{stex_annotate_env}| +% \end{syntax} +% behaves like \cs{stex_annotate:nnn} \Arg{property} \Arg{resource} +% \Arg{content}. +% \end{environment} +% +% \subsection{Babel Languages} +% +% \begin{variable}{\c_stex_languages_prop,\c_stex_language_abbrevs_prop} +% Map language abbreviations to their full babel names and vice versa. +% e.g. \cs{c_stex_languages_prop}|{en}| yields |english|, and +% \cs{c_stex_language_abbrevs_prop}|{english}| yields |en|. +% \end{variable} +% +% \subsection{Auxiliary Methods} +% +% \begin{function}{\stex_deactivate_macro:Nn , \stex_reactivate_macro:N} +% \begin{syntax}\cs{stex_deactivate_macro:Nn}\meta{cs}\Arg{environments}\end{syntax} +% Makes the macro \meta{cs} throw an error, indicating that it +% is only allowed in the context of \meta{environments}. +% +% \cs{stex_reactivate_macro:N}\meta{cs} reactivates it again, i.e. +% this happens ideally in the \meta{begin}-code of the associated +% environments. +% \end{function} +% +% \begin{function}{\ignorespacesandpars} +% ignores white space characters and |\par| control sequences. +% Expands tokens in the process. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\sTeX-Basics Implementation}\label{pkg:basics:impl} +% +% \subsection{The \sTeX Document Class} +% +% The \cls{stex} document class is pretty straight-forward: It largely extends the \cls{standalone} package +% and loads the \pkg{stex} package, passing all provided options on to the package. +% +% \begin{macrocode} +%<*cls> + +%%%%%%%%%%%%% basics.dtx %%%%%%%%%%%%% + +\RequirePackage{expl3,l3keys2e} +\ProvidesExplClass{stex}{2022/02/24}{3.0.0}{sTeX document class} +\LoadClass[border=1px,varwidth]{standalone} +\setlength\textwidth{15cm} + +\DeclareOption*{\PassOptionsToPackage{\CurrentOption}{stex}} +\ProcessOptions + +\RequirePackage{stex} +%</cls> +% \end{macrocode} +% +% \subsection{Preliminaries} +% +% \begin{macrocode} +%<*package> + +%%%%%%%%%%%%% basics.dtx %%%%%%%%%%%%% + +\RequirePackage{expl3,l3keys2e,ltxcmds} +\ProvidesExplPackage{stex}{2022/02/24}{3.0.0}{sTeX package} + +%\RequirePackage{morewrites} +%\RequirePackage{amsmath} + +% \end{macrocode} +% +% Package options: +% +% \begin{macrocode} +\keys_define:nn { stex } { + debug .clist_set:N = \c_stex_debug_clist , + lang .clist_set:N = \c_stex_languages_clist , + mathhub .tl_set_x:N = \mathhub , + sms .bool_set:N = \c_stex_persist_mode_bool , + image .bool_set:N = \c_tikzinput_image_bool, + unknown .code:n = {} +} +\ProcessKeysOptions { stex } +% \end{macrocode} +% +% \begin{macro}{\stex,\sTeX} +% The \sTeX logo: +% +% \begin{macrocode} +\protected\def\stex{% + \@ifundefined{texorpdfstring}% + {\let\texorpdfstring\@firstoftwo}% + {}% + \texorpdfstring{\raisebox{-.5ex}S\kern-.5ex\TeX}{sTeX}\xspace% +} +\def\sTeX{\stex} +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Messages and logging} +% +% \begin{macrocode} +%<@@=stex_log> +% \end{macrocode} +% +% Warnings and error messages +% +% \begin{macrocode} +\msg_new:nnn{stex}{error/unknownlanguage}{ + Unknown~language:~#1 +} +\msg_new:nnn{stex}{warning/nomathhub}{ + MATHHUB~system~variable~not~found~and~no~ + \detokenize{\mathhub}-value~set! +} +\msg_new:nnn{stex}{error/deactivated-macro}{ + The~\detokenize{#1}~command~is~only~allowed~in~#2! +} +% \end{macrocode} +% +% \begin{macro}{\stex_debug:nn} +% +% A simple macro issuing package messages with subpath. +% +% \begin{macrocode} +\cs_new_protected:Nn \stex_debug:nn { + \clist_if_in:NnTF \c_stex_debug_clist { all } { + \exp_args:Nnnx\msg_set:nnn{stex}{debug / #1}{ + \\Debug~#1:~#2\\ + } + \msg_none:nn{stex}{debug / #1} + }{ + \clist_if_in:NnT \c_stex_debug_clist { #1 } { + \exp_args:Nnnx\msg_set:nnn{stex}{debug / #1}{ + \\Debug~#1:~#2\\ + } + \msg_none:nn{stex}{debug / #1} + } + } +} +% \end{macrocode} +% \end{macro} +% +% Redirecting messages: +% +% \begin{macrocode} +\clist_if_in:NnTF \c_stex_debug_clist {all} { + \msg_redirect_module:nnn{ stex }{ none }{ term } +}{ + \clist_map_inline:Nn \c_stex_debug_clist { + \msg_redirect_name:nnn{ stex }{ debug / ##1 }{ term } + } +} + +\stex_debug:nn{log}{debug~mode~on} +% \end{macrocode} +% +% +% \subsection{HTML Annotations} +% \begin{macrocode} +%<@@=stex_annotate> +\RequirePackage{rustex} +% \end{macrocode} +% +% We add the namespace abbreviation |ns:stex="http://kwarc.info/ns/sTeX"| to \rustex: +% +% \begin{macrocode} +\rustex_add_Namespace:nn{stex}{http://kwarc.info/ns/sTeX} +% \end{macrocode} +% +% Conditionals for \latexml: +% +% \begin{macro}{\if@latexml} +% \begin{macrocode} +\ifcsname if@latexml\endcsname\else + \expandafter\newif\csname if@latexml\endcsname\@latexmlfalse +\fi +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\latexml_if:} +% \begin{macrocode} +\prg_new_conditional:Nnn \latexml_if: {p, T, F, TF} { + \if@latexml + \prg_return_true: + \else: + \prg_return_false: + \fi: +} +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\l_@@_arg_tl, \c_@@_emptyarg_tl} +% +% Used by annotation macros to ensure that the HTML output to annotate +% is not empty. +% +% \begin{macrocode} +\tl_new:N \l_@@_arg_tl +\tl_const:Nx \c_@@_emptyarg_tl { + \rustex_if:TF { + \rustex_direct_HTML:n { \c_ampersand_str lrm; } + }{~} +} +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\_@@_checkempty:n} +% \begin{macrocode} +\cs_new_protected:Nn \_@@_checkempty:n { + \tl_set:Nn \l_@@_arg_tl { #1 } + \tl_if_empty:NT \l_@@_arg_tl { + \tl_set_eq:NN \l_@@_arg_tl \c_@@_emptyarg_tl + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\stex_if_do_html:} +% Whether to (locally) produce HTML output +% \begin{macrocode} +\bool_new:N \_stex_html_do_output_bool +\bool_set_true:N \_stex_html_do_output_bool + +\prg_new_conditional:Nnn \stex_if_do_html: {p,T,F,TF} { + \bool_if:nTF \_stex_html_do_output_bool + \prg_return_true: \prg_return_false: +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stex_suppress_html:n} +% Whether to (locally) produce HTML output +% \begin{macrocode} +\cs_new_protected:Nn \stex_suppress_html:n { + \exp_args:Nne \use:nn { + \bool_set_false:N \_stex_html_do_output_bool + #1 + }{ + \stex_if_do_html:T { + \bool_set_true:N \_stex_html_do_output_bool + } + } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{environment}{stex_annotate_env} +% \begin{macro}{\stex_annotate:nnn, \stex_annotate_invisible:n, +% \stex_annotate_invisible:nnn} +% +% We define four macros for introducing attributes in the HTML +% output. The definitions depend on the ``backend'' used +% (\latexml, \rustex, \texttt{pdflatex}). +% +% The \texttt{pdflatex}-macros largely do nothing; the +% \rustex-implementations are pretty clear in what they do, +% the \latexml-implementations resort to perl bindings. +% +% \begin{macrocode} +\rustex_if:TF{ + \cs_new_protected:Nn \stex_annotate:nnn { + \_@@_checkempty:n { #3 } + \rustex_annotate_HTML:nn { + property="stex:#1" ~ + resource="#2" + } { + \mode_if_vertical:TF{ + \tl_use:N \l_@@_arg_tl\par + }{ + \tl_use:N \l_@@_arg_tl + } + } + } + \cs_new_protected:Nn \stex_annotate_invisible:n { + \_@@_checkempty:n { #1 } + \rustex_annotate_HTML:nn { + stex:visible="false" ~ + style:display="none" + } { + \mode_if_vertical:TF{ + \tl_use:N \l_@@_arg_tl\par + }{ + \tl_use:N \l_@@_arg_tl + } + } + } + \cs_new_protected:Nn \stex_annotate_invisible:nnn { + \_@@_checkempty:n { #3 } + \rustex_annotate_HTML:nn { + property="stex:#1" ~ + resource="#2" ~ + stex:visible="false" ~ + style:display="none" + } { + \mode_if_vertical:TF{ + \tl_use:N \l_@@_arg_tl\par + }{ + \tl_use:N \l_@@_arg_tl + } + } + } + \NewDocumentEnvironment{stex_annotate_env} { m m } { + \par + \rustex_annotate_HTML_begin:n { + property="stex:#1" ~ + resource="#2" + } + }{ + \par\rustex_annotate_HTML_end: + } +}{ + \latexml_if:TF { + \cs_new_protected:Nn \stex_annotate:nnn { + \_@@_checkempty:n { #3 } + \mode_if_math:TF { + \cs:w latexml@annotate@math\cs_end:{#1}{#2}{ + \tl_use:N \l_@@_arg_tl + } + }{ + \cs:w latexml@annotate@text\cs_end:{#1}{#2}{ + \tl_use:N \l_@@_arg_tl + } + } + } + \cs_new_protected:Nn \stex_annotate_invisible:n { + \_@@_checkempty:n { #1 } + \mode_if_math:TF { + \cs:w latexml@invisible@math\cs_end:{ + \tl_use:N \l_@@_arg_tl + } + } { + \cs:w latexml@invisible@text\cs_end:{ + \tl_use:N \l_@@_arg_tl + } + } + } + \cs_new_protected:Nn \stex_annotate_invisible:nnn { + \_@@_checkempty:n { #3 } + \cs:w latexml@annotate@invisible\cs_end:{#1}{#2}{ + \tl_use:N \l_@@_arg_tl + } + } + \NewDocumentEnvironment{stex_annotate_env} { m m } { + \par\begin{latexml@annotateenv}{#1}{#2} + }{ + \par\end{latexml@annotateenv} + } + }{ + \cs_new_protected:Nn \stex_annotate:nnn {#3} + \cs_new_protected:Nn \stex_annotate_invisible:n {} + \cs_new_protected:Nn \stex_annotate_invisible:nnn {} + \NewDocumentEnvironment{stex_annotate_env} { m m } {}{} + } +} +% \end{macrocode} +% \end{macro} +% \end{environment} +% +% \subsection{Babel Languages} +% \begin{macrocode} +%<@@=stex_language> +% \end{macrocode} +% +% \begin{variable}{\c_stex_languages_prop,\c_stex_language_abbrevs_prop} +% +% We store language abbreviations in two (mutually inverse) +% property lists: +% \begin{macrocode} +\prop_const_from_keyval:Nn \c_stex_languages_prop { + en = english , + de = ngerman , + ar = arabic , + bg = bulgarian , + ru = russian , + fi = finnish , + ro = romanian , + tr = turkish , + fr = french +} + +\prop_const_from_keyval:Nn \c_stex_language_abbrevs_prop { + english = en , + ngerman = de , + arabic = ar , + bulgarian = bg , + russian = ru , + finnish = fi , + romanian = ro , + turkish = tr , + french = fr +} +% todo: chinese simplified (zhs) +% chinese traditional (zht) +% \end{macrocode} +% \end{variable} +% +% we use the |lang|-package option to load the corresponding +% babel languages: +% +% \begin{macrocode} +\clist_if_empty:NF \c_stex_languages_clist { + \clist_clear:N \l_tmpa_clist + \clist_map_inline:Nn \c_stex_languages_clist { + \prop_get:NnNTF \c_stex_languages_prop { #1 } \l_tmpa_str { + \clist_put_right:No \l_tmpa_clist \l_tmpa_str + } { + \msg_error:nnx{stex}{error/unknownlanguage}{\l_tmpa_str} + } + } + \stex_debug:nn{lang} {Languages:~\clist_use:Nn \l_tmpa_clist {,~} } + \RequirePackage[\clist_use:Nn \l_tmpa_clist,]{babel} +} +% \end{macrocode} +% +% \subsection{Auxiliary Methods} +% +% \begin{macro}{\stex_deactivate_macro:Nn} +% \begin{macrocode} +\cs_new_protected:Nn \stex_deactivate_macro:Nn { + \exp_after:wN\let\csname \detokenize{#1} - orig\endcsname#1 + \def#1{ + \msg_error:nnnn{stex}{error/deactivated-macro}{#1}{#2} + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stex_reactivate_macro:N} +% \begin{macrocode} +\cs_new_protected:Nn \stex_reactivate_macro:N { + \exp_after:wN\let\exp_after:wN#1\csname \detokenize{#1} - orig\endcsname +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ignorespacesandpars} +% \begin{macrocode} +\protected\def\ignorespacesandpars{ + \begingroup\catcode13=10\relax + \@ifnextchar\par{ + \endgroup\expandafter\ignorespacesandpars\@gobble + }{ + \endgroup + } +} +%</package> +% \end{macrocode} +% \end{macro} +% +% \end{implementation} +% +% \PrintIndex diff --git a/macros/latex/contrib/stex/source/stex/features.dtx b/macros/latex/contrib/stex/source/stex/features.dtx new file mode 100644 index 0000000000..851af04984 --- /dev/null +++ b/macros/latex/contrib/stex/source/stex/features.dtx @@ -0,0 +1,784 @@ +% \iffalse meta-comment +% An Infrastructure for Semantic Macros and Module Scoping +% Copyright (c) 2019 Michael Kohlhase, all rights reserved +% this file is released under the +% LaTeX Project Public License (LPPL) +% +% The original of this file is in the public repository at +% http://github.com/sLaTeX/sTeX/ +% +% TODO update copyright +% +%<*driver> +\providecommand\bibfolder{../../lib/bib} +\input{../../doc/docheader} + +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{ \sTeX-Structural Features +% \thanks{Version {\fileversion} (last revised {\filedate})} +% } +% +% \author{Michael Kohlhase, Dennis Müller\\ +% FAU Erlangen-Nürnberg\\ +% \url{http://kwarc.info/} +% } +% +% \maketitle +% +%\ifinfulldoc\else +% This is the documentation for the \pkg{stex-features} package. +% For a more high-level introduction, +% see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the +% \href{\basedocurl/stex.pdf}{full \sTeX documentation}. +% +% \input{../../doc/packages/features} +% \fi +% +% \begin{documentation}\label{pkg:features:doc} +% +% Code related to structural features +% +% \section{Macros and Environments}\label{pkg:features:doc:macros} +% +% \subsection{Structures} +% +% \begin{environment}{mathstructure} +% TODO +% \end{environment} +% +% \end{documentation} +% +% \begin{implementation}\label{pkg:features:impl} +% +% \section{\sTeX-Structural Features Implementation} +% +% \begin{macrocode} +%<*package> + +%%%%%%%%%%%%% features.dtx %%%%%%%%%%%%% + +%<@@=stex_features> +% \end{macrocode} +% +% Warnings and error messages +% +% \begin{macrocode} +\msg_new:nnn{stex}{error/copymodule/notallowed}{ + Symbol~#1~can~not~be~assigned~in~copymodule~#2 +} +\msg_new:nnn{stex}{error/interpretmodule/nodefiniens}{ + Symbol~#1~not~assigned~in~interpretmodule~#2 +} + +% \end{macrocode} +% +% \subsection{Imports with modification} +% +% \begin{macrocode} +\cs_new_protected:Nn \stex_get_symbol_in_copymodule:n { + \tl_if_head_eq_catcode:nNTF { #1 } \relax { + \_@@_get_symbol_from_cs:n { #1 } + }{ + % argument is a string + % is it a command name? + \cs_if_exist:cTF { #1 }{ + \cs_set_eq:Nc \l_tmpa_tl { #1 } + \str_set:Nx \l_tmpa_str { \cs_argument_spec:N \l_tmpa_tl } + \str_if_empty:NTF \l_tmpa_str { + \exp_args:Nx \cs_if_eq:NNTF { + \tl_head:N \l_tmpa_tl + } \stex_invoke_symbol:n { + \exp_args:No \_@@_get_symbol_from_cs:n { \use:c { #1 } } + }{ + \_@@_get_symbol_from_string:n { #1 } + } + } { + \_@@_get_symbol_from_string:n { #1 } + } + }{ + % argument is not a command name + \_@@_get_symbol_from_string:n { #1 } + % \l_stex_all_symbols_seq + } + } +} + +\cs_new_protected:Nn \_@@_get_symbol_from_string:n { + \str_set:Nn \l_tmpa_str { #1 } + \bool_set_false:N \l_tmpa_bool + \bool_if:NF \l_tmpa_bool { + \tl_set:Nn \l_tmpa_tl { + \msg_set:nnn{stex}{error/unknownsymbol}{ + No~symbol~#1~found! + } + \msg_error:nn{stex}{error/unknownsymbol} + } + \str_set:Nn \l_tmpa_str { #1 } + \int_set:Nn \l_tmpa_int { \str_count:N \l_tmpa_str } + \seq_map_inline:Nn \l_@@_copymodule_fields_seq { + \str_set:Nn \l_tmpb_str { ##1 } + \str_if_eq:eeT { \l_tmpa_str } { + \str_range:Nnn \l_tmpb_str { -\l_tmpa_int } { -1 } + } { + \seq_map_break:n { + \tl_set:Nn \l_tmpa_tl { + \str_set:Nn \l_stex_get_symbol_uri_str { + ##1 + } + \_@@_get_symbol_check: + } + } + } + } + \l_tmpa_tl + } +} + +\cs_new_protected:Nn \_@@_get_symbol_from_cs:n { + \exp_args:NNx \tl_set:Nn \l_tmpa_tl + { \tl_tail:N \l_tmpa_tl } + \tl_if_single:NTF \l_tmpa_tl { + \exp_args:No \tl_if_head_is_group:nTF \l_tmpa_tl { + \exp_after:wN \str_set:Nn \exp_after:wN + \l_stex_get_symbol_uri_str \l_tmpa_tl + \_@@_get_symbol_check: + }{ + % TODO + % tail is not a single group + } + }{ + % TODO + % tail is not a single group + } +} + +\cs_new_protected:Nn \_@@_get_symbol_check: { + \exp_args:NNno \seq_set_split:Nnn \l_tmpa_seq {?} \l_stex_get_symbol_uri_str + \int_compare:nNnTF {\seq_count:N \l_tmpa_seq} = 3 { + \seq_pop_right:NN \l_tmpa_seq \l_tmpb_str + \str_set:Nx \l_tmpa_str {\seq_use:Nn \l_tmpa_seq ?} + \seq_if_in:NoF \l_@@_copymodule_modules_seq \l_tmpa_str { + \msg_error:nnxx{stex}{error/copymodule/notallowed}{\l_stex_get_symbol_uri_str}{ + \l_stex_current_copymodule_name_str\\Allowed:~\seq_use:Nn \l_@@_copymodule_modules_seq {,~} + } + } + }{ + \msg_error:nnxx{stex}{error/copymodule/notallowed}{\l_stex_get_symbol_uri_str}{ + \l_stex_current_copymodule_name_str~(inexplicably) + } + } +} + +\cs_new_protected:Nn \stex_copymodule_start:nnnn { + \stex_import_module_uri:nn { #1 } { #2 } + \str_set:Nx \l_stex_current_copymodule_name_str {#3} + \stex_import_require_module:nnnn + { \l_stex_import_ns_str } { \l_stex_import_archive_str } + { \l_stex_import_path_str } { \l_stex_import_name_str } + \stex_collect_imports:n {\l_stex_import_ns_str ?\l_stex_import_name_str } + \seq_set_eq:NN \l_@@_copymodule_modules_seq \l_stex_collect_imports_seq + \seq_clear:N \l_@@_copymodule_fields_seq + \seq_map_inline:Nn \l_@@_copymodule_modules_seq { + \seq_map_inline:cn {c_stex_module_##1_constants}{ + \exp_args:NNx \seq_put_right:Nn \l_@@_copymodule_fields_seq { + ##1 ? ####1 + } + } + } + \seq_clear:N \l_tmpa_seq + \exp_args:NNx \prop_set_from_keyval:Nn \l_stex_current_copymodule_prop { + name = \l_stex_current_copymodule_name_str , + module = \l_stex_current_module_str , + from = \l_stex_import_ns_str ?\l_stex_import_name_str , + includes = \l_tmpa_seq , + fields = \l_tmpa_seq + } + \stex_debug:nn{copymodule}{#4~for~module~{\l_stex_import_ns_str ?\l_stex_import_name_str} + as~\l_stex_current_module_str?\l_stex_current_copymodule_name_str} + \stex_debug:nn{copymodule}{modules:\seq_use:Nn \l_@@_copymodule_modules_seq {,~}} + \stex_debug:nn{copymodule}{fields:\seq_use:Nn \l_@@_copymodule_fields_seq {,~}} + \stex_if_smsmode:F { + \begin{stex_annotate_env} {#4} { + \l_stex_current_module_str?\l_stex_current_copymodule_name_str + } + \stex_annotate_invisible:nnn{from}{\l_stex_import_ns_str ?\l_stex_import_name_str}{} + } + \bool_set_eq:NN \l_@@_oldhtml_bool \_stex_html_do_output_bool + \bool_set_false:N \_stex_html_do_output_bool +} +\cs_new_protected:Nn \stex_copymodule_end:n { + \def \l_tmpa_cs ##1 ##2 {#1} + \bool_set_eq:NN \_stex_html_do_output_bool \l_@@_oldhtml_bool + \tl_clear:N \l_tmpa_tl + \tl_clear:N \l_tmpb_tl + \prop_get:NnN \l_stex_current_copymodule_prop {fields} \l_tmpa_seq + \seq_map_inline:Nn \l_@@_copymodule_modules_seq { + \seq_map_inline:cn {c_stex_module_##1_constants}{ + \tl_clear:N \l_tmpc_tl + \l_tmpa_cs{##1}{####1} + \str_if_exist:cTF {l_@@_copymodule_##1?####1_name_str} { + \tl_put_right:Nx \l_tmpa_tl { + \prop_set_from_keyval:cn { + l_stex_symdecl_\l_stex_current_module_str ? \use:c{l_@@_copymodule_##1?####1_name_str}_prop + }{ + \exp_after:wN \prop_to_keyval:N \csname + l_stex_symdecl_\l_stex_current_module_str ? \use:c{l_@@_copymodule_##1?####1_name_str}_prop + \endcsname + } + \seq_clear:c { + l_stex_symdecl_ + \l_stex_current_module_str ? \use:c{l_@@_copymodule_##1?####1_name_str} + _notations + } + } + \tl_put_right:Nx \l_tmpc_tl { + \stex_copy_notations:nn {\l_stex_current_module_str ? \use:c{l_@@_copymodule_##1?####1_name_str}}{##1?####1} + \stex_annotate_invisible:nnn{alias}{\use:c{l_@@_copymodule_##1?####1_name_str}}{} + } + \seq_put_right:Nx \l_tmpa_seq {\l_stex_current_module_str ? \use:c{l_@@_copymodule_##1?####1_name_str}} + \str_if_exist:cT {l_@@_copymodule_##1?####1_macroname_str} { + \tl_put_right:Nx \l_tmpc_tl { + \stex_annotate_invisible:nnn{macroname}{\use:c{l_@@_copymodule_##1?####1_macroname_str}}{} + } + \tl_put_right:Nx \l_tmpa_tl { + \tl_set:cx {\use:c{l_@@_copymodule_##1?####1_macroname_str}}{ + \stex_invoke_symbol:n { + \l_stex_current_module_str ? \use:c{l_@@_copymodule_##1?####1_name_str} + } + } + } + } + }{ + \tl_put_right:Nx \l_tmpc_tl { + \stex_copy_notations:nn {\l_stex_current_module_str ? \l_stex_current_copymodule_name_str / ####1 }{##1?####1} + } + \prop_set_eq:Nc \l_tmpa_prop {l_stex_symdecl_ ##1?####1 _prop} + \prop_put:Nnx \l_tmpa_prop { name }{ \l_stex_current_copymodule_name_str / ####1 } + \prop_put:Nnx \l_tmpa_prop { module }{ \l_stex_current_module_str } + \tl_put_right:Nx \l_tmpa_tl { + \prop_set_from_keyval:cn { + l_stex_symdecl_\l_stex_current_module_str ? \l_stex_current_copymodule_name_str / ####1_prop + }{ + \prop_to_keyval:N \l_tmpa_prop + } + \seq_clear:c { + l_stex_symdecl_ + \l_stex_current_module_str ? \l_stex_current_copymodule_name_str / ####1 + _notations + } + } + \seq_put_right:Nx \l_tmpa_seq {\l_stex_current_module_str ? \l_stex_current_copymodule_name_str / ####1 } + \str_if_exist:cT {l_@@_copymodule_##1?####1_macroname_str} { + \tl_put_right:Nx \l_tmpc_tl { + \stex_annotate_invisible:nnn{macroname}{\use:c{l_@@_copymodule_##1?####1_macroname_str}}{} + } + \tl_put_right:Nx \l_tmpa_tl { + \tl_set:cx {\use:c{l_@@_copymodule_##1?####1_macroname_str}}{ + \stex_invoke_symbol:n { + \l_stex_current_module_str ? \l_stex_current_copymodule_name_str / ####1 + } + } + } + } + } + \tl_if_exist:cT {l_@@_copymodule_##1?####1_def_tl}{ + \tl_put_right:Nx \l_tmpc_tl { + \stex_annotate_invisible:nnn{definiens}{}{$\use:c{l_@@_copymodule_##1?####1_def_tl}$} + } + } + \tl_put_right:Nx \l_tmpb_tl { + \stex_annotate:nnn{assignment} {##1?####1} { \l_tmpc_tl } + } + } + } + \prop_put:Nno \l_stex_current_copymodule_prop {fields} \l_tmpa_seq + \tl_put_left:Nx \l_tmpa_tl { + \prop_set_from_keyval:cn { + l_stex_copymodule_ \l_stex_current_module_str?\l_stex_current_copymodule_name_str _prop + }{ + \prop_to_keyval:N \l_stex_current_copymodule_prop + } + } + \exp_args:No \stex_add_to_current_module:n \l_tmpa_tl + \stex_debug:nn{copymodule}{result:\meaning \l_tmpa_tl} + \exp_args:Nx \stex_do_up_to_module:n { + \exp_args:No \exp_not:n \l_tmpa_tl + } + \l_tmpb_tl + \stex_if_smsmode:F { + \end{stex_annotate_env} + } +} + +\NewDocumentEnvironment {copymodule} { O{} m m}{ + \stex_copymodule_start:nnnn { #1 }{ #2 }{ #3 }{ structure } + \stex_deactivate_macro:Nn \symdecl {module~environments} + \stex_deactivate_macro:Nn \symdef {module~environments} + \stex_deactivate_macro:Nn \notation {module~environments} + \stex_reactivate_macro:N \assign + \stex_reactivate_macro:N \renamedecl + \stex_reactivate_macro:N \donotcopy + \stex_smsmode_do: +}{ + \stex_copymodule_end:n {} +} + +\NewDocumentEnvironment {interpretmodule} { O{} m m}{ + \stex_copymodule_start:nnnn { #1 }{ #2 }{ #3 }{ realization } + \stex_deactivate_macro:Nn \symdecl {module~environments} + \stex_deactivate_macro:Nn \symdef {module~environments} + \stex_deactivate_macro:Nn \notation {module~environments} + \stex_reactivate_macro:N \assign + \stex_reactivate_macro:N \renamedecl + \stex_reactivate_macro:N \donotcopy + \stex_smsmode_do: +}{ + \stex_copymodule_end:n { + \tl_if_exist:cF { + l_@@_copymodule_##1?##2_def_tl + }{ + \msg_error:nnxx{stex}{error/interpretmodule/nodefiniens}{ + ##1?##2 + }{\l_stex_current_copymodule_name_str} + } + } +} + +\NewDocumentCommand \donotcopy { O{} m}{ + \stex_import_module_uri:nn { #1 } { #2 } + \stex_collect_imports:n {\l_stex_import_ns_str ?\l_stex_import_name_str } + \seq_map_inline:Nn \l_stex_collect_imports_seq { + \seq_remove_all:Nn \l_@@_copymodule_modules_seq { ##1 } + \seq_map_inline:cn {c_stex_module_##1_constants}{ + \seq_remove_all:Nn \l_@@_copymodule_fields_seq { ##1 ? ####1 } + \bool_lazy_any_p:nT { + { \cs_if_exist_p:c {l_@@_copymodule_##1?####1_name_str}} + { \cs_if_exist_p:c {l_@@_copymodule_##1?####1_macroname_str}} + { \cs_if_exist_p:c {l_@@_copymodule_##1?####1_def_tl}} + }{ + % TODO throw error + } + } + } + + \prop_get:NnN \l_stex_current_copymodule_prop { includes } \l_tmpa_seq + \seq_put_right:Nx \l_tmpa_seq {\l_stex_import_ns_str ?\l_stex_import_name_str } + \prop_put:Nnx \l_stex_current_copymodule_prop {includes} \l_tmpa_seq +} + +\NewDocumentCommand \assign { m m }{ + \stex_get_symbol_in_copymodule:n {#1} + \stex_debug:nn{assign}{defining~{\l_stex_get_symbol_uri_str}~as~\detokenize{#2}} + \tl_set:cn {l_@@_copymodule_\l_stex_get_symbol_uri_str _def_tl}{#2} +} + +\keys_define:nn { stex / renamedecl } { + name .str_set_x:N = \l_stex_renamedecl_name_str +} +\cs_new_protected:Nn \_@@_renamedecl_args:n { + \str_clear:N \l_stex_renamedecl_name_str + + \keys_set:nn { stex / renamedecl } { #1 } +} + +\NewDocumentCommand \renamedecl { O{} m m}{ + \_@@_renamedecl_args:n { #1 } + \stex_get_symbol_in_copymodule:n {#2} + \stex_debug:nn{renamedecl}{renaming~{\l_stex_get_symbol_uri_str}~to~#3} + \str_set:cx {l_@@_copymodule_\l_stex_get_symbol_uri_str _macroname_str}{#3} + \str_if_empty:NTF \l_stex_renamedecl_name_str { + \tl_set:cx { #3 }{ \stex_invoke_symbol:n { + \l_stex_get_symbol_uri_str + } } + } { + \str_set:cx {l_@@_copymodule_\l_stex_get_symbol_uri_str _name_str}{\l_stex_renamedecl_name_str} + \stex_debug:nn{renamedecl}{@~\l_stex_current_module_str ? \l_stex_renamedecl_name_str} + \prop_set_eq:cc {l_stex_symdecl_ + \l_stex_current_module_str ? \l_stex_renamedecl_name_str + _prop + }{l_stex_symdecl_ \l_stex_get_symbol_uri_str _prop} + \seq_set_eq:cc {l_stex_symdecl_ + \l_stex_current_module_str ? \l_stex_renamedecl_name_str + _notations + }{l_stex_symdecl_ \l_stex_get_symbol_uri_str _notations} + \prop_put:cnx {l_stex_symdecl_ + \l_stex_current_module_str ? \l_stex_renamedecl_name_str + _prop + }{ name }{ \l_stex_renamedecl_name_str } + \prop_put:cnx {l_stex_symdecl_ + \l_stex_current_module_str ? \l_stex_renamedecl_name_str + _prop + }{ module }{ \l_stex_current_module_str } + \exp_args:NNx \seq_put_left:Nn \l_@@_copymodule_fields_seq { + \l_stex_current_module_str ? \l_stex_renamedecl_name_str + } + \tl_set:cx { #3 }{ \stex_invoke_symbol:n { + \l_stex_current_module_str ? \l_stex_renamedecl_name_str + } } + } +} + +\stex_deactivate_macro:Nn \assign {copymodules} +\stex_deactivate_macro:Nn \renamedecl {copymodules} +\stex_deactivate_macro:Nn \donotcopy {copymodules} + + +% \end{macrocode} +% +% +% +% \begin{macrocode} +\seq_new:N \l_stex_implicit_morphisms_seq +\NewDocumentCommand \implicitmorphism { O{} m m}{ + \stex_import_module_uri:nn { #1 } { #2 } + \stex_debug:nn{implicits}{ + Implicit~morphism:~ + \l_stex_module_ns_str ? \l_@@_name_str + } + \exp_args:NNx \seq_if_in:NnT \l_stex_all_modules_seq { + \l_stex_module_ns_str ? \l_@@_name_str + }{ + \msg_error:nnn{stex}{error/conflictingmodules}{ + \l_stex_module_ns_str ? \l_@@_name_str + } + } + + % TODO + + + + \seq_put_right:Nx \l_stex_implicit_morphisms_seq { + \l_stex_module_ns_str ? \l_@@_name_str + } +} + +% \end{macrocode} +% +% +% \subsection{The feature environment} +% +% \begin{environment}{structural@feature} +% \begin{macrocode} + +\NewDocumentEnvironment{structural@feature}{ m m m }{ + \stex_if_in_module:F { + \msg_set:nnn{stex}{error/nomodule}{ + Structural~Feature~has~to~occur~in~a~module:\\ + Feature~#2~of~type~#1\\ + In~File:~\stex_path_to_string:N \g_stex_currentfile_seq + } + \msg_error:nn{stex}{error/nomodule} + } + + \str_set:Nx \l_stex_module_name_str { + \prop_item:Nn \l_stex_current_module_prop + { name } / #2 - feature + } + + \str_set:Nx \l_stex_module_ns_str { + \prop_item:Nn \l_stex_current_module_prop + { ns } + } + + + \str_clear:N \l_tmpa_str + \seq_clear:N \l_tmpa_seq + \tl_clear:N \l_tmpa_tl + \exp_args:NNx \prop_set_from_keyval:Nn \l_stex_current_module_prop { + origname = #2, + name = \l_stex_module_name_str , + ns = \l_stex_module_ns_str , + imports = \exp_not:o { \l_tmpa_seq } , + constants = \exp_not:o { \l_tmpa_seq } , + content = \exp_not:o { \l_tmpa_tl } , + file = \exp_not:o { \g_stex_currentfile_seq } , + lang = \l_stex_module_lang_str , + sig = \l_tmpa_str , + meta = \l_tmpa_str , + feature = #1 , + } + + \stex_if_smsmode:F { + \begin{stex_annotate_env}{ feature:#1 }{} + \stex_annotate_invisible:nnn{header}{}{ #3 } + } +}{ + \str_set:Nx \l_tmpa_str { + c_stex_feature_ + \prop_item:Nn \l_stex_current_module_prop { ns } ? + \prop_item:Nn \l_stex_current_module_prop { name } + _prop + } + \prop_gset_eq:cN { \l_tmpa_str } \l_stex_current_module_prop + \prop_gset_eq:NN \g_stex_last_feature_prop \l_stex_current_module_prop + \stex_if_smsmode:F { + \end{stex_annotate_env} + } +} + +% \end{macrocode} +% \end{environment} +% +% +% \subsection{Features} +% +% \begin{environment}{structure} +% \begin{macrocode} + +\prop_new:N \l_stex_all_structures_prop + +\keys_define:nn { stex / features / structure } { + name .str_set_x:N = \l_@@_structure_name_str , +} + +\cs_new_protected:Nn \_@@_structure_args:n { + \str_clear:N \l_@@_structure_name_str + \keys_set:nn { stex / features / structure } { #1 } +} + +\NewDocumentEnvironment{mathstructure}{ O{} m }{ + \_@@_structure_args:n { #1 } + \str_if_empty:NT \l_@@_structure_name_str { + \str_set:Nx \l_@@_structure_name_str { #2 } + } + \exp_args:Nnnx + \begin{structural@feature}{ structure } + { \l_@@_structure_name_str }{} + \seq_clear:N \l_tmpa_seq + \prop_put:Nno \l_stex_current_module_prop { fields } \l_tmpa_seq + \stex_smsmode_do: +}{ + \prop_get:NnN \l_stex_current_module_prop { constants } \l_tmpa_seq + \prop_get:NnN \l_stex_current_module_prop { fields } \l_tmpb_seq + \str_set:Nx \l_tmpa_str { + \prop_item:Nn \l_stex_current_module_prop { ns } ? + \prop_item:Nn \l_stex_current_module_prop { name } + } + \seq_map_inline:Nn \l_tmpa_seq { + \exp_args:NNx \seq_put_right:Nn \l_tmpb_seq { \l_tmpa_str ? ##1 } + } + \prop_put:Nno \l_stex_current_module_prop { fields } { \l_tmpb_seq } + \exp_args:Nnx + \AddToHookNext { env / mathstructure / after }{ + \symdecl{ #2 }[type = \exp_not:N\collection,def={\STEXsymbol{module-type}{ + \_stex_term_math_oms:nnnn { \l_tmpa_str }{}{0}{} + }}, name = \prop_item:Nn \l_stex_current_module_prop { origname }] + \STEXexport { + \prop_put:Nno \exp_not:N \l_stex_all_structures_prop + {\prop_item:Nn \l_stex_current_module_prop { origname }} + {\l_tmpa_str} + \prop_put:Nno \exp_not:N \l_stex_all_structures_prop + {#2}{\l_tmpa_str} +% \seq_put_right:Nn \exp_not:N \l_stex_all_structures_seq { +% \prop_item:Nn \l_stex_current_module_prop { origname }, +% \l_tmpa_str +% } +% \seq_put_right:Nn \exp_not:N \l_stex_all_structures_seq { +% #2,\l_tmpa_str +% } +% \tl_set:cx { #2 } { +% \stex_invoke_structure:n { \l_tmpa_str } + } + } + + \end{structural@feature} + % \g_stex_last_feature_prop +} +% \end{macrocode} +% \end{environment} +% +% +% \begin{macro}{\instantiate} +% \begin{macrocode} +\seq_new:N \l_@@_structure_field_seq +\str_new:N \l_@@_structure_field_str +\str_new:N \l_@@_structure_def_tl +\prop_new:N \l_@@_structure_prop +\NewDocumentCommand \instantiate { m O{} m }{ + \prop_get:NnN \l_stex_all_structures_prop {#1} \l_tmpa_str + \prop_set_eq:Nc \l_@@_structure_prop { + c_stex_feature_\l_tmpa_str _prop + } + \seq_set_from_clist:Nn \l_@@_structure_field_seq { #2 } + \seq_map_inline:Nn \l_@@_structure_field_seq { + \seq_set_split:Nnn \l_tmpa_seq{=}{ ##1 } + \int_compare:nNnTF {\seq_count:N \l_tmpa_seq} > 1 { + \seq_get_left:NN \l_tmpa_seq \l_tmpa_tl + \exp_args:NNno \seq_set_split:Nnn \l_tmpb_seq + {!} \l_tmpa_tl + \int_compare:nNnTF {\seq_count:N \l_tmpb_seq} > 1 { + \str_set:Nx \l_@@_structure_field_str {\seq_item:Nn \l_tmpb_seq 1} + \seq_get_right:NN \l_tmpb_seq \l_tmpb_tl + \seq_get_right:NN \l_tmpa_seq \l_tmpa_tl + }{ + \str_set:Nx \l_@@_structure_field_str \l_tmpa_tl + \seq_get_right:NN \l_tmpa_seq \l_tmpa_tl + \exp_args:NNno \seq_set_split:Nnn \l_tmpb_seq{!} + \l_tmpa_tl + \int_compare:nNnTF {\seq_count:N \l_tmpb_seq} > 1 { + \seq_get_left:NN \l_tmpb_seq \l_tmpa_tl + \seq_get_right:NN \l_tmpb_seq \l_tmpb_tl + }{ + \tl_clear:N \l_tmpb_tl + } + } + }{ + \seq_set_split:Nnn \l_tmpa_seq{!}{ ##1 } + \int_compare:nNnTF {\seq_count:N \l_tmpa_seq} > 1 { + \str_set:Nx \l_@@_structure_field_str {\seq_item:Nn \l_tmpa_seq 1} + \seq_get_right:NN \l_tmpa_seq \l_tmpb_tl + \tl_clear:N \l_tmpa_tl + }{ + % TODO throw error + } + } + % \l_tmpa_str: name + % \l_tmpa_tl: definiens + % \l_tmpb_tl: notation + \tl_if_empty:NT \l_@@_structure_field_str { + % TODO throw error + } + \str_clear:N \l_tmpb_str + + \prop_get:NnN \l_@@_structure_prop { fields } \l_tmpa_seq + \seq_map_inline:Nn \l_tmpa_seq { + \seq_set_split:Nnn \l_tmpb_seq ? { ####1 } + \seq_get_right:NN \l_tmpb_seq \l_tmpb_str + \str_if_eq:NNT \l_@@_structure_field_str \l_tmpb_str { + \seq_map_break:n { + \str_set:Nn \l_tmpb_str { ####1 } + } + } + } + \prop_get:cnN { l_stex_symdecl_ \l_tmpb_str _prop } {args} + \l_tmpb_str + + \tl_if_empty:NTF \l_tmpb_tl { + \tl_if_empty:NF \l_tmpa_tl { + \exp_args:Nx \use:n { + \symdecl{#3/\l_@@_structure_field_str}[args=\l_tmpb_str,def={\exp_args:No\exp_not:n{\l_tmpa_tl}}] + } + } + }{ + \tl_if_empty:NTF \l_tmpa_tl { + \exp_args:Nx \use:n { + \symdef{#3/\l_@@_structure_field_str}[args=\l_tmpb_str]\exp_after:wN\exp_not:n\exp_after:wN{\l_tmpb_tl} + } + + }{ + \exp_args:Nx \use:n { + \symdef{#3/\l_@@_structure_field_str}[args=\l_tmpb_str,def={\exp_args:No\exp_not:n{\l_tmpa_tl}}] + \exp_after:wN\exp_not:n\exp_after:wN{\l_tmpb_tl} + } + } + } +% \par \prop_item:Nn \l_stex_current_module_prop {ns} ? +% \prop_item:Nn \l_stex_current_module_prop {name} ? +% #3/\l_@@_structure_field_str +% \par +% \expandafter\present\csname +% l_stex_symdecl_ +% \prop_item:Nn \l_stex_current_module_prop {ns} ? +% \prop_item:Nn \l_stex_current_module_prop {name} ? +% #3/\l_@@_structure_field_str +% _prop +% \endcsname + } + + \tl_clear:N \l_@@_structure_def_tl + + \prop_get:NnN \l_@@_structure_prop { fields } \l_tmpa_seq + \seq_map_inline:Nn \l_tmpa_seq { + \seq_set_split:Nnn \l_tmpb_seq ? { ##1 } + \seq_get_right:NN \l_tmpb_seq \l_tmpa_str + \exp_args:Nx \use:n { + \tl_put_right:Nn \exp_not:N \l_@@_structure_def_tl { + + } + } + + \prop_if_exist:cF { + l_stex_symdecl_ + \prop_item:Nn \l_stex_current_module_prop {ns} ? + \prop_item:Nn \l_stex_current_module_prop {name} ? + #3/\l_tmpa_str + _prop + }{ + \prop_get:cnN { l_stex_symdecl_ ##1 _prop } {args} + \l_tmpb_str + \exp_args:Nx \use:n { + \symdecl{#3/\l_tmpa_str}[args=\l_tmpb_str] + } + } + } + + \symdecl*{#3}[type={\STEXsymbol{module-type}{ + \_stex_term_math_oms:nnnn { + \prop_item:Nn \l_@@_structure_prop {ns} ? + \prop_item:Nn \l_@@_structure_prop {name} + }{}{0}{} + }}] + + % TODO: -> sms file + + \tl_set:cx{ #3 }{ + \stex_invoke_structure:nnn { + \prop_item:Nn \l_stex_current_module_prop {ns} ? + \prop_item:Nn \l_stex_current_module_prop {name} ? #3 + } { + \prop_item:Nn \l_@@_structure_prop {ns} ? + \prop_item:Nn \l_@@_structure_prop {name} + } + } + \stex_smsmode_do: +} +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\stex_invoke_structure:nnn} +% \begin{macrocode} +% #1: URI of the instance +% #2: URI of the instantiated module +\cs_new_protected:Nn \stex_invoke_structure:nnn { + \tl_if_empty:nTF{ #3 }{ + \prop_set_eq:Nc \l_@@_structure_prop { + c_stex_feature_ #2 _prop + } + \tl_clear:N \l_tmpa_tl + \prop_get:NnN \l_@@_structure_prop { fields } \l_tmpa_seq + \seq_map_inline:Nn \l_tmpa_seq { + \seq_set_split:Nnn \l_tmpb_seq ? { ##1 } + \seq_get_right:NN \l_tmpb_seq \l_tmpa_str + \cs_if_exist:cT { + stex_notation_ #1/\l_tmpa_str \c_hash_str\c_hash_str _cs + }{ + \tl_if_empty:NF \l_tmpa_tl { + \tl_put_right:Nn \l_tmpa_tl {,} + } + \tl_put_right:Nx \l_tmpa_tl { + \stex_invoke_symbol:n {#1/\l_tmpa_str}! + } + } + } + \exp_args:No \mathstruct \l_tmpa_tl + }{ + \stex_invoke_symbol:n{#1/#3} + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/macros/latex/contrib/stex/source/stex/inheritance.dtx b/macros/latex/contrib/stex/source/stex/inheritance.dtx new file mode 100644 index 0000000000..692d7b952c --- /dev/null +++ b/macros/latex/contrib/stex/source/stex/inheritance.dtx @@ -0,0 +1,575 @@ +% \iffalse meta-comment +% An Infrastructure for Semantic Macros and Module Scoping +% Copyright (c) 2019 Michael Kohlhase, all rights reserved +% this file is released under the +% LaTeX Project Public License (LPPL) +% +% The original of this file is in the public repository at +% http://github.com/sLaTeX/sTeX/ +% +% TODO update copyright +% +%<*driver> +\providecommand\bibfolder{../../lib/bib} +\input{../../doc/docheader} + +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{ \sTeX-Module Inheritance +% \thanks{Version {\fileversion} (last revised {\filedate})} +% } +% +% \author{Michael Kohlhase, Dennis Müller\\ +% FAU Erlangen-Nürnberg\\ +% \url{http://kwarc.info/} +% } +% +% \maketitle +% +%\ifinfulldoc\else +% This is the documentation for the \pkg{stex-inheritance} package. +% For a more high-level introduction, +% see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the +% \href{\basedocurl/stex.pdf}{full \sTeX documentation}. +% \fi +% +% \begin{documentation}\label{pkg:inheritance:doc} +% +% Code related to Module Inheritance, in particular \emph{sms mode}. +% +%\ifinfulldoc\else +% \input{../../doc/packages/inheritance} +%\fi +% +% \section{Macros and Environments}\label{pkg:inheritance:doc:macros} +% +% \subsection{SMS Mode} +% ``SMS Mode'' is used when loading modules from external tex files. +% It deactivates any output and ignores all \TeX\ commands +% not explicitly allowed via the following lists -- all of which either +% declare module content or are needed in order to declare module content: +% +% \begin{variable}{\g_stex_smsmode_allowedmacros_tl} +% Macros that are executed as is; i.e. sms mode continues immediately after. +% These macros may not take any arguments or otherwise gobble tokens. +% +% Initially: \cs{makeatletter}, \cs{makeatother}, \cs{ExplSyntaxOn}, +% \cs{ExplSyntaxOff}. +% \end{variable} +% +% \begin{variable}{\g_stex_smsmode_allowedmacros_escape_tl} +% Macros that are executed and potentially gobble up further tokens. +% These macros need to make sure, that the very last token they ultimately +% expand to is \cs{stex_smsmode_do:}. +% +% Initially: \cs{symdecl}, \cs{notation}, \cs{symdef}, +% \cs{importmodule}, \cs{STEXexport}, \cs{inlineass}, \cs{inlinedef}, +% \cs{inlineex}, \cs{endinput}, \cs{setnotation}, \cs{copynotation}. +% \end{variable} +% +% \begin{variable}{\g_stex_smsmode_allowedenvs_seq} +% The names of environments that should be allowed in SMS mode. +% The corresponding \cs{begin}-statements are treated like +% the macros in \cs{g_stex_smsmode_allowedmacros_escape_tl}, so +% \cs{stex_smsmode_do:} needs to be the last token in the +% \cs{begin}-code. Since \cs{end}-statements take no arguments anyway, +% those are called directly and sms mode continues afterwards. +% +% Initially: |smodule|, |copymodule|, |interpretmodule|, |sdefinition|, +% |sexample|, |sassertion|, |sparagraph|. +% \end{variable} +% +% \begin{function}[pTF]{\stex_if_smsmode:} +% Tests whether SMS mode is currently active. +% \end{function} +% +% \begin{function}{\stex_file_in_smsmode:nn} +% \begin{syntax} \cs{stex_in_smsmode:nn} \Arg{filename} \Arg{code} \end{syntax} +% Executes \meta{code} in SMS mode, followed by the content of \meta{filename}. +% \meta{code} can be used e.g. to set the current repository, and is +% executed within a new tex group, and the same group as the file content. +% \end{function} +% +% \begin{function}{\stex_smsmode_do:} +% Starts gobbling tokens until one is encountered that is allowed in SMS mode. +% \end{function} +% +% \subsection{Imports and Inheritance} +% +% \begin{function}{\importmodule} +% \begin{syntax} \cs{importmodule}|[|\meta{archive-ID}|]|\Arg{module-path} \end{syntax} +% Imports a module by reading it from a file and ``activating'' it. +% \sTeX determines the module and its containing file by passing its +% arguments on to \cs{stex_import_module_path:nn}. +% +% \end{function} +% +% \begin{function}{\usemodule} +% \begin{syntax} \cs{importmodule}|[|\meta{archive-ID}|]|\Arg{module-path} \end{syntax} +% Like \cs{importmodule}, but does not export its contents; +% i.e. including the current module will not activate the used module +% \end{function} +% +% \begin{function}{\stex_import_module_uri:nn} +% \begin{syntax} \cs{stex_import_module_uri:nn} \Arg{archive-ID} \Arg{module-path} \end{syntax} +% Determines the URI of a module by splitting +% \meta{module-path} into \meta{path}|?|\meta{name}. If \meta{module-path} +% does \emph{not} contain a |?|-character, we consider it to be the \meta{name}, +% and \meta{path} to be empty. +% +% If \meta{archive-ID} is empty, it is automatically set to the +% ID of the current archive (if one exists). +% +% \begin{enumerate} +% \item If \meta{archive-ID} is empty: +% \begin{enumerate} +% \item If \meta{path} is empty, then +% \meta{name} must have been declared earlier in the same file +% and retrievable from \cs{g_stex_modules_in_file_seq}, or +% a file with name \meta{name}|.|\meta{lang}|.tex| must exist +% in the same folder, containing a module \meta{name}. +% +% That module should have the same namespace as the current one. +% \item If \meta{path} is not empty, it must point to the relative +% path of the containing file as well as the namespace. +% \end{enumerate} +% \item Otherwise: +% \begin{enumerate} +% \item If \meta{path} is empty, then +% \meta{name} must have been declared earlier in the same file +% and retrievable from \cs{g_stex_modules_in_file_seq}, or +% a file with name \meta{name}|.|\meta{lang}|.tex| must exist +% in the top |source| folder of the archive, +% containing a module \meta{name}. +% +% That module should lie directly in the namespace +% of the archive. +% \item If \meta{path} is not empty, it must point to the +% path of the containing file as well as the namespace, +% relative to the namespace of the archive. +% +% If a module by that namespace exists, it is returned. +% Otherwise, we call \cs{stex_require_module:nn} +% on the |source| directory of the archive to find the +% file. +% \end{enumerate} +% \end{enumerate} +% \end{function} +% \begin{variable}{ +% \l_stex_import_name_str,\l_stex_import_archive_str,\l_stex_import_path_str,\l_stex_import_ns_str +% } +% stores the result in these four variables. +% \end{variable} +% +% \begin{function}{\stex_import_require_module:nnnn} +% \begin{syntax} \Arg{ns} \Arg{archive-ID} \Arg{path} \Arg{name} \end{syntax} +% Checks whether a module with URI \meta{ns}|?|\meta{name} already +% exists. If not, it looks for a plausible file that declares +% a module with that URI. +% +% Finally, activates that module by executing its |_code|-macro. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation}\label{pkg:inheritance:impl} +% +% \section{\sTeX-Module Inheritance Implementation} +% +% \begin{macrocode} +%<*package> + +%%%%%%%%%%%%% inheritance.dtx %%%%%%%%%%%%% + +% \end{macrocode} +% +% \subsection{SMS Mode} +% \begin{macrocode} +%<@@=stex_smsmode> +% \end{macrocode} +% +% \begin{variable}{ +% \g_stex_smsmode_allowedmacros_tl, +% \g_stex_smsmode_allowedmacros_escape_tl, +% \g_stex_smsmode_allowedenvs_seq +% } +% \begin{macrocode} +\tl_new:N \g_stex_smsmode_allowedmacros_tl +\tl_new:N \g_stex_smsmode_allowedmacros_escape_tl +\seq_new:N \g_stex_smsmode_allowedenvs_seq + +\tl_set:Nn \g_stex_smsmode_allowedmacros_tl { + \makeatletter + \makeatother + \ExplSyntaxOn + \ExplSyntaxOff + \rustexBREAK +} + +\tl_set:Nn \g_stex_smsmode_allowedmacros_escape_tl { + \symdef + \importmodule + \notation + \symdecl + \STEXexport + \inlineass + \inlinedef + \inlineex + \endinput + \setnotation + \copynotation +} + +\exp_args:NNx \seq_set_from_clist:Nn \g_stex_smsmode_allowedenvs_seq { + \tl_to_str:n { + smodule, + copymodule, + interpretmodule, + sdefinition, + sexample, + sassertion, + sparagraph + } +} +% \end{macrocode} +% \end{variable} +% +% \begin{macro}[pTF]{\stex_if_smsmode:} +% \begin{macrocode} +\bool_new:N \g_@@_bool +\bool_set_false:N \g_@@_bool +\prg_new_conditional:Nnn \stex_if_smsmode: { p, T, F, TF } { + \bool_if:NTF \g_@@_bool \prg_return_true: \prg_return_false: +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\_@@_in_smsmode:nn} +% \begin{macrocode} +\cs_new_protected:Nn \_@@_in_smsmode:nn { + \vbox_set:Nn \l_tmpa_box { + \bool_set_eq:cN { l_@@_#1_bool } \g_@@_bool + \bool_gset_true:N \g_@@_bool + #2 + \bool_gset_eq:Nc \g_@@_bool { l_@@_#1_bool } + } + \box_clear:N \l_tmpa_box +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stex_file_in_smsmode:nn} +% \begin{macrocode} +\quark_new:N \q_@@_break + +\cs_new_protected:Nn \stex_file_in_smsmode:nn { + \stex_filestack_push:n{#1} + \_@@_in_smsmode:nn{#1} { + #2 + \everyeof{\q_@@_break\noexpand} + \expandafter\expandafter\expandafter + \stex_smsmode_do: + \csname @ @ input\endcsname "#1"\relax + } + \stex_filestack_pop: +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stex_smsmode_do:} +% is executed on encountering |\| in smsmode. +% It checks whether the corresponding command is allowed and executes +% or ignores it accordingly: +% \begin{macrocode} +\cs_new_protected:Npn \stex_smsmode_do: { + \stex_if_smsmode:T { + \_@@_do:w + } +} +\cs_new_protected:Npn \_@@_do:w #1 { + \exp_args:Nx \tl_if_empty:nTF { \tl_tail:n{ #1 }}{ + \expandafter\if\expandafter\relax\noexpand#1 + \expandafter\_@@_do_aux:N\expandafter#1 + \else\expandafter\_@@_do:w\fi + }{ + \_@@_do:w %#1 + } +} +\cs_new_protected:Nn \_@@_do_aux:N { + \cs_if_eq:NNF #1 \q_@@_break { + \tl_if_in:NnTF \g_stex_smsmode_allowedmacros_tl {#1} { + #1\_@@_do:w + }{ + \tl_if_in:NnTF \g_stex_smsmode_allowedmacros_escape_tl {#1} { + #1 + }{ + \cs_if_eq:NNTF \begin #1 { + \_@@_check_begin:n + }{ + \cs_if_eq:NNTF \end #1 { + \_@@_check_end:n + }{ + \_@@_do:w + } + } + } + } + } +} + +\cs_new_protected:Nn \_@@_check_begin:n { + \seq_if_in:NxTF \g_stex_smsmode_allowedenvs_seq { \detokenize{#1} }{ + \begin{#1} + }{ + \_@@_do:w + } +} +\cs_new_protected:Nn \_@@_check_end:n { + \seq_if_in:NxTF \g_stex_smsmode_allowedenvs_seq { \detokenize{#1} }{ + \end{#1}\_@@_do:w + }{ + \str_if_eq:nnTF{#1}{document}{\endinput}{\_@@_do:w} + } +} +% \end{macrocode} +% \end{macro} +% + +% \subsection{Inheritance} +% \begin{macrocode} +%<@@=stex_importmodule> +% \end{macrocode} +% +% \begin{macro}{\stex_import_module_uri:nn} +% \begin{macrocode} +\cs_new_protected:Nn \stex_import_module_uri:nn { + \str_set:Nx \l_stex_import_archive_str { #1 } + \str_set:Nn \l_stex_import_path_str { #2 } + + \exp_args:NNNo \seq_set_split:Nnn \l_tmpb_seq ? { \l_stex_import_path_str } + \seq_pop_right:NN \l_tmpb_seq \l_stex_import_name_str + \str_set:Nx \l_stex_import_path_str { \seq_use:Nn \l_tmpb_seq ? } + + \stex_modules_current_namespace: + \bool_lazy_all:nTF { + {\str_if_empty_p:N \l_stex_import_archive_str} + {\str_if_empty_p:N \l_stex_import_path_str} + {\stex_if_module_exists_p:n { \l_stex_module_ns_str ? \l_stex_import_name_str } } + }{ + \str_set_eq:NN \l_stex_import_path_str \l_stex_modules_subpath_str + \str_set_eq:NN \l_stex_import_ns_str \l_stex_module_ns_str + }{ + \str_if_empty:NT \l_stex_import_archive_str { + \prop_if_exist:NT \l_stex_current_repository_prop { + \prop_get:NnN \l_stex_current_repository_prop { id } \l_stex_import_archive_str + } + } + \str_if_empty:NTF \l_stex_import_archive_str { + \str_if_empty:NF \l_stex_import_path_str { + \str_set:Nx \l_stex_import_ns_str { + \l_stex_module_ns_str / \l_stex_import_path_str + } + } + }{ + \stex_require_repository:n \l_stex_import_archive_str + \prop_get:cnN { c_stex_mathhub_\l_stex_import_archive_str _manifest_prop } { ns } + \l_stex_import_ns_str + \str_if_empty:NF \l_stex_import_path_str { + \str_set:Nx \l_stex_import_ns_str { + \l_stex_import_ns_str / \l_stex_import_path_str + } + } + } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{ +% \l_stex_import_name_str,\l_stex_import_archive_str,\l_stex_import_path_str,\l_stex_import_ns_str +% } +% Store the return values of \cs{stex_import_module_uri:nn}. +% \begin{macrocode} +\str_new:N \l_stex_import_name_str +\str_new:N \l_stex_import_archive_str +\str_new:N \l_stex_import_path_str +\str_new:N \l_stex_import_ns_str +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\stex_import_require_module:nnnn} +% \begin{syntax} \Arg{ns} \Arg{archive-ID} \Arg{path} \Arg{name} \end{syntax} +% \begin{macrocode} +\cs_new_protected:Nn \stex_import_require_module:nnnn { + \exp_args:Nx \stex_if_module_exists:nF { #1 ? #4 } { + + % archive + \str_set:Nx \l_tmpa_str { #2 } + \str_if_empty:NTF \l_tmpa_str { + \seq_set_eq:NN \l_tmpa_seq \g_stex_currentfile_seq + } { + \stex_path_from_string:Nn \l_tmpb_seq { \l_tmpa_str } + \seq_concat:NNN \l_tmpa_seq \c_stex_mathhub_seq \l_tmpb_seq + \seq_put_right:Nn \l_tmpa_seq { source } + } + + % path + \str_set:Nx \l_tmpb_str { #3 } + \str_if_empty:NTF \l_tmpb_str { + \str_set:Nx \l_tmpa_str { \stex_path_to_string:N \l_tmpa_seq / #4 } + + \ltx@ifpackageloaded{babel} { + \exp_args:NNx \prop_get:NnNF \c_stex_language_abbrevs_prop + { \languagename } \l_tmpb_str { + \msg_error:nnx{stex}{error/unknownlanguage}{\languagename} + } + } { + \str_clear:N \l_tmpb_str + } + + \stex_debug:nn{modules}{Checking~\l_tmpa_str.\l_tmpb_str.tex} + \IfFileExists{ \l_tmpa_str.\l_tmpb_str.tex }{ + \str_gset:Nx \g_@@_file_str { \l_tmpa_str.\l_tmpb_str.tex } + }{ + \stex_debug:nn{modules}{Checking~\l_tmpa_str.tex} + \IfFileExists{ \l_tmpa_str.tex }{ + \str_gset:Nx \g_@@_file_str { \l_tmpa_str.tex } + }{ + % try english as default + \stex_debug:nn{modules}{Checking~\l_tmpa_str.en.tex} + \IfFileExists{ \l_tmpa_str.en.tex }{ + \str_gset:Nx \g_@@_file_str { \l_tmpa_str.en.tex } + }{ + \msg_error:nnx{stex}{error/unknownmodule}{#1?#4} + } + } + } + + } { + \seq_set_split:NnV \l_tmpb_seq / \l_tmpb_str + \seq_concat:NNN \l_tmpa_seq \l_tmpa_seq \l_tmpb_seq + + \ltx@ifpackageloaded{babel} { + \exp_args:NNx \prop_get:NnNF \c_stex_language_abbrevs_prop + { \languagename } \l_tmpb_str { + \msg_error:nnx{stex}{error/unknownlanguage}{\languagename} + } + } { + \str_clear:N \l_tmpb_str + } + + \stex_path_to_string:NN \l_tmpa_seq \l_tmpa_str + + \stex_debug:nn{modules}{Checking~\l_tmpa_str/#4.\l_tmpb_str.tex} + \IfFileExists{ \l_tmpa_str/#4.\l_tmpb_str.tex }{ + \str_gset:Nx \g_@@_file_str { \l_tmpa_str/#4.\l_tmpb_str.tex } + }{ + \stex_debug:nn{modules}{Checking~\l_tmpa_str/#4.tex} + \IfFileExists{ \l_tmpa_str/#4.tex }{ + \str_gset:Nx \g_@@_file_str { \l_tmpa_str/#4.tex } + }{ + % try english as default + \stex_debug:nn{modules}{Checking~\l_tmpa_str/#4.en.tex} + \IfFileExists{ \l_tmpa_str/#4.en.tex }{ + \str_gset:Nx \g_@@_file_str { \l_tmpa_str/#4.en.tex } + }{ + \stex_debug:nn{modules}{Checking~\l_tmpa_str.\l_tmpb_str.tex} + \IfFileExists{ \l_tmpa_str.\l_tmpb_str.tex }{ + \str_gset:Nx \g_@@_file_str { \l_tmpa_str.\l_tmpb_str.tex } + }{ + \stex_debug:nn{modules}{Checking~\l_tmpa_str.tex} + \IfFileExists{ \l_tmpa_str.tex }{ + \str_gset:Nx \g_@@_file_str { \l_tmpa_str.tex } + }{ + % try english as default + \stex_debug:nn{modules}{Checking~\l_tmpa_str.en.tex} + \IfFileExists{ \l_tmpa_str.en.tex }{ + \str_gset:Nx \g_@@_file_str { \l_tmpa_str.en.tex } + }{ + \msg_error:nnx{stex}{error/unknownmodule}{#1?#4} + } + } + } + } + } + } + } + + \exp_args:No \stex_file_in_smsmode:nn { \g_@@_file_str } { + \seq_clear:N \l_stex_all_modules_seq + \str_clear:N \l_stex_current_module_str + \str_set:Nx \l_tmpb_str { #2 } + \str_if_empty:NF \l_tmpb_str { + \stex_set_current_repository:n { #2 } + } + \stex_debug:nn{modules}{Loading~\g_@@_file_str} + } + + \stex_if_module_exists:nF { #1 ? #4 } { + \msg_error:nnx{stex}{error/unknownmodule}{ + #1?#4~(in~file~\g_@@_file_str) + } + } + } + \stex_activate_module:n { #1 ? #4 } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\importmodule} +% \begin{macrocode} +\NewDocumentCommand \importmodule { O{} m } { + \stex_import_module_uri:nn { #1 } { #2 } + \stex_debug:nn{modules}{Importing~module:~ + \l_stex_import_ns_str ? \l_stex_import_name_str + } + \stex_if_smsmode:F { + \stex_import_require_module:nnnn + { \l_stex_import_ns_str } { \l_stex_import_archive_str } + { \l_stex_import_path_str } { \l_stex_import_name_str } + \stex_annotate_invisible:nnn + {import} {\l_stex_import_ns_str ? \l_stex_import_name_str} {} + } + \exp_args:Nx \stex_add_to_current_module:n { + \stex_import_require_module:nnnn + { \l_stex_import_ns_str } { \l_stex_import_archive_str } + { \l_stex_import_path_str } { \l_stex_import_name_str } + } + \exp_args:Nx \stex_add_import_to_current_module:n { + \l_stex_import_ns_str ? \l_stex_import_name_str + } + \stex_smsmode_do: + \ignorespacesandpars +} +\stex_deactivate_macro:Nn \importmodule {module~environments} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\usemodule} +% \begin{macrocode} +\NewDocumentCommand \usemodule { O{} m } { + \stex_if_smsmode:F { + \stex_import_module_uri:nn { #1 } { #2 } + \stex_import_require_module:nnnn + { \l_stex_import_ns_str } { \l_stex_import_archive_str } + { \l_stex_import_path_str } { \l_stex_import_name_str } + \stex_annotate_invisible:nnn + {usemodule} {\l_stex_import_ns_str ? \l_stex_import_name_str} {} + } + \stex_smsmode_do: + \ignorespacesandpars +} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/macros/latex/contrib/stex/source/stex/mathhub.dtx b/macros/latex/contrib/stex/source/stex/mathhub.dtx new file mode 100644 index 0000000000..16ff57ede8 --- /dev/null +++ b/macros/latex/contrib/stex/source/stex/mathhub.dtx @@ -0,0 +1,916 @@ +% \iffalse meta-comment +% An Infrastructure for Semantic Macros and Module Scoping +% Copyright (c) 2019 Michael Kohlhase, all rights reserved +% this file is released under the +% LaTeX Project Public License (LPPL) +% +% The original of this file is in the public repository at +% http://github.com/sLaTeX/sTeX/ +% +% TODO update copyright +% +%<*driver> +\providecommand\bibfolder{../../lib/bib} +\input{../../doc/docheader} + +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{ \sTeX-MathHub +% \thanks{Version {\fileversion} (last revised {\filedate})} +% } +% +% \author{Michael Kohlhase, Dennis Müller\\ +% FAU Erlangen-Nürnberg\\ +% \url{http://kwarc.info/} +% } +% +% \maketitle +% +%\ifinfulldoc\else +% This is the documentation for the \pkg{stex-mathhub} package. +% For a more high-level introduction, +% see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the +% \href{\basedocurl/stex.pdf}{full \sTeX documentation}. +% \fi +% +% +% \begin{documentation}\label{pkg:mathhub:doc} +% +% This sub package provides code for handling \sTeX archives, +% files, file paths and related methods. +% +% \ifinfulldoc\else +% \begin{sfragment}{Manual}\input{../../doc/packages/mathhub}\end{sfragment} +% \fi +% +% \section{Macros and Environments}\label{pkg:mathhub:doc:macros} +% +% \begin{function}{\stex_kpsewhich:n} +% |\stex_kpsewhich:n| executes kpsewhich and stores the return +% in\\ |\l_stex_kpsewhich_return_str|. This does not require +% shell escaping. +% \end{function} +% +% \subsection{Files, Paths, URIs} +% +% \begin{function}{\stex_path_from_string:Nn} +% +% \begin{syntax} \cs{stex_path_from_string:Nn} \meta{path-variable} \Arg{string} \end{syntax} +% turns the \meta{string} into a path by splitting it at |/|-characters +% and stores the result in \meta{path-variable}. Also applies +% \cs{stex_path_canonicalize:N}. +% \end{function} +% +% \begin{function}{\stex_path_to_string:NN, \stex_path_to_string:N} +% The inverse; turns a path into a string and stores it in the second +% argument variable, or leaves it in the input stream. +% \end{function} +% +% \begin{function}{\stex_path_canonicalize:N} +% Canonicalizes the path provided; in particular, resolves |.| and |..| +% path segments. +% \end{function} +% +% \begin{function}[pTF]{\stex_path_if_absolute:N} +% Checks whether the path provided is \emph{absolute}, i.e. starts +% with an empty segment +% \end{function} +% +% \begin{variable}{\c_stex_pwd_seq, \c_stex_pwd_str, \c_stex_mainfile_seq, \c_stex_mainfile_str} +% Store the current working directory as path-sequence and string, +% respectively, and the (heuristically guessed) full path to the +% main file, based on the PWD and |\jobname|. +% \end{variable} +% +% \begin{variable}{\g_stex_currentfile_seq} +% The file being currently processed (respecting |\input| etc.) +% \end{variable} +% +% \begin{function}{\stex_filestack_push:n,\stex_filestack_pop:} +% Push and pop (repsectively) a file path to the file stack, +% to keep track of the current file. Are called in hooks |file/before| +% and |file/after|, respectively. +% \end{function} +% +% \subsection{MathHub Archives} +% +% \begin{variable}{\mathhub, \c_stex_mathhub_seq, \c_stex_mathhub_str} +% We determine the path to the local MathHub folder via one of +% three means, in order of precedence: +% \begin{enumerate} +% \item The |mathhub| package option, or +% \item the |\mathhub|-macro, if it has been defined before +% the |\usepackage{stex}|-statement, or +% \item the |MATHHUB| system variable. +% \end{enumerate} +% In all three cases, \cs{c_stex_mathhub_seq} and +% \cs{c_stex_mathhub_str} are set accordingly. +% \end{variable} +% +% \begin{variable}{\l_stex_current_repository_prop} +% Always points to the \emph{current} MathHub repository (if +% we currently are in one). Has the following fields corresponding +% to the entries in the |MANIFEST.MF|-file: +% \begin{itemize} +% \item[|id|:] The name of the archive, including its group (e.g. |smglom/calculus|), +% \item[|ns|:] The content namespace (for modules and symbols), +% \item[|narr|:] the narration namespace (for document references), +% \item[|docurl|:] The URL that is used as a basis for \emph{external references}, +% \item[|deps|:] All archives that this archive depends on (currently not in use). +% \end{itemize} +% \end{variable} +% +% \begin{function}{\stex_set_current_repository:n} +% Sets the current repository to the one with the provided ID. +% calls \cs{__stex_mathhub_do_manifest:n}, so works whether this +% repository's |MANIFEST.MF|-file has already been read or not. +% \end{function} +% +% \begin{function}{\stex_require_repository:n} +% Calls \cs{__stex_mathhub_do_manifest:n} iff the corresponding +% archive property list does not already exist, and +% adds a corresponding definition to the |.sms|-file. +% \end{function} +% +% \begin{function}{\stex_in_repository:nn} +% \begin{syntax}\cs{stex_in_repository:nn}\Arg{repository-name}\Arg{code}\end{syntax} +% Change the current repository to \Arg{repository-name} (or not, if \Arg{repository-name} is +% empty), and passes its ID on to \Arg{code} as |#1|. Switches back +% to the previous repository after executing \Arg{code}. +% \end{function} +% +% \subsection{Using Content in Archives} +% +% \begin{function}[EXP]{\mhpath} +% \begin{syntax}\cs{mhpath}\Arg{archive-ID}\Arg{filename}\end{syntax} +% Expands to the full path of file \meta{filename} in repository \meta{archive-ID}. +% Does not check whether the file or the repository exist. +% \end{function} +% +% \begin{function}{\inputref,\mhinput} +% \begin{syntax}\cs{inputref}|[|\meta{archive-ID}|]|\Arg{filename}\end{syntax} +% Both \cs{input} the file \meta{filename} in archive \meta{archive-ID} (relative +% to the |source|-subdirectory). \cs{mhinput} does so directly. +% \cs{inputref} does so within an |\begingroup|...|\endgroup|-block, +% and skips it in |html|-mode, inserting a \emph{reference} to the +% file instead. +% +% Both also set |\ifinputref| to true. +% \end{function} +% +% \begin{function}{\addmhbibresource} +% \begin{syntax}\cs{inputref}|[|\meta{archive-ID}|]|\Arg{filename}\end{syntax} +% Adds a |.bib|-file \meta{filename} in archive \meta{archive-ID} (relative +% to the top-directory of the archive!). +% \end{function} +% +% \begin{function}{\libinput} +% \begin{syntax} \cs{libinput}\Arg{filename} \end{syntax} +% Inputs \meta{filename}|.tex| from the |lib| folders in the +% current archive and the |meta-inf|-archive of the current archive group(s) +% (if existent) in descending order. Throws an error if no file by that name exists in +% any of the relevant |lib|-folders. +% \end{function} +% +% \begin{function}{\libusepackage} +% \begin{syntax} \cs{libusepackage}[\meta{args}]\Arg{filename} \end{syntax} +% Like \cs{libinput}, but looks for |.sty|-files and calls +% |\usepackage[\meta{args}]\Arg{filename}| instead of \cs{input}. +% +% Throws an error, if none or more than one suitable package file is found. +% \end{function} +% +% \begin{function}{\mhgraphics,\cmhgraphics} +% \emph{If} the \pkg{graphicx} package is loaded, these +% macros are defined at |\begin{document}|. +% +% \cs{mhgraphics} takes the same arguments as \cs{includegraphics}, +% with the additional optional key |mhrepos|. It then resolves +% the file path in |\mhgraphics[mhrepos=Foo/Bar]{foo/bar.png}| +% relative to the |source|-folder of the |Foo/Bar|-archive. +% +% \cs{cmhgraphics} additional wraps the image in a |center|-environment. +% \end{function} +% +% \begin{function}{\lstinputmhlisting,\clstinputmhlisting} +% Like \cs{mhgraphics}, but only defined if the \pkg{listings}-package +% is loaded, and with \cs{lstinputlisting} instead of \cs{includegraphics}. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\sTeX-MathHub Implementation}\label{pkg:mathhub:doc:impl} +% +% \begin{macrocode} +%<*package> + +%%%%%%%%%%%%% mathhub.dtx %%%%%%%%%%%%% + +%<@@=stex_path> +% \end{macrocode} +% +% Warnings and error messages +% +% \begin{macrocode} +\msg_new:nnn{stex}{error/norepository}{ + No~archive~#1~found~in~#2 +} +\msg_new:nnn{stex}{error/notinarchive}{ + Not~currently~in~an~archive,~but~\detokenize{#1}~ + needs~one! +} +\msg_new:nnn{stex}{error/nofile}{ + \detokenize{#1}~could~not~find~file~#2 +} +\msg_new:nnn{stex}{error/twofiles}{ + \detokenize{#1}~found~two~candidates~for~#2 +} +% \end{macrocode} +% +% \subsubsection{Generic Path Handling} +% +% We treat paths as \LaTeX3-sequences (of the individual +% path segments, i.e. separated by a /-character) unix-style; +% i.e. a path is absolute if the sequence starts with an empty +% entry. +% +% \begin{macro}{\stex_path_from_string:Nn} +% \begin{macrocode} +\cs_new_protected:Nn \stex_path_from_string:Nn { + \str_set:Nx \l_tmpa_str { #2 } + \str_if_empty:NTF \l_tmpa_str { + \seq_clear:N #1 + }{ + \exp_args:NNNo \seq_set_split:Nnn #1 / { \l_tmpa_str } + \sys_if_platform_windows:T{ + \seq_clear:N \l_tmpa_tl + \seq_map_inline:Nn #1 { + \seq_set_split:Nnn \l_tmpb_tl \c_backslash_str { ##1 } + \seq_concat:NNN \l_tmpa_tl \l_tmpa_tl \l_tmpb_tl + } + \seq_set_eq:NN #1 \l_tmpa_tl + } + \stex_path_canonicalize:N #1 + } +} + +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stex_path_to_string:NN,\stex_path_to_string:N} +% \begin{macrocode} +\cs_new_protected:Nn \stex_path_to_string:NN { + \exp_args:NNe \str_set:Nn #2 { \seq_use:Nn #1 / } +} + +\cs_new:Nn \stex_path_to_string:N { + \seq_use:Nn #1 / +} +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\c_@@_dot_str,\c_@@_up_str} +% +% |.| and |..|, respectively. +% +% \begin{macrocode} +\str_const:Nn \c_@@_dot_str {.} +\str_const:Nn \c_@@_up_str {..} +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\stex_path_canonicalize:N} +% +% Canonicalizes the path provided; in particular, resolves |.| and |..| +% path segments. +% +% \begin{macrocode} +\cs_new_protected:Nn \stex_path_canonicalize:N { + \seq_if_empty:NF #1 { + \seq_clear:N \l_tmpa_seq + \seq_get_left:NN #1 \l_tmpa_tl + \str_if_empty:NT \l_tmpa_tl { + \seq_put_right:Nn \l_tmpa_seq {} + } + \seq_map_inline:Nn #1 { + \str_set:Nn \l_tmpa_tl { ##1 } + \str_if_eq:NNF \l_tmpa_tl \c_@@_dot_str { + \str_if_eq:NNTF \l_tmpa_tl \c_@@_up_str { + \seq_if_empty:NTF \l_tmpa_seq { + \exp_args:NNo \seq_put_right:Nn \l_tmpa_seq { + \c_@@_up_str + } + }{ + \seq_get_right:NN \l_tmpa_seq \l_tmpa_tl + \str_if_eq:NNTF \l_tmpa_tl \c_@@_up_str { + \exp_args:NNo \seq_put_right:Nn \l_tmpa_seq { + \c_@@_up_str + } + }{ + \seq_pop_right:NN \l_tmpa_seq \l_tmpb_tl + } + } + }{ + \str_if_empty:NF \l_tmpa_tl { + \exp_args:NNo \seq_put_right:Nn \l_tmpa_seq { \l_tmpa_tl } + } + } + } + } + \seq_gset_eq:NN #1 \l_tmpa_seq + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\stex_path_if_absolute:N} +% \begin{macrocode} +\prg_new_conditional:Nnn \stex_path_if_absolute:N {p, T, F, TF} { + \seq_if_empty:NTF #1 { + \prg_return_false: + }{ + \seq_get_left:NN #1 \l_tmpa_tl + \sys_if_platform_windows:TF{ + \str_if_in:NnTF \l_tmpa_tl {:}{ + \prg_return_true: + }{ + \prg_return_false: + } + }{ + \str_if_empty:NTF \l_tmpa_tl { + \prg_return_true: + }{ + \prg_return_false: + } + } + } +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{PWD and kpsewhich} +% +% \begin{macro}{\stex_kpsewhich:n} +% \begin{macrocode} +\str_new:N\l_stex_kpsewhich_return_str +\cs_new_protected:Nn \stex_kpsewhich:n { + \sys_get_shell:nnN { kpsewhich ~ #1 } { } \l_tmpa_tl + \exp_args:NNo\str_set:Nn\l_stex_kpsewhich_return_str{\l_tmpa_tl} + \tl_trim_spaces:N \l_stex_kpsewhich_return_str +} +% \end{macrocode} +% \end{macro} +% +% We determine the PWD +% +% \begin{variable}{\c_stex_pwd_seq,\c_stex_pwd_str} +% \begin{macrocode} +\sys_if_platform_windows:TF{ + \begingroup\escapechar=-1\catcode`\\=12 + \exp_args:Nx\stex_kpsewhich:n{-expand-var~\c_percent_str CD\c_percent_str} + \exp_args:NNx\str_replace_all:Nnn\l_stex_kpsewhich_return_str{\c_backslash_str}/ + \exp_args:Nnx\use:nn{\endgroup}{\str_set:Nn\exp_not:N\l_stex_kpsewhich_return_str{\l_stex_kpsewhich_return_str}} +}{ + \stex_kpsewhich:n{-var-value~PWD} +} + +\stex_path_from_string:Nn\c_stex_pwd_seq\l_stex_kpsewhich_return_str +\stex_path_to_string:NN\c_stex_pwd_seq\c_stex_pwd_str +\stex_debug:nn {mathhub} {PWD:~\str_use:N\c_stex_pwd_str} +% \end{macrocode} +% \end{variable} +% +% \subsubsection{File Hooks and Tracking} +% \begin{macrocode} +%<@@=stex_files> +% \end{macrocode} +% +% We introduce hooks for file inputs that keep track of the +% absolute paths of files used. This will be useful to keep track +% of modules, their archives, namespaces etc. +% +% Note that the absolute paths are only accurate in |\input|-statements +% for paths relative to the PWD, so they shouldn't be relied upon +% in any other setting than for \sTeX-purposes. +% +% \begin{variable}{\g_@@_stack} +% +% keeps track of file changes +% +% \begin{macrocode} +\seq_gclear_new:N\g_@@_stack +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_stex_mainfile_seq, \c_stex_mainfile_str} +% \begin{macrocode} +\str_set:Nx \c_stex_mainfile_str {\c_stex_pwd_str/\jobname.tex} +\stex_path_from_string:Nn \c_stex_mainfile_seq + \c_stex_mainfile_str +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\g_stex_currentfile_seq} +% \begin{macrocode} +\seq_gclear_new:N\g_stex_currentfile_seq +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\stex_filestack_push:n} +% \begin{macrocode} +\cs_new_protected:Nn \stex_filestack_push:n { + \stex_path_from_string:Nn\g_stex_currentfile_seq{#1} + \stex_path_if_absolute:NF\g_stex_currentfile_seq{ + \stex_path_from_string:Nn\g_stex_currentfile_seq{ + \c_stex_pwd_str/#1 + } + } + \seq_gset_eq:NN\g_stex_currentfile_seq\g_stex_currentfile_seq + \exp_args:NNo\seq_gpush:Nn\g_@@_stack\g_stex_currentfile_seq +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stex_filestack_pop:} +% \begin{macrocode} +\cs_new_protected:Nn \stex_filestack_pop: { + \seq_if_empty:NF\g_@@_stack{ + \seq_gpop:NN\g_@@_stack\l_tmpa_seq + } + \seq_if_empty:NTF\g_@@_stack{ + \seq_gset_eq:NN\g_stex_currentfile_seq\c_stex_mainfile_seq + }{ + \seq_get:NN\g_@@_stack\l_tmpa_seq + \seq_gset_eq:NN\g_stex_currentfile_seq\l_tmpa_seq + } +} +% \end{macrocode} +% \end{macro} +% +% Hooks for the current file: +% +% \begin{macrocode} +\AddToHook{file/before}{ + \stex_filestack_push:n{\CurrentFilePath/\CurrentFile} +} +\AddToHook{file/after}{ + \stex_filestack_pop: +} +% \end{macrocode} +% +% \subsection{MathHub Repositories} +% \begin{macrocode} +%<@@=stex_mathhub> +% \end{macrocode} +% +% \begin{variable}{\mathhub, \c_stex_mathhub_seq, \c_stex_mathhub_str} +% The path to the mathhub directory. If the \cs{mathhub}-macro is not set, +% we query |kpsewhich| for the |MATHHUB| system variable. +% \begin{macrocode} +\str_if_empty:NTF\mathhub{ + \sys_if_platform_windows:TF{ + \begingroup\escapechar=-1\catcode`\\=12 + \exp_args:Nx\stex_kpsewhich:n{-expand-var~\c_percent_str MATHHUB\c_percent_str} + \exp_args:NNx\str_replace_all:Nnn\l_stex_kpsewhich_return_str{\c_backslash_str}/ + \exp_args:Nnx\use:nn{\endgroup}{\str_set:Nn\exp_not:N\l_stex_kpsewhich_return_str{\l_stex_kpsewhich_return_str}} + }{ + \stex_kpsewhich:n{-var-value~MATHHUB} + } + \str_set_eq:NN\c_stex_mathhub_str\l_stex_kpsewhich_return_str + + \str_if_empty:NTF\c_stex_mathhub_str{ + \msg_warning:nn{stex}{warning/nomathhub} + }{ + \stex_debug:nn{mathhub}{MathHub:~\str_use:N\c_stex_mathhub_str} + \exp_args:NNo \stex_path_from_string:Nn\c_stex_mathhub_seq\c_stex_mathhub_str + } +}{ + \stex_path_from_string:Nn \c_stex_mathhub_seq \mathhub + \stex_path_if_absolute:NF \c_stex_mathhub_seq { + \exp_args:NNx \stex_path_from_string:Nn \c_stex_mathhub_seq { + \c_stex_pwd_str/\mathhub + } + } + \stex_path_to_string:NN\c_stex_mathhub_seq\c_stex_mathhub_str + \stex_debug:nn{mathhub} {MathHub:~\str_use:N\c_stex_mathhub_str} +} +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\_@@_do_manifest:n} +% Checks whether the manifest for archive |#1| already exists, and +% if not, finds and parses the corresponding manifest file +% \begin{macrocode} +\cs_new_protected:Nn \_@@_do_manifest:n { + \prop_if_exist:cF {c_stex_mathhub_#1_manifest_prop} { + \str_set:Nx \l_tmpa_str { #1 } + \prop_new:c { c_stex_mathhub_#1_manifest_prop } + \seq_set_split:NnV \l_tmpa_seq / \l_tmpa_str + \seq_concat:NNN \l_tmpa_seq \c_stex_mathhub_seq \l_tmpa_seq + \_@@_find_manifest:N \l_tmpa_seq + \seq_if_empty:NTF \l_@@_manifest_file_seq { + \msg_error:nnxx{stex}{error/norepository}{#1}{ + \stex_path_to_string:N \c_stex_mathhub_str + } + } { + \exp_args:No \_@@_parse_manifest:n { \l_tmpa_str } + } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\l_@@_manifest_file_seq} +% \begin{macrocode} +\seq_new:N\l_@@_manifest_file_seq +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\_@@_find_manifest:N} +% +% Attempts to find the |MANIFEST.MF| in some file path and +% stores its path in \cs{l_@@_manifest_file_seq}: +% +% \begin{macrocode} +\cs_new_protected:Nn \_@@_find_manifest:N { + \seq_set_eq:NN\l_tmpa_seq #1 + \bool_set_true:N\l_tmpa_bool + \bool_while_do:Nn \l_tmpa_bool { + \seq_if_empty:NTF \l_tmpa_seq { + \bool_set_false:N\l_tmpa_bool + }{ + \file_if_exist:nTF{ + \stex_path_to_string:N\l_tmpa_seq/MANIFEST.MF + }{ + \seq_put_right:Nn\l_tmpa_seq{MANIFEST.MF} + \bool_set_false:N\l_tmpa_bool + }{ + \file_if_exist:nTF{ + \stex_path_to_string:N\l_tmpa_seq/META-INF/MANIFEST.MF + }{ + \seq_put_right:Nn\l_tmpa_seq{META-INF} + \seq_put_right:Nn\l_tmpa_seq{MANIFEST.MF} + \bool_set_false:N\l_tmpa_bool + }{ + \file_if_exist:nTF{ + \stex_path_to_string:N\l_tmpa_seq/meta-inf/MANIFEST.MF + }{ + \seq_put_right:Nn\l_tmpa_seq{meta-inf} + \seq_put_right:Nn\l_tmpa_seq{MANIFEST.MF} + \bool_set_false:N\l_tmpa_bool + }{ + \seq_pop_right:NN\l_tmpa_seq\l_tmpa_tl + } + } + } + } + } + \seq_set_eq:NN\l_@@_manifest_file_seq\l_tmpa_seq +} +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\c_@@_manifest_ior} +% +% File variable used for |MANIFEST|-files +% +% \begin{macrocode} +\ior_new:N \c_@@_manifest_ior +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\_@@_parse_manifest:n} +% +% Stores the entries in manifest file in the +% corresponding property list: +% +% \begin{macrocode} +\cs_new_protected:Nn \_@@_parse_manifest:n { + \seq_set_eq:NN \l_tmpa_seq \l_@@_manifest_file_seq + \ior_open:Nn \c_@@_manifest_ior {\stex_path_to_string:N \l_tmpa_seq} + \ior_map_inline:Nn \c_@@_manifest_ior { + \str_set:Nn \l_tmpa_str {##1} + \exp_args:NNoo \seq_set_split:Nnn + \l_tmpb_seq \c_colon_str \l_tmpa_str + \seq_pop_left:NNTF \l_tmpb_seq \l_tmpa_tl { + \exp_args:NNe \str_set:Nn \l_tmpb_tl { + \exp_args:NNo \seq_use:Nn \l_tmpb_seq \c_colon_str + } + \exp_args:No \str_case:nnTF \l_tmpa_tl { + {id} { + \prop_gput:cno { c_stex_mathhub_#1_manifest_prop } + { id } \l_tmpb_tl + } + {narration-base} { + \prop_gput:cno { c_stex_mathhub_#1_manifest_prop } + { narr } \l_tmpb_tl + } + {url-base} { + \prop_gput:cno { c_stex_mathhub_#1_manifest_prop } + { docurl } \l_tmpb_tl + } + {source-base} { + \prop_gput:cno { c_stex_mathhub_#1_manifest_prop } + { ns } \l_tmpb_tl + } + {ns} { + \prop_gput:cno { c_stex_mathhub_#1_manifest_prop } + { ns } \l_tmpb_tl + } + {dependencies} { + \prop_gput:cno { c_stex_mathhub_#1_manifest_prop } + { deps } \l_tmpb_tl + } + }{}{} + }{} + } + \ior_close:N \c_@@_manifest_ior +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\stex_set_current_repository:n} +% \begin{macrocode} +\cs_new_protected:Nn \stex_set_current_repository:n { + \stex_require_repository:n { #1 } + \prop_set_eq:Nc \l_stex_current_repository_prop { + c_stex_mathhub_#1_manifest_prop + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stex_require_repository:n} +% \begin{macrocode} +\cs_new_protected:Nn \stex_require_repository:n { + \prop_if_exist:cF { c_stex_mathhub_#1_manifest_prop } { + \stex_debug:nn{mathhub}{Opening~archive:~#1} + \_@@_do_manifest:n { #1 } + } +} +% \end{macrocode} +% \end{macro} +% +%\begin{variable}{\l_stex_current_repository_prop} +% +% Current MathHub repository +% +% \begin{macrocode} +%\prop_new:N \l_stex_current_repository_prop + +\_@@_find_manifest:N \c_stex_pwd_seq +\seq_if_empty:NTF \l_@@_manifest_file_seq { + \stex_debug:nn{mathhub}{Not~currently~in~a~MathHub~repository} +} { + \_@@_parse_manifest:n { main } + \prop_get:NnN \c_stex_mathhub_main_manifest_prop {id} + \l_tmpa_str + \prop_set_eq:cN { c_stex_mathhub_\l_tmpa_str _manifest_prop } + \c_stex_mathhub_main_manifest_prop + \exp_args:Nx \stex_set_current_repository:n { \l_tmpa_str } + \stex_debug:nn{mathhub}{Current~repository:~ + \prop_item:Nn \l_stex_current_repository_prop {id} + } +} +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\stex_in_repository:nn} +% Executes the code in the second argument in the context +% of the repository whose ID is provided as the first argument. +% \begin{macrocode} +\cs_new_protected:Nn \stex_in_repository:nn { + \str_set:Nx \l_tmpa_str { #1 } + \cs_set:Npn \l_tmpa_cs ##1 { #2 } + \str_if_empty:NTF \l_tmpa_str { + \prop_if_exist:NTF \l_stex_current_repository_prop { + \stex_debug:nn{mathhub}{do~in~current~repository:~\prop_item:Nn \l_stex_current_repository_prop { id }} + \exp_args:Ne \l_tmpa_cs{ + \prop_item:Nn \l_stex_current_repository_prop { id } + } + }{ + \l_tmpa_cs{} + } + }{ + \stex_debug:nn{mathhub}{in~repository:~\l_tmpa_str} + \stex_require_repository:n \l_tmpa_str + \str_set:Nx \l_tmpa_str { #1 } + \exp_args:Nne \use:nn { + \stex_set_current_repository:n \l_tmpa_str + \exp_args:Nx \l_tmpa_cs{\l_tmpa_str} + }{ + \stex_debug:nn{mathhub}{switching~back~to:~ + \prop_if_exist:NTF \l_stex_current_repository_prop { + \prop_item:Nn \l_stex_current_repository_prop { id }:~ + \meaning\l_stex_current_repository_prop + }{ + no~repository + } + } + \prop_if_exist:NTF \l_stex_current_repository_prop { + \stex_set_current_repository:n { + \prop_item:Nn \l_stex_current_repository_prop { id } + } + }{ + \let\exp_not:N\l_stex_current_repository_prop\exp_not:N\undefined + } + } + } +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Using Content in Archives} +% +% \begin{macro}{\mhpath} +% \begin{macrocode} +\def \mhpath #1 #2 { + \exp_args:Ne \tl_if_empty:nTF{#1}{ + \c_stex_mathhub_str / + \prop_item:Nn \l_stex_current_repository_prop { id } + / source / #2 + }{ + \c_stex_mathhub_str / #1 / source / #2 + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\inputref,\mhinput} +% \begin{macrocode} +\newif \ifinputref \inputreffalse + +\cs_new_protected:Nn \_@@_mhinput:nn { + \stex_in_repository:nn {#1} { + \ifinputref + \input{ \c_stex_mathhub_str / ##1 / source / #2 } + \else + \inputreftrue + \input{ \c_stex_mathhub_str / ##1 / source / #2 } + \inputreffalse + \fi + } +} +\NewDocumentCommand \mhinput { O{} m}{ + \stex_mhinput:nn{ #1 }{ #2 } +} + +\cs_new_protected:Nn \_@@_inputref:nn { + \stex_in_repository:nn {#1} { + \bool_lazy_any:nTF { + {\rustex_if_p:} + {\latexml_if_p:} + } { + \str_clear:N \l_tmpa_str + \prop_get:NnNF \l_stex_current_repository_prop { narr } \l_tmpa_str { + \prop_get:NnNF \l_stex_current_repository_prop { ns } \l_tmpa_str {} + } + \stex_annotate_invisible:nnn{inputref}{ + \l_tmpa_str / #2 + }{} + }{ + \begingroup + \inputreftrue + \input{ \c_stex_mathhub_str / ##1 / source / #2 } + \endgroup + } + } +} +\NewDocumentCommand \inputref { O{} m}{ + \_@@_inputref:nn{ #1 }{ #2 } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\addmhbibresource} +% \begin{macrocode} +\cs_new_protected:Nn \_@@_mhbibresource:nn { + \stex_in_repository:nn {#1} { + \addbibresource{ \c_stex_mathhub_str / ##1 / #2 } + } +} +\newcommand\addmhbibresource[2][]{ + \_@@_mhbibresource:nn{ #1 }{ #2 } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\libinput} +% \begin{macrocode} +\cs_new_protected:Npn \libinput #1 { + \prop_if_exist:NF \l_stex_current_repository_prop { + \msg_error:nnn{stex}{error/notinarchive}\libinput + } + \prop_get:NnNF \l_stex_current_repository_prop {id} \l_tmpa_str { + \msg_error:nnn{stex}{error/notinarchive}\libinput + } + \seq_clear:N \l_@@_libinput_files_seq + \seq_set_eq:NN \l_tmpa_seq \c_stex_mathhub_seq + \seq_set_split:NnV \l_tmpb_seq / \l_tmpa_str + + \bool_while_do:nn { ! \seq_if_empty_p:N \l_tmpb_seq }{ + \str_set:Nx \l_tmpa_str {\stex_path_to_string:N \l_tmpa_seq / meta-inf / lib / #1.tex} + \IfFileExists{ \l_tmpa_str }{ + \seq_put_right:No \l_@@_libinput_files_seq \l_tmpa_str + }{} + \seq_pop_left:NN \l_tmpb_seq \l_tmpa_str + \seq_put_right:No \l_tmpa_seq \l_tmpa_str + } + + \str_set:Nx \l_tmpa_str {\stex_path_to_string:N \l_tmpa_seq / lib / #1.tex} + \IfFileExists{ \l_tmpa_str }{ + \seq_put_right:No \l_@@_libinput_files_seq \l_tmpa_str + }{} + + \seq_if_empty:NTF \l_@@_libinput_files_seq { + \msg_error:nnxx{stex}{error/nofile}{\exp_not:N\libinput}{#1.tex} + }{ + \seq_map_inline:Nn \l_@@_libinput_files_seq { + \input{ ##1 } + } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\libusepackage} +% \begin{macrocode} +\NewDocumentCommand \libusepackage {O{} m} { + \prop_if_exist:NF \l_stex_current_repository_prop { + \msg_error:nnn{stex}{error/notinarchive}\libusepackage + } + \prop_get:NnNF \l_stex_current_repository_prop {id} \l_tmpa_str { + \msg_error:nnn{stex}{error/notinarchive}\libusepackage + } + \seq_clear:N \l_@@_libinput_files_seq + \seq_set_eq:NN \l_tmpa_seq \c_stex_mathhub_seq + \seq_set_split:NnV \l_tmpb_seq / \l_tmpa_str + + \bool_while_do:nn { ! \seq_if_empty_p:N \l_tmpb_seq }{ + \str_set:Nx \l_tmpa_str {\stex_path_to_string:N \l_tmpa_seq / meta-inf / lib / #2} + \IfFileExists{ \l_tmpa_str.sty }{ + \seq_put_right:No \l_@@_libinput_files_seq \l_tmpa_str + }{} + \seq_pop_left:NN \l_tmpb_seq \l_tmpa_str + \seq_put_right:No \l_tmpa_seq \l_tmpa_str + } + + \str_set:Nx \l_tmpa_str {\stex_path_to_string:N \l_tmpa_seq / lib / #2} + \IfFileExists{ \l_tmpa_str.sty }{ + \seq_put_right:No \l_@@_libinput_files_seq \l_tmpa_str + }{} + + \seq_if_empty:NTF \l_@@_libinput_files_seq { + \msg_error:nnxx{stex}{error/nofile}{\exp_not:N\libusepackage}{#2.sty} + }{ + \int_compare:nNnTF {\seq_count:N \l_@@_libinput_files_seq} = 1 { + \seq_map_inline:Nn \l_@@_libinput_files_seq { + \usepackage[#1]{ ##1 } + } + }{ + \msg_error:nnxx{stex}{error/twofiles}{\exp_not:N\libusepackage}{#2.sty} + } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\mhgraphics,\cmhgraphics} +% \begin{macrocode} + +\AddToHook{begindocument}{ + \ltx@ifpackageloaded{graphicx}{ + \define@key{Gin}{mhrepos}{\def\Gin@mhrepos{#1}} + \newcommand\mhgraphics[2][]{% + \def\Gin@mhrepos{}\setkeys{Gin}{#1}% + \includegraphics[#1]{\mhpath\Gin@mhrepos{#2}}} + \newcommand\cmhgraphics[2][]{\begin{center}\mhgraphics[#1]{#2}\end{center}} + }{} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\lstinputmhlisting,\clstinputmhlisting} +% \begin{macrocode} + \ltx@ifpackageloaded{listings}{ + \define@key{lst}{mhrepos}{\def\lst@mhrepos{#1}} + \newcommand\lstinputmhlisting[2][]{% + \def\lst@mhrepos{}\setkeys{lst}{#1}% + \lstinputlisting[#1]{\mhpath\lst@mhrepos{#2}}} + \newcommand\clstinputmhlisting[2][]{\begin{center}\lstinputmhlisting[#1]{#2}\end{center}} + }{} +} + +%</package> +% \end{macrocode} +% \end{macro} +% +% \end{implementation} +% +% \PrintIndex diff --git a/macros/latex/contrib/stex/source/stex/metatheory.dtx b/macros/latex/contrib/stex/source/stex/metatheory.dtx new file mode 100644 index 0000000000..a477e67f63 --- /dev/null +++ b/macros/latex/contrib/stex/source/stex/metatheory.dtx @@ -0,0 +1,179 @@ +% \iffalse meta-comment +% An Infrastructure for Semantic Macros and Module Scoping +% Copyright (c) 2019 Michael Kohlhase, all rights reserved +% this file is released under the +% LaTeX Project Public License (LPPL) +% +% The original of this file is in the public repository at +% http://github.com/sLaTeX/sTeX/ +% +% TODO update copyright +% +%<*driver> +\providecommand\bibfolder{../../lib/bib} +\input{../../doc/docheader} + +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{ \sTeX-Metatheory +% \thanks{Version {\fileversion} (last revised {\filedate})} +% } +% +% \author{Michael Kohlhase, Dennis Müller\\ +% FAU Erlangen-Nürnberg\\ +% \url{http://kwarc.info/} +% } +% +% \maketitle +% +%\ifinfulldoc\else +% This is the documentation for the \pkg{stex-metatheory} package. +% For a more high-level introduction, +% see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the +% \href{\basedocurl/stex.pdf}{full \sTeX documentation}. +% +% \input{../../doc/packages/metatheory} +% \fi +% +% \begin{documentation}\label{pkg:metatheory:doc} +% +% The default meta theory for an \sTeX module. Contains +% symbols so ubiquitous, that it is virtually impossible +% to describe any flexiformal content without them, or +% that are required to annotate even the most primitive symbols +% with meaningful (foundation-independent) ``type''-annotations, +% or required for basic structuring principles (theorems, definitions). +% +% Foundations should ideally instantiate these symbols +% with their formal counterparts, e.g. |isa| corresponds +% to a typing operation in typed setting, or the $\in$-operator +% in set-theoretic contexts; |bind| corresponds to a universal +% quantifier in ($n$th-order) logic, or a $\Pi$ in dependent type +% theories. +% +% \section{Symbols}\label{pkg:metatheory:symbols} +% +% \end{documentation} +% +% \begin{implementation}\label{pkg:metatheory:impl} +% +% \section{\sTeX-Metatheory Implementation} +% +% \begin{macrocode} +%<*package> +%<@@=stex_modules> + +%%%%%%%%%%%%% metatheory.dtx %%%%%%%%%%%%% + +\str_const:Nn \c_stex_metatheory_ns_str {http://mathhub.info/sTeX} +\begingroup +\stex_module_setup:nn{ + ns=\c_stex_metatheory_ns_str, + meta=NONE +}{Metatheory} +\stex_reactivate_macro:N \symdecl +\stex_reactivate_macro:N \notation +\stex_reactivate_macro:N \symdef +\ExplSyntaxOff +\csname stex_suppress_html:n\endcsname{ + % is-a (a:A, a \in A, a is an A, etc.) + \symdecl{isa}[args=ai] + \notation{isa}[typed]{#1 \comp{:} #2}{##1 \comp, ##2} + \notation{isa}[in]{#1 \comp\in #2}{##1 \comp, ##2} + \notation{isa}[pred]{#2\comp(#1 \comp)}{##1 \comp, ##2} + + % bind (\forall, \Pi, \lambda etc.) + \symdecl{bind}[args=Bi] + \notation{bind}[forall]{\comp\forall #1.\;#2}{##1 \comp, ##2} + \notation{bind}[Pi]{\comp\prod_{#1}#2}{##1 \comp, ##2} + \notation{bind}[depfun]{\comp( #1 \comp{)\;\to\;} #2}{##1 \comp, ##2} + + % dummy variable + \symdecl{dummyvar} + \notation{dummyvar}[underscore]{\comp\_} + \notation{dummyvar}[dot]{\comp\cdot} + \notation{dummyvar}[dash]{\comp{{\rm --}}} + + %fromto (function space, Hom-set, implication etc.) + \symdecl{fromto}[args=ai] + \notation{fromto}[xarrow]{#1 \comp\to #2}{##1 \comp\times ##2} + \notation{fromto}[arrow]{#1 \comp\to #2}{##1 \comp\to ##2} + + % mapto (lambda etc.) + %\symdecl{mapto}[args=Bi] + %\notation{mapto}[mapsto]{#1 \comp\mapsto #2}{#1 \comp, #2} + %\notation{mapto}[lambda]{\comp\lambda #1 \comp.\; #2}{#1 \comp, #2} + %\notation{mapto}[lambdau]{\comp\lambda_{#1} \comp.\; #2}{#1 \comp, #2} + + % function/operator application + \symdecl{apply}[args=ia] + \notation{apply}[prec=0;0x\infprec,parens]{#1 \comp( #2 \comp)}{##1 \comp, ##2} + \notation{apply}[prec=0;0x\infprec,lambda]{#1 \; #2 }{##1 \; ##2} + + % ``type'' of all collections (sets,classes,types,kinds) + \symdecl{collection} + \notation{collection}[U]{\comp{\mathcal{U}}} + \notation{collection}[set]{\comp{\textsf{Set}}} + + % collection of propositions/booleans/truth values + \symdecl{prop}[name=proposition] + \notation{prop}[prop]{\comp{{\rm prop}}} + \notation{prop}[BOOL]{\comp{{\rm BOOL}}} + + % sequences + \symdecl{seqtype}[args=1] + \notation{seqtype}[kleene]{#1^{\comp\ast}} + + \symdef{sequence-index}[args=2,li,prec=nobrackets]{{#1}_{#2}} + \notation{sequence-index}[ui,prec=nobrackets]{{#1}^{#2}} + + \symdef{aseqdots}[args=a,prec=nobrackets]{#1\comp{,\ellipses}}{##1\comp,##2} + \symdef{aseqfromto}[args=ai,prec=nobrackets]{#1\comp{,\ellipses,}#2}{##1\comp,##2} + \symdef{aseqfromtovia}[args=aii,prec=nobrackets]{#1\comp{,\ellipses,}#2\comp{,\ellipses,}#3}{##1\comp,##2} + + % letin (``let'', local definitions, variable substitution) + \symdecl{letin}[args=bii] + \notation{letin}[let]{\comp{{\rm let}}\;#1\comp{=}#2\;\comp{{\rm in}}\;#3} + \notation{letin}[subst]{#3 \comp[ #1 \comp/ #2 \comp]} + \notation{letin}[frac]{#3 \comp[ \frac{#2}{#1} \comp]} + + % structures + \symdecl*{module-type}[args=1] + \notation{module-type}{\mathtt{MOD} #1} + \symdecl{mathstruct}[name=mathematical-structure,args=a] % TODO + \notation{mathstruct}[angle,prec=nobrackets]{\comp\langle #1 \comp\rangle}{##1 \comp, ##2} + +} + \ExplSyntaxOn + \stex_add_to_current_module:n{ + \let\nappa\apply + \def\nappli#1#2#3#4{\apply{#1}{\naseqli{#2}{#3}{#4}}} + \def\nappui#1#2#3#4{\apply{#1}{\nasequi{#2}{#3}{#4}}} + \def\livar{\csname sequence-index\endcsname[li]} + \def\uivar{\csname sequence-index\endcsname[ui]} + \def\naseqli#1#2#3{\aseqfromto{\livar{#1}{#2}}{\livar{#1}{#3}}} + \def\nasequi#1#2#3{\aseqfromto{\uivar{#1}{#2}}{\uivar{#1}{#3}}} + \def\nappe#1#2#3{\apply{#1}{\aseqfromto{#2}{#3}}} + } +\_@@_end_module: +\endgroup +% \end{macrocode} +% +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex + +% \endinput +% Local Variables: +% mode: doctex +% TeX-master: t +% End: diff --git a/macros/latex/contrib/stex/source/stex/modules.dtx b/macros/latex/contrib/stex/source/stex/modules.dtx new file mode 100644 index 0000000000..f345e3066b --- /dev/null +++ b/macros/latex/contrib/stex/source/stex/modules.dtx @@ -0,0 +1,824 @@ +% \iffalse meta-comment +% An Infrastructure for Semantic Macros and Module Scoping +% Copyright (c) 2019 Michael Kohlhase, all rights reserved +% this file is released under the +% LaTeX Project Public License (LPPL) +% +% The original of this file is in the public repository at +% http://github.com/sLaTeX/sTeX/ +% +% TODO update copyright +% +%<*driver> +\providecommand\bibfolder{../../lib/bib} +\input{../../doc/docheader} + +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{ \sTeX-Modules +% \thanks{Version {\fileversion} (last revised {\filedate})} +% } +% +% \author{Michael Kohlhase, Dennis Müller\\ +% FAU Erlangen-Nürnberg\\ +% \url{http://kwarc.info/} +% } +% +% \maketitle +% +%\ifinfulldoc\else +% This is the documentation for the \pkg{stex-modules} package. +% For a more high-level introduction, +% see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the +% \href{\basedocurl/stex.pdf}{full \sTeX documentation}.\fi +% +% +% \begin{documentation}\label{pkg:modules:doc} +% +% This sub package contains code related to Modules +% +% \ifinfulldoc\else +% \input{../../doc/packages/modules} +% \fi +% +% \section{Macros and Environments}\label{pkg:modules:doc:macros} +% +% The content of a module with uri \meta{<URI>} is stored in four +% macros. All modifications of these macros are global: +% \begin{variable}{\c_stex_module_<URI>_prop} +% A property list with the following fields: +% \begin{itemize} +% \item[|name|] The \emph{name} of the module, +% \item[|ns|] the \emph{namespace} in field |ns|, +% \item[|file|] the \emph{file} containing the module, +% as a sequence of path fragments +% \item[|lang|] the module's \emph{language}, +% \item[|sig|] the language of the signature module, if the +% current file is a translation from some other language, +% \item[|deprecate|] if this module is deprecated, the module +% that replaces it, +% \item[|meta|] the metatheory of the module. +% \end{itemize} +% \end{variable} +% +% \begin{variable}{\c_stex_module_<URI>_code} +% The code to execute when this module is activated (i.e. imported), +% e.g. to set all the semantic macros, notations, etc. +% \end{variable} +% +% \begin{variable}{\c_stex_module_<URI>_constants} +% The names of all constants declared in the module +% \end{variable} +% +% \begin{variable}{\c_stex_module_<URI>_constants} +% The full URIs of all modules imported in this module +% \end{variable} +% +% \begin{variable}{\l_stex_current_module_str} +% \cs{l_stex_current_module_str} always +% contains the URI of the current module (if existent). +% \end{variable} +% +% \begin{variable}{\l_stex_all_modules_seq} +% Stores full URIs for all modules currently in scope. +% \end{variable} +% +% \begin{function}[pTF]{\stex_if_in_module:} +% Conditional for whether we are currently in a module +% \end{function} +% +% \begin{function}[pTF]{\stex_if_module_exists:n} +% Conditional for whether a module with the provided URI +% is already known. +% \end{function} +% +% \begin{function}{\stex_add_to_current_module:n,\STEXexport} +% Adds the provided tokens to the |_code| control sequence of the +% current module. +% +% \cs{stex_add_to_current_module:n} is used internally, +% \cs{STEXexport} is intended for users and additionally executes +% the provided code immediately. +% \end{function} +% +% \begin{function}{\stex_add_constant_to_current_module:n} +% Adds the declaration with the provided name to the |_constants| +% control sequence of the current module. +% \end{function} +% +% \begin{function}{\stex_add_import_to_current_module:n} +% Adds the module with the provided full URI to the |_imports| +% control sequence of the current module. +% \end{function} +% +% \begin{function}{\stex_collect_imports:n} +% Iterates over all imports of the provided (full URI of a) module +% and stores them as a topologically sorted list -- including +% the provided module as the last element -- in +% |\l_stex_collect_imports_seq| +% \end{function} +% +% \begin{function}{\stex_do_up_to_module:n} +% Code that is \emph{exported} from module (such as symbol declarations) +% should be local \emph{to the current module}. For that reason, ideally +% all symbol declarations and similar commands should be called directly +% in the module environment, however, that is not always feasible, e.g. +% in structural features or |sparapraph|s. \cs{stex_do_up_to_module} +% therefore executes the provided code repeatedly in an \cs{aftergroup} +% up until the group level is equal to that of the innermost smodule environment. +% \end{function} +% +% \begin{function}{\stex_modules_current_namespace:} +% Computes the current namespace as follows: +% +% If the current file is |.../source/sub/file.tex| in some archive +% with namespace |http://some.namespace/foo|, then the namespace of +% is |http://some.namespace/foo/sub/file|. Otherwise, the namespace +% is the absolute file path of the current file (i.e. starting with |file:///|). +% +% The result is stored in |\l_stex_modules_ns_str|. Additionally, the sub path +% relative to the current repository is stored in |\l_stex_modules_subpath_str|. +% \end{function} +% +% \subsection{The \texttt{smodule} environment} +% +% \begin{environment}{module} +% \begin{syntax} \cs{begin}|{module}[|\meta{options}|]|\Arg{name}\end{syntax} +% +% Opens a new module with name \meta{name}. Options are: +% \begin{itemize} +% \item[|title|] (\meta{token list}) to display in customizations. +% \item[|type|] (\meta{string}$\ast$) for use in customizations. +% \item[|deprecate|] (\meta{module}) if set, will throw a warning +% when loaded, urging to use \meta{module} instead. +% \item[|id|] (\meta{string}) for cross-referencing. +% \item[|ns|] (\meta{URI}) the namespace to use. \emph{Should not be used, +% unless you know precisely what you're doing}. If not explicitly set, is +% computed using \cs{stex_modules_current_namespace:}. +% \item[|lang|] (\meta{language}) if not set, computed from the current file name (e.g. |foo.en.tex|). +% \item[|sig|] (\meta{language}) if the current file is a translation of a file with the same base name +% but a different language suffix, setting |sig=<lang>| will preload the module +% from that language file. This helps ensuring that the (formal) content of both modules +% is (almost) identical across languages and avoids duplication. +% \item[|creators|] (\meta{string}$\ast$) names of the creators. +% \item[|contributors|] (\meta{string}$\ast$) names of contributors. +% \item[|srccite|] (\meta{string}) a source citation for the content of this module. +% \end{itemize} +% +% \begin{function}{\stex_module_setup:nn} +% \begin{syntax}\cs{stex_module_setup:nn}\Arg{params}\Arg{name}\end{syntax} +% Sets up a new module with name \meta{name} and optional parameters +% \meta{params}. In particular, sets +% \cs{l_stex_current_module_str} appropriately. +% \end{function} +% +% \end{environment} +% +% \begin{function}{\stexpatchmodule} +% \begin{syntax} \cs{stexpatchmodule} [\meta{type}] \Arg{begincode} \Arg{endcode} \end{syntax} +% Customizes the presentation for those |smodule|-environments +% with |type=|\meta{type}, or all others if no \meta{type} is given. +% \end{function} +% +% \begin{function}{\STEXModule} +% \begin{syntax} \cs{STEXModule} \Arg{fragment} \end{syntax} +% Attempts to find a module whose URI ends with \meta{fragment} +% in the current scope and passes the full URI on to +% \cs{stex_invoke_module:n}. +% \end{function} +% +% \begin{function}{\stex_invoke_module:n} +% Invoked by \cs{STEXModule}. Needs to be followed either +% by |!\macro| or |?|\Arg{symbolname}. In the first case, +% it stores the full URI in \cs{macro}; in the second +% case, it invokes the symbol \meta{symbolname} in the +% selected module. +% \end{function} +% +% \begin{function}{\stex_activate_module:n} +% Activate the module with the provided URI; i.e. executes +% all macro code of the module's |_code|-macro (does +% nothing if the module is already activated in the current +% context) and adds the module to \cs{l_stex_all_modules_seq}. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation}\label{pkg:modules:impl} +% +% \section{\sTeX-Modules Implementation} +% +% \begin{macrocode} +%<*package> + +%%%%%%%%%%%%% modules.dtx %%%%%%%%%%%%% + +%<@@=stex_modules> +% \end{macrocode} +% +% Warnings and error messages +% +% \begin{macrocode} +\msg_new:nnn{stex}{error/unknownmodule}{ + No~module~#1~found +} +\msg_new:nnn{stex}{error/syntax}{ + Syntax~error:~#1 +} +\msg_new:nnn{stex}{error/siglanguage}{ + Module~#1~declares~signature~#2,~but~does~not~ + declare~its~language +} +\msg_new:nnn{stex}{warning/deprecated}{ + #1~is~deprecated;~please~use~#2~instead! +} + +\msg_new:nnn{stex}{error/conflictingmodules}{ + Conflicting~imports~for~module~#1 +} +% \end{macrocode} +% +% +% \begin{variable}{\l_stex_current_module_str} +% The current module: +% \begin{macrocode} +\str_new:N \l_stex_current_module_str +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_stex_all_modules_seq} +% Stores all available modules +% \begin{macrocode} +\seq_new:N \l_stex_all_modules_seq +% \end{macrocode} +% \end{variable} +% +% \begin{macro}[pTF]{\stex_if_in_module:} +% \begin{macrocode} +\prg_new_conditional:Nnn \stex_if_in_module: {p, T, F, TF} { + \str_if_empty:NTF \l_stex_current_module_str + \prg_return_false: \prg_return_true: +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\stex_if_module_exists:n} +% \begin{macrocode} +\prg_new_conditional:Nnn \stex_if_module_exists:n {p, T, F, TF} { + \prop_if_exist:cTF { c_stex_module_#1_prop } + \prg_return_true: \prg_return_false: +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stex_add_to_current_module:n,\STEXexport} +% +% Only allowed within modules: +% +% \begin{macrocode} +\cs_new_protected:Nn \stex_add_to_current_module:n { + \tl_gput_right:cn {c_stex_module_\l_stex_current_module_str _code} { #1 } +} +\cs_new_protected:Npn \STEXexport { + \begingroup + \newlinechar=-1\relax + \endlinechar=-1\relax + %\catcode`\ = 9\relax + \expandafter\endgroup\_@@_export:n +} +\cs_new_protected:Nn \_@@_export:n { + \ignorespaces #1 + \stex_add_to_current_module:n { \ignorespaces #1 } + \stex_smsmode_do: +} +\stex_deactivate_macro:Nn \STEXexport {module~environments} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stex_add_constant_to_current_module:n} +% \begin{macrocode} +\cs_new_protected:Nn \stex_add_constant_to_current_module:n { + \str_set:Nx \l_tmpa_str { #1 } + \seq_gput_right:co {c_stex_module_\l_stex_current_module_str _constants} { \l_tmpa_str } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stex_add_import_to_current_module:n} +% \begin{macrocode} +\cs_new_protected:Nn \stex_add_import_to_current_module:n { + \str_set:Nx \l_tmpa_str { #1 } + \exp_args:Nno + \seq_if_in:cnF{c_stex_module_\l_stex_current_module_str _imports}\l_tmpa_str{ + \seq_gput_right:co{c_stex_module_\l_stex_current_module_str _imports}\l_tmpa_str + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stex_collect_imports:n} +% \begin{macrocode} +\cs_new_protected:Nn \stex_collect_imports:n { + \seq_clear:N \l_stex_collect_imports_seq + \_@@_collect_imports:n {#1} +} +\cs_new_protected:Nn \_@@_collect_imports:n { + \seq_map_inline:cn {c_stex_module_#1_imports} { + \seq_if_in:NnF \l_stex_collect_imports_seq { ##1 } { + \_@@_collect_imports:n { ##1 } + } + } + \seq_if_in:NnF \l_stex_collect_imports_seq { #1 } { + \seq_put_right:Nx \l_stex_collect_imports_seq { #1 } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stex_do_up_to_module:n} +% \begin{macrocode} +\int_new:N \l_@@_group_depth_int +\tl_new:N \l_@@_aftergroup_tl +\cs_new_protected:Nn \stex_do_up_to_module:n { + \int_compare:nNnTF \l_@@_group_depth_int = \currentgrouplevel { + #1 + }{ + #1 + \expandafter \tl_gset:Nn \expandafter \l_@@_aftergroup_tl \expandafter { \l_@@_aftergroup_tl #1 } + \aftergroup\_@@_aftergroup_do: + } +} +\cs_new_protected:Nn \_@@_aftergroup_do: { + \int_compare:nNnTF \l_@@_group_depth_int = \currentgrouplevel { + \l_@@_aftergroup_tl + \tl_clear:N \l_@@_aftergroup_tl + }{ + \l_@@_aftergroup_tl + \aftergroup\_@@_aftergroup_do: + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stex_modules_compute_namespace:nN} +% Computes the appropriate namespace from the top-level namespace +% of a repository (|#1|) and a file path +% (|#2|). +% +% +% \begin{macrocode} + +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stex_modules_current_namespace:} +% +% Computes the current namespace based on the current +% MathHub repository (if existent) and the current file. +% +% \begin{macrocode} +\str_new:N \l_stex_modules_ns_str +\str_new:N \l_stex_modules_subpath_str +\cs_new_protected:Nn \_@@_compute_namespace:nN { + \str_set:Nx \l_tmpa_str { #1 } + \seq_set_eq:NN \l_tmpa_seq #2 + % split off file extension + \seq_pop_right:NN \l_tmpa_seq \l_tmpb_str + \exp_args:NNno \seq_set_split:Nnn \l_tmpb_seq . \l_tmpb_str + \seq_get_left:NN \l_tmpb_seq \l_tmpb_str + \seq_put_right:No \l_tmpa_seq \l_tmpb_str + + \bool_set_true:N \l_tmpa_bool + \bool_while_do:Nn \l_tmpa_bool { + \seq_pop_left:NN \l_tmpa_seq \l_tmpb_str + \exp_args:No \str_case:nnTF { \l_tmpb_str } { + {source} { \bool_set_false:N \l_tmpa_bool } + }{}{ + \seq_if_empty:NT \l_tmpa_seq { + \bool_set_false:N \l_tmpa_bool + } + } + } + + \stex_path_to_string:NN \l_tmpa_seq \l_stex_modules_subpath_str + \str_if_empty:NTF \l_stex_modules_subpath_str { + \str_set_eq:NN \l_stex_modules_ns_str \l_tmpa_str + }{ + \str_set:Nx \l_stex_modules_ns_str { + \l_tmpa_str/\l_stex_modules_subpath_str + } + } +} + +\cs_new_protected:Nn \stex_modules_current_namespace: { + \str_clear:N \l_stex_modules_subpath_str + \prop_if_exist:NTF \l_stex_current_repository_prop { + \prop_get:NnN \l_stex_current_repository_prop { ns } \l_tmpa_str + \_@@_compute_namespace:nN \l_tmpa_str \g_stex_currentfile_seq + }{ + % split off file extension + \seq_set_eq:NN \l_tmpa_seq \g_stex_currentfile_seq + \seq_pop_right:NN \l_tmpa_seq \l_tmpb_str + \exp_args:NNno \seq_set_split:Nnn \l_tmpb_seq . \l_tmpb_str + \seq_get_left:NN \l_tmpb_seq \l_tmpb_str + \seq_put_right:No \l_tmpa_seq \l_tmpb_str + \str_set:Nx \l_stex_modules_ns_str { + file:/\stex_path_to_string:N \l_tmpa_seq + } + } +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{The \texttt{smodule} environment} +% +% |smodule| arguments: +% +% \begin{macrocode} +\keys_define:nn { stex / module } { + title .tl_set:N = \smoduletitle , + type .str_set_x:N = \smoduletype , + id .str_set_x:N = \smoduleid , + deprecate .str_set_x:N = \l_stex_module_deprecate_str , + ns .str_set_x:N = \l_stex_module_ns_str , + lang .str_set_x:N = \l_stex_module_lang_str , + sig .str_set_x:N = \l_stex_module_sig_str , + creators .str_set_x:N = \l_stex_module_creators_str , + contributors .str_set_x:N = \l_stex_module_contributors_str , + meta .str_set_x:N = \l_stex_module_meta_str , + srccite .str_set_x:N = \l_stex_module_srccite_str +} + +\cs_new_protected:Nn \_@@_args:n { + \str_clear:N \smoduletitle + \str_clear:N \smoduletype + \str_clear:N \smoduleid + \str_clear:N \l_stex_module_ns_str + \str_clear:N \l_stex_module_deprecate_str + \str_clear:N \l_stex_module_lang_str + \str_clear:N \l_stex_module_sig_str + \str_clear:N \l_stex_module_creators_str + \str_clear:N \l_stex_module_contributors_str + \str_clear:N \l_stex_module_meta_str + \str_clear:N \l_stex_module_srccite_str + \keys_set:nn { stex / module } { #1 } +} + +% module parameters here? In the body? + +% \end{macrocode} +% +% \begin{macro}{\stex_module_setup:nn} +% Sets up a new module property list: +% \begin{macrocode} +\cs_new_protected:Nn \stex_module_setup:nn { + \str_set:Nx \l_stex_module_name_str { #2 } + \_@@_args:n { #1 } +% \end{macrocode} +% +% First, we set up the name and namespace of the module. +% +% Are we in a nested module? +% +% \begin{macrocode} + \stex_if_in_module:TF { + % Nested module + \prop_get:cnN {c_stex_module_\l_stex_current_module_str _prop} + { ns } \l_stex_module_ns_str + \str_set:Nx \l_stex_module_name_str { + \prop_item:cn {c_stex_module_\l_stex_current_module_str _prop} + { name } / \l_stex_module_name_str + } + }{ + % not nested: + \str_if_empty:NT \l_stex_module_ns_str { + \stex_modules_current_namespace: + \str_set_eq:NN \l_stex_module_ns_str \l_stex_modules_ns_str + \exp_args:NNNo \seq_set_split:Nnn \l_tmpa_seq + / {\l_stex_module_ns_str} + \seq_pop_right:NN \l_tmpa_seq \l_tmpa_str + \str_if_eq:NNT \l_tmpa_str \l_stex_module_name_str { + \str_set:Nx \l_stex_module_ns_str { + \stex_path_to_string:N \l_tmpa_seq + } + } + } + } +% \end{macrocode} +% +% Next, we determine the language of the module: +% +% \begin{macrocode} + \str_if_empty:NT \l_stex_module_lang_str { + \seq_get_right:NN \g_stex_currentfile_seq \l_tmpa_str + \seq_set_split:NnV \l_tmpa_seq . \l_tmpa_str + \seq_pop_right:NN \l_tmpa_seq \l_tmpa_str % .tex + \seq_pop_left:NN \l_tmpa_seq \l_tmpa_str % <filename> + \seq_if_empty:NF \l_tmpa_seq { %remaining element should be language + \stex_debug:nn{modules} {Language~\l_stex_module_lang_str~ + inferred~from~file~name} + \seq_pop_left:NN \l_tmpa_seq \l_stex_module_lang_str + } + } + + \stex_if_smsmode:F { \str_if_empty:NF \l_stex_module_lang_str { + \prop_get:NVNTF \c_stex_languages_prop \l_stex_module_lang_str + \l_tmpa_str { + \ltx@ifpackageloaded{babel}{ + \exp_args:Nx \selectlanguage { \l_tmpa_str } + }{} + } { + \msg_error:nnx{stex}{error/unknownlanguage}{\l_tmpa_str} + } + }} +% \end{macrocode} +% +% We check if we need to extend a signature module, and set +% \cs{l_stex_current_module_prop} accordingly: +% +% \begin{macrocode} + \str_if_empty:NTF \l_stex_module_sig_str { + \exp_args:Nnx \prop_gset_from_keyval:cn { + c_stex_module_\l_stex_module_ns_str?\l_stex_module_name_str _prop + } { + name = \l_stex_module_name_str , + ns = \l_stex_module_ns_str , + file = \exp_not:o { \g_stex_currentfile_seq } , + lang = \l_stex_module_lang_str , + sig = \l_stex_module_sig_str , + deprecate = \l_stex_module_deprecate_str , + meta = \l_stex_module_meta_str + } + \seq_clear:c {c_stex_module_\l_stex_module_ns_str?\l_stex_module_name_str _imports} + \seq_clear:c {c_stex_module_\l_stex_module_ns_str?\l_stex_module_name_str _constants} + \tl_clear:c {c_stex_module_\l_stex_module_ns_str?\l_stex_module_name_str _code} + \str_set:Nx\l_stex_current_module_str{\l_stex_module_ns_str?\l_stex_module_name_str} +% \end{macrocode} +% +% We load the metatheory: +% +% \begin{macrocode} + \str_if_empty:NT \l_stex_module_meta_str { + \str_set:Nx \l_stex_module_meta_str { + \c_stex_metatheory_ns_str ? Metatheory + } + } + \str_if_eq:VnF \l_stex_module_meta_str {NONE} { + \bool_set_true:N \l_stex_in_meta_bool + \exp_args:Nx \stex_add_to_current_module:n { + \bool_set_true:N \l_stex_in_meta_bool + \stex_activate_module:n {\l_stex_module_meta_str} + \bool_set_false:N \l_stex_in_meta_bool + } + \stex_activate_module:n {\l_stex_module_meta_str} + \bool_set_false:N \l_stex_in_meta_bool + } + }{ + \str_if_empty:NT \l_stex_module_lang_str { + \msg_error:nnxx{stex}{error/siglanguage}{ + \l_stex_module_ns_str?\l_stex_module_name_str + }{\l_stex_module_sig_str} + } + + \seq_set_eq:NN \l_tmpa_seq \g_stex_currentfile_seq + \seq_pop_right:NN \l_tmpa_seq \l_tmpa_str + \seq_set_split:NnV \l_tmpb_seq . \l_tmpa_str + \seq_pop_right:NN \l_tmpb_seq \l_tmpa_str % .tex + \seq_pop_left:NN \l_tmpb_seq \l_tmpa_str % <filename> + \str_set:Nx \l_tmpa_str { + \stex_path_to_string:N \l_tmpa_seq / + \l_tmpa_str . \l_stex_module_sig_str .tex + } + \IfFileExists \l_tmpa_str { + \exp_args:No \stex_file_in_smsmode:nn { \l_tmpa_str } { + \str_clear:N \l_stex_current_module_str + \seq_clear:N \l_stex_all_modules_seq + \stex_debug:nn{modules}{Loading~signature~\l_tmpa_str} + } + }{ + \msg_error:nnx{stex}{error/unknownmodule}{for~signature~\l_tmpa_str} + } + \stex_if_smsmode:F { + \stex_activate_module:n { + \l_stex_module_ns_str ? \l_stex_module_name_str + } + } + \str_set:Nx\l_stex_current_module_str{\l_stex_module_ns_str?\l_stex_module_name_str} + } + \str_if_empty:NF \l_stex_module_deprecate_str { + \msg_warning:nnxx{stex}{warning/deprecated}{ + Module~\l_stex_current_module_str + }{ + \l_stex_module_deprecate_str + } + } + \seq_put_right:Nx \l_stex_all_modules_seq { + \l_stex_module_ns_str ? \l_stex_module_name_str + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{environment}{smodule} +% +% The |module| environment. +% +% \begin{macro}{\_@@_begin_module:} +% +% implements |\begin{smodule}| +% +% \begin{macrocode} +\cs_new_protected:Nn \_@@_begin_module: { + \stex_reactivate_macro:N \STEXexport + \stex_reactivate_macro:N \importmodule + \stex_reactivate_macro:N \symdecl + \stex_reactivate_macro:N \notation + \stex_reactivate_macro:N \symdef + + \stex_debug:nn{modules}{ + New~module:\\ + Namespace:~\l_stex_module_ns_str\\ + Name:~\l_stex_module_name_str\\ + Language:~\l_stex_module_lang_str\\ + Signature:~\l_stex_module_sig_str\\ + Metatheory:~\l_stex_module_meta_str\\ + File:~\stex_path_to_string:N \g_stex_currentfile_seq + } + + \stex_if_smsmode:F{ + \begin{stex_annotate_env} {theory} { + \l_stex_module_ns_str ? \l_stex_module_name_str + } + + \stex_annotate_invisible:nnn{header}{} { + \stex_annotate:nnn{language}{ \l_stex_module_lang_str }{} + \stex_annotate:nnn{signature}{ \l_stex_module_sig_str }{} + \str_if_eq:VnF \l_stex_module_meta_str {NONE} { + \stex_annotate:nnn{metatheory}{ \l_stex_module_meta_str }{} + } + \str_if_empty:NF \smoduletype { + \stex_annotate:nnn{type}{\smoduletype}{} + } + } + } + \int_set:Nn \l_@@_group_depth_int {\currentgrouplevel} + % TODO: Inherit metatheory for nested modules? +} +\iffalse \end{stex_annotate_env} \fi %^^A make syntax highlighting work again +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\_@@_end_module:} +% +% implements |\end{module}| +% +% \begin{macrocode} +\cs_new_protected:Nn \_@@_end_module: { + \stex_debug:nn{modules}{Closing~module~\prop_item:cn {c_stex_module_\l_stex_current_module_str _prop} { name }} +} +% \end{macrocode} +% \end{macro} +% +% The core environment +% +% \begin{macrocode} +\iffalse \begin{stex_annotate_env} \fi %^^A make syntax highlighting work again +\NewDocumentEnvironment { smodule } { O{} m } { + \stex_module_setup:nn{#1}{#2} + \par + \stex_if_smsmode:F{ + \tl_clear:N \l_tmpa_tl + \clist_map_inline:Nn \smoduletype { + \tl_if_exist:cT {_@@_smodule_##1_start:}{ + \tl_set:Nn \l_tmpa_tl {\use:c{_@@_smodule_##1_start:}} + } + } + \tl_if_empty:NTF \l_tmpa_tl { + \_@@_smodule_start: + }{ + \l_tmpa_tl + } + } + \_@@_begin_module: + \str_if_empty:NF \smoduleid { + \stex_ref_new_doc_target:n \smoduleid + } + \stex_smsmode_do: +} { + \_@@_end_module: + \stex_if_smsmode:F { + \end{stex_annotate_env} + \clist_set:No \l_tmpa_clist \smoduletype + \tl_clear:N \l_tmpa_tl + \clist_map_inline:Nn \l_tmpa_clist { + \tl_if_exist:cT {_@@_smodule_##1_end:}{ + \tl_set:Nn \l_tmpa_tl {\use:c{_@@_smodule_##1_end:}} + } + } + \tl_if_empty:NTF \l_tmpa_tl { + \_@@_smodule_end: + }{ + \l_tmpa_tl + } + } +} +% \end{macrocode} +% \end{environment} +% +% \begin{macro}{\stexpatchmodule} +% \begin{macrocode} +\cs_new_protected:Nn \_@@_smodule_start: {} +\cs_new_protected:Nn \_@@_smodule_end: {} + +\newcommand\stexpatchmodule[3][] { + \str_set:Nx \l_tmpa_str{ #1 } + \str_if_empty:NTF \l_tmpa_str { + \tl_set:Nn \_@@_smodule_start: { #2 } + \tl_set:Nn \_@@_smodule_end: { #3 } + }{ + \exp_after:wN \tl_set:Nn \csname _@@_smodule_#1_start:\endcsname{ #2 } + \exp_after:wN \tl_set:Nn \csname _@@_smodule_#1_end:\endcsname{ #3 } + } +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Invoking modules} +% +% \begin{macro}{\STEXModule,\stex_invoke_module:n} +% \begin{macrocode} +\NewDocumentCommand \STEXModule { m } { + \exp_args:NNx \str_set:Nn \l_tmpa_str { #1 } + \int_set:Nn \l_tmpa_int { \str_count:N \l_tmpa_str } + \tl_set:Nn \l_tmpa_tl { + \msg_error:nnx{stex}{error/unknownmodule}{#1} + } + \seq_map_inline:Nn \l_stex_all_modules_seq { + \str_set:Nn \l_tmpb_str { ##1 } + \str_if_eq:eeT { \l_tmpa_str } { + \str_range:Nnn \l_tmpb_str { -\l_tmpa_int } { -1 } + } { + \seq_map_break:n { + \tl_set:Nn \l_tmpa_tl { + \stex_invoke_module:n { ##1 } + } + } + } + } + \l_tmpa_tl +} + +\cs_new_protected:Nn \stex_invoke_module:n { + \stex_debug:nn{modules}{Invoking~module~#1} + \peek_charcode_remove:NTF ! { + \_@@_invoke_uri:nN { #1 } + } { + \peek_charcode_remove:NTF ? { + \_@@_invoke_symbol:nn { #1 } + } { + \msg_error:nnx{stex}{error/syntax}{ + ?~or~!~expected~after~ + \c_backslash_str STEXModule{#1} + } + } + } +} + +\cs_new_protected:Nn \_@@_invoke_uri:nN { + \str_set:Nn #2 { #1 } +} + +\cs_new_protected:Nn \_@@_invoke_symbol:nn { + \stex_invoke_symbol:n{#1?#2} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stex_activate_module:n} +% \begin{macrocode} +\bool_new:N \l_stex_in_meta_bool +\bool_set_false:N \l_stex_in_meta_bool +\cs_new_protected:Nn \stex_activate_module:n { + \stex_debug:nn{modules}{Activating~module~#1} + \seq_if_in:NnT \l_stex_implicit_morphisms_seq { #1 }{ + \msg_error:nnn{stex}{error/conflictingmodules}{ #1 } + } + \exp_args:NNx \seq_if_in:NnF \l_stex_all_modules_seq { #1 } { + \seq_put_right:Nx \l_stex_all_modules_seq { #1 } + \use:c{ c_stex_module_#1_code } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/macros/latex/contrib/stex/source/stex/others.dtx b/macros/latex/contrib/stex/source/stex/others.dtx new file mode 100644 index 0000000000..1905079a9c --- /dev/null +++ b/macros/latex/contrib/stex/source/stex/others.dtx @@ -0,0 +1,87 @@ +% \iffalse meta-comment +% An Infrastructure for Semantic Macros and Module Scoping +% Copyright (c) 2019 Michael Kohlhase, all rights reserved +% this file is released under the +% LaTeX Project Public License (LPPL) +% +% The original of this file is in the public repository at +% http://github.com/sLaTeX/sTeX/ +% +% TODO update copyright +% +%<*driver> +\providecommand\bibfolder{../../lib/bib} +\input{../../doc/docheader} + +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{ \sTeX-Others +% \thanks{Version {\fileversion} (last revised {\filedate})} +% } +% +% \author{Michael Kohlhase, Dennis Müller\\ +% FAU Erlangen-Nürnberg\\ +% \url{http://kwarc.info/} +% } +% +% \maketitle +% +% \begin{documentation}\label{pkg:finally:doc} +% +% +% \end{documentation} +% +% \begin{implementation}\label{pkg:finally:impl} +% +% Some auxiliary code, and clean up to be executed at the +% end of the package. +% +% \section{\sTeX-Others Implementation} +% +% \begin{macrocode} +%<*package> + +%%%%%%%%%%%%% others.dtx %%%%%%%%%%%%% + +%<@@=stex_others> +% \end{macrocode} +% +% Warnings and error messages +% +% \begin{macrocode} + % None +% \end{macrocode} +% +% \begin{macro}{\MSC} +% +% Math subject classifier +% +% \begin{macrocode} +\NewDocumentCommand \MSC {m} { + % TODO +} +% \end{macrocode} +% \end{macro} +% +% +% Patching \pkg{tikzinput}, if loaded +% +% \begin{macrocode} +\@ifpackageloaded{tikzinput}{ + \RequirePackage{stex-tikzinput} +}{} +% \end{macrocode} +% +% +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/macros/latex/contrib/stex/source/stex/references.dtx b/macros/latex/contrib/stex/source/stex/references.dtx new file mode 100644 index 0000000000..3153eeabab --- /dev/null +++ b/macros/latex/contrib/stex/source/stex/references.dtx @@ -0,0 +1,525 @@ +% \iffalse meta-comment +% An Infrastructure for Semantic Macros and Module Scoping +% Copyright (c) 2019 Michael Kohlhase, all rights reserved +% this file is released under the +% LaTeX Project Public License (LPPL) +% +% The original of this file is in the public repository at +% http://github.com/sLaTeX/sTeX/ +% +% TODO update copyright +% +%<*driver> +\providecommand\bibfolder{../../lib/bib} +\input{../../doc/docheader} + +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{ \sTeX-References +% \thanks{Version {\fileversion} (last revised {\filedate})} +% } +% +% \author{Michael Kohlhase, Dennis Müller\\ +% FAU Erlangen-Nürnberg\\ +% \url{http://kwarc.info/} +% } +% +% \maketitle +% +%\ifinfulldoc\else +% This is the documentation for the \pkg{stex-references} package. +% For a more high-level introduction, +% see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the +% \href{\basedocurl/stex.pdf}{full \sTeX documentation}. +% \fi +% +% \begin{documentation}\label{pkg:sref:doc} +% +% This sub package contains code related to links and cross-references +% +%\ifinfulldoc\else +% \input{../../doc/packages/references} +% \fi +% +% \section{Macros and Environments}\label{pkg:sref:doc:macros} +% +% \begin{function}{\STEXreftitle} +% \begin{syntax} \cs{STEXreftitle}\Arg{some title} \end{syntax} +% +% Sets the title of the current document to \meta{some title}. +% A reference to the current document from \emph{some other} +% document will then be displayed accordingly. e.g. +% if |\STEXreftitle{foo book}| is called, then referencing +% Definition 3.5 in this document in another document will display +% |Definition 3.5 in foo book|. +% \end{function} +% +% \begin{function}{\stex_get_document_uri:} +% Computes the current document uri from the current archive's +% |narr|-field and its location relative to the archive's +% |source|-directory. Reference targets are computed from +% this URI and the reference-id. +% +% \begin{variable}{\l_stex_current_docns_str} +% Stores its result in |\l_stex_current_docns_str| +% \end{variable} +% \end{function} +% +% \begin{function}{\stex_get_document_url:} +% Computes the current URL from the current archive's +% |docurl|-field and its location relative to the archive's +% |source|-directory. Reference targets are computed from +% this URL and the reference-id, if this document is only included +% in SMS mode. +% +% \begin{variable}{\l_stex_current_docurl_str} +% Stores its result in |\l_stex_current_docurl_str| +% \end{variable} +% \end{function} +% +% \subsection{Setting Reference Targets} +% +% \begin{function}{\stex_ref_new_doc_target:n} +% \begin{syntax} \cs{stex_ref_new_doc_target:n}\Arg{id} \end{syntax} +% +% Sets a new reference target with id \meta{id}. +% \end{function} +% +% \begin{function}{\stex_ref_new_sym_target:n} +% \begin{syntax} \cs{stex_ref_new_sym_target:n}\Arg{uri} \end{syntax} +% +% Sets a new reference target for the symbol \meta{uri}. +% \end{function} +% +% \subsection{Using References} +% +% \begin{function}{\sref} +% \begin{syntax} \cs{sref}|[|\meta{opt-args}|]|\Arg{id} \end{syntax} +% References the label with if \meta{id}. +% Optional arguments: TODO +% \end{function} +% +% \begin{function}{\srefsym} +% \begin{syntax} \cs{srefsym}|[|\meta{opt-args}|]|\Arg{symbol} \end{syntax} +% Like \cs{sref}, but references the \emph{canonical label} for +% the provided symbol. The canonical target is the last of the following +% occuring in the document: +% \begin{itemize} +% \item A \cs{definiendum} or \cs{definame} for \meta{symbol}, +% \item The |sassertion|, |sexample| or |sparagraph| with |for=|\meta{symbol} that +% generated \meta{symbol} in the first place, or +% \item A \cs{sparagraph} with |type=symdoc| and |for=|\meta{symbol}. +% \end{itemize} +% \end{function} +% +% \begin{function}{\srefsymuri} +% \begin{syntax} \cs{srefsymuri}\Arg{URI}\Arg{text} \end{syntax} +% A convenient short-hand for |\srefsym[linktext={text}]{URI}|, +% but requires the first argument to be a full URI already. +% Intended to be used in e.g. \cs{compemph@uri}, \cs{defemph@uri}, etc. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation}\label{pkg:sref:impl} +% +% \section{\sTeX-References Implementation} +% +% \begin{macrocode} +%<*package> + +%%%%%%%%%%%%% references.dtx %%%%%%%%%%%%% + +%<@@=stex_refs> +% \end{macrocode} +% +% Warnings and error messages +% +% \begin{macrocode} + +% \end{macrocode} +% +% References are stored in the file |\jobname.sref|, to enable +% cross-referencing external documents. +% +% \begin{macrocode} +%\iow_new:N \c_@@_refs_iow +\AddToHook{begindocument}{ +% \iow_open:Nn \c_@@_refs_iow {\jobname.sref} +} +\AddToHook{enddocument}{ +% \iow_close:N \c_@@_refs_iow +} +% \end{macrocode} +% +% \begin{macro}{\STEXreftitle} +% \begin{macrocode} +\str_set:Nn \g_@@_title_tl {Unnamed~Document} + +\NewDocumentCommand \STEXreftitle { m } { + \tl_gset:Nx \g_@@_title_tl { #1 } +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Document URIs and URLs} +% +% \begin{variable}{\l_stex_current_docns_str} +% \begin{macrocode} +\str_new:N \l_stex_current_docns_str +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\stex_get_document_uri:} +% \begin{macrocode} +\cs_new_protected:Nn \stex_get_document_uri: { + \seq_set_eq:NN \l_tmpa_seq \g_stex_currentfile_seq + \seq_pop_right:NN \l_tmpa_seq \l_tmpb_str + \exp_args:NNno \seq_set_split:Nnn \l_tmpb_seq . \l_tmpb_str + \seq_get_left:NN \l_tmpb_seq \l_tmpb_str + \seq_put_right:No \l_tmpa_seq \l_tmpb_str + + \str_clear:N \l_tmpa_str + \prop_if_exist:NT \l_stex_current_repository_prop { + \prop_get:NnNF \l_stex_current_repository_prop { narr } \l_tmpa_str { + \prop_get:NnNF \l_stex_current_repository_prop { ns } \l_tmpa_str {} + } + } + + \str_if_empty:NTF \l_tmpa_str { + \str_set:Nx \l_stex_current_docns_str { + file:/\stex_path_to_string:N \l_tmpa_seq + } + }{ + \bool_set_true:N \l_tmpa_bool + \bool_while_do:Nn \l_tmpa_bool { + \seq_pop_left:NN \l_tmpa_seq \l_tmpb_str + \exp_args:No \str_case:nnTF { \l_tmpb_str } { + {source} { \bool_set_false:N \l_tmpa_bool } + }{}{ + \seq_if_empty:NT \l_tmpa_seq { + \bool_set_false:N \l_tmpa_bool + } + } + } + + \seq_if_empty:NTF \l_tmpa_seq { + \str_set_eq:NN \l_stex_current_docns_str \l_tmpa_str + }{ + \str_set:Nx \l_stex_current_docns_str { + \l_tmpa_str/\stex_path_to_string:N \l_tmpa_seq + } + } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\l_stex_current_docurl_str} +% \begin{macrocode} +\str_new:N \l_stex_current_docurl_str +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\stex_get_document_url:} +% \begin{macrocode} +\cs_new_protected:Nn \stex_get_document_url: { + \seq_set_eq:NN \l_tmpa_seq \g_stex_currentfile_seq + \seq_pop_right:NN \l_tmpa_seq \l_tmpb_str + \exp_args:NNno \seq_set_split:Nnn \l_tmpb_seq . \l_tmpb_str + \seq_get_left:NN \l_tmpb_seq \l_tmpb_str + \seq_put_right:No \l_tmpa_seq \l_tmpb_str + + \str_clear:N \l_tmpa_str + \prop_if_exist:NT \l_stex_current_repository_prop { + \prop_get:NnNF \l_stex_current_repository_prop { docurl } \l_tmpa_str { + \prop_get:NnNF \l_stex_current_repository_prop { narr } \l_tmpa_str { + \prop_get:NnNF \l_stex_current_repository_prop { ns } \l_tmpa_str {} + } + } + } + + \str_if_empty:NTF \l_tmpa_str { + \str_set:Nx \l_stex_current_docurl_str { + file:/\stex_path_to_string:N \l_tmpa_seq + } + }{ + \bool_set_true:N \l_tmpa_bool + \bool_while_do:Nn \l_tmpa_bool { + \seq_pop_left:NN \l_tmpa_seq \l_tmpb_str + \exp_args:No \str_case:nnTF { \l_tmpb_str } { + {source} { \bool_set_false:N \l_tmpa_bool } + }{}{ + \seq_if_empty:NT \l_tmpa_seq { + \bool_set_false:N \l_tmpa_bool + } + } + } + + \seq_if_empty:NTF \l_tmpa_seq { + \str_set_eq:NN \l_stex_current_docurl_str \l_tmpa_str + }{ + \str_set:Nx \l_stex_current_docurl_str { + \l_tmpa_str/\stex_path_to_string:N \l_tmpa_seq + } + } + } +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Setting Reference Targets} +% +% \begin{macrocode} +\str_const:Nn \c_@@_url_str{URL} +\str_const:Nn \c_@@_ref_str{REF} +\str_new:N \l_@@_curr_label_str +% @currentlabel -> number +% @currentlabelname -> title +% @currentHref -> name.number <- id of some kind +% \theH# -> \arabic{section} +% \the# -> number +% \hyper@makecurrent{#} +\int_new:N \l_@@_unnamed_counter_int +% \end{macrocode} +% +% \begin{macro}{\stex_ref_new_doc_target:n} +% \begin{macrocode} +\cs_new_protected:Nn \stex_ref_new_doc_target:n { + \stex_get_document_uri: + \str_clear:N \l_@@_curr_label_str + \str_set:Nx \l_tmpa_str { #1 } + \str_if_empty:NT \l_tmpa_str { + \int_incr:N \l_@@_unnamed_counter_int + \str_set:Nx \l_tmpa_str {REF\int_use:N \l_@@_unnamed_counter_int} + } + \str_set:Nx \l_@@_curr_label_str { + \l_stex_current_docns_str?\l_tmpa_str + } + \seq_if_exist:cF{g_@@_labels_\l_tmpa_str _seq}{ + \seq_new:c {g_@@_labels_\l_tmpa_str _seq} + } + \seq_if_in:coF{g_@@_labels_\l_tmpa_str _seq}\l_@@_curr_label_str { + \seq_gput_right:co{g_@@_labels_\l_tmpa_str _seq}\l_@@_curr_label_str + } + \stex_if_smsmode:TF { + \stex_get_document_url: + \str_gset_eq:cN {sref_url_\l_@@_curr_label_str _str}\l_stex_current_docurl_str + \str_gset_eq:cN {sref_\l_@@_curr_label_str _type}\c_@@_url_str + }{ + %\iow_now:Nx \c_@@_refs_iow { \l_tmpa_str~=~\expandafter\unexpanded\expandafter{\@currentlabel}~in~\exp_args:No\unexpanded\g_@@_title_tl,} + \exp_args:Nx\label{sref_\l_@@_curr_label_str} + \immediate\write\@auxout{\stexauxadddocref{\l_stex_current_docns_str}{\l_tmpa_str}} + \str_gset:cx {sref_\l_@@_curr_label_str _type}\c_@@_ref_str + } +} +% \end{macrocode} +% \end{macro} +% +% The following is used to set the necessary macros in the |.aux|-file. +% +% \begin{macrocode} +\cs_new_protected:Npn \stexauxadddocref #1 #2 { + \str_set:Nn \l_tmpa_str {#1?#2} + \str_gset_eq:cN{sref_#1?#2_type}\c_@@_ref_str + \seq_if_exist:cF{g_@@_labels_#2_seq}{ + \seq_new:c {g_@@_labels_#2_seq} + } + \seq_if_in:coF{g_@@_labels_#2_seq}\l_tmpa_str { + \seq_gput_right:co{g_@@_labels_#2_seq}\l_tmpa_str + } +} +% \end{macrocode} +% To avoid resetting the same macros when the |.aux|-file is read +% at the end of the document: +% +% \begin{macrocode} +\AtEndDocument{ + \def\stexauxadddocref#1 #2 {}{} +} +% \end{macrocode} +% +% \begin{macro}{\stex_ref_new_sym_target:n} +% \begin{macrocode} +\cs_new_protected:Nn \stex_ref_new_sym_target:n { + \stex_if_smsmode:TF { + \str_if_exist:cF{sref_sym_#1_type}{ + \stex_get_document_url: + \str_gset_eq:cN {sref_sym_url_#1_str}\l_stex_current_docurl_str + \str_gset_eq:cN {sref_sym_#1_type}\c_@@_url_str + } + }{ + \str_if_empty:NF \l_@@_curr_label_str { + \str_gset_eq:cN {sref_sym_#1_label_str}\l_@@_curr_label_str + \immediate\write\@auxout{ + \exp_not:N\expandafter\def\exp_not:N\csname sref_sym_#1_label_str\exp_not:N\endcsname{ + \l_@@_curr_label_str + } + } + } + } +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Using References} +% +% \begin{macrocode} +\str_new:N \l_@@_indocument_str +% \end{macrocode} +% +% \begin{macro}{\sref} +% Optional arguments: +% \begin{macrocode} + +\keys_define:nn { stex / sref } { + linktext .tl_set:N = \l_@@_linktext_tl , + fallback .tl_set:N = \l_@@_fallback_tl , + pre .tl_set:N = \l_@@_pre_tl , + post .tl_set:N = \l_@@_post_tl , +} +\cs_new_protected:Nn \_@@_args:n { + \tl_clear:N \l_@@_linktext_tl + \tl_clear:N \l_@@_fallback_tl + \tl_clear:N \l_@@_pre_tl + \tl_clear:N \l_@@_post_tl + \str_clear:N \l_@@_repo_str + \keys_set:nn { stex / sref } { #1 } +} +% \end{macrocode} +% The actual macro: +% \begin{macrocode} +\NewDocumentCommand \sref { O{} m}{ + \_@@_args:n { #1 } + \str_if_empty:NTF \l_@@_indocument_str { + \str_set:Nx \l_tmpa_str { #2 } + \exp_args:NNno \seq_set_split:Nnn \l_tmpa_seq ? \l_tmpa_str + \int_compare:nNnTF {\seq_count:N \l_tmpa_seq} = 1 { + \seq_if_exist:cTF{g_@@_labels_\l_tmpa_str _seq}{ + \seq_get_left:cNF {g_@@_labels_\l_tmpa_str _seq} \l_tmpa_str { + \str_clear:N \l_tmpa_str + } + }{ + \str_clear:N \l_tmpa_str + } + }{ + \seq_pop_left:NN \l_tmpa_seq \l_tmpb_str + \seq_pop_right:NN \l_tmpa_seq \l_tmpa_str + \int_set:Nn \l_tmpa_int { \exp_args:Ne \str_count:n {\l_tmpb_str?\l_tmpa_str} } + \seq_if_exist:cTF{g_@@_labels_\l_tmpa_str _seq}{ + \str_set_eq:NN \l_tmpc_str \l_tmpa_str + \str_clear:N \l_tmpa_str + \seq_map_inline:cn {g_@@_labels_\l_tmpc_str _seq} { + \str_if_eq:eeT { \l_tmpb_str?\l_tmpc_str }{ + \str_range:nnn { ##1 }{ -\l_tmpa_int}{ -1 } + }{ + \seq_map_break:n { + \str_set:Nn \l_tmpa_str { ##1 } + } + } + } + }{ + \str_clear:N \l_tmpa_str + } + } + \str_if_empty:NTF \l_tmpa_str { + \tl_if_empty:NTF \l_@@_linktext_tl \l_@@_fallback_tl \l_@@_linktext_tl + }{ + \str_if_eq:cNTF {sref_\l_tmpa_str _type} \c_@@_ref_str { + \tl_if_empty:NTF \l_@@_linktext_tl { + \cs_if_exist:cTF{autoref}{ + \l_@@_pre_tl\exp_args:Nx\autoref{sref_\l_tmpa_str}\l_@@_post_tl + }{ + \l_@@_pre_tl\exp_args:Nx\ref{sref_\l_tmpa_str}\l_@@_post_tl + } + }{ + \ltx@ifpackageloaded{hyperref}{ + \hyperref[sref_\l_tmpa_str]\l_@@_linktext_tl + }{ + \l_@@_linktext_tl + } + } + }{ + \ltx@ifpackageloaded{hyperref}{ + \href{\use:c{sref_url_\l_tmpa_str _str}}{\tl_if_empty:NTF \l_@@_linktext_tl \l_@@_fallback_tl \l_@@_linktext_tl} + }{ + \tl_if_empty:NTF \l_@@_linktext_tl \l_@@_fallback_tl \l_@@_linktext_tl + } + } + } + }{ + % TODO + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\srefsym} +% \begin{macrocode} +\NewDocumentCommand \srefsym { O{} m}{ + \stex_get_symbol:n { #2 } + \_@@_sym_aux:nn{#1}{\l_stex_get_symbol_uri_str} +} + +\cs_new_protected:Nn \_@@_sym_aux:nn { + \str_if_exist:cTF {sref_sym_#2 _label_str }{ + \sref[#1]{\use:c{sref_sym_#2 _label_str}} + }{ + \_@@_args:n { #1 } + \str_if_empty:NTF \l_@@_indocument_str { + \tl_if_exist:cTF{sref_sym_#2 _type}{ + % doc uri in \l_tmpb_str + \str_set:Nx \l_tmpa_str {\use:c{sref_sym_#2 _type}} + \str_if_eq:NNTF \l_tmpa_str \c_@@_ref_str { + % reference + \tl_if_empty:NTF \l_@@_linktext_tl { + \cs_if_exist:cTF{autoref}{ + \l_@@_pre_tl\autoref{sref_sym_#2}\l_@@_post_tl + }{ + \l_@@_pre_tl\ref{sref_sym_#2}\l_@@_post_tl + } + }{ + \ltx@ifpackageloaded{hyperref}{ + \hyperref[sref_sym_#2]\l_@@_linktext_tl + }{ + \l_@@_linktext_tl + } + } + }{ + % URL + \ltx@ifpackageloaded{hyperref}{ + \href{\use:c{sref_sym_url_#2 _str}}{\tl_if_empty:NTF \l_@@_linktext_tl \l_@@_fallback_tl \l_@@_linktext_tl} + }{ + \tl_if_empty:NTF \l_@@_linktext_tl \l_@@_fallback_tl \l_@@_linktext_tl + } + } + }{ + \tl_if_empty:NTF \l_@@_linktext_tl \l_@@_fallback_tl \l_@@_linktext_tl + } + }{ + % TODO + } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\srefsymuri} +% \begin{macrocode} +\cs_new_protected:Npn \srefsymuri #1 #2 { + \_@@_sym_aux:nn{linktext={#2}}{#1} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex diff --git a/macros/latex/contrib/stex/source/stex/sproof.dtx b/macros/latex/contrib/stex/source/stex/sproof.dtx new file mode 100644 index 0000000000..f3cbdb869a --- /dev/null +++ b/macros/latex/contrib/stex/source/stex/sproof.dtx @@ -0,0 +1,1053 @@ +% \iffalse meta-comment +% An Infrastructure for Structural Markup for Proofs +% Copyright (c) 2019 Michael Kohlhase, all rights reserved +% this file is released under the +% LaTeX Project Public License (LPPL) +% +% The original of this file is in the public repository at +% http://github.com/sLaTeX/sTeX/ +% \fi +% +% \iffalse +%<*driver> +\def\bibfolder{../../lib/bib} +\input{../../doc/docheader} + +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \iffalse\CheckSum{341}\fi +% +% ^^A \changes{v0.9}{2005/06/14}{First Version with Documentation} +% +% \GetFileInfo{sproof.sty} +% +% \title{\sTeX-Proofs: Structural Markup for Proofs\thanks{Version {\fileversion} (last revised +% {\filedate})}} +% \author{Michael Kohlhase, Dennis Müller\\ +% FAU Erlangen-N\"urnberg\\ +% \url{http://kwarc.info/kohlhase}} +% \maketitle +% +%\ifinfulldoc\else +% This is the documentation for the \pkg{stex-proofs} package. +% For a more high-level introduction, +% see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the +% \href{\basedocurl/stex.pdf}{full \sTeX documentation}. +% +% \input{../../doc/packages/sproofs} +% \fi +% +% \begin{documentation} +% +% The |sproof| package is part of the {\stex} collection, a version of {\TeX/\LaTeX} that +% allows to markup {\TeX/\LaTeX} documents semantically without leaving the document +% format, essentially turning {\TeX/\LaTeX} into a document format for mathematical +% knowledge management (MKM). +% +% This package supplies macros and environment that allow to annotate the structure of +% mathematical proofs in {\stex} files. This structure can be used by MKM systems for +% added-value services, either directly from the \sTeX sources, or after translation. +% +% \newpage\tableofcontents\newpage +% +%\section{Introduction}\label{sec:sproof} +% +% The |sproof| ({\twintoo{semantic}{proofs}}) package supplies macros and environment that +% allow to annotate the structure of mathematical proofs in {\stex} files. This structure +% can be used by MKM systems for added-value services, either directly from the \sTeX +% sources, or after translation. Even though it is part of the {\stex} collection, it can +% be used independently, like it's sister package |statements|. +% +% {\stex} is a version of {\TeX/\LaTeX} that allows to markup {\TeX/\LaTeX} documents +% semantically without leaving the document format, essentially turning {\TeX/\LaTeX} into +% a document format for mathematical knowledge management (MKM). +% +% \begin{exfig}\scriptsize +% \begin{verbatim} +% \begin{sproof}[id=simple-proof] +% {We prove that $\sum_{i=1}^n{2i-1}=n^{2}$ by induction over $n$} +% \begin{spfcases}{For the induction we have to consider the following cases:} +% \begin{spfcase}{$n=1$} +% \begin{spfstep}[type=inline] then we compute $1=1^2$\end{spfstep} +% \end{spfcase} +% \begin{spfcase}{$n=2$} +% \begin{sproofcomment}[type=inline] +% This case is not really necessary, but we do it for the +% fun of it (and to get more intuition). +% \end{sproofcomment} +% \begin{spfstep}[type=inline] We compute $1+3=2^{2}=4$.\end{spfstep} +% \end{spfcase} +% \begin{spfcase}{$n>1$} +% \begin{spfstep}[type=assumption,id=ind-hyp] +% Now, we assume that the assertion is true for a certain $k\geq 1$, +% i.e. $\sum_{i=1}^k{(2i-1)}=k^{2}$. +% \end{spfstep} +% \begin{sproofcomment} +% We have to show that we can derive the assertion for $n=k+1$ from +% this assumption, i.e. $\sum_{i=1}^{k+1}{(2i-1)}=(k+1)^{2}$. +% \end{sproofcomment} +% \begin{spfstep} +% We obtain $\sum_{i=1}^{k+1}{2i-1}=\sum_{i=1}^k{2i-1}+2(k+1)-1$ +% \begin{justification}[method=arith:split-sum] +% by splitting the sum. +% \end{justification} +% \end{spfstep} +% \begin{spfstep} +% Thus we have $\sum_{i=1}^{k+1}{(2i-1)}=k^2+2k+1$ +% \begin{justification}[method=fertilize] +% by inductive hypothesis. +% \end{justification} +% \end{spfstep} +% \begin{spfstep}[type=conclusion] +% We can \begin{justification}[method=simplify]simplify\end{justification} +% the right-hand side to ${k+1}^2$, which proves the assertion. +% \end{spfstep} +% \end{spfcase} +% \begin{spfstep}[type=conclusion] +% We have considered all the cases, so we have proven the assertion. +% \end{spfstep} +% \end{spfcases} +% \end{sproof} +% \end{verbatim} +% \vspace*{-.5cm} +% \caption{A very explicit proof, marked up semantically}\label{fig:proof:src} +% \end{exfig} +% +% We will go over the general intuition by way of our running example (see +% Figure~\ref{fig:proof:src} for the source and Figure~\ref{fig:proof:result} for the +% formatted result).\ednote{talk a bit more about proofs and their structure,... maybe +% copy from OMDoc spec. } +% +% \section{The User Interface} +% +% \subsection{Package Options}\label{sec:user:options} +% +% The |sproof| package takes a single option: \DescribeMacro{showmeta}|showmeta|. If +% this is set, then the metadata keys are shown (see~\cite{Kohlhase:metakeys} for details +% and customization options). +% +% \subsection{Proofs and Proof steps} +% +% \DescribeEnv{sproof} The |proof| environment is the main container for proofs. It takes +% an optional |KeyVal| argument that allows to specify the |id| (identifier) and |for| +% (for which assertion is this a proof) keys. The regular argument of the |proof| +% environment contains an introductory comment, that may be used to announce the proof +% style. The |proof| environment contains a sequence of |\step|, |proofcomment|, and +% |pfcases| environments that are used to markup the proof steps. The |proof| environment +% has a variant |Proof|, which does not use the proof end marker. This is convenient, if a +% proof ends in a case distinction, which brings it's own proof end marker with it. +% \DescribeEnv{sProof} The |Proof| environment is a variant of |proof| that does not mark +% the end of a proof with a little box; presumably, since one of the subproofs already has +% one and then a box supplied by the outer proof would generate an otherwise empty line. +% \DescribeMacro{\spfidea} The |\spfidea| macro allows to give a one-paragraph +% description of the proof idea. +% +% For one-line proof sketches, we use the \DescribeMacro{spfsketch}|\spfsketch| macro, +% which takes the |KeyVal| argument as |sproof| and another one: a natural language text +% that sketches the proof. +% +% \DescribeEnv{spfstep} Regular proof steps are marked up with the |step| environment, which +% takes an optional |KeyVal| argument for annotations. A proof step usually contains a +% local assertion (the text of the step) together with some kind of evidence that this can +% be derived from already established assertions. +% +% Note that both |\premise| and |\justarg| can be used with an empty second argument to +% mark up premises and arguments that are not explicitly mentioned in the text. +% +% \begin{exfig} +% \begin{sproof}[id=simple-proof] +% {We prove that $\sum_{i=1}^n{2i-1}=n^{2}$ by induction over $n$} +% \begin{spfcases}{For the induction we have to consider the following cases:} +% \begin{spfcase}{$n=1$} +% \begin{spfstep}[type=inline] then we compute $1=1^2$\end{spfstep} +% \end{spfcase} +% \begin{spfcase}{$n=2$} +% \begin{sproofcomment}[type=inline] +% This case is not really necessary, but we do it for the fun +% of it (and to get more intuition). +% \end{sproofcomment} +% \begin{spfstep}[type=inline] +% We compute $1+3=2^{2}=4$ +% \end{spfstep} +% \end{spfcase} +% \begin{spfcase}{$n>1$} +% \begin{spfstep}[type=hypothesis,id=ind-hyp] +% Now, we assume that the assertion is true for a certain $k\geq 1$, i.e. +% $\sum_{i=1}^k{(2i-1)}=k^{2}$. +% \end{spfstep} +% \begin{sproofcomment} +% We have to show that we can derive the assertion for $n=k+1$ from this +% assumption, i.e. $\sum_{i=1}^{k+1}{(2i-1)}=(k+1)^{2}$. +% \end{sproofcomment} +% \begin{spfstep}[id=splitit] +% We obtain $\sum_{i=1}^{k+1}{(2i-1)}=\sum_{i=1}^k{(2i-1)}+2(k+1)-1$ +% \begin{justification}[method=arith:split-sum] +% by splitting the sum +% \end{justification} +% \end{spfstep} +% \begin{spfstep}[id=byindhyp] +% Thus we have $\sum_{i=1}^{k+1}{(2i-1)}=k^2+2k+1$ +% \begin{justification}[method=fertilize] +% by \premise[ind-hyp]{inductive hypothesis}. +% \end{justification} +% \end{spfstep} +% \begin{spfstep}[type=conclusion] +% We can \begin{justification}[method=simplify-eq] +% simplify the {\justarg[rhs]{right-hand side}} +% \end{justification} to $(k+1)^2$, which proves the assertion. +% \end{spfstep} +% \end{spfcase} +% \begin{spfstep}[type=conclusion] +% We have considered all the cases, so we have proven the assertion. +% \end{spfstep} +% \end{spfcases} +% \end{sproof} +% \caption{The formatted result of the proof in Figure~\ref{fig:proof:src}}\label{fig:proof:result} +% \end{exfig} +% +% \subsection{Justifications} +% +% \DescribeEnv{justification} This evidence is marked up with the |justification| +% environment in the |sproof| package. This environment totally invisible to the formatted +% result; it wraps the text in the proof step that corresponds to the evidence. The +% environment takes an optional |KeyVal| argument, which can have the |method| key, whose +% value is the name of a proof method (this will only need to mean something to the +% application that consumes the semantic annotations). Furthermore, the justification can +% contain ``premises'' (specifications to assertions that were used justify the step) and +% ``arguments'' (other information taken into account by the proof method). +% +% \DescribeMacro{\premise} The |\premise| macro allows to mark up part of the text as +% reference to an assertion that is used in the argumentation. In the example in +% Figure~\ref{fig:proof:src} we have used the |\premise| macro to identify the inductive +% hypothesis. +% +% \DescribeMacro{\justarg} The |\justarg| macro is very similar to |\premise| with the +% difference that it is used to mark up arguments to the proof method. Therefore the +% content of the first argument is interpreted as a mathematical object rather than as an +% identifier as in the case of |\premise|. In our example, we specified that the +% simplification should take place on the right hand side of the equation. Other examples +% include proof methods that instantiate. Here we would indicate the substituted object in +% a |\justarg| macro. +% +% \subsection{Proof Structure} +% +% \DescribeEnv{subproof} The |pfcases| environment is used to mark up a subproof. This +% environment takes an optional |KeyVal| argument for semantic annotations and a second +% argument that allows to specify an introductory comment (just like in the |proof| +% environment). The \DescribeMacro{method}|method| key can be used to give the name of the +% proof method executed to make this subproof. +% +% \DescribeEnv{spfcases} The |pfcases| environment is used to mark up a proof by +% cases. Technically it is a variant of the |subproof| where the |method| is +% |by-cases|. Its contents are |spfcase| environments that mark up the cases one by one. +% +% \DescribeEnv{spfcase} The content of a |pfcases| environment are a sequence of case +% proofs marked up in the |pfcase| environment, which takes an optional |KeyVal| argument +% for semantic annotations. The second argument is used to specify the the description of +% the case under consideration. The content of a |pfcase| environment is the same as that +% of a |proof|, i.e. |step|s, |proofcomment|s, and |pfcases| +% environments. \DescribeMacro{\spfcasesketch}|\spfcasesketch| is a variant of the |spfcase| +% environment that takes the same arguments, but instead of the |spfstep|s in the body +% uses a third argument for a proof sketch. +% +% \DescribeEnv{sproofcomment} The |proofcomment| environment is much like a |step|, only +% that it does not have an object-level assertion of its own. Rather than asserting some +% fact that is relevant for the proof, it is used to explain where the proof is going, +% what we are attempting to to, or what we have achieved so far. As such, it cannot be the +% target of a |\premise|. +% +% \subsection{Proof End Markers} +% +% Traditionally, the end of a mathematical proof is marked with a little box at the end of +% the last line of the proof (if there is space and on the end of the next line if there +% isn't), like so:\sproofend +% +% The |sproof| package provides the \DescribeMacro{\sproofend}|\sproofend| macro for +% this. If a different symbol for the proof end is to be used (e.g. {\sl{q.e.d}}), then +% this can be obtained by specifying it using the +% \DescribeMacro{\sProofEndSymbol}|\sProofEndSymbol| configuration macro (e.g. by specifying +% |\sProofEndSymbol{q.e.d}|). +% +% Some of the proof structuring macros above will insert proof end symbols for sub-proofs, +% in most cases, this is desirable to make the proof structure explicit, but sometimes +% this wastes space (especially, if a proof ends in a case analysis which will supply its +% own proof end marker). To suppress it locally, just set |proofend={}| in them or use use +% |\sProofEndSymbol{}|. +% +% \subsection{Configuration of the Presentation}\label{sec:user:conf} +% +% Finally, we provide configuration hooks in Figure~\ref{fig:hooks} for the keywords in +% proofs. These are mainly intended for package authors building on |statements|, e.g. for +% multi-language support.\ednote{we might want to develop an extension +% \texttt{sproof-babel} in the future.}. +%\begin{figure}[ht]\centering +% \begin{tabular}{|lll|}\hline +% Environment & configuration macro & value\\\hline\hline +% \texttt{sproof} & \texttt{\textbackslash spf@proof@kw} & \makeatletter\spf@proof@kw\\\hline +% \texttt{sketchproof} & \texttt{\textbackslash spf@sketchproof@kw} & \makeatletter\spf@proofsketch@kw\\\hline +% \end{tabular} +% \caption{Configuration Hooks for Semantic Proof Markup}\label{fig:hooks} +% \end{figure} +% The proof step labels can be customized via the +% \DescribeMacro{\pstlabelstyle}|\pstlabelstyle| macro: |\pstlabelstyle{|\meta{style}|}| +% sets the style; see Figure~\ref{fig:pstlabel} for an overview of styles. Package writers +% can add additional styles by adding a macro |\pst@make@label@|\meta{style} that takes +% two arguments: a comma-separated list of ordinals that make up the prefix and the current +% ordinal. Note that comma-separated lists can be conveniently iterated over by the +% {\LaTeX} |\@for|\ldots|:=|\ldots|\do{|\ldots|}| macro; see Figure~\ref{fig:pstlabel} for +% examples. +% +% \section{Limitations}\label{sec:limitations} +% +% In this section we document known limitations. If you want to help alleviate them, +% please feel free to contact the package author. Some of them are currently discussed in +% the \sTeX issue tracker at \cite{sTeX:github:on}. +% \begin{enumerate} +% \item The numbering scheme of proofs cannot be changed. It is more geared for teaching +% proof structures (the author's main use case) and not for writing papers.\lec{reported +% by Tobias Pfeiffer (fixed)} +% \item currently proof steps are formatted by the {\LaTeX} |description| environment. We +% would like to configure this, e.g. to use the |inparaenum| environment for more +% condensed proofs. I am just not sure what the best user interface would be I can +% imagine redefining an internal environment |spf@proofstep@list| or adding a key +% |prooflistenv| to the |proof| environment that allows to specify the environment +% directly. Maybe we should do both. +% \end{enumerate} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{The Implementation} +% +% \subsection{Package Options}\label{sec:impl:options} +% +% We declare some switches which will modify the behavior according to the package +% options. Generally, an option |xxx| will just set the appropriate switches to true +% (otherwise they stay false).\ednote{need an implementation for {\latexml}} +% +% \begin{macrocode} +%<*package> +%<@@=stex_sproof> + +%%%%%%%%%%%%% sproof.dtx %%%%%%%%%%%%% + +% \end{macrocode} +% +% +% \subsection{Proofs}\label{sec:impl:proofs} +% +% We first define some keys for the |proof| environment. +% \begin{macrocode} +\keys_define:nn { stex / spf } { + id .str_set_x:N = \spfid, + for .clist_set:N = \l_@@_spf_for_clist , + from .tl_set:N = \l_@@_spf_from_tl , + proofend .tl_set:N = \l_@@_spf_proofend_tl, + type .str_set_x:N = \spftype, + title .tl_set:N = \spftitle, + continues .tl_set:N = \l_@@_spf_continues_tl, + functions .tl_set:N = \l_@@_spf_functions_tl, + method .tl_set:N = \l_@@_spf_method_tl +} +\cs_new_protected:Nn \_@@_spf_args:n { + \str_clear:N \spfid + \tl_clear:N \l_@@_spf_for_tl + \tl_clear:N \l_@@_spf_from_tl + \tl_set:Nn \l_@@_spf_proofend_tl {\sproof@box} + \str_clear:N \spftype + \tl_clear:N \spftitle + \tl_clear:N \l_@@_spf_continues_tl + \tl_clear:N \l_@@_spf_functions_tl + \tl_clear:N \l_@@_spf_method_tl + \bool_set_false:N \l_@@_inc_counter_bool + \keys_set:nn { stex / spf }{ #1 } +} +% \end{macrocode} +% +% \begin{macro}{\c_@@_flow_str} +% We define this macro, so that we can test whether the |display| key has the value |flow| +% \begin{macrocode} +\str_set:Nn\c_@@_flow_str{inline} +% \end{macrocode} +% \end{macro} +% +% For proofs, we will have to have deeply nested structures of enumerated list-like +% environments. However, {\LaTeX} only allows |enumerate| environments up to nesting depth +% 4 and general list environments up to listing depth 6. This is not enough for us. +% Therefore we have decided to go along the route proposed by Leslie Lamport to use a +% single top-level list with dotted sequences of numbers to identify the position in the +% proof tree. Unfortunately, we could not use his |pf.sty| package directly, since it does +% not do automatic numbering, and we have to add keyword arguments all over the place, to +% accomodate semantic information. +% +% \begin{environment}{pst@with@label} +% This environment manages\footnote{This gets the labeling right but only works 8 levels +% deep} the path labeling of the proof steps in the description environment of the +% outermost |proof| environment. The argument is the label prefix up to now; which we +% cache in |\pst@label| (we need evaluate it first, since are in the right place +% now!). Then we increment the proof depth which is stored in |\count10| (lower counters +% are used by {\TeX} for page numbering) and initialize the next level counter +% |\count\count10| with 1. In the end call for this environment, we just decrease the +% proof depth counter by 1 again. +% \begin{macrocode} +\intarray_new:Nn\l_@@_counter_intarray{50} +\cs_new_protected:Npn \sproofnumber { + \int_set:Nn \l_tmpa_int {1} + \bool_while_do:nn { + \int_compare_p:nNn { + \intarray_item:Nn \l_@@_counter_intarray \l_tmpa_int + } > 0 + }{ + \intarray_item:Nn \l_@@_counter_intarray \l_tmpa_int . + \int_incr:N \l_tmpa_int + } +} +\cs_new_protected:Npn \_@@_inc_counter: { + \int_set:Nn \l_tmpa_int {1} + \bool_while_do:nn { + \int_compare_p:nNn { + \intarray_item:Nn \l_@@_counter_intarray \l_tmpa_int + } > 0 + }{ + \int_incr:N \l_tmpa_int + } + \int_compare:nNnF \l_tmpa_int = 1 { + \int_decr:N \l_tmpa_int + } + \intarray_gset:Nnn \l_@@_counter_intarray \l_tmpa_int { + \intarray_item:Nn \l_@@_counter_intarray \l_tmpa_int + 1 + } +} + +\cs_new_protected:Npn \_@@_add_counter: { + \int_set:Nn \l_tmpa_int {1} + \bool_while_do:nn { + \int_compare_p:nNn { + \intarray_item:Nn \l_@@_counter_intarray \l_tmpa_int + } > 0 + }{ + \int_incr:N \l_tmpa_int + } + \intarray_gset:Nnn \l_@@_counter_intarray \l_tmpa_int { 1 } +} + +\cs_new_protected:Npn \_@@_remove_counter: { + \int_set:Nn \l_tmpa_int {1} + \bool_while_do:nn { + \int_compare_p:nNn { + \intarray_item:Nn \l_@@_counter_intarray \l_tmpa_int + } > 0 + }{ + \int_incr:N \l_tmpa_int + } + \int_decr:N \l_tmpa_int + \intarray_gset:Nnn \l_@@_counter_intarray \l_tmpa_int { 0 } +} +% \end{macrocode} +% \end{environment} +% +% +%\begin{macro}{\sproofend} +% This macro places a little box at the end of the line if there is space, or at the +% end of the next line if there isn't +% \begin{macrocode} +\def\sproof@box{ + \hbox{\vrule\vbox{\hrule width 6 pt\vskip 6pt\hrule}\vrule} +} +\def\sproofend{ + \tl_if_empty:NF \l_@@_spf_proofend_tl { + \hfil\null\nobreak\hfill\l_@@_spf_proofend_tl\par\smallskip + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{spf@*@kw} +% \begin{macrocode} +\def\spf@proofsketch@kw{Proof~Sketch} +\def\spf@proof@kw{Proof} +\def\spf@step@kw{Step} +% \end{macrocode} +% \end{macro} +% +% For the other languages, we set up triggers +% \begin{macrocode} +\AddToHook{begindocument}{ + \ltx@ifpackageloaded{babel}{ + \makeatletter + \clist_set:Nx \l_tmpa_clist {\bbl@loaded} + \clist_if_in:NnT \l_tmpa_clist {ngerman}{ + \input{sproof-ngerman.ldf} + } + \clist_if_in:NnT \l_tmpa_clist {finnish}{ + \input{sproof-finnish.ldf} + } + \clist_if_in:NnT \l_tmpa_clist {french}{ + \input{sproof-french.ldf} + } + \clist_if_in:NnT \l_tmpa_clist {russian}{ + \input{sproof-russian.ldf} + } + \makeatother + }{} +} +% \end{macrocode} +% +% \begin{macro}{spfsketch} +% \begin{macrocode} +\newcommand\spfsketch[2][]{ + \begingroup + \let \premise \stex_proof_premise: + \_@@_spf_args:n{#1} + \stex_if_smsmode:TF { + \str_if_empty:NF \spfid { + \stex_ref_new_doc_target:n \spfid + } + }{ + \seq_clear:N \l_tmpa_seq + \clist_map_inline:Nn \l_@@_spf_for_clist { + \tl_if_empty:nF{ ##1 }{ + \stex_get_symbol:n { ##1 } + \exp_args:NNo \seq_put_right:Nn \l_tmpa_seq { + \l_stex_get_symbol_uri_str + } + } + } + \exp_args:Nnx + \stex_annotate:nnn{proofsketch}{\seq_use:Nn \l_tmpa_seq {,}}{ + \str_if_empty:NF \spftype { + \stex_annotate_invisible:nnn{type}{\spftype}{} + } + \clist_set:No \l_tmpa_clist \spftype + \tl_set:Nn \l_tmpa_tl { + \titleemph{ + \tl_if_empty:NTF \spftitle { + \spf@proofsketch@kw + }{ + \spftitle + } + }:~ + } + \clist_map_inline:Nn \l_tmpa_clist { + \exp_args:No \str_if_eq:nnT \c_@@_flow_str {##1} { + \tl_clear:N \l_tmpa_tl + } + } + \str_if_empty:NF \spfid { + \stex_ref_new_doc_target:n \spfid + } + \l_tmpa_tl #2 \sproofend + } + } + \endgroup + \stex_smsmode_do: +} + +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{spfeq} +% This is very similar to |\spfsketch|, but uses a computation array\ednote{This should +% really be more like a tabular with an ensuremath in it. or invoke text on the last +% column}\ednote{document above} +% \begin{macrocode} +\newenvironment{spfeq}[2][]{ + \_@@_spf_args:n{#1} + \let \premise \stex_proof_premise: + \stex_if_smsmode:TF { + \str_if_empty:NF \spfid { + \stex_ref_new_doc_target:n \spfid + } + }{ + \seq_clear:N \l_tmpa_seq + \clist_map_inline:Nn \l_@@_spf_for_clist { + \tl_if_empty:nF{ ##1 }{ + \stex_get_symbol:n { ##1 } + \exp_args:NNo \seq_put_right:Nn \l_tmpa_seq { + \l_stex_get_symbol_uri_str + } + } + } + \exp_args:Nnnx + \begin{stex_annotate_env}{spfeq}{\seq_use:Nn \l_tmpa_seq {,}} + \str_if_empty:NF \spftype { + \stex_annotate_invisible:nnn{type}{\spftype}{} + } + + \clist_set:No \l_tmpa_clist \spftype + \tl_clear:N \l_tmpa_tl + \clist_map_inline:Nn \l_tmpa_clist { + \tl_if_exist:cT {_@@_spfeq_##1_start:}{ + \tl_set:Nn \l_tmpa_tl {\use:c{_@@_spfeq_##1_start:}} + } + \exp_args:No \str_if_eq:nnT \c_@@_flow_str {##1} { + \tl_set:Nn \l_tmpa_tl {\use:n{}} + } + } + \tl_if_empty:NTF \l_tmpa_tl { + \_@@_spfeq_start: + }{ + \l_tmpa_tl + }{~#2} + \str_if_empty:NF \spfid { + \stex_ref_new_doc_target:n \spfid + } + \begin{displaymath}\begin{array}{rcll} + } + \stex_smsmode_do: +}{ + \stex_if_smsmode:F { + \end{array}\end{displaymath} + \clist_set:No \l_tmpa_clist \spftype + \tl_clear:N \l_tmpa_tl + \clist_map_inline:Nn \l_tmpa_clist { + \tl_if_exist:cT {_@@_spfeq_##1_end:}{ + \tl_set:Nn \l_tmpa_tl {\use:c{_@@_spfeq_##1_end:}} + } + } + \tl_if_empty:NTF \l_tmpa_tl { + \_@@_spfeq_end: + }{ + \l_tmpa_tl + } + \end{stex_annotate_env} + } +} + +\cs_new_protected:Nn \_@@_spfeq_start: { + \titleemph{ + \tl_if_empty:NTF \spftitle { + \spf@proof@kw + }{ + \spftitle + } + }: +} +\cs_new_protected:Nn \_@@_spfeq_end: {\sproofend} + +\newcommand\stexpatchspfeq[3][] { + \str_set:Nx \l_tmpa_str{ #1 } + \str_if_empty:NTF \l_tmpa_str { + \tl_set:Nn \_@@_spfeq_start: { #2 } + \tl_set:Nn \_@@_spfeq_end: { #3 } + }{ + \exp_after:wN \tl_set:Nn \csname _@@_spfeq_#1_start:\endcsname{ #2 } + \exp_after:wN \tl_set:Nn \csname _@@_spfeq_#1_end:\endcsname{ #3 } + } +} + +% \end{macrocode} +% \end{macro} +% +% \begin{environment}{sproof} +% In this environment, we initialize the proof depth counter |\count10| to 10, and set +% up the description environment that will take the proof steps. At the end of the +% proof, we position the proof end into the last line. +% \begin{macrocode} +\newenvironment{sproof}[2][]{ + \let \premise \stex_proof_premise: + \intarray_gzero:N \l_@@_counter_intarray + \intarray_gset:Nnn \l_@@_counter_intarray 1 1 + \_@@_spf_args:n{#1} + \stex_if_smsmode:TF { + \str_if_empty:NF \spfid { + \stex_ref_new_doc_target:n \spfid + } + }{ + \seq_clear:N \l_tmpa_seq + \clist_map_inline:Nn \l_@@_spf_for_clist { + \tl_if_empty:nF{ ##1 }{ + \stex_get_symbol:n { ##1 } + \exp_args:NNo \seq_put_right:Nn \l_tmpa_seq { + \l_stex_get_symbol_uri_str + } + } + } + \exp_args:Nnnx + \begin{stex_annotate_env}{sproof}{\seq_use:Nn \l_tmpa_seq {,}} + \str_if_empty:NF \spftype { + \stex_annotate_invisible:nnn{type}{\spftype}{} + } + + \clist_set:No \l_tmpa_clist \spftype + \tl_clear:N \l_tmpa_tl + \clist_map_inline:Nn \l_tmpa_clist { + \tl_if_exist:cT {_@@_sproof_##1_start:}{ + \tl_set:Nn \l_tmpa_tl {\use:c{_@@_sproof_##1_start:}} + } + \exp_args:No \str_if_eq:nnT \c_@@_flow_str {##1} { + \tl_set:Nn \l_tmpa_tl {\use:n{}} + } + } + \tl_if_empty:NTF \l_tmpa_tl { + \_@@_sproof_start: + }{ + \l_tmpa_tl + }{~#2} + \str_if_empty:NF \spfid { + \stex_ref_new_doc_target:n \spfid + } + \begin{description} + } + \stex_smsmode_do: +}{ + \stex_if_smsmode:F{ + \end{description} + \clist_set:No \l_tmpa_clist \spftype + \tl_clear:N \l_tmpa_tl + \clist_map_inline:Nn \l_tmpa_clist { + \tl_if_exist:cT {_@@_sproof_##1_end:}{ + \tl_set:Nn \l_tmpa_tl {\use:c{_@@_sproof_##1_end:}} + } + } + \tl_if_empty:NTF \l_tmpa_tl { + \_@@_sproof_end: + }{ + \l_tmpa_tl + } + \end{stex_annotate_env} + } +} + +\cs_new_protected:Nn \_@@_sproof_start: { + \par\noindent\titleemph{ + \tl_if_empty:NTF \spftype { + \spf@proof@kw + }{ + \spftype + } + }: +} +\cs_new_protected:Nn \_@@_sproof_end: {\sproofend} + +\newcommand\stexpatchsproof[3][] { + \str_set:Nx \l_tmpa_str{ #1 } + \str_if_empty:NTF \l_tmpa_str { + \tl_set:Nn \_@@_sproof_start: { #2 } + \tl_set:Nn \_@@_sproof_end: { #3 } + }{ + \exp_after:wN \tl_set:Nn \csname _@@_sproof_#1_start:\endcsname{ #2 } + \exp_after:wN \tl_set:Nn \csname _@@_sproof_#1_end:\endcsname{ #3 } + } +} +% \end{macrocode} +% \end{environment} +% +% \begin{macro}{\spfidea} +% \begin{macrocode} +\newcommand\spfidea[2][]{ + \_@@_spf_args:n{#1} + \titleemph{ + \tl_if_empty:NTF \spftype {Proof~Idea}{ + \spftype + }: + }~#2 + \sproofend +} +% \end{macrocode} +% \end{macro} +% +% The next two environments (proof steps) and comments, are mostly semantical, they take +% |KeyVal| arguments that specify their semantic role. In draft mode, they read these +% values and show them. If the surrounding proof had |display=flow|, then no new |\item| is +% generated, otherwise it is. In any case, the proof step number (at the current level) is +% incremented. +% \begin{environment}{spfstep} +% \begin{macrocode} +\newenvironment{spfstep}[1][]{ + \_@@_spf_args:n{#1} + \stex_if_smsmode:TF { + \str_if_empty:NF \spfid { + \stex_ref_new_doc_target:n \spfid + } + }{ + \@in@omtexttrue + \seq_clear:N \l_tmpa_seq + \clist_map_inline:Nn \l_@@_spf_for_clist { + \tl_if_empty:nF{ ##1 }{ + \stex_get_symbol:n { ##1 } + \exp_args:NNo \seq_put_right:Nn \l_tmpa_seq { + \l_stex_get_symbol_uri_str + } + } + } + \exp_args:Nnnx + \begin{stex_annotate_env}{spfstep}{\seq_use:Nn \l_tmpa_seq {,}} + \str_if_empty:NF \spftype { + \stex_annotate_invisible:nnn{type}{\spftype}{} + } + \clist_set:No \l_tmpa_clist \spftype + \tl_set:Nn \l_tmpa_tl { + \item[\sproofnumber] + \bool_set_true:N \l_@@_inc_counter_bool + } + \clist_map_inline:Nn \l_tmpa_clist { + \exp_args:No \str_if_eq:nnT \c_@@_flow_str {##1} { + \tl_clear:N \l_tmpa_tl + } + } + \l_tmpa_tl + \tl_if_empty:NF \spftitle { + {(\titleemph{\spftitle})\enspace} + } + \str_if_empty:NF \spfid { + \stex_ref_new_doc_target:n \spfid + } + } + \stex_smsmode_do: + \ignorespacesandpars +}{ + \bool_if:NT \l_@@_inc_counter_bool { + \_@@_inc_counter: + } + \stex_if_smsmode:F { + \end{stex_annotate_env} + } +} +% \end{macrocode} +% \end{environment} +% +% \begin{environment}{sproofcomment} +% \begin{macrocode} +\newenvironment{sproofcomment}[1][]{ + \_@@_spf_args:n{#1} + \clist_set:No \l_tmpa_clist \spftype + \tl_set:Nn \l_tmpa_tl { + \item[\sproofnumber] + \bool_set_true:N \l_@@_inc_counter_bool + } + \clist_map_inline:Nn \l_tmpa_clist { + \exp_args:No \str_if_eq:nnT \c_@@_flow_str {##1} { + \tl_clear:N \l_tmpa_tl + } + } + \l_tmpa_tl +}{ + \bool_if:NT \l_@@_inc_counter_bool { + \_@@_inc_counter: + } +} +% \end{macrocode} +% \end{environment} +% +% The next two environments also take a |KeyVal| argument, but also a regular one, which +% contains a start text. Both environments start a new numbered proof level. +% +% \begin{environment}{subproof} +% In the |subproof| environment, a new (lower-level) proproofof environment is started. +% \begin{macrocode} +\newenvironment{subproof}[2][]{ + \_@@_spf_args:n{#1} + \stex_if_smsmode:TF{ + \str_if_empty:NF \spfid { + \stex_ref_new_doc_target:n \spfid + } + }{ + \seq_clear:N \l_tmpa_seq + \clist_map_inline:Nn \l_@@_spf_for_clist { + \tl_if_empty:nF{ ##1 }{ + \stex_get_symbol:n { ##1 } + \exp_args:NNo \seq_put_right:Nn \l_tmpa_seq { + \l_stex_get_symbol_uri_str + } + } + } + \exp_args:Nnnx + \begin{stex_annotate_env}{subproof}{\seq_use:Nn \l_tmpa_seq {,}} + \str_if_empty:NF \spftype { + \stex_annotate_invisible:nnn{type}{\spftype}{} + } + + \clist_set:No \l_tmpa_clist \spftype + \tl_set:Nn \l_tmpa_tl { + \item[\sproofnumber] + \bool_set_true:N \l_@@_inc_counter_bool + } + \clist_map_inline:Nn \l_tmpa_clist { + \exp_args:No \str_if_eq:nnT \c_@@_flow_str {##1} { + \tl_clear:N \l_tmpa_tl + } + } + \l_tmpa_tl + \tl_if_empty:NF \spftitle { + {(\titleemph{\spftitle})\enspace} + } + {~#2} + \str_if_empty:NF \spfid { + \stex_ref_new_doc_target:n \spfid + } + } + \_@@_add_counter: + \stex_smsmode_do: +}{ + \_@@_remove_counter: + \bool_if:NT \l_@@_inc_counter_bool { + \_@@_inc_counter: + } + \stex_if_smsmode:F{ + \end{stex_annotate_env} + } +} +% \end{macrocode} +% \end{environment} +% +% \begin{environment}{spfcases} +% In the |pfcases| environment, the start text is displayed as the first comment of the +% proof. +% \begin{macrocode} +\newenvironment{spfcases}[2][]{ + \tl_if_empty:nTF{#1}{ + \begin{subproof}[method=by-cases]{#2} + }{ + \begin{subproof}[#1,method=by-cases]{#2} + } +}{ + \end{subproof} +} +% \end{macrocode} +% \end{environment} +% +% \begin{environment}{spfcase} +% In the |pfcase| environment, the start text is displayed specification of the case +% after the |\item| +% \begin{macrocode} +\newenvironment{spfcase}[2][]{ + \_@@_spf_args:n{#1} + \stex_if_smsmode:TF { + \str_if_empty:NF \spfid { + \stex_ref_new_doc_target:n \spfid + } + }{ + \seq_clear:N \l_tmpa_seq + \clist_map_inline:Nn \l_@@_spf_for_clist { + \tl_if_empty:nF{ ##1 }{ + \stex_get_symbol:n { ##1 } + \exp_args:NNo \seq_put_right:Nn \l_tmpa_seq { + \l_stex_get_symbol_uri_str + } + } + } + \exp_args:Nnnx + \begin{stex_annotate_env}{spfcase}{\seq_use:Nn \l_tmpa_seq {,}} + \str_if_empty:NF \spftype { + \stex_annotate_invisible:nnn{type}{\spftype}{} + } + \clist_set:No \l_tmpa_clist \spftype + \tl_set:Nn \l_tmpa_tl { + \item[\sproofnumber] + \bool_set_true:N \l_@@_inc_counter_bool + } + \clist_map_inline:Nn \l_tmpa_clist { + \exp_args:No \str_if_eq:nnT \c_@@_flow_str {##1} { + \tl_clear:N \l_tmpa_tl + } + } + \l_tmpa_tl + \tl_if_empty:nF{#2}{ + \titleemph{#2}:~ + } + } + \_@@_add_counter: + \stex_smsmode_do: +}{ + \_@@_remove_counter: + \bool_if:NT \l_@@_inc_counter_bool { + \_@@_inc_counter: + } + \stex_if_smsmode:F{ + \clist_set:No \l_tmpa_clist \spftype + \tl_set:Nn \l_tmpa_tl{\sproofend} + \clist_map_inline:Nn \l_tmpa_clist { + \exp_args:No \str_if_eq:nnT \c_@@_flow_str {##1} { + \tl_clear:N \l_tmpa_tl + } + } + \l_tmpa_tl + \end{stex_annotate_env} + } +} +% \end{macrocode} +% \end{environment} +% +% \begin{environment}{spfcase} +% similar to |spfcase|, takes a third argument. +% \begin{macrocode} +\newcommand\spfcasesketch[3][]{ + \begin{spfcase}[#1]{#2}#3\end{spfcase} +} +% \end{macrocode} +% \end{environment} +% +% \subsection{Justifications} +% +% We define the actions that are undertaken, when the keys for justifications are +% encountered. Here this is very simple, we just define an internal macro with the value, +% so that we can use it later. +% \begin{macrocode} +\keys_define:nn { stex / just }{ + id .str_set_x:N = \l_@@_just_id_str, + method .tl_set:N = \l_@@_just_method_tl, + premises .tl_set:N = \l_@@_just_premises_tl, + args .tl_set:N = \l_@@_just_args_tl +} +% \end{macrocode} +% +% The next three environments and macros are purely semantic, so we ignore the keyval +% arguments for now and only display the content.\ednote{need to do something about the +% premise in draft mode.} +% +% \begin{environment}{justification} +% \begin{macrocode} +\newenvironment{justification}[1][]{}{} +% \end{macrocode} +% \end{environment} +% +% \begin{macro}{\premise} +% \begin{macrocode} +\newcommand\stex_proof_premise:[2][]{#2} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\justarg} +% the |\justarg| macro is purely semantic, so we ignore the keyval arguments for now and +% only display the content. +% \begin{macrocode} +\newcommand\justarg[2][]{#2} +%</package> +% \end{macrocode} +% \end{macro} +% \end{implementation} +% \Finale +\endinput +%%% Local Variables: +%%% mode: doctex +%%% TeX-master: t +%%% End: +% LocalWords: GPL structuresharing STR sproof dtx CPERL keyval methodfalse env +% LocalWords: methodtrue envtrue medhodtrue DefKeyVal Semiverbatim omdoc args +% LocalWords: DefEnvironment OptionalKeyVals KeyVal omtext DefConstructor str +% LocalWords: proofidea KeyVal pfstep DefCMPEnvironment KeyVal proofcomment eq +% LocalWords: KeyVal pfcases KeyVal pfcase KeyVal extractBodyText unlist elsif +% LocalWords: foreach getBody toString str str str LookupValue LastSeenCMP Thu +% LocalWords: appendText getValue undef openElement closeElement DefMacro omd +% LocalWords: afterClose nodeType childNodes firstCMP localname hasChildNodes +% LocalWords: firstChild textContent removeChild iffalse kohlhase sref scsys +% LocalWords: sproofs.sty sc sc mathml openmath latexml cmathml activemath geq +% LocalWords: twintoo atwin atwintoo texttt fileversion maketitle stex newpage +% LocalWords: tableofcontents newpage exfig scriptsize vspace ednote spfidea +% LocalWords: spfidea spfsketch spfsketch spfstep justarg spfcases spfcase rhs +% LocalWords: sproofcomment ind-hyp splitit arith byindhyp sproofend proofend +% LocalWords: printbibliography textsf langle textsf langle ltxml ctancite spf +% LocalWords: srefaddidkey pf.sty newenvironment hbox vrule vbox ifx showmeta +% LocalWords: hrule vskip hrule vrule hfil nobreak hfill smallskip newcommand +% LocalWords: stDMemph newcount endsproof xref doctex showmeta hline lec ldots +% LocalWords: textbackslash makeatletter sketchproof compactenum tracissue +% LocalWords: metakeys addmetakey metasetkeys stylable pstlabelstyle pstlabel +% LocalWords: pstlabelstyle pstlabelstyle ldots ldots ensuremath inparaenum +% LocalWords: nameuse prooflistenv spfcasesketch spfcasesketch spfeq rcll +% LocalWords: displaymath noindent ignorespaces diff --git a/macros/latex/contrib/stex/source/stex/statements.dtx b/macros/latex/contrib/stex/source/stex/statements.dtx new file mode 100644 index 0000000000..3ddeca0dbd --- /dev/null +++ b/macros/latex/contrib/stex/source/stex/statements.dtx @@ -0,0 +1,908 @@ +% \iffalse meta-comment +% An Infrastructure for Semantic Macros and Module Scoping +% Copyright (c) 2019 Michael Kohlhase, all rights reserved +% this file is released under the +% LaTeX Project Public License (LPPL) +% +% The original of this file is in the public repository at +% http://github.com/sLaTeX/sTeX/ +% +% TODO update copyright +% +%<*driver> +\providecommand\bibfolder{../../lib/bib} +\input{../../doc/docheader} + +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{ \sTeX-Statements +% \thanks{Version {\fileversion} (last revised {\filedate})} +% } +% +% \author{Michael Kohlhase, Dennis Müller\\ +% FAU Erlangen-Nürnberg\\ +% \url{http://kwarc.info/} +% } +% +% \maketitle +% +%\ifinfulldoc\else +% This is the documentation for the \pkg{stex-statements} package. +% For a more high-level introduction, +% see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the +% \href{\basedocurl/stex.pdf}{full \sTeX documentation}. +% +% \input{../../doc/packages/statements} +% \fi +% +% \begin{documentation}\label{pkg:statements:doc} +% +% Code related to statements, e.g. definitions, theorems +% +% \section{Macros and Environments}\label{pkg:statements:doc:macros} +% +% \begin{environment}{symboldoc} +% \begin{syntax} \cs{begin}\Arg{symboldoc}\Arg{symbols} \meta{text} \cs{end}\Arg{symboldoc} \end{syntax} +% Declares \meta{text} to be a (natural language, encyclopaedic) description +% of \Arg{symbols} (a comma separated list of symbol identifiers). +% \end{environment} +% +% \end{documentation} +% +% \begin{implementation}\label{pkg:statements:impl} +% +% \section{\sTeX-Statements Implementation} +% +% \begin{macrocode} +%<*package> + +%%%%%%%%%%%%% features.dtx %%%%%%%%%%%%% + +%<@@=stex_statements> +% \end{macrocode} +% +% Warnings and error messages +% +% \begin{macrocode} + +% \end{macrocode} +% \begin{macro}{\titleemph} +% \begin{macrocode} +\def\titleemph#1{\textbf{#1}} +% \end{macrocode} +% \end{macro} +% +% \subsection{Definitions} +% +% \begin{macro}{definiendum} +% \begin{macrocode} +\keys_define:nn {stex / definiendum }{ + pre .tl_set:N = \l_@@_definiendum_pre_tl, + post .tl_set:N = \l_@@_definiendum_post_tl, + root .str_set_x:N = \l_@@_definiendum_root_str, + gfa .str_set_x:N = \l_@@_definiendum_gfa_str +} +\cs_new_protected:Nn \_@@_definiendum_args:n { + \str_clear:N \l_@@_definiendum_root_str + \tl_clear:N \l_@@_definiendum_post_tl + \str_clear:N \l_@@_definiendum_gfa_str + \keys_set:nn { stex / definiendum }{ #1 } +} +\NewDocumentCommand \definiendum { O{} m m} { + \_@@_definiendum_args:n { #1 } + \stex_get_symbol:n { #2 } + \stex_ref_new_sym_target:n \l_stex_get_symbol_uri_str + \str_if_empty:NTF \l_@@_definiendum_root_str { + \tl_if_empty:NTF \l_@@_definiendum_post_tl { + \tl_set:Nn \l_tmpa_tl { #3 } + } { + \str_set:Nx \l_@@_definiendum_root_str { #3 } + \tl_set:Nn \l_tmpa_tl { + \l_@@_definiendum_pre_tl\l_@@_definiendum_root_str\l_@@_definiendum_post_tl + } + } + } { + \tl_set:Nn \l_tmpa_tl { #3 } + } + + % TODO root + \rustex_if:TF { + \stex_annotate:nnn { definiendum } { \l_stex_get_symbol_uri_str } { \l_tmpa_tl } + } { + \exp_args:Nnx \defemph@uri { \l_tmpa_tl } { \l_stex_get_symbol_uri_str } + } +} +\stex_deactivate_macro:Nn \definiendum {definition~environments} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{definame} +% \begin{macrocode} + +\NewDocumentCommand \definame { O{} m } { + \_@@_definiendum_args:n { #1 } + % TODO: root + \stex_get_symbol:n { #2 } + \stex_ref_new_sym_target:n \l_stex_get_symbol_uri_str + \str_set:Nx \l_tmpa_str { + \prop_item:cn { l_stex_symdecl_ \l_stex_get_symbol_uri_str _prop } { name } + } + \exp_args:NNno \str_replace_all:Nnn \l_tmpa_str {-} {~} + \rustex_if:TF { + \stex_annotate:nnn { definiendum } { \l_stex_get_symbol_uri_str } { + \l_tmpa_str\l_@@_definiendum_post_tl + } + } { + \defemph@uri { + \l_tmpa_str\l_@@_definiendum_post_tl + } { \l_stex_get_symbol_uri_str } + } +} +\stex_deactivate_macro:Nn \definame {definition~environments} + +\NewDocumentCommand \Definame { O{} m } { + \_@@_definiendum_args:n { #1 } + \stex_get_symbol:n { #2 } + \str_set:Nx \l_tmpa_str { + \prop_item:cn { l_stex_symdecl_ \l_stex_get_symbol_uri_str _prop } { name } + } + \exp_args:NNno \str_replace_all:Nnn \l_tmpa_str {-} {~} + \stex_ref_new_sym_target:n \l_stex_get_symbol_uri_str + \rustex_if:TF { + \stex_annotate:nnn { definiendum } { \l_stex_get_symbol_uri_str } { + \l_tmpa_str\l__stex_statements_definiendum_post_tl + } + } { + \defemph@uri { + \exp_after:wN \stex_capitalize:n \l_tmpa_str\l__stex_statements_definiendum_post_tl + } { \l_stex_get_symbol_uri_str } + } +} +\stex_deactivate_macro:Nn \Definame {definition~environments} + +\NewDocumentCommand \premise { m }{ + \stex_annotate:nnn{ premise }{}{ #1 } +} +\NewDocumentCommand \conclusion { m }{ + \stex_annotate:nnn{ conclusion }{}{ #1 } +} +\NewDocumentCommand \definiens { m }{ + \stex_annotate:nnn{ definiens }{}{ #1 } +} + +\stex_deactivate_macro:Nn \premise {definition,~example~or~assertion~environments} +\stex_deactivate_macro:Nn \conclusion {example~or~assertion~environments} +\stex_deactivate_macro:Nn \definiens {definition~environments} + +% \end{macrocode} +% \end{macro} +% +% \begin{environment}{sdefinition} +% \begin{macrocode} + +\keys_define:nn {stex / sdefinition }{ + type .str_set_x:N = \sdefinitiontype, + id .str_set_x:N = \sdefinitionid, + name .str_set_x:N = \sdefinitionname, + for .clist_set:N = \l_@@_sdefinition_for_clist , + title .tl_set:N = \sdefinitiontitle +} +\cs_new_protected:Nn \_@@_sdefinition_args:n { + \str_clear:N \sdefinitiontype + \str_clear:N \sdefinitionid + \str_clear:N \sdefinitionname + \clist_clear:N \l_@@_sdefinition_for_clist + \tl_clear:N \sdefinitiontitle + \keys_set:nn { stex / sdefinition }{ #1 } +} + +\NewDocumentEnvironment{sdefinition}{O{}}{ + \_@@_sdefinition_args:n{ #1 } + \stex_reactivate_macro:N \definiendum + \stex_reactivate_macro:N \definame + \stex_reactivate_macro:N \Definame + \stex_reactivate_macro:N \premise + \stex_reactivate_macro:N \definiens + \stex_if_smsmode:F{ + \seq_clear:N \l_tmpa_seq + \clist_map_inline:Nn \l_@@_sdefinition_for_clist { + \tl_if_empty:nF{ ##1 }{ + \stex_get_symbol:n { ##1 } + \exp_args:NNo \seq_put_right:Nn \l_tmpa_seq { + \l_stex_get_symbol_uri_str + } + } + } + \exp_args:Nnnx + \begin{stex_annotate_env}{definition}{\seq_use:Nn \l_tmpa_seq {,}} + \str_if_empty:NF \sdefinitiontype { + \stex_annotate_invisible:nnn{type}{\sdefinitiontype}{} + } + \clist_set:No \l_tmpa_clist \sdefinitiontype + \tl_clear:N \l_tmpa_tl + \clist_map_inline:Nn \l_tmpa_clist { + \tl_if_exist:cT {_@@_sdefinition_##1_start:}{ + \tl_set:Nn \l_tmpa_tl {\use:c{_@@_sdefinition_##1_start:}} + } + } + \tl_if_empty:NTF \l_tmpa_tl { + \_@@_sdefinition_start: + }{ + \l_tmpa_tl + } + } + \stex_ref_new_doc_target:n \sdefinitionid + \stex_smsmode_do: +}{ + \str_if_empty:NF \sdefinitionname { \stex_symdecl_do:nn{}{\sdefinitionname} } + \stex_if_smsmode:F { + \clist_set:No \l_tmpa_clist \sdefinitiontype + \tl_clear:N \l_tmpa_tl + \clist_map_inline:Nn \l_tmpa_clist { + \tl_if_exist:cT {_@@_sdefinition_##1_end:}{ + \tl_set:Nn \l_tmpa_tl {\use:c{_@@_sdefinition_##1_end:}} + } + } + \tl_if_empty:NTF \l_tmpa_tl { + \_@@_sdefinition_end: + }{ + \l_tmpa_tl + } + \end{stex_annotate_env} + } +} +% \end{macrocode} +% \end{environment} +% +% \begin{macro}{\stexpatchdefinition} +% \begin{macrocode} +\cs_new_protected:Nn \_@@_sdefinition_start: { + \par\noindent\titleemph{Definition\tl_if_empty:NF \sdefinitiontitle { + ~(\sdefinitiontitle) + }~} +} +\cs_new_protected:Nn \_@@_sdefinition_end: {\par\medskip} + +\newcommand\stexpatchdefinition[3][] { + \str_set:Nx \l_tmpa_str{ #1 } + \str_if_empty:NTF \l_tmpa_str { + \tl_set:Nn \_@@_sdefinition_start: { #2 } + \tl_set:Nn \_@@_sdefinition_end: { #3 } + }{ + \exp_after:wN \tl_set:Nn \csname _@@_sdefinition_#1_start:\endcsname{ #2 } + \exp_after:wN \tl_set:Nn \csname _@@_sdefinition_#1_end:\endcsname{ #3 } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\inlinedef} +% inline: +% \begin{macrocode} +\keys_define:nn {stex / inlinedef }{ + type .str_set_x:N = \sdefinitiontype, + id .str_set_x:N = \sdefinitionid, + for .clist_set:N = \l_@@_sdefinition_for_clist , + name .str_set_x:N = \sdefinitionname +} +\cs_new_protected:Nn \_@@_inlinedef_args:n { + \str_clear:N \sdefinitiontype + \str_clear:N \sdefinitionid + \str_clear:N \sdefinitionname + \clist_clear:N \l_@@_sdefinition_for_clist + \keys_set:nn { stex / inlinedef }{ #1 } +} +\NewDocumentCommand \inlinedef { O{} m } { + \begingroup + \_@@_inlinedef_args:n{ #1 } + \stex_reactivate_macro:N \definiendum + \stex_reactivate_macro:N \definame + \stex_reactivate_macro:N \Definame + \stex_reactivate_macro:N \premise + \stex_reactivate_macro:N \definiens + \stex_ref_new_doc_target:n \sdefinitionid + \stex_if_smsmode:TF{ + \str_if_empty:NF \sdefinitionname { \stex_symdecl_do:nn{}{\sdefinitionname} } + }{ + \seq_clear:N \l_tmpa_seq + \clist_map_inline:Nn \l_@@_sdefinition_for_clist { + \tl_if_empty:nF{ ##1 }{ + \stex_get_symbol:n { ##1 } + \exp_args:NNo \seq_put_right:Nn \l_tmpa_seq { + \l_stex_get_symbol_uri_str + } + } + } + \exp_args:Nnx + \stex_annotate:nnn{definition}{\seq_use:Nn \l_tmpa_seq {,}}{ + \str_if_empty:NF \sdefinitiontype { + \stex_annotate_invisible:nnn{type}{\sdefinitiontype}{} + } + #2 + \str_if_empty:NF \sdefinitionname { \stex_symdecl_do:nn{}{\sdefinitionname} } + } + } + \endgroup + \stex_smsmode_do: +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Assertions} +% +% \begin{environment}{sassertion} +% \begin{macrocode} + +\keys_define:nn {stex / sassertion }{ + type .str_set_x:N = \sassertiontype, + id .str_set_x:N = \sassertionid, + title .tl_set:N = \sassertiontitle , + for .clist_set:N = \l_@@_sassertion_for_clist , + name .str_set_x:N = \sassertionname +} +\cs_new_protected:Nn \_@@_sassertion_args:n { + \str_clear:N \sassertiontype + \str_clear:N \sassertionid + \str_clear:N \sassertionname + \clist_clear:N \l_@@_sassertion_for_clist + \tl_clear:N \sassertiontitle + \keys_set:nn { stex / sassertion }{ #1 } +} + +%\tl_new:N \g_@@_aftergroup_tl + +\NewDocumentEnvironment{sassertion}{O{}}{ + \_@@_sassertion_args:n{ #1 } + \stex_reactivate_macro:N \premise + \stex_reactivate_macro:N \conclusion + \stex_if_smsmode:F { + \seq_clear:N \l_tmpa_seq + \clist_map_inline:Nn \l_@@_sassertion_for_clist { + \tl_if_empty:nF{ ##1 }{ + \stex_get_symbol:n { ##1 } + \exp_args:NNo \seq_put_right:Nn \l_tmpa_seq { + \l_stex_get_symbol_uri_str + } + } + } + \exp_args:Nnnx + \begin{stex_annotate_env}{assertion}{\seq_use:Nn \l_tmpa_seq {,}} + \str_if_empty:NF \sassertiontype { + \stex_annotate_invisible:nnn{type}{\sassertiontype}{} + } + \clist_set:No \l_tmpa_clist \sassertiontype + \tl_clear:N \l_tmpa_tl + \clist_map_inline:Nn \l_tmpa_clist { + \tl_if_exist:cT {_@@_sassertion_##1_start:}{ + \tl_set:Nn \l_tmpa_tl {\use:c{_@@_sassertion_##1_start:}} + } + } + \tl_if_empty:NTF \l_tmpa_tl { + \_@@_sassertion_start: + }{ + \l_tmpa_tl + } + } + \str_if_empty:NTF \sassertionid { + \str_if_empty:NF \sassertionname { + \stex_ref_new_doc_target:n {} + } + } { + \stex_ref_new_doc_target:n \sassertionid + } + \stex_smsmode_do: +}{ + \str_if_empty:NF \sassertionname { + \stex_symdecl_do:nn{}{\sassertionname} + \stex_ref_new_sym_target:n {\l_stex_current_module_str ? \sassertionname} + } + \stex_if_smsmode:F { + \clist_set:No \l_tmpa_clist \sassertiontype + \tl_clear:N \l_tmpa_tl + \clist_map_inline:Nn \l_tmpa_clist { + \tl_if_exist:cT {_@@_sassertion_##1_end:}{ + \tl_set:Nn \l_tmpa_tl {\use:c{_@@_sassertion_##1_end:}} + } + } + \tl_if_empty:NTF \l_tmpa_tl { + \_@@_sassertion_end: + }{ + \l_tmpa_tl + } + \end{stex_annotate_env} + } +} +% \end{macrocode} +% \end{environment} +% +% \begin{macro}{\stexpatchassertion} +% \begin{macrocode} + +\cs_new_protected:Nn \_@@_sassertion_start: { + \par\noindent\titleemph{Assertion~\tl_if_empty:NF \sassertiontitle { + (\sassertiontitle) + }~} +} +\cs_new_protected:Nn \_@@_sassertion_end: {\par\medskip} + +\newcommand\stexpatchassertion[3][] { + \str_set:Nx \l_tmpa_str{ #1 } + \str_if_empty:NTF \l_tmpa_str { + \tl_set:Nn \_@@_sassertion_start: { #2 } + \tl_set:Nn \_@@_sassertion_end: { #3 } + }{ + \exp_after:wN \tl_set:Nn \csname _@@_sassertion_#1_start:\endcsname{ #2 } + \exp_after:wN \tl_set:Nn \csname _@@_sassertion_#1_end:\endcsname{ #3 } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\inlineass} +% inline: +% \begin{macrocode} +\keys_define:nn {stex / inlineass }{ + type .str_set_x:N = \sassertiontype, + id .str_set_x:N = \sassertionid, + for .clist_set:N = \l_@@_sassertion_for_clist , + name .str_set_x:N = \sassertionname +} +\cs_new_protected:Nn \_@@_inlineass_args:n { + \str_clear:N \sassertiontype + \str_clear:N \sassertionid + \str_clear:N \sassertionname + \clist_clear:N \l_@@_sassertion_for_clist + \keys_set:nn { stex / inlineass }{ #1 } +} +\NewDocumentCommand \inlineass { O{} m } { + \begingroup + \stex_reactivate_macro:N \premise + \stex_reactivate_macro:N \conclusion + \_@@_inlineass_args:n{ #1 } + \str_if_empty:NTF \sassertionid { + \str_if_empty:NF \sassertionname { + \stex_ref_new_doc_target:n {} + } + } { + \stex_ref_new_doc_target:n \sassertionid + } + + \stex_if_smsmode:TF{ + \str_if_empty:NF \sassertionname { + \stex_symdecl_do:nn{}{\sassertionname} + \stex_ref_new_sym_target:n {\l_stex_current_module_str ? \sassertionname} + } + }{ + \seq_clear:N \l_tmpa_seq + \clist_map_inline:Nn \l_@@_sassertion_for_clist { + \tl_if_empty:nF{ ##1 }{ + \stex_get_symbol:n { ##1 } + \exp_args:NNo \seq_put_right:Nn \l_tmpa_seq { + \l_stex_get_symbol_uri_str + } + } + } + \exp_args:Nnx + \stex_annotate:nnn{assertion}{\seq_use:Nn \l_tmpa_seq {,}}{ + \str_if_empty:NF \sassertiontype { + \stex_annotate_invisible:nnn{type}{\sassertiontype}{} + } + #2 + \str_if_empty:NF \sassertionname { + \stex_symdecl_do:nn{}{\sassertionname} + \stex_ref_new_sym_target:n {\l_stex_current_module_str ? \sassertionname} + } + } + } + \endgroup + \stex_smsmode_do: +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Examples} +% +% \begin{environment}{sexample} +% \begin{macrocode} + +\keys_define:nn {stex / sexample }{ + type .str_set_x:N = \exampletype, + id .str_set_x:N = \sexampleid, + title .tl_set:N = \sexampletitle, + for .clist_set:N = \l_@@_sexample_for_clist, +} +\cs_new_protected:Nn \_@@_sexample_args:n { + \str_clear:N \sexampletype + \str_clear:N \sexampleid + \tl_clear:N \sexampletitle + \clist_clear:N \l_@@_sexample_for_clist + \keys_set:nn { stex / sexample }{ #1 } +} + +\NewDocumentEnvironment{sexample}{O{}}{ + \_@@_sexample_args:n{ #1 } + \stex_reactivate_macro:N \premise + \stex_reactivate_macro:N \conclusion + \stex_if_smsmode:F { + \seq_clear:N \l_tmpa_seq + \clist_map_inline:Nn \l_@@_sexample_for_clist { + \tl_if_empty:nF{ ##1 }{ + \stex_get_symbol:n { ##1 } + \exp_args:NNo \seq_put_right:Nn \l_tmpa_seq { + \l_stex_get_symbol_uri_str + } + } + } + \exp_args:Nnnx + \begin{stex_annotate_env}{example}{\seq_use:Nn \l_tmpa_seq {,}} + \str_if_empty:NF \sexampletype { + \stex_annotate_invisible:nnn{type}{\sexampletype}{} + } + \clist_set:No \l_tmpa_clist \sexampletype + \tl_clear:N \l_tmpa_tl + \clist_map_inline:Nn \l_tmpa_clist { + \tl_if_exist:cT {_@@_sexample_##1_start:}{ + \tl_set:Nn \l_tmpa_tl {\use:c{_@@_sexample_##1_start:}} + } + } + \tl_if_empty:NTF \l_tmpa_tl { + \_@@_sexample_start: + }{ + \l_tmpa_tl + } + } + \str_if_empty:NF \sexampleid { + \stex_ref_new_doc_target:n \sexampleid + } + \stex_smsmode_do: +}{ + \str_if_empty:NF \sexamplename { \stex_symdecl_do:nn{}{\sexamplename} } + \stex_if_smsmode:F { + \clist_set:No \l_tmpa_clist \sexampletype + \tl_clear:N \l_tmpa_tl + \clist_map_inline:Nn \l_tmpa_clist { + \tl_if_exist:cT {_@@_sexample_##1_end:}{ + \tl_set:Nn \l_tmpa_tl {\use:c{_@@_sexample_##1_end:}} + } + } + \tl_if_empty:NTF \l_tmpa_tl { + \_@@_sexample_end: + }{ + \l_tmpa_tl + } + \end{stex_annotate_env} + } +} +% \end{macrocode} +% \end{environment} +% +% \begin{macro}{\stexpatchexample} +% \begin{macrocode} + +\cs_new_protected:Nn \_@@_sexample_start: { + \par\noindent\titleemph{Example~\tl_if_empty:NF \sexampletitle { + (\sexampletitle) + }~} +} +\cs_new_protected:Nn \_@@_sexample_end: {\par\medskip} + +\newcommand\stexpatchexample[3][] { + \str_set:Nx \l_tmpa_str{ #1 } + \str_if_empty:NTF \l_tmpa_str { + \tl_set:Nn \_@@_sexample_start: { #2 } + \tl_set:Nn \_@@_sexample_end: { #3 } + }{ + \exp_after:wN \tl_set:Nn \csname _@@_sexample_#1_start:\endcsname{ #2 } + \exp_after:wN \tl_set:Nn \csname _@@_sexample_#1_end:\endcsname{ #3 } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\inlineex} +% inline: +% \begin{macrocode} +\keys_define:nn {stex / inlineex }{ + type .str_set_x:N = \sexampletype, + id .str_set_x:N = \sexampleid, + for .clist_set:N = \l_@@_sexample_for_clist , + name .str_set_x:N = \sexamplename +} +\cs_new_protected:Nn \_@@_inlineex_args:n { + \str_clear:N \sexampletype + \str_clear:N \sexampleid + \str_clear:N \sexamplename + \clist_clear:N \l_@@_sexample_for_clist + \keys_set:nn { stex / inlineex }{ #1 } +} +\NewDocumentCommand \inlineex { O{} m } { + \begingroup + \stex_reactivate_macro:N \premise + \stex_reactivate_macro:N \conclusion + \_@@_inlineex_args:n{ #1 } + \str_if_empty:NF \sexampleid { + \stex_ref_new_doc_target:n \sexampleid + } + \stex_if_smsmode:TF{ + \str_if_empty:NF \sexamplename { \stex_symdecl_do:nn{}{\examplename} } + }{ + \seq_clear:N \l_tmpa_seq + \clist_map_inline:Nn \l_@@_sexample_for_clist { + \tl_if_empty:nF{ ##1 }{ + \stex_get_symbol:n { ##1 } + \exp_args:NNo \seq_put_right:Nn \l_tmpa_seq { + \l_stex_get_symbol_uri_str + } + } + } + \exp_args:Nnx + \stex_annotate:nnn{example}{\seq_use:Nn \l_tmpa_seq {,}}{ + \str_if_empty:NF \sexampletype { + \stex_annotate_invisible:nnn{type}{\sexampletype}{} + } + #2 + \str_if_empty:NF \sexamplename { \stex_symdecl_do:nn{}{\sexamplename} } + } + } + \endgroup + \stex_smsmode_do: +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Logical Paragraphs} +% +% \begin{environment}{sparagraph} +% \begin{macrocode} +\keys_define:nn { stex / sparagraph} { + id .str_set_x:N = \sparagraphid , + title .tl_set:N = \l_stex_sparagraph_title_tl , + type .str_set_x:N = \sparagraphtype , + for .clist_set:N = \l_@@_sparagraph_for_clist , + from .tl_set:N = \sparagraphfrom , + to .tl_set:N = \sparagraphto , + start .tl_set:N = \l_stex_sparagraph_start_tl , + name .str_set:N = \sparagraphname +} + +\cs_new_protected:Nn \stex_sparagraph_args:n { + \tl_clear:N \l_stex_sparagraph_title_tl + \tl_clear:N \sparagraphfrom + \tl_clear:N \sparagraphto + \tl_clear:N \l_stex_sparagraph_start_tl + \str_clear:N \sparagraphid + \str_clear:N \sparagraphtype + \clist_clear:N \l_@@_sparagraph_for_clist + \str_clear:N \sparagraphname + \keys_set:nn { stex / sparagraph }{ #1 } +} +\newif\if@in@omtext\@in@omtextfalse + +\NewDocumentEnvironment {sparagraph} { O{} } { + \stex_sparagraph_args:n { #1 } + \tl_if_empty:NTF \l_stex_sparagraph_start_tl { + \tl_set_eq:NN \sparagraphtitle \l_stex_sparagraph_title_tl + }{ + \tl_set_eq:NN \sparagraphtitle \l_stex_sparagraph_start_tl + } + \@in@omtexttrue + \stex_if_smsmode:F { + \seq_clear:N \l_tmpa_seq + \clist_map_inline:Nn \l_@@_sparagraph_for_clist { + \tl_if_empty:nF{ ##1 }{ + \stex_get_symbol:n { ##1 } + \exp_args:NNo \seq_put_right:Nn \l_tmpa_seq { + \l_stex_get_symbol_uri_str + } + } + } + \exp_args:Nnnx + \begin{stex_annotate_env}{paragraph}{\seq_use:Nn \l_tmpa_seq {,}} + \str_if_empty:NF \sparagraphtype { + \stex_annotate_invisible:nnn{type}{\sparagraphtype}{} + } + \str_if_empty:NF \sparagraphfrom { + \stex_annotate_invisible:nnn{from}{\sparagraphfrom}{} + } + \str_if_empty:NF \sparagraphto { + \stex_annotate_invisible:nnn{to}{\sparagraphto}{} + } + \clist_set:No \l_tmpa_clist \sparagraphtype + \tl_clear:N \l_tmpa_tl + \clist_map_inline:Nn \sparagraphtype { + \tl_if_exist:cT {_@@_sparagraph_##1_start:}{ + \tl_set:Nn \l_tmpa_tl {\use:c{_@@_sparagraph_##1_start:}} + } + } + \tl_if_empty:NTF \l_tmpa_tl { + \_@@_sparagraph_start: + }{ + \l_tmpa_tl + } + } + \clist_set:No \l_tmpa_clist \sparagraphtype + \str_if_empty:NTF \sparagraphid { + \str_if_empty:NTF \sparagraphname { + \exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\tl_to_str:n{symdoc}}{ + \stex_ref_new_doc_target:n {} + } + } { + \stex_ref_new_doc_target:n {} + } + } { + \stex_ref_new_doc_target:n \sparagraphid + } + \exp_args:NNx + \clist_if_in:NnT \l_tmpa_clist {\tl_to_str:n{symdoc}}{ + \clist_map_inline:Nn \l_@@_sparagraph_for_clist { + \tl_if_empty:nF{ ##1 }{ + \stex_get_symbol:n { ##1 } + \stex_ref_new_sym_target:n \l_stex_get_symbol_uri_str + } + } + } + \stex_smsmode_do: + \ignorespacesandpars +}{ + \str_if_empty:NF \sparagraphname { + \stex_symdecl_do:nn{}{\sparagraphname} + \stex_ref_new_sym_target:n {\l_stex_current_module_str ? \sparagraphname} + } + \stex_if_smsmode:F { + \clist_set:No \l_tmpa_clist \sparagraphtype + \tl_clear:N \l_tmpa_tl + \clist_map_inline:Nn \l_tmpa_clist { + \tl_if_exist:cT {_@@_sparagraph_##1_end:}{ + \tl_set:Nn \l_tmpa_tl {\use:c{_@@_sparagraph_##1_end:}} + } + } + \tl_if_empty:NTF \l_tmpa_tl { + \_@@_sparagraph_end: + }{ + \l_tmpa_tl + } + \end{stex_annotate_env} + } +} +% \end{macrocode} +% \end{environment} +% +% \begin{macro}{\stexpatchparagraph} +% \begin{macrocode} + +\cs_new_protected:Nn \_@@_sparagraph_start: { + \par\noindent\tl_if_empty:NTF \l_stex_sparagraph_start_tl { + \tl_if_empty:NF \l_stex_sparagraph_title_tl { + \titleemph{\l_stex_sparagraph_title_tl}:~ + } + }{ + \titleemph{\l_stex_sparagraph_start_tl}~ + } +} +\cs_new_protected:Nn \_@@_sparagraph_end: {\par\medskip} + +\newcommand\stexpatchparagraph[3][] { + \str_set:Nx \l_tmpa_str{ #1 } + \str_if_empty:NTF \l_tmpa_str { + \tl_set:Nn \_@@_sparagraph_start: { #2 } + \tl_set:Nn \_@@_sparagraph_end: { #3 } + }{ + \exp_after:wN \tl_set:Nn \csname _@@_sparagraph_#1_start:\endcsname{ #2 } + \exp_after:wN \tl_set:Nn \csname _@@_sparagraph_#1_end:\endcsname{ #3 } + } +} + +\keys_define:nn { stex / inlinepara} { + id .str_set_x:N = \sparagraphid , + type .str_set_x:N = \sparagraphtype , + for .clist_set:N = \l_@@_sparagraph_for_clist , + from .tl_set:N = \sparagraphfrom , + to .tl_set:N = \sparagraphto , + name .str_set:N = \sparagraphname +} +\cs_new_protected:Nn \_@@_inlinepara_args:n { + \tl_clear:N \sparagraphfrom + \tl_clear:N \sparagraphto + \str_clear:N \sparagraphid + \str_clear:N \sparagraphtype + \clist_clear:N \l_@@_sparagraph_for_clist + \str_clear:N \sparagraphname + \keys_set:nn { stex / inlinepara }{ #1 } +} +\NewDocumentCommand \inlinepara { O{} m } { + \begingroup + \_@@_inlinepara_args:n{ #1 } + \clist_set:No \l_tmpa_clist \sparagraphtype + \str_if_empty:NTF \sparagraphid { + \str_if_empty:NTF \sparagraphname { + \exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\tl_to_str:n{symdoc}}{ + \stex_ref_new_doc_target:n {} + } + } { + \stex_ref_new_doc_target:n {} + } + } { + \stex_ref_new_doc_target:n \sparagraphid + } + \stex_if_smsmode:TF{ + \str_if_empty:NF \sparagraphname { + \stex_symdecl_do:nn{}{\sparagraphname} + \stex_ref_new_sym_target:n {\l_stex_current_module_str ? \sparagraphname} + } + }{ + \seq_clear:N \l_tmpa_seq + \clist_map_inline:Nn \l_@@_sparagraph_for_clist { + \tl_if_empty:nF{ ##1 }{ + \stex_get_symbol:n { ##1 } + \exp_args:NNo \seq_put_right:Nn \l_tmpa_seq { + \l_stex_get_symbol_uri_str + } + } + } + \exp_args:Nnx + \stex_annotate:nnn{paragraph}{\seq_use:Nn \l_tmpa_seq {,}}{ + \str_if_empty:NF \sparagraphtype { + \stex_annotate_invisible:nnn{type}{\sparagraphtype}{} + } + \str_if_empty:NF \sparagraphfrom { + \stex_annotate_invisible:nnn{from}{\sparagraphfrom}{} + } + \str_if_empty:NF \sparagraphto { + \stex_annotate_invisible:nnn{to}{\sparagraphto}{} + } + \str_if_empty:NF \sparagraphname { + \stex_symdecl_do:nn{}{\sparagraphname} + \stex_ref_new_sym_target:n {\l_stex_current_module_str ? \sparagraphname} + } + \exp_args:NNx \clist_if_in:NnT \l_tmpa_clist {\tl_to_str:n{symdoc}}{ + \clist_map_inline:Nn \l_tmpa_seq { + \stex_ref_new_sym_target:n {##1} + } + } + #2 + } + } + \endgroup + \stex_smsmode_do: +} + +% \end{macrocode} +% \end{macro} +% +% +% +% +% +% +% +% +% +% +% +% +% +% +% +% +% +% +% +% +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex + +% \endinput +% Local Variables: +% mode: doctex +% TeX-master: t +% End: diff --git a/macros/latex/contrib/stex/source/stex/stex.ins b/macros/latex/contrib/stex/source/stex/stex.ins new file mode 100644 index 0000000000..95ff248c0d --- /dev/null +++ b/macros/latex/contrib/stex/source/stex/stex.ins @@ -0,0 +1,46 @@ + %% +%% This file generates files required to use the ed package. +%% At your command prompt write +%% +%% latex stex.ins +%% +%% Copyright (c) 2021 Michael Kohlhase +%% +%% This file is distributed under the terms of the LaTeX Project Public +%% License from CTAN archives in directory macros/latex/base/lppl.txt. +%% Either version 1.0 or, at your option, any later version. +%% +\input docstrip +\preamble +\endpreamble + +\keepsilent +\askforoverwritefalse + +\generate{ + \file{stex.cls}{\from{basics.dtx}{cls}} + \file{stex.sty}{ + \from{basics.dtx}{package} + \from{mathhub.dtx}{package} + \from{references.dtx}{package} + \from{modules.dtx}{package} + \from{inheritance.dtx}{package} + \from{symbols.dtx}{package} + \from{terms.dtx}{package} + \from{features.dtx}{package} + \from{statements.dtx}{package} + \from{sproof.dtx}{package} + % ... + \from{others.dtx}{package} + \from{metatheory.dtx}{package} + } +} + +\Msg{*} +\Msg{* You probably need to move the generated style files into a directory searched by TeX.} +\Msg{*} +\Msg{* And don't forget to refresh your filename database} +\Msg{* if your TeX distribution uses such a database.} +\Msg{*} + +\endbatchfile diff --git a/macros/latex/contrib/stex/source/stex/symbols.dtx b/macros/latex/contrib/stex/source/stex/symbols.dtx new file mode 100644 index 0000000000..da633e1be3 --- /dev/null +++ b/macros/latex/contrib/stex/source/stex/symbols.dtx @@ -0,0 +1,1263 @@ +% \iffalse meta-comment +% An Infrastructure for Semantic Macros and Module Scoping +% Copyright (c) 2019 Michael Kohlhase, all rights reserved +% this file is released under the +% LaTeX Project Public License (LPPL) +% +% The original of this file is in the public repository at +% http://github.com/sLaTeX/sTeX/ +% +% TODO update copyright +% +%<*driver> +\providecommand\bibfolder{../../lib/bib} +\input{../../doc/docheader} + +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{ \sTeX-Symbols +% \thanks{Version {\fileversion} (last revised {\filedate})} +% } +% +% \author{Michael Kohlhase, Dennis Müller\\ +% FAU Erlangen-Nürnberg\\ +% \url{http://kwarc.info/} +% } +% +% \maketitle +% +%\ifinfulldoc\else +% This is the documentation for the \pkg{stex-symbols} package. +% For a more high-level introduction, +% see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the +% \href{\basedocurl/stex.pdf}{full \sTeX documentation}. +% +% \input{../../doc/packages/symbols} +% \fi +% +% \begin{documentation}\label{pkg:symbols:doc} +% +% Code related to symbol declarations and notations +% +% \section{Macros and Environments}\label{pkg:symbols:doc:macros} +% +% \begin{function}{\symdecl} +% \begin{syntax} \cs{symdecl}\Arg{macroname}|[|\meta{args}|]| \end{syntax} +% Declares a new symbol with semantic macro \cs{macroname}. Optional +% arguments are: +% \begin{itemize} +% \item |name|: An (\omdoc) name. By default equal to \meta{macroname}. +% \item |type|: An (ideally semantic) term. Not used by \sTeX, but +% passed on to \mmt for semantic services. +% \item |local|: A boolean (by default false). If set, this declaration +% will not be added to the module content, i.e. importing +% the current module will not make this declaration available. +% \item |args|: Specifies the ``signature'' of the semantic macro. +% Can be either an integer $0 \leq n \leq 9$, or a (more precise) +% sequence of the following characters: +% \begin{itemize} +% \item[|i|] a ``normal'' argument, e.g. +% |\symdecl{plus}[args=ii]| allows for |\plus{2}{2}|. +% \item[|a|] an \emph{associative} argument; i.e. a sequence of +% arbitrarily many arguments provided as a comma-separated list, +% e.g. +% |\symdecl{plus}[args=a]| allows for |\plus{2,2,2}|. +% \item[|b|] a \emph{variable} argument. Is treated by \sTeX +% like an |i|-argument, but an application is turned into +% an |OMBind| in \omdoc, binding the provided variable +% in the subsequent arguments of the operator; e.g. +% |\symdecl{forall}[args=bi]| allows for |\forall{x\in\Nat}{x\geq0}|. +% \end{itemize} +% \end{itemize} +% \end{function} +% +% \begin{function}{\stex_symdecl_do:n} +% Implements the core functionality of \cs{symdecl}, and is +% called by \cs{symdecl} and \cs{symdef}. +% +% Ultimately stores the symbol \meta{URI} in the property +% list |\l_stex_symdecl_|\meta{URI}|_prop| with fields: +% \begin{itemize} +% \item |name| (string), +% \item |module| (string), +% \item |notations| (sequence of strings; initially empty), +% \item |local| (boolean), +% \item |type| (token list), +% \item |args| (string of |i|s, |a|s and |b|s), +% \item |arity| (integer string), +% \item |assocs| (integer string; number of associative arguments), +% \end{itemize} +% \end{function} +% +% \begin{function}{\stex_all_symbols:n} +% Iterates over all currently available symbols. +% Requires two |\seq_map_break:| to break fully. +% \end{function} +% +% \begin{function}{\stex_get_symbol:n} +% Computes the full URI of a symbol from a macro argument, e.g. +% the macro name, the macro itself, the full URI... +% \end{function} +% +% \begin{function}{\notation} +% \begin{syntax} \cs{notation}|[|\meta{args}|]|\Arg{symbol}\Arg{notations$^+$} \end{syntax} +% Introduces a new notation for \meta{symbol}, see \cs{stex_notation_do:nn} +% \end{function} +% +% \begin{function}{\stex_notation_do:nn} +% \begin{syntax} \cs{stex_notation_do:nn}\Arg{URI}\Arg{notations$^+$}\end{syntax} +% +% Implements the core functionality of \cs{notation}, and is +% called by \cs{notation} and \cs{symdef}. +% +% Ultimately stores the notation in the property +% list\\ |\g_stex_notation_|\meta{URI}|#|\meta{variant}|#|^^A +% \meta{lang}|_prop| with fields: +% \begin{itemize} +% \item |symbol| (URI string), +% \item |language| (string), +% \item |variant| (string), +% \item |opprec| (integer string), +% \item |argprecs| (sequence of integer strings) +% \end{itemize} +% \end{function} +% +% \begin{function}{\symdef} +% \begin{syntax} \cs{symdef}|[|\meta{args}|]|\Arg{symbol}\Arg{notations$^+$} \end{syntax} +% Combines \cs{symdecl} and \cs{notation} by introducing a new +% symbol and assigning a new notation for it. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation}\label{pkg:symbols:impl} +% +% \section{\sTeX-Symbols Implementation} +% +% \begin{macrocode} +%<*package> + +%%%%%%%%%%%%% symbols.dtx %%%%%%%%%%%%% + +% \end{macrocode} +% +% Warnings and error messages +% +% \begin{macrocode} +\msg_new:nnn{stex}{error/wrongargs}{ + args~value~in~symbol~declaration~for~#1~ + needs~to~be~i,~a,~b~or~B,~but~#2~given +} +% \end{macrocode} +% +% \subsection{Symbol Declarations} +% \begin{macrocode} +%<@@=stex_symdecl> +% \end{macrocode} +% +% \begin{macro}{\stex_all_symbols:n} +% Map over all available symbols +% \begin{macrocode} +\cs_new_protected:Nn \stex_all_symbols:n { + \def \_@@_all_symbols_cs ##1 {#1} + \seq_map_inline:Nn \l_stex_all_modules_seq { + \seq_map_inline:cn{c_stex_module_##1_constants}{ + \_@@_all_symbols_cs{##1?####1} + } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\STEXsymbol} +% \begin{macrocode} +\NewDocumentCommand \STEXsymbol { m } { + \stex_get_symbol:n { #1 } + \exp_args:No + \stex_invoke_symbol:n { \l_stex_get_symbol_uri_str } +} +% \end{macrocode} +% \end{macro} +% +% |symdecl| arguments: +% +% \begin{macrocode} +\keys_define:nn { stex / symdecl } { + name .str_set_x:N = \l_stex_symdecl_name_str , + local .bool_set:N = \l_stex_symdecl_local_bool , + args .str_set_x:N = \l_stex_symdecl_args_str , + type .tl_set:N = \l_stex_symdecl_type_tl , + deprecate .str_set_x:N = \l_stex_symdecl_deprecate_str , + align .str_set:N = \l_stex_symdecl_align_str , % TODO(?) + gfc .str_set:N = \l_stex_symdecl_gfc_str , % TODO(?) + specializes .str_set:N = \l_stex_symdecl_specializes_str , % TODO(?) + def .tl_set:N = \l_stex_symdecl_definiens_tl , + assoc .choices:nn = + {bin,binl,binr,pre,conj,pwconj} + {\str_set:Nx \l_stex_symdecl_assoctype_str {\l_keys_choice_tl}} +} + +\bool_new:N \l_stex_symdecl_make_macro_bool + +\cs_new_protected:Nn \_@@_args:n { + \str_clear:N \l_stex_symdecl_name_str + \str_clear:N \l_stex_symdecl_args_str + \str_clear:N \l_stex_symdecl_deprecate_str + \str_clear:N \l_stex_symdecl_assoctype_str + \bool_set_false:N \l_stex_symdecl_local_bool + \tl_clear:N \l_stex_symdecl_type_tl + \tl_clear:N \l_stex_symdecl_definiens_tl + + \keys_set:nn { stex / symdecl } { #1 } +} +% \end{macrocode} +% +% \begin{macro}{\symdecl} +% +% Parses the optional arguments and passes them on to +% \cs{stex_symdecl_do:} (so that \cs{symdef} +% can do the same) +% +% \begin{macrocode} + +\NewDocumentCommand \symdecl { s m O{}} { + \_@@_args:n { #3 } + \IfBooleanTF #1 { + \bool_set_false:N \l_stex_symdecl_make_macro_bool + } { + \bool_set_true:N \l_stex_symdecl_make_macro_bool + } + \stex_symdecl_do:n { #2 } + \stex_smsmode_do: +} + +\cs_new_protected:Nn \stex_symdecl_do:nn { + \_@@_args:n{#1} + \bool_set_false:N \l_stex_symdecl_make_macro_bool + \stex_symdecl_do:n{#2} +} + +\stex_deactivate_macro:Nn \symdecl {module~environments} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\stex_symdecl_do:n} +% \begin{macrocode} +\cs_new_protected:Nn \stex_symdecl_do:n { + \stex_if_in_module:F { + % TODO throw error? some default namespace? + } + + \str_if_empty:NT \l_stex_symdecl_name_str { + \str_set:Nx \l_stex_symdecl_name_str { #1 } + } + + \prop_if_exist:cT { l_stex_symdecl_ + \l_stex_current_module_str ? + \l_stex_symdecl_name_str + _prop + }{ + % TODO throw error (beware of circular dependencies) + } + + \prop_clear:N \l_tmpa_prop + \prop_put:Nnx \l_tmpa_prop { module } { \l_stex_current_module_str } + \seq_clear:N \l_tmpa_seq + \prop_put:Nno \l_tmpa_prop { name } \l_stex_symdecl_name_str + \prop_put:Nno \l_tmpa_prop { type } \l_stex_symdecl_type_tl + + \str_if_empty:NT \l_stex_symdecl_deprecate_str { + \str_if_empty:NF \l_stex_module_deprecate_str { + \str_set_eq:NN \l_stex_symdecl_deprecate_str \l_stex_module_deprecate_str + } + } + \prop_put:Nno \l_tmpa_prop { deprecate } \l_stex_symdecl_deprecate_str + + \exp_args:No \stex_add_constant_to_current_module:n { + \l_stex_symdecl_name_str + } + + % arity/args + \int_zero:N \l_tmpb_int + + \bool_set_true:N \l_tmpa_bool + \str_map_inline:Nn \l_stex_symdecl_args_str { + \token_case_meaning:NnF ##1 { + 0 {} 1 {} 2 {} 3 {} 4 {} 5 {} 6 {} 7 {} 8 {} 9 {} + {\tl_to_str:n i} { \bool_set_false:N \l_tmpa_bool } + {\tl_to_str:n b} { \bool_set_false:N \l_tmpa_bool } + {\tl_to_str:n a} { + \bool_set_false:N \l_tmpa_bool + \int_incr:N \l_tmpb_int + } + {\tl_to_str:n B} { + \bool_set_false:N \l_tmpa_bool + \int_incr:N \l_tmpb_int + } + }{ + \msg_error:nnxx{stex}{error/wrongargs}{ + \l_stex_current_module_str ? + \l_stex_symdecl_name_str + }{##1} + } + } + \bool_if:NTF \l_tmpa_bool { + % possibly numeric + \str_if_empty:NTF \l_stex_symdecl_args_str { + \prop_put:Nnn \l_tmpa_prop { args } {} + \prop_put:Nnn \l_tmpa_prop { arity } { 0 } + }{ + \int_set:Nn \l_tmpa_int { \l_stex_symdecl_args_str } + \prop_put:Nnx \l_tmpa_prop { arity } { \int_use:N \l_tmpa_int } + \str_clear:N \l_tmpa_str + \int_step_inline:nn \l_tmpa_int { + \str_put_right:Nn \l_tmpa_str i + } + \prop_put:Nnx \l_tmpa_prop { args } { \l_tmpa_str } + } + } { + \prop_put:Nnx \l_tmpa_prop { args } { \l_stex_symdecl_args_str } + \prop_put:Nnx \l_tmpa_prop { arity } + { \str_count:N \l_stex_symdecl_args_str } + } + \prop_put:Nnx \l_tmpa_prop { assocs } { \int_use:N \l_tmpb_int } + + + % semantic macro + + \bool_if:NT \l_stex_symdecl_make_macro_bool { + \exp_args:Nx \stex_do_up_to_module:n { + \tl_set:cn { #1 } { \stex_invoke_symbol:n { + \l_stex_current_module_str ? \l_stex_symdecl_name_str + }} + } + + \bool_if:NF \l_stex_symdecl_local_bool { + \exp_args:Nx \stex_add_to_current_module:n { + \tl_set:cn { #1 } { \stex_invoke_symbol:n { + \l_stex_current_module_str ? \l_stex_symdecl_name_str + } } + } + } + } + + \stex_debug:nn{symbols}{New~symbol:~ + \l_stex_current_module_str ? \l_stex_symdecl_name_str^^J + Type:~\exp_not:o { \l_stex_symdecl_type_tl }^^J + Args:~\prop_item:Nn \l_tmpa_prop { args } + } + + % circular dependencies require this: + + \prop_if_exist:cF { + l_stex_symdecl_ + \l_stex_current_module_str ? \l_stex_symdecl_name_str + _prop + } { + \prop_set_eq:cN { + l_stex_symdecl_ + \l_stex_current_module_str ? \l_stex_symdecl_name_str + _prop + } \l_tmpa_prop + } + + \seq_clear:c { + l_stex_symdecl_ + \l_stex_current_module_str ? \l_stex_symdecl_name_str + _notations + } + + \bool_if:NF \l_stex_symdecl_local_bool { + \exp_args:Nx + \stex_add_to_current_module:n { + \seq_clear:c { + l_stex_symdecl_ + \l_stex_current_module_str ? \l_stex_symdecl_name_str + _notations + } + \prop_set_from_keyval:cn { + l_stex_symdecl_ + \l_stex_current_module_str ? \l_stex_symdecl_name_str + _prop + } { + name = \prop_item:Nn \l_tmpa_prop { name } , + module = \prop_item:Nn \l_tmpa_prop { module } , + type = \prop_item:Nn \l_tmpa_prop { type } , + args = \prop_item:Nn \l_tmpa_prop { args } , + arity = \prop_item:Nn \l_tmpa_prop { arity } , + assocs = \prop_item:Nn \l_tmpa_prop { assocs } + } + } + } + + \stex_if_smsmode:F { +% \exp_args:Nx \stex_do_up_to_module:n { +% \seq_put_right:Nn \exp_not:N \l_stex_all_symbols_seq { +% \l_stex_current_module_str ? \l_stex_symdecl_name_str +% } +% } + \stex_if_do_html:T { + \stex_annotate_invisible:nnn {symdecl} { + \l_stex_current_module_str ? \l_stex_symdecl_name_str + } { + \tl_if_empty:NF \l_stex_symdecl_type_tl {\stex_annotate_invisible:nnn{type}{}{$\l_stex_symdecl_type_tl$}} + \stex_annotate_invisible:nnn{args}{}{ + \prop_item:Nn \l_tmpa_prop { args } + } + \stex_annotate_invisible:nnn{macroname}{#1}{} + \tl_if_empty:NF \l_stex_symdecl_definiens_tl { + \stex_annotate_invisible:nnn{definiens}{} + {$\l_stex_symdecl_definiens_tl$} + } + \str_if_empty:NF \l_stex_symdecl_assoctype_str { + \stex_annotate_invisible:nnn{assoctype}{\l_stex_symdecl_assoctype_str}{} + } + } + } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stex_get_symbol:n} +% +% \begin{macrocode} +\str_new:N \l_stex_get_symbol_uri_str + +\cs_new_protected:Nn \stex_get_symbol:n { + \tl_if_head_eq_catcode:nNTF { #1 } \relax { + \_@@_get_symbol_from_cs:n { #1 } + }{ + % argument is a string + % is it a command name? + \cs_if_exist:cTF { #1 }{ + \cs_set_eq:Nc \l_tmpa_tl { #1 } + \str_set:Nx \l_tmpa_str { \cs_argument_spec:N \l_tmpa_tl } + \str_if_empty:NTF \l_tmpa_str { + \exp_args:Nx \cs_if_eq:NNTF { + \tl_head:N \l_tmpa_tl + } \stex_invoke_symbol:n { + \exp_args:No \_@@_get_symbol_from_cs:n { \use:c { #1 } } + }{ + \_@@_get_symbol_from_string:n { #1 } + } + } { + \_@@_get_symbol_from_string:n { #1 } + } + }{ + % argument is not a command name + \_@@_get_symbol_from_string:n { #1 } + % \l_stex_all_symbols_seq + } + } + \str_if_eq:eeF { + \prop_item:cn { + l_stex_symdecl_\l_stex_get_symbol_uri_str _prop + }{ deprecate } + }{}{ + \msg_warning:nnxx{stex}{warning/deprecated}{ + Symbol~\l_stex_get_symbol_uri_str + }{ + \prop_item:cn {l_stex_symdecl_\l_stex_get_symbol_uri_str _prop}{ deprecate } + } + } +} + +\cs_new_protected:Nn \_@@_get_symbol_from_string:n { + \tl_set:Nn \l_tmpa_tl { + \msg_set:nnn{stex}{error/unknownsymbol}{ + No~symbol~#1~found! + } + \msg_error:nn{stex}{error/unknownsymbol} + } + \str_set:Nn \l_tmpa_str { #1 } + \int_set:Nn \l_tmpa_int { \str_count:N \l_tmpa_str } + + \stex_all_symbols:n { + \str_if_eq:eeT { \l_tmpa_str }{ \str_range:nnn {##1}{-\l_tmpa_int}{-1}}{ + \seq_map_break:n{\seq_map_break:n{ + \tl_set:Nn \l_tmpa_tl { + \str_set:Nn \l_stex_get_symbol_uri_str { ##1 } + } + }} + } + } + + \l_tmpa_tl +} + +\cs_new_protected:Nn \_@@_get_symbol_from_cs:n { + \exp_args:NNx \tl_set:Nn \l_tmpa_tl + { \tl_tail:N \l_tmpa_tl } + \tl_if_single:NTF \l_tmpa_tl { + \exp_args:No \tl_if_head_is_group:nTF \l_tmpa_tl { + \exp_after:wN \str_set:Nn \exp_after:wN + \l_stex_get_symbol_uri_str \l_tmpa_tl + }{ + % TODO + % tail is not a single group + } + }{ + % TODO + % tail is not a single group + } +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Notations} +% \begin{macrocode} +%<@@=stex_notation> +% \end{macrocode} +% +% |notation| arguments: +% +% \begin{macrocode} +\keys_define:nn { stex / notation } { + lang .tl_set_x:N = \l_@@_lang_str , + variant .tl_set_x:N = \l_@@_variant_str , + prec .str_set_x:N = \l_@@_prec_str , + op .tl_set:N = \l_@@_op_tl , + primary .bool_set:N = \l_@@_primary_bool , + primary .default:n = {true} , + unknown .code:n = \str_set:Nx + \l_@@_variant_str \l_keys_key_str +} + +\cs_new_protected:Nn \_stex_notation_args:n { + \str_clear:N \l_@@_lang_str + \str_clear:N \l_@@_variant_str + \str_clear:N \l_@@_prec_str + \tl_clear:N \l_@@_op_tl + \bool_set_false:N \l_@@_primary_bool + + \keys_set:nn { stex / notation } { #1 } +} +% \end{macrocode} +% +% +% +% \begin{macro}{\notation} +% \begin{macrocode} +\NewDocumentCommand \notation { s m O{}} { + \_stex_notation_args:n { #3 } + \tl_clear:N \l_stex_symdecl_definiens_tl + \stex_get_symbol:n { #2 } + \tl_set:Nn \l_stex_notation_after_do_tl { + \_@@_final: + \IfBooleanTF#1{ + \stex_setnotation:n {\l_stex_get_symbol_uri_str} + }{} + \stex_smsmode_do: + } + \stex_notation_do:nnnn + { \prop_item:cn {l_stex_symdecl_\l_stex_get_symbol_uri_str _prop } { args } } + { \prop_item:cn { l_stex_symdecl_\l_stex_get_symbol_uri_str _prop } { arity } } + { \l_@@_variant_str \c_hash_str \l_@@_lang_str } +} +\stex_deactivate_macro:Nn \notation {module~environments} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stex_notation_do:nnnn} +% \begin{macrocode} +\seq_new:N \l_@@_precedences_seq +\tl_new:N \l_@@_opprec_tl +\int_new:N \l_@@_currarg_int +\tl_new:N \stex_symbol_after_invocation_tl + +\cs_new_protected:Nn \stex_notation_do:nnnn { + \let\l_stex_current_symbol_str\relax + \seq_clear:N \l_@@_precedences_seq + \tl_clear:N \l_@@_opprec_tl + \str_set:Nx \l_@@_args_str { #1 } + \str_set:Nx \l_@@_arity_str { #2 } + \str_set:Nx \_@@_suffix_str { #3 } + + % precedences + \str_if_empty:NTF \l_@@_prec_str { + \int_compare:nNnTF \l_@@_arity_str = 0 { + \tl_set:No \l_@@_opprec_tl { \neginfprec } + }{ + \tl_set:Nn \l_@@_opprec_tl { 0 } + } + } { + \str_if_eq:onTF \l_@@_prec_str {nobrackets}{ + \tl_set:No \l_@@_opprec_tl { \neginfprec } + \int_step_inline:nn { \l_@@_arity_str } { + \exp_args:NNo + \seq_put_right:Nn \l_@@_precedences_seq { \infprec } + } + }{ + \seq_set_split:NnV \l_tmpa_seq ; \l_@@_prec_str + \seq_pop_left:NNTF \l_tmpa_seq \l_tmpa_str { + \tl_set:No \l_@@_opprec_tl { \l_tmpa_str } + \seq_pop_left:NNT \l_tmpa_seq \l_tmpa_str { + \exp_args:NNNo \exp_args:NNno \seq_set_split:Nnn + \l_tmpa_seq {\tl_to_str:n{x} } { \l_tmpa_str } + \seq_map_inline:Nn \l_tmpa_seq { + \seq_put_right:Nn \l_tmpb_seq { ##1 } + } + } + }{ + \int_compare:nNnTF \l_@@_arity_str = 0 { + \tl_set:No \l_@@_opprec_tl { \infprec } + }{ + \tl_set:No \l_@@_opprec_tl { 0 } + } + } + } + } + + \seq_set_eq:NN \l_tmpa_seq \l_@@_precedences_seq + \int_step_inline:nn { \l_@@_arity_str } { + \seq_pop_left:NNF \l_tmpa_seq \l_tmpb_str { + \exp_args:NNo + \seq_put_right:No \l_@@_precedences_seq { + \l_@@_opprec_tl + } + } + } + \tl_clear:N \l_stex_notation_dummyargs_tl + + \int_compare:nNnTF \l_@@_arity_str = 0 { + \exp_args:NNe + \cs_set:Npn \l_stex_notation_macrocode_cs { + \_stex_term_math_oms:nnnn { \l_stex_current_symbol_str } + { \_@@_suffix_str } + { \l_@@_opprec_tl } + { \exp_not:n { #4 } } + } + \l_stex_notation_after_do_tl + }{ + \str_if_in:NnTF \l_@@_args_str b { + \exp_args:Nne \use:nn + { + \cs_generate_from_arg_count:NNnn \l_stex_notation_macrocode_cs + \cs_set:Npn \l_@@_arity_str } { { + \_stex_term_math_omb:nnnn { \l_stex_current_symbol_str } + { \_@@_suffix_str } + { \l_@@_opprec_tl } + { \exp_not:n { #4 } } + }} + }{ + \str_if_in:NnTF \l_@@_args_str B { + \exp_args:Nne \use:nn + { + \cs_generate_from_arg_count:NNnn \l_stex_notation_macrocode_cs + \cs_set:Npn \l_@@_arity_str } { { + \_stex_term_math_omb:nnnn { \l_stex_current_symbol_str } + { \_@@_suffix_str } + { \l_@@_opprec_tl } + { \exp_not:n { #4 } } + } } + }{ + \exp_args:Nne \use:nn + { + \cs_generate_from_arg_count:NNnn \l_stex_notation_macrocode_cs + \cs_set:Npn \l_@@_arity_str } { { + \_stex_term_math_oma:nnnn { \l_stex_current_symbol_str } + { \_@@_suffix_str } + { \l_@@_opprec_tl } + { \exp_not:n { #4 } } + } } + } + } + + \str_set_eq:NN \l_@@_remaining_args_str \l_@@_args_str + \int_zero:N \l_@@_currarg_int + \seq_set_eq:NN \l_@@_remaining_precs_seq \l_@@_precedences_seq + \_@@_arguments: + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\_@@_arguments:} +% +% Takes care of annotating the arguments in a +% notation macro +% +% \begin{macrocode} +\cs_new_protected:Nn \_@@_arguments: { + \int_incr:N \l_@@_currarg_int + \str_if_empty:NTF \l_@@_remaining_args_str { + \l_stex_notation_after_do_tl + }{ + \str_set:Nx \l_tmpa_str { \str_head:N \l_@@_remaining_args_str } + \str_set:Nx \l_@@_remaining_args_str { \str_tail:N \l_@@_remaining_args_str } + \str_if_eq:VnTF \l_tmpa_str a { + \_@@_argument_assoc:n + }{ + \str_if_eq:VnTF \l_tmpa_str B { + \_@@_argument_assoc:n + }{ + \seq_pop_left:NN \l_@@_remaining_precs_seq \l_tmpa_str + \tl_put_right:Nx \l_stex_notation_dummyargs_tl { + { \_stex_term_math_arg:nnn + { \int_use:N \l_@@_currarg_int } + { \l_tmpa_str } + { ####\int_use:N \l_@@_currarg_int } + } + } + \_@@_arguments: + } + } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\_@@_argument_assoc:n} +% \begin{macrocode} +\cs_new_protected:Nn \_@@_argument_assoc:n { + + \cs_generate_from_arg_count:NNnn \l_tmpa_cs \cs_set:Npn + {\l_@@_arity_str}{ + #1 + } + \int_zero:N \l_tmpa_int + \tl_clear:N \l_tmpa_tl + \str_map_inline:Nn \l_@@_args_str { + \int_incr:N \l_tmpa_int + \tl_put_right:Nx \l_tmpa_tl { + \str_if_eq:nnTF {##1}{a}{ {} }{ + \str_if_eq:nnTF {##1}{B}{ {} }{ + {\_stex_term_arg:nn{\int_use:N \l_tmpa_int}{################ \int_use:N \l_tmpa_int}} + } + } + } + } + \exp_after:wN\exp_after:wN\exp_after:wN \def + \exp_after:wN\exp_after:wN\exp_after:wN \l_tmpa_cs + \exp_after:wN\exp_after:wN\exp_after:wN ## + \exp_after:wN\exp_after:wN\exp_after:wN 1 + \exp_after:wN\exp_after:wN\exp_after:wN ## + \exp_after:wN\exp_after:wN\exp_after:wN 2 + \exp_after:wN\exp_after:wN\exp_after:wN { + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_not:n \exp_after:wN \exp_after:wN \exp_after:wN { + \exp_after:wN \l_tmpa_cs \l_tmpa_tl + } + } + + \seq_pop_left:NN \l_@@_remaining_precs_seq \l_tmpa_str + \tl_put_right:Nx \l_stex_notation_dummyargs_tl { { + \_stex_term_math_assoc_arg:nnnn + { \int_use:N \l_@@_currarg_int } + { \l_tmpa_str } + { ####\int_use:N \l_@@_currarg_int } + { \l_tmpa_cs {####1} {####2} } + } } + \_@@_arguments: +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\_@@_final:} +% +% Called after processing all notation arguments +% +% \begin{macrocode} +\cs_new_protected:Nn \_@@_final: { + \exp_args:Nne \use:nn + { + \cs_generate_from_arg_count:cNnn { + stex_notation_ \l_stex_get_symbol_uri_str \c_hash_str + \_@@_suffix_str + _cs + } + \cs_set:Npn \l_@@_arity_str } { { + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_not:n \exp_after:wN \exp_after:wN \exp_after:wN + { \exp_after:wN \l_stex_notation_macrocode_cs \l_stex_notation_dummyargs_tl \stex_symbol_after_invocation_tl} + } } + + \tl_if_empty:NF \l_@@_op_tl { + \cs_set:cpx { + stex_op_notation_ \l_stex_get_symbol_uri_str \c_hash_str + \_@@_suffix_str + _cs + } { + \_stex_term_oms:nnn { + \l_stex_get_symbol_uri_str \c_hash_str \_@@_suffix_str + }{ + \l_stex_get_symbol_uri_str + }{ \comp{ \exp_args:No \exp_not:n { \l_@@_op_tl } } } + } + } + + \exp_args:Ne + \stex_add_to_current_module:n { + \cs_generate_from_arg_count:cNnn { + stex_notation_ \l_stex_get_symbol_uri_str \c_hash_str + \_@@_suffix_str + _cs + } \cs_set:Npn {\l_@@_arity_str} { + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_not:n \exp_after:wN \exp_after:wN \exp_after:wN + { \exp_after:wN \l_stex_notation_macrocode_cs \l_stex_notation_dummyargs_tl \stex_symbol_after_invocation_tl} + } + \tl_if_empty:NF \l_@@_op_tl { + \cs_set:cpn { + stex_op_notation_\l_stex_get_symbol_uri_str \c_hash_str + \_@@_suffix_str + _cs + } { + \_stex_term_oms:nnn { + \l_stex_get_symbol_uri_str\c_hash_str \_@@_suffix_str + }{ + \l_stex_get_symbol_uri_str + }{ \comp{ \exp_args:No \exp_not:n { \l_@@_op_tl } } } + } + } + } + %\exp_args:Nx + % \stex_do_up_to_module:n { + \seq_put_right:cx { + l_stex_symdecl_ \l_stex_get_symbol_uri_str + _notations + } { + \_@@_suffix_str + } + % } + + \stex_debug:nn{symbols}{ + Notation~\_@@_suffix_str + ~for~\l_stex_get_symbol_uri_str^^J + Operator~precedence:~\l_@@_opprec_tl^^J + Argument~precedences:~ + \seq_use:Nn \l_@@_precedences_seq {,~}^^J + Notation: \cs_meaning:c { + stex_notation_ \l_stex_get_symbol_uri_str \c_hash_str + \_@@_suffix_str + _cs + } + } + + \exp_args:Ne + \stex_add_to_current_module:n { + \seq_put_right:cn { + l_stex_symdecl_\l_stex_get_symbol_uri_str + _notations + } { \_@@_suffix_str } + } + + \stex_if_smsmode:F { + + % HTML annotations + \stex_if_do_html:T { + \stex_annotate_invisible:nnn { notation } + { \l_stex_get_symbol_uri_str } { + \stex_annotate_invisible:nnn { notationfragment } + { \_@@_suffix_str }{} + \stex_annotate_invisible:nnn { precedence } + { \l_@@_prec_str }{} + + \int_zero:N \l_tmpa_int + \str_set_eq:NN \l_@@_remaining_args_str \l_@@_args_str + \tl_clear:N \l_tmpa_tl + \int_step_inline:nn { \l_@@_arity_str }{ + \int_incr:N \l_tmpa_int + \str_set:Nx \l_tmpb_str { \str_head:N \l_@@_remaining_args_str } + \str_set:Nx \l_@@_remaining_args_str { \str_tail:N \l_@@_remaining_args_str } + \str_if_eq:VnTF \l_tmpb_str a { + \tl_set:Nx \l_tmpa_tl { \l_tmpa_tl { + \c_hash_str \c_hash_str \int_use:N \l_tmpa_int a , + \c_hash_str \c_hash_str \int_use:N \l_tmpa_int b + } } + }{ + \str_if_eq:VnTF \l_tmpb_str B { + \tl_set:Nx \l_tmpa_tl { \l_tmpa_tl { + \c_hash_str \c_hash_str \int_use:N \l_tmpa_int a , + \c_hash_str \c_hash_str \int_use:N \l_tmpa_int b + } } + }{ + \tl_set:Nx \l_tmpa_tl { \l_tmpa_tl { + \c_hash_str \c_hash_str \int_use:N \l_tmpa_int + } } + } + } + } + \stex_annotate_invisible:nnn { notationcomp }{}{ + \str_set:Nx \l_stex_current_symbol_str {\l_stex_get_symbol_uri_str } + $ \exp_args:Nno \use:nn { \use:c { + stex_notation_ \l_stex_current_symbol_str + \c_hash_str \_@@_suffix_str _cs + } } { \l_tmpa_tl } $ + } + } + } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\setnotation} +% \begin{macrocode} +\keys_define:nn { stex / setnotation } { + lang .tl_set_x:N = \l_@@_lang_str , + variant .tl_set_x:N = \l_@@_variant_str , + unknown .code:n = \str_set:Nx + \l_@@_variant_str \l_keys_key_str +} + +\cs_new_protected:Nn \_stex_setnotation_args:n { + \str_clear:N \l_@@_lang_str + \str_clear:N \l_@@_variant_str + \keys_set:nn { stex / setnotation } { #1 } +} + +\cs_new_protected:Nn \stex_setnotation:n { + \exp_args:Nnx \seq_if_in:cnTF { l_stex_symdecl_#1 _notations } + { \l_@@_variant_str \c_hash_str \l_@@_lang_str }{ + \exp_args:Nnx \seq_remove_all:cn { l_stex_symdecl_#1 _notations } + { \l_@@_variant_str \c_hash_str \l_@@_lang_str } + \exp_args:Nnx \seq_remove_all:cn { l_stex_symdecl_#1 _notations } + { \c_hash_str } + \exp_args:Nnx \seq_put_left:cn { l_stex_symdecl_#1 _notations } + { \l_@@_variant_str \c_hash_str \l_@@_lang_str } + \exp_args:Nx \stex_add_to_current_module:n { + \exp_args:Nnx \seq_remove_all:cn { l_stex_symdecl_#1 _notations } + { \l_@@_variant_str \c_hash_str \l_@@_lang_str } + \exp_args:Nnx \seq_put_left:cn { l_stex_symdecl_#1 _notations } + { \l_@@_variant_str \c_hash_str \l_@@_lang_str } + \exp_args:Nnx \seq_remove_all:cn { l_stex_symdecl_#1 _notations } + { \c_hash_str } + } + \stex_debug:nn {notations}{ + Setting~default~notation~ + {\l_@@_variant_str \c_hash_str \l_@@_lang_str}~for~ + #1 \\ + \expandafter\meaning\csname + l_stex_symdecl_#1 _notations\endcsname + } + }{ + % todo throw error + } +} + +\NewDocumentCommand \setnotation {m m} { + \stex_get_symbol:n { #1 } + \_stex_setnotation_args:n { #2 } + \stex_setnotation:n{\l_stex_get_symbol_uri_str} + \stex_smsmode_do: +} + +\cs_new_protected:Nn \stex_copy_notations:nn { + \stex_debug:nn {notations}{ + Copying~notations~from~#2~to~#1\\ + \seq_use:cn{l_stex_symdecl_#2_notations}{,~} + } + \tl_clear:N \l_tmpa_tl + \int_step_inline:nn { \prop_item:cn {l_stex_symdecl_#2_prop}{ arity } } { + \tl_put_right:Nn \l_tmpa_tl { {## ##1} } + } + \seq_map_inline:cn {l_stex_symdecl_#2_notations}{ + \cs_set_eq:Nc \l_tmpa_cs { stex_notation_ #2 \c_hash_str ##1 _cs } + \edef \l_tmpa_tl { + \exp_after:wN\exp_after:wN\exp_after:wN \exp_not:n + \exp_after:wN\exp_after:wN\exp_after:wN { + \exp_after:wN \l_tmpa_cs \l_tmpa_tl + } + } + \exp_args:Nx + \stex_do_up_to_module:n { + \seq_put_right:cn{l_stex_symdecl_#1_notations}{##1} + \cs_generate_from_arg_count:cNnn { + stex_notation_ #1 \c_hash_str ##1 _cs + } \cs_set:Npn { \prop_item:cn {l_stex_symdecl_#2_prop}{ arity } }{ + \exp_after:wN\exp_not:n\exp_after:wN{\l_tmpa_tl} + } + } + } +} + +\NewDocumentCommand \copynotation {m m} { + \stex_get_symbol:n { #1 } + \str_set_eq:NN \l_tmpa_str \l_stex_get_symbol_uri_str + \stex_get_symbol:n { #2 } + \exp_args:Noo + \stex_copy_notations:nn \l_tmpa_str \l_stex_get_symbol_uri_str + \exp_args:Nx \stex_add_import_to_current_module:n{ + \stex_copy_notations:nn {\l_tmpa_str} {\l_stex_get_symbol_uri_str} + } + \stex_smsmode_do: +} + +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\symdef} +% \begin{macrocode} +\keys_define:nn { stex / symdef } { + name .str_set_x:N = \l_stex_symdecl_name_str , + local .bool_set:N = \l_stex_symdecl_local_bool , + args .str_set_x:N = \l_stex_symdecl_args_str , + type .tl_set:N = \l_stex_symdecl_type_tl , + def .tl_set:N = \l_stex_symdecl_definiens_tl , + op .tl_set:N = \l_@@_op_tl , + lang .str_set_x:N = \l_@@_lang_str , + variant .str_set_x:N = \l_@@_variant_str , + prec .str_set_x:N = \l_@@_prec_str , + assoc .choices:nn = + {bin,binl,binr,pre,conj,pwconj} + {\str_set:Nx \l_stex_symdecl_assoctype_str {\l_keys_choice_tl}}, + unknown .code:n = \str_set:Nx + \l_@@_variant_str \l_keys_key_str +} + +\cs_new_protected:Nn \_@@_symdef_args:n { + \str_clear:N \l_stex_symdecl_name_str + \str_clear:N \l_stex_symdecl_args_str + \str_clear:N \l_stex_symdecl_assoctype_str + \bool_set_false:N \l_stex_symdecl_local_bool + \tl_clear:N \l_stex_symdecl_type_tl + \tl_clear:N \l_stex_symdecl_definiens_tl + \str_clear:N \l_@@_lang_str + \str_clear:N \l_@@_variant_str + \str_clear:N \l_@@_prec_str + \tl_clear:N \l_@@_op_tl + + \keys_set:nn { stex / symdef } { #1 } +} + +\NewDocumentCommand \symdef { m O{} } { + \_@@_symdef_args:n { #2 } + \bool_set_true:N \l_stex_symdecl_make_macro_bool + \stex_symdecl_do:n { #1 } + \tl_set:Nn \l_stex_notation_after_do_tl { + \_@@_final: + \stex_smsmode_do: + } + \str_set:Nx \l_stex_get_symbol_uri_str { + \l_stex_current_module_str ? \l_stex_symdecl_name_str + } + \exp_args:Nx \stex_notation_do:nnnn + { \prop_item:cn {l_stex_symdecl_\l_stex_get_symbol_uri_str _prop } { args } } + { \prop_item:cn { l_stex_symdecl_\l_stex_get_symbol_uri_str _prop } { arity } } + { \l_@@_variant_str \c_hash_str \l_@@_lang_str } +} +\stex_deactivate_macro:Nn \symdef {module~environments} +% \end{macrocode} +% \end{macro} +% +% \subsection{Variables} +% +% \begin{macrocode} +%<@@=stex_variables> + +\keys_define:nn { stex / vardef } { + name .str_set_x:N = \l_@@_name_str , + args .str_set_x:N = \l_@@_args_str , + type .tl_set:N = \l_@@_type_tl , + def .tl_set:N = \l_@@_def_tl , + op .tl_set:N = \l_@@_op_tl , + prec .str_set_x:N = \l_@@_prec_str , + assoc .choices:nn = + {bin,binl,binr,pre,conj,pwconj} + {\str_set:Nx \l_@@_assoctype_str {\l_keys_choice_tl}}, + bind .choices:nn = + {forall,exists} + {\str_set:Nx \l_@@_bind_str {\l_keys_choice_tl}} +} + +\cs_new_protected:Nn \_@@_args:n { + \str_clear:N \l_@@_name_str + \str_clear:N \l_@@_args_str + \str_clear:N \l_@@_prec_str + \str_clear:N \l_@@_assoctype_str + \str_clear:N \l_@@_bind_str + \tl_clear:N \l_@@_type_tl + \tl_clear:N \l_@@_def_tl + \tl_clear:N \l_@@_op_tl + + \keys_set:nn { stex / vardef } { #1 } +} + +\NewDocumentCommand \_@@_do_simple:nnn { m O{}} { + \_@@_args:n {#2} + \str_if_empty:NT \l_@@_name_str { + \str_set:Nx \l_@@_name_str { #1 } + } + \prop_clear:N \l_tmpa_prop + \prop_put:Nno \l_tmpa_prop { name } \l_@@_name_str + + \int_zero:N \l_tmpb_int + \bool_set_true:N \l_tmpa_bool + \str_map_inline:Nn \l_@@_args_str { + \token_case_meaning:NnF ##1 { + 0 {} 1 {} 2 {} 3 {} 4 {} 5 {} 6 {} 7 {} 8 {} 9 {} + {\tl_to_str:n i} { \bool_set_false:N \l_tmpa_bool } + {\tl_to_str:n b} { \bool_set_false:N \l_tmpa_bool } + {\tl_to_str:n a} { + \bool_set_false:N \l_tmpa_bool + \int_incr:N \l_tmpb_int + } + {\tl_to_str:n B} { + \bool_set_false:N \l_tmpa_bool + \int_incr:N \l_tmpb_int + } + }{ + \msg_error:nnxx{stex}{error/wrongargs}{ + variable~\l_@@_name_str + }{##1} + } + } + \bool_if:NTF \l_tmpa_bool { + % possibly numeric + \str_if_empty:NTF \l_@@_args_str { + \prop_put:Nnn \l_tmpa_prop { args } {} + \prop_put:Nnn \l_tmpa_prop { arity } { 0 } + }{ + \int_set:Nn \l_tmpa_int { \l_@@_args_str } + \prop_put:Nnx \l_tmpa_prop { arity } { \int_use:N \l_tmpa_int } + \str_clear:N \l_tmpa_str + \int_step_inline:nn \l_tmpa_int { + \str_put_right:Nn \l_tmpa_str i + } + \str_set_eq:NN \l_@@_args_str \l_tmpa_str + \prop_put:Nnx \l_tmpa_prop { args } { \l_@@_args_str } + } + } { + \prop_put:Nnx \l_tmpa_prop { args } { \l_@@_args_str } + \prop_put:Nnx \l_tmpa_prop { arity } + { \str_count:N \l_@@_args_str } + } + \prop_put:Nnx \l_tmpa_prop { assocs } { \int_use:N \l_tmpb_int } + \tl_set:cx { #1 }{ \stex_invoke_variable:n { \l_@@_name_str } } + + \prop_set_eq:cN { l_stex_variable_\l_@@_name_str _prop} \l_tmpa_prop + + \tl_if_empty:NF \l_@@_op_tl { + \cs_set:cpx { + stex_var_op_notation_ \l_@@_name_str _cs + } { + \_stex_term_omv:nn { + var://\l_@@_name_str + }{ \comp{ \exp_args:No \exp_not:n { \l_@@_op_tl } } } + } + } + + \tl_set:Nn \l_stex_notation_after_do_tl { + \exp_args:Nne \use:nn { + \cs_generate_from_arg_count:cNnn { stex_var_notation_\l_@@_name_str _cs } + \cs_set:Npn { \prop_item:Nn \l_tmpa_prop { arity } } + } {{ + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_not:n \exp_after:wN \exp_after:wN \exp_after:wN + { \exp_after:wN \l_stex_notation_macrocode_cs \l_stex_notation_dummyargs_tl \stex_symbol_after_invocation_tl} + }} + \stex_if_do_html:T { + \stex_annotate_invisible:nnn {vardecl}{\l_@@_name_str}{ + \stex_annotate_invisible:nnn { precedence } + { \l_@@_prec_str }{} + \tl_if_empty:NF \l_@@_type_tl {\stex_annotate_invisible:nnn{type}{}{$\l_@@_type_tl$}} + \stex_annotate_invisible:nnn{args}{}{ \l_@@_args_str } + \stex_annotate_invisible:nnn{macroname}{#1}{} + \tl_if_empty:NF \l_@@_def_tl { + \stex_annotate_invisible:nnn{definiens}{} + {$\l_@@_def_tl$} + } + \str_if_empty:NF \l_@@_assoctype_str { + \stex_annotate_invisible:nnn{assoctype}{\l_@@_assoctype_str}{} + } + \int_zero:N \l_tmpa_int + \str_set_eq:NN \l_@@_remaining_args_str \l_@@_args_str + \tl_clear:N \l_tmpa_tl + \int_step_inline:nn { \prop_item:Nn \l_tmpa_prop { arity } }{ + \int_incr:N \l_tmpa_int + \str_set:Nx \l_tmpb_str { \str_head:N \l_@@_remaining_args_str } + \str_set:Nx \l_@@_remaining_args_str { \str_tail:N \l_@@_remaining_args_str } + \str_if_eq:VnTF \l_tmpb_str a { + \tl_set:Nx \l_tmpa_tl { \l_tmpa_tl { + \c_hash_str \c_hash_str \int_use:N \l_tmpa_int a , + \c_hash_str \c_hash_str \int_use:N \l_tmpa_int b + } } + }{ + \str_if_eq:VnTF \l_tmpb_str B { + \tl_set:Nx \l_tmpa_tl { \l_tmpa_tl { + \c_hash_str \c_hash_str \int_use:N \l_tmpa_int a , + \c_hash_str \c_hash_str \int_use:N \l_tmpa_int b + } } + }{ + \tl_set:Nx \l_tmpa_tl { \l_tmpa_tl { + \c_hash_str \c_hash_str \int_use:N \l_tmpa_int + } } + } + } + } + \stex_annotate_invisible:nnn { notationcomp }{}{ + \str_set:Nx \l_stex_current_symbol_str {var://\l_@@_name_str } + $ \exp_args:Nno \use:nn { \use:c { + stex_var_notation_\l_@@_name_str _cs + } } { \l_tmpa_tl } $ + } + } + } + } + + \stex_notation_do:nnnn { \l_@@_args_str } { \prop_item:Nn \l_tmpa_prop { arity } } {} +} + +\cs_new:Nn \_@@_reset:N { + \tl_if_exist:NTF #1 { + \def \exp_not:N #1 { \exp_args:No \exp_not:n #1 } + }{ + \let \exp_not:N #1 \exp_not:N \undefined + } +} + +\NewDocumentCommand \_@@_do_complex:nn { m m }{ + \clist_set:Nx \l_@@_names { \tl_to_str:n {#1} } + \exp_args:Nnx \use:nn { + % TODO + \stex_annotate_invisible:nnn {vardecls}{\clist_use:Nn\l_@@_names,}{ + #2 + } + }{ + \_@@_reset:N \varnot + \_@@_reset:N \vartype + \_@@_reset:N \vardefi + } +} + +\NewDocumentCommand \vardef { s } { + \IfBooleanTF#1 { + \_@@_do_complex:nn + }{ + \_@@_do_simple:nnn + } +} + +\NewDocumentCommand \svar { O{} m }{ + \tl_if_empty:nTF {#1}{ + \str_set:Nn \l_tmpa_str { #2 } + }{ + \str_set:Nn \l_tmpa_str { #1 } + } + \_stex_term_omv:nn { + var://\l_tmpa_str + }{ \comp{ #2 } } +} + +% \end{macrocode} +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex + +% \endinput +% Local Variables: +% mode: doctex +% TeX-master: t +% End: diff --git a/macros/latex/contrib/stex/source/stex/terms.dtx b/macros/latex/contrib/stex/source/stex/terms.dtx new file mode 100644 index 0000000000..94a71d0208 --- /dev/null +++ b/macros/latex/contrib/stex/source/stex/terms.dtx @@ -0,0 +1,1037 @@ +% \iffalse meta-comment +% An Infrastructure for Semantic Macros and Module Scoping +% Copyright (c) 2019 Michael Kohlhase, all rights reserved +% this file is released under the +% LaTeX Project Public License (LPPL) +% +% The original of this file is in the public repository at +% http://github.com/sLaTeX/sTeX/ +% +% TODO update copyright +% +%<*driver> +\providecommand\bibfolder{../../lib/bib} +\input{../../doc/docheader} + +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{ \sTeX-Terms +% \thanks{Version {\fileversion} (last revised {\filedate})} +% } +% +% \author{Michael Kohlhase, Dennis Müller\\ +% FAU Erlangen-Nürnberg\\ +% \url{http://kwarc.info/} +% } +% +% \maketitle +% +%\ifinfulldoc\else +% This is the documentation for the \pkg{stex-terms} package. +% For a more high-level introduction, +% see \href{\basedocurl/manual.pdf}{the \sTeX Manual} or the +% \href{\basedocurl/stex.pdf}{full \sTeX documentation}. +% +% \input{../../doc/packages/terms} +% \fi +% +% \begin{documentation}\label{pkg:terms:doc} +% +% Code related to symbolic expressions, typesetting notations, +% notation components, etc. +% +% \section{Macros and Environments}\label{pkg:terms:doc:macros} +% +% \begin{function}{\STEXsymbol} +% Uses \cs{stex_get_symbol:n} to find the symbol denoted by +% the first argument and passes the result on to +% \cs{stex_invoke_symbol:n} +% \end{function} +% +% \begin{function}{\symref} +% \begin{syntax} \cs{symref}\Arg{symbol}\Arg{text} \end{syntax} +% shortcut for \cs{STEXsymbol}\Arg{symbol}|![|\meta{text}|]| +% \end{function} +% +% \begin{function}{\stex_invoke_symbol:n} +% Executes a semantic macro. Outside of math mode or if followed by |*|, +% it continues to \cs{stex_term_custom:nn}. In math mode, +% it uses the default or optionally provided notation of +% the associated symbol. +% +% If followed by |!|, it will invoke the symbol \emph{itself} +% rather than its application (and continue to +% \cs{stex_term_custom:nn}), i.e. it allows to refer to +% |\plus![addition]| as an operation, rather than +% |\plus[addition of]{some}{terms}|. +% \end{function} +% +% \begin{function}{\_stex_term_math_oms:nnnn,\_stex_term_math_oma:nnnn,\_stex_term_math_omb:nnnn} +% \begin{syntax} \meta{URI}\meta{fragment}\meta{precedence}\meta{body} \end{syntax} +% +% Annotates \meta{body} as an \omdoc-term (|OMID|, |OMA| or |OMBIND|, respectively) +% with head symbol \meta{URI}, generated +% by the specific notation \meta{fragment} with (upwards) operator precedence +% \meta{precedence}. Inserts parentheses according to +% the current downwards precedence and operator precedence. +% \end{function} +% +% \begin{function}{\_stex_term_math_arg:nnn} +% \begin{syntax} \cs{stex_term_arg:nnn}\meta{int}\meta{prec}\meta{body} \end{syntax} +% Annotates \meta{body} as the \meta{int}th argument of the current |OMA| or |OMBIND|, +% with (downwards) argument precedence \meta{prec}. +% \end{function} +% +% \begin{function}{\_stex_term_math_assoc_arg:nnnn} +% \begin{syntax} \cs{stex_term_arg:nnn}\meta{int}\meta{prec}\meta{notation}\meta{body} \end{syntax} +% Annotates \meta{body} as the \meta{int}th (associative) \emph{sequence} argument +% (as comma-separated list of terms) of the current |OMA| or |OMBIND|, +% with (downwards) argument precedence \meta{prec} and associative +% notation \meta{notation}. +% +% \end{function} +% +% \begin{variable}{\infprec, \neginfprec} +% Maximal and minimal notation precedences. +% \end{variable} +% +% \begin{function}{\dobrackets} +% \begin{syntax} \cs{dobrackets} \Arg{body} \end{syntax} +% Puts \meta{body} in parentheses; scaled if in display mode +% unscaled otherwise. Uses the current \sTeX brackets (by default |(| and |)|), +% which can be changed temporarily using \cs{withbrackets}. +% \end{function} +% +% \begin{function}{\withbrackets} +% \begin{syntax} \cs{withbrackets} \meta{left} \meta{right} \Arg{body} \end{syntax} +% Temporarily (i.e. within \meta{body}) sets the brackets used by \sTeX for automated +% bracketing (by default |(| and |)|) to \meta{left} and \meta{right}. +% +% Note that \meta{left} and \meta{right} need to be allowed +% after \cs{left} and \cs{right} in displaymode. +% \end{function} +% +% \begin{function}{\stex_term_custom:nn} +% \begin{syntax} \cs{stex_term_custom:nn}\Arg{URI}\Arg{args}\end{syntax} +% Implements custom one-time notation. +% Invoked by \cs{stex_invoke_symbol:n} in text mode, or if +% followed by |*| in math mode, or whenever followed by |!|. +% \end{function} +% +% \begin{function}{\stex_highlight_term:nn} +% \begin{syntax} \cs{stex_highlight_term:nn}\Arg{URI}\Arg{args}\end{syntax} +% Establishes a context for \cs{comp}. Stores the URI in a variable +% so that \cs{comp} knows which symbol governs the current notation. +% \end{function} +% +% \begin{function}{\comp, \compemph,\compemph@uri, \defemph, \defemph@uri, \symrefemph,\symrefemph@uri} +% \begin{syntax} \cs{comp}\Arg{args}\end{syntax} +% Marks \meta{args} as a notation component of the current symbol for +% highlighting, linking, etc. +% +% The precise behavior is governed by \cs{@comp}, which takes as +% additional argument the URI of the current symbol. By default, +% \cs{@comp} adds the URI as a PDF tooltip and colors the highlighted part +% in blue. +% +% \cs{@defemph} behaves like \cs{@comp}, and can be similarly redefined, +% but marks an expression as \emph{definiendum} (used by \cs{definiendum}) +% \end{function} +% +% \begin{function}{\STEXinvisible} +% Exports its argument as \omdoc (invisible), but does +% not produce PDF output. Useful e.g. for semantic macros +% that take arguments that are not part of the symbolic +% notation. +% \end{function} +% +% \begin{function}{\ellipses} +% TODO +% \end{function} +% +% \end{documentation} +% +% \begin{implementation}\label{pkg:terms:impl} +% +% \section{\sTeX-Terms Implementation} +% +% \begin{macrocode} +%<*package> + +%%%%%%%%%%%%% terms.dtx %%%%%%%%%%%%% + +%<@@=stex_terms> +% \end{macrocode} +% +% Warnings and error messages +% +% \begin{macrocode} +\msg_new:nnn{stex}{error/nonotation}{ + Symbol~#1~invoked,~but~has~no~notation#2! +} +\msg_new:nnn{stex}{error/notationarg}{ + Error~in~parsing~notation~#1 +} +\msg_new:nnn{stex}{error/noop}{ + Symbol~#1~has~no~operator~notation~for~notation~#2 +} +\msg_new:nnn{stex}{error/notallowed}{ + Symbol~invocation~#1~not~allowed~in~notation~component~of~#2 +} + +% \end{macrocode} +% \subsection{Symbol Invocations} +% +% +% \begin{macro}{\stex_invoke_symbol:n} +% +% Invokes a semantic macro +% +% \begin{macrocode} +\keys_define:nn { stex / terms } { + lang .tl_set_x:N = \l_@@_lang_str , + variant .tl_set_x:N = \l_@@_variant_str , + unknown .code:n = \str_set:Nx + \l_@@_variant_str \l_keys_key_str +} + +\cs_new_protected:Nn \_@@_args:n { + \str_clear:N \l_@@_lang_str + \str_clear:N \l_@@_variant_str + + \keys_set:nn { stex / terms } { #1 } +} + +\cs_new:Nn \_@@_reset:N { + \tl_if_exist:NTF #1 { + \def \exp_not:N #1 { \exp_args:No \exp_not:n #1 } + }{ + \let \exp_not:N #1 \exp_not:N \undefined + } +} + +\bool_new:N \l_@@_allow_semantic_bool +\bool_set_true:N \l_@@_allow_semantic_bool + +\cs_new_protected:Nn \stex_invoke_symbol:n { + \bool_if:NTF \l_@@_allow_semantic_bool { + \str_if_eq:eeF { + \prop_item:cn { + l_stex_symdecl_#1_prop + }{ deprecate } + }{}{ + \msg_warning:nnxx{stex}{warning/deprecated}{ + Symbol~#1 + }{ + \prop_item:cn {l_stex_symdecl_#1_prop}{ deprecate } + } + } + \if_mode_math: + \exp_after:wN \_@@_invoke_math:n + \else: + \exp_after:wN \_@@_invoke_text:n + \fi: { #1 } + }{ + \msg_error:nnxx{stex}{error/notallowed}{#1}{\l_stex_current_symbol_str} + } +} + +\cs_new_protected:Nn \_@@_invoke_text:n { + \peek_charcode_remove:NTF ! { + \_@@_invoke_op_custom:nn {#1} + }{ + \_@@_invoke_custom:nn {#1} + } +} + +\cs_new_protected:Nn \_@@_invoke_math:n { + \peek_charcode_remove:NTF ! { + % operator + \peek_charcode_remove:NTF * { + % custom op + \_@@_invoke_op_custom:nn {#1} + }{ + % op notation + \peek_charcode:NTF [ { + \_@@_invoke_op_notation:nw {#1} + }{ + \_@@_invoke_op_notation:nw {#1}[] + } + } + }{ + \peek_charcode_remove:NTF * { + \_@@_invoke_custom:nn {#1} + % custom + }{ + % normal + \peek_charcode:NTF [ { + \_@@_invoke_notation:nw {#1} + }{ + \_@@_invoke_notation:nw {#1}[] + } + } + } +} + + +\cs_new_protected:Nn \_@@_invoke_op_custom:nn { + \exp_args:Nnx \use:nn { + \str_set:Nn \l_stex_current_symbol_str { #1 } + \bool_set_false:N \l_@@_allow_semantic_bool + \_stex_term_oms:nnn {#1 \c_hash_str\c_hash_str}{#1}{ + \comp{ #2 } + } + }{ + \_@@_reset:N \l_stex_current_symbol_str + \bool_set_true:N \l_@@_allow_semantic_bool + } +} + +\cs_new_protected:Nn \_@@_find_notation:nn { + \str_set:Nn \l_stex_current_symbol_str { #1 } + \_@@_args:n { #2 } + \seq_if_empty:cTF { + l_stex_symdecl_ #1 _notations + } { + \msg_error:nnxx{stex}{error/nonotation}{#1}{s} + } { + \bool_lazy_all:nTF { + {\str_if_empty_p:N \l_@@_variant_str} + {\str_if_empty_p:N \l_@@_lang_str} + }{ + \seq_get_left:cN {l_stex_symdecl_#1_notations}\l_@@_variant_str + }{ + \seq_if_in:cxTF {l_stex_symdecl_#1_notations}{ + \l_@@_variant_str \c_hash_str \l_@@_lang_str + }{ + \str_set:Nx \l_@@_variant_str { \l_@@_variant_str \c_hash_str \l_@@_lang_str } + }{ + \msg_error:nnxx{stex}{error/nonotation}{#1}{ + ~\l_@@_variant_str \c_hash_str \l_@@_lang_str + } + } + } + } +} + +\cs_new_protected:Npn \_@@_invoke_op_notation:nw #1 [#2] { + \_@@_find_notation:nn { #1 }{ #2 } + \bool_set_false:N \l_@@_allow_semantic_bool + \cs_if_exist:cTF { + stex_op_notation_ #1 \c_hash_str \l_@@_variant_str _cs + }{ + \use:c{stex_op_notation_ #1 \c_hash_str \l_@@_variant_str _cs} + }{ + \msg_error:nnxx{stex}{error/noop}{#1}{\l_@@_variant_str} + } + \bool_set_true:N \l_@@_allow_semantic_bool +} + +\cs_new_protected:Npn \_@@_invoke_notation:nw #1 [#2] { + \_@@_find_notation:nn { #1 }{ #2 } + \cs_if_exist:cTF { + stex_notation_ #1 \c_hash_str \l_@@_variant_str _cs + }{ + \tl_set:Nx \stex_symbol_after_invocation_tl { + \_@@_reset:N \stex_symbol_after_invocation_tl + \_@@_reset:N \l_stex_current_symbol_str + \bool_set_true:N \l_@@_allow_semantic_bool + } + \bool_set_false:N \l_@@_allow_semantic_bool + \use:c{stex_notation_ #1 \c_hash_str \l_@@_variant_str _cs} + }{ + \msg_error:nnxx{stex}{error/nonotation}{#1}{ + ~\l_@@_variant_str + } + } +} + +\prop_new:N \l_@@_custom_args_prop + +\cs_new_protected:Nn \_@@_invoke_custom:nn { + \exp_args:Nnx \use:nn { + \bool_set_false:N \l_@@_allow_semantic_bool + \str_set:Nn \l_stex_current_symbol_str { #1 } + \prop_clear:N \l_@@_custom_args_prop + \prop_put:Nnn \l_@@_custom_args_prop {currnum} {1} + \prop_get:cnN { + l_stex_symdecl_#1 _prop + }{ args } \l_tmpa_str + \prop_put:Nno \l_@@_custom_args_prop {args} \l_tmpa_str + \tl_set:Nn \arg { \_@@_arg: } + \str_if_empty:NTF \l_tmpa_str { + \_stex_term_oms:nnn {#1}{#1}{#2} + }{ + \str_if_in:NnTF \l_tmpa_str b { + \_stex_term_ombind:nnn {#1}{#1}{#2} + }{ + \str_if_in:NnTF \l_tmpa_str B { + \_stex_term_ombind:nnn {#1}{#1}{#2} + }{ + \_stex_term_oma:nnn {#1}{#1}{#2} + } + } + } + % TODO check that all arguments exist + }{ + \_@@_reset:N \l_stex_current_symbol_str + \_@@_reset:N \arg + \_@@_reset:N \l_@@_custom_args_prop + \bool_set_true:N \l_@@_allow_semantic_bool + } +} + +\NewDocumentCommand \_@@_arg: { s O{} m}{ + \tl_if_empty:nTF {#2}{ + \int_set:Nn \l_tmpa_int {\prop_item:Nn \l_@@_custom_args_prop {currnum}} + \bool_set_true:N \l_tmpa_bool + \bool_do_while:Nn \l_tmpa_bool { + \exp_args:NNx \prop_if_in:NnTF \l_@@_custom_args_prop {\int_use:N \l_tmpa_int} { + \int_incr:N \l_tmpa_int + }{ + \bool_set_false:N \l_tmpa_bool + } + } + }{ + \int_set:Nn \l_tmpa_int { #2 } + \exp_args:NNx \prop_if_in:NnT \l_@@_custom_args_prop {\int_use:N \l_tmpa_int} { + % TODO throw error + } + } + \str_set:Nx \l_tmpa_str {\prop_item:Nn \l_@@_custom_args_prop {args} } + \int_compare:nNnT \l_tmpa_int > {\str_count:N \l_tmpa_str} { + % TODO throw error + } + \IfBooleanTF#1{ + \stex_annotate_invisible:n { + \exp_args:No \_stex_term_arg:nn {\l_stex_current_symbol_str}{#3} + } + }{ + \exp_args:No \_stex_term_arg:nn {\l_stex_current_symbol_str}{#3} + } +} + + +\cs_new_protected:Nn \_stex_term_arg:nn { + \exp_args:Nnx \use:nn { + \bool_set_true:N \l_@@_allow_semantic_bool + \stex_annotate:nnn{ arg }{ #1 }{ #2 } + }{ + \bool_set_false:N \l_@@_allow_semantic_bool + } +} + +\cs_new_protected:Nn \_stex_term_math_arg:nnn { + \exp_args:Nnx \use:nn + { \int_set:Nn \l_@@_downprec { #2 } + \_stex_term_arg:nn { #1 }{ #3 } + } + { \int_set:Nn \exp_not:N \l_@@_downprec { \int_use:N \l_@@_downprec } } +} + + +% \end{macrocode} +% \end{macro} +% +% \subsection{Terms} +% +% Precedences: +% \begin{variable}{\infprec, \neginfprec, \l_@@_downprec} +% \begin{macrocode} +\tl_const:Nx \infprec {\int_use:N \c_max_int} +\tl_const:Nx \neginfprec {-\int_use:N \c_max_int} +\int_new:N \l_@@_downprec +\int_set_eq:NN \l_@@_downprec \infprec +% \end{macrocode} +% \end{variable} +% +% Bracketing: +% +% \begin{variable}{\l_@@_left_bracket_str, \l_@@_right_bracket_str} +% \begin{macrocode} +\tl_set:Nn \l_@@_left_bracket_str ( +\tl_set:Nn \l_@@_right_bracket_str ) +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\_@@_maybe_brackets:nn} +% +% Compares precedences and insert brackets accordingly +% +% \begin{macrocode} +\cs_new_protected:Nn \_@@_maybe_brackets:nn { + \bool_if:NTF \l_@@_brackets_done_bool { + \bool_set_false:N \l_@@_brackets_done_bool + #2 + } { + \int_compare:nNnTF { #1 } > \l_@@_downprec { + \bool_if:NTF \l_stex_inparray_bool { #2 }{ + \stex_debug:nn{dobrackets}{\number#1 > \number\l_@@_downprec; \detokenize{#2}} + \dobrackets { #2 } + } + }{ #2 } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\dobrackets} +% \begin{macrocode} +\bool_new:N \l_@@_brackets_done_bool +%\RequirePackage{scalerel} +\cs_new_protected:Npn \dobrackets #1 { + %\ThisStyle{\if D\m@switch + % \exp_args:Nnx \use:nn + % { \exp_after:wN \left\l_@@_left_bracket_str #1 } + % { \exp_not:N\right\l_@@_right_bracket_str } + % \else + \exp_args:Nnx \use:nn + { + \bool_set_true:N \l_@@_brackets_done_bool + \int_set:Nn \l_@@_downprec \infprec + \l_@@_left_bracket_str + #1 + } + { + \bool_set_false:N \l_@@_brackets_done_bool + \l_@@_right_bracket_str + \int_set:Nn \l_@@_downprec { \int_use:N \l_@@_downprec } + } + %\fi} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\withbrackets} +% \begin{macrocode} +\cs_new_protected:Npn \withbrackets #1 #2 #3 { + \exp_args:Nnx \use:nn + { + \tl_set:Nx \l_@@_left_bracket_str { #1 } + \tl_set:Nx \l_@@_right_bracket_str { #2 } + #3 + } + { + \tl_set:Nn \exp_not:N \l_@@_left_bracket_str + {\l_@@_left_bracket_str} + \tl_set:Nn \exp_not:N \l_@@_right_bracket_str + {\l_@@_right_bracket_str} + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\STEXinvisible} +% \begin{macrocode} +\cs_new_protected:Npn \STEXinvisible #1 { + \stex_annotate_invisible:n { #1 } +} +% \end{macrocode} +% \end{macro} +% +% \omdoc terms: +% +% \begin{macro}{\_stex_term_math_oms:nnnn} +% \begin{macrocode} +\cs_new_protected:Nn \_stex_term_oms:nnn { + \stex_annotate:nnn{ OMID }{ #2 }{ + \stex_highlight_term:nn { #1 } { #3 } + } +} + +\cs_new_protected:Nn \_stex_term_math_oms:nnnn { + \_@@_maybe_brackets:nn { #3 }{ + \_stex_term_oms:nnn { #1 } { #1\c_hash_str#2 } { #4 } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\_stex_term_math_omv:nn} +% \begin{macrocode} +\cs_new_protected:Nn \_stex_term_omv:nn { + \stex_annotate:nnn{ OMID }{ #1 }{ + \stex_highlight_term:nn { #1 } { #2 } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\_stex_term_math_oma:nnnn} +% \begin{macrocode} +\cs_new_protected:Nn \_stex_term_oma:nnn { + \stex_annotate:nnn{ OMA }{ #2 }{ + \stex_highlight_term:nn { #1 } { #3 } + } +} + +\cs_new_protected:Nn \_stex_term_math_oma:nnnn { + \_@@_maybe_brackets:nn { #3 }{ + \_stex_term_oma:nnn { #1 } { #1\c_hash_str#2 } { #4 } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\_stex_term_math_omb:nnnn} +% \begin{macrocode} +\cs_new_protected:Nn \_stex_term_ombind:nnn { + \stex_annotate:nnn{ OMBIND }{ #2 }{ + \stex_highlight_term:nn { #1 } { #3 } + } +} + +\cs_new_protected:Nn \_stex_term_math_omb:nnnn { + \_@@_maybe_brackets:nn { #3 }{ + \_stex_term_ombind:nnn { #1 } { #1\c_hash_str#2 } { #4 } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\_stex_term_math_assoc_arg:nnnn} +% \begin{macrocode} +\cs_new_protected:Nn \_stex_term_math_assoc_arg:nnnn { + % TODO sequences + \clist_set:Nn \l_tmpa_clist{ #3 } + \int_compare:nNnTF { \clist_count:N \l_tmpa_clist } < 2 { + \tl_set:Nn \l_tmpa_tl { #3 } + }{ + \cs_set:Npn \l_tmpa_cs ##1 ##2 { #4 } + \clist_reverse:N \l_tmpa_clist + \clist_pop:NN \l_tmpa_clist \l_tmpa_tl + + \clist_map_inline:Nn \l_tmpa_clist { + \exp_args:NNNo \exp_args:NNo \tl_set:No \l_tmpa_tl { + \exp_args:Nno + \l_tmpa_cs { ##1 } \l_tmpa_tl + } + } + } + \exp_args:Nnno + \_stex_term_math_arg:nnn{#1}{#2}\l_tmpa_tl +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\stex_term_custom:nn} +% \begin{macrocode} +\cs_new_protected:Nn \stex_term_custom:nn { + \str_set:Nn \l_@@_custom_uri { #1 } + \str_set:Nn \l_tmpa_str { #2 } + \tl_clear:N \l_tmpa_tl + \int_zero:N \l_tmpa_int + \int_set:Nn \l_tmpb_int { \str_count:N \l_tmpa_str } + \_@@_custom_loop: +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\_@@_custom_loop:} +% \begin{macrocode} +\cs_new_protected:Nn \_@@_custom_loop: { + \bool_set_false:N \l_tmpa_bool + \bool_while_do:nn { + \str_if_eq_p:ee X { + \str_item:Nn \l_tmpa_str { \l_tmpa_int + 1 } + } + }{ + \int_incr:N \l_tmpa_int + } + + \peek_charcode:NTF [ { + % notation/text component + \_@@_custom_component:w + } { + \int_compare:nNnTF \l_tmpa_int = \l_tmpb_int { + % all arguments read => finish + \_@@_custom_final: + } { + % arguments missing + \peek_charcode_remove:NTF * { + % invisible, specific argument position or both + \peek_charcode:NTF [ { + % visible specific argument position + \_@@_custom_arg:wn + } { + % invisible + \peek_charcode_remove:NTF * { + % invisible specific argument position + \_@@_custom_arg_inv:wn + } { + % invisible next argument + \_@@_custom_arg_inv:wn [ \l_tmpa_int + 1 ] + } + } + } { + % next normal argument + \_@@_custom_arg:wn [ \l_tmpa_int + 1 ] + } + } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\_@@_custom_arg_inv:wn} +% \begin{macrocode} +\cs_new_protected:Npn \_@@_custom_arg_inv:wn [ #1 ] #2 { + \bool_set_true:N \l_tmpa_bool + \_@@_custom_arg:wn [ #1 ] { #2 } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\_@@_custom_arg:wn} +% \begin{macrocode} +\cs_new_protected:Npn \_@@_custom_arg:wn [ #1 ] #2 { + \str_set:Nx \l_tmpb_str { + \str_item:Nn \l_tmpa_str { #1 } + } + \str_case:VnTF \l_tmpb_str { + { X } { + \msg_error:nnx{stex}{error/notationarg}{\l_@@_custom_uri} + } + { i } { \_@@_custom_set_X:n { #1 } } + { b } { \_@@_custom_set_X:n { #1 } } + { a } { \_@@_custom_set_X:n { #1 } } % TODO ? + { B } { \_@@_custom_set_X:n { #1 } } % TODO ? + }{}{ + \msg_error:nnx{stex}{error/notationarg}{\l_@@_custom_uri} + } + + \bool_if:nTF \l_tmpa_bool { + \tl_put_right:Nx \l_tmpa_tl { + \stex_annotate_invisible:n { + \_stex_term_arg:nn { \int_eval:n { #1 } } + \exp_not:n { { #2 } } + } + } + } { + \tl_put_right:Nx \l_tmpa_tl { + \_stex_term_arg:nn { \int_eval:n { #1 } } + \exp_not:n { { #2 } } + } + } + + \_@@_custom_loop: +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\_@@_custom_set_X:n} +% \begin{macrocode} +\cs_new_protected:Nn \_@@_custom_set_X:n { + \str_set:Nx \l_tmpa_str { + \str_range:Nnn \l_tmpa_str 1 { #1 - 1 } + X + \str_range:Nnn \l_tmpa_str { #1 + 1 } { -1 } + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\_@@_custom_component:} +% \begin{macrocode} +\cs_new_protected:Npn \_@@_custom_component:w [ #1 ] { + \tl_put_right:Nn \l_tmpa_tl { \comp{ #1 } } + \_@@_custom_loop: +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\_@@_custom_final:} +% \begin{macrocode} +\cs_new_protected:Nn \_@@_custom_final: { + \int_compare:nNnTF \l_tmpb_int = 0 { + \exp_args:Nnno \_stex_term_oms:nnn + }{ + \str_if_in:NnTF \l_tmpa_str {b} { + \exp_args:Nnno \_stex_term_ombind:nnn + } { + \exp_args:Nnno \_stex_term_oma:nnn + } + } + { \l_@@_custom_uri } { \l_@@_custom_uri } { \l_tmpa_tl } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\symref,\symname} +% \begin{macrocode} +\cs_new:Nn \stex_capitalize:n { \uppercase{#1} } + +\keys_define:nn { stex / symname } { + pre .tl_set_x:N = \l_@@_pre_tl , + post .tl_set_x:N = \l_@@_post_tl , + root .tl_set_x:N = \l_@@_root_tl +} + +\cs_new_protected:Nn \stex_symname_args:n { + \tl_clear:N \l_@@_post_tl + \tl_clear:N \l_@@_pre_tl + \tl_clear:N \l_@@_root_str + \keys_set:nn { stex / symname } { #1 } +} + +\NewDocumentCommand \symref { m m }{ + \let\compemph_uri_prev:\compemph@uri + \let\compemph@uri\symrefemph@uri + \STEXsymbol{#1}!{ #2 } + \let\compemph@uri\compemph_uri_prev: +} + +\NewDocumentCommand \synonym { O{} m m}{ + \stex_symname_args:n { #1 } + \let\compemph_uri_prev:\compemph@uri + \let\compemph@uri\symrefemph@uri + % TODO + \STEXsymbol{#2}!{\l_@@_pre_tl #3 \l_@@_post_tl} + \let\compemph@uri\compemph_uri_prev: +} + +\NewDocumentCommand \symname { O{} m }{ + \stex_symname_args:n { #1 } + \stex_get_symbol:n { #2 } + \str_set:Nx \l_tmpa_str { + \prop_item:cn { l_stex_symdecl_ \l_stex_get_symbol_uri_str _prop } { name } + } + \exp_args:NNno \str_replace_all:Nnn \l_tmpa_str {-} {~} + + \let\compemph_uri_prev:\compemph@uri + \let\compemph@uri\symrefemph@uri + \exp_args:NNx \use:nn + \stex_invoke_symbol:n { { \l_stex_get_symbol_uri_str }!{ + \l_@@_pre_tl \l_tmpa_str \l_@@_post_tl + } } + \let\compemph@uri\compemph_uri_prev: +} + +\NewDocumentCommand \Symname { O{} m }{ + \stex_symname_args:n { #1 } + \stex_get_symbol:n { #2 } + \str_set:Nx \l_tmpa_str { + \prop_item:cn { l_stex_symdecl_ \l_stex_get_symbol_uri_str _prop } { name } + } + \exp_args:NNno \str_replace_all:Nnn \l_tmpa_str {-} {~} + \let\compemph_uri_prev:\compemph@uri + \let\compemph@uri\symrefemph@uri + \exp_args:NNx \use:nn + \stex_invoke_symbol:n { { \l_stex_get_symbol_uri_str }!{ + \exp_after:wN \stex_capitalize:n \l_tmpa_str + \l_@@_post_tl + } } + \let\compemph@uri\compemph_uri_prev: +} +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Notation Components} +% \begin{macrocode} +%<@@=stex_notationcomps> +% \end{macrocode} +% +% +% \begin{macro}{\stex_highlight_term:nn} +% \begin{macrocode} + +\str_new:N \l_stex_current_symbol_str +\cs_new_protected:Nn \stex_highlight_term:nn { + \exp_args:Nnx + \use:nn { + \str_set:Nx \l_stex_current_symbol_str { #1 } + #2 + } { + \str_set:Nx \exp_not:N \l_stex_current_symbol_str + { \l_stex_current_symbol_str } + } +} + +\cs_new_protected:Nn \stex_unhighlight_term:n { +% \latexml_if:TF { +% #1 +% } { +% \rustex_if:TF { +% #1 +% } { + #1 %\iffalse{{\fi}} #1 {{\iffalse}}\fi +% } +% } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\comp,\compemph@uri,\compemph,\defemph,\defemph@uri,\symrefemph,\symrefemph@uri} +% \begin{macrocode} +\cs_new_protected:Npn \comp #1 { + \str_if_empty:NF \l_stex_current_symbol_str { + \rustex_if:TF { + \stex_annotate:nnn { comp }{ \l_stex_current_symbol_str }{ #1 } + }{ + \exp_args:Nnx \compemph@uri { #1 } { \l_stex_current_symbol_str } + } + } +} + +\cs_new_protected:Npn \compemph@uri #1 #2 { + \compemph{ #1 } +} + + +\cs_new_protected:Npn \compemph #1 { + #1 +} + +\cs_new_protected:Npn \defemph@uri #1 #2 { + \defemph{#1} +} + +\cs_new_protected:Npn \defemph #1 { + \textbf{#1} +} + +\cs_new_protected:Npn \symrefemph@uri #1 #2 { + \symrefemph{#1} +} + +\cs_new_protected:Npn \symrefemph #1 { + \textbf{#1} +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\ellipses} +% \begin{macrocode} +\NewDocumentCommand \ellipses {} { \ldots } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\parray,\prmatrix,\parrayline,\parraylineh,\parraycell} +% \begin{macrocode} +\bool_new:N \l_stex_inparray_bool +\bool_set_false:N \l_stex_inparray_bool +\NewDocumentCommand \parray { m m } { + \begingroup + \bool_set_true:N \l_stex_inparray_bool + \begin{array}{#1} + #2 + \end{array} + \endgroup +} + +\NewDocumentCommand \prmatrix { m } { + \begingroup + \bool_set_true:N \l_stex_inparray_bool + \begin{matrix} + #1 + \end{matrix} + \endgroup +} + +\def \maybephline { + \bool_if:NT \l_stex_inparray_bool {\hline} +} + +\def \parrayline #1 #2 { + #1 #2 \bool_if:NT \l_stex_inparray_bool {\\} +} + +\def \pmrow #1 { \parrayline{}{ #1 } } + +\def \parraylineh #1 #2 { + #1 #2 \bool_if:NT \l_stex_inparray_bool {\\\hline} +} + +\def \parraycell #1 { + #1 \bool_if:NT \l_stex_inparray_bool {&} +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Variables} +% \begin{macrocode} +%<@@=stex_variables> +% \end{macrocode} +% +% \begin{macro}{\stex_invoke_variable:n} +% +% Invokes a variable +% +% \begin{macrocode} +\cs_new_protected:Nn \stex_invoke_variable:n { + \if_mode_math: + \exp_after:wN \_@@_invoke_math:n + \else: + \exp_after:wN \_@@_invoke_text:n + \fi: {#1} +} + +\cs_new_protected:Nn \_@@_invoke_text:n { + %TODO +} + + +\cs_new_protected:Nn \_@@_invoke_math:n { + \peek_charcode_remove:NTF ! { + \peek_charcode_remove:NTF ! { + \peek_charcode:NTF [ { + \_@@_invoke_op_custom:nw + }{ + % TODO throw error + } + }{ + \_@@_invoke_op:n { #1 } + } + }{ + \peek_charcode_remove:NTF * { + \_@@_invoke_text:n { #1 } + }{ + \_@@_invoke_math_ii:n { #1 } + } + } +} + +\cs_new_protected:Nn \_@@_invoke_op:n { + \cs_if_exist:cTF { + stex_var_op_notation_ #1 _cs + }{ + \use:c{stex_var_op_notation_ #1 _cs } + }{ + \msg_error:nnxx{stex}{error/noop}{variable~#1}{} + } +} + +\cs_new_protected:Npn \_@@_invoke_math_ii:n #1 { + \cs_if_exist:cTF { + stex_var_notation_#1_cs + }{ + \str_set:Nn \l_stex_current_symbol_str { #1 } + \use:c{stex_var_notation_#1_cs} + }{ + \msg_error:nnxx{stex}{error/nonotation}{variable~#1}{s} + } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex + +% \endinput +% Local Variables: +% mode: doctex +% TeX-master: t +% End: |