% \iffalse meta-comment % % Copyright (C) 2019-2026 by Pablo González L % % This work may be distributed and/or modified under the conditions of the % LaTeX Project Public License, either version 1.3c of this license or (at % your option) any later version. The latest version of this license is in % % https://www.latex-project.org/lppl.txt % % and version 1.3c or later is part of all distributions of LaTeX version % 2005/12/01 or later. % % This work is "maintained" (as per the LPPL maintenance status) % by Pablo González Luengo. % % This work consists of the files scontents.dtx and % scontents.ins, % and the derived files scontents.sty, % scontents.tex, % t-scontents.mkiv and % scontents-code.tex. % %<*driver> \documentclass[full]{l3doc} \usepackage[svgnames]{xcolor} \usepackage[sf,bf,compact,medium,pagestyles]{titlesec} \usepackage{lastpage,microtype,attachfile2,multicol,listings,titletoc,fontawesome5} \usepackage{graphicx} \usepackage[english]{babel} \usepackage[top=0.5in,bottom=0.3in,left=2in,right=0.7in,footskip=0.2in,headheight=1cm,headsep=0.27cm]{geometry} % Set \parindent and \parskip \setlength{\parindent}{0pt} \setlength{\parskip}{\smallskipamount} % Extra stretch before overflowing the line \setlength{\emergencystretch}{2em} % Only for arara... I like arara :) \usepackage[scale=0.85]{comfortaa} \definecolor{araracolor}{rgb}{0, 0.72, 0.28} \newcommand{\araratext}[1]{{\small\normalfont\comfortaa\color{araracolor}\bfseries#1}} \newcommand*\arara{\araratext{ar\kern-.03emar\kern-.03ema}} % Fonts, libertine is only loaded for \LKeyTab \usepackage[llscaled=0.95]{libertine} \usepackage[osf,nomath,mono=false,ScaleSF=0.95,ScaleRM=0.95]{libertinus-otf} % Set Monospace font, fix 'quotes' in verbatim \usepackage{sourcecodepro} \defaultfontfeatures[\ttfamily] { Numbers = OldStyle, Scale = 0.84249, Extension = .otf, } \setmonofont[ UprightFont = *-Regular, ItalicFont = *-RegularIt, BoldFont = *-Medium, BoldItalicFont = *-MediumIt, RawFeature = {+zero,+ss01}]{SourceCodePro} \newfontfamily\mysourcecodeprolight{SourceCodePro-Regular.otf}[ Scale = 0.80,FakeStretch =0.75, FontFace = {m}{it}{Font =SourceCodePro-RegularIt.otf,Color=FF0000}] \RenewDocumentCommand{\MacroLongFont}{} { \mysourcecodeprolight\small } % Internal \newfontfamily\mylmrotf{lmroman10-regular.otf}[NFSSFamily=lmrotf,Scale = 0.95] \newfontfamily\mylmmotf{lmmono10-regular.otf}[NFSSFamily=lmmotf,Scale = 0.95] % The character of visible space is now taken from Latin Modern Mono % to prevent fonts in T1. The original definition for xetex/luatex is % \def\verbvisiblespace{\usefont{OT1}{cmtt}{m}{n}\asciispace} \def\verbvisiblespace{{\fontfamily{lmmotf}\fontshape{n}\selectfont\char"2423}} % Math font \usepackage{unicode-math} \setmathfont[Scale = 0.95]{latinmodern-math.otf} \newfontfamily\fetamontotf{ffmw10.otf}[ Scale = 0.95,% RawFeature = {+latn,+rand,+kern,+size},% FontFace = {b}{n}{ffmw10.otf},% fix replace font ] % Index \usepackage{imakeidx} \indexsetup{level=\section,firstpagestyle=myheader,othercode=\pagestyle{myheader}} % imakeidx also opens a write stream for the .idx file, and that conflicts % with the one opened by l3doc. Here we close that write stream: \ExplSyntaxOn \iow_close:c { @indexfile } % and later we will copy the write stream opened by imakeidx into \@indexfile % so that entries written to both streams end up in the same file. \makeindex[name=userdoc,options={-q ~ -s ~ gind.ist},columnsep=15pt,title={Index ~ of ~ Documentation}] \makeindex[options={-q ~ -s ~ gind.ist},columnsep=15pt,title={Index ~ of ~ Implementation}] \EnableCrossrefs % \PageIndex, \CodelineIndex undoes what \PageIndex does % \CodelineIndex tries to open another write stream for the index file. We don't % want that, so we temporarily make \makeindex a no-op: \cs_set_eq:NN \l__mydoc_tmp_makeindex_cs \makeindex \cs_set_nopar:Npn \makeindex { } \CodelineIndex \cs_set_eq:NN \makeindex \l__mydoc_tmp_makeindex_cs \DoNotIndex{\ , \1,\^} \exp_args:Ne \DoNotIndex { \tl_to_str:n { \{ } } \exp_args:Ne \DoNotIndex { \tl_to_str:n { \} } } \exp_args:Ne \DoNotIndex { \tl_to_str:n { \begin } } % \StartImplementation \cs_new_protected:Npn \StartImplementation { \bool_set_true:N \l__codedoc_in_implementation_bool } \bool_set_false:N \l__codedoc_in_implementation_bool % Links and index \newcommand{\HP}[1]{\emph{\hyperpage{#1}}\normalsize} \cs_new_protected:Nn \__mydoc_sort_index:nn { \bool_if:NTF \l__codedoc_in_implementation_bool { \index{#1\actualchar#2|HP} } { \index[userdoc]{#1\actualchar#2|HP} } } % Now, after imakeidx opens the write stream for the index file, we copy % the reference to \@indexfile: \cs_set_eq:cc { @indexfile } { \c_sys_jobname_str @idxfile } \ExplSyntaxOff % Package documented \usepackage{scontents} % main % LuaLaTeX syntax highlighter for l3doc (it also defines the color palette) \usepackage{mylhmc} \setmylhmc { module = scontents, provide = { setupsc, newenvsc, Scontents, getstored, foreachsc, typestored, meaningsc, mergesc, countsc, cleanseqsc, scontents, endscontents, startscontents, stopscontents, verbatimsc, endverbatimsc, stopverbatimsc }, key-path = {typemeaning,}, } % Colors \definecolor{newlinkcolor}{HTML}{0A602C} \definecolor{rulecolor}{rgb}{0.96,0.96,0.96} % Get file info \GetFileInfo{scontents.sty} % Config hyperref \hypersetup { allcolors = newlinkcolor, colorlinks = true, linktoc = all, pdftitle = {.:: The scontents package --- \fileinfo{} ::.}, pdfauthor = {Pablo González L}, pdfsubject = {Documentation for \fileversion{} [\filedate] }, pdfkeywords = {sequences, contents, external files, expl3, l3seq, store contents, tagged}, bookmarksopenlevel = 1, } % User level commands \ExplSyntaxOn % Logo with fetamont font \NewDocumentCommand \pkglogo { } { \group_begin: \fetamontotf { \textcolor { module_name } { s } \textcolor { OrangeRed } { content } \textcolor { module_name } { s } } \group_end: } % Custom \meta[...]{...}, \marg[...]{...} and \oarg[...]{...} with color \NewDocumentCommand \mymeta { O{} m } { \__mydoc_meta_generic:Nnn \__mydoc_meta:n { #1 } { #2 } } \NewDocumentCommand \mymarg { O{} m } { \__mydoc_meta_generic:Nnn \__mydoc_marg:n { #1 } { #2 } } \NewDocumentCommand \myoarg { O{} m } { \__mydoc_meta_generic:Nnn \__mydoc_oarg:n { #1 } { #2 } } % Variables and keys \tl_new:N \l_userdoc_meta_font_tl \keys_define:nn { userdoc / mymeta } { type .choice:, type / tt .code:n = \tl_set:Nn \l_userdoc_meta_font_tl { \ttfamily }, type / rm .code:n = \tl_set:Nn \l_userdoc_meta_font_tl { \rmfamily }, type .initial:n = tt, cf .tl_set:N = \l_userdoc_meta_color_tl, cf .initial:n = keyname, ac .tl_set:N = \l_userdoc_meta_anglecolor_tl, ac .initial:n = lightgray, sbc .tl_set:N = \l_userdoc_meta_brackcolor_tl, sbc .initial:n = gray, cbc .tl_set:N = \l_userdoc_meta_bracecolor_tl, cbc .initial:n = gray, } % Internal commands \cs_new_protected:Npn \__mydoc_meta_generic:Nnn #1 #2 #3 { \group_begin: \keys_set:nn { userdoc / mymeta } { #2 } \color{ \l_userdoc_meta_color_tl } \l_userdoc_meta_font_tl #1 { #3 } % #1 is \__mydoc_meta:n, \__mydoc_marg:n or \__mydoc_oarg:n \group_end: } \cs_new_protected:Npn \__mydoc_meta:n #1 { \__mydoc_meta_angle:n { \textlangle } \__mydoc_meta_meta:n { #1 } \__mydoc_meta_angle:n { \textrangle } } \cs_new_protected:Npn \__mydoc_marg:n #1 { \__mydoc_meta_brace:n { \textbraceleft } \__mydoc_meta:n { #1 } \__mydoc_meta_brace:n { \textbraceright } } \cs_new_protected:Npn \__mydoc_oarg:n #1 { \__mydoc_meta_brack:n { [ } \__mydoc_meta:n { #1 } \__mydoc_meta_brack:n { ] } } \cs_new_protected:Npn \__mydoc_meta_meta:n #1 { \textnormal{\textit{#1}} } \cs_new_protected:Npn \__mydoc_meta_angle:n #1 { \group_begin: \fontfamily{lmrotf}\fontshape{n}\selectfont \textcolor{\l_userdoc_meta_anglecolor_tl}{#1} \group_end: } \cs_new_protected:Npn \__mydoc_meta_brace:n #1 { \group_begin: \color{\l_userdoc_meta_bracecolor_tl} #1 \group_end: } \cs_new_protected:Npn \__mydoc_meta_brack:n #1 { \textcolor{\l_userdoc_meta_brackcolor_tl}{#1} } % Color the characters matched by the regex #2 in the token list #1 with the % palette color #3 (only the first match, or every match) \cs_new_protected:Npn \__mydoc_color_once:Nnn #1 #2 #3 { \regex_replace_once:nnN { ( #2 ) } { \c{textcolor}\cB\{#3\cE\}\cB\{\1\cE\} } #1 } \cs_new_protected:Npn \__mydoc_color_all:Nnn #1 #2 #3 { \regex_replace_all:nnN { ( #2 ) } { \c{textcolor}\cB\{#3\cE\}\cB\{\1\cE\} } #1 } % \envexamp{m}: syntax of an environment, \begin{env}[key=val] ... \end{env} \newsavebox{\boxexaenv} \NewDocumentCommand \envexamp { m } { \begin{lrbox}{\boxexaenv}% \begin{minipage}[t]{\marginparwidth}% \raggedright\ttfamily\small \textcolor{gray}{\textbackslash begin\{\textcolor{module_name}{#1}\}\myoarg [type=tt,sbc=gray,ac=lightgray,cf=keyname]{key\textnormal{\textcolor{gray}{=}}val}}\par% \hspace{0.5cm}\mymeta[type=tt,ac=lightgray,cf=gray]{body~env}\par% \textcolor{gray}{\textbackslash end\{\textcolor{module_name}{#1}\}}\par \end{minipage}% \end{lrbox}% \usebox{\boxexaenv} } % \envexaplain{O{} m O{end}}: syntax of a pseudo environment in plain TeX % (\scontents ... \endscontents) or ConTeXt (\startscontents ... \stopscontents) \NewDocumentCommand \envexaplain { O{} m O{end} } { \begin{lrbox}{\boxexaenv}% \begin{minipage}[t]{\marginparwidth}% \raggedright\ttfamily\small \textcolor{module_name}{\textbackslash#1#2}\myoarg [type=tt,sbc=gray,ac=lightgray,cf=keyname]{key\textnormal{\textcolor{gray}{=}}val}\par% \hspace{0.5cm}\mymeta[type=tt,ac=lightgray,cf=gray]{body~env}\par% \textcolor{module_name}{\textbackslash#3#2}\par \end{minipage}% \end{lrbox}% \usebox{\boxexaenv} } % \cmdexamp{o m o m o} \tl_new:N \l__mydoc_cmdexamp_tl \NewDocumentCommand \cmdexamp { o m o m o } { \group_begin: \small\ttfamily \textcolor{module_name}{\textbackslash#2} \IfValueT{#1}{ \textcolor{star}{#1} } \IfValueT{#3} { \tl_set:Nn \l__mydoc_cmdexamp_tl { #3 } \regex_replace_once:nnN { (\*) } { \c{texttt}\cB\{\c{textcolor}\cB\{star\cE\}\cB\{\1\cE\} \cE\} } \l__mydoc_cmdexamp_tl \myoarg[type=tt,sbc=gray,ac=lightgray,cf=keyname]{\tl_use:N \l__mydoc_cmdexamp_tl} } \IfValueTF{#5} { \mymeta[ac=gray,type=tt,cf=star]{#5}% \mymeta[type=tt,ac=gray,cf=keyname]{#4} \mymeta[ac=gray,type=tt,cf=star]{#5}% } { \mymarg[type=tt,cbc=gray,ac=lightgray,cf=keyname]{#4} } \par \group_end: } % Index entries for the keys. #1 is the target: 'env' (environments in % general) or the name of a command (printed with a backslash). #2 is the key. \cs_new_protected:Npn \__mydoc_key_index:nn #1 #2 { \str_case:nnF {#1} { { env } { \__mydoc_sort_index:nn { Keys } { Keys~for~environments~provided~by~\pkglogo :> \texttt {#2} } } } { \__mydoc_sort_index:nn { Keys } { Keys~for~\texttt { \textbackslash #1 }~provided~by~\pkglogo :> \texttt {#2} } } } \cs_new_protected:Npn \__mydoc_key_index_list:nn #1 #2 { \clist_map_inline:nn {#1} { \__mydoc_key_index:nn {##1} {#2} } } % Key line: name hanging in the margin, value, and default % \__mydoc_key_line:Nnnn {boolean} {key} {value} {default} \cs_new_protected:Npn \__mydoc_key_line:Nnnn #1 #2 #3 #4 { \group_begin: \noindent \mode_leave_vertical: \hbox_to_wd:nn { -\marginparsep } { \hss \textcolor { keyname } { \small \ttfamily {#2} } } \IfBooleanTF {#1} { \hphantom { \textcolor { white } { \, \bfseries \texttt{=} } \, {} } \mymeta [ type=tt, cbc=gray, ac=lightgray, cf=lightgray ] { \small {#3} } } { \textcolor { gray } { \, \bfseries \texttt{=} } \, {} \mymarg [ type=tt, cbc=gray, ac=lightgray, cf=keyname ] { \small {#3} } } \hfill \textcolor { gray } { \small \textsf { default } :~ \emph{#4} } \par \group_end: } % \keyexampcmd{s m m m o}, the optional #5 is a clist of targets for the % index (env or a command name); without it there is no index entry \NewDocumentCommand \keyexampcmd { s m m m o } { \__mydoc_key_line:Nnnn #1 {#2} {#3} {#4} \IfValueT {#5} { \__mydoc_key_index_list:nn {#5} {#2} } } % \mykey{o m}, the optional #1 is a clist of targets for the index \tl_new:N \l__mydoc_name_tl \NewDocumentCommand \mykey { o m } { \group_begin: \tl_set:Nn \l__mydoc_name_tl { #2 } \__mydoc_color_once:Nnn \l__mydoc_name_tl { \* } { star } \textcolor { keyname } { \ttfamily \tl_use:N \l__mydoc_name_tl } \IfValueT {#1} { \__mydoc_key_index_list:nn {#1} { \tl_use:N \l__mydoc_name_tl } } \group_end: } % \mypkg{s O{} m}, use the optional argument [no-index] to skip the index \NewDocumentCommand \mypkg { s O{} m } { \group_begin: \IfBooleanTF {#1} { \pkglogo } { \textcolor { pkgname } { \textbf { \texttt {#3} } } } \str_if_eq:nnF {#2} { no-index } { \__mydoc_sort_index:nn { packages } { Packages~:>~\texttt {#3} } } \group_end: } % \myenv{s O{} m}, use the optional argument [no-index] to skip the index \NewDocumentCommand \myenv { s O{} m } { \IfBooleanTF {#1} { \tl_set:Nn \l__mydoc_name_tl { #3 } \__mydoc_color_once:Nnn \l__mydoc_name_tl { \* } { star } \textcolor { module_name } { \ttfamily { \tl_use:N \l__mydoc_name_tl } } \str_if_eq:nnF {#2} { no-index } { \__mydoc_sort_index:nn { environment } { Environments~provided~by~\pkglogo :> \texttt { \tl_use:N \l__mydoc_name_tl } } } } { \textcolor { pkgname } { \ttfamily {#3} } \str_if_eq:nnF {#2} { no-index } { \__mydoc_sort_index:nn { environment } { Environments~:>~\texttt {#3} } } } } % \ics{s m} \NewDocumentCommand \ics { s m } { \IfBooleanTF {#1} { \tl_set:Nn \l__mydoc_name_tl { #2 } \__mydoc_color_once:Nnn \l__mydoc_name_tl { \* } { star } \textcolor { module_name } { \ttfamily \textbackslash { \tl_use:N \l__mydoc_name_tl } } \__mydoc_sort_index:nn { Commands } { Commands~provided~by~\pkglogo :> \texttt { \textbackslash #2 } } } { \textcolor { latex_cmd } { \ttfamily \textbackslash {#2} } \__mydoc_sort_index:nn {#2} { \texttt { \textbackslash #2 } } } } % \myfile{m} \NewDocumentCommand \myfile { m } { \group_begin: \tl_set:Nn \l__mydoc_name_tl { #1 } \__mydoc_color_all:Nnn \l__mydoc_name_tl { \d } { number } \__mydoc_color_all:Nnn \l__mydoc_name_tl { \. } { star } \textcolor { filename } { \ttfamily \tl_use:N \l__mydoc_name_tl } \group_end: } % \myattachfile{s m}, the star version attaches only the \texttt{.tex} file \NewDocumentCommand \myattachfile { s m } { \group_begin: \IfBooleanTF { #1 } { \IfFileExists { #2.tex } { Source~file~ \textattachfile[color=newlinkcolor,print=false]{#2.tex}{\faFile*[regular]}. } { } } { \IfFileExists { #2.pdf } { Source~file~ \textattachfile[color=newlinkcolor,print=false]{#2.tex}{\faFile*[regular]}~ and~\emph{tagged}~\texttt{PDF}~ \textattachfile[color=newlinkcolor,print=false]{#2.pdf}{\faFilePdf[regular]}. } { } } \group_end: } % Space before the function environment \hook_gput_code:nnn { env/function/before } { mydoc } { \vspace* { -\baselineskip } } % Icons in the margin for the environment important (internal use) \cs_new_protected:Npn \__mydoc_margin_icon:n #1 { \par \mode_leave_vertical: \skip_horizontal:n { -0.5 \marginparsep } \hbox_overlap_left:n { \hbox_to_wd:nn { \marginparsep } { \hss \textcolor { module_at } { #1 } } } \skip_horizontal:n { 0.5 \marginparsep } } % Environment for notes \NewDocumentEnvironment { important } { s } { \par\addvspace { \smallskipamount } \small\sffamily \IfBooleanTF { #1 } { \__mydoc_margin_icon:n { \footnotesize \faIcon { bomb } } } { \__mydoc_margin_icon:n { \scriptsize \reflectbox { \faIcon { tag } } } } \ignorespaces } { } % Parse and format an e-mail address \seq_new:N \l__mydoc_email_seq \cs_new_protected:Npn \__mydoc_format_email:n #1 { \seq_set_split:Nnn \l__mydoc_email_seq { @ } { #1 } \href { mailto:#1 } { \ttfamily \seq_item:Nn \l__mydoc_email_seq { 1 } \textcolor { arroba } { \footnotesize @ } \seq_item:Nn \l__mydoc_email_seq { 2 } } } \NewDocumentCommand \email { m } { \__mydoc_format_email:n { #1 } } % Don't copy numbers in code example \newcommand*{\noaccsupp}[1] { \__mylhmc_luafun_actual_text_begin: #1 \__mylhmc_luafun_actual_text_end: } \ExplSyntaxOff % Custom verbatimsc, used by \typestored in this documentation \ExplSyntaxOn \cs_undefine:N \verbatimsc \cs_undefine:N \endverbatimsc \ExplSyntaxOff \lstnewenvironment{verbatimsc} { \lstset{ language =,% basicstyle = \ttfamily\small, gobble = 2,% } }{} % Create a language for documentation \lstdefinelanguage{scontents-doc}{ texcsstyle = *,% escapechar = Ç,% extendedchars = true,% keepspaces = true,% stringstyle = {\color{red}},% basicstyle = \ttfamily\small,% alsoletter = {-,@,.},% % comments morecomment = [l]{\%},% commentstyle = \ttfamily\small\color{comment},% % Important \documentclass \begin \end \makeatletter \NewDocumentCommand keywordstyle = [1]{\bfseries\color{structure}},% keywords = [1]{begin, end, document, documentclass, makeatletter, makeatother,% ExplSyntaxOn, ExplSyntaxOff, NewDocumentCommand, RenewDocumentCommand},% % Other words \usepackage keywordstyle = [2]{\color{pkgstruct}},% keywords = [2]{usepackage, RequirePackage, ProvidesExplPackage, input, usemodule},% % Other words 3 tagpdf keywordstyle = [3]{\color{mathtag}},% keywords = [3]{DocumentMetadata, IfDocumentMetadataTF},% % Other words 4 (LaTeX2e and expl3) keywordstyle = [4]{\color{latex_cmd}},% keywords = [4]{section, subsection, lstinline, Verb, verb, macro, makebox, detokenize,% meaning, definetyping, lstset, small, ttfamily, tiny, color, scantokens,% setlength, pagestyle, definecolor, obeyedline, item, par, parindent,% newtheorem, newenvironment, DefineVerbatimEnvironment, lstnewenvironment,% newminted, VerbatimEnvironment, dospecials, char, jobname, setuptyping,% peek_charcode_ignore_spaces, cs_argument_spec, cs_parameter_spec,% regex_replace_all, tl_replace_all, tex_scantokens, tex_endinput,% file_input_stop, peek_charcode, cs_undefine, tl_rescan, int_to_roman,% tl_retokenize, int_step_tokens, keys_set, l_keys_key_str, tl_gset_rescan,% contextlmtxmode},% % Other words 5 (package name) keywordstyle = [5]{\bfseries\color{pkgname}},% keywords = [5]{listings, minted, fancyvrb, fvextra, tcolorbox},% % Reserved words 6 (document class) keywordstyle = [6]{\bfseries\color{clsname}},% keywords = [6]{article},% % Reserved words 7 (scontents cmd) keywordstyle = [7]{\color{module_name}},% keywords = [7]{scontents, Scontents, getstored, typestored, verbatimsc, mergesc,% endverbatimsc, countsc, meaningsc, foreachsc, newenvsc, setupsc, cleanseqsc,% endverbatim, endscontents, startscontents, stopscontents, scontents.tex,% startverbatimsc, stopverbatimsc, myenvstore},% % Reserved words 8 (keyname) KEYS keywordstyle = [8]{\color{keyname}},% keywords = [8]{store-cmd, store-env, print-env, print-cmd, write-env, verb-font,% start, stop, wrapper, sep, step, before, after, write-out, write-cmd,% overwrite, width-tab, force-eol, store-all, print-all, debug-var, 1-end, remember,% I, J, M, L, Ascheol, lang, pdfversion, pdfstandard, testphase, tagging},% % Reserved words 9 (values) keywordstyle = [9]{\color{ltcmd_arg}},% keywords = [9]{true, false, myseq, inner, outer, env, Verbatim, en-US, ua-2, on},% % Reserved words 10 (signature) keywordstyle = [10]{\color{sigargs}},% keywords = [10]{NTF, N, x, e, n, nn, nnn, D, Nnn},% % Reserved words 12 (plain TeX or internal) keywordstyle = [12]{\color{danger}},% keywords = [12]{let, @undefined, def, @bsphack, @esphack, @ifpackagelater,% ver@xparse.sty, ver@scontents.sty, l__scontents_ver_str, do@noligs,% MakeFile},% % Reserved words 13 (message names) keywordstyle = [13]{\color{red}},% keywords = [13]{already-loaded, cmd-key-unknown, cmd-key-value-unknown,% empty-argument-command, empty-environment, empty-store-name,% empty-variable, env-already-defined, env-key-unknown,% env-key-value-unknown, expl-too-old, index-out-of-range,% junk-after-begin, luametatex, mergesc-missing-key, multiple-begin,% not-writing, overwrite-file, positive-integer, remember-latex-only,% remember-rerun, remember-undefined, rescanning-text,% undefined-storage, writing-file},% % literate literate =*{\{}{{{\color{brace}{\char`\{}}}}{1} {\}}{{{\color{brace}{\char`\}}}}}{1} {\|}{{{\color{gray}{\char`\|}}}}{1} {\$}{{{\color{math}{\char`\$}}}}{1} {\#}{{{\color{argument}{\char`\#}}}}{1} {[}{{\textcolor{bracket}{[}}}{1} {]}{{\textcolor{bracket}{]}}}{1} {,}{{\textcolor{gray}{,}}}{1} {;}{{\textcolor{gray}{;}}}{1} {:}{{\textcolor{signature}{:}}}{1} {`}{{\textcolor{backtick}{\textasciigrave}}}{1} {\&}{{\textcolor{gray}{\&}}}{1} {>}{{\textcolor{quote}{\guillemotright}}}{1} {<}{{\textcolor{quote}{\guillemotleft}}}{1} {*}{{\textcolor{star}{*}}}{1} {\^}{{\textcolor{keyname}{\textasciicircum}}}{1} {0}{{\textcolor{argnum}{0}}}{1} {1}{{\textcolor{argnum}{1}}}{1} {2}{{\textcolor{argnum}{2}}}{1} {3}{{\textcolor{argnum}{3}}}{1} {4}{{\textcolor{argnum}{4}}}{1} {5}{{\textcolor{argnum}{5}}}{1} {6}{{\textcolor{argnum}{6}}}{1} {7}{{\textcolor{argnum}{7}}}{1} {8}{{\textcolor{argnum}{8}}}{1} {9}{{\textcolor{argnum}{9}}}{1} {.0}{{\textcolor{argnum}{.0}}}{2}% Following is to ensure that only periods {.1}{{\textcolor{argnum}{.1}}}{2}% followed by a digit are changed. {.2}{{\textcolor{argnum}{.2}}}{2} {.3}{{\textcolor{argnum}{.3}}}{2} {.4}{{\textcolor{argnum}{.4}}}{2} {.5}{{\textcolor{argnum}{.5}}}{2} {.6}{{\textcolor{argnum}{.6}}}{2} {.7}{{\textcolor{argnum}{.7}}}{2} {.8}{{\textcolor{argnum}{.8}}}{2} {.9}{{\textcolor{argnum}{.9}}}{2} {=}{{\textcolor{compare}{=}}}{1},% }[keywords,tex,comments,strings]% end language % \begin{examplecode}[key=val]...\end{examplecode} \lstnewenvironment{examplecode}[1][]{% \lstset{ language = scontents-doc,% stringstyle = {\color{red}},% basicstyle = \ttfamily\small,% columns = fullflexible,% fontadjust = true,% aboveskip = 8pt,% belowskip = 5pt,% rulecolor = \color{gray!50},% framesep = \fboxsep,% framerule = \fboxrule,% xleftmargin = \dimexpr\fboxsep+\fboxrule\relax,% xrightmargin= \dimexpr\fboxsep+\fboxrule\relax,% #1,% }% close lstset }{}% close examplecode % \lstinline[style=inline]|...| \lstdefinestyle{inline} { language = scontents-doc,% upquote = true,% numbersep = 1em,% numberstyle = \tiny\color{lightgray}\noaccsupp,% literate =*{\%}{{\textcolor{percent}{\%}}}{1} } % Set default \lstinline style \lstset{style=inline} % Remove `"` and `|` for short verbatim defined in l3doc, then set short |...| \AtBeginDocument { \DeleteShortVerb \" \DeleteShortVerb \| \lstMakeShortInline[language=scontents-doc,basicstyle=\ttfamily]\| } % Configuration titleps and titlesec \settitlemarks{section} \renewpagestyle{plain}[\color{keyname}\small\sffamily]{% \setfoot{\rlap{\hskip\dimexpr-\oddsidemargin-1in\relax% \parbox{1.93\paperwidth}{\hfil\thepage\,/\,\pageref{LastPage}}}}% {}% {}% } \newpagestyle{myheader}[\color{keyname}\small\sffamily]{% \renewcommand\makeheadrule{% \rlap{\hskip\dimexpr-\oddsidemargin-1in\relax \color{rulecolor}\rule[0.3cm]{\paperwidth}{0.7cm}}\hss } \setfoot{\rlap{\hskip\dimexpr-\oddsidemargin-1in\relax% \parbox{1.93\paperwidth}{\hfil\thepage\,/\,\pageref{LastPage}}}}% {\parbox{\textwidth}{\raggedright \textcolor{gray}{\raisebox{-1pt}{\textcopyright}{}2019--2026 by Pablo González L}}}% {}% \sethead{\llap{\raisebox{0.55cm}{\parbox{\dimexpr\oddsidemargin+1in\relax}{\makebox[0pt][l]{\hspace{15pt}\pkglogo\space\fileversion}}}}} {\raisebox{0.55cm}{\parbox{\textwidth}{\hspace*{-\oddsidemargin}\centering\small\S.\thesection\space\sectiontitle}}}% {}% } \titlecontents{section}[0mm]{}% {\bfseries\contentspush{\makebox[5mm][l]{\thecontentslabel\hfill}}}% {\hspace*{-5mm}}% numberless {\hspace{0.25em}\titlerule*[6pt]{.}\contentspage}% \titlecontents{subsection}[5mm]{}% {\contentspush{\makebox[6mm][l]{\thecontentslabel\hfill}}} {\hspace*{-11mm}}% numberless {\hspace{0.25em}\titlerule*[6pt]{.}\contentspage}% % Table of contents \ExplSyntaxOn \cs_new_eq:Nc \__mydoc_mkboth:nn { @mkboth } \cs_new_eq:Nc \__mydoc_starttoc:n { @starttoc } \RenewDocumentCommand \tableofcontents { } { \group_begin: % Restore the l3doc \parskip locally (only for the TOC) \skip_set:Nn \parskip { 0pt~plus~3pt~minus~0pt } \section* { \contentsname \quad { \color { gray } \leaders \hrule height 5pt depth -4.4pt \hfill } } \__mydoc_mkboth:nn { \text_uppercase:n { \contentsname } } { \text_uppercase:n { \contentsname } } \vspace* { -14pt } \dim_set:Nn \columnsep { 10pt } \begin{multicols}{2} \__mydoc_starttoc:n { toc } \end{multicols} \vspace* { -3pt } { \color { gray } \hrule height 0.6pt } \vspace* { 5pt } \group_end: } % \thanks \cs_new:Npn \__mydoc_fnsymbol:n #1 { \ensuremath { \int_case:nnF { #1 } { { 0 } { } { 1 } { \textcolor { module_name } { * } } { 2 } { \textcolor { module_name } { \dagger } } { 3 } { \ddagger } { 4 } { \mathsection } { 5 } { \mathparagraph } { 6 } { \| } { 7 } { ** } { 8 } { \dagger \dagger } { 9 } { \ddagger \ddagger } } { \use:c { @ctrerr } } } } \hook_gput_code:nnn { begindocument } { scontents } { \cs_set_eq:cN { @fnsymbol } \__mydoc_fnsymbol:n } \ExplSyntaxOff \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \title{ % \scalebox{1.72}{\pkglogo}\\[1pt] % \Large % \textcolor{gray}{\fetamontotf{stores} \hologo{LaTeX} \fetamontotf{contents}}\\[3pt] % \fileversion \quad \filedate\thanks{ % This file describes a documentation for \fileversion, last revised % \filedate.}\\[25pt] % \author{ % \large % \raisebox{-1pt}{\textcopyright}{}2019--2026 by Pablo González L\thanks{ % E-mail: \textcolor{OrangeRed}{\textsf{\guillemotleft}}\email{pablgonz@educarchile.cl}\textcolor{OrangeRed}{\textsf{\guillemotright}}. % }% % } % \small % \textsc{ctan}: \url{https://www.ctan.org/pkg/scontents}\\ % \textcolor{gray}{\scriptsize\faIcon[regular]{github}}\,\,\,\url{https://github.com/pablgonz/scontents} % \vspace*{-2cm} % } % \date{} % \maketitle % % \begin{scontents}[store-env=abstract, print-env=true] % \begin{abstract} % This package allows to store \hologo{LaTeX} code, including \enquote{\emph{verbatim}}, % in \mymeta{sequences} using the \mypkg{l3seq} module of \mypkg{expl3}. The \mymeta{stored % content} can be used as many times as desired in the document, additionally you can write % to \mymeta{external files} or show it in \mymeta{verbatim style}. % \end{abstract} % \end{scontents} % % \tableofcontents % % \section{Description of the package} % % \begin{scontents}[store-env=description, print-env=true] % The \mypkg*[no-index]{scontents} package allows to \mymeta{store contents} in \mymeta{sequences} % or \mymeta{external files}. In some ways it is similar to the \mypkg{filecontentsdef} % package, with the difference in which the \mymeta{content} is stored. The idea behind % this package is to get an approach to \hologo{ConTeXt} \emph{\enquote{buffers}} by % making use of \mymeta{sequences}. % \end{scontents} % % \section{Motivation and Acknowledgments} % % In \hologo{LaTeX} there is no direct way to record content for later use, although % you can do this using |\macro|, recording \mymeta{verbatim content} is a % problem, usually you can avoid this by creating external files or boxes. % % The general idea of this package is to try to imitate this implementation % \enquote{\emph{buffers}} that has \hologo{ConTeXt} which allows you to save content in % memory, including \emph{verbatim}, to be used later. The \mypkg{filecontentsdef}\cite{filecontentsdef} % package solves this problem and since \mypkg{expl3}\cite{expl3} has an excellent way to manage data, % ideas were combined giving rise to this package. % % This package would not be possible without the great work of \textsc{Jean % Fran\c{c}ois Burnol} who was kind enough to take my requirements into account % and add the \myenv{filecontentsdefmacro} environment to \mypkg{filecontentsdef} package. % Also a special thanks to Phelype Oleinik who has collaborated and adapted a large part of the code and % all \hologo{LaTeX} team for their great work and to the different members % of the \href{https://tex.stackexchange.com}{TeX-SX} community who have provided % great answers and ideas. Here a note of the main ones: % % \begin{enumerate}[left=0pt, labelsep=5pt, noitemsep, nosep, label=\small\arabic*.] % \item \href{https://tex.stackexchange.com/q/45946/7832}{Stack datastructure using LaTeX} % % \item \href{https://tex.stackexchange.com/q/5338/7832}{LaTeX equivalent of ConTeXt buffers} % % \item \href{https://tex.stackexchange.com/q/215563/7832}{Storing an array of strings in a command} % % \item \href{https://tex.stackexchange.com/q/184503/7832}{Collecting contents of environment and store them for later retrieval} % % \item \href{https://tex.stackexchange.com/q/373647/7832}{Collect contents of an environment (that contains verbatim content)} % \end{enumerate} % % \begin{important}* % Starting with version 2.3 the \mypkg*[no-index]{scontents} package is fully % compatible with \emph{tagged} \texttt{PDF}\cite{tagpdf} and will have \LaTeX{} % release 2026-11-01 (\TeX{} Live 2026) and update \mypkg{expl3} release as a minimum requirement. % \end{important} % % \thispagestyle{plain} % \pagestyle{myheader} % % \section{License and Requirements}\label{sec:licence} % % Permission is granted to copy, distribute and/or modify this software under % the terms of the LaTeX Project Public License (lppl), version 1.3 or later % (\url{https://www.latex-project.org/lppl.txt}). The software has the status % \enquote{maintained}. % % The package \mypkg*[no-index]{scontents} requires an updated version of \LaTeX{} to work % (minimum required to \LaTeX{} release 2026-11-01 and \mypkg{expl3} update). % This package can be used with |plain|, |context|, |xelatex|, |lualatex|, |pdflatex| % and the classical workflow |latex>dvips>ps2pdf|. % % \section{The \texttt{scontents} package}\label{sec:pkgscontents} % % \subsection{Installation} % % The package \mypkg*[no-index]{scontents} is present in \hologo{TeX} Live and \hologo{MiKTeX}, % use the package manager to install. For manual installation, download % \href{https://mirrors.ctan.org/macros/latex/contrib/scontents.zip}{scontents.zip} % and unzip it, run \lstinline[language=scontents-doc,basicstyle=\ttfamily]+luatex scontents.ins+ % and move all files to appropriate locations, then run |mktexlsr|. To produce the documentation % with source code run \lstinline[language=scontents-doc,basicstyle=\ttfamily]+luatex scontents.ins+ and % |lualatex scontents.dtx| three times. % % \iffalse %<*example> % \fi \begin{examplecode}[frame=single,language={}] scontents.tex > TDS:tex/generic/scontents/ scontents-code.tex > TDS:tex/generic/scontents/ scontents.sty > TDS:tex/latex/scontents/ t-scontents.mkiv > TDS:tex/context/third/scontents/ scontents.pdf > TDS:doc/latex/scontents/ README.md > TDS:doc/latex/scontents/ scontents.dtx > TDS:source/latex/scontents/ scontents.ins > TDS:source/latex/scontents/ \end{examplecode} % \iffalse % % \fi % % \subsection{Loading and options} % % The package is loaded in the usual way: % % \subsubsection*{For \hologo{LaTeX} users} % % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \usepackageÇ\small\myoarg{key \textnormal{\textcolor{gray}{=}} val}Ç{scontents} \end{examplecode} % \iffalse % % \fi % % \subsubsection*{For \hologo{plainTeX} users} % % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \input scontents.tex \end{examplecode} % \iffalse % % \fi % % \subsubsection*{For \hologo{ConTeXt} users} % % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \usemodule{scontents} \end{examplecode} % \iffalse % % \fi % % \begin{important}* % The package options are not available for \hologo{plainTeX} and % \hologo{ConTeXt} and must be passed using |\setupsc| (\S\ref{subsec:confopt}). % \hologo{ConTeXt} users should use |-luatex|, the implementation does % not support LuaMetaTeX. % \end{important} % % \subsection{The TAB character}\label{subsec:tabcharacter} % % Some users use the horizontal \texttt{TAB} `\LKeyTab' character from % keyboard to indent the source code of the document and depending on the text editor % used, some will use real \texttt{TAB} (\emph{hard tabs}), others with % \emph{soft tabs} (\verb*+ + or \verb*+ +) or both. % % At first glance it may seem the same, but the way in which \texttt{TAB} character % (\emph{hard tabs}) are processed according to the context in which they are found within % a file, both in \mymeta{reading}\footnote{Check the answer given by Ulrich Diez % in \href{https://tex.stackexchange.com/a/508103/7832}{Keyboard TAB % character in argument v (xparse)}.} and \mymeta{writing}\footnote{Check the answer % given by Enrico Gregorio in \href{https://tex.stackexchange.com/a/58740/7832}{How to output a % tabulation into a file}.} are different and may have adverse consequences. % % In a standard \hologo{LaTeX} document, the character \texttt{TAB} `\LKeyTab' % are treated as explicit spaces (in most contexts) and is the behavior when % \mymeta{stored content}, but when \mymeta{writing files} these are preserved. % % With a \hologo{TeX} Live distribution, the \texttt{TAB} character is \emph{printable} % for |latex|, |pdflatex| and |lualatex|, but if you use |xelatex| you % must add the |-8bit| option on the command % line, otherwise you will get \hologo{TeX} character \texttt{TAB} `\myhlc|^^I|' % in the \mymeta{output file}. % % As a general recommendation \emph{\enquote{Do not use \texttt{TAB} character unless strictly % necessary}}, for example within a \emph{\enquote{verbatim environment}} that supports % this character such as \myenv{Verbatim} of the packages \mypkg{fancyvrb}\cite{fancyvrb}, % \mypkg{fvextra}\cite{fvextra} or \myenv{lstlisting} of the package \mypkg{listings}\cite{listings} % or when you want to generate a |MakeFile| file. % % \subsection{Configuration of the options}\label{subsec:confopt} % % Most of the options can be passed directly to the package or using the % command |\setupsc|. All boolean keys can be passed using the % equal sign `|=|' or just the % name of the key, all unknown \mymeta{keys} will return an error. In this section % are described some of the options, a summary of all options is shown in \S\ref{subsec:optover}. % % \begin{function}{\setupsc} % \begin{syntax} % \cmdexamp{setupsc}{key \textnormal{\textcolor{gray}{=}} val} % \end{syntax} % % The command \ics*{setupsc} takes the mandatory argument % \mymarg{key \textnormal{\textcolor{gray}{=}} val} and sets the \mymeta{keys} for the rest of the % document, or until the end of the current group, it can be used both in % the preamble and in the body of the document as many times as desired. % However, options set in the declaration of an environment (with % |\newenvsc|) have precedence over options set with |\setupsc|. % % Options in the optional arguments of environments and % commands have the highest precedence, overriding both % options in |\newenvsc| and in |\setupsc|. % \end{function} % % \keyexampcmd{debug-var}{true \textnormal{\textcolor{lightgray}{\textbar}} false}{true}[setupsc] % Determines whether the \mymeta{argument} passed to commands or the \mymeta{body} passed % to provided environments is written to the \texttt{.log} file. This \mymeta{key} % is only available as a package option or using |\setupsc|. % % \keyexampcmd{verb-font}{font family}{\textnormal{\ttfamily\textbackslash{}ttfamily}}[setupsc] % Sets the \mymeta{font family} used to display the \mymeta{stored content} for % |\typestored|, |\mergesc| and |\meaningsc| commands. This \mymeta{key} % is only available as a package option or using |\setupsc|. % % \keyexampcmd{store-all}{seq name}{not used}[setupsc] % It is a \mymeta{meta-key} that sets the \mykey{store-env} key of the \myenv*[no-index]{scontents} % environment and the \mykey{store-cmd} key of the |\Scontents| command. This \mymeta{key} % is only available as a package option or using |\setupsc|. % % \keyexampcmd{remember}{seq names}{not used}[setupsc] % Sets the \emph{sequences}, a comma separated list of \mymarg{seq names}, % whose \mymeta{stored contents} can be used before they are stored, as % |\label| and |\ref| do with the references. At the end of the document % the \mymeta{stored contents} of these \emph{sequences} are written to the % file |\jobname.sct| and in the next compilation |\getstored|, % |\foreachsc|, |\typestored|, |\meaningsc|, |\mergesc| and |\countsc| % take the \mymeta{stored contents} from it, so they are available before % they are stored. % As with the references, two compilations are needed: the first one prints % nothing where a \mymeta{stored content} is not available yet and a % \enquote{warning} at the end of the document asks to compile again. If % a \mymeta{stored content} is still not available, for example with an % \mymeta{index} greater than the number of \mymeta{stored contents}, a % \enquote{warning} says that there were undefined \mymeta{stored contents}. % This \mymeta{key} is only available in \hologo{LaTeX}, in the preamble, % as a package option or using |\setupsc|. For example: % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \setupsc{remember=objectives} % in the preamble \section{Objectives} \getstored[1]{objectives} \section{Methods} \Scontents[store-cmd=objectives]{Measure the effect of the method.} \end{examplecode} % \iffalse % % \fi % A complete example is in \S\ref{exa:remember}. The file |\jobname.sct| is % an auxiliary file, as the |.aux| file, and it can be removed at any time. % To remove it with |latexmk -c| add this line to the \myfile{latexmkrc} % file: % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] push @generated_exts, 'sct'; \end{examplecode} % \iffalse % % \fi % % \keyexampcmd{overwrite}{true \textnormal{\textcolor{lightgray}{\textbar}} false}{false}[setupsc] % Sets whether the \mymeta{files} generated by \mykey{write-out} and \mykey{write-env} % from the \myenv*[no-index]{scontents} environment will be rewritten. This \mymeta{key} is available as % a package option, for |\setupsc|, for |\Scontents| and % |\Scontents*|, for the base environment \myenv*[no-index]{scontents} and all % environments created using |\newenvsc|. % % \keyexampcmd{print-all}{true \textnormal{\textcolor{lightgray}{\textbar}} false}{false}[setupsc] % It is a \mymeta{meta-key} that sets the \mykey{print-env} key of the \myenv*[no-index]{scontents} % environment and the \mykey{print-cmd} key of the |\Scontents| command. This \mymeta{key} is % only available as a package option or using |\setupsc|. % % \keyexampcmd{force-eol}{true \textnormal{\textcolor{lightgray}{\textbar}} false}{false}[setupsc] % Sets if the \emph{last end of line} for the \mymeta{stored content} is hidden or not. % This \mymeta{key} is necessary only if the \emph{last line} is the closing of some % environment defined by \mypkg{fancyvrb}\cite{fancyvrb} or \mypkg{fvextra}\cite{fvextra} % packages as |\end{Verbatim}| or another environment that does not support % a comments `|%|' after closing |\end{}%|. % This \mymeta{key} is available for the base environment \myenv*[no-index]{scontents}, % the |\Scontents| and |\Scontents*| commands and all environments % created using |\newenvsc|. % % \keyexampcmd{width-tab}{integer}{1}[setupsc] % Sets the equivalence in \mymeta{spaces} for the character \texttt{TAB} `\LKeyTab' % used when displaying \mymeta{stored content} in \emph{verbatim style}. The value % must be a \mymeta{positive integer}. This \mymeta{key} is available for |\typestored|, % |\mergesc| and |\meaningsc| commands. % % \subsection{Options Overview}\label{subsec:optover} % % \newcommand*{\xmark}{\textcolor{OrangeRed}{✘}}% % \newcommand*{\cmark}{\textcolor{newlinkcolor}{✔}}% % % \setlength{\tabcolsep}{0.25em} % \begin{center} % \small % \begin{tabular}{lcccccccc} % \toprule % \texttt{key} & \texttt{package} &|\setupsc| &\myenv*[no-index]{scontents} &|\Scontents| &|\Scontents*| &|\typestored| &|\meaningsc| &|\mergesc|\\ % \midrule % \mykey{debug-var} & \cmark & \cmark & \xmark & \xmark & \xmark & \xmark & \xmark & \xmark \\ % \mykey{verb-font} & \cmark & \cmark & \xmark & \xmark & \xmark & \xmark & \xmark & \xmark \\ % \mykey{store-all} & \cmark & \cmark & \xmark & \xmark & \xmark & \xmark & \xmark & \xmark \\ % \mykey{remember} & \cmark & \cmark & \xmark & \xmark & \xmark & \xmark & \xmark & \xmark \\ % \mykey{overwrite} & \cmark & \cmark & \cmark & \cmark & \cmark & \cmark & \cmark & \cmark \\ % \mykey{print-all} & \cmark & \cmark & \xmark & \xmark & \xmark & \xmark & \xmark & \xmark \\ % \mykey{force-eol} & \cmark & \cmark & \cmark & \cmark & \cmark & \xmark & \xmark & \xmark \\ % \mykey{width-tab} & \cmark & \cmark & \xmark & \xmark & \xmark & \cmark & \cmark & \cmark \\ % \mykey{store-env} & \cmark & \cmark & \cmark & \xmark & \xmark & \xmark & \xmark & \xmark \\ % \mykey{store-cmd} & \cmark & \cmark & \xmark & \cmark & \cmark & \xmark & \xmark & \xmark \\ % \mykey{print-env} & \cmark & \cmark & \cmark & \xmark & \xmark & \xmark & \xmark & \xmark \\ % \mykey{print-cmd} & \cmark & \cmark & \xmark & \cmark & \cmark & \cmark & \cmark & \cmark \\ % \mykey{write-env} & \xmark & \xmark & \cmark & \xmark & \xmark & \xmark & \xmark & \xmark \\ % \mykey{write-cmd} & \xmark & \xmark & \xmark & \cmark & \cmark & \xmark & \xmark & \xmark \\ % \mykey{write-out} & \xmark & \xmark & \cmark & \cmark & \cmark & \cmark & \cmark & \cmark \\ % \mykey{typestored} & \xmark & \xmark & \xmark & \xmark & \xmark & \xmark & \xmark & \cmark \\ % \mykey{meaningsc} & \xmark & \xmark & \xmark & \xmark & \xmark & \xmark & \xmark & \cmark \\ % \mykey{getstored} & \xmark & \xmark & \xmark & \xmark & \xmark & \xmark & \xmark & \cmark \\ % \bottomrule % \end{tabular} % \end{center} % % \section{User interface}\label{sec:interface} % % The user interface consists in \myenv*[no-index]{scontents} environment, |\Scontents| % and |\Scontents*| commands to \mymeta{stored content}, |\getstored| % command to get the \mymeta{stored content}, |\typestored| and |\mergesc| commands to print % \emph{verbatim style} the \mymeta{stored content} along with other utilities described % in this documentation. % % \subsection{The environment \texttt{scontents}}\label{subsec:envscontents} % % \begin{function}[label=SCONTENTS]{scontents} % \begin{syntax} % \envexamp{scontents} % \end{syntax} % % The \myenv*{scontents} environment takes the optional argument % \myoarg{key \textnormal{\textcolor{gray}{=}} val} and the \mymarg{body env}, which it % \emph{\enquote{stores}} in a \mymeta{sequence} or \emph{\enquote{writes}} % to an \mymeta{external file} if desired, including \emph{verbatim % material}. After the package has been loaded, the environment can be % used both in the preamble and in the body of the document. % % For the correct operation |\begin{scontents}| and |\end{scontents}| must % be in \emph{different lines}, all \mymeta{keys} must be passed separated by % commas and \emph{without spaces} `\verb*+ +' of the start of the % environment. % \end{function} % % Comments `|%|' or \emph{any character} after % |\begin{scontents}| or \myoarg{key \textnormal{\textcolor{gray}{=}} val} on % the \emph{same line} are NOT supported, the package will return an \enquote{error} message if this happens. % In a similar way comments `|%|' or \emph{any character} % after |\end{scontents}| on the \emph{same line} the package will return a \enquote{warning} message. % % The environment can be \emph{\enquote{nested}} if it is properly balanced and % does not appear \emph{\enquote{literally}} in commented lines or in some \emph{verbatim} % environment or command. As an example: % % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \begin{scontents}[store-env=outer] This text is in the outer environment (before nested). \begin{scontents}[store-env=inner] This text is found in the inner environment (inside of nested). \end{scontents} This text is in the outer environment (after nested). \end{scontents} \end{examplecode} % \iffalse % % \fi % % Of course, the \mymeta{stored content} in the \emph{sequence} \mymarg{inner} % is \emph{only available} after \mymeta{stored content} in the \emph{sequence} % \mymarg{outer} one has been retrieved, either by using the key \mykey{print-env} % or |\getstored| command. % % \begin{important}* % It is advisable to store the \mymeta{content} in \emph{sequences} with % different names, so as not to get lost in the order (position) in which % it is stored. % \end{important} % % \subsection*{Notes for \hologo{plainTeX} and \hologo{ConTeXt} users} % % In \hologo{plainTeX} there are no environments as in \hologo{LaTeX}. % Instead of using the environment \myenv*[no-index]{scontents}, one should use a % \emph{\enquote{pseudo environment}} delimited by |\scontents| and |\endscontents|. % % \begin{function}{\scontents,\endscontents} % \begin{syntax} % \envexaplain{scontents} % \end{syntax} % The \emph{pseudo environment} takes the same optional argument % \myoarg{key \textnormal{\textcolor{gray}{=}} val} as the \myenv*[no-index]{scontents} % environment, on the same line as |\scontents|, and the % \mymarg{body env} up to |\endscontents|. % \end{function} % % \hologo{ConTeXt} users should use |\startscontents| and |\stopscontents|. % \begin{function}{\startscontents,\stopscontents} % \begin{syntax} % \envexaplain[start]{scontents}[stop] % \end{syntax} % The \emph{pseudo environment} takes the same optional argument % \myoarg{key \textnormal{\textcolor{gray}{=}} val} as the \myenv*[no-index]{scontents} % environment, on the same line as |\startscontents|, and the % \mymarg{body env} up to |\stopscontents|. % \end{function} % % \subsection*{Options for environment} % % The environment options can be configured globally using option % in package or the |\setupsc| command and locally using % \myoarg{key \textnormal{\textcolor{gray}{=}} val} in the environment. % The key \mykey{force-eol} is available for this environment. % % \keyexampcmd{store-env}{seq name}{contents}[env] % Sets the \emph{name} of the \emph{sequence} in which the \mymarg{body env} will be % stored. If the \emph{sequence} does not exist, it will be created globally. % % \keyexampcmd{print-env}{true \textnormal{\textcolor{lightgray}{\textbar}} false}{false}[env] % Sets if the \mymeta{stored content} is displayed or not at the time of % running the environment. The \mymeta{stored content} is extracted from % the \emph{sequence} \mymarg{seq name} set by the key \mykey{store-env} % at the time it is executed. % % \keyexampcmd{write-env}{file.ext}{not used}[env] % Sets the \emph{name} of the \mymeta{external file} in which the \mymarg{body env} of % the environment will be written. The \mymeta{file.ext} will be created % in the working directory and the \mymarg{body env} will be \emph{stored} % in the \emph{sequence} set by the key \mykey{store-env} % at the time it is executed. If \mymeta{file.ext} does not exist, it will % be created or overwritten if the \mykey{overwrite} key is used. % % \keyexampcmd{write-out}{file.ext}{not used}[env] % Sets the \emph{name} of the \mymeta{external file} in which the \mymarg{body env} of % the environment will be written. The \mymeta{file.ext} will be created % in the working directory and the \mymarg{body env} will NOT be \emph{stored} % in the \emph{sequence} set by the key \mykey{store-env} % at the time it is executed. If \mymeta{file.ext} does not exist, it will % be created or overwritten if the \mykey{overwrite} key is used. % % \begin{important}* % In the keys \mykey{write-env} and \mykey{write-out} the character % \texttt{TAB} will be written in \mymeta{file.ext}, % relative or absolute paths are not supported. \hologo{XeLaTeX} users % using character \texttt{TAB} must add |-8bit| % at the command line, otherwise you will get \hologo{TeX} character % \texttt{TAB} `\myhlc|^^I|' in \mymeta{file.ext}. % \end{important} % % \subsection{The command \cs{newenvsc}}\label{subsec:newenvsc} % % \newsavebox{\exaboxtmp} % \begin{lrbox}{\exaboxtmp} % \small\ttfamily % \textcolor{module_name}{\textbackslash newenvsc}\mymarg{env name}\myoarg{initial keys} % \end{lrbox} % % \begin{function}{\newenvsc} % \begin{syntax} % \usebox{\exaboxtmp} % \end{syntax} % The command \ics*{newenvsc} takes the mandatory argument % \mymarg{env name} and the optional argument \myoarg{initial keys}, and % creates the \mymeta{new environment} \mymarg{env name} with the same % characteristics of the \myenv*[no-index]{scontents} environment. The % values entered in \myoarg{initial keys} will be considered as the % default values for this new environment and the valid \mymeta{keys} are % \mykey{store-env} and \mykey{print-env}. If \mymarg{env name} already % exists, an \enquote{error} is returned and its definition is not altered. % \end{function} % % In \hologo{plainTeX} and \hologo{ConTeXt} the \mymeta{new environment} % is a \emph{pseudo environment} as the one of \myenv*[no-index]{scontents} % (\S\ref{subsec:envscontents}): for an environment named |myenv| it is % |\myenv|\,\dots\,|\endmyenv| in \hologo{plainTeX} and % |\startmyenv|\,\dots\,|\stopmyenv| in \hologo{ConTeXt}. For example: % % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \newenvsc{myenvstore}[store-env=myseq,print-env=false] \end{examplecode} % \iffalse % % \fi % % created the environment |myenvstore| that \mymeta{stored content} in % the \emph{sequence} \mymarg{myseq} and will NOT display the \mymeta{stored content} % when the environment it is executed. % % \subsection{The command \cs{Scontents}}\label{subsec:Scontents} % % \begin{function}{\Scontents} % \begin{syntax} % \cmdexamp{Scontents}[key \textnormal{\textcolor{gray}{=}} val]{argument} % \cmdexamp[*]{Scontents}[key \textnormal{\textcolor{gray}{=}} val]{argument} % \cmdexamp[*]{Scontents}[key \textnormal{\textcolor{gray}{=}} val]{argument}[del] % \end{syntax} % The command \ics*{Scontents} takes an optional \emph{starred argument} % `|*|', the optional argument \myoarg{key \textnormal{\textcolor{gray}{=}} val} and the mandatory % \mymarg{argument}, between \emph{braces} or, in the starred version, % between two \mymeta[cf=star]{del}, and stores the \mymarg{argument} in % the \emph{sequence} set by the key \mykey{store-cmd}. % \end{function} % % The command |\Scontents| reads the \mymarg{argument} in standard % mode and \emph{\enquote{stores}} it in the \emph{sequence} set % by the key \mykey{store-cmd} at the time it is executed. It is not % possible to pass \emph{verbatim things}, but it is possible to use % the implementation of |\Verb| delimited by \emph{braces} % `|{ }|' % provided by the \mypkg{fvextra}\cite{fvextra} package for \emph{verbatim one line} % and |\lstinline| from \mypkg{listings}\cite{listings} package, but it % is preferable to use the \emph{starred argument} `|*|'. % % The |\Scontents*| command reads the \mymarg{argument} under \emph{verbatim catcode} % regimen and \emph{\enquote{stores}} it in the \emph{sequence} set % by the key \mykey{store-cmd} at the time it is executed. If its \emph{\enquote{first}} % delimiter is a \emph{brace} `|{|', it will be % assumed that the \mymarg{argument} is nested within \emph{braces}. Otherwise it % will be assumed that \mymarg{argument} is delimited by that % first delimiter \mymeta[cf=star]{del} like command |\verb|. % Blank lines are preserved, escaped braces `|\{|' and % `|\}|' must also be % balanced if the \mymarg{argument} is used with \emph{braces} and character \texttt{TAB} typed % from the keyboard are converted into spaces. % % The \emph{starred argument} `|*|' and \myoarg{key \textnormal{\textcolor{gray}{=}} val} % must NOT be separated by \emph{spaces} `\verb*+ +' between them and the command. % Both versions can be used anywhere in the document and cannot be used % as an \mymarg{argument} for other command. % % \subsection*{Options for command} % % The command options can be configured globally using option in package % or the |\setupsc| command and locally using \myoarg{key \textnormal{\textcolor{gray}{=}} val}. % % \keyexampcmd{store-cmd}{seq name}{contents}[Scontents] % Sets the \emph{name} of the \emph{sequence} in which the \mymarg{argument} % is stored. If the \emph{sequence} does not exist, it will be created globally. % % \keyexampcmd{print-cmd}{true \textnormal{\textcolor{lightgray}{\textbar}} false}{false}[Scontents] % Sets if the \mymeta{stored content} is displayed or not at the time of % running the command. The \mymeta{stored content} is extracted from the \emph{sequence} % \mymarg{seq name} set by the key \mykey{store-cmd} at the time it is executed. % % \subsection*{Options for writing files} % % The following \mymeta{keys} and the \mykey{force-eol} and \mykey{overwrite} % keys are available for both versions of the command. The |\Scontents*| % command writes the \mymarg{argument} to \mymeta{file.ext} exactly as it was % typed. The |\Scontents| command reads the \mymarg{argument} in standard % mode, so it is written as a list of tokens, in the same way as |\detokenize| % does: a space is added after each control word, the character `|#|' is % doubled, the line breaks become spaces and the blank lines become |\par|. % To write the \mymarg{argument} literally, use the \emph{starred argument} % `|*|'. % % \keyexampcmd{write-cmd}{file.ext}{not used}[Scontents] % Sets the \emph{name} of the \mymeta{external file} in which the \mymarg{argument} % will be written. The \mymeta{file.ext} will be created in the working % directory and the \mymarg{argument} will be \emph{stored} % in the \emph{sequence} set by the key \mykey{store-cmd} % at the time it is executed. If \mymeta{file.ext} does not exist, it will % be created or overwritten if the \mykey{overwrite} key is used. % % \keyexampcmd{write-out}{file.ext}{not used}[Scontents] % Sets the \emph{name} of the \mymeta{external file} in which the \mymarg{argument} % will be written. The \mymeta{file.ext} will be created in the working % directory and the \mymarg{argument} will NOT be \emph{stored} % in any \emph{sequence} set by the key \mykey{store-cmd} % at the time it is executed. If \mymeta{file.ext} does not exist, it will % be created or overwritten if the \mykey{overwrite} key is used. % % \begin{important}* % In the keys \mykey{write-cmd} and \mykey{write-out} the character % \texttt{TAB} will be written in \mymeta{file.ext}, relative or absolute % paths are not supported. \hologo{XeLaTeX} users using character \texttt{TAB} % must add |-8bit| at the command line, otherwise % you will get \hologo{TeX} character \texttt{TAB} `\myhlc|^^I|' in \mymeta{file.ext}. % \end{important} % % \subsection{The command \cs{getstored}}\label{subsec:getstored} % % \begin{function}{\getstored} % \begin{syntax} % \cmdexamp{getstored}[index]{seq name} % \end{syntax} % The command \ics*{getstored} takes the optional argument % \myoarg{index} and the mandatory argument \mymarg{seq name}, and % retrieves the \mymeta{stored content} whose \emph{position} in the % \emph{sequence} \mymarg{seq name} is the \emph{integer value} set in % \mymeta{index}. A \emph{negative} \mymeta{index} counts from the last % \mymeta{stored content} and, if the \emph{optional argument} is not % passed, the \emph{\enquote{last}} \mymeta{stored content} is retrieved. % \end{function} % % The command is robust and can be used as an \mymarg{argument} for % another command. % % \subsection{The command \cs{foreachsc}}\label{subsec:foreachsc} % % \begin{function}{\foreachsc} % \begin{syntax} % \cmdexamp{foreachsc}[key \textnormal{\textcolor{gray}{=}} val]{seq name} % \end{syntax} % The command \ics*{foreachsc} takes the optional argument % \myoarg{key \textnormal{\textcolor{gray}{=}} val} and the mandatory argument \mymarg{seq name}, % and executes the command |\getstored| on each \mymeta{stored content} % in the \emph{sequence} \mymarg{seq name}, or |\typestored| or % |\meaningsc| with the \mykey{typestored} or \mykey{meaningsc} key. If the % \emph{optional argument} is not passed, |\getstored| is executed on all % the \mymeta{stored content} in the \emph{sequence} \mymarg{seq name}. % \end{function} % % \subsubsection*{Options for command} % % \keyexampcmd*{getstored}{without value}{active}[foreachsc] % Executes |\getstored| on each \mymeta{stored content}, as without % \mymeta{keys}. % % \keyexampcmd*{typestored}{without value}{not active}[foreachsc] % Executes |\typestored| on each \mymeta{stored content}, which is shown in % \emph{verbatim style} (\S\ref{subsec:typestored}). % % \keyexampcmd*{meaningsc}{without value}{not active}[foreachsc] % Executes |\meaningsc| on each \mymeta{stored content} % (\S\ref{subsec:meaningsc}). % % \keyexampcmd{sep}{code}{empty}[foreachsc] % Establishes the \emph{separation} between each \mymeta{stored content} % in the \emph{sequence} \mymarg{seq name}. % For example, you can use |sep={\\[10pt]}| for vertical separation of % \mymeta{stored contents}. % % \keyexampcmd{step}{integer}{1}[foreachsc] % Sets the \emph{increment} (\mymeta{step}) applied to the value set by key \mykey{start} % for each \mymeta{stored content} in the \emph{sequence} \mymarg{seq name}. % The value must be a \mymeta{positive integer}. % % \keyexampcmd{start}{integer}{1}[foreachsc] % Set the \emph{position} of the \mymeta{stored content} within the % \emph{sequence} \mymarg{seq name} from which to \emph{start} executing. % The value must be a \mymeta{positive integer}. % % \keyexampcmd{stop}{integer}{total}[foreachsc] % Set the \emph{position} of the \mymeta{stored content} within the % \emph{sequence} \mymarg{seq name} at which execution ends. The value % must be a \mymeta{positive integer}. % % \keyexampcmd{before}{code}{empty}[foreachsc] % Sets the \mymarg{code} that will be executed \emph{before} each \mymeta{stored content} % within the \emph{sequence} \mymarg{seq name}. The \mymarg{code} must % be passed \emph{between braces} `|{ }|'. % % \keyexampcmd{after}{code}{empty}[foreachsc] % Sets the \mymarg{code} that will be executed \emph{after} each \mymeta{stored content} % within the \emph{sequence} \mymarg{seq name}. The \mymarg{code} must % be passed \emph{between braces} `|{ }|'. % % \newsavebox{\hashbox} % \begin{lrbox}{\hashbox} % \lstinline[language=scontents-doc,basicstyle=\small\ttfamily]+{#1}+ % \end{lrbox} % % \keyexampcmd{wrapper}{code{} \space\usebox{\hashbox} more code}{empty}[foreachsc] % Wraps the \mymeta{stored content} within the \emph{sequence} \mymarg{seq name} % referenced by |{#1}|. The \mymarg{code} must be passed \emph{between braces} % `|{ }|'. % For example |\foreachsc[wrapper={\makebox[1em][l]{#1}}]{contents}|. % % \subsection{The command \cs{typestored}}\label{subsec:typestored} % % \begin{function}{\typestored} % \begin{syntax} % \cmdexamp{typestored}[index\textnormal{\textcolor{gray}{,}} start-stop\textnormal{\textcolor{gray}{,}} 1-end\textnormal{\textcolor{gray}{,}} keys]{seq name} % \end{syntax} % The command \ics*{typestored} takes the optional argument with the % \mymeta{index}, the \mymeta{start-stop}, the \mymeta{1-end} and the % \mymeta{keys}, and the mandatory argument \mymarg{seq name}, and prints % the \mymeta{stored content} in the \emph{sequence} \mymarg{seq name} % in the internal \myenv*[no-index]{verbatimsc} environment % (\S\ref{subsec:verbatimsc}). If the \emph{optional argument} is not % passed, the \emph{first} \mymeta{stored content} is printed. % \end{function} % % The \emph{integer value} set in \mymeta{index} is the \emph{position} % of the \mymeta{stored content} in the \emph{sequence} \mymarg{seq name}, % a \emph{negative} \mymeta{index} counts from the last % \mymeta{stored content} as in |\getstored|. The \emph{integer values} % set in \mymeta{start-stop} define a \emph{range} of positions, where % |end| is the last \mymeta{stored content} and a \mymeta{start} greater % than \mymeta{stop} prints the \emph{range} in reverse order, and % \mymeta{1-end} prints \emph{\enquote{all}} the \mymeta{stored content}. % Several of them can be given separated by commas. The rest of the % accepted \mymeta{keys} are \mykey{print-cmd} with default value |true|, % \mykey{write-out}, \mykey{width-tab} and \mykey{overwrite}. % % \begin{important}* % In the key \mykey{write-out} the character \texttt{TAB} will be written % in \mymeta{file.ext}, relative or absolute paths are not supported. % \hologo{XeLaTeX} users using character \texttt{TAB} must add |-8bit| % at the command line, otherwise you will get \hologo{TeX} character % \texttt{TAB} `\myhlc|^^I|' in \mymeta{file.ext}. % \end{important} % % \subsection{The command \cs{meaningsc}}\label{subsec:meaningsc} % % \begin{function}{\meaningsc} % \begin{syntax} % \cmdexamp{meaningsc}[index\textnormal{\textcolor{gray}{,}} start-stop\textnormal{\textcolor{gray}{,}} 1-end\textnormal{\textcolor{gray}{,}} keys]{seq name} % \end{syntax} % The command \ics*{meaningsc} takes the same optional argument as % |\typestored| (\S\ref{subsec:typestored}) and the mandatory argument % \mymarg{seq name}, and prints the \emph{meaning} of the % \mymeta{stored content} in the \emph{sequence} \mymarg{seq name}, as % |\meaning| does, on a single line. The \mymeta{index}, % \mymeta{start-stop}, \mymeta{1-end} and \mymeta{keys} have the same % behavior as in |\typestored| and, if the \emph{optional argument} is % not passed, the \emph{first} \mymeta{stored content} is printed. % \end{function} % % \subsection{The command \cs{mergesc}}\label{subsec:mergesc} % % \newsavebox{\argmergesc} % \begin{lrbox}{\argmergesc} % \small\mymarg{seq A}\myoarg{index}\textcolor{gray}{, }\mymarg{seq B}\myoarg{start \textcolor{gray}{-} stop}\textcolor{gray}{, }\mymarg{seq C}\myoarg{1-end} % \end{lrbox} % % \begin{function}{\mergesc} % \begin{syntax} % \cmdexamp{mergesc}[typestored \textnormal{\textcolor{lightgray}{\textbar}} meaningsc \textnormal{\textcolor{lightgray}{\textbar}} getstored\textcolor{lightgray}{, }keys]{\usebox{\argmergesc}} % \end{syntax} % The command \ics*{mergesc} takes the optional argument with the % \mymeta{keys}, one of them \mykey{typestored}, \mykey{meaningsc} or % \mykey{getstored}, and the mandatory argument with a % \emph{comma separated list} of \emph{sequences}, and assembles the % \mymeta{stored content} in them, as \mymarg{seq A}|[1]|, % \mymarg{seq B}|[2-5]| and \mymarg{seq C}|[1-|\mykey{end}|]| in the % syntax, and then executes |\typestored| (\S\ref{subsec:typestored}) if % the \mykey{typestored} key is active, |\meaningsc| % (\S\ref{subsec:meaningsc}) if the \mykey{meaningsc} key is active, or % rescans it as |\getstored| (\S\ref{subsec:getstored}) does if the % \mykey{getstored} key is active. % \end{function} % % The \mymarg{argument} taken by this command is a \emph{comma separated list} % of the form \mymarg{seq name} followed by either \myoarg{index}, % \myoarg{start-stop} or \myoarg{1-end}, a \mymarg{seq name} alone % assembles all its \mymeta{stored content}. % The use of the keys \mykey{typestored}, \mykey{meaningsc} or % \mykey{getstored} are \emph{\enquote{mandatory}} and disjoint from each % other, the rest of the accepted \mymeta{keys} are \mykey{print-cmd}, % \mykey{write-out}, \mykey{width-tab} and \mykey{overwrite}, which are not % accepted with the \mykey{getstored} key. % % The use of the \mykey{write-out} key with this command follows the same % rules already described, the main advantage is that allows joining % \mymeta{stored content} \emph{without rewriting} the file over and over again, % by design \hologo{TeX} does not have an \emph{append mode} for writing % files, this effectively allows you to write chunks of code and then % merge them into a single file. % % \subsection{The environment \env{verbatimsc}}\label{subsec:verbatimsc} % % \begin{function}{verbatimsc} % The environment used by |\typestored| and |\mergesc| to % display the \mymeta{stored content} in \emph{verbatim style}. % The environment is compatible with \emph{tagged} \texttt{PDF} and can % be customized in the following ways after loading the \mypkg*[no-index]{scontents} % package: % \end{function} % % Using the packages \mypkg{fvextra}\cite{fvextra} or \mypkg{fancyvrb}\cite{fancyvrb}: % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \ExplSyntaxOn \cs_undefine:N \verbatimsc \cs_undefine:N \endverbatimsc \ExplSyntaxOff \usepackage{fancyvrb} \DefineVerbatimEnvironment{verbatimsc}{Verbatim}{numbers=left} \end{examplecode} % \iffalse % % \fi % Using the package \mypkg{minted}\cite{minted}: % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \ExplSyntaxOn \cs_undefine:N \verbatimsc \cs_undefine:N \endverbatimsc \ExplSyntaxOff \usepackage{minted} \newminted{tex}{linenos} \newenvironment{verbatimsc}{\VerbatimEnvironment\begin{texcode}}{\end{texcode}} \end{examplecode} % \iffalse % % \fi % Using the package \mypkg{listings}\cite{listings}: % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \ExplSyntaxOn \cs_undefine:N \verbatimsc \cs_undefine:N \endverbatimsc \ExplSyntaxOff \usepackage{listings} \lstnewenvironment{verbatimsc} { \lstset{ basicstyle=\small\ttfamily, columns=fullflexible, language=[LaTeX]TeX, numbers=left, numberstyle=\tiny\color{gray}, keywordstyle=\color{red} } }{} \end{examplecode} % \iffalse % % \fi % % \begin{function}{\startverbatimsc, \stopverbatimsc} % In \hologo{plainTeX} the environment is |\verbatimsc|\,\dots\,|\endverbatimsc| % and in \hologo{ConTeXt} it is |\startverbatimsc|\,\dots\,|\stopverbatimsc|, % defined with |\definetyping|, so there it can be customized with % |\setuptyping[verbatimsc][...]|. % \end{function} % % \begin{important}* % At the moment, the \mypkg{fvextra}\cite{fvextra} and \mypkg{fancyvrb}\cite{fancyvrb} % packages partially support \emph{tagged} \texttt{PDF}. % \end{important} % % \section{Other commands provided} % % \subsection{The command \cs{countsc}}\label{subsec:countsc} % % \begin{function}{\countsc} % \begin{syntax} % \cmdexamp{countsc}{seq name} % \end{syntax} % The command \ics*{countsc} takes the mandatory argument % \mymarg{seq name} and returns the number of \mymeta{stored content} in % the \emph{sequence} \mymarg{seq name}. The command is expandable, so it % can be used in an \emph{integer expression}, and if the \emph{sequence} % does not exist an \enquote{error} is returned along with |0|. % \end{function} % % \subsection{The command \cs{cleanseqsc}}\label{subsec:cleanseqsc} % % \begin{function}{\cleanseqsc} % \begin{syntax} % \cmdexamp{cleanseqsc}{seq name} % \end{syntax} % The command \ics*{cleanseqsc} takes the mandatory argument % \mymarg{seq name} and removes all \mymeta{stored content} in the % \emph{sequence} \mymarg{seq name}. If the \emph{sequence} does not % exist, it is created empty. % \end{function} % % \section{Programming interface}\label{sec:api} % % For other packages and for the code written with \mypkg{expl3}, the % \mymeta{stored contents} can be read without printing them with the % following functions. They work in \hologo{LaTeX}, \hologo{plainTeX} and % \hologo{ConTeXt} and also read the \emph{sequences} set by the % \mykey{remember} key. % % The \mymeta{stored contents} are given as they were stored, without the % mark that \mypkg*[no-index]{scontents} adds to hide the last end of line: % the content of an environment is a string whose lines are separated by % the end of line character \myhlc|^^J|, the content of |\Scontents*| is also a % string and the content of |\Scontents| keeps its tokens. % % \begin{function}[EXP,pTF]{\scontents_if_exist:n} % \begin{syntax} % \myhlc|\scontents_if_exist_p:n| \mymarg{seq name} % \myhlc|\scontents_if_exist:nTF| \mymarg{seq name} \mymarg{true code} \mymarg{false code} % \end{syntax} % Tests if the \emph{sequence} \mymarg{seq name} exists. % \end{function} % % \begin{function}[EXP]{\scontents_count:n} % \begin{syntax} % \myhlc|\scontents_count:n| \mymarg{seq name} % \end{syntax} % Leaves the number of \mymeta{stored contents} in the \emph{sequence} % \mymarg{seq name} in the input stream, or |0| if it does not exist, % without an \enquote{error}. It can be used in an \emph{integer % expression}. % \end{function} % % \begin{function}{\scontents_get:nnN} % \begin{syntax} % \myhlc|\scontents_get:nnN| \mymarg{seq name} \mymarg{index} \mymeta{tl var} % \end{syntax} % Sets the \mymeta{tl var}, locally, to the \mymeta{stored content} at the % position \mymarg{index} of the \emph{sequence} \mymarg{seq name}. The % \mymarg{index} is an \emph{integer expression}, a negative one counts % from the end. If the \emph{sequence} does not exist or the % \mymarg{index} is out of range, the \mymeta{tl var} is empty and an % \enquote{error} is returned. % \end{function} % % \begin{function}{\scontents_map_inline:nn} % \begin{syntax} % \myhlc|\scontents_map_inline:nn| \mymarg{seq name} \mymarg{inline function} % \end{syntax} % Applies the \mymarg{inline function} to each \mymeta{stored content} of % the \emph{sequence} \mymarg{seq name}, in order, the % \mymeta{stored content} is |#1|. The \mymarg{inline function} can use % the other functions and \myhlc|\scontents_map_inline:nn| again. If the % \emph{sequence} does not exist an \enquote{error} is returned. For % example, this shows in the \texttt{.log} file each % \mymeta{stored content} of the \emph{sequence} |data| converted to % uppercase: % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \ExplSyntaxOn \scontents_map_inline:nn { data } { \iow_log:e { \text_uppercase:n {#1} } } \ExplSyntaxOff \end{examplecode} % \iffalse % % \fi % \end{function} % % \section[The \textnormal{\texttt{scontents}} package in action]{The \mypkg*[no-index]{scontents} package in action} % % Remember the abstract on the first page? This is it: % % \getstored{abstract} % % And the description of the package? % % \getstored{description} % % I've only written: % % \typestored{abstract} % % and % % \typestored{description} % % Of course, I didn't copy and paste. The real code they were written with is: % % \iffalse %<*example> % \fi \begin{examplecode}[numbers=left] \begin{scontents}[store-env=abstract,print-env=true] \begin{abstract} This package allows to store \hologo{LaTeX} code, including \enquote{\emph{verbatim}}, in \mymeta{sequences} using the \mypkg{l3seq} module of \mypkg{expl3}. The \mymeta{stored content} can be used as many times as desired in the document, additionally you can write to \mymeta{external files} or show it in \mymeta{verbatim style}. \end{abstract} \end{scontents} \end{examplecode} % \iffalse % % \fi % % and % % \iffalse %<*example> % \fi \begin{examplecode}[numbers=left] \begin{scontents}[store-env=description, print-env=true] The \mypkg*[no-index]{scontents} package allows to \mymeta{store contents} in \mymeta{sequences} or \mymeta{external files}. In some ways it is similar to the \mypkg{filecontentsdef} package, with the difference in which the \mymeta{content} is stored. The idea behind this package is to get an approach to \hologo{ConTeXt} \emph{\enquote{buffers}} by making use of \mymeta{sequences}. \end{scontents} \end{examplecode} % \iffalse % % \fi % % I stored the content in memory and then ran |\getstored| and % |\typestored|. This is one of the ways you can use \mypkg*[no-index]{scontents}. % % \section{Examples} % % These are some adapted examples that have served as inspiration for % the creation of this package. The examples are attached to this documentation % and can be extracted from your PDF viewer or from the command line by running: % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] $ pdfdetach -saveall scontents.pdf \end{examplecode} % \iffalse % % \fi % and then you can use the excellent \arara\footnote{The cool \TeX\ automation tool: % \url{https://www.ctan.org/pkg/arara}} tool to compile them. % % \subsection{From \texttt{answers} package} % % \subsubsection*{Example 1} % % Adaptation of example 1 of the package \mypkg{answers}\cite{answers}. % \myattachfile*{scontents-exa-1} % \lstinputlisting[language=scontents-doc,numbers=left]{scontents-exa-1.tex} % % \subsection{From \texttt{filecontentsdef} package} % % \subsubsection*{Example 2} % % Adaptation of example from package \mypkg{filecontentsdef}\cite{filecontentsdef}. % \myattachfile*{scontents-exa-2} % \lstinputlisting[language=scontents-doc,numbers=left]{scontents-exa-2.tex} % % \subsection{From TeX-SX} % % \subsubsection*{Example 3} % % Adapted from \href{https://tex.stackexchange.com/q/5338/7832}{LaTeX equivalent of ConTeXt buffers}. % \myattachfile*{scontents-exa-3} % \lstinputlisting[language=scontents-doc,numbers=left]{scontents-exa-3.tex} % % \subsubsection*{Example 4} % % Adapted from \href{https://tex.stackexchange.com/q/184503/7832}{Collecting contents of environment and store them for later retrieval}. % \myattachfile*{scontents-exa-4} % \lstinputlisting[language=scontents-doc,numbers=left]{scontents-exa-4.tex} % % \subsubsection*{Example 5} % % Adapted from \href{https://tex.stackexchange.com/q/373647/7832}{Collect contents of an environment (that contains verbatim content)}. % \myattachfile*{scontents-exa-5} % \lstinputlisting[language=scontents-doc,numbers=left]{scontents-exa-5.tex} % % \subsubsection*{Example 6} % % Adapted from \href{https://tex.stackexchange.com/q/509595/7832}{Environment hiding its content}. % \myattachfile*{scontents-exa-6} % \lstinputlisting[language=scontents-doc,numbers=left]{scontents-exa-6.tex} % % \subsection{Customization of \texttt{verbatimsc}} % % \subsubsection*{Example 7} % % Customization of \myenv*[no-index]{verbatimsc} using the \mypkg{fvextra}\cite{fvextra} and % \mypkg{tcolorbox}\cite{tcolorbox} packages. % \myattachfile*{scontents-exa-7} % \lstinputlisting[language=scontents-doc,numbers=left]{scontents-exa-7.tex} % % \subsubsection*{Example 8} % % Customization of \myenv*[no-index]{verbatimsc} using the \mypkg{listings}\cite{listings} package. % \myattachfile*{scontents-exa-8} % \lstinputlisting[language=scontents-doc,numbers=left]{scontents-exa-8.tex} % % \subsubsection*{Example 9} % % Customization of \myenv*[no-index]{verbatimsc} using the \mypkg{minted}\cite{minted} package. % \myattachfile*{scontents-exa-9} % \lstinputlisting[language=scontents-doc,numbers=left]{scontents-exa-9.tex} % % \subsection{The command \cs{mergesc} in action} % % The command |\mergesc| in action, adapted from Denis Bitouzé request % at \url{https://github.com/pablgonz/scontents/issues/2}. % \myattachfile*{scontents-exa-10} % \lstinputlisting[language=scontents-doc,numbers=left]{scontents-exa-10.tex} % % \subsection{Stored contents before storing them}\label{exa:remember} % % The \mykey{remember} key in action: the \mymeta{stored contents} of the % \emph{sequence} |objectives| are used in the section % \enquote{Objectives} before they are stored in the section % \enquote{Methods}, as requested at % \url{https://github.com/pablgonz/scontents/issues/1}. It needs two % compilations. % \myattachfile*{scontents-exa-12} % \lstinputlisting[language=scontents-doc,numbers=left]{scontents-exa-12.tex} % % \subsection{The tagged PDF example} % % This example is just to show the compatibility of \mypkg*[no-index]{scontents} with % \emph{tagged} \texttt{PDF} using |lualatex|. The attached files are only % for testing. % \myattachfile{scontents-exa-11} % \lstinputlisting[language=scontents-doc,numbers=left]{scontents-exa-11.tex} % % \begin{important}* % This example has been checked using \href{https://dev.verapdf-rest.duallab.com}{\texttt{veraPDF}} % together with \href{https://ngpdf.com}{\texttt{ngpdf}}. % \end{important} % % \let\stdsection\section % \def\section*#1{\stdsection{#1}} % \expandafter\let\expandafter\thebibliography\csname HDorg@thebibliography\endcsname % % \begin{thebibliography}{10} % % \bibitem{filecontentsdef} \textsc{Burnol, Jean François}. \enquote{The % \textsf{filecontentsdef} package}. Available from % \textsc{ctan}, \url{https://ctan.org/pkg/filecontentsdef}, 2019. % % \bibitem{expl3} The \hologo{LaTeX} Project. \enquote{The \textsf{expl3} % package}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/expl3}, 2026. % % \bibitem{tagpdf} \textsc{Fischer, Ulrike}. \enquote{\textsf{tagpdf} – \hologo{LaTeX} % kernel code for PDF tagging}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/tagpdf}, 2026. % % \bibitem{fancyvrb} \textsc{Van Zandt, Timothy}. \enquote{The \textsf{fancyvrb} % package - Fancy Verbatims in \hologo{LaTeX}}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/fancyvrb}, 2026. % % \bibitem{fvextra} \textsc{Poore, Geoffrey M}. \enquote{The \textsf{fvextra} % package - Extensions and patches for \textsf{fancyvrb}}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/fvextra}, 2026. % % \bibitem{listings} \textsc{Hoffmann, Jobst}. \enquote{The \textsf{listings} % package}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/listings}, 2025. % % \bibitem{minted} \textsc{Poore, Geoffrey M}. \enquote{The \textsf{minted} % package - Highlighted source code in \hologo{LaTeX}}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/minted}, 2026. % % \bibitem{answers} \textsc{Wright, Joseph}. \enquote{\textsf{answers} – Setting % questions (or exercises) and answers}. Available from % \textsc{ctan}, % \url{https://ctan.org/pkg/answers}, 2014. % % \bibitem{tcolorbox} \textsc{F. Sturm, Thomas}. \enquote{\textsf{tcolorbox} – Coloured boxes, % for \hologo{LaTeX} examples and theorems, etc}. Available from % \textsc{ctan}, \url{https://ctan.org/pkg/tcolorbox}, 2026. % % \bibitem{xparse} The \hologo{LaTeX} Project. \enquote{The \textsf{xparse} % package}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/xparse}, 2024. % % \bibitem{latex2e} The \hologo{LaTeX} Project. \enquote{The \hologo{LaTeX2e} % sources}. Available from % \textsc{ctan}, \url{https://ctan.org/tex-archive/macros/latex/base}, 2026. % % \bibitem{userguide} The \hologo{LaTeX} Project. \enquote{\hologo{LaTeX} for authors % current version}. Available from % \textsc{ctan}, \url{https://ctan.org/pkg/latex-base}, 2026. % % \bibitem{xsim} \textsc{Niederberger, Clemens}. \enquote{\textsf{xsim} – eXercise % Sheets IMproved}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/xsim}, 2023. % % \bibitem{latexlab} The \hologo{LaTeX} Project. \enquote{\textsf{latex-lab} – \hologo{LaTeX} % laboratory}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/latex-lab}, 2026. % % \bibitem{verbatim} The \hologo{LaTeX} Project. \enquote{\textsf{verbatim} – Reimplementation % of and extensions to \hologo{LaTeX} \textsf{verbatim}}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/verbatim}, 2023. % % \bibitem{inter3} The \hologo{LaTeX} Project. \enquote{The \hologo{LaTeX}3 % Interfaces}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/l3kernel}, 2026. % % \bibitem{keyval} \textsc{Wright, Joseph}. \enquote{Programming % \textsf{key–value} in \textsf{expl3}}. Available from % \textsc{TUGboat}, % \url{https://www.tug.org/TUGboat/tb31-1/tb97wright-l3keys.pdf}, 2010. % % \end{thebibliography} % % \let\section\stdsection % % \section{Change history}\label{sec:changes} % % In this section you will find some (not all) of the changes in \mypkg*[no-index]{scontents} % development, from the first public implementation using the \mypkg{filecontentsdef}\cite{filecontentsdef} % package to the current version with only \mypkg{expl3}\cite{expl3}. % % \setlist[itemize,1]{label=\textendash,leftmargin=*,labelsep=0.5em,nosep,noitemsep} % \newlength\descrwidth % \settowidth{\descrwidth}{\textsf{v1.0a, (ctan), 2019-07-30} } % % \begin{description}[font=\small\sffamily,wide=0pt,style=multiline,leftmargin=1.1\descrwidth,nosep,noitemsep] % \item [\fileversion{} (ctan), \filedate] % \begin{itemize} % \item Update requirement to \hologo{LaTeX} release 2026-11-01. % \item Fix warning for empty argument in |\Scontents| and |\Scontents*|. % \item Add error for empty sequence names and undefined sequences. % \item Check positive integers in \mykey{start}, \mykey{step}, \mykey{stop} and \mykey{width-tab} keys. % \item The messages for writing and overwriting files only go to the \texttt{.log} file. % \item Fix \mykey{wrapper} key and allow |\par| in the optional argument of |\foreachsc|. % \item Fix negative \mymeta{index} in |\typestored|, |\meaningsc| and |\mergesc|. % \item Fix the check of existing \mymeta{output files} in \hologo{ConTeXt} for files written in the same run. % \item Fix loading in \hologo{ConTeXt} when \mypkg{expl3} was already loaded by another module. % \item The messages of the environments show their start and end as written in \hologo{plainTeX} and \hologo{ConTeXt}. % \item The \enquote{error} |index-out-of-range| shows the limit of the sequence and the \enquote{errors} |index-out-of-range| and |empty-variable| have a help text. % \item Fix \mymarg{seq name} without \mymeta{index}, undefined sequences and \mymeta{index} out of range in |\mergesc|. % \item Fix \texttt{TAB} at the beginning of a line in |\typestored| and |\mergesc|. % \item Fix empty line at the beginning of |\typestored| and |\mergesc| in \hologo{plainTeX}. % \item Unknown \mymeta{keys} in the package options, |\setupsc| and the \mymeta{initial keys} of |\newenvsc| return an \enquote{error} that names the command. % \item Added regression tests for \hologo{LaTeX}, \hologo{plainTeX} and \hologo{ConTeXt}, run with |l3build check|. % \item New \mykey{remember} key to use the \mymeta{stored contents} before they are stored, only in \hologo{LaTeX} (GitHub issue \#1). % \item New \mykey{getstored} key for |\mergesc| and \mykey{getstored}, \mykey{typestored} and \mykey{meaningsc} keys for |\foreachsc| (GitHub issue \#10). % \item New programming interface for \mypkg{expl3}: \myhlc|\scontents_if_exist:nTF|, \myhlc|\scontents_count:n|, \myhlc|\scontents_get:nnN| and \myhlc|\scontents_map_inline:nn| (GitHub issue \#10). % \end{itemize} % \item [v2.7 (ctan), 2026-06-01] % \begin{itemize} % \item Internal environment \myenv*[no-index]{verbatimsc} update for \emph{tagged} \texttt{PDF}. % \item Update requirement to \hologo{LaTeX} release 2026-06-01. % \item Add \mykey{debug-var} key for writing variables to the \texttt{.log} file. % \item Update and improvements documentation and examples. % \end{itemize} % \item [v2.6 (ctan), 2025-11-20] % \begin{itemize} % \item Internal environment \myenv*[no-index]{verbatimsc} update for \emph{tagged} \texttt{PDF}. % \item Update requirement to \hologo{LaTeX} release 2025-11-01. % \end{itemize} % \item [v2.5 (ctan), 2025-11-01] % \begin{itemize} % \item Replacing |\scantokens| (primitive) with \myhlc|\tl_retokenize:n|. % \item Cleanup warnings and details returned by |expltools|. % \item Update minimum required of \mypkg{expl3} to 2025-07-08. % \end{itemize} % \item [v2.4 (ctan), 2025-05-15] % \begin{itemize} % \item Optimization of expansion code from `|x|' to `|e|'. % \item Restructuring code for documentation and implementation. % \item Add new keys for |\typestored| and |\meaningsc|. % \item Check the version of \mypkg{expl3} in \hologo{plainTeX} and \hologo{ConTeXt}. % \end{itemize} % \item [v2.3 (ctan), 2025-04-23] % \begin{itemize} % \item Adapting the \myenv*[no-index]{verbatimsc} environment for \emph{tagged} \texttt{PDF}. % \item Update minimum required to \LaTeX{} release 2024-11-01. % \item Safer code for replacement |\obeyedline|. % \end{itemize} % \item [v2.2 (ctan), 2025-03-26] % \begin{itemize} % \item Fix internal definition for some functions. % \item Replace \myhlc|\peek_charcode_ignore_spaces:NTF| by \myhlc|\peek_charcode:NTF|. % \item Set correct code for |\obeyedline| implement in \LaTeX{} release 2024-06-01. % \end{itemize} % \item [v2.1 (ctan), 2024-06-14] % \begin{itemize} % \item Fix |\cleanseqsc| command. % \item Add |\mergesc| command. % \item Fix internal definition for seq var. % \item Fix internal code for |\typestored|. % \item Replace \myhlc|\cs_argument_spec:N| by \myhlc|\cs_parameter_spec:N|. % \item Detect \mypkg{l3keys2e} package (obsolete in june 2022 \LaTeX{} release). % \item Minor adjustments in the documentation. % \end{itemize} % \item [v2.0 (ctan), 2022-04-04] % \begin{itemize} % \item Adapting the \myenv*[no-index]{verbatimsc} environment (compatibility \mypkg{verbatim} package). % \item Removed compatibility layer for older \hologo{LaTeX} releases. % \item Fix loader in \hologo{plainTeX} and \hologo{ConTeXt}. % \item Minor adjustments in the documentation. % \end{itemize} % \item [v1.9 (ctan), 2020-01-21] % \begin{itemize} % \item Update and improvements in the internal code. % \item Updating the generic code for |I/O| verification. % \item Add \mykey{write-cmd} and \mykey{write-out} keys for |\Scontents*|. % \item Fix \mykey{sep} key in |\foreachsc|. % \end{itemize} % \item [v1.8 (ctan), 2019-11-18] % \begin{itemize} % \item Add |\newenvsc| command. % \item Fix nested environment in \hologo{plainTeX} and \hologo{ConTeXt}. % \item Modified default value in |\getstored|. % \item Add \mykey{overwrite} key to reduce |I/O| operations. % \item Deleted an unnecessary group in the code. % \end{itemize} % \item [v1.7 (ctan), 2019-10-29] % \begin{itemize} % \item The \myenv*[no-index]{verbatimsc} environment was rewritten. % \item Minor adjustments in documentation. % \end{itemize} % \item [v1.6 (ctan), 2019-10-26] % \begin{itemize} % \item The internal behavior of |\getstored| has been modified. % \item The internal behavior of |\foreachsc| has been modified. % \item Corrected file extension for \hologo{ConTeXt}. % \item Remove spurious warning. % \end{itemize} % \item [v1.5 (ctan), 2019-10-24] % \begin{itemize} % \item Add support for \hologo{plainTeX} and \hologo{ConTeXt}. % \item Split internal code for optimization. % \item Add support for vertical spaces in \myoarg{key \textnormal{\textcolor{gray}{=}} val}. % \item Add |\foreachsc| command. % \item Check if \mypkg{verbatim} package is loaded. % \end{itemize} % \item [v1.4 (ctan), 2019-10-03] % \begin{itemize} % \item Add \mykey{store-all} key. % \item Messages and keys were separated. % \item Restructuring of documentation. % \item Now the version of \mypkg{expl3} is checked instead of \mypkg{xparse}. % \item The internal behavior of \mykey{force-eol} has been modified. % \end{itemize} % \item [v1.3 (ctan), 2019-09-24] % \begin{itemize} % \item The environment \myenv*[no-index]{scontents} can now nest. % \item Added \mykey{force-eol}, \mykey{verb-font} and \mykey{width-tab} keys. % \item The extra space has been removed when you run |\getstored|. % \item Internal code has been rewritten more efficiently. % \item Remove \emph{starred argument} `|*|' for |\typestored|. % \item Remove \mypkg{filecontentsdef} dependency. % \item Changing \myhlc|\regex_replace_all:| for \myhlc|\tl_replace_all:|. % \end{itemize} % \item [v1.2 (ctan), 2019-08-28] % \begin{itemize} % \item Restructuring of documentation. % \item Added copy of \myhlc|\tex_scantokens:|. % \end{itemize} % \item [v1.1 (ctan), 2019-08-12] % \begin{itemize} % \item Extension of documentation. % \item Replace \myhlc|\tex_endinput:D| by \myhlc|\file_input_stop:|. % \end{itemize} % \item [v1.0 (ctan), 2019-07-30] % \begin{itemize} % \item First public release. % \end{itemize} % \end{description} % % \newpage % % \indexprologue{ % The italic numbers denote the pages where the corresponding entry is % described.} % % \printindex[userdoc] % % \newpage % % \StartImplementation % % \StopEventually{^^A % \newgeometry{top=0.5in,bottom=0.3in,left=1.0in,right=0.5in,footskip=0.2in,headheight=1cm,headsep=0.27cm} % \addtocontents{toc}{\protect\setcounter{tocdepth}{2}} % \cleardoublepage % \phantomsection % \indexprologue{ % The italic numbers denote the pages where the corresponding entry is % described, the numbers underlined and all others indicate the line on % which they are implemented in the package code. % } % \printindex % } % % \section{Implementation}\label{sec:implementation} % \addtocontents{toc}{\protect\setcounter{tocdepth}{0}} % % The most recent publicly released version of \mypkg*[no-index]{scontents} % is available at \textsc{ctan}: \url{https://www.ctan.org/pkg/scontents}. % Historical and developmental versions are available at % \textcolor{gray}{\scriptsize\faIcon[regular]{github}} % \url{https://github.com/pablgonz/scontents}. While general feedback via % email is welcomed, specific bugs or feature requests should be reported % through the issue tracker: % \url{https://github.com/pablgonz/scontents/issues}. % % \begin{important}* % All variables and functions defined in this package are private and % are NOT intended to work or be used by another package or module, % except the functions of the programming interface (\S\ref{sec:api}). % \end{important} % % \subsection{General conventions}\label{subsec:conventions} % % The package is split into a \emph{loader} and a \emph{core}. The loader % is different for each format and generates \myfile{scontents.sty} for % \hologo{LaTeX}, \myfile{scontents.tex} for \hologo{plainTeX} and % \myfile{t-scontents.mkiv} for \hologo{ConTeXt}, the core is shared by % the three formats and generates \myfile{scontents-code.tex}, which is % loaded by each loader. % % Since the core runs in \hologo{plainTeX} and \hologo{ConTeXt}, where % the names of some primitives may be redefined by the format, the core % uses the \myhlc|\tex_...:D| names for the primitives that have no % \mypkg{expl3} interface, such as \myhlc|\tex_kern:D|, % \myhlc|\tex_lastskip:D| or \myhlc|\tex_spacefactor:D|. % % Each command and environment is implemented in the same order: its % variables, its messages, its \mymeta{keys}, its internal functions and % finally the public command or environment. % % \subsection{Declaration of the package} % % First we set up the module name for \mypkg{docstrip} and the \mypkg{l3doc} % class: % \begin{macrocode} %<@@=scontents> % \end{macrocode} % % Now we define some common macros to hold the package date and version: % \begin{macrocode} %<*loader> \def\ScontentsFileDate{2026-11-01}% \def\ScontentsFileVersion{2.8}% \def\ScontentsFileDescription{Stores LaTeX contents in memory or files}% % \end{macrocode} % % The \LaTeX{} loader is quite simple, we just need to make sure of the % minimum version for correct operation and then set interfaces up. % The choice of \LaTeX{} release 2026-11-01 is the latest available in % \TeX{} Live 2026 and is necessary to be able to implement % the package's full compatibility with \emph{tagged} \texttt{PDF}. % % \begin{macrocode} %<*latex> \NeedsTeXFormat{LaTeX2e}[2026-11-01] \ProvidesExplPackage {scontents} {\ScontentsFileDate} {\ScontentsFileVersion} {\ScontentsFileDescription} % % \end{macrocode} % % \subsubsection{Load \texttt{expl3-generic} and \texttt{xparse-generic} in \hologo{plainTeX} and \hologo{ConTeXt}}\label{subsubsec:generic-layer} % % \begin{macro}[int] % { % \c_@@_version_str, % \l_@@_char_value_int, % } % The \hologo{plainTeX} and \hologo{ConTeXt} loaders are similar. We % define the constant string \myhlc|\c_@@_version_str| with the version % info and add |\ExplSyntaxOn| to be able to load the frozen % \mypkg{xparse}\cite{xparse}. In \hologo{ConTeXt} the module is loaded % after \myhlc|\unprotect|, which makes `|!|' a letter, but % \mypkg{expl3} and \myfile{xparse-generic.tex} use `|!|' in boolean % expressions and \myfile{expl3-generic.tex} does not set its category % code, so `|!|' is set to \emph{other} before loading it and is a % letter again at the end (\S\ref{subsec:finish}). % \begin{macrocode} %<*!latex> %\writestatus{loading}{User Module scontents v\ScontentsFileVersion} %\unprotect %\catcode`\!=12\relax \input expl3-generic.tex \ExplSyntaxOn \str_const:ce { c_@@_version_str } { \ScontentsFileDate\space v\ScontentsFileVersion\space \ScontentsFileDescription } \iow_log:e { Package: ~ scontents ~ \str_use:c { c_@@_version_str } } % \end{macrocode} % Outside of \LaTeX{} we can't use \mypkg{ltcmd}\cite{latex2e,userguide}, % part of the \LaTeX{} kernel, but the old \mypkg{xparse}\cite{xparse} % provides \myfile{xparse-generic.tex}, which is loadable in any format. % The integer variable \myhlc|\l_@@_char_value_int| saves the category code % of `|@|' while it is loaded. % \begin{macrocode} \int_new:N \l_@@_char_value_int \int_set:Nn \l_@@_char_value_int { \char_value_catcode:n { `\@ } } \char_set_catcode_letter:N \@ \file_input:n { xparse-generic.tex } \char_set_catcode:nn { `\@ } { \l_@@_char_value_int } % % \end{macrocode} % \end{macro} % % \subsubsection{Checking \texttt{expl3} version} % % For \hologo{plainTeX}, \hologo{LaTeX} and \hologo{ConTeXt} we must check % the minimum requirement, in this case \myhlc|\tl_retokenize:n| which % was added in release 2025-07-08 of \mypkg{expl3} included in % \hologo{TeX} Live 2025. % \begin{macrocode} \cs_if_exist:NF \tl_retokenize:n { \msg_new:nnn { scontents } { expl-too-old } { Please~install~an~up~to~date~TeX~distribution~or~update~using~ your~TeX~package~manager~or~from~CTAN. \\ See~documentation.~Loading~scontents~will~abort! } \msg_fatal:nn { scontents } { expl-too-old } \ExplSyntaxOff \file_input_stop: } % \end{macrocode} % % \subsubsection{Preventing double loading in \hologo{plainTeX}} % % In \hologo{plainTeX}, check that the package isn't being loaded twice, % \LaTeX{} and \hologo{ConTeXt} already defend against that: % \begin{macrocode} %<*plain> \tl_if_exist:NT \l_@@_cmd_name_tl { \msg_new:nnn { scontents } { already-loaded } { The~'scontents'~package~is~already~loaded.~ Aborting~input~\msg_line_context:. } \msg_warning:nn { scontents } { already-loaded } \ExplSyntaxOff \file_input_stop: } % % % \end{macrocode} % % \subsubsection{Checking proper loader} % % Checking that the package was loaded with the proper loader code. This code % was copied from \myfile{expl3-code.tex}. % \begin{macrocode} %<*core> \def\ScontentsCoreFileDate{2026-11-01}% \begingroup \catcode32=10 \endlinechar=32 \def\next{\endgroup}% \expandafter\ifx\csname PackageError\endcsname\relax \begingroup \def\next{\endgroup\endgroup}% \def\PackageError#1#2#3% {% \endgroup \errhelp{#3}% \errmessage{#1 Error: #2!}% }% \fi \expandafter\ifx\csname ScontentsFileDate\endcsname\relax \def\next {% \PackageError{scontents}{No scontents loader detected} {% You have attempted to use the scontents code directly rather than using the correct loader. Loading of scontents will abort. }% \endgroup \endinput }% \else \ifx\ScontentsFileDate\ScontentsCoreFileDate \else \def\next {% \PackageError{scontents}{Mismatched scontents files detected} {% You have attempted to load scontents with mismatched files: probably you have one or more files 'locally installed' which are in conflict. Loading of scontents will abort. }% \endgroup \endinput }% \fi \fi \next % % \end{macrocode} % % \subsection{Variables and functions by format}\label{subsec:format} % % We define and set the variables and the function that must be handled % separately in order to work properly with \hologo{plainTeX}, \LaTeX{} and % \hologo{ConTeXt}. % % \begin{macro}[int]{\@@_format_case:nnn} % The function \myhlc|\@@_format_case:nnn| leaves the argument for the % current format: |#1| for \LaTeX, |#2| for \hologo{plainTeX} and |#3| for % \hologo{ConTeXt}. % \begin{macrocode} %<*loader> \cs_new:Npn \@@_format_case:nnn #1 #2 #3 % {#1} % LaTeX % {#2} % Plain/Generic % {#3} % ConTeXt % \end{macrocode} % \end{macro} % % \begin{macro}[int,TF]{\@@_file_if_exist:n} % The conditional \myhlc|\@@_file_if_exist:nTF| tests if the % \mymeta{output file} passed in |#1| exists in the working directory. % In \hologo{LaTeX} and \hologo{plainTeX} it is % \myhlc|\file_if_exist:nTF|. In \hologo{ConTeXt} the file search keeps % the result found at the start of the run, so a file written by the % package in the same run is not found; there the test is done with % |lfs.isfile| of \hologo{LuaTeX}, the \mymeta{output file} is always % in the working directory. % \begin{macrocode} %\cs_new_eq:NN \@@_file_if_exist:nTF \file_if_exist:nTF %<*context> \prg_new_conditional:Npnn \@@_file_if_exist:n #1 { TF } { \str_if_eq:eeTF { \lua_now:e { tex.write(lfs.isfile("\lua_escape:e {#1}")~and~"1"~or~"0") } } { 1 } { \prg_return_true: } { \prg_return_false: } } % % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\c_@@_newline_tl} % The constant token list \myhlc|\c_@@_newline_tl| stores the character % `\myhlc|^^J|' used as end of line in the \mymeta{stored content}. % \begin{macrocode} %<*!context> \tl_const:Ne \c_@@_newline_tl { \iow_char:N \^^J } % % \end{macrocode} % In \hologo{ConTeXt} the package does not work under LMTX, so loading % is aborted there. The test with \myhlc|\contextlmtxmode| is adapted % from the file \myfile{t-lua-widow-control.mkxl} of Max Chernoff's % \mypkg{lua-widow-control} package, \myhlc|\contextlmtxmode| is % described in \url{https://source.contextgarden.net/tex/context/base/mkxl/context.mkxl}. % \begin{macrocode} %<*context> \bool_if:NTF \contextlmtxmode { \msg_new:nnn { scontents } { luametatex } { The~'scontents'~package~doesn't~work~under~LMTX. } \msg_fatal:nn { scontents } { luametatex } } { \tl_const:Ne \c_@@_newline_tl { \iow_char:N \^^J } } % % \end{macrocode} % \end{macro} % % \begin{macro}[int] % { % \g_@@_end_verbatimsc_tl, % \c_@@_end_env_tl, % \l_@@_env_name_tl, % } % The global token list \myhlc|\g_@@_end_verbatimsc_tl| matches the end of % the |verbatimsc| environment (\S\ref{env:verbatimsc}) in each format. % \begin{macrocode} \tl_new:N \g_@@_end_verbatimsc_tl \tl_gset_rescan:Nnn \g_@@_end_verbatimsc_tl { \char_set_catcode_other:N \\ %<*latex> \char_set_catcode_other:N \{ \char_set_catcode_other:N \} % } % { \end{verbatimsc} } % { \endverbatimsc } % { \stopverbatimsc } % \end{macrocode} % The constant token list \myhlc|\c_@@_end_env_tl| matches the end of the % environments defined by |\newenvsc| and the token list % \myhlc|\l_@@_env_name_tl| stores the \emph{name} of the environment % being processed (\S\ref{cmd:newenvsc}). % \begin{macrocode} \tl_new:N \l_@@_env_name_tl \tl_const:Ne \c_@@_end_env_tl { \c_backslash_str % end % stop % \c_left_brace_str \exp_not:N \l_@@_env_name_tl % \c_right_brace_str } % \end{macrocode} % \end{macro} % % \subsection{Loading the package core} % % Now we load the core \mypkg*[no-index]{scontents} code: % \begin{macrocode} \file_input:n { scontents-code.tex } % % \end{macrocode} % % \subsection{Some kernel variants} % % \begin{macro}[int]{\tl_replace_all:NeV, \tl_retokenize:e} % Some nonstandard kernel variants. % \begin{macrocode} %<*core> \cs_generate_variant:Nn \tl_replace_all:Nnn { NeV } \cs_generate_variant:Nn \tl_retokenize:n { e } % \end{macrocode} % \end{macro} % % \subsection{General variables}\label{subsec:general-vars} % % \begin{macro}[int]{\q_@@_stop, \q_@@_mark, \s_@@_stop, \s_@@_mark} % Quarks and scan marks used along the code as delimiters. % \begin{macrocode} \quark_new:N \q_@@_stop \quark_new:N \q_@@_mark \scan_new:N \s_@@_stop \scan_new:N \s_@@_mark % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\l_@@_cmd_name_tl} % The token list \myhlc|\l_@@_cmd_name_tl| stores the \emph{name} of the % command that receives the \mymeta{keys}: |\Scontents|, |\foreachsc|, % |\typestored|, |\meaningsc|, |\mergesc|, |\setupsc|, |\newenvsc| or % |\usepackage| for the options of the package. It is used in the % messages for unknown \mymeta{keys} (\S\ref{key:unknown-keys}). % \begin{macrocode} \tl_new:N \l_@@_cmd_name_tl % \end{macrocode} % \end{macro} % % \begin{macro}[int] % { % \l_@@_file_name_tl, % \l_@@_file_write_iow, % \l_@@_writing_bool, % \l_@@_storing_bool, % \l_@@_writable_bool, % } % The token list \myhlc|\l_@@_file_name_tl| stores the name of the % \mymeta{output file} set by the \mykey{write-env}, \mykey{write-out} % and \mykey{write-cmd} keys and \myhlc|\l_@@_file_write_iow| is the % \emph{output stream} used to write it. % % The boolean variables \myhlc|\l_@@_writing_bool| and % \myhlc|\l_@@_storing_bool|, set by the same keys, determine whether the % content is written to the \mymeta{output file} and whether it is % stored, \myhlc|\l_@@_storing_bool| is true by default. The boolean % variable \myhlc|\l_@@_writable_bool| keeps track of whether the % \mymeta{output file} was opened by \myhlc|\@@_file_if_writable:nTF| % (\S\ref{fun:utility}). % \begin{macrocode} \tl_new:N \l_@@_file_name_tl \iow_new:N \l_@@_file_write_iow \bool_new:N \l_@@_writing_bool \bool_new:N \l_@@_storing_bool \bool_new:N \l_@@_writable_bool \bool_set_true:N \l_@@_storing_bool % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\l_@@_seq_item_seq, \g_@@_name_sc!internal_seq} % The sequence \myhlc|\l_@@_seq_item_seq| stores the \mymeta{indexes} % of the \mymeta{stored content} requested to |\typestored|, % |\meaningsc| or |\mergesc| and the sequence % \myhlc|\g_@@_name_sc!internal_seq| is the one assembled by |\mergesc| % (\S\ref{cmd:mergesc}). % \begin{macrocode} \seq_new:N \l_@@_seq_item_seq \seq_new:c { g_@@_name_sc!internal_seq } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\g_@@_last_stored_tl} % The token list \myhlc|\g_@@_last_stored_tl| is used by the function % \myhlc|\@@_lastfrom_seq:n| (\S\ref{fun:sequences}) to execute the % last \mymeta{stored content} outside the group. % \begin{macrocode} \tl_new:N \g_@@_last_stored_tl % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\c_@@_hidden_space_str} % The constant string \myhlc|\c_@@_hidden_space_str| hides the % \mymeta{forced space} added by \hologo{TeX} when recording content in % a macro. It contains the \emph{reserved phrase} `|%^^Ascheol%|', which % is added to the end of the \mymeta{stored content} when the key % \mykey{force-eol} is false. % \begin{macrocode} \str_const:Ne \c_@@_hidden_space_str { \c_percent_str \c_circumflex_str \c_circumflex_str A scheol \c_percent_str } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\l_@@_save_sf_int, \l_@@_save_skip} % Variables used by the functions \myhlc|\@@_bsphack:| and % \myhlc|\@@_esphack:| (\S\ref{fun:sphack}). % \begin{macrocode} \int_new:N \l_@@_save_sf_int \skip_new:N \l_@@_save_skip % \end{macrocode} % \end{macro} % % \subsection{General messages}\label{subsec:general-messages} % % \subsubsection{Definition of error messages} % % \begin{macro}[int]{undefined-storage, index-out-of-range} % The \enquote{error} |undefined-storage| is raised when the % \emph{sequence} passed to |\getstored|, |\foreachsc|, |\typestored|, % |\meaningsc|, |\mergesc|, |\countsc| or to the functions of the % programming interface does not exist % (\S\ref{fun:sequences}, \S\ref{cmd:foreachsc}, \S\ref{cmd:mergesc}, % \S\ref{cmd:countsc}, \S\ref{fun:api}) and the \enquote{error} % |index-out-of-range| is raised when the \mymeta{index} is zero or its % absolute value is greater than the number of \mymeta{stored contents} % (\S\ref{fun:sequences}, \S\ref{cmd:mergesc}, \S\ref{fun:api}). % \begin{macrocode} \msg_new:nnnn { scontents } { undefined-storage } { Storage~named~'#1'~is~not~defined. } { No~content~has~been~stored~in~a~sequence~named~'#1'. } \msg_new:nnnn { scontents } { index-out-of-range } { \int_compare:nNnTF {#1} = { 0 } { Index~of~sequence~'#2'~cannot~be~zero. } { Index~'#1'~out~of~range~for~'#2',~the~ \int_compare:nNnTF {#1} > { 0 } { maximum~is~#3. } { minimum~is~-#3. } } } { The~sequence~'#2'~has~#3~stored~contents,~use~an~index~from~ 1~to~#3~or~from~-#3~to~-1. } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{positive-integer, empty-store-name} % The \enquote{error} |positive-integer| is raised when the keys % \mykey{width-tab}, \mykey{start}, \mykey{step} or \mykey{stop} receive % a value that is not a \mymeta{positive integer} % (\S\ref{key:package},~\S\ref{key:foreachsc}) and the \enquote{error} % |empty-store-name| is raised when the name of the \emph{sequence} is % blank (\S\ref{fun:sequences}). % \begin{macrocode} \msg_new:nnnn { scontents } { positive-integer } { The~key~'#1'~needs~a~positive~integer,~'#2'~given~\msg_line_context:. } { The~value~'#2'~is~ignored~and~the~key~'#1'~keeps~its~previous~value. } \msg_new:nnnn { scontents } { empty-store-name } { Empty~sequence~name~for~storing~content~\msg_line_context:. } { The~keys~'store-env',~'store-cmd'~and~'store-all'~need~a~non-empty~ sequence~name.~The~content~will~not~be~stored. } % \end{macrocode} % \end{macro} % % \subsubsection{Definition of messages for writing files} % % \begin{macro}[int]{writing-file, overwrite-file, not-writing} % The \enquote{info} messages |writing-file| and |overwrite-file| are % written to the \texttt{.log} file when an \mymeta{output file} is % written or overwritten and the \enquote{warning} |not-writing| is % issued when the \mymeta{output file} already exists and the key % \mykey{overwrite} is not active (\S\ref{fun:utility}). % \begin{macrocode} \msg_new:nnn { scontents } { writing-file } { Writing~file~'#1'. } \msg_new:nnn { scontents } { overwrite-file } { Overwriting~file~'#1'. } \msg_new:nnn { scontents } { not-writing } { File~'#1'~already~exists.~Not~writing~\msg_line_context:. } % % \end{macrocode} % \end{macro} % % \subsection{Keys for the package}\label{key:package} % % \begin{macro}[int]{\l_@@_tab_width_int, \@@_set_positive_int:Nnn} % The integer variable \myhlc|\l_@@_tab_width_int| stores the value of % the \mykey{width-tab} key. The function % \myhlc|\@@_set_positive_int:Nnn| sets the integer variable passed in % |#1| to the value passed in |#3| only if it is a % \mymeta{positive integer}, otherwise it raises the \enquote{error} % |positive-integer| naming the \mymeta{key} passed in |#2| and the % value is ignored. It is used by the \mykey{width-tab} key and by the % \mykey{start}, \mykey{step} and \mykey{stop} keys of |\foreachsc| % (\S\ref{key:foreachsc}). The core code does not use `|!|' in boolean % expressions, so it does not depend on the category code of `|!|' in % \hologo{ConTeXt} (\S\ref{subsubsec:generic-layer}). % \begin{macrocode} %<*core> \int_new:N \l_@@_tab_width_int \cs_new_protected:Npn \@@_set_positive_int:Nnn #1 #2 #3 { \bool_lazy_or:nnTF { \tl_if_blank_p:n {#3} } { \int_compare_p:nNn {#3} < { 1 } } { \msg_error:nnnn { scontents } { positive-integer } {#2} {#3} } { \int_set:Nn #1 {#3} } } % \end{macrocode} % \end{macro} % % \begin{macro}[int] % { % store-env, % store-cmd, % verb-font, % print-env, % print-cmd, % force-eol, % overwrite, % width-tab, % print-all, % store-all, % debug-var, % remember, % unknown, % } % We define the common \mymeta{keys} used by the options passed to the % package, by |\setupsc| and by the environments and commands. The % unknown \mymeta{keys} are passed to \myhlc|\@@_unknown_keys_cmd:n| % (\S\ref{key:unknown-keys}), which names the command from % \myhlc|\l_@@_cmd_name_tl|: |\usepackage| for the options of the % package, |\setupsc| or |\newenvsc| for the \mymeta{initial keys} of % an environment. % \begin{macrocode} \keys_define:nn { scontents } { store-env .tl_set:N = \l_@@_name_seq_env_tl, store-env .initial:n = contents, store-env .value_required:n = true, store-cmd .tl_set:N = \l_@@_name_seq_cmd_tl, store-cmd .initial:n = contents, store-cmd .value_required:n = true, verb-font .tl_set:N = \l_@@_verb_font_tl, verb-font .value_required:n = true, print-env .bool_set:N = \l_@@_print_env_bool, print-env .initial:n = false, print-env .default:n = true, print-cmd .bool_set:N = \l_@@_print_cmd_bool, print-cmd .initial:n = false, print-cmd .default:n = true, force-eol .bool_set:N = \l_@@_forced_eol_bool, force-eol .initial:n = false, force-eol .default:n = true, overwrite .bool_set:N = \l_@@_overwrite_bool, overwrite .initial:n = false, overwrite .default:n = true, width-tab .code:n = { \@@_set_positive_int:Nnn \l_@@_tab_width_int { width-tab } {#1} }, width-tab .initial:n = 1, width-tab .value_required:n = true, print-all .meta:n = { print-env = #1, print-cmd = #1 }, print-all .default:n = true, store-all .meta:n = { store-env = #1, store-cmd = #1 }, store-all .value_required:n = true, debug-var .bool_set:N = \l_@@_debug_var_bool, debug-var .initial:n = true, debug-var .default:n = true, remember .code:n = { \@@_remember:n {#1} }, remember .value_required:n = true, remember .usage:n = preamble, unknown .code:n = { \@@_unknown_keys_cmd:n {#1} }, } % % \end{macrocode} % The default value of the \mykey{verb-font} key depends on the format. % \begin{macrocode} %\keys_define:nn { scontents } % { verb-font .initial:n = \ttfamily } % { verb-font .initial:n = \tt } % \end{macrocode} % In \LaTeX{} the \mymeta{keys} passed as options to the package are % processed and an unknown \mymeta{key} returns an \enquote{error}. % \begin{macrocode} %<*latex> \tl_set:Nn \l_@@_cmd_name_tl { usepackage } \ProcessKeyOptions [ scontents ] % % \end{macrocode} % \end{macro} % % \subsection{Handling unknown keys}\label{key:unknown-keys} % % The \mymeta{keys} that are not known by the environments and the % commands are passed to the functions defined here. The name of the % \mymeta{key} is taken from \myhlc|\l_keys_key_str| and the value, if % any, is passed as argument. % % \subsubsection{Definition of error messages for unknown keys} % % \begin{macro}[int]{env-key-unknown, env-key-value-unknown} % The \enquote{errors} |env-key-unknown| and |env-key-value-unknown| % are raised when an unknown \mymeta{key}, without or with value, is % passed to an environment defined by |\newenvsc| (\S\ref{key:newenvsc}). % \begin{macrocode} %<*core> \msg_new:nnnn { scontents } { env-key-unknown } { The~key~'#1'~is~unknown~by~environment~ '\l_@@_env_name_tl'~and~is~being~ignored. } { The~environment~'\l_@@_env_name_tl'~does~not~have~a~key~called~'#1'.\\ Check~that~you~have~spelled~the~key~name~correctly. } \msg_new:nnnn { scontents } { env-key-value-unknown } { The~key~'#1=#2'~is~unknown~by~environment~ '\l_@@_env_name_tl'~and~is~being~ignored. } { The~environment~'\l_@@_env_name_tl'~does~not~have~a~key~called~'#1'.\\ Check~that~you~have~spelled~the~key~name~correctly. } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{cmd-key-unknown, cmd-key-value-unknown} % The \enquote{errors} |cmd-key-unknown| and |cmd-key-value-unknown| % are raised when an unknown \mymeta{key}, without or with value, is % passed to the commands |\Scontents|, |\foreachsc|, |\typestored|, % |\meaningsc|, |\mergesc| or |\setupsc|, to the \mymeta{initial keys} % of |\newenvsc| or as an option of the package % (\S\ref{key:package}, \S\ref{key:Scontents}, \S\ref{key:foreachsc}, % \S\ref{key:typemeaning}). % \begin{macrocode} \msg_new:nnnn { scontents } { cmd-key-unknown } { The~key~'#1'~is~unknown~by~command~ \c_backslash_str \l_@@_cmd_name_tl \c_space_tl and~is~being~ignored~\msg_line_context:. } { The~command~\c_backslash_str \l_@@_cmd_name_tl \c_space_tl does~not~have~a~key~called~'#1'.\\ Check~that~you~have~spelled~the~key~name~correctly. } \msg_new:nnnn { scontents } { cmd-key-value-unknown } { The~key~'#1=#2'~is~unknown~by~command~ \c_backslash_str \l_@@_cmd_name_tl \c_space_tl and~is~being~ignored~\msg_line_context:. } { The~command~\c_backslash_str \l_@@_cmd_name_tl \c_space_tl does~not~have~a~key~called~'#1'.\\ Check~that~you~have~spelled~the~key~name~correctly. } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for unknown keys} % % \begin{macro}[int]{\@@_unknown_keys_env:n, \@@_unknown_keys_env:nn} % The function \myhlc|\@@_unknown_keys_env:n| raises the % \enquote{error} for an unknown \mymeta{key} passed to an environment % defined by |\newenvsc|. % \begin{macrocode} \cs_new_protected:Npn \@@_unknown_keys_env:n #1 { \exp_args:NV \@@_unknown_keys_env:nn \l_keys_key_str {#1} } \cs_new_protected:Npn \@@_unknown_keys_env:nn #1 #2 { \tl_if_blank:nTF {#2} { \msg_error:nnn { scontents } { env-key-unknown } {#1} } { \msg_error:nnnn { scontents } { env-key-value-unknown } {#1} {#2} } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_unknown_keys_cmd:n, \@@_unknown_keys_cmd:nn} % The function \myhlc|\@@_unknown_keys_cmd:n| raises the % \enquote{error} for an unknown \mymeta{key} passed to the commands % |\Scontents|, |\foreachsc|, |\mergesc| and |\setupsc|, to the % \mymeta{initial keys} of |\newenvsc| and to the package. % \begin{macrocode} \cs_new_protected:Npn \@@_unknown_keys_cmd:n #1 { \exp_args:NV \@@_unknown_keys_cmd:nn \l_keys_key_str {#1} } \cs_new_protected:Npn \@@_unknown_keys_cmd:nn #1 #2 { \tl_if_blank:nTF {#2} { \msg_error:nnn { scontents } { cmd-key-unknown } {#1} } { \msg_error:nnnn { scontents } { cmd-key-value-unknown } {#1} {#2} } } % \end{macrocode} % \end{macro} % % \subsection{Utility functions}\label{fun:utility} % % \begin{macro}[int] % { % \@@_use_delimit_by_s_stop:nw, % \@@_use_i_delimit_by_s_stop:nw, % \@@_use_none_delimit_by_s_stop:w, % \@@_use_none_delimit_by_q_stop:w, % } % Functions used in the implementation of |\newenvsc| % (\S\ref{fun:newenvsc}) and |\mergesc| (\S\ref{cmd:mergesc}). % \begin{macrocode} \cs_new:Npn \@@_use_delimit_by_s_stop:nw #1 \s_@@_stop {#1} \cs_new:Npn \@@_use_i_delimit_by_s_stop:nw #1 #2 \s_@@_stop {#1} \cs_new:Npn \@@_use_none_delimit_by_s_stop:w #1 \s_@@_stop { } \cs_new:Npn \@@_use_none_delimit_by_q_stop:w #1 \q_@@_stop { } % \end{macrocode} % \end{macro} % % \begin{macro}[int,TF]{\@@_tl_if_head_is_q_mark:n} % The conditional \myhlc|\@@_tl_if_head_is_q_mark:nTF| tests if the head % of the token list is \myhlc|\q_@@_mark|. % \begin{macrocode} \prg_new_protected_conditional:Npnn \@@_tl_if_head_is_q_mark:n #1 { F, TF } { \exp_after:w \if_meaning:w \exp_after:w \q_@@_mark \@@_use_i_delimit_by_s_stop:nw #1 ? \s_@@_stop \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_remove_trailing_eol:N, \@@_remove_trailing_eol:w} % The function \myhlc|\@@_remove_trailing_eol:N| removes the string % \myhlc|\c_@@_hidden_space_str| from the end of the token list passed in % |#1|. It is used by |\typestored| (\S\ref{cmd:typestored}) and % |\mergesc| (\S\ref{cmd:mergesc}). % \begin{macrocode} \cs_new_protected:Npe \@@_remove_trailing_eol:N #1 { \exp_not:N \exp_after:w \exp_not:N \@@_remove_trailing_eol:w #1 \s_@@_stop \c_@@_hidden_space_str \s_@@_stop \s_@@_mark #1 } \use:e { \cs_new_protected:Npn \exp_not:N \@@_remove_trailing_eol:w #1 \c_@@_hidden_space_str \s_@@_stop #2 \s_@@_mark #3 } { \tl_set:Ne #3 { \tl_if_empty:nTF {#2} { \exp_not:o { \@@_use_delimit_by_s_stop:nw #1 } } { \exp_not:n {#1} } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int,TF]{\@@_file_if_writable:n} % The conditional \myhlc|\@@_file_if_writable:nTF| tests if the % \mymeta{output file} passed in |#1| can be written, according to the % \mykey{write-env}, \mykey{write-cmd}, \mykey{write-out} and % \mykey{overwrite} keys, and issues the messages for writing files % (\S\ref{subsec:general-messages}). The \mymeta{output file} is % searched with \myhlc|\@@_file_if_exist:nTF|. % \begin{macrocode} \prg_new_protected_conditional:Npnn \@@_file_if_writable:n #1 { T, TF } { \bool_if:NTF \l_@@_writing_bool { \@@_file_if_exist:nTF {#1} { \bool_if:NTF \l_@@_overwrite_bool { \msg_info:nne { scontents } { overwrite-file } {#1} \prg_return_true: } { \msg_warning:nne { scontents } { not-writing } {#1} \prg_return_false: } } { \msg_info:nne { scontents } { writing-file } {#1} \prg_return_true: } } { \prg_return_false: } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_file_write_cmd:nn, \@@_file_write_cmd:VV} % The function \myhlc|\@@_file_write_cmd:nn| writes the content passed % in |#2| to the \mymeta{output file} passed in |#1|, it is used by the % commands. % \begin{macrocode} \cs_new_protected:Npn \@@_file_write_cmd:nn #1 #2 { \@@_file_if_writable:nT {#1} { \iow_open:Nn \l_@@_file_write_iow {#1} \iow_now:Nn \l_@@_file_write_iow {#2} \iow_close:N \l_@@_file_write_iow } } \cs_generate_variant:Nn \@@_file_write_cmd:nn { VV } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_set_write_out:n, \@@_set_write_store:n} % The function \myhlc|\@@_set_write_out:n| sets the name of the % \mymeta{output file} passed in |#1| and only writes the content, it is % used by the \mykey{write-out} key. The function % \myhlc|\@@_set_write_store:n| also stores the content, it is used by % the \mykey{write-env} and \mykey{write-cmd} keys % (\S\ref{key:newenvsc},~\S\ref{key:Scontents},~\S\ref{key:typemeaning}). % \begin{macrocode} \cs_new_protected:Npn \@@_set_write_out:n #1 { \bool_set_false:N \l_@@_storing_bool \bool_set_true:N \l_@@_writing_bool \tl_set:Nn \l_@@_file_name_tl {#1} } \cs_new_protected:Npn \@@_set_write_store:n #1 { \@@_set_write_out:n {#1} \bool_set_true:N \l_@@_storing_bool } % \end{macrocode} % \end{macro} % % \subsubsection{Functions for \texttt{TAB} and \texttt{verbatimsc}} % % \begin{macro}[int]{\@@_tab:, \@@_par:} % Control sequences to replace the tab `\myhlc|^^I|' and form feed `\myhlc|^^L|' % characters. % \begin{macrocode} \cs_new:Ne \@@_tab: { \c_space_tl } \cs_new:Nn \@@_par: { ^^J ^^J } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_tabs_to_spaces:} % In a \emph{verbatim} context the \texttt{TAB} character is made active % and set equal to \myhlc|\@@_tabs_to_spaces:|, to produce as many spaces % as the \mykey{width-tab} key was set to. The spaces are \emph{active} % characters, the same as the spaces of the \emph{verbatim} context: a % space token at the beginning of a line would be dropped in vertical % mode and the \texttt{TAB} that indent a line would be lost. The % \emph{active} space is made with \myhlc|\tex_lowercase:D| from the % \emph{active} character `\myhlc|^^@|', since \myhlc|\char_generate:nn| % would expand it while defining the function. % \begin{macrocode} \group_begin: \char_set_catcode_active:N \^^@ \char_set_lccode:nn { 0 } { 32 } \tex_lowercase:D { \group_end: \cs_new:Npn \@@_tabs_to_spaces: { \prg_replicate:nn { \l_@@_tab_width_int } { ^^@ } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_do_noligs:N} % The function \myhlc|\@@_do_noligs:N| is an alternative definition for % \LaTeXe's \myhlc|\do@noligs| which makes sure to not consume the % following space tokens. The \LaTeXe{} version ends with % \myhlc|\char`#1|, which leaves \TeX{} still looking for an % \mymeta{optional~space}. % \begin{macrocode} \cs_new_protected:Npn \@@_do_noligs:N #1 { \char_set_catcode_active:N #1 \cs_set:cpe { @@_active_char_ \token_to_str:N #1 : } { \mode_leave_vertical: \tex_kern:D \c_zero_dim \tex_char:D `\exp_not:N #1 } \char_set_active_eq:Nc #1 { @@_active_char_ \token_to_str:N #1 : } } % \end{macrocode} % \end{macro} % % \begin{macro}[int] % { % \@@_set_active_eq:NN, % \@@_plain_disable_outer_par:, % \@@_make_control_chars_active:, % } % Shortcut definitions for common catcode changes. The `\myhlc|^^L|' needs a % special treatment in \hologo{plainTeX} because it is an % \myhlc|\outer| token there. % \begin{macrocode} \cs_new_protected:Npn \@@_set_active_eq:NN #1 { \char_set_catcode_active:N #1 \char_set_active_eq:NN #1 } % %<*loader> \group_begin: % \char_set_catcode_active:n { `\* } \cs_new_protected:Nn \@@_plain_disable_outer_par: %<*plain> { \group_begin: \char_set_lccode:nn { `\* } { `\^^L } \tex_lowercase:D { \group_end: \tex_let:D * \scan_stop: } } % % { } \group_end: % %<*core> \cs_new_protected:Nn \@@_make_control_chars_active: { \@@_plain_disable_outer_par: \@@_set_active_eq:NN \^^I \@@_tab: \@@_set_active_eq:NN \^^L \@@_par: \@@_set_active_eq:NN \^^M \@@_ret:w } % \end{macrocode} % \end{macro} % % \subsubsection{Functions \cs[no-index]{@bsphack} and \cs[no-index]{@esphack}}\label{fun:sphack} % % \begin{macro}[int]{\@@_bsphack:, \@@_esphack:} % We emulate \myhlc|\@bsphack| and \myhlc|\@esphack| for \hologo{plainTeX} % and \hologo{ConTeXt}, this is necessary to prevent \emph{unwanted % spaces} when the \mykey{print-cmd} key is false. In \LaTeX{} the % kernel definitions are used. % \begin{macrocode} \cs_new_protected:Nn \@@_bsphack: { \scan_stop: \mode_if_horizontal:T { \skip_set_eq:NN \l_@@_save_skip \tex_lastskip:D \int_set_eq:NN \l_@@_save_sf_int \tex_spacefactor:D } } \cs_new_protected:Nn \@@_esphack: { \scan_stop: \mode_if_horizontal:T { \int_set_eq:NN \tex_spacefactor:D \l_@@_save_sf_int \dim_compare:nNnT { \l_@@_save_skip } > { \c_zero_skip } { \skip_if_eq:nnT { \tex_lastskip:D } { \c_zero_skip } { \nobreak \skip_horizontal:n { \c_zero_skip } } \tex_ignorespaces:D } } } % %<*latex> \cs_gset_eq:NN \@@_bsphack: \@bsphack \cs_gset_eq:NN \@@_esphack: \@esphack % % \end{macrocode} % \end{macro} % % \subsection{Functions for sequences}\label{fun:sequences} % % The \emph{storage system} of the package \mypkg*[no-index]{scontents} is % done using |seq| variables. Here we set up the functions that manage them. % % \begin{macro}[int]{\@@_append_contents:nn, \@@_append_contents:Ve} % The function \myhlc|\@@_append_contents:nn| creates the \emph{sequence} % passed in |#1| if it does not exist and appends the \mymarg{body env} % of an environment or the \mymarg{argument} of a command, passed in % |#2|, to the right of the \emph{sequence}. % \begin{macrocode} %<*core> \cs_new_protected:Npn \@@_append_contents:nn #1 #2 { \seq_if_exist:cF { g_@@_name_#1_seq } { \seq_new:c { g_@@_name_#1_seq } } \seq_gput_right:cn { g_@@_name_#1_seq } {#2} } \cs_generate_variant:Nn \@@_append_contents:nn { Ve } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_store_to_seq:NN} % The function \myhlc|\@@_store_to_seq:NN| writes the recorded content % in |#1| to the \texttt{.log} file if \mykey{debug-var} is true and % stores it in the \emph{sequence} named by |#2|. % \begin{macrocode} \cs_new_protected:Npn \@@_store_to_seq:NN #1 #2 { \bool_if:NT \l_@@_debug_var_bool { \tl_log:N #1 } \@@_append_contents:Ve #2 { \exp_not:V #1 } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_finish_storing:NNN} % The function \myhlc|\@@_finish_storing:NNN| works only in the % \emph{storing mode}, when the \mykey{write-out} key is not active. If % the key \mykey{force-eol} is false, its default value, % \myhlc|\c_@@_hidden_space_str| is added to the end of the token list % passed in |#1|, which contains the \mymarg{body env} of an environment % or the \mymarg{argument} of |\Scontents|. % % Then \myhlc|\@@_store_to_seq:NN| stores the content in the % \emph{sequence} named by |#2| and, if the boolean passed in |#3|, set % by the \mykey{print-env} or \mykey{print-cmd} key, is true, the content % is printed from the \emph{sequence} by \myhlc|\@@_lastfrom_seq:V|. If % the \emph{name} of the \emph{sequence} is blank, the \enquote{error} % |empty-store-name| is raised and nothing is stored or printed. % \begin{macrocode} \cs_new_protected:Npn \@@_finish_storing:NNN #1 #2 #3 { \bool_if:NT \l_@@_storing_bool { \tl_if_blank:VTF #2 { \msg_error:nn { scontents } { empty-store-name } } { \bool_if:NF \l_@@_forced_eol_bool { \tl_put_right:Ne #1 { \c_@@_hidden_space_str } } \@@_store_to_seq:NN #1 #2 \bool_if:NT #3 { \@@_lastfrom_seq:V #2 } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_seq_count:n, \@@_seq_item:nn} % \begin{macro}[int,TF]{\@@_seq_if_exist:n} % A \emph{sequence} set by the \mykey{remember} key has a second copy % with the \mymeta{stored contents} of the previous compilation, whose % name uses |prev| instead of |name| (\S\ref{subsec:remember}). The % conditional \myhlc|\@@_seq_if_exist:nTF| tests if any of the two % \emph{sequences} named by |#1| exists, the function % \myhlc|\@@_seq_count:n| returns the larger number of % \mymeta{stored contents} of the two, or |0| if none exists, and the % function \myhlc|\@@_seq_item:nn| returns the \mymeta{stored content} % at the \mymeta{index} passed in |#2|, from the previous compilation % if it has it and from the current one otherwise. Without % \mykey{remember}, and always in \hologo{plainTeX} and % \hologo{ConTeXt}, only the current \emph{sequence} exists. % \begin{macrocode} \prg_new_conditional:Npnn \@@_seq_if_exist:n #1 { TF } { \bool_lazy_or:nnTF { \seq_if_exist_p:c { g_@@_name_#1_seq } } { \seq_if_exist_p:c { g_@@_prev_#1_seq } } { \prg_return_true: } { \prg_return_false: } } \cs_new:Npn \@@_seq_count:n #1 { \int_max:nn { \seq_if_exist:cTF { g_@@_name_#1_seq } { \seq_count:c { g_@@_name_#1_seq } } { 0 } } { \seq_if_exist:cTF { g_@@_prev_#1_seq } { \seq_count:c { g_@@_prev_#1_seq } } { 0 } } } \cs_new:Npn \@@_seq_item:nn #1 #2 { \bool_lazy_and:nnTF { \seq_if_exist_p:c { g_@@_prev_#1_seq } } { \int_compare_p:nNn { \int_abs:n {#2} } < { \seq_count:c { g_@@_prev_#1_seq } + 1 } } { \seq_item:cn { g_@@_prev_#1_seq } {#2} } { \seq_item:cn { g_@@_name_#1_seq } {#2} } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[int] % { % \@@_getfrom_seq:Nn, % \@@_getfrom_seq:nNn, % \@@_getfrom_seq_aux:nnn, % \@@_getfrom_seq:nn, % \@@_getfrom_seq:nnn, % } % The function \myhlc|\@@_getfrom_seq:Nn| retrieves the % \mymeta{stored contents} whose \mymeta{indexes} are in the sequence % passed in |#1| from the \emph{sequence} named by |#2| and the function % \myhlc|\@@_getfrom_seq:nn| retrieves the one whose \mymeta{index} is % passed in |#1|, both with \myhlc|\@@_seq_item:nn|. Both raise the % \enquote{errors} |undefined-storage| and |index-out-of-range| % (\S\ref{subsec:general-messages}). % \begin{macrocode} \cs_new:Npn \@@_getfrom_seq:Nn #1 #2 { \@@_seq_if_exist:nTF {#2} { \exp_args:Nf \@@_getfrom_seq:nNn { \@@_seq_count:n {#2} } #1 {#2} } { \msg_expandable_error:nnn { scontents } { undefined-storage } {#2} } } \cs_new:Npn \@@_getfrom_seq:nNn #1 #2 #3 { \seq_map_tokens:Nn #2 { \@@_getfrom_seq_aux:nnn {#1} {#3} } } \cs_new:Npn \@@_getfrom_seq_aux:nnn #1 #2 #3 { \exp_args:Nnf \use:n { \@@_getfrom_seq:nnn {#1} } { \int_eval:n {#3} } {#2} } \cs_new:Npn \@@_getfrom_seq:nn #1 #2 { \@@_seq_if_exist:nTF {#2} { \exp_args:Nf \@@_getfrom_seq:nnn { \@@_seq_count:n {#2} } {#1} {#2} } { \msg_expandable_error:nnn { scontents } { undefined-storage } {#2} } } \cs_new:Npn \@@_getfrom_seq:nnn #1 #2 #3 { \bool_lazy_or:nnTF { \int_compare_p:nNn {#2} = { 0 } } { \int_compare_p:nNn { \int_abs:n {#2} } > {#1} } { \msg_expandable_error:nnnnn { scontents } { index-out-of-range } {#2} {#3} {#1} } { \@@_seq_item:nn {#3} {#2} } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_lastfrom_seq:n, \@@_lastfrom_seq:V} % The function \myhlc|\@@_lastfrom_seq:n| saves the last % \mymeta{stored content} of the \emph{sequence} named by |#1| in % \myhlc|\g_@@_last_stored_tl| and rescans it with % \myhlc|\tl_retokenize:V| after the group, when the keys % \mykey{print-env} or \mykey{print-cmd} are active. % \begin{macrocode} \cs_new_protected:Npn \@@_lastfrom_seq:n #1 { \tl_gset:Ne \g_@@_last_stored_tl { \seq_item:cn { g_@@_name_#1_seq } { -1 } } \group_insert_after:N \tl_retokenize:V \group_insert_after:N \g_@@_last_stored_tl \group_insert_after:N \tl_gclear:N \group_insert_after:N \g_@@_last_stored_tl } \cs_generate_variant:Nn \@@_lastfrom_seq:n { V } % % \end{macrocode} % \end{macro} % % \subsection{Remembering contents between compilations}\label{subsec:remember} % % The \mykey{remember} key (\S\ref{key:package}) makes the % \mymeta{stored contents} of some \emph{sequences} available before they % are stored, as |\label| and |\ref| do with the references. At the end % of the document the \mymeta{stored contents} of these \emph{sequences} % are written to the file |\jobname.sct| and at the beginning of % the next compilation they are read in a second \emph{sequence}, that % is used by \myhlc|\@@_seq_item:nn| (\S\ref{fun:sequences}). Each line % of the file has the name of the \emph{sequence} and one % \mymeta{stored content}, both converted to hexadecimal digits and % separated by `|=|', so that any character can be written and read % again. This is only available in \hologo{LaTeX}. % % \subsubsection{Definition of variables for remembering contents} % % \begin{macro}[int]{\g_@@_remember_seq, \g_@@_remember_pending_bool} % The global \emph{sequence} \myhlc|\g_@@_remember_seq| stores, as % strings, the names of the \emph{sequences} set by the % \mykey{remember} key and the boolean % \myhlc|\g_@@_remember_pending_bool| is true when a % \mymeta{stored content} of one of them is requested and it is not % available yet. % \begin{macrocode} %<*core> \seq_new:N \g_@@_remember_seq \bool_new:N \g_@@_remember_pending_bool % % \end{macrocode} % \end{macro} % % \begin{macro}[int] % { % \g_@@_remember_ior, % \g_@@_remember_iow, % \g_@@_remember_old_str, % \l_@@_remember_new_str, % \l_@@_remember_name_str, % \l_@@_remember_item_str, % } % The streams \myhlc|\g_@@_remember_ior| and \myhlc|\g_@@_remember_iow| % read and write the file |\jobname.sct|. The string % \myhlc|\g_@@_remember_old_str| saves the lines read from the file and % \myhlc|\l_@@_remember_new_str| the lines written, to compare them at % the end of the document, and the strings % \myhlc|\l_@@_remember_name_str| and \myhlc|\l_@@_remember_item_str| % save the name of the \emph{sequence} and the \mymeta{stored content} % of a line. % \begin{macrocode} %<*latex> \ior_new:N \g_@@_remember_ior \iow_new:N \g_@@_remember_iow \str_new:N \g_@@_remember_old_str \str_new:N \l_@@_remember_new_str \str_new:N \l_@@_remember_name_str \str_new:N \l_@@_remember_item_str % % \end{macrocode} % \end{macro} % % \subsubsection{Definition of error messages for remembering contents} % % \begin{macro}[int]{remember-latex-only} % The \enquote{error} |remember-latex-only| is raised when the % \mykey{remember} key is used in \hologo{plainTeX} or \hologo{ConTeXt}. % \begin{macrocode} %<*core> \msg_new:nnnn { scontents } { remember-latex-only } { The~key~'remember'~is~only~available~in~LaTeX~\msg_line_context:. } { The~stored~contents~can~only~be~used~after~they~are~stored~ in~this~format.~The~key~is~ignored. } % % \end{macrocode} % \end{macro} % % \subsubsection{Definition of messages for remembering contents} % % \begin{macro}[int]{remember-rerun, remember-undefined} % The \enquote{warning} |remember-rerun| is issued at the end of the % document when the lines written to |\jobname.sct| are not the % ones read from it, and otherwise the \enquote{warning} % |remember-undefined| when a \mymeta{stored content} was requested and % it was not available. % \begin{macrocode} %<*latex> \msg_new:nnn { scontents } { remember-rerun } { Stored~contents~may~have~changed.~Rerun~to~get~them~right. } \msg_new:nnn { scontents } { remember-undefined } { There~were~undefined~stored~contents. } % % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for remembering contents} % % \begin{macro}[int]{\@@_remember:n} % The function \myhlc|\@@_remember:n|, used by the \mykey{remember} % key, adds each name of the comma separated list passed in |#1| to % \myhlc|\g_@@_remember_seq| as a string, only once. In % \hologo{plainTeX} and \hologo{ConTeXt} it raises the % \enquote{error} |remember-latex-only|. % \begin{macrocode} %<*core> \cs_new_protected:Npn \@@_remember:n #1 { \@@_format_case:nnn { \clist_map_inline:nn {#1} { \seq_if_in:NeF \g_@@_remember_seq { \tl_to_str:n {##1} } { \seq_gput_right:Ne \g_@@_remember_seq { \tl_to_str:n {##1} } } } } { \msg_error:nn { scontents } { remember-latex-only } } { \msg_error:nn { scontents } { remember-latex-only } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int,TF]{\@@_if_pending:n} % \begin{macro}[int]{\@@_if_pending:neF} % The conditionals \myhlc|\@@_if_pending:nnT| and % \myhlc|\@@_if_pending:nnF| test if the \mymeta{stored content} at the % \mymeta{index} passed in |#2| of the remembered \emph{sequence} named % by |#1| is not available yet, that is, if its absolute value is % greater than the number of \mymeta{stored contents} of both copies. In % that case \myhlc|\g_@@_remember_pending_bool| is set to true and the % commands print nothing. For the \emph{sequences} that are not % remembered it is always false and the \enquote{errors} of the commands % are raised as usual. % \begin{macrocode} \prg_new_protected_conditional:Npnn \@@_if_pending:nn #1 #2 { T, F } { \bool_lazy_and:nnTF { \seq_if_exist_p:c { g_@@_prev_#1_seq } } { \int_compare_p:nNn { \int_abs:n {#2} } > { \@@_seq_count:n {#1} } } { \bool_gset_true:N \g_@@_remember_pending_bool \prg_return_true: } { \prg_return_false: } } \prg_generate_conditional_variant:Nnn \@@_if_pending:nn { ne } { F } % % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[int] % { % \@@_remember_read:, % \@@_remember_read_line:n, % \@@_remember_read_line:w, % } % The function \myhlc|\@@_remember_read:| reads the file % |\jobname.sct|, if it exists, line by line with % \myhlc|\@@_remember_read_line:n|, and creates an empty copy of the % remembered \emph{sequences} that are not in the file. The function % \myhlc|\@@_remember_read_line:w| converts the name of the % \emph{sequence} from hexadecimal digits and, if it is remembered, % saves the line in \myhlc|\g_@@_remember_old_str| and adds the % \mymeta{stored content}, converted from hexadecimal digits, to the % copy of the previous compilation. The lines of the % \emph{sequences} that are no longer remembered are ignored. % \begin{macrocode} %<*latex> \cs_new_protected:Npn \@@_remember_read: { \ior_open:NnT \g_@@_remember_ior { \c_sys_jobname_str .sct } { \ior_str_map_inline:Nn \g_@@_remember_ior { \@@_remember_read_line:n {##1} } \ior_close:N \g_@@_remember_ior } \seq_map_inline:Nn \g_@@_remember_seq { \seq_if_exist:cF { g_@@_prev_##1_seq } { \seq_new:c { g_@@_prev_##1_seq } } } } \cs_new_protected:Npn \@@_remember_read_line:n #1 { \str_if_empty:nF {#1} { \@@_remember_read_line:w #1 = = \s_@@_stop } } \cs_new_protected:Npn \@@_remember_read_line:w #1 = #2 = #3 \s_@@_stop { \str_set_convert:Nnnn \l_@@_remember_name_str {#1} { utf8/hex } { } \seq_if_in:NVT \g_@@_remember_seq \l_@@_remember_name_str { \str_gput_right:Nn \g_@@_remember_old_str { #1 = #2 , } \str_set_convert:Nnnn \l_@@_remember_item_str {#2} { utf8/hex } { } \seq_if_exist:cF { g_@@_prev_ \l_@@_remember_name_str _seq } { \seq_new:c { g_@@_prev_ \l_@@_remember_name_str _seq } } \seq_gput_right:cV { g_@@_prev_ \l_@@_remember_name_str _seq } \l_@@_remember_item_str } } % \end{macrocode} % \end{macro} % % \begin{macro}[int] % { % \@@_remember_write:, % \@@_remember_write_seq:n, % \@@_remember_write_item:n, % } % The function \myhlc|\@@_remember_write:| writes the file % |\jobname.sct| if some \emph{sequence} is remembered: for each % one that exists, \myhlc|\@@_remember_write_seq:n| converts its name % to hexadecimal digits and \myhlc|\@@_remember_write_item:n| writes a % line for each \mymeta{stored content}, also saved in % \myhlc|\l_@@_remember_new_str|. If the lines written are not the ones % read, the \enquote{warning} |remember-rerun| is issued, otherwise % |remember-undefined| if a \mymeta{stored content} was not available. % \begin{macrocode} \cs_new_protected:Npn \@@_remember_write: { \seq_if_empty:NF \g_@@_remember_seq { \str_clear:N \l_@@_remember_new_str \iow_open:Nn \g_@@_remember_iow { \c_sys_jobname_str .sct } \seq_map_function:NN \g_@@_remember_seq \@@_remember_write_seq:n \iow_close:N \g_@@_remember_iow \str_if_eq:NNTF \g_@@_remember_old_str \l_@@_remember_new_str { \bool_if:NT \g_@@_remember_pending_bool { \msg_warning:nn { scontents } { remember-undefined } } } { \msg_warning:nn { scontents } { remember-rerun } } } } \cs_new_protected:Npn \@@_remember_write_seq:n #1 { \seq_if_exist:cT { g_@@_name_#1_seq } { \str_set_convert:Nnnn \l_@@_remember_name_str {#1} { } { utf8/hex } \seq_map_function:cN { g_@@_name_#1_seq } \@@_remember_write_item:n } } \cs_new_protected:Npn \@@_remember_write_item:n #1 { \str_set_convert:Nnnn \l_@@_remember_item_str {#1} { } { utf8/hex } \iow_now:Ne \g_@@_remember_iow { \l_@@_remember_name_str = \l_@@_remember_item_str } \str_put_right:Ne \l_@@_remember_new_str { \l_@@_remember_name_str = \l_@@_remember_item_str , } } % \end{macrocode} % \end{macro} % % The file is read at the beginning of the document and written at the % end of it. % \begin{macrocode} \hook_gput_code:nnn { begindocument } { scontents } { \@@_remember_read: } \hook_gput_code:nnn { enddocument } { scontents } { \@@_remember_write: } % % \end{macrocode} % % \subsection{The command \cs{newenvsc}}\label{cmd:newenvsc} % % The user-level command |\newenvsc| creates a new environment with the % same behavior as the base environment |scontents|, which is itself % defined with |\newenvsc| (\S\ref{env:scontents}). It takes a mandatory % argument, the \mymarg{env name}, and an optional argument with the % \mymeta{initial keys}. The references to |\begin{scontents}| or % |\end{scontents}| in this section apply to any environment defined % with |\newenvsc|. % % \subsubsection{Definition of variables for \cs[no-index]{newenvsc}} % % \begin{macro}[int] % { % \l_@@_save_every_body_lines_tl, % \l_@@_processed_body_lines_tl, % \l_@@_environment_keys_tl, % \l_@@_nesting_env_int, % \l_@@_nesting_aux_int, % } % The token list \myhlc|\l_@@_save_every_body_lines_tl| holds the % \mymarg{body env} of the environment while it is being read and the % token list \myhlc|\l_@@_processed_body_lines_tl| saves it once the % environment is closed. The token list % \myhlc|\l_@@_environment_keys_tl| saves the \mymeta{keys} passed to the % \emph{optional argument} and the integer variables % \myhlc|\l_@@_nesting_env_int| and \myhlc|\l_@@_nesting_aux_int| are % used to analyze the nesting of the environment. % \begin{macrocode} %<*core> \tl_new:N \l_@@_save_every_body_lines_tl \tl_new:N \l_@@_processed_body_lines_tl \tl_new:N \l_@@_environment_keys_tl \int_new:N \l_@@_nesting_env_int \int_new:N \l_@@_nesting_aux_int % \end{macrocode} % \end{macro} % % \subsubsection{Definition of error messages for \cs[no-index]{newenvsc}} % % \begin{macro}[int]{\@@_env_begin_str:n, \@@_env_end_str:n} % The functions \myhlc|\@@_env_begin_str:n| and % \myhlc|\@@_env_end_str:n| return the start and the end of the % environment named by |#1| as they are written in each format: % |\begin{#1}| and |\end{#1}| in \LaTeX, |\#1| and |\end#1| in % \hologo{plainTeX} and |\start#1| and |\stop#1| in \hologo{ConTeXt}. % They are used in the messages of the environments. % \begin{macrocode} \cs_new:Npn \@@_env_begin_str:n #1 { \@@_format_case:nnn { \c_backslash_str begin \c_left_brace_str #1 \c_right_brace_str } { \c_backslash_str #1 } { \c_backslash_str start #1 } } \cs_new:Npn \@@_env_end_str:n #1 { \@@_format_case:nnn { \c_backslash_str end \c_left_brace_str #1 \c_right_brace_str } { \c_backslash_str end #1 } { \c_backslash_str stop #1 } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{junk-after-begin, env-already-defined} % The \enquote{error} |junk-after-begin| is raised when there are % characters after the start of the environment or its % \emph{optional argument} on the same line and the \enquote{error} % |env-already-defined| is % raised when |\newenvsc| is used with the name of an environment that % already exists. % \begin{macrocode} \msg_new:nnnn { scontents } { junk-after-begin } { Junk~characters~#1~\msg_line_context: : \\ \\ #2 } { Nothing~is~allowed~after~the~start~of~the~environment~on~the~same~ line.~These~characters~are~ignored. } \msg_new:nnnn { scontents } { env-already-defined } { Environment~'#1'~already~defined! } { You~have~used~\token_to_str:N \newenvsc \c_space_tl with~an~environment~that~already~has~a~definition. \\ \\ The~existing~definition~of~'#1'~will~not~be~altered. } % \end{macrocode} % \end{macro} % % \subsubsection{Definition of messages for \cs[no-index]{newenvsc}} % % \begin{macro}[int]{empty-environment, rescanning-text, multiple-begin} % The \enquote{warning} |empty-environment| is issued when the % environment is empty, the \enquote{warning} |rescanning-text| when % there are characters after the end of the environment on the same line % and the \enquote{warning} |multiple-begin| when the environment starts % more than once on the same line. The start and the end of the % environment are written with \myhlc|\@@_env_begin_str:n| and % \myhlc|\@@_env_end_str:n|. % \begin{macrocode} \msg_new:nnn { scontents } { empty-environment } { Environment~'#1'~is~empty~\msg_line_context:. } \msg_new:nnn { scontents } { rescanning-text } { Rescanning~text~'#1'~after~\@@_env_end_str:n {#2}~ \msg_line_context:. } \msg_new:nnn { scontents } { multiple-begin } { Multiple~\@@_env_begin_str:n { \l_@@_env_name_tl }~ \msg_line_context:. } % \end{macrocode} % \end{macro} % % \subsubsection{Definition of keys for \cs[no-index]{newenvsc}}\label{key:newenvsc} % % \begin{macro}[int] % { % write-env, % write-out, % print-env, % store-env, % force-eol, % overwrite, % unknown, % } % We define the \mymeta{keys} for the environments defined by % |\newenvsc|, the unknown \mymeta{keys} are passed to % \myhlc|\@@_unknown_keys_env:n| (\S\ref{key:unknown-keys}). % \begin{macrocode} \keys_define:nn { scontents / scontents } { write-env .code:n = { \@@_set_write_store:n {#1} }, write-out .code:n = { \@@_set_write_out:n {#1} }, write-env .value_required:n = true, write-out .value_required:n = true, print-env .meta:nn = { scontents } { print-env = #1 }, print-env .default:n = true, store-env .meta:nn = { scontents } { store-env = #1 }, force-eol .meta:nn = { scontents } { force-eol = #1 }, force-eol .default:n = true, overwrite .meta:nn = { scontents } { overwrite = #1 }, overwrite .default:n = true, unknown .code:n = { \@@_unknown_keys_env:n {#1} }, } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for \cs[no-index]{newenvsc}}\label{fun:newenvsc} % % \begin{macro}[int]{\@@_grab_opt_arg:w, \@@_grab_opt_arg:n} % The function \myhlc|\@@_grab_opt_arg:w| is called with the tokens % following |\begin{scontents}| when the next character is a `|[|'. It % is defined with \mypkg{ltcmd}\cite{latex2e} to use its delimited % argument processor. % \begin{macrocode} \NewDocumentCommand \@@_grab_opt_arg:w { r[] } { \@@_grab_opt_arg:n {#1} } % \end{macrocode} % The function \myhlc|\@@_grab_opt_arg:n| is called where `\myhlc|^^M|' is % active, so \myhlc|\@@_normalise_line_ends:N| replaces the active % `\myhlc|^^M|' characters by spaces before setting the \mymeta{keys}. % \begin{macrocode} \cs_new_protected:Npn \@@_grab_opt_arg:n #1 { \tl_set:Nn \l_@@_environment_keys_tl {#1} \@@_normalise_line_ends:N \l_@@_environment_keys_tl \keys_set:nV { scontents / scontents } \l_@@_environment_keys_tl \@@_start_after_option:w } % \end{macrocode} % \end{macro} % % \begin{macro}[int] % { % \@@_normalise_line_ends:N, % \@@_start_environment:w, % \@@_start_after_option:w, % \@@_check_line_process:nn, % \@@_stop_environment:, % } % Here `\myhlc|^^I|', `\myhlc|^^L|' and `\myhlc|^^M|' are active characters, so that the % end of line can be used as a delimiter and \hologo{TeX} does not % remove the space-like characters. % % The function \myhlc|\@@_start_environment:w| checks if the next token % after |\begin{scontents}| is a `|[|', in that case % \myhlc|\@@_grab_opt_arg:w| processes the \emph{optional argument} and % calls \myhlc|\@@_start_after_option:w|. In all cases the function % \myhlc|\@@_check_line_process:nn| raises the \enquote{error} % |junk-after-begin| if there is something else on the line and then % calls \myhlc|\@@_file_tl_write_start:V|, which reads the content of % the environment and stores it in a token list or writes it to an % \mymeta{external file}. % % At the end of the environment, the function % \myhlc|\@@_stop_environment:| calls \myhlc|\@@_file_write_stop:N| and % issues the \enquote{warning} |empty-environment| if nothing was % stored. This part of the code is adapted from the code of the package % \mypkg{xsim}\cite{xsim} by Clemens Niederberger. % \begin{macrocode} \group_begin: \char_set_catcode_active:N \^^I \char_set_catcode_active:N \^^L \char_set_catcode_active:N \^^M \cs_new_protected:Npn \@@_normalise_line_ends:N #1 { \tl_replace_all:Nnn #1 { ^^M } { ~ } } \cs_new_protected:Npn \@@_start_environment:w #1 ^^M { \tl_if_head_is_N_type:nTF {#1} { \str_if_eq:eeTF { \tl_head:n {#1} } { [ } { \@@_grab_opt_arg:w #1 ^^M } { \@@_check_line_process:nn { } {#1} } } { \@@_check_line_process:nn { } {#1} } } \cs_new_protected:Npn \@@_start_after_option:w #1 ^^M { \@@_check_line_process:nn { [...] } {#1} } \cs_new_protected:Npn \@@_check_line_process:nn #1 #2 { \tl_if_blank:nF {#2} { \msg_error:nnee { scontents } { junk-after-begin } { after~ \@@_env_begin_str:n { \l_@@_env_name_tl } #1 } {#2} } \@@_make_control_chars_active: \@@_file_tl_write_start:V \l_@@_file_name_tl } \cs_new_protected:Nn \@@_stop_environment: { \@@_file_write_stop:N \l_@@_processed_body_lines_tl \bool_lazy_and:nnT { \l_@@_storing_bool } { \tl_if_empty_p:N \l_@@_processed_body_lines_tl } { \msg_warning:nne { scontents } { empty-environment } { \l_@@_env_name_tl } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int] % { % \@@_file_tl_write_start:n, % \@@_file_tl_write_start:V, % \@@_setup_verb_processor:, % \@@_verb_processor_iterate:w, % \@@_verb_processor_iterate:nnn, % \@@_env_end_function:, % \@@_file_write_stop:N, % \@@_remove_leading_nl:n, % \@@_remove_leading_nl:nn, % \@@_remove_leading_nl:w, % } % This is the main function to collect the \mymarg{body env} of the % environment. The function \myhlc|\@@_file_tl_write_start:n| starts a % \emph{group}, opens the \mymeta{output file} if necessary, sets the % \emph{verbatim catcodes} and then issues `\myhlc|^^M|', set equal to % \myhlc|\@@_ret:w|, to read the \mymarg{body env} line by line until % its end. Each line read is appended to the output token list after an % active `\myhlc|^^J|' and written to the \mymeta{output file}, if any. % % The function \myhlc|\@@_setup_verb_processor:| defines % \myhlc|\@@_verb_processor_iterate:w|, delimited by the end of the % current environment, and \myhlc|\@@_verb_processor_iterate:nnn| % decides if the line is a nested |\end{scontents}| or the end of the % environment, in which case \myhlc|\@@_env_end_function:| leaves the % closing command for the current format and the characters after it % are rescanned with the \enquote{warning} |rescanning-text|. % % At the end of the environment, the function % \myhlc|\@@_file_write_stop:N| closes the \mymeta{output file}, if it % was opened, and smuggles the output token list out of the group. The % leading `\myhlc|^^J|' is removed with \myhlc|\@@_remove_leading_nl:n|, which % expects an active `\myhlc|^^J|' at the head of the token list, otherwise a % low level \hologo{TeX} \enquote{error} is raised. % \begin{macrocode} \cs_new_protected:Npn \@@_file_tl_write_start:n #1 { \group_begin: \@@_file_if_writable:nTF {#1} { \bool_set_true:N \l_@@_writable_bool \iow_open:Nn \l_@@_file_write_iow {#1} } { \bool_set_false:N \l_@@_writable_bool } \tl_clear:N \l_@@_save_every_body_lines_tl \seq_map_function:NN \l_char_special_seq \char_set_catcode_other:N \int_step_function:nnnN { 128 } { 1 } { 255 } \char_set_catcode_letter:n \cs_set_protected:Npe \@@_ret:w ##1 ^^M { \exp_not:N \@@_verb_processor_iterate:w ##1 \c_@@_end_env_tl \c_@@_end_env_tl \exp_not:N \q_@@_stop } \@@_make_control_chars_active: \@@_ret:w } \cs_new_protected:Nn \@@_setup_verb_processor: { \use:e { \cs_set_protected:Npn \exp_not:N \@@_verb_processor_iterate:w ##1 \c_@@_end_env_tl ##2 \c_@@_end_env_tl ##3 \exp_not:N \q_@@_stop } { \@@_verb_processor_iterate:nnn {##1} {##2} {##3} } } \cs_new_protected:Npn \@@_verb_processor_iterate:nnn #1 #2 #3 { \tl_if_blank:nTF {#3} { \@@_analyse_nesting:n {#1} \@@_verb_processor_output:n {#1} } { \@@_if_nested:TF { \@@_nesting_decr: \@@_verb_processor_output:e { \exp_not:n {#1} \c_@@_end_env_tl \exp_not:n {#2} } } { \tl_if_blank:nF {#1} { \@@_verb_processor_output:n {#1} } \cs_set_protected:Npe \@@_ret:w { \@@_env_end_function: \bool_lazy_or:nnF { \tl_if_blank_p:n {#2} } { \str_if_eq_p:ee {#2} { \c_percent_str } } { \str_if_eq:VnF \c_@@_hidden_space_str {#2} { \msg_warning:nnnn { scontents } { rescanning-text } {#2} { \tl_use:N \l_@@_env_name_tl } } \tl_retokenize:n {#2} } } \char_set_active_eq:NN ^^M \@@_ret:w } } ^^M } \cs_new:Nn \@@_env_end_function: { \@@_format_case:nnn { \exp_not:N \end { \if_false: } \fi: } { \exp_after:w \exp_not:N \cs:w end } { \exp_after:w \exp_not:N \cs:w stop } \tl_use:N \l_@@_env_name_tl \@@_format_case:nnn { \if_false: { \fi: } } { \cs_end: } { \cs_end: } } \cs_new_protected:Npn \@@_file_write_stop:N #1 { \bool_if:NT \l_@@_writable_bool { \iow_close:N \l_@@_file_write_iow } \use:e { \group_end: \bool_if:NT \l_@@_storing_bool { \tl_set:Nn \exp_not:N #1 { \exp_args:NV \@@_remove_leading_nl:n \l_@@_save_every_body_lines_tl } } } } \cs_new:Npn \@@_remove_leading_nl:n #1 { \tl_if_head_is_N_type:nTF {#1} { \exp_args:Nf \@@_remove_leading_nl:nn { \tl_head:n {#1} } {#1} } { \exp_not:n {#1} } } \cs_new:Npn \@@_remove_leading_nl:nn #1 #2 { \token_if_eq_meaning:NNTF ^^J #1 { \exp_not:o { \@@_remove_leading_nl:w #2 } } { \exp_not:n {#2} } } \cs_new:Npn \@@_remove_leading_nl:w ^^J { } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_verb_processor_output:n, \@@_verb_processor_output:e} % The function \myhlc|\@@_verb_processor_output:n| does the output of % each line read, to the token list and to the \mymeta{output file}, % according to the booleans \myhlc|\l_@@_writable_bool| and % \myhlc|\l_@@_storing_bool|. % \begin{macrocode} \cs_new_protected:Npn \@@_verb_processor_output:n #1 { \bool_if:NT \l_@@_writable_bool { \iow_now:Nn \l_@@_file_write_iow {#1} } \bool_if:NT \l_@@_storing_bool { \tl_put_right:Nn \l_@@_save_every_body_lines_tl { ^^J #1 } } } \group_end: \cs_generate_variant:Nn \@@_verb_processor_output:n { e } \cs_generate_variant:Nn \@@_file_tl_write_start:n { V } % \end{macrocode} % \end{macro} % % \begin{macro}[int] % { % \@@_analyse_nesting:n, % \@@_nesting_incr:, % \@@_nesting_decr:, % } % \begin{macro}[int,TF]{\@@_if_nested:} % The function \myhlc|\@@_analyse_nesting:n| scans the nested % |\begin{scontents}| in a line and steps the counter % \myhlc|\l_@@_nesting_env_int|, issuing the \enquote{warning} % |multiple-begin| if there is more than one. The conditional % \myhlc|\@@_if_nested:TF| tests if we are in a nested environment and % \myhlc|\@@_nesting_decr:| reduces the nesting level when an % |\end{scontents}| is found. % \begin{macrocode} \cs_new_protected:Npn \@@_analyse_nesting:n #1 { \int_zero:N \l_@@_nesting_aux_int \@@_analyse_nesting_format:n {#1} \int_compare:nNnT { \l_@@_nesting_aux_int } > { 1 } { \msg_warning:nn { scontents } { multiple-begin } } } \cs_new_protected:Nn \@@_nesting_incr: { \int_incr:N \l_@@_nesting_env_int \int_incr:N \l_@@_nesting_aux_int } \cs_new_protected:Nn \@@_nesting_decr: { \int_decr:N \l_@@_nesting_env_int } \prg_new_protected_conditional:Npnn \@@_if_nested: { TF } { \int_compare:nNnTF { \l_@@_nesting_env_int } > { \c_zero_int } { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{important}* % Multiple |\end{scontents}| on the same line are NOT supported. % \end{important} % % \begin{macro}[int] % { % \@@_analyse_nesting_latex:n, % \@@_analyse_nesting_latex:w, % \@@_analyse_nesting_generic:nn, % \@@_analyse_nesting_generic:w, % \@@_analyse_nesting_generic_process:nn, % \@@_define_generic_nesting_function:n, % \@@_analyse_nesting_format:n, % } % In \LaTeX{} the environments start with |\begin{}| and no `|}|' % can appear inside ||, so a macro delimited by `|}|' is enough to % find the nested |\begin{scontents}|. % \begin{macrocode} \use:e { \cs_new_protected:Npn \exp_not:N \@@_analyse_nesting_latex:w #1 \c_backslash_str begin \c_left_brace_str #2 \c_right_brace_str } { \@@_tl_if_head_is_q_mark:nTF {#2} { \@@_use_none_delimit_by_q_stop:w } { \str_if_eq:VnT \l_@@_env_name_tl {#2} { \@@_nesting_incr: } \@@_analyse_nesting_latex:w } } \cs_new_protected:Npe \@@_analyse_nesting_latex:n #1 { \@@_analyse_nesting_latex:w #1 \c_backslash_str begin \c_left_brace_str \exp_not:N \q_@@_mark \c_right_brace_str \exp_not:N \q_@@_stop } % \end{macrocode} % In the other formats there is no \enquote{end anchor} to delimit the % name of the environment, so we search for the whole command that % starts the environment, |\scontents| or |\startscontents|. % \begin{macrocode} \cs_new_protected:Npn \@@_analyse_nesting_generic_process:nn #1 #2 { \tl_if_head_is_N_type:nTF {#2} { \@@_tl_if_head_is_q_mark:nF {#2} { \@@_nesting_incr: \@@_analyse_nesting_generic:w #2 \q_@@_stop } } { \@@_analyse_nesting_generic:w #2 \q_@@_stop } } \cs_new_protected:Npn \@@_analyse_nesting_generic:nn #1 #2 { \@@_define_generic_nesting_function:n {#1} \use:e { \exp_not:N \@@_analyse_nesting_generic:w #2 \c_backslash_str #1 \tl_use:N \l_@@_env_name_tl \exp_not:N \q_@@_mark \exp_not:N \q_@@_stop } } \cs_new_protected:Npn \@@_define_generic_nesting_function:n #1 { \use:e { \cs_set_protected:Npn \exp_not:N \@@_analyse_nesting_generic:w ##1 \c_backslash_str #1 \tl_use:N \l_@@_env_name_tl ##2 \exp_not:N \q_@@_stop } { \@@_analyse_nesting_generic_process:nn {##1} {##2} } } % % \end{macrocode} % The function \myhlc|\@@_analyse_nesting_format:n| uses the version % for the current format. % \begin{macrocode} %<*loader> %\cs_new_eq:NN \@@_analyse_nesting_format:n % \@@_analyse_nesting_latex:n %\cs_new_protected:Npn \@@_analyse_nesting_format:n % { \@@_analyse_nesting_generic:nn { } } % { \@@_analyse_nesting_generic:nn { start } } % % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_generic_begin:, \@@_generic_end:} % The function \myhlc|\@@_generic_begin:| leaves the `\myhlc|^^M|' character % active and calls \myhlc|\@@_start_environment:w|. The function % \myhlc|\@@_generic_end:| calls \myhlc|\@@_stop_environment:| and then % \myhlc|\@@_finish_storing:NNN|, which stores the \mymarg{body env} in % the \emph{sequence} and prints it if the \mykey{print-env} key is % active (\S\ref{fun:sequences}). % \begin{macrocode} %<*core> \cs_new_protected:Npn \@@_generic_begin: { \char_set_catcode_active:N \^^M \@@_start_environment:w } \cs_new_protected:Npn \@@_generic_end: { \@@_stop_environment: \@@_finish_storing:NNN \l_@@_processed_body_lines_tl \l_@@_name_seq_env_tl \l_@@_print_env_bool } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_setting_env:nn, \@@_define_env:nnn} % The function \myhlc|\@@_setting_env:nn| receives the \emph{name} of % the environment in |#1| and the \mymeta{initial keys} in |#2|. It % creates the functions \cs[no-index]{@@_\#1_begin:} and % \cs[no-index]{@@_\#1_end:}, which set \myhlc|\l_@@_env_name_tl| and % the \mymeta{initial keys} and call \myhlc|\@@_generic_begin:| and % \myhlc|\@@_generic_end:|, and passes them to % \myhlc|\@@_define_env:nnn|. % \begin{macrocode} \cs_new_protected:Npn \@@_setting_env:nn #1 #2 { \cs_new_protected:cpn { @@_#1_begin: } { \tl_set:Nn \l_@@_env_name_tl {#1} \tl_set:Nn \l_@@_cmd_name_tl { newenvsc } \keys_set:nn { scontents } {#2} \@@_setup_verb_processor: \@@_generic_begin: } \cs_new_protected:cpn { @@_#1_end: } { \@@_generic_end: } \exp_args:Nooo \@@_define_env:nnn { \tl_to_str:n {#1} } { \cs:w @@_#1_begin: \cs_end: } { \cs:w @@_#1_end: \cs_end: } } % % \end{macrocode} % The function \myhlc|\@@_define_env:nnn| creates the environment for % \hologo{LaTeX}, \hologo{plainTeX} and \hologo{ConTeXt}. % \begin{macrocode} %<*loader> \cs_new_protected:Npn \@@_define_env:nnn #1 #2 #3 { % \NewDocumentEnvironment {#1} { } % \cs_new_protected:cpn { start #1 } { % \group_begin: #2 } % \cs_new_protected:cpn { stop #1 } { #3 % \group_end: } } % \end{macrocode} % \end{macro} % % \begin{macro}{\newenvsc} % Defines the user command \ics*{newenvsc} for \hologo{LaTeX}, % \hologo{plainTeX} and \hologo{ConTeXt}, raising the \enquote{error} % |env-already-defined| if the environment exists. % \begin{macrocode} \NewDocumentCommand \newenvsc { m O{} } { % \cs_if_exist:cTF {#1} % \cs_if_exist:cTF { start #1 } { \msg_error:nnn { scontents } { env-already-defined } {#1} } { \@@_setting_env:nn {#1} {#2} } } % % \end{macrocode} % \end{macro} % % \subsection{The environment \env{scontents}}\label{env:scontents} % % \begin{macro} % { % scontents, % \scontents, % \endscontents, % \startscontents, % \stopscontents, % } % The base environment |scontents| is defined with |\newenvsc|, in % \hologo{plainTeX} it is |\scontents|\,\dots\,|\endscontents| and in % \hologo{ConTeXt} |\startscontents|\,\dots\,|\stopscontents|. % \begin{macrocode} %<*loader> \newenvsc{scontents} % % \end{macrocode} % \end{macro} % % \subsection{The environment \env{verbatimsc}}\label{env:verbatimsc} % % The |verbatimsc| environment is a customized version of the standard % \myenv[no-index]{verbatim} environment of \hologo{LaTeX} used by % |\typestored| (\S\ref{cmd:typestored}). For \hologo{plainTeX} and % \hologo{ConTeXt} we must add some additional functions. % % \subsubsection{Definition of variables for \env{verbatimsc}} % % \begin{macro}[int]{\l_@@_plain_bool} % The boolean variable \myhlc|\l_@@_plain_bool| is used in the % \hologo{plainTeX} version of the |verbatimsc| environment. % \begin{macrocode} %<*plain> \bool_new:N \l_@@_plain_bool % % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for \env{verbatimsc}} % % \begin{macro}[int]{\dospecials} % The \myenv[no-index]{verbatim} environment requires % \myhlc|\dospecials|. In case it does not exist when % \mypkg*[no-index]{scontents} is loaded, we define it with % \myhlc|\l_char_special_seq|. % \begin{macrocode} %<*!latex> \cs_if_exist:NF \dospecials { \cs_new:Npn \dospecials { \seq_map_function:NN \l_char_special_seq \do } } % % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_xverb:w, \@@_xverb:} % The environment |verbatimsc| needs to find literally its end, this is % done by \myhlc|\@@_xverb:w|, delimited by % \myhlc|\g_@@_end_verbatimsc_tl|, for \hologo{plainTeX} and \LaTeX. % The function \myhlc|\@@_xverb:| makes the \texttt{TAB} character % active, equal to \myhlc|\@@_tabs_to_spaces:|, and calls % \myhlc|\@@_xverb:w|. % \begin{macrocode} %<*loader> %<*!context> \use:e { \cs_new_protected:Npn \exp_not:N \@@_xverb:w #1 \g_@@_end_verbatimsc_tl % { #1 \exp_not:N \end{verbatimsc} } % { #1 \exp_not:N \endverbatimsc } } % % %<*core> \cs_new_protected:Nn \@@_xverb: { \char_set_catcode_active:n { 9 } \char_set_active_eq:nN { 9 } \@@_tabs_to_spaces: \@@_xverb:w } % % \end{macrocode} % \end{macro} % % \subsubsection{\hologo{plainTeX} version of \texttt{verbatimsc}} % % \begin{macro}[int] % { % \@@_verbatimsc_aux:, % \@@_nolig_list:, % \@@_vobeyspaces:, % \@@_xobeysp:, % } % In \hologo{plainTeX} we emulate the \myenv[no-index]{verbatim} % environment of \LaTeX. % \begin{macrocode} %<*plain> \cs_new_protected:Nn \@@_verbatimsc_aux: { \skip_vertical:N \parskip \dim_zero:N \parindent \skip_set:Nn \parfillskip { 0pt plus 1fil } \skip_set:Nn \parskip { 0pt plus0pt minus0pt } \tex_par:D \bool_set_false:N \l_@@_plain_bool \cs_set:Npn \par { \bool_if:NTF \l_@@_plain_bool { \mode_leave_vertical: \null \tex_par:D \penalty \interlinepenalty } { \bool_set_true:N \l_@@_plain_bool \mode_if_horizontal:T { \tex_par:D \penalty \interlinepenalty } } } \cs_set_eq:NN \do \char_set_catcode_other:N \dospecials \obeylines \tl_use:N \l_@@_verb_font_tl \cs_set_eq:NN \do \@@_do_noligs:N \@@_nolig_list: \tex_everypar:D \exp_after:w { \tex_the:D \tex_everypar:D \tex_unpenalty:D } } \cs_new_protected:Nn \@@_nolig_list: { \do\`\do\<\do\>\do\,\do\'\do\- } \cs_new_protected:Nn \@@_vobeyspaces: { \@@_set_active_eq:NN \ \@@_xobeysp: } \cs_new_protected:Nn \@@_xobeysp: { \mode_leave_vertical: \nobreak \ } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_verbatimsc_line:w} % The function \myhlc|\@@_verbatimsc_line:w| discards the rest of the % line of |\verbatimsc| up to the active end of line. When |\typestored| % rescans the \mymeta{stored content} a space follows |\verbatimsc| and, % once the spaces are active, it would start an empty line at the top of % the environment. % \begin{macrocode} \group_begin: \char_set_catcode_active:N \^^M \cs_new_protected:Npn \@@_verbatimsc_line:w #1 ^^M { \@@_verbatimsc_aux: \frenchspacing \@@_vobeyspaces: \@@_xverb: } \group_end: % \end{macrocode} % \end{macro} % % \begin{macro}{\verbatimsc, \endverbatimsc} % Defines the environment \myenv*{verbatimsc} for \hologo{plainTeX}. % As in the environments of \hologo{ConTeXt}, the rest of the line of % |\verbatimsc| is ignored. % \begin{macrocode} \cs_new_protected:Npn \verbatimsc { \group_begin: \char_set_catcode_active:N \^^M \@@_verbatimsc_line:w } \cs_new_protected:Npn \endverbatimsc { \group_end: } % % \end{macrocode} % \end{macro} % % \subsubsection{\hologo{ConTeXt} version of \texttt{verbatimsc}} % % \begin{macro}{\startverbatimsc, \stopverbatimsc} % In \hologo{ConTeXt} we use its own tool \myhlc|\definetyping|. % \begin{macrocode} %<*loader> %\definetyping[verbatimsc] % % \end{macrocode} % \end{macro} % % \subsubsection{\hologo{LaTeX} version of \texttt{verbatimsc}} % % \begin{macro}[int]{\@@_verbatimsc_instance:} % To be compatible with \emph{tagged} \texttt{PDF} the environment % |verbatimsc| is defined with the \mypkg{xtemplate}\cite{latex2e} % module of the \LaTeX{} kernel and the \texttt{blocks-code} of % \mypkg{latex-lab}\cite{latexlab}. The function % \myhlc|\@@_verbatimsc_instance:| declares the instance of % \texttt{blockenv} used by the environment, only once at the beginning % of the document and only if \emph{tagged} \texttt{PDF} is active. % This code is adapted from the answer of Ulrike Fischer to % \href{https://tex.stackexchange.com/a/741178/7832}{New verbatim environment with block code (tagged-pdf)}. % \begin{macrocode} %<*loader> %<*latex> \cs_new_protected:Nn \@@_verbatimsc_instance: { \DeclareInstance{blockenv}{verbatimsc}{std} { name = verbatimsc, tag-name = \UseStructureName{block/verbatim}, tagging-recipe = standard, tagging-suppress-paras = true, block-instance = verbatim, para-instance = justify, final-code = \legacyverbatimsetup{invisible}, } } \hook_gput_code:nnn { begindocument } { scontents } { \IfDocumentMetadataTF { \@@_verbatimsc_instance: } { } } % \end{macrocode} % \end{macro} % % \begin{macro}{verbatimsc} % Defines the environment \myenv*{verbatimsc} for \LaTeX. The % |\endverbatim| in the second argument is only needed for % compatibility with the \mypkg{verbatim}\cite{verbatim} package. % \begin{macrocode} \NewDocumentEnvironment { verbatimsc } { } { \IfDocumentMetadataTF { \UseInstance{blockenv}{verbatimsc}{} \@setupverbinvisiblespace\frenchspacing\@vobeyspaces \@@_xverb: } { \cs_set_eq:cN { @xverbatim } \@@_xverb: \verbatim } } { \IfDocumentMetadataTF { \BlockEnvEnd } { \endverbatim } } % % % \end{macrocode} % \end{macro} % % \subsection{The command \cs{Scontents}}\label{cmd:Scontents} % % The user-level command |\Scontents| stores its \mymarg{argument} in a % \emph{sequence}. It takes an optional \emph{starred argument}, an % optional argument with the \mymeta{keys} and the \mymarg{argument}, % which is read in standard mode or, with the \emph{starred argument}, % under the \emph{verbatim catcode} regimen. It is adapted from code by % Ulrich Diez in \href{https://tex.stackexchange.com/a/472044/7832}{Stringify % input - \textbackslash string on token list} and code by user % \texttt{@siracusa} in % \href{https://tex.stackexchange.com/a/500281/7832}{Convert a macro from Latex2e to expl3}. % % \subsubsection{Definition of variables for \cs[no-index]{Scontents}} % % \begin{macro}[int]{\l_@@_Scontents_arg_tl} % The token list \myhlc|\l_@@_Scontents_arg_tl| saves the % \mymarg{argument} passed to |\Scontents|. % \begin{macrocode} %<*core> \tl_new:N \l_@@_Scontents_arg_tl % \end{macrocode} % \end{macro} % % \subsubsection{Definition of messages for \cs[no-index]{Scontents}} % % \begin{macro}[int]{empty-argument-command} % The \enquote{warning} |empty-argument-command| is issued when the % \mymarg{argument} of |\Scontents| is empty. % \begin{macrocode} \msg_new:nnn { scontents } { empty-argument-command } { Empty~argument~for~\c_backslash_str Scontents~\msg_line_context:. } % \end{macrocode} % \end{macro} % % \subsubsection{Definition of keys for \cs[no-index]{Scontents}}\label{key:Scontents} % % \begin{macro}[int] % { % write-cmd, % write-out, % print-cmd, % store-cmd, % force-eol, % overwrite, % unknown, % } % We define the \mymeta{keys} for both versions of |\Scontents|, the % unknown \mymeta{keys} are passed to \myhlc|\@@_unknown_keys_cmd:n| % (\S\ref{key:unknown-keys}). % \begin{macrocode} \keys_define:nn { scontents / Scontents } { write-cmd .code:n = { \@@_set_write_store:n {#1} }, write-out .code:n = { \@@_set_write_out:n {#1} }, write-cmd .value_required:n = true, write-out .value_required:n = true, print-cmd .meta:nn = { scontents } { print-cmd = #1 }, print-cmd .default:n = true, store-cmd .meta:nn = { scontents } { store-cmd = #1 }, force-eol .meta:nn = { scontents } { force-eol = #1 }, force-eol .default:n = true, overwrite .meta:nn = { scontents } { overwrite = #1 }, overwrite .default:n = true, unknown .code:n = { \@@_unknown_keys_cmd:n {#1} }, } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for \cs[no-index]{Scontents}} % % \begin{macro}[int]{\@@_Scontents_code:nn} % The function \myhlc|\@@_Scontents_code:nn| executes % \myhlc|\@@_bsphack:|, opens a group, sets the \mymeta{keys} passed in % |#2| and leaves the \texttt{TAB} character active. With the % \emph{starred argument} passed in |#1| it calls % \myhlc|\@@_Scontents_verb_arg:w|, otherwise % \myhlc|\@@_Scontents_norm_arg:n|. % \begin{macrocode} \cs_new_protected:Npn \@@_Scontents_code:nn #1 #2 { \@@_bsphack: \group_begin: \keys_set:nn { scontents / Scontents } {#2} \char_set_catcode_active:n { 9 } \bool_if:NTF #1 { \@@_Scontents_verb_arg:w } { \@@_Scontents_norm_arg:n } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_Scontents_verb_arg:w} % The function \myhlc|\@@_Scontents_verb_arg:w| saves the % \mymarg{argument} under the \emph{verbatim catcode} regimen, using a % |v|-type argument of \mypkg{ltcmd}, in \myhlc|\l_@@_Scontents_arg_tl| % and replaces every `\myhlc|^^M|' and |\obeyedline|, added in \hologo{LaTeX} % release 2024-06-01, by `\myhlc|^^J|'. The command |\obeyedline| is redefined % with |\RenewDocumentCommand| because it can be modified by the user, % which would return a low-level error. % \begin{macrocode} \NewDocumentCommand \@@_Scontents_verb_arg:w { +v } { \tl_set:Nn \l_@@_Scontents_arg_tl {#1} \cs_if_exist:NT \obeyedline { \RenewDocumentCommand \obeyedline { } { \iow_char:N \^^M } \tl_replace_all:Nee \l_@@_Scontents_arg_tl { \obeyedline } { \iow_char:N \^^M } } \tl_replace_all:NeV \l_@@_Scontents_arg_tl { \iow_char:N \^^M } \c_@@_newline_tl \@@_Scontents_finish: } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_Scontents_norm_arg:n} % The function \myhlc|\@@_Scontents_norm_arg:n| saves the % \mymarg{argument} read in the \emph{standard catcode} regimen. % \begin{macrocode} \cs_new_protected:Npn \@@_Scontents_norm_arg:n #1 { \tl_set:Nn \l_@@_Scontents_arg_tl {#1} \@@_Scontents_finish: } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_Scontents_finish:} % The function \myhlc|\@@_Scontents_finish:| issues the % \enquote{warning} |empty-argument-command| if the \mymarg{argument} is % empty, writes it with \myhlc|\@@_file_write_cmd:VV| for the % \mykey{write-out} and \mykey{write-cmd} keys and stores and prints it % with \myhlc|\@@_finish_storing:NNN|. Finally it closes the group and % runs \myhlc|\@@_esphack:| if the \mykey{print-cmd} key is not active. % \begin{macrocode} \cs_new_protected:Nn \@@_Scontents_finish: { \tl_if_empty:NT \l_@@_Scontents_arg_tl { \msg_warning:nn { scontents } { empty-argument-command } } \@@_file_write_cmd:VV \l_@@_file_name_tl \l_@@_Scontents_arg_tl \@@_finish_storing:NNN \l_@@_Scontents_arg_tl \l_@@_name_seq_cmd_tl \l_@@_print_cmd_bool \use:e { \group_end: \bool_if:NF \l_@@_print_cmd_bool { \@@_esphack: } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\Scontents} % Defines the user command \ics*{Scontents}. % \begin{macrocode} \NewDocumentCommand \Scontents { !s !O{} } { \tl_set:Nn \l_@@_cmd_name_tl { Scontents } \@@_Scontents_code:nn {#1} {#2} } % \end{macrocode} % \end{macro} % % \subsection{The command \cs{getstored}}\label{cmd:getstored} % % The user-level command |\getstored| takes an optional argument with the % \mymeta{index}, the last \mymeta{stored content} by default, and a % mandatory argument with the \mymarg{seq name}. It is robust. % % \subsubsection{Internal functions for \cs[no-index]{getstored}} % % \begin{macro}[int]{\@@_getstored:nn} % The function \myhlc|\@@_getstored:nn| rescans with % \myhlc|\tl_retokenize:e| the \mymeta{stored content} at the % \mymeta{index} passed in |#1| in the \emph{sequence} named by |#2|, % given by \myhlc|\@@_getfrom_seq:nn| (\S\ref{fun:sequences}), unless % it is not available yet in a remembered \emph{sequence} % (\S\ref{subsec:remember}). % \begin{macrocode} \cs_new_protected:Npn \@@_getstored:nn #1 #2 { \@@_if_pending:neF {#2} { \int_eval:n {#1} } { \tl_retokenize:e { \@@_getfrom_seq:nn {#1} {#2} } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\getstored} % Defines the user command \ics*{getstored}. % \begin{macrocode} \NewDocumentCommand \getstored { O{-1} m } { \@@_getstored:nn {#1} {#2} } % \end{macrocode} % \end{macro} % % \subsection{The command \cs{foreachsc}}\label{cmd:foreachsc} % % The user-level command |\foreachsc| runs |\getstored| on the % \mymeta{stored contents} of a \emph{sequence}. It takes an optional % argument with the \mymeta{keys} and a mandatory argument with the % \mymarg{seq name}, raising the \enquote{error} |undefined-storage| if % the \emph{sequence} does not exist. % % \subsubsection{Definition of variables for \cs[no-index]{foreachsc}} % % \begin{macro}[int] % { % \l_@@_foreachsc_arg_tl, % \l_@@_foreach_print_seq, % \g_@@_foreach_exec_tl, % \l_@@_foreach_before_tl, % \l_@@_foreach_before_bool, % \l_@@_foreach_after_tl, % \l_@@_foreach_after_bool, % \l_@@_foreach_start_int, % \l_@@_foreach_step_int, % \l_@@_foreach_stop_int, % \l_@@_foreach_stop_bool, % \l_@@_foreach_wrapper_bool, % \l_@@_foreach_body_tl, % \l_@@_foreach_cmd_tl, % } % The token list \myhlc|\l_@@_foreachsc_arg_tl| saves the % \mymarg{seq name}, the sequence \myhlc|\l_@@_foreach_print_seq| % collects the code for each \mymeta{stored content}, built in the token % list \myhlc|\l_@@_foreach_body_tl|, and the token list % \myhlc|\g_@@_foreach_exec_tl| executes it outside the group. The % token list \myhlc|\l_@@_foreach_cmd_tl| saves the command executed on % each \mymeta{stored content}, |\getstored| by default. The other % variables are set by the \mymeta{keys} of |\foreachsc|. % \begin{macrocode} \tl_new:N \l_@@_foreachsc_arg_tl \seq_new:N \l_@@_foreach_print_seq \tl_new:N \g_@@_foreach_exec_tl \tl_new:N \l_@@_foreach_before_tl \bool_new:N \l_@@_foreach_before_bool \tl_new:N \l_@@_foreach_after_tl \bool_new:N \l_@@_foreach_after_bool \int_new:N \l_@@_foreach_start_int \int_new:N \l_@@_foreach_step_int \int_new:N \l_@@_foreach_stop_int \bool_new:N \l_@@_foreach_stop_bool \bool_new:N \l_@@_foreach_wrapper_bool \tl_new:N \l_@@_foreach_body_tl \tl_new:N \l_@@_foreach_cmd_tl \tl_set:Nn \l_@@_foreach_cmd_tl { \getstored } % \end{macrocode} % \end{macro} % % \subsubsection{Definition of keys for \cs[no-index]{foreachsc}}\label{key:foreachsc} % % \begin{macro}[int] % { % before, % after, % start, % stop, % step, % wrapper, % sep, % unknown, % } % We define the \mymeta{keys} for |\foreachsc|, the keys \mykey{start}, % \mykey{step} and \mykey{stop} use \myhlc|\@@_set_positive_int:Nnn| % (\S\ref{key:package}) and the unknown \mymeta{keys} are passed to % \myhlc|\@@_unknown_keys_cmd:n| (\S\ref{key:unknown-keys}). % \begin{macrocode} \keys_define:nn { scontents / foreachsc } { before .code:n = { \bool_set_true:N \l_@@_foreach_before_bool \tl_set:Nn \l_@@_foreach_before_tl {#1} }, before .value_required:n = true, after .code:n = { \bool_set_true:N \l_@@_foreach_after_bool \tl_set:Nn \l_@@_foreach_after_tl {#1} }, after .value_required:n = true, start .code:n = { \@@_set_positive_int:Nnn \l_@@_foreach_start_int { start } {#1} }, start .value_required:n = true, start .initial:n = 1, stop .code:n = { \@@_set_positive_int:Nnn \l_@@_foreach_stop_int { stop } {#1} \bool_set:Nn \l_@@_foreach_stop_bool { \int_compare_p:nNn { \l_@@_foreach_stop_int } > { 0 } } }, stop .value_required:n = true, step .code:n = { \@@_set_positive_int:Nnn \l_@@_foreach_step_int { step } {#1} }, step .value_required:n = true, step .initial:n = 1, wrapper .code:n = { \bool_set_true:N \l_@@_foreach_wrapper_bool \cs_set_protected:Npn \@@_foreach_wrapper:n ##1 {#1} }, wrapper .value_required:n = true, sep .tl_set:N = \l_@@_foreach_sep_tl, sep .initial:n = { }, sep .value_required:n = true, unknown .code:n = { \@@_unknown_keys_cmd:n {#1} }, } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{getstored, typestored, meaningsc} % The \mymeta{keys} \mykey{getstored}, \mykey{typestored} and % \mykey{meaningsc} set the command saved in % \myhlc|\l_@@_foreach_cmd_tl|. % \begin{macrocode} \keys_define:nn { scontents / foreachsc } { getstored .code:n = { \tl_set:Nn \l_@@_foreach_cmd_tl { \getstored } }, getstored .value_forbidden:n = true, typestored .code:n = { \tl_set:Nn \l_@@_foreach_cmd_tl { \typestored } }, typestored .value_forbidden:n = true, meaningsc .code:n = { \tl_set:Nn \l_@@_foreach_cmd_tl { \meaningsc } }, meaningsc .value_forbidden:n = true, } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for \cs[no-index]{foreachsc}} % % \begin{macro}[int] % { % \@@_foreachsc:nn, % \@@_foreach_add_body:n, % \@@_foreach_wrap:n, % \@@_foreach_wrap:V, % } % The function \myhlc|\@@_foreachsc:nn| sets the \mymeta{keys} passed in % |#1| and steps from \mykey{start} to \mykey{stop}, the number of % \mymeta{stored contents} by default, with \myhlc|\@@_foreach_add_body:n|, % which adds the command saved in \myhlc|\l_@@_foreach_cmd_tl|, with the % code of the \mykey{before}, \mykey{after} and \mykey{wrapper} keys, to % \myhlc|\l_@@_foreach_print_seq|. The result, separated by \mykey{sep}, % is executed after the group. The function \myhlc|\@@_foreach_wrap:n| % expands \myhlc|\@@_foreach_wrapper:n| once inside the group, so the % code of the \mykey{wrapper} key is already in place when the result % is executed; the function \myhlc|\@@_foreach_wrapper:n| is local and % no longer exists after the group. % \begin{macrocode} \cs_new_protected:Npn \@@_foreachsc:nn #1 #2 { \group_begin: \tl_if_novalue:nF {#1} { \keys_set:nn { scontents / foreachsc } {#1} } \tl_set:Nn \l_@@_foreachsc_arg_tl {#2} \seq_clear:N \l_@@_foreach_print_seq \bool_if:NF \l_@@_foreach_stop_bool { \int_set:Nn \l_@@_foreach_stop_int { \@@_seq_count:n {#2} } } \int_step_function:nnnN { \l_@@_foreach_start_int } { \l_@@_foreach_step_int } { \l_@@_foreach_stop_int } \@@_foreach_add_body:n \tl_gset:Ne \g_@@_foreach_exec_tl { \exp_args:NNV \seq_use:Nn \l_@@_foreach_print_seq \l_@@_foreach_sep_tl } \group_end: \exp_after:w \tl_gclear:N \exp_after:w \g_@@_foreach_exec_tl \g_@@_foreach_exec_tl } \cs_new_protected:Npn \@@_foreach_add_body:n #1 { \tl_set:Ne \l_@@_foreach_body_tl { \exp_not:V \l_@@_foreach_cmd_tl [#1] { \exp_not:V \l_@@_foreachsc_arg_tl } } \bool_if:NT \l_@@_foreach_wrapper_bool { \@@_foreach_wrap:V \l_@@_foreach_body_tl } \seq_put_right:Ne \l_@@_foreach_print_seq { \bool_if:NT \l_@@_foreach_before_bool { \exp_not:V \l_@@_foreach_before_tl } \exp_not:V \l_@@_foreach_body_tl \bool_if:NT \l_@@_foreach_after_bool { \exp_not:V \l_@@_foreach_after_tl } } } \cs_new_protected:Npn \@@_foreach_wrap:n #1 { \tl_set:No \l_@@_foreach_body_tl { \@@_foreach_wrapper:n {#1} } } \cs_generate_variant:Nn \@@_foreach_wrap:n { V } % \end{macrocode} % \end{macro} % % \begin{macro}{\foreachsc} % Defines the user command \ics*{foreachsc}. % \begin{macrocode} \NewDocumentCommand \foreachsc { +o m } { \tl_set:Nn \l_@@_cmd_name_tl { foreachsc } \@@_seq_if_exist:nTF {#2} { \@@_foreachsc:nn {#1} {#2} } { \msg_error:nnn { scontents } { undefined-storage } {#2} } } % \end{macrocode} % \end{macro} % % \subsection{The optional argument of \cs{typestored}, \cs{meaningsc} and \cs{mergesc}}\label{fun:range-parser} % % The commands |\typestored| and |\meaningsc|, and |\mergesc| which uses % them internally, accept a single \emph{optional argument} with the % \mymeta{index}, \mymeta{1-end} or the range \mymeta{start-stop} of the % \mymeta{stored contents} in the \emph{sequence} along with the % \mymeta{keys}, this avoids the awkward % |\typestored[...]|\myoarg{keys}|{...}| syntax. The \mymeta{indexes} and % ranges are processed as unknown \mymeta{keys} of % \mypkg{l3keys}\cite{inter3,keyval}. % % \subsubsection{Definition of variables for the optional argument} % % \begin{macro}[int] % { % \l_@@_current_seq_name_str, % \l_@@_index_str, % \l_@@_range_start_tl, % \l_@@_range_stop_tl, % } % The string variable \myhlc|\l_@@_current_seq_name_str| stores the name % of the \emph{sequence} passed to |\typestored| or |\meaningsc|, it is % used by \myhlc|\@@_parse_type_meaning_key:nn|. The string variable % \myhlc|\l_@@_index_str| is used to check that an \mymeta{index} only % has digits and the token lists \myhlc|\l_@@_range_start_tl| and % \myhlc|\l_@@_range_stop_tl| save the limits of a range % \mymeta{start-stop}. % \begin{macrocode} \str_new:N \l_@@_current_seq_name_str \str_new:N \l_@@_index_str \tl_new:N \l_@@_range_start_tl \tl_new:N \l_@@_range_stop_tl % \end{macrocode} % \end{macro} % % \subsubsection{Definition of keys for the optional argument}\label{key:typemeaning} % % \begin{macro}[int]{width-tab, write-out, overwrite, print-cmd, unknown} % We define the common \mymeta{keys} for |\typestored| and |\meaningsc|. % The \mykey{write-out}, \mykey{overwrite} and \mykey{print-cmd} keys are % necessary for the implementation of |\mergesc| (\S\ref{cmd:mergesc}) % and the unknown \mymeta{keys} are passed to % \myhlc|\@@_parse_type_meaning_key:n|. % \begin{macrocode} \keys_define:nn { scontents / typemeaning } { width-tab .meta:nn = { scontents } { width-tab = #1 }, write-out .code:n = { \@@_set_write_out:n {#1} }, write-out .value_required:n = true, overwrite .meta:nn = { scontents } { overwrite = #1 }, overwrite .default:n = true, print-cmd .bool_set:N = \l_@@_print_verb_style_bool, print-cmd .initial:n = true, print-cmd .default:n = true, unknown .code:n = { \@@_parse_type_meaning_key:n {#1} }, } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for the optional argument} % % \begin{macro}[int] % { % \@@_parse_type_meaning_key:n, % \@@_parse_type_meaning_key:nn, % \@@_range_parser:nnn, % \@@_range_parser:nnnw, % \@@_range_limit:nn, % \@@_range_step:nn, % } % \begin{macro}[int,TF]{\@@_if_digits:n} % The function \myhlc|\@@_parse_type_meaning_key:n| checks that the % unknown \mymeta{key} has no value, otherwise something odd as |1=1| % was used and the \enquote{error} |cmd-key-value-unknown| is raised. % The conditional \myhlc|\@@_if_digits:nTF| % tests if |#1| is not blank and only has digits, it removes the digits % from \myhlc|\l_@@_index_str|, so a text that is not a number never % reaches an \emph{integer expression} and only the \enquote{error} of % the package is raised. % % The function \myhlc|\@@_range_parser:nnn| receives the % \mymeta{index} or the range in |#1|, the number of % \mymeta{stored contents} in |#2| and the code that raises the % \enquote{error} in |#3|, and splits |#1| at the hyphens with % \myhlc|\@@_range_parser:nnnw|: without hyphen it is an % \mymeta{index}, with a hyphen at the beginning it is a negative % \mymeta{index} and otherwise it is a range \mymeta{start-stop}, where % \myhlc|\@@_range_limit:nn| replaces |end| by the number of % \mymeta{stored contents} and \myhlc|\@@_range_step:nn| adds the % \mymeta{indexes} of the range, ascending or descending, to % \myhlc|\l_@@_seq_item_seq|. Anything else is passed to the code in % |#3|. % \begin{macrocode} \cs_new_protected:Npn \@@_parse_type_meaning_key:n #1 { \exp_args:NV \@@_parse_type_meaning_key:nn \l_keys_key_str {#1} } \cs_new_protected:Npn \@@_parse_type_meaning_key:nn #1 #2 { \tl_if_blank:nTF {#2} { \@@_range_parser:nnn {#1} { \@@_seq_count:n { \l_@@_current_seq_name_str } } { \msg_error:nnn { scontents } { cmd-key-unknown } } } { \msg_error:nnnn { scontents } { cmd-key-value-unknown } {#1} {#2} } } \prg_new_protected_conditional:Npnn \@@_if_digits:n #1 { TF } { \str_set:Ne \l_@@_index_str { \tl_trim_spaces:n {#1} } \clist_map_inline:nn { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } { \str_remove_all:Nn \l_@@_index_str {##1} } \tl_if_blank:nTF {#1} { \prg_return_false: } { \str_if_empty:NTF \l_@@_index_str { \prg_return_true: } { \prg_return_false: } } } \prg_generate_conditional_variant:Nnn \@@_if_digits:n { V } { TF } \cs_new_protected:Npn \@@_range_parser:nnn #1 #2 #3 { \@@_range_parser:nnnw {#1} {#2} {#3} #1 - \q_@@_mark - \s_@@_mark } \cs_new_protected:Npn \@@_range_parser:nnnw #1 #2 #3 #4 - #5 - #6 \s_@@_mark { \@@_tl_if_head_is_q_mark:nTF {#5} { \@@_if_digits:nTF {#4} { \seq_put_right:Ne \l_@@_seq_item_seq { \int_eval:n {#4} } } { #3 {#1} } } { \@@_tl_if_head_is_q_mark:nTF {#6} { \tl_if_blank:nTF {#4} { \@@_if_digits:nTF {#5} { \seq_put_right:Ne \l_@@_seq_item_seq { \int_eval:n { - #5 } } } { #3 {#1} } } { \tl_set:Ne \l_@@_range_start_tl { \@@_range_limit:nn {#4} {#2} } \tl_set:Ne \l_@@_range_stop_tl { \@@_range_limit:nn {#5} {#2} } \@@_if_digits:VTF \l_@@_range_start_tl { \@@_if_digits:VTF \l_@@_range_stop_tl { \exp_args:NVV \@@_range_step:nn \l_@@_range_start_tl \l_@@_range_stop_tl } { #3 {#1} } } { #3 {#1} } } } { #3 {#1} } } } \cs_new:Npn \@@_range_limit:nn #1 #2 { \str_if_eq:eeTF { \tl_trim_spaces:n {#1} } { end } {#2} { \tl_trim_spaces:n {#1} } } \cs_new_protected:Npn \@@_range_step:nn #1 #2 { \int_step_inline:nnnn {#1} { \int_compare:nNnTF {#2} < {#1} { -1 } { 1 } } {#2} { \seq_put_right:Nn \l_@@_seq_item_seq {##1} } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[int]{\@@_typemeaning_setup:nn, \l_@@_pending_bool} % The function \myhlc|\@@_typemeaning_setup:nn| is the common start of % |\typestored| and |\meaningsc|, it saves the name of the % \emph{sequence} passed in |#2|, sets the \mymeta{keys} and the % \mymeta{indexes} passed in |#1| and uses the first % \mymeta{stored content} if no \mymeta{index} was given. The boolean % \myhlc|\l_@@_pending_bool| is true if any of them is not available % yet in a remembered \emph{sequence} (\S\ref{subsec:remember}). % \begin{macrocode} \bool_new:N \l_@@_pending_bool \cs_new_protected:Npn \@@_typemeaning_setup:nn #1 #2 { \seq_clear:N \l_@@_seq_item_seq \str_set:Ne \l_@@_current_seq_name_str {#2} \tl_if_novalue:nF {#1} { \keys_set:nn { scontents / typemeaning } {#1} } \seq_if_empty:NT \l_@@_seq_item_seq { \seq_set_from_clist:Nn \l_@@_seq_item_seq { 1 } } \bool_set_false:N \l_@@_pending_bool \seq_map_inline:Nn \l_@@_seq_item_seq { \@@_if_pending:nnT {#2} {##1} { \bool_set_true:N \l_@@_pending_bool } } } % \end{macrocode} % \end{macro} % % \subsection{The command \cs{typestored}}\label{cmd:typestored} % % The user-level command |\typestored| prints the \mymeta{stored contents} % of a \emph{sequence} in the |verbatimsc| environment % (\S\ref{env:verbatimsc}). It takes an optional argument % (\S\ref{fun:range-parser}) and a mandatory argument with the % \mymarg{seq name}. % % \subsubsection{Definition of variables for \cs[no-index]{typestored}} % % \begin{macro}[int]{\l_@@_typestored_arg_tl} % The token list \myhlc|\l_@@_typestored_arg_tl| saves the % \mymeta{stored contents} to print. % \begin{macrocode} \tl_new:N \l_@@_typestored_arg_tl % \end{macrocode} % \end{macro} % % \subsubsection{Definition of error messages for \cs[no-index]{typestored}} % % \begin{macro}[int]{empty-variable} % The \enquote{error} |empty-variable| is raised when the % \mymeta{stored contents} to print are blank. % \begin{macrocode} \msg_new:nnnn { scontents } { empty-variable } { Blank~stored~content~to~print~\msg_line_context:. } { The~stored~content~only~has~spaces,~so~there~is~nothing~to~print~ in~verbatim~style.~Check~the~stored~content~or~the~index. } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for \cs[no-index]{typestored}} % % \begin{macro}[int]{\@@_typestored:nn} % The function \myhlc|\@@_typestored:nn| sets the \mymeta{keys} and the % \mymeta{indexes} passed in |#1| with \myhlc|\@@_typemeaning_setup:nn|, % gets the \mymeta{stored contents} of the \emph{sequence} named by |#2|, % writes them to the \texttt{.log} file if \mykey{debug-var} is true and % prints them with \myhlc|\@@_typestored:N| and writes them with % \myhlc|\@@_file_write_cmd:VV|. % \begin{macrocode} \cs_new_protected:Npn \@@_typestored:nn #1 #2 { \@@_bsphack: \group_begin: \@@_typemeaning_setup:nn {#1} {#2} \bool_if:NF \l_@@_pending_bool { \tl_set:Ne \l_@@_typestored_arg_tl { \@@_getfrom_seq:Nn \l_@@_seq_item_seq {#2} } \@@_remove_trailing_eol:N \l_@@_typestored_arg_tl \tl_replace_all:NeV \l_@@_typestored_arg_tl { \c_@@_hidden_space_str } \c_@@_newline_tl \bool_if:NT \l_@@_debug_var_bool { \tl_log:N \l_@@_typestored_arg_tl } \tl_if_empty:NF \l_@@_typestored_arg_tl { \bool_if:NT \l_@@_print_verb_style_bool { \@@_typestored:N \l_@@_typestored_arg_tl } } \@@_file_write_cmd:VV \l_@@_file_name_tl \l_@@_typestored_arg_tl } \use:e { \group_end: \bool_if:NF \l_@@_print_verb_style_bool { \@@_esphack: } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_typestored:N, \@@_verb_print_EOL:} % The function \myhlc|\@@_typestored:N| is defined with active carriage % return characters to mimic an actual |verbatim| environment % \enquote{on the loose}. The content of the token list passed in |#1| % is placed in a |verbatimsc| environment and rescanned with % \myhlc|\tl_retokenize:e|. % \begin{macrocode} \group_begin: \char_set_catcode_active:N \^^M \cs_new_protected:Npn \@@_typestored:N #1 { \tl_if_blank:VT #1 { \msg_error:nn { scontents } { empty-variable } } \cs_set_eq:NN \@@_verb_print_EOL: ^^M \cs_set_eq:NN ^^M \scan_stop: \cs_set_eq:cN { do@noligs } \@@_do_noligs:N \int_set:Nn \tex_newlinechar:D { `\^^J } \tl_retokenize:e { \@@_format_case:nnn { \exp_not:N \begin{verbatimsc} } % LaTeX { \verbatimsc } % Plain/Generic { \startverbatimsc } % ConTeXt ^^M \exp_not:V #1 ^^M \g_@@_end_verbatimsc_tl } \cs_set_eq:NN ^^M \@@_verb_print_EOL: } \group_end: % \end{macrocode} % \end{macro} % % \begin{macro}{\typestored} % Defines the user command \ics*{typestored}. % \begin{macrocode} \NewDocumentCommand \typestored { o m } { \tl_set:Nn \l_@@_cmd_name_tl { typestored } \@@_typestored:nn {#1} {#2} } % \end{macrocode} % \end{macro} % % \subsection{The command \cs{meaningsc}}\label{cmd:meaningsc} % % The user-level command |\meaningsc| prints the meaning of the % \mymeta{stored contents} of a \emph{sequence}. It takes the same % arguments as |\typestored| (\S\ref{cmd:typestored}). % % \subsubsection{Definition of variables for \cs[no-index]{meaningsc}} % % \begin{macro}[int]{\l_@@_meaningsc_arg_tl} % The token list \myhlc|\l_@@_meaningsc_arg_tl| saves the % \mymeta{stored contents} to print. % \begin{macrocode} \tl_new:N \l_@@_meaningsc_arg_tl % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for \cs[no-index]{meaningsc}} % % \begin{macro}[int]{\@@_meaningsc:nn} % The function \myhlc|\@@_meaningsc:nn| sets the \mymeta{keys} and the % \mymeta{indexes} passed in |#1| with \myhlc|\@@_typemeaning_setup:nn| % and calls \myhlc|\@@_meaningsc:n| with the \emph{sequence} named by % |#2|. % \begin{macrocode} \cs_new_protected:Npn \@@_meaningsc:nn #1 #2 { \@@_bsphack: \group_begin: \@@_typemeaning_setup:nn {#1} {#2} \bool_if:NF \l_@@_pending_bool { \@@_meaningsc:n {#2} } \use:e { \group_end: \bool_if:NF \l_@@_print_verb_style_bool { \@@_esphack: } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_meaningsc:n} % The function \myhlc|\@@_meaningsc:n| is defined with the \texttt{TAB} % character active. It gets the \mymeta{stored contents}, replaces the % ends of line and \myhlc|\c_@@_hidden_space_str| by spaces and each % \texttt{TAB} character, active or read from a remembered % \emph{sequence} (\S\ref{subsec:remember}), by as many spaces as the % \mykey{width-tab} key was set to, prints them with % \myhlc|\cs_replacement_spec:N| and writes them with % \myhlc|\@@_file_write_cmd:VV|. % \begin{macrocode} \group_begin: \char_set_catcode_active:N \^^I \cs_new_protected:Npn \@@_meaningsc:n #1 { \tl_set:Ne \l_@@_meaningsc_arg_tl { \@@_getfrom_seq:Nn \l_@@_seq_item_seq {#1} } \tl_replace_all:Nen \l_@@_meaningsc_arg_tl { \iow_char:N \^^J } { ~ } \tl_replace_all:Nen \l_@@_meaningsc_arg_tl { \c_@@_hidden_space_str } { ~ } \bool_if:NT \l_@@_debug_var_bool { \tl_log:N \l_@@_meaningsc_arg_tl } \tl_use:N \l_@@_verb_font_tl \tl_replace_all:Nne \l_@@_meaningsc_arg_tl { ^^I } { \prg_replicate:nn { \l_@@_tab_width_int } { ~ } } \tl_replace_all:Nee \l_@@_meaningsc_arg_tl { \iow_char:N \^^I } { \prg_replicate:nn { \l_@@_tab_width_int } { ~ } } \tl_if_empty:NF \l_@@_meaningsc_arg_tl { \bool_if:NT \l_@@_print_verb_style_bool { \cs_replacement_spec:N \l_@@_meaningsc_arg_tl } } \@@_file_write_cmd:VV \l_@@_file_name_tl \l_@@_meaningsc_arg_tl } \group_end: % \end{macrocode} % \end{macro} % % \begin{macro}{\meaningsc} % Defines the user command \ics*{meaningsc}. % \begin{macrocode} \NewDocumentCommand \meaningsc { o m } { \tl_set:Nn \l_@@_cmd_name_tl { meaningsc } \@@_meaningsc:nn {#1} {#2} } % \end{macrocode} % \end{macro} % % \subsection{The command \cs{mergesc}}\label{cmd:mergesc} % % The user-level command |\mergesc| takes an optional argument with the % \mymeta{keys} and a mandatory argument with a \emph{comma separated % list} of \mymarg{seq name} followed by an optional \mymeta{index} or % range. It assembles the \mymeta{stored contents} in a temporary % \emph{internal sequence} and passes it to |\typestored| or |\meaningsc|, % or rescans it as |\getstored| does. % % \subsubsection{Definition of variables for \cs[no-index]{mergesc}} % % \begin{macro}[int]{\l_@@_mergesc_arg_tl, \l_@@_mergesc_keys_tl} % The token list \myhlc|\l_@@_mergesc_arg_tl| saves the last % \mymeta{stored content} assembled and the token list % \myhlc|\l_@@_mergesc_keys_tl| saves the \mymeta{keys} passed to % |\typestored| or |\meaningsc|. % \begin{macrocode} \tl_new:N \l_@@_mergesc_arg_tl \tl_new:N \l_@@_mergesc_keys_tl % \end{macrocode} % \end{macro} % % \subsubsection{Definition of error messages for \cs[no-index]{mergesc}} % % \begin{macro}[int]{mergesc-missing-key} % The \enquote{error} |mergesc-missing-key| is raised when none of the % \mykey{typestored}, \mykey{meaningsc} and \mykey{getstored} keys is % passed to |\mergesc|. % \begin{macrocode} \msg_new:nnnn { scontents } { mergesc-missing-key } { Missing~mandatory~key~'typestored',~'meaningsc'~or~'getstored'~ for~\c_backslash_str mergesc~\msg_line_context:. } { The~command~\c_backslash_str mergesc~needs~one~of~the~keys~ 'typestored',~'meaningsc'~or~'getstored'.\\ Check~that~you~have~spelled~the~key~name~correctly. } % \end{macrocode} % \end{macro} % % \subsubsection{Definition of keys for \cs[no-index]{mergesc}} % % \begin{macro}[int]{typestored, meaningsc, getstored, \@@_mergesc_cmd:nn} % The \mymeta{keys} \mykey{typestored}, \mykey{meaningsc} and % \mykey{getstored} are \emph{mandatory}, they set the function % \myhlc|\@@_mergesc_cmd:nn|, which by default raises the % \enquote{error} |mergesc-missing-key|. % \begin{macrocode} \keys_define:nn { scontents / mergesc } { typestored .code:n = { \cs_set_eq:NN \@@_mergesc_cmd:nn \@@_typestored:nn }, typestored .value_forbidden:n = true, meaningsc .code:n = { \cs_set_eq:NN \@@_mergesc_cmd:nn \@@_meaningsc:nn }, meaningsc .value_forbidden:n = true, getstored .code:n = { \cs_set_eq:NN \@@_mergesc_cmd:nn \@@_mergesc_getstored:nn }, getstored .value_forbidden:n = true, } \cs_new_protected:Npn \@@_mergesc_cmd:nn #1 #2 { \msg_error:nn { scontents } { mergesc-missing-key } } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for \cs[no-index]{mergesc}} % % \begin{macro}[int]{\@@_mergesc_code:nn} % The function \myhlc|\@@_mergesc_code:nn| sets the known \mymeta{keys} % passed in |#1|, saves the others in \myhlc|\l_@@_mergesc_keys_tl|, % assembles the \emph{internal sequence} from the list passed in |#2| % and, if it is not empty, passes it to \myhlc|\@@_mergesc_cmd:nn|. % \begin{macrocode} \cs_new_protected:Npn \@@_mergesc_code:nn #1 #2 { \group_begin: \tl_clear:N \l_@@_mergesc_keys_tl \tl_if_novalue:nF {#1} { \keys_set_known:nnN { scontents / mergesc } {#1} \l_@@_mergesc_keys_tl } \seq_gclear:c { g_@@_name_sc!internal_seq } \@@_mergesc_parse_list:n {#2} \seq_if_empty:cF { g_@@_name_sc!internal_seq } { \exp_args:Ne \@@_mergesc_cmd:nn { 1-end, \exp_not:V \l_@@_mergesc_keys_tl } { sc!internal } } \group_end: } % \end{macrocode} % \end{macro} % % \begin{macro}[int] % { % \@@_mergesc_parse_list:n, % \@@_mergesc_parse_item:n, % \@@_parse_mergesc:nw, % \@@_parse_mergesc_aux:nw, % \@@_mergesc_put_item:nn, % } % The function \myhlc|\@@_mergesc_parse_list:n| parses each item of the % list with \myhlc|\@@_mergesc_parse_item:n|, which passes the % \mymarg{seq name} between braces to \myhlc|\@@_parse_mergesc:nw| when % the item has no \mymeta{index}, because the \emph{comma separated % list} removes the braces around an item. The function % \myhlc|\@@_parse_mergesc:nw| raises the \enquote{error} % |undefined-storage| if the \emph{sequence} does not exist and uses all % the \mymeta{stored contents} of the \emph{sequence} if there is no % \mymeta{index}. The function \myhlc|\@@_parse_mergesc_aux:nw| uses % \myhlc|\@@_range_parser:nnn| (\S\ref{fun:range-parser}) and % \myhlc|\@@_mergesc_put_item:nn| adds each \mymeta{stored content} to % the \emph{internal sequence} or raises the \enquote{error} % |index-out-of-range|, except for the \mymeta{stored contents} that % are not available yet in a remembered \emph{sequence} % (\S\ref{subsec:remember}). Finally the end of line of the last % \mymeta{stored content} is removed with % \myhlc|\@@_remove_trailing_eol:N|. % \begin{macrocode} \cs_new_protected:Npn \@@_mergesc_parse_list:n #1 { \clist_map_inline:nn {#1} { \@@_mergesc_parse_item:n {##1} } \seq_if_empty:cF { g_@@_name_sc!internal_seq } { \seq_gpop_right:cN { g_@@_name_sc!internal_seq } \l_@@_mergesc_arg_tl \@@_remove_trailing_eol:N \l_@@_mergesc_arg_tl \seq_gput_right:cV { g_@@_name_sc!internal_seq } \l_@@_mergesc_arg_tl } } \cs_new_protected:Npn \@@_mergesc_parse_item:n #1 { \tl_if_in:nnTF {#1} { [ } % ] { \@@_parse_mergesc:nw #1 \s_@@_stop } { \@@_parse_mergesc:nw {#1} \s_@@_stop } } \cs_new_protected:Npn \@@_parse_mergesc:nw #1 { \@@_seq_if_exist:nTF {#1} { \peek_remove_spaces:n { \peek_charcode:NTF [ % ] { \@@_parse_mergesc_aux:nw {#1} } { \@@_parse_mergesc_aux:nw {#1} [ 1-end ] } } } { \msg_error:nnn { scontents } { undefined-storage } {#1} \@@_use_none_delimit_by_s_stop:w } } \cs_new_protected:Npn \@@_parse_mergesc_aux:nw #1 [#2] { \seq_clear:N \l_@@_seq_item_seq \clist_map_inline:nn {#2} { \@@_range_parser:nnn {##1} { \@@_seq_count:n {#1} } { \msg_error:nnn { scontents } { cmd-key-unknown } } } \seq_map_inline:Nn \l_@@_seq_item_seq { \@@_mergesc_put_item:nn {#1} {##1} } \@@_use_none_delimit_by_s_stop:w } \cs_new_protected:Npn \@@_mergesc_put_item:nn #1 #2 { \@@_if_pending:nnF {#1} {#2} { \bool_lazy_or:nnTF { \int_compare_p:nNn {#2} = { 0 } } { \int_compare_p:nNn { \int_abs:n {#2} } > { \@@_seq_count:n {#1} } } { \msg_error:nneee { scontents } { index-out-of-range } {#2} {#1} { \@@_seq_count:n {#1} } } { \seq_gput_right:ce { g_@@_name_sc!internal_seq } { \@@_seq_item:nn {#1} {#2} } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_mergesc_getstored:nn} % The function \myhlc|\@@_mergesc_getstored:nn|, set by the % \mykey{getstored} key, joins the \mymeta{stored contents} of the % \emph{internal sequence} passed in |#2| in % \myhlc|\g_@@_last_stored_tl| separated by an end of line, adds % \myhlc|\c_@@_hidden_space_str| at the end, because the last one has % no end of line, and rescans them with \myhlc|\tl_retokenize:V| after % the group of |\mergesc|, as \myhlc|\@@_lastfrom_seq:n| does % (\S\ref{fun:sequences}). The result is the same as using |\getstored| % on each \mymeta{stored content}. The % \mymeta{indexes} passed in |#1| are always |1-end| and the other % \mymeta{keys}, saved in \myhlc|\l_@@_mergesc_keys_tl|, are unknown for % it and raise the \enquote{errors} of the unknown \mymeta{keys} % (\S\ref{key:unknown-keys}). % \begin{macrocode} \keys_define:nn { scontents / getstored } { unknown .code:n = { \@@_unknown_keys_cmd:n {#1} }, } \cs_new_protected:Npn \@@_mergesc_getstored:nn #1 #2 { \keys_set:nV { scontents / getstored } \l_@@_mergesc_keys_tl \tl_gset:Ne \g_@@_last_stored_tl { \exp_args:NnV \seq_use:cn { g_@@_name_#2_seq } \c_@@_newline_tl \c_@@_hidden_space_str } \group_insert_after:N \tl_retokenize:V \group_insert_after:N \g_@@_last_stored_tl \group_insert_after:N \tl_gclear:N \group_insert_after:N \g_@@_last_stored_tl } % \end{macrocode} % \end{macro} % % \begin{macro}{\mergesc} % Defines the user command \ics*{mergesc}. % \begin{macrocode} \NewDocumentCommand \mergesc { o m } { \tl_set:Nn \l_@@_cmd_name_tl { mergesc } \@@_mergesc_code:nn {#1} {#2} } % \end{macrocode} % \end{macro} % % \subsection{The command \cs{setupsc}}\label{cmd:setupsc} % % \begin{macro}{\setupsc} % Defines the user command \ics*{setupsc}, which sets the \mymeta{keys} % of the package (\S\ref{key:package}). % \begin{macrocode} \NewDocumentCommand \setupsc { +m } { \tl_set:Nn \l_@@_cmd_name_tl { setupsc } \keys_set:nn { scontents } {#1} } % \end{macrocode} % \end{macro} % % \subsection{The command \cs{countsc}}\label{cmd:countsc} % % \begin{macro}{\countsc} % Defines the user command \ics*{countsc}, which counts the % \mymeta{stored contents} in the \emph{sequence}. If the % \emph{sequence} does not exist, the \enquote{error} % |undefined-storage| is raised and |0| is returned. % \begin{macrocode} \NewExpandableDocumentCommand \countsc { m } { \@@_seq_if_exist:nTF {#1} { \@@_seq_count:n {#1} } { \msg_expandable_error:nnn { scontents } { undefined-storage } {#1} 0 } } % \end{macrocode} % \end{macro} % % \subsection{The command \cs{cleanseqsc}}\label{cmd:cleanseqsc} % % \begin{macro}{\cleanseqsc} % Defines the user command \ics*{cleanseqsc}, which removes all the % \mymeta{stored contents} in the \emph{sequence}. % \begin{macrocode} \NewDocumentCommand \cleanseqsc { m } { \seq_gclear_new:c { g_@@_name_#1_seq } } % % \end{macrocode} % \end{macro} % % \subsection{Programming interface}\label{fun:api} % % The public functions of \mypkg*[no-index]{scontents} for \mypkg{expl3} % (\S\ref{sec:api}), they use the functions for sequences % (\S\ref{fun:sequences}). % % \subsubsection{Definition of variables for the programming interface} % % \begin{macro}[int]{\g_@@_map_int, \l_@@_map_item_tl} % The integer variable \myhlc|\g_@@_map_int| is the nesting level of % \myhlc|\scontents_map_inline:nn|, used in the name of the function that % saves each \mymarg{inline function}, and the token list % \myhlc|\l_@@_map_item_tl| saves each \mymeta{stored content}. % \begin{macrocode} %<*core> \int_new:N \g_@@_map_int \tl_new:N \l_@@_map_item_tl % \end{macrocode} % \end{macro} % % \subsubsection{Public functions of the programming interface} % % \begin{macro}[EXP,pTF]{\scontents_if_exist:n} % \begin{macro}[EXP]{\scontents_count:n} % The conditional \myhlc|\scontents_if_exist:nTF| and the function % \myhlc|\scontents_count:n| use \myhlc|\@@_seq_if_exist:nTF| and % \myhlc|\@@_seq_count:n|. % \begin{macrocode} \prg_new_conditional:Npnn \scontents_if_exist:n #1 { p, T, F, TF } { \@@_seq_if_exist:nTF {#1} { \prg_return_true: } { \prg_return_false: } } \cs_new:Npn \scontents_count:n #1 { \@@_seq_count:n {#1} } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\scontents_get:nnN} % \begin{macro}[int]{\@@_get:nnN} % The function \myhlc|\scontents_get:nnN| evaluates the \mymeta{index} and % passes it to \myhlc|\@@_get:nnN|, which sets the token list passed in % |#3| to the \mymeta{stored content} given by \myhlc|\@@_seq_item:nn| % and removes \myhlc|\c_@@_hidden_space_str| from its end with % \myhlc|\@@_remove_trailing_eol:N|. Otherwise the token list is empty % and the \enquote{errors} |undefined-storage| or |index-out-of-range| % are raised, except for a \mymeta{stored content} that is not available % yet in a remembered \emph{sequence} (\S\ref{subsec:remember}). % \begin{macrocode} \cs_new_protected:Npn \scontents_get:nnN #1 #2 #3 { \exp_args:Nne \@@_get:nnN {#1} { \int_eval:n {#2} } #3 } \cs_new_protected:Npn \@@_get:nnN #1 #2 #3 { \tl_clear:N #3 \@@_seq_if_exist:nTF {#1} { \@@_if_pending:nnF {#1} {#2} { \bool_lazy_or:nnTF { \int_compare_p:nNn {#2} = { 0 } } { \int_compare_p:nNn { \int_abs:n {#2} } > { \@@_seq_count:n {#1} } } { \msg_error:nneee { scontents } { index-out-of-range } {#2} {#1} { \@@_seq_count:n {#1} } } { \tl_set:Ne #3 { \@@_seq_item:nn {#1} {#2} } \@@_remove_trailing_eol:N #3 } } } { \msg_error:nnn { scontents } { undefined-storage } {#1} } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\scontents_map_inline:nn} % \begin{macro}[int]{\@@_map_inline:nn} % The function \myhlc|\scontents_map_inline:nn| increases % \myhlc|\g_@@_map_int|, defines with the \mymarg{inline function} % passed in |#2| a function whose name has the nesting level and calls % \myhlc|\@@_map_inline:nn|, which gets each \mymeta{stored content} % with \myhlc|\@@_get:nnN| and passes it to that function. Each nesting % level has its own function, so the \mymarg{inline function} can use % \myhlc|\scontents_map_inline:nn| again. % \begin{macrocode} \cs_new_protected:Npn \scontents_map_inline:nn #1 #2 { \@@_seq_if_exist:nTF {#1} { \int_gincr:N \g_@@_map_int \cs_gset_protected:cpn { @@_map_ \int_use:N \g_@@_map_int :n } ##1 {#2} \exp_args:Nne \@@_map_inline:nn {#1} { \int_use:N \g_@@_map_int } \int_gdecr:N \g_@@_map_int } { \msg_error:nnn { scontents } { undefined-storage } {#1} } } \cs_new_protected:Npn \@@_map_inline:nn #1 #2 { \int_step_inline:nn { \@@_seq_count:n {#1} } { \@@_get:nnN {#1} {##1} \l_@@_map_item_tl \exp_args:Nc \exp_args:NV { @@_map_ #2 :n } \l_@@_map_item_tl } } % % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Finish package}\label{subsec:finish} % % Finish package implementation, in \hologo{ConTeXt} `|!|' is a letter % again (\S\ref{subsubsec:generic-layer}). % % \begin{macrocode} %\char_set_catcode_letter:N \! %\ExplSyntaxOff %\endinput %\file_input_stop: % \end{macrocode} % % \Finale