summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/scontents/scontents.dtx
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-10-24 03:02:46 +0000
committerNorbert Preining <norbert@preining.info>2019-10-24 03:02:46 +0000
commit33b877a6413cc7b93c7a2c17e6df36c03f55481d (patch)
treed1006be84566ca91a3dc9fdc5798c20c9fb0c095 /macros/latex/contrib/scontents/scontents.dtx
parent43e60b98142683b95336b9086ee52f4daefff93e (diff)
CTAN sync 201910240302
Diffstat (limited to 'macros/latex/contrib/scontents/scontents.dtx')
-rw-r--r--macros/latex/contrib/scontents/scontents.dtx1083
1 files changed, 863 insertions, 220 deletions
diff --git a/macros/latex/contrib/scontents/scontents.dtx b/macros/latex/contrib/scontents/scontents.dtx
index fd0504e7a2..4b77c043ee 100644
--- a/macros/latex/contrib/scontents/scontents.dtx
+++ b/macros/latex/contrib/scontents/scontents.dtx
@@ -6,68 +6,21 @@
% 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
%
-% http://www.latex-project.org/lppl.txt
+% http://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 file scontents.dtx
-% and the derived files scontents.ins,
-% scontents.pdf and
-% scontents.sty.
-%
-%<*internal>
-\def\nameofplainTeX{plain}
-\ifx\fmtname\nameofplainTeX\else
- \expandafter\begingroup
-\fi
-%</internal>
-%<*install>
-\input l3docstrip.tex
-\keepsilent
-\askforoverwritefalse
-\preamble
-
-Copyright (C) 2019 by Pablo González L <pablgonz@educarchile.cl>
-
-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
-
- http://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 file scontents.dtx
-and the derived files scontents.ins,
- scontents.pdf and
- scontents.sty.
-
-\endpreamble
-\usedir{tex/latex/scontents}
-\generate{%
- \file{\jobname.sty}{\from{\jobname.dtx}{package}}%
-}%
-%</install>
-%<install>\endbatchfile
-%<*internal>
-\usedir{source/latex/scontents}
-\generate{
- \file{\jobname.ins}{\from{\jobname.dtx}{install}}
-}
-\ifx\fmtname\nameofplainTeX
- \expandafter\endbatchfile
-\else
- \expandafter\endgroup
-\fi
-%</internal>
+%
+% This work consists of the files scontents.dtx and
+% scontents.ins,
+% and the derived files scontents.sty,
+% scontents.tex,
+% t-scontents.mkvi and
+% scontents-code.tex.
+%
%<*driver>
\documentclass[full]{l3doc}
% imakeidx also opens a write stream for the .idx file, and that conflicts
@@ -372,8 +325,11 @@ and the derived files scontents.ins,
\lstdefinelanguage{scontents-doc}{
texcsstyle=*,%
escapechar=`,%
- showstringspaces=false,%
- extendedchars=true, %
+ extendedchars=true,%
+ breakatwhitespace=true,%
+ breaklines=true,%
+ keepspaces=true,%
+ columns=fullflexible,%
stringstyle= {\color{red}},%
basicstyle=\ttfamily\small,%
alsoletter=-,%
@@ -382,28 +338,30 @@ and the derived files scontents.ins,
commentstyle=\lmmitalic\small\itshape\color{lightgray},%
% Important words 1
keywordstyle=[1]{\color{gray}},%
- keywords=[1]{begin,end},%
+ keywords=[1]{begin,end,Verbatim},%
% Other words 2
keywordstyle=[2]{\color{blue!75}},%
- keywords=[2]{usepackage,section,documentclass},%
+ keywords=[2]{usepackage,section,documentclass,input,usemodule},%
% Other words 3
keywordstyle=[3]{\color{optcolor!85}},%
keywords=[3]{document,article},%
% Reserved words 4 (scontents pkg)
keywordstyle=[4]{\color{mypkgcolor}},%
keywords=[4]{scontents,Scontents,getstored,typestored,verbatimsc,%
- endverbatimsc,countsc,meaningsc},%
+ endverbatimsc,countsc,meaningsc,foreachsc,macros
+ endscontents,startscontents,stopscontents},%
% Reserved in red
keywordstyle=[5]{\color{red}},%
- keywords=[5]{makeatletter,makeatother,let},%
+ keywords=[5]{makeatletter,makeatother,let,verb,undefined,makebox},%
% Reserved in orange
keywordstyle=[6]{\color{optcolor}},%
- keywords=[6]{verb,myverb,store-cmd,store-env,print-env,write-env,%
- write-out,width-tab,force-eol,inner,outer,I,J,M,L,Ascheol},%
+ keywords=[6]{store-cmd,store-env,print-env,write-env,%
+ start,stopt,wrapper,sep,step,before,after,write-out,%
+ width-tab,force-eol,inner,outer,I,J,M,L,Ascheol},%
% Reserved in orange
keywordstyle=[7]{\color{OrangeRed}},%
- keywords=[7]{foreach,DefineVerbatimEnvironment,lstnewenvironment,newminted},%
-% literateee
+ keywords=[7]{DefineVerbatimEnvironment,lstnewenvironment,newminted,newenvironment},%
+% literate
literate=*{\{}{{\textcolor{gray}{\{}}}{1}
{\}}{{\textcolor{gray}{\}}}}{1}
{[}{{\textcolor{gray}{[}}}{1}
@@ -440,6 +398,7 @@ and the derived files scontents.ins,
escapechar=`,%
upquote=true,%
numbersep=1em,%
+ columns=fullflexible,%
numberstyle=\tiny\color{lightgray}\noaccsupp,%
literate=*{\%}{{\bfseries\textcolor{gray}{\%}}}{1}
}
@@ -449,7 +408,7 @@ and the derived files scontents.ins,
\lstMakeShortInline[language=scontents-doc,basicstyle=\ttfamily]§
% Get file info
-\GetFileInfo{\jobname.sty}
+\GetFileInfo{scontents.sty}
% Config hyperref
\hypersetup{
@@ -463,7 +422,7 @@ and the derived files scontents.ins,
pdfsubject = {Documentation for \fileversion{} [\filedate] },%
pdfcopyright = {\textcopyright 2019 by Pablo González},
pdfcontacturl = {https://github.com/pablgonz/scontents},
- pdfkeywords = {contents, external files, expl3, xparse, l3seq, Store contents},
+ pdfkeywords = {sequences, contents, external files, expl3, xparse, l3seq, store contents},
pdfstartview = {FitH},%
bookmarksopenlevel = 1,%
}
@@ -554,7 +513,7 @@ and the derived files scontents.ins,
% \section{Motivation and Acknowledgments}
%
% In \hologo{(La)TeX} there is no direct way to record content for later use, although
-% you can do this using "\macros", recording \mymeta{verbatim content} is a
+% you can do this using §\macros§, 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
% \emph{buffers} that has \hologo{ConTeXt} which allows you to save content in
@@ -593,8 +552,8 @@ and the derived files scontents.ins,
% \medskip
%
% The \mypkg*{scontents} package loads \mypkg{expl3}, \mypkg{xparse} and
-% \mypkg{l3keys2e}. This package can be used with "xelatex", "lualatex"
-% , "pdflatex" and the classical workflow §latex>dvips>ps2pdf§.
+% \mypkg{l3keys2e}. This package can be used with "plain", "context", "xelatex",
+% "lualatex", "pdflatex" and the classical workflow §latex>dvips>ps2pdf§.
%
% \thispagestyle{plain}
%
@@ -616,9 +575,9 @@ and the derived files scontents.ins,
% by making use \mymeta{sequences}.
% \end{scontents}
%
-% The package uses a \myoarg{key \textnormal{\textcolor{gray}{=}} val}
-% system for the options and is loaded in the usual way:
+% The package is loaded in the usual way:
%
+% \subsubsection*{For \hologo{LaTeX} users}
% \iffalse
%<*example>
% \fi
@@ -640,6 +599,30 @@ and the derived files scontents.ins,
%</example>
% \fi
%
+% \subsubsection*{For \hologo{plainTeX} users}
+%
+% \iffalse
+%<*example>
+% \fi
+\begin{examplecode}[frame=single]
+\input scontents.tex
+\end{examplecode}
+% \iffalse
+%</example>
+% \fi
+%
+% \subsubsection*{For \hologo{ConTeXt} users}
+%
+% \iffalse
+%<*example>
+% \fi
+\begin{examplecode}[frame=single]
+\usemodule{scontents}
+\end{examplecode}
+% \iffalse
+%</example>
+% \fi
+%
% \subsection{The TAB character}
% \label{sec:tabcharacter}
%
@@ -667,7 +650,7 @@ and the derived files scontents.ins,
%
% As a general recommendation \enquote{Do not use "TAB" character unless strictly
% necessary}, for example within a \emph{verbatim} environment that supports
-% this character such as §Verbatim§ of the package \mypkg{fancyvrb} or §lstlisting§
+% this character such as \myenv{Verbatim} of the package \mypkg{fancyvrb} or \myenv{lstlisting}
% of the package \mypkg{listings} or when you want to generate a §MakeFile§ file.
%
% \subsection{Configuration of the options}
@@ -718,7 +701,7 @@ and the derived files scontents.ins,
% This key is necessary only if the last line is the closing of some
% environment defined by the \mypkg{fancyvrb} package as §\end{Verbatim}§
% or another environment that does not support a comments \enquote{\textcolor{gray}{\%}}
-% after closing §\end{...}%§. This key is available for the \myenv*{scontents}
+% after closing §\end{§\textcolor{gray}{...}§}%§. This key is available for the \myenv*{scontents}
% environment and the \ics*{Scontents} command.
%
% \keyexamp{width-tab}{integer}{1}
@@ -776,13 +759,13 @@ and the derived files scontents.ins,
% \end{syntax}
%
% The \myenv*{scontents} environment allows you to \mymeta{store} and \mymeta{write}
-% content, 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.
+% content, 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
-% different lines, all \mymeta{keys} must be passed in a \mymeta{single line} separated
-% by commas \enquote{without vertical spaces} and \enquote{without separation} of
-% the start of the environment.
+% For the correct operation §\begin{scontents}§ and §\end{scontents}§ must
+% be in different lines, all \mymeta{keys} must be passed separated by
+% commas and \enquote{without separation} of the start of the environment.
% \end{function}
%
% Comments \enquote{\textcolor{gray}{\%}} or \enquote{any character} after
@@ -818,6 +801,11 @@ This text is in the outer environment (after nested).
% It is advisable to store content within sequences with different names,
% so as not to get lost in the order in which content is stored.
%
+% In \hologo{plainTeX} there is not environments as in \hologo{LaTeX}.
+% Instead of using the environment \myenv*{scontents}, one should use a
+% \emph{pseudo environment} delimited by \ics*{scontents} and \ics*{endscontents}.
+% \hologo{ConTeXt} users should use \ics*{startscontents} and \ics*{stopscontents}.
+%
% \subsection*{Options for environment}
%
% The environment options can be configured globally using option
@@ -836,7 +824,7 @@ This text is in the outer environment (after nested).
% running the environment. The content is extracted from the \mymeta{sequence}
% in which it is stored.
%
-% \newpage
+% \medskip
%
% \keyexamp{write-env}{file.ext}{not used}
% Sets the name of the \mymeta{external file} in which the \mymeta{contents} of
@@ -925,11 +913,63 @@ This text is in the outer environment (after nested).
% \end{syntax}
% \end{function}
%
-% The command \ics*{getstored} gets the content stored in \mymeta{seq name}
+% The command \ics*{getstored} gets the content stored in \mymarg{seq name}
% according to the \mymeta{index} in which it was stored. The command is
% robust and can be used as an \mymeta{argument} for another command. If the
% optional argument is not passed it defaults to the first element stored
-% in the \mymeta{seq name}.
+% in the \mymarg{seq name}.
+%
+% \subsection{The command \cs{foreachsc}}
+% \label{sec:foreachsc}
+%
+% \vspace*{-10pt}
+%
+% \begin{function}{\foreachsc}
+% \begin{syntax}
+% \cmdexamp{foreachsc}[key \textnormal{\textcolor{gray}{=}} val]{seq name}
+% \end{syntax}
+% \end{function}
+%
+% The command \ics*{foreachsc} goes through and executes the command §\getstored§
+% on the contents stored in \mymarg{seq name}. If you pass without options run
+% §\getstored§ on all contents stored in \mymarg{seq name}.
+%
+% \subsection*{Options for command}
+% \label{sec:optcmdfor}
+%
+% \keyexamp{sep}{code}{empty}
+% Establishes the separation between each content stored in \mymarg{seq name}.
+% For example, you can use §sep={\\[10pt]}§ for vertical separation of stored
+% contents.
+%
+% \keyexamp{step}{integer}{1}
+% Sets the increment (\mymeta{step}) applied to the value set by key §start§
+% for each element stored in the \mymarg{seq name}. The value must be a
+% \mymeta{positive integer}.
+%
+% \keyexamp{start}{integer}{1}
+% Sets the \mymeta{index} number of the \mymarg{seq name} from which execution
+% will start. The value must be a \mymeta{positive integer}.
+%
+% \keyexamp{stop}{integer}{total}
+% Sets the \mymeta{index} number of the \mymarg{seq name} from which execution
+% it will finish executing. The value must be a \mymeta{positive integer}.
+%
+% \keyexamp{before}{code}{empty}
+% Sets the \mymarg{code} that will be executed \mymeta{before} each content stored
+% in \mymarg{seq name}. The \mymarg{code} must be passed between braces.
+%
+% \medskip
+%
+% \keyexamp{after}{code}{empty}
+% Sets the \mymarg{code} that will be executed \mymeta{after} each content stored
+% in \mymarg{seq name}. The \mymarg{code} must be passed between braces.
+%
+% \keyexamp{wrapper}{code \textnormal{\textcolor{gray}{\{\#1\}}} more code}{empty}
+% Wraps the content stored in \mymarg{seq name} referenced by \mymarg{\#1}.
+% The \mymarg{code} must be passed between braces. For example
+% §\foreachsc[wrapper={\makebox[1em][l]{#1}}]{contents}§.
+%
%
% \subsection{The command \cs{typestored}}
% \label{sec:typestored}
@@ -941,13 +981,12 @@ This text is in the outer environment (after nested).
% \cmdexamp{typestored}[index\textnormal{\textcolor{gray}{,}} width-tab \textnormal{\textcolor{gray}{=}} number]{seq name}
% \end{syntax}
% The command \ics*{typestored} internally places the content stored in
-% the \mymeta{seq name} into the \myenv*{verbatimsc} environment. The \mymeta{index}
-% number corresponds to the position in which the content is stored in
-% the \mymeta{seq name}.
+% the \mymarg{seq name} into the \myenv*{verbatimsc} environment. The \mymeta{index}
+% corresponds to the position in which the content is stored in the \mymarg{seq name}.
% \end{function}
%
% If the optional argument is not passed it defaults to the first element
-% stored in the \mymeta{seq name}. The key §width-tab§ is available for
+% stored in the \mymarg{seq name}. The key §width-tab§ is available for
% this command.
%
% The \mypkg{verbatim} package is not compatible with the implementation
@@ -955,8 +994,6 @@ This text is in the outer environment (after nested).
% a user of that package consider customizing the \myenv*{verbatimsc}
% environment.
%
-% \newpage
-%
% \subsection{The environment \env{verbatimsc}}
% \label{sec:verbatimsc}
%
@@ -1043,12 +1080,12 @@ This text is in the outer environment (after nested).
% \cmdexamp{meaningsc}[index\textnormal{\textcolor{gray}{,}} width-tab \textnormal{\textcolor{gray}{=}} number]{seq name}
% \end{syntax}
% The command \ics*{meaningsc} executes \ics{meaning} on the content stored
-% in \mymeta{seq name}. The \mymeta{index} number corresponds to the position
-% in which the content is stored in the \mymeta{seq name}.
+% in \mymarg{seq name}. The \mymeta{index} corresponds to the position
+% in which the content is stored in the \mymarg{seq name}.
% \end{function}
%
% If the optional argument is not passed it defaults to the first element
-% stored in the \mymeta{seq name}. The key §width-tab§ is available for
+% stored in the \mymarg{seq name}. The key §width-tab§ is available for
% this command.
%
% \subsection{The command \cs{countsc}}
@@ -1060,7 +1097,7 @@ This text is in the outer environment (after nested).
% \begin{syntax}
% \cmdexamp{countsc}{seq name}
% \end{syntax}
-% The command \ics*{countsc} count a number of contents stored in \mymeta{seq name}.
+% The command \ics*{countsc} count a number of contents stored in \mymarg{seq name}.
% \end{function}
%
% \subsection{The command \cs{cleanseqsc}}
@@ -1072,7 +1109,7 @@ This text is in the outer environment (after nested).
% \begin{syntax}
% \cmdexamp{cleanseqsc}{seq name}
% \end{syntax}
-% The command \ics*{cleanseqsc} remove all contents stored in \mymeta{seq name}.
+% The command \ics*{cleanseqsc} remove all contents stored in \mymarg{seq name}.
% \end{function}
%
% \newpage
@@ -1158,7 +1195,6 @@ by making use \mymeta{sequences}.
\begin{scontents}[write-out=scexamp1.ltx]
\documentclass[12pt,a4paper]{article}
\usepackage[store-cmd=solutions]{scontents}
-\usepackage{pgffor}
\newtheorem{ex}{Exercise}
\begin{document}
\section{Problems}
@@ -1177,9 +1213,7 @@ Second exercise
\end{ex}
\section{Solutions}
-\foreach \i in {1,...,\countsc{solutions}} {
-\noindent\textbf{\i} \getstored[\i]{solutions}\par
-}
+\foreachsc[sep={\\[10pt]}]{solutions}
\end{document}
\end{scontents}
% \iffalse
@@ -1200,7 +1234,6 @@ Second exercise
\begin{scontents}[write-out=scexamp2.ltx]
\documentclass{article}
\usepackage[store-env=defexercise,store-cmd=defexercise]{scontents}
-\usepackage{pgffor}
\pagestyle{empty}
\begin{document}
% not starred
@@ -1218,10 +1251,9 @@ advance evidence from knowledge of the names of its employees in the
seventies that the \NSA\ has known that for 40 years.\par
\end{scontents}
% see all stored
-\foreach \i in {1,...,3} {
\begin{itemize}
-\item \getstored[\i]{defexercise}
-\end{itemize}}
+\foreachsc[before={\item }]{defexercise}
+\end{itemize}
% \getstored are robust :)
\section{\getstored[2]{defexercise}}
\end{document}
@@ -1286,7 +1318,6 @@ seventies that the \NSA\ has known that for 40 years.\par
\begin{scontents}[write-out=scexamp4.ltx]
\documentclass{article}
\usepackage{scontents}
-\usepackage{pgffor}
\pagestyle{empty}
\begin{document}
\begin{scontents}[store-env=a]
@@ -1306,9 +1337,8 @@ Something with no label
This is a: \getstored[1]{a}\par
This is b: \getstored[2]{a}
-\textbf{Print all of them}
-
-\foreach \i in {1,...,\countsc{a}} {\getstored[\i]{a}\par}
+\textbf{Print all of them}\par
+\foreachsc[sep={\\[10pt]}]{a}
\end{document}
\end{scontents}
% \iffalse
@@ -1554,13 +1584,21 @@ No tab
% \begin{description}[font=\small\sffamily,wide=0pt,style=multiline,leftmargin=\descrwidth,nosep,noitemsep]
% \item [\fileversion{} (ctan), \filedate]
% \begin{itemize}
+% \item Add support for \hologo{plainTeX} and \hologo{ConTeXt}.
+% \item Split internal code for optimization.
+% \item Add support for vertical spaces in |key=val|.
+% \item Add |\foreachsc| command.
+% \item Check if |verbatim| package is loaded.
+% \end{itemize}
+% \item [v1.4 (ctan), 2019-10-03]
+% \begin{itemize}
% \item Add |store-all| key.
% \item Messages and keys were separated.
% \item Restructuring of documentation.
% \item Now the version of |expl3| is checked instead of |xparse|.
% \item The internal behavior of \verb+force-eol+ has been modified.
% \end{itemize}
-% \item [v1.3 (ctan), 2019/09/24]
+% \item [v1.3 (ctan), 2019-09-24]
% \begin{itemize}
% \item The environment can now nest.
% \item Added \verb+force-eol+, \verb+verb-font+ and \verb+width-tab+ keys.
@@ -1570,17 +1608,17 @@ No tab
% \item Remove \verb+filecontentsdef+ dependency.
% \item Changing \verb+\regex_replace_all:+ for \verb+\tl_replace_all:+.
% \end{itemize}
-% \item [v1.2 (ctan), 2019/08/28]
+% \item [v1.2 (ctan), 2019-08-28]
% \begin{itemize}
% \item Restructuring of documentation.
% \item Added copy of \verb+\tex_scantokens:D+.
% \end{itemize}
-% \item [v1.1 (ctan), 2019/08/12]
+% \item [v1.1 (ctan), 2019-08-12]
% \begin{itemize}
% \item Extension of documentation.
% \item Replace \verb+\tex_endinput:D+ by \verb+\file_input_stop:+.
% \end{itemize}
-% \item [v1.0 (ctan), 2019/07/30]
+% \item [v1.0 (ctan), 2019-07-30]
% \begin{itemize}
% \item First public release,
% \end{itemize}
@@ -1604,10 +1642,6 @@ No tab
% \label{sec:Implementation}
% \addtocontents{toc}{\protect\setcounter{tocdepth}{0}}
%
-% \iffalse
-%<*package>
-% \fi
-%
% \subsection{Declaration of the package}
%
% First we set up the module name for \pkg{l3doc}:
@@ -1615,30 +1649,155 @@ No tab
%<@@=scontents>
% \end{macrocode}
%
-% Then, we can give the traditional declaration of a package written with
-% \pkg{expl3} and the necessary packages for its operation.
-%
+% Now we define some common macros to hold the package date and version:
% \begin{macrocode}
-\RequirePackage{l3keys2e}
-\RequirePackage{xparse}[2019/05/28]
-\ProvidesExplPackage{scontents}{2019/10/03}{1.4}
- {Stores LaTeX contents in memory or files}
+%<loader>\def\ScontentsFileDate{2019-10-24}%
+%<core>\def\ScontentsCoreFileDate{2019-10-24}%
+%<*loader>
+\def\ScontentsFileVersion{1.5}%
+\def\ScontentsFileDescription{Stores LaTeX contents in memory or files}%
% \end{macrocode}
%
-% A check to make sure that \pkg{expl3} is not too old
+% The \LaTeX{} loader is fairly simple: just load the dependencies, load the
+% core code, and then set interfaces up.
%
+% We also check if the \pkg{verbatim} package is loaded and show a compatibility
+% warning.
% \begin{macrocode}
-\@ifpackagelater { expl3 } { 2019/09/19 }
- { }
+%<*latex>
+\RequirePackage{expl3,xparse,l3keys2e}[2019/05/28]
+\ProvidesExplPackage
+ {scontents} {\ScontentsFileDate} {\ScontentsFileVersion} {\ScontentsFileDescription}
+\@ifpackageloaded { verbatim }
{
- \PackageError { scontents } { Support~package~expl3~too~old }
+ \iow_term:n
{
- You~need~to~update~your~installation~of~the~bundles~
- 'l3kernel'~and~'l3packages'.\MessageBreak
- Loading~scontents~will~abort!
+ The~implementation~of~the~'verbatimsc'~environment~\\
+ used~by~\tl_to_str:n{\typestored}~is~not~compatible~with~package\\
+ 'verbatim'.~Review~the~documentation~and~redefine~\\
+ the~'verbatimsc'~environment.
}
+ } { }
+%</latex>
+% \end{macrocode}
+% The Plain and \hologo{ConTeXt} loaders are similar (probably because I don't
+% know how to make a proper \hologo{ConTeXt} module :-). We define a
+% \LaTeX{}-style ver@scontents.sty macro with version info (just in case):
+% \begin{macrocode}
+%<*!latex>
+%<context>\writestatus{loading}{User Module scontents v\ScontentsFileVersion}
+%<context>\unprotect
+\input expl3-generic.tex
+\ExplSyntaxOn
+\tl_gset:cx { ver @ scontents . sty } { \ScontentsFileDate\space
+ v\ScontentsFileVersion\space \ScontentsFileDescription }
+\iow_log:x { Package: ~ scontents ~ \use:c { ver @ scontents . sty } }
+%</!latex>
+% \end{macrocode}
+%
+% In Plain, check that the package isn't being loaded twice (\LaTeX{} and
+% \hologo{ConTeXt} already defend against that):
+% \begin{macrocode}
+%<*plain>
+\msg_gset:nnn { scontents } { already-loaded }
+ { The~`scontents'~package~is~already~loaded.~Aborting~input~\msg_line_context:. }
+\cs_if_exist:NT \@@_rescan_tokens:n
+ {
+ \msg_warning:nn { scontents } { already-loaded }
+ \ExplSyntaxOff
\file_input_stop:
}
+%</plain>
+% \end{macrocode}
+%
+% \begin{macro}{\g_@@_end_verbatimsc_tl,\c_@@_end_env_tl}
+% A token list to match when ending \env{verbatimsc} and \env{scontents}
+% environments.
+%
+% \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 \}
+%</latex>
+ }
+%<latex> { \end{verbatimsc} }
+%<plain> { \endverbatimsc }
+%<context> { \stopverbatimsc }
+\tl_const:Nx \c_@@_end_env_tl
+ {
+ \c_backslash_str
+%<latex|plain> end
+%<context> stop
+%<latex> \c_left_brace_str
+ scontents
+%<latex> \c_right_brace_str
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% Now we load the core \mypkg*{scontents} code:
+% \begin{macrocode}
+\file_input:n { scontents-code.tex }
+% \end{macrocode}
+%
+% Sometimes we need to detect the format from within a macro:
+% \begin{macrocode}
+\cs_new:Npn \@@_format_case:nnn #1 #2 #3
+%<latex> {#1} % LaTeX
+%<plain> {#2} % Plain/Generic
+%<context> {#3} % ConTeXt
+% \end{macrocode}
+%
+% Checking that the package was loaded with the proper loader code. This code
+% was copied from \texttt{expl3-code.tex}.
+% \begin{macrocode}
+%</loader>
+%<*core>
+\begingroup
+ \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{Definition of common keys}
@@ -1656,7 +1815,6 @@ No tab
store-cmd .initial:n = contents,
store-cmd .value_required:n = true,
verb-font .tl_set:N = \l_@@_verb_font_tl,
- verb-font .initial:n = \ttfamily,
verb-font .value_required:n = true,
print-env .bool_set:N = \l_@@_print_env_bool,
print-env .initial:n = false,
@@ -1675,14 +1833,18 @@ No tab
store-all .meta:n = { store-env = #1 , store-cmd = #1 },
store-all .value_required:n = true
}
+%</core>
+%<loader>\keys_define:nn { scontents }
+%<latex> { verb-font .initial:n = \ttfamily }
+%<plain|context> { verb-font .initial:n = \tt }
% \end{macrocode}
%
-% We process the \mymeta{keys} as options passed on to the package, the
-% package \pkg{l3keys2e} will verify the \mymeta{keys} and will return
-% an error when they are \emph{unknown}.
-%
+% In \LaTeX{} mode we load \mypkg{l3keys2e} process the \mymeta{keys} as options
+% passed on to the package, the package \pkg{l3keys2e} will verify the
+% \mymeta{keys} and will return an error when they are \emph{unknown}.
% \begin{macrocode}
-\ProcessKeysOptions { scontents }
+%<latex>\ProcessKeysOptions { scontents }
+%<*core>
% \end{macrocode}
%
% \subsection{Internal variables}
@@ -1690,28 +1852,41 @@ No tab
% Now we declare the internal variables we will use.
%
% \begin{macro}{\l_@@_macro_tmp_tl,\l_@@_fname_out_tl,\l_@@_temp_tl,
-% \l_@@_file_tl,\g_@@_temp_tl}
+% \l_@@_file_tl,\g_@@_temp_tl,\l_@@_foreach_name_seq_tl,
+% \l_@@_foreach_before_tl,\l_@@_foreach_after_tl}
% \cs{l_@@_macro_tmp_tl} is a temporary token list to hold the contents
% of the macro/environment, \cs{l_@@_fname_out_tl} is used as the name
% of the output file, when there's one, \cs{l_@@_file_tl} holds the contents
% of an environment as it's being read, and \cs{l_@@_temp_tl} and
% \cs{g_@@_temp_tl} are generic temporary token lists.
%
+% \cs{l_@@_foreach_name_seq_tl} is the name assigned to the sequence on
+% which the loop will be made, \cs{l_@@_foreach_before_tl} and \cs{l_@@_foreach_after_tl}
+% are token lists in which the assigned material will be placed before
+% and after the execution of the §\foreachsc§ loop.
+%
% \begin{macrocode}
\tl_new:N \l_@@_macro_tmp_tl
\tl_new:N \l_@@_fname_out_tl
\tl_new:N \l_@@_temp_tl
\tl_new:N \l_@@_file_tl
\tl_new:N \g_@@_temp_tl
+\tl_new:N \l_@@_foreach_name_seq_tl
+\tl_new:N \l_@@_foreach_before_tl
+\tl_new:N \l_@@_foreach_after_tl
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\l_@@_seq_item_int,\l_@@_env_nesting_int,\l_@@_tmpa_int}
+% \begin{macro}{\l_@@_seq_item_int,\l_@@_env_nesting_int,\l_@@_tmpa_int,
+% \l_@@_foreach_stop_int}
% \cs{l_@@_seq_item_int} stores the index in the sequence of the item
% requested to \cs{typestored} or \cs{meaningsc}. \cs{l_@@_env_nesting_int}
% stores the current nesting level of the \env{scontents} environment.
+% \cs{l_@@_foreach_stop_int} will save the value at which the §\foreachsc§
+% loop will stop.
%
% \begin{macrocode}
+\int_new:N \l_@@_foreach_stop_int
\int_new:N \l_@@_seq_item_int
\int_new:N \l_@@_env_nesting_int
\int_new:N \l_@@_tmpa_int
@@ -1731,22 +1906,28 @@ No tab
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\g_@@_end_verbatimsc_tl,\c_@@_end_env_tl}
-% A token list to match when ending \env{verbatimsc} and \env{scontents}
-% environments.
+%
+% \begin{macro}{\l_@@_foreach_before_bool,\l_@@_foreach_after_bool
+% \l_@@_foreach_stop_bool,\l_@@_foreach_wrapper_bool}
+% Boolean variables used by the §\foreachsc§ loop.
%
% \begin{macrocode}
-\tl_new:N \g_@@_end_verbatimsc_tl
-\tl_gset_rescan:Nnn
- \g_@@_end_verbatimsc_tl
- {
- \char_set_catcode_other:N \\
- \char_set_catcode_other:N \{
- \char_set_catcode_other:N \}
- }
- { \end{verbatimsc} }
-\tl_const:Nx \c_@@_end_env_tl
- { \c_backslash_str end \c_left_brace_str scontents \c_right_brace_str }
+\bool_new:N \l_@@_foreach_before_bool
+\bool_set_false:N \l_@@_foreach_before_bool
+\bool_new:N \l_@@_foreach_after_bool
+\bool_set_false:N \l_@@_foreach_after_bool
+\bool_new:N \l_@@_foreach_stop_bool
+\bool_set_false:N \l_@@_foreach_stop_bool
+\bool_new:N \l_@@_foreach_wrapper_bool
+\bool_set_false:N \l_@@_foreach_wrapper_bool
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\l_@@_foreach_print_seq}
+% The \cs{l_@@_foreach_print_seq} is the sequence used by §\foreachsc§.
+%
+% \begin{macrocode}
+\seq_new:N \l_@@_foreach_print_seq
% \end{macrocode}
% \end{macro}
%
@@ -1809,6 +1990,7 @@ No tab
% \begin{macrocode}
\cs_generate_variant:Nn \tl_remove_once:Nn { NV }
\cs_generate_variant:Nn \tl_replace_all:Nnn { Nx, Nxx, Nnx }
+\cs_generate_variant:Nn \msg_error:nnnn { nnx }
\prg_generate_conditional_variant:Nnn \tl_if_empty:n { f } { TF }
% \end{macrocode}
% \end{macro}
@@ -1862,6 +2044,46 @@ No tab
}
% \end{macrocode}
%
+% \subsubsection{Keys for command \cs{foreachsc}}
+%
+% We define a set of \mymeta{keys} for command §\foreachsc§.
+%
+% \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 .int_set:N = \l_@@_foreach_start_int,
+ start .value_required:n = true,
+ start .initial:n = 1,
+ stop .code:n = {
+ \bool_set_true:N \l_@@_foreach_stop_bool
+ \int_set:Nn \l_@@_foreach_stop_int {#1}
+ },
+ stop .value_required:n = true,
+ step .int_set:N = \l_@@_foreach_step_int,
+ 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 = { \@@_parse_foreach_keys:n {#1} }
+ }
+% \end{macrocode}
+%
% \subsubsection{Key for commands \cs{typestored} and \cs{meaningsc}}
%
% We define a \mymeta{key} for command §\typestored§ and §\meaningsc§.
@@ -1923,6 +2145,27 @@ No tab
% \end{macrocode}
% \end{macro}
%
+% \subsubsection{Undefined keys for \cs{foreachsc}}
+%
+% \begin{macro}{\@@_parse_foreach_keys:n,
+% \@@_parse_foreach_keys:nn}
+%
+% We check the \meta{keys} passed to command §\foreachsc§ and process
+% it with \cs{@@_parse_foreach_keys:n}, if the \mymeta{key} is
+% \emph{unknown} we return an error message.
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_parse_foreach_keys:nn #1#2
+ {
+ \tl_if_blank:nTF {#2}
+ { \msg_error:nnn { scontents } { for-key-unknown } {#1} }
+ { \msg_error:nnnn { scontents } { for-key-value-unknown } {#1} {#2} }
+ }
+\cs_new_protected:Npn \@@_parse_foreach_keys:n #1
+ { \exp_args:NV \@@_parse_foreach_keys:nn \l_keys_key_tl {#1} }
+% \end{macrocode}
+% \end{macro}
+%
% \subsubsection{Undefined keys for \cs{typestored} and \cs{meaningsc}}
%
% \begin{macro}{\@@_parse_type_meaning_key:n,
@@ -1963,6 +2206,112 @@ No tab
% \end{macrocode}
% \end{macro}
%
+% \subsection{Compatibility layer with Plain}
+%
+% When loading the package outside of \LaTeX{} we can't usually use \pkg{xparse}.
+% However since \pkg{xparse} doesn't actually hold any dependency with \LaTeX{}
+% except for package-loading commands, we can emulate those commands (much like
+% in \pkg{miniltx}) so that \pkg{xparse} is loadable in any format.
+%
+% The bunch of macros below is adapted from the \LaTeX{} kernel (greatly simplified).
+% \begin{macrocode}
+%</core>
+%<*loader&!latex>
+\seq_new:N \l_@@_compat_seq
+\cs_new_protected:Npn \@@_compat_redefine:Npn #1
+ {
+ \seq_put_right:Nn \l_@@_compat_seq {#1}
+ \cs_set_eq:cN { @@_saved_\cs_to_str:N #1: } #1
+ \cs_new_protected:Npn #1
+ }
+\cs_new_protected:Npn \@@_compat_restore:
+ { \seq_map_function:NN \l_@@_compat_seq \@@_compat_restore:N }
+\cs_new_protected:Npn \@@_compat_restore:N #1
+ {
+ \cs_set_eq:Nc #1 { @@_saved_\cs_to_str:N #1: }
+ \cs_undefine:c { @@_saved_\cs_to_str:N #1: }
+ }
+\cs_generate_variant:Nn \@@_compat_redefine:Npn { c }
+\cs_new_protected:Npn \@@_optarg:nn #1 #2
+ { \peek_charcode_ignore_spaces:NTF [ {#1} {#1[#2]} }
+\cs_new_protected:Npn \@@_stararg:nn #1 #2
+ { \peek_charcode_remove_ignore_spaces:NTF * {#1} {#2} }
+\@@_compat_redefine:Npn \RequirePackage
+ { \@@_optarg:nn { \@@_require_auxi:wn } { } }
+\cs_new_protected:Npn \@@_require_auxi:wn [#1] #2
+ { \@@_optarg:nn { \@@_require_auxii:wnw [{#1}]{#2} } { } }
+\cs_new:Npn \@@_zap_space:ww #1~#2
+ {
+ #1 \if_meaning:w #2 \q_mark
+ \exp_after:wN \use_none:n
+ \else:
+ \exp_after:wN \@@_zap_space:ww
+ \fi: #2
+ }
+\cs_new_protected:Npn \@@_require_auxii:wnw [#1] #2 [#3]
+ {
+ \tl_set:Nx \l_@@_temp_tl { \@@_zap_space:ww #2 ~ \q_mark }
+ \clist_map_function:NN \l_@@_temp_tl \@@_require_auxiii:n
+ }
+\cs_new_protected:Npn \@@_require_auxiii:n #1
+ { \str_if_eq:eeF {expl3} {#1} { \msg_error:nnn { scontents } { invalid-package } {#1} } }
+\msg_new:nnn { scontents } { invalid-package }
+ { Package~`#1'~invalid~in~scontents.~This~is~an~error~in~scontents. }
+\@@_compat_redefine:cpn { @ifpackagelater } #1
+ { \exp_args:Nc \@@_package_later_aux:Nn { ver@#1.sty } }
+\cs_new_protected:Npn \@@_package_later_aux:Nn #1 #2
+ {
+ \int_compare:nNnTF
+ { \exp_after:wN \@@_parse_version:w #1 //00 \q_mark } <
+ { \exp_after:wN \@@_parse_version:w #2 //00 \q_mark }
+ }
+\cs_new:Npn \@@_parse_version:w #1 { \@@_parse_version_auxi:w 0#1 }
+\cs_new:Npn \@@_parse_version_auxi:w #1/#2/#3#4#5 \q_mark
+ { \@@_parse_version_auxii:w #1-#2-#3#4 \q_mark }
+\cs_new:Npn \@@_parse_version_auxii:w #1-#2-#3#4#5 \q_mark
+ { \tl_if_blank:nF {#2} {#1} #2 #3 #4 }
+\@@_compat_redefine:Npn \ProvidesExplPackage #1 #2 #3 #4
+ { \@@_provides_aux:nn {#1} { #2 \ifx\relax#3\relax\else v#3\space\fi #4 } }
+\cs_new_protected:Npn \@@_provides_aux:nn #1 #2
+ {
+ \tl_gset:cx { ver@#1.sty } {#2}
+ \iow_log:n { Package~#1:~#2 }
+ \ExplSyntaxOn
+ }
+\@@_compat_redefine:Npn \DeclareOption
+ { \@@_stararg:nn { \use_none:n } { \use_none:nn } }
+\@@_compat_redefine:Npn \ProcessOptions
+ { \@@_stararg:nn { } { } }
+% \end{macrocode}
+%
+% Now that the compatibility layer is defined, we can finally load \pkg{xparse}.
+% \pkg{xparse} expects to be loaded with \cs{ExplSyntaxOff} (not much harm would
+% be done otherwise, but just to be on the safe side).
+%
+% Within \pkg{xparse} a §\RequirePackage{expl3}§ is done. We can ignore that since
+% we have already loaded \pkg{expl3}. Next, a §\@ifpackagelater§ test is done:
+% we do that test too to ensure that \pkg{xparse} is compatible with the current
+% running version of \pkg{expl3}. The following §\ProvidesExplPackage§ simply
+% defines §\ver@xparse.sty§ for any other package that might uset it, and then
+% does \cs{ExplSyntaxOn}. At the end of the package, \pkg{xparse} parses (heh)
+% the package options. Since we don't have those in non-\LaTeX{} formats, they are
+% ignored. Okay, so load \pkg{xparse}:
+% \begin{macrocode}
+\int_set:Nn \l_@@_tmpa_int { \char_value_catcode:n { `\@ } }
+\char_set_catcode_letter:N \@
+\exp_after:wN
+\ExplSyntaxOff
+\file_input:n { xparse.sty }
+\ExplSyntaxOn
+\char_set_catcode:nn { `\@ } { \l_@@_tmpa_int }
+\@@_compat_restore:
+%</loader&!latex>
+%<*core>
+% \end{macrocode}
+% (actually we don't need to do \cs{ExplSyntaxOn} there because we don't have
+% \LaTeX{}'s full package loading mechanism, so the \pkg{expl3} syntax remains
+% active after \pkg{xparse} is loaded, but it doesn't harm either).
+%
% \subsection{Programming of the sequences}
%
% The storage of the package is done using |seq| variables. Here we
@@ -2013,7 +2362,7 @@ No tab
%
% \begin{macro}{\@@_lastfrom_seq:n}
% \cs{@@_lastfrom_seq:n} retrieves the last saved item from the
-% sequence when \cs{l_@@__print_env_bool} or \cs{l_@@__print_cmd_bool}
+% sequence when \cs{l_@@_print_env_bool} or \cs{l_@@_print_cmd_bool}
% is true.
%
% \begin{macrocode}
@@ -2048,15 +2397,39 @@ No tab
% is divided into three parts. This implementation is taken from answer
% by Enrico Gregorio in \url{https://tex.stackexchange.com/a/487746/7832}.
%
-% \begin{macro}{scontents}
+% \begin{macro}{
+% scontents,
+% \scontents,
+% \startscontents,
+% \endscontents,
+% \stopscontents,
+% \@@_scontents_env_begin:,
+% \@@_scontents_env_end:,
+% }
% This is the main environment used in the document.
%
% \begin{macrocode}
-\NewDocumentEnvironment { scontents } { }
+%</core>
+%<*loader>
+%<!context>\NewDocumentEnvironment { scontents } { }
+%<context>\cs_new_protected:Npn \startscontents
+ {
+%<plain|context> \group_begin:
+ \@@_scontents_env_begin:
+ }
+%<context>\cs_new_protected:Npn \stopscontents
+ {
+ \@@_scontents_env_end:
+%<plain|context> \group_end:
+ }
+%</loader>
+%<*core>
+\cs_new_protected:Npn \@@_scontents_env_begin:
{
\char_set_catcode_active:N \^^M
\@@_start_environment:w
}
+\cs_new_protected:Npn \@@_scontents_env_end:
{
\@@_stop_environment:
\@@_atend_environment:
@@ -2069,54 +2442,58 @@ No tab
% Define a \myoarg{key \textnormal{\textcolor{gray}{=}} val} for
% environment \env{scontents}
%
-% \begin{macro}{\@@_environment_inline:w,\@@_environment_keys:w,
-% \@@_environment_junk:nw,\@@_environment_junk:xw}
-% The macro \cs{@@_environment_inline:w} is called from the
+% \begin{macro}{\@@_grab_optional:n,\@@_grab_optional:w}
+% The macro \cs{@@_grab_optional:w} is called from the
% \env{scontents} environment with the tokens following the
-% §\begin{scontents}§. If the immediate next token (ignoring spaces)
-% is a §[§, then we look for an optional argument delimited by a §]§.
-% All the remaining tokens are treated as junk and an error is raised
-% if they are non-blank.
+% §\begin{scontents}§ when the next character is a §[§. This function
+% is defined using \mypkg{xparse} to exploit its delimited argument
+% processor.
%
+% The function is called from a context where §^^M§ is active, so
+% \cs{@@_normalise_line_ends:N} is used to replace active §^^M§
+% characters by spaces.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_environment_inline:w
+%</core>
+%<*loader>
+\NewDocumentCommand \@@_grab_optional:w { r[] }
+ { \@@_grab_optional:n {#1} }
+%</loader>
+%<*core>
+\cs_new_protected:Npn \@@_grab_optional:n #1
{
- \peek_charcode_ignore_spaces:NTF [ % ]
- { \@@_environment_keys:w }
+ \tl_if_novalue:nF {#1}
{
- \@@_environment_junk:xw
- { after~\c_backslash_str begin{scontents} }
+ \tl_set:Nn \l_@@_temp_tl {#1}
+ \@@_normalise_line_ends:N \l_@@_temp_tl
+ \keys_set:nV { scontents / scontents } \l_@@_temp_tl
}
+ \@@_start_after_option:w
}
-\cs_new_protected:Npn \@@_environment_keys:w [ #1 ]
- {
- \keys_set:nn { scontents / scontents } {#1}
- \@@_environment_junk:xw
- { after~optional~argument~to~\c_backslash_str begin{scontents} }
- }
-\cs_new_protected:Npn \@@_environment_junk:nw #1 #2 \q_@@_mark
- {
- \tl_if_blank:nF {#2}
- { \msg_error:nnnn { scontents } { junk-after-begin } {#1} {#2} }
- }
-\cs_generate_variant:Nn \@@_environment_junk:nw { x }
% \end{macrocode}
% \end{macro}
%
% \subsubsection{The environment itself}
%
-% \begin{macro}{\@@_start_environment:w,\@@_stop_environment:}
+% \begin{macro}{\@@_start_environment:w,\@@_start_after_option:w,
+% \@@_check_line_and_process:xn,\@@_stop_environment:}
% Here we make §^^I§, §^^L§ and §^^M§ active characters so that the end of
% line can be \enquote{seen} to be used as a delimiter, and \hologo{TeX} doesn't try to
-% eliminate space-like characters. First we check if the line
-% directly after §\begin{scontents}§ contains an optional argument
-% enclosed in §[...]§ or other tokens. The trailing tokens are
-% treated as junk and an error is raised. The
-% \cs{@@_environment_inline:w} macro checks for those cases.
+% eliminate space-like characters.
+%
+% First we check if the immediate next token after §\begin{scontents}§
+% is a §[§. If it is, then \cs{@@_grab_optional:w} is called
+% to do the heavy lifting. \cs{@@_grab_optional:w} processes the optional
+% argument and calls \cs{@@_start_after_option:w}.
%
-% \cs{@@_start_environment:w} calls the \cs{@@_file_tl_write_start:V}
-% function, which will then read the contents of the environment and
-% optionally store them in a token list or write to an external file.
+% \cs{@@_start_after_option:w} also checks for trailing tokens after
+% the optional argument and issues an error if any.
+%
+% In all cases \cs{@@_check_line_and_process:xn} is called to check that
+% the rest of the §\begin{scontents}§ is empty and then process
+% the environment. \cs{@@_check_line_and_process:xn} calls the
+% \cs{@@_file_tl_write_start:V} function, which will then read the contents
+% of the environment and optionally store them in a token list or write to
+% an external file.
%
% When that's done, \cs{@@_file_write_stop:N} does the cleanup and the
% read token list is smuggled out of the verbatim group. This part of
@@ -2132,9 +2509,27 @@ No tab
\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
{
- \@@_environment_inline:w #1 \q_@@_mark
+ \tl_if_head_is_N_type:nTF {#1}
+ {
+ \str_if_eq:eeTF { \tl_head:n {#1} } { [ }
+ { \@@_grab_optional:w #1 ^^M }
+ { \@@_check_line_and_process:xn { } {#1} }
+ }
+ { \@@_check_line_and_process:xn { } {#1} }
+ }
+ \cs_new_protected:Npn \@@_start_after_option:w #1 ^^M
+ { \@@_check_line_and_process:xn { [...] } {#1} }
+ \cs_new_protected:Npn \@@_check_line_and_process:xn #1 #2
+ {
+ \tl_if_blank:nF {#2}
+ {
+ \msg_error:nnxn { scontents } { junk-after-begin }
+ { after~\c_backslash_str begin{scontents} #1 } {#2}
+ }
\@@_make_control_chars_active:
\group_begin:
\@@_file_tl_write_start:V \l_@@_fname_out_tl
@@ -2145,6 +2540,8 @@ No tab
\exp_args:NNNV
\group_end:
\tl_set:Nn \l_@@_macro_tmp_tl \l_@@_macro_tmp_tl
+ \tl_if_empty:NT \l_@@_macro_tmp_tl
+ { \msg_warning:nnn { scontents } { empty-environment } }
}
% \end{macrocode}
% \end{macro}
@@ -2217,7 +2614,10 @@ No tab
{ \@@_verb_processor_output:n {#1} }
\cs_set_protected:Npx \@@_ret:w
{
- \exp_not:N \end{scontents}
+ \@@_format_case:nnn
+ { \exp_not:N \end{scontents} } % LaTeX
+ { \endscontents } % Plain/Generic
+ { \stopscontents } % ConTeXt
\bool_lazy_or:nnF
{ \tl_if_blank_p:n {#2} }
{ \str_if_eq_p:ee {#2} { \c_percent_str } }
@@ -2246,7 +2646,21 @@ No tab
}
}
\cs_new:Npn \@@_remove_leading_nl:n #1
- { \exp_not:o { \@@_remove_leading_nl:w #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}
@@ -2344,15 +2758,87 @@ No tab
{ \@@_lastfrom_seq:n \l_@@_name_seq_env_tl }
}
}
+%</core>
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\verbatim,\endverbatim}
+% In Plain we emulate \LaTeX's \env{verbatim} environment.
+% \begin{macrocode}
+%<*plain>
+\bool_new:N \l_@@_temp_bool
+\cs_new_protected:Npn \verbatim
+ { \@@_verbatim_aux: \frenchspacing \@@_vobeyspaces: \@@_xverb: }
+\cs_new_protected:Npn \@@_verbatim_aux:
+ {
+ \skip_vertical:N \parskip
+ \int_set:Nn \parindent { 0pt }
+ \skip_set:Nn \parfillskip { 0pt plus 1fil }
+ \int_set:Nn \parskip { 0pt plus0pt minus0pt }
+ \tex_par:D
+ \bool_set_false:N \l_@@_temp_bool
+ \cs_set:Npn \par
+ {
+ \bool_if:NTF \l_@@_temp_bool
+ {
+ \mode_leave_vertical:
+ \null
+ \tex_par:D
+ \penalty \interlinepenalty
+ }
+ {
+ \bool_set_true:N \l_@@_temp_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:wN
+ { \tex_the:D \tex_everypar:D \tex_unpenalty:D }
+ }
+\cs_new_protected:Npn \@@_nolig_list:
+ { \do\`\do\<\do\>\do\,\do\'\do\- }
+\cs_new_protected:Npn \@@_vobeyspaces:
+ { \@@_set_active_eq:NN \ \@@_xobeysp: }
+\cs_new_protected:Npn \@@_xobeysp:
+ { \mode_leave_vertical: \nobreak \ }
+%</plain>
% \end{macrocode}
% \end{macro}
%
-% \subsection{The \cs{Scontents} command}
+% \begin{macro}[int]{\dospecials}
+% \pkg{xparse} also requires \LaTeX's \cs{dospecials}. In case it doesn't
+% exist (at the time \pkg{scontents} is loaded) we define \cs{dospecials}
+% to use the \cs{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 }
+ }
+%</!latex>
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{The command \cs{Scontents}}
%
% User command to \mymeta{stored content}, adapted from
% \url{https://tex.stackexchange.com/a/500281/7832}.
%
-% \begin{macro}{\Scontents,\@@_norm_arg:n,\@@_verb_arg:w}
+% \begin{macro}{
+% \Scontents,
+% \@@_norm_arg:n,
+% \@@_Scontents_auxi:N,
+% \Scontents code,
+% \@@_Scontents_internal:nn,
+% \@@_verb_arg:w,
+% \@@_verb_arg_internal:n,
+% }
% The §\Scontents§ macro starts by parsing an optional argument and
% then delegates to \cs{@@_verb_arg:w} or \cs{@@_norm_arg:n} depending whether
% a star (§*§) argument is present.
@@ -2364,13 +2850,18 @@ No tab
% argument parser.
%
% \begin{macrocode}
+%<*loader>
\NewDocumentCommand { \Scontents }{ !s !O{} }
+ { \@@_Scontents_internal:nn {#1} {#2} }
+%</loader>
+%<*core>
+\cs_new_protected:Npn \@@_Scontents_internal:nn #1 #2
{
\group_begin:
- \IfNoValueF {#2}
+ \tl_if_novalue:nF {#2}
{ \keys_set:nn { scontents / Scontents } {#2} }
\char_set_catcode_active:n { 9 }
- \IfBooleanTF {#1}
+ \bool_if:NTF #1
{ \@@_verb_arg:w }
{ \@@_norm_arg:n }
}
@@ -2383,7 +2874,13 @@ No tab
{ \@@_lastfrom_seq:n \l_@@_name_seq_cmd_tl }
\group_end:
}
+%</core>
+%<*loader>
\NewDocumentCommand { \@@_verb_arg:w } { +v }
+ { \@@_verb_arg_internal:n {#1} }
+%</loader>
+%<*core>
+\cs_new_protected:Npn \@@_verb_arg_internal:n #1
{
\tl_set:Nx \l_@@_temp_tl { \exp_not:n {#1} }
\tl_replace_all:Nxx \l_@@_temp_tl { \iow_char:N \^^M } { \iow_char:N \^^J }
@@ -2404,9 +2901,16 @@ No tab
% (robust).
%
% \begin{macrocode}
+%</core>
+%<*loader>
\NewDocumentCommand { \getstored } { O{1} m }
+ { \@@_getstored_internal:nn {#1} {#2} }
+%</loader>
+%<*core>
+\cs_new_protected:Npn \@@_getstored_internal:nn #1 #2
{
\group_begin:
+ \int_set:Nn \tex_newlinechar:D { `\^^J }
\@@_rescan_tokens:x
{ \@@_getfrom_seq:nn {#1} {#2} }
\group_end:
@@ -2414,7 +2918,55 @@ No tab
% \end{macrocode}
% \end{macro}
%
-% \subsection{The \cs{typestored} command}
+% \subsection{The command \cs{foreachsc}}
+%
+% \begin{macro}{\foreachsc}
+% User command §\foreachsc§ to loop over \mymeta{stored content} in |seq|.
+%
+% \begin{macrocode}
+%</core>
+%<*loader>
+\NewDocumentCommand { \foreachsc } { o m }
+ { \@@_foreachsc_internal:nn {#1} {#2} }
+%</loader>
+%<*core>
+\cs_new_protected:Npn \@@_foreachsc_internal:nn #1 #2
+ {
+ \group_begin:
+ \tl_if_novalue:nF {#1} { \keys_set:nn { scontents / foreachsc } {#1} }
+ \tl_set:Nn \l_@@_foreach_name_seq_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:c { g_@@_name_#2_seq } }
+ }
+ \int_step_function:nnnN
+ { \l_@@_foreach_start_int }
+ { \l_@@_foreach_step_int }
+ { \l_@@_foreach_stop_int }
+ \@@_foreach_add_body:n
+ \seq_use:Nn \l_@@_foreach_print_seq { \tl_use:N \l_@@_foreach_sep_tl }
+ \group_end:
+ }
+\cs_new_protected:Npn \@@_foreach_add_body:n #1
+ {
+ \seq_put_right:Nx \l_@@_foreach_print_seq
+ {
+ \bool_if:NT \l_@@_foreach_before_bool
+ { \exp_not:V \l_@@_foreach_before_tl }
+ \bool_if:NTF \l_@@_foreach_wrapper_bool
+ { \@@_foreach_wrapper:n }
+ { \use:n }
+ { \getstored [#1] { \tl_use:N \l_@@_foreach_name_seq_tl } }
+ \bool_if:NT \l_@@_foreach_after_bool
+ { \exp_not:V \l_@@_foreach_after_tl }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{The command \cs{typestored}}
%
% This implementation is an adaptation taken from answer by Phelype Oleinik
% in (\url{https://tex.stackexchange.com/a/497651/7832}).
@@ -2424,15 +2976,19 @@ No tab
% to the log file, and then calls \cs{@@_verb_print:N}.
%
% \begin{macrocode}
+%</core>
+%<*loader>
\NewDocumentCommand { \typestored } { o m }
+ { \@@_typestored_internal:nn {#1} {#2} }
+%</loader>
+%<*core>
+\cs_new_protected:Npn \@@_typestored_internal:nn #1 #2
{
\group_begin:
\int_set:Nn \l_@@_seq_item_int { 1 }
- \IfValueT {#1} { \keys_set:nn { scontents / typemeaning } {#1} }
+ \tl_if_novalue:nF {#1} { \keys_set:nn { scontents / typemeaning } {#1} }
\tl_set:Nx \l_@@_temp_tl
- {
- \exp_args:NV \@@_getfrom_seq:nn \l_@@_seq_item_int {#2}
- }
+ { \exp_args:NV \@@_getfrom_seq:nn \l_@@_seq_item_int {#2} }
\tl_remove_once:NV \l_@@_temp_tl \c_@@_hidden_space_str
\tl_log:N \l_@@_temp_tl
\tl_if_empty:NF \l_@@_temp_tl
@@ -2456,9 +3012,14 @@ No tab
\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 }
\@@_rescan_tokens:x
{
- \exp_not:N \begin{verbatimsc} ^^M
+ \@@_format_case:nnn
+ { \exp_not:N \begin{verbatimsc} } % LaTeX
+ { \verbatimsc } % Plain/Generic
+ { \startverbatimsc } % ConTeXt
+ ^^M
\exp_not:V #1 ^^M
\g_@@_end_verbatimsc_tl
}
@@ -2476,18 +3037,30 @@ No tab
\char_set_active_eq:nN { 9 } \@@_tabs_to_spaces:
\@@_xverb:w
}
+%</core>
+%<*loader>
\use:x
{
\cs_new_protected:Npn \exp_not:N \@@_xverb:w
##1 \g_@@_end_verbatimsc_tl
+%<latex> { ##1 \exp_not:N \end{verbatimsc} }
+%<plain> { ##1 \exp_not:N \endverbatimsc }
+%<context> { ##1 \exp_not:N \stopverbatimsc }
}
- { #1 \end{verbatimsc} }
+%<*!context>
\NewDocumentEnvironment { verbatimsc } { }
{
- \cs_set_eq:cN { @xverbatim } \@@_xverb:
+%<plain> \group_begin:
+%<latex> \cs_set_eq:cN { @xverbatim } \@@_xverb:
\verbatim
}
- { }
+ {
+%<plain> \group_end:
+ }
+%</!context>
+%<context>\definetyping[verbatimsc]
+%</loader>
+%<*core>
% \end{macrocode}
% \end{macro}
%
@@ -2532,19 +3105,42 @@ No tab
% \@@_make_control_chars_active:,
% }
% Shortcut definitions for common catcode changes.
-%
+% The §^^L§ needs a special treatment in non-\LaTeX{} mode
+% because in Plain\,\TeX{} it is an \cs{outer} token.
% \begin{macrocode}
\cs_new_protected:Npn \@@_set_active_eq:NN #1
{
\char_set_catcode_active:N #1
\char_set_active_eq:NN #1
}
-\cs_new_protected:Npn \@@_make_control_chars_active:
- {
- \@@_set_active_eq:NN \^^I \@@_tab:
- \@@_set_active_eq:NN \^^L \@@_par:
- \@@_set_active_eq:NN \^^M \@@_ret:w
- }
+%</core>
+%<*loader>
+\group_begin:
+%<plain> \char_set_catcode_active:n { `\* }
+ \cs_new_protected:Npn \@@_plain_disable_outer_par:
+%<*plain>
+ {
+ \group_begin:
+ \char_set_lccode:nn { `\* } { `\^^L }
+ \tex_lowercase:D { \group_end:
+ \tex_let:D * \scan_stop:
+ }
+ }
+%</plain>
+%<latex|context> { }
+\group_end:
+%</loader>
+%<*core>
+\group_begin:
+ \char_set_catcode_active:N \*
+ \cs_new_protected:Npn \@@_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
+ }
+\group_end:
% \end{macrocode}
% \end{macro}
%
@@ -2556,22 +3152,32 @@ No tab
% A user-level wrapper for \cs{keys_set:nn}§{ scontents }§.
%
% \begin{macrocode}
+%</core>
+%<*loader>
\NewDocumentCommand { \setupsc } { +m }
{ \keys_set:nn { scontents } {#1} }
+%</loader>
+%<*core>
% \end{macrocode}
% \end{macro}
%
-% \subsection{The command meaningsc}
+% \subsection{The command \cs{meaningsc}}
%
% \begin{macro}{\meaningsc}
% User command §\meaningsc§ to see content stored in |seq|.
%
% \begin{macrocode}
+%</core>
+%<*loader>
\NewDocumentCommand { \meaningsc } { o m }
+ { \@@_meaningsc_internal:nn {#1} {#2} }
+%</loader>
+%<*core>
+\cs_new_protected:Npn \@@_meaningsc_internal:nn #1 #2
{
\group_begin:
\int_set:Nn \l_@@_seq_item_int { 1 }
- \IfValueT {#1} { \keys_set:nn { scontents / typemeaning } {#1} }
+ \tl_if_novalue:nF {#1} { \keys_set:nn { scontents / typemeaning } {#1} }
\@@_meaningsc:n {#2}
\group_end:
}
@@ -2580,9 +3186,7 @@ No tab
\cs_new_protected:Npn \@@_meaningsc:n #1
{
\tl_set:Nx \l_@@_temp_tl
- {
- \exp_args:NV \@@_getfrom_seq:nn \l_@@_seq_item_int {#1}
- }
+ { \exp_args:NV \@@_getfrom_seq:nn \l_@@_seq_item_int {#1} }
\tl_replace_all:Nxn \l_@@_temp_tl { \iow_char:N \^^J } { ~ }
\tl_remove_once:NV \l_@@_temp_tl \c_@@_hidden_space_str
\tl_log:N \l_@@_temp_tl
@@ -2601,8 +3205,12 @@ No tab
% User command §\countsc§ to count number of contents stored in |seq|.
%
% \begin{macrocode}
+%</core>
+%<*loader>
\NewExpandableDocumentCommand { \countsc } { m }
{ \seq_count:c { g_@@_name_#1_seq } }
+%</loader>
+%<*core>
% \end{macrocode}
% \end{macro}
%
@@ -2613,8 +3221,12 @@ No tab
% A user command §\cleanseqsc§ to clear (remove) a defined |seq|.
%
% \begin{macrocode}
+%</core>
+%<*loader>
\NewDocumentCommand { \cleanseqsc } { m }
{ \seq_clear_new:c { g_@@_name_#1_seq } }
+%</loader>
+%<*core>
% \end{macrocode}
% \end{macro}
%
@@ -2677,6 +3289,18 @@ No tab
The~command~'\c_backslash_str Scontents'~does~not~have~a~key~called~'#1'.\\
Check~that~you~have~spelled~the~key~name~correctly.
}
+\msg_new:nnnn { scontents } { for-key-unknown }
+ { The~key~'#1'~is~unknown~by~'\c_backslash_str foreachsc'~and~is~being~ignored.}
+ {
+ The~command~'\c_backslash_str foreachsc'~does~not~have~a~key~called~'#1'.\\
+ Check~that~you~have~spelled~the~key~name~correctly.
+ }
+\msg_new:nnnn { scontents } { for-key-value-unknown }
+ { The~key~'#1=#2'~is~unknown~by~'\c_backslash_str foreachsc'~and~is~being~ignored. }
+ {
+ The~command~'\c_backslash_str foreachsc'~does~not~have~a~key~called~'#1'.\\
+ Check~that~you~have~spelled~the~key~name~correctly.
+ }
\msg_new:nnnn { scontents } { type-key-unknown }
{ The~key~'#1'~is~unknown~and~is~being~ignored. }
{
@@ -2689,6 +3313,27 @@ No tab
This~command~does~not~have~a~key~called~'#1'.\\
This~command~only~accepts~the~key~'width-tab'.
}
+\msg_new:nnn { scontents } { empty-environment }
+ { scontents~environment~empty~\msg_line_context:. }
+\msg_new:nnnn { scontents } { verbatim-newline }
+ { Verbatim~argument~of~#1~ended~by~end~of~line. }
+ {
+ The~verbatim~argument~of~the~#1~cannot~contain~more~than~one~line,~
+ but~the~end~
+ of~the~current~line~has~been~reached.~You~may~have~forgotten~the~
+ closing~delimiter.
+ \\ \\
+ LaTeX~will~ignore~'#2'.
+ }
+\msg_new:nnnn { scontents } { verbatim-tokenized }
+ { The~verbatim~#1~cannot~be~used~inside~an~argument. }
+ {
+ The~#1~takes~a~verbatim~argument.~
+ It~may~not~appear~within~the~argument~of~another~function.~
+ It~received~an~illegal~token \tl_if_empty:nF {#3} { ~'#3' } .
+ \\ \\
+ LaTeX~will~ignore~'#2'.
+ }
% \end{macrocode}
%
% \subsection{Finish package}
@@ -2696,9 +3341,7 @@ No tab
% Finish package implementation.
%
% \begin{macrocode}
-\file_input_stop:
+%</core>
+%<plain|context>\ExplSyntaxOff
% \end{macrocode}
-% \iffalse
-%</package>
-% \fi
% \Finale