% \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> \def\libfolder#1{../../lib/#1} \input{../../doc/stex-docheader} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \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} % \changes{3.1.0}{2022/03/10}{SMS mode now loads recursive dependencies \emph{first}} % % Code related to Module Inheritance, in particular \emph{sms mode}. % %\ifinfulldoc\else % \input{../../doc/packages/stex-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 \assign \renamedecl \donotcopy \instantiate \textsymdecl } \exp_args:NNx \seq_set_from_clist:Nn \g_stex_smsmode_allowedenvs_seq { \tl_to_str:n { smodule, copymodule, interpretmodule, realization, sdefinition, sexample, sassertion, sparagraph, mathstructure, extstructure, extstructure* } } % \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 { \stex_suppress_html:n { \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 \NewDocumentCommand \_@@_importmodule: { O{} m} { \seq_gput_right:Nn \l_@@_importmodules_seq {{#1}{#2}} \stex_smsmode_do: } \cs_new_protected:Nn \_@@_module:nn { \__stex_modules_args:n{#1} \stex_if_in_module:F { \str_if_empty:NF \l_stex_module_sig_str { \stex_modules_current_namespace: \str_set:Nx \l_stex_module_name_str { #2 } \stex_if_module_exists:nF{\l_stex_module_ns_str?\l_stex_module_name_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 % \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:NNx \seq_gput_right:Nn \l_@@_sigmodules_seq \l_tmpa_str }{ \msg_error:nnx{stex}{error/unknownmodule}{for~signature~\l_tmpa_str} } } } } } \prg_new_conditional:Nnn \_@@_check_import_pair:nn {T,F,TF} { %\stex_debug:nn{import-pair}{\detokenize{{#1}~{#2}}} \tl_if_empty:nTF{#1}{ \prop_if_exist:NTF \l_stex_current_repository_prop { %\stex_debug:nn{import-pair}{in repository \prop_item:Nn \l_stex_current_repository_prop {id}} \prg_return_true: } { \seq_set_split:Nnn \l_tmpa_seq ? {#2} \seq_get_left:NN \l_tmpa_seq \l_tmpa_tl \tl_if_empty:NT \l_tmpa_tl { \seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl } %\stex_debug:nn{import-pair}{\seq_use:Nn \l_tmpa_seq,~of~length~\seq_count:N \l_tmpa_seq} \int_compare:nNnTF {\seq_count:N \l_tmpa_seq} > 1 \prg_return_true: \prg_return_false: } }\prg_return_true: } \cs_new_protected:Nn \stex_file_in_smsmode:nn { \stex_filestack_push:n{#1} \seq_gclear:N \l_@@_importmodules_seq \seq_gclear:N \l_@@_sigmodules_seq % ----- new ----------------------------- \_@@_in_smsmode:nn{#1}{ \let\importmodule\_@@_importmodule: \let\stex_module_setup:nn\_@@_module:nn \let\__stex_modules_begin_module:\relax \let\__stex_modules_end_module:\relax \seq_clear:N \g_stex_smsmode_allowedenvs_seq \exp_args:NNx \seq_put_right:Nn \g_stex_smsmode_allowedenvs_seq {\tl_to_str:n{smodule}} \tl_clear:N \g_stex_smsmode_allowedmacros_tl \tl_clear:N \g_stex_smsmode_allowedmacros_escape_tl \tl_put_right:Nn \g_stex_smsmode_allowedmacros_escape_tl {\importmodule} \everyeof{\q_@@_break\noexpand} \expandafter\expandafter\expandafter \stex_smsmode_do: \csname @ @ input\endcsname "#1"\relax \seq_map_inline:Nn \l_@@_sigmodules_seq { \stex_filestack_push:n{##1} \expandafter\expandafter\expandafter \stex_smsmode_do: \csname @ @ input\endcsname "##1"\relax \stex_filestack_pop: } } % ----- new ----------------------------- \_@@_in_smsmode:nn{#1} { #2 % ----- new ----------------------------- \begingroup %\stex_debug:nn{smsmode}{Here:~\seq_use:Nn\l_@@_importmodules_seq, } \seq_map_inline:Nn \l_@@_importmodules_seq { \_@@_check_import_pair:nnT ##1 { \begingroup \stex_import_module_uri:nn ##1 \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 \endgroup } } \endgroup \stex_debug:nn{smsmode}{Actually~loading~file~#1} % ----- new ----------------------------- \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_module_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 { \stex_path_from_string:Nn \l_tmpb_seq { \l_stex_module_ns_str / .. / \l_stex_import_path_str } \str_set:Nx \l_stex_import_ns_str {\stex_path_to_string:N \l_tmpb_seq} \str_replace_once:Nnn \l_stex_import_ns_str {file:/} {file://} } }{ \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 } { \stex_debug:nn{requiremodule}{Here:\\~~1:~#1\\~~2:~#2\\~~3:~#3\\~~4:~#4} \exp_args:NNxx \seq_set_split:Nnn \l_tmpa_seq {\tl_to_str:n{/}} {#4} \seq_get_left:NN \l_tmpa_seq \l_tmpc_str %\stex_debug:nn{requiremodule}{Top~module:\l_tmpc_str} % 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 \seq_put_right:Nn \l_tmpa_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 / \l_tmpc_str } \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~a1~\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~a2~\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~a3~\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_tmpb_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_canonicalize:N \l_tmpb_seq \stex_path_to_string:NN \l_tmpb_seq \l_tmpa_str \stex_debug:nn{modules}{Checking~b1~\l_tmpa_str/\l_tmpc_str.\l_tmpb_str.tex} \IfFileExists{ \l_tmpa_str/\l_tmpc_str.\l_tmpb_str.tex }{ \str_gset:Nx \g_@@_file_str { \l_tmpa_str/\l_tmpc_str.\l_tmpb_str.tex } }{ \stex_debug:nn{modules}{Checking~b2~\l_tmpa_str/\l_tmpc_str.tex} \IfFileExists{ \l_tmpa_str/\l_tmpc_str.tex }{ \str_gset:Nx \g_@@_file_str { \l_tmpa_str/\l_tmpc_str.tex } }{ % try english as default \stex_debug:nn{modules}{Checking~b3~\l_tmpa_str/\l_tmpc_str.en.tex} \IfFileExists{ \l_tmpa_str/\l_tmpc_str.en.tex }{ \str_gset:Nx \g_@@_file_str { \l_tmpa_str/\l_tmpc_str.en.tex } }{ \stex_debug:nn{modules}{Checking~b4~\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~b4~\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~b5~\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} } } } } } } } \str_if_eq:eeF{\g_@@_file_str}{\seq_use:Nn \g_stex_currentfile_seq /}{ \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_annotate_invisible:nnn {import} {\l_stex_import_ns_str ? \l_stex_import_name_str} {} } \stex_execute_in_module:x { \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} \cs_new_protected:Nn \stex_csl_to_imports:Nn { \tl_if_empty:nF{#2}{ \clist_set:Nn \l_tmpa_clist {#2} \clist_map_inline:Nn \l_tmpa_clist { \tl_if_head_eq_charcode:nNTF {##1}[{ #1 ##1 }{ #1{##1} } } } } \cs_generate_variant:Nn \stex_csl_to_imports:Nn {No} % % \end{macrocode} % % \end{implementation} % \ifinfulldoc\else\printbibliography\fi % % \PrintIndex