diff options
author | Karl Berry <karl@freefriends.org> | 2024-08-29 20:39:45 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2024-08-29 20:39:45 +0000 |
commit | 5356980faaec739ffb82f2f950a10257aef9a77d (patch) | |
tree | 3fbf6e9e8097f492ab51a5945c3cb0eef0dc87e6 /Master/texmf-dist/source | |
parent | 6e0931c360d843dca63b865645eee56357719006 (diff) |
enverb (29aug24)
git-svn-id: svn://tug.org/texlive/trunk@72137 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source')
-rw-r--r-- | Master/texmf-dist/source/latex/enverb/enverb.dtx | 720 |
1 files changed, 720 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/enverb/enverb.dtx b/Master/texmf-dist/source/latex/enverb/enverb.dtx new file mode 100644 index 00000000000..a33dc713d70 --- /dev/null +++ b/Master/texmf-dist/source/latex/enverb/enverb.dtx @@ -0,0 +1,720 @@ +% \iffalse meta-comment +% +% File: enverb.dtx Copyright (C) 2023-2024 Jonathan P. Spratte +% +% This work may be distributed and/or modified under the conditions of the +% LaTeX Project Public License (LPPL), either version 1.3c of this license or +% (at your option) any later version. The latest version of this license is in +% the file: +% +% http://www.latex-project.org/lppl.txt +% +% ------------------------------------------------------------------------------ +% +%<*driver>^^A>>= +\def\nameofplainTeX{plain} +\ifx\fmtname\nameofplainTeX\else + \expandafter\begingroup +\fi +\input l3docstrip.tex +\askforoverwritefalse +\preamble + +-------------------------------------------------------------- +enverb -- read an environment verbatim +E-mail: jspratte@yahoo.de +Released under the LaTeX Project Public License v1.3c or later +See http://www.latex-project.org/lppl.txt +-------------------------------------------------------------- + +Copyright (C) 2023-2024 Jonathan P. Spratte + +This work may be distributed and/or modified under the conditions of the +LaTeX Project Public License (LPPL), either version 1.3c of this license or +(at your option) any later version. The latest version of this license is in +the file: + + http://www.latex-project.org/lppl.txt + +This work is "maintained" (as per LPPL maintenance status) by + Jonathan P. Spratte. + +This work consists of the files enverb.dtx + enverb-doc.tex +and the derived files enverb-doc.pdf + enverb.sty + +\endpreamble +\postamble +\endpostamble +\generate{\file{enverb.sty}{\from{enverb.dtx}{pkg}}} +\ifx\fmtname\nameofplainTeX + \expandafter\endbatchfile +\else + \expandafter\endgroup +\fi +%</driver>^^A=<< +% \fi +% +% \gobbledocstriptag +%<*pkg> +% +% \subsection{Who we are} +% +% \begin{macro}[internal]{\enverb@date,\enverb@version} +% We store the package version and date inside macros. +% \begin{macrocode} +\newcommand*\enverb@date{2024-08-28} +\newcommand*\enverb@version{1.0} +% \end{macrocode} +% \end{macro} +% +% And the package identification: +% \begin{macrocode} +\ProvidesPackage{enverb} + [\enverb@date\space v\enverb@version\space read an environment verbatim] +% \end{macrocode} +% +% \subsection{Some required \LaTeXe\ style argument grabbers} +% \begin{macro}[internal]{\@thirdofthree,\@firstofnine} +% This here are just two argument grabbers that aren't defined in all versions +% of \LaTeXe. +% \begin{macrocode} +\providecommand\@thirdofthree[3]{#3} +\providecommand\@firstofnine[9]{#1} +% \end{macrocode} +% \end{macro} +% +% \subsection{Borrow some code} +% \begin{macro}[internal] +% {\enverb@count,\enverb@ifxTF,\enverb@chargen,\enverb@othercr} +% We'll make use of the following two \pkg{expl3} functions, but since the +% remainder of this package is coded in \LaTeXe\ style we stick to that. +% \begin{macrocode} +\ExplSyntaxOn +\cs_new_eq:NN \enverb@count \tl_count:n +\cs_new_eq:NN \enverb@ifxTF \token_if_eq_meaning:NNTF +\cs_new_eq:NN \enverb@chargen \char_generate:nn +\cs_set:Npx \enverb@othercr { \char_generate:nn {13} {12} } +\ExplSyntaxOff +% \end{macrocode} +% \end{macro} +% +% \subsection{Key-value Setup} +% First we need to load a package to allow us defining our keys, then we define +% a bunch of keys: +% \begin{macrocode} +\RequirePackage{expkv-def} +% \end{macrocode} +% +% \begin{macrocode} +\ekvdefinekeys{enverb} + { + protect code ignore = \let\enverb@ifautoignore\@secondoftwo + ,also eint ignore = \enverb@ignore + ,boolTF auto-ignore = \enverb@ifautoignore + ,initial auto-ignore + ,eint more-ignore = \enverb@moreignore + ,initial more-ignore = 2 + ,long store bol = \enverb@bol@content + ,long code bol+ = \enverb@add\enverb@bol@content{#1} + ,long code +bol = \enverb@pre\enverb@bol@content{#1} + ,long store eol = \enverb@eol@content + ,einitial eol = \enverb@othercr + ,long code eol+ = \enverb@add\enverb@eol@content{#1} + ,long code +eol = \enverb@pre\enverb@eol@content{#1} + ,protect code key-handler = \protected\long\def\enverb@keyhandler##1{#1} + ,protect code key-set = \protected\long\ekvsetdef\enverb@keyhandler{#1} + ,unknown code = \enverb@add\enverb@unknown@kv{, {#3} = {#2} } + ,unknown noval = \enverb@add\enverb@unknown@kv{, {#2} } + ,boolTF oarg-not-enverb = \enverb@ifoargtokeyhandler + } +% \end{macrocode} +% \begin{macro}{\enverbsetup} +% We need a user facing macro to set our keys. +% \begin{macrocode} +\protected\long\ekvsetdef\enverbsetup{enverb} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\enverb@unknown@kv} +% This is a storage for all unknown keys encountered. +% \begin{macrocode} +\let\enverb@unknown@kv\@empty +% \end{macrocode} +% \end{macro} +% +% \subsection{Miscellaneous Auxiliary Functions} +% +% \begin{macro}[internal]{\enverb@stop} +% A very simple minded stop-macro, just gobble up to the eponymous mark. +% \begin{macrocode} +\long\def\enverb@stop#1\enverb@stop{} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\enverb@error} +% \begin{macrocode} +\protected\def\enverb@error{\PackageError{enverb}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\enverb@misused} +% This is an error message that'd be used inside a |\lowercase| environment if +% put where it originally should've been. Hence we define it now to get +% correct formatting. +% \begin{macrocode} +\protected\def\enverb@misused + {% + \enverb@error + {Misused \string\enverb. Input already tokenised}% + {% + It seems you used the \string\enverb\space based environment + {\@currenvir} inside another\MessageBreak + macro's or a primitive's argument; that doesn't work.% + }% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\enverb@keyhandler, \enverb@keyhandler@} +% This is the initial definition of the handler for unknown keys, namely throw +% an error containing the list of unknown keys. +% \begin{macrocode} +\protected\long\def\enverb@keyhandler#1% + {% + \if\relax\detokenize{#1}\relax + \expandafter\@gobbletwo + \fi + \@firstofone + {% + \enverb@error + {% + Unknown keys encountered: + \expanded + {% + \ekvparse + {\MessageBreak\@spaces\unexpanded}% + {\MessageBreak\@spaces\enverb@keyhandler@}% + {#1}% + }% + \@gobble + }% + {% + Perhaps you misspelled some key names? Or you forgot to set up + custom key\MessageBreak + parsing.% + }% + }% + } +\long\def\enverb@keyhandler@#1{\unexpanded{#1} = \unexpanded} +% \end{macrocode} +% \end{macro} +% +% \subsection{Collector} +% +% Much of the code in this package works under a weird category code regime, +% which the following sets up. After this |~| will be an active newline +% character, |:| will be an active space, and |;| will be an active tab. +% \begin{macrocode} +\begingroup +\lccode`\~=`\^^M +\catcode`\:=13 +\lccode`\:=`\ % <- space +\catcode`\;=13 +\lccode`\;=`\^^I % <- tab +\lowercase{\endgroup +% \end{macrocode} +% +% \begin{macro}[internal] +% {\enverb@body@space,\enverb@body@tab,\enverb@body@newline,\enverb@collect} +% To quickly check whether a line contains only spaces or tabs we define them +% as empty, that way we can remove them simply by one step of |\romannumeral| +% expansion. The newlines on the other hand grab the entire next line, check +% whether the matching |\end| is encountered, and if not leave the contents +% in |\unexpanded|. This grabbing is not done by the newline characters +% directly, but instead via |\enverb@collect| so that low level errors are +% easier to understand. +% \begin{macrocode} +\def\enverb@body@space{} +\def\enverb@body@tab{} +\def\enverb@body@newline{\enverb@collect} +\def\enverb@collect#1~% + {\enverb@ifnotend{#1}{\enverb@bol\unexpanded{#1}\enverb@eol\enverb@collect}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\enverbBody} +% \begin{macro}[internal]{\enverb@body@setup} +% This function sets up the entire category code regime and initial +% assignments of special tokens. +% \begin{macrocode} +\protected\def\enverb@body@setup + {% + \let\enverbBody\@empty + \let\do\@makeother\dospecials + \endlinechar=`\^^M + \catcode`\^^M=13 \let~\enverb@body@newline + \catcode`\ =13 \let:\enverb@body@space + \catcode`\^^I=13 \let;\enverb@body@tab + \let\enverb@bol\relax + \let\enverb@eol\relax + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[internal] +% { +% \enverb@ifxanyTF, \enverb@ifxanyTF@, \enverb@ifxanyTF@ifdone, +% \enverb@ifxanyTF@F, \enverb@ifxanyTF@T +% } +% This function provides a loop to check a list of symbols whether any of them +% matches the meaning of the first argument. +% \begin{macrocode} +\long\def\enverb@ifxanyTF#1#2% + {\enverb@ifxanyTF@#1#2\enverb@ifxanyTF@} +\long\def\enverb@ifxanyTF@#1#2% + {% + \enverb@ifxanyTF@ifdone#2\enverb@ifxanyTF@F\enverb@ifxanyTF@ + \enverb@ifxTF#1#2\enverb@ifxanyTF@T{\enverb@ifxanyTF@#1}% + } +\long\def\enverb@ifxanyTF@ifdone#1\enverb@ifxanyTF@{} +\long\def\enverb@ifxanyTF@F + \enverb@ifxanyTF@\enverb@ifxTF#1\enverb@ifxanyTF@T#2#3#4% + {#4} +\long\def\enverb@ifxanyTF@T#1\enverb@ifxanyTF@#2#3{#2} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\enverb@search@oarg@a, \enverb@search@oarg@ifx} +% This function shall search for the optional argument. The first case is +% rather easy, namely we check for a space (remember that |:| is an active +% space character in the current context). If this isn't the first line (so +% the line containing the |\begin| statement) that space is added to the body +% and searching continues.\par +% Next repeat the same logic but for an active tab (|;|). Afterwards we check +% for an active newline (|~|) which if found sets the conditional for the +% first line to false, still applying the same logic otherwise.\par +% Lastly we check for the open bracket. If it's found we collect our optional +% argument, otherwise the body starts, which is either an illegal character +% immediately following the |\begin| line, or we normally collect the body. +% +% \begin{macrocode} +\def\enverb@search@oarg@ifx#1#2% + {% + \enverb@ifxTF#1\@let@token + {% + \ifenverb@firsteol#2\else\enverb@body@add{#1}\fi + \enverb@search@oarg@b + }% + } +\protected\def\enverb@search@oarg@a + {% + \enverb@search@oarg@ifx:{}% + {% + \enverb@search@oarg@ifx;{}% + {% + \enverb@search@oarg@ifx~\enverb@firsteolfalse + {% + \enverb@ifxTF{[}\@let@token + {\enverb@oarg}% + {% + \enverb@ifxanyTF\@let@token + {% + \@sptoken\par\bgroup\egroup$&##^_% $ + } + {% + \enverb@misused + \endgroup + }% + {% + \ifenverb@firsteol + \expandafter\enverb@body@after@begin + \else + \expandafter\enverb@body + \fi + }% + }% + }% + }% + }% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal] +% {\enverb@body, \enverb@body@after@oarg, \enverb@body@after@begin} +% The body collection works by collecting everything inside a macro in one +% sweep, and a second pass over the collected material to strip leading spaces +% if the |ignore| or |auto-ignore| feature is used. This macro starts the +% first sweep. Since during the collection of the optional argument we might +% already have collected a few tokens we place those at the start by expanding +% the current definition of |\enverbBody| once. +% \begin{macrocode} +\protected\def\enverb@body + {\edef\enverbBody{\iffalse}\fi\expandafter\enverb@collect\enverbBody} +% \end{macrocode} +% The other two macros also start collecting the body, but are only called +% after either an optional argument was found, or if the first non-ignored +% character of the optional argument search was encountered before the first +% newline. In both cases we check whether the remainder of that line can be +% considered blank, and if so collect the body. +% \begin{macrocode} +\def\enverb@body@after@oarg#1~% + {\enverb@ensure@blank{#1}{closing bracket}\enverb@body} +\def\enverb@body@after@begin#1~% + {\enverb@ensure@blank{#1}{\string\begin}\enverb@body} +% \end{macrocode} +% This is also the last place we need the strange category setup in, so we +% close the delimiting brace of the |\lowercase| above here. +% \begin{macrocode} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\enverb@ensure@blank} +% We actually need to define the check for an empty line. This check here +% works for our specifically set up regime of spaces and tabs (which both +% expand to nothing, the same trick is basically used twice, though we once +% fully expand and once use romannumeral-expansion). +% \begin{macrocode} +\newcommand\enverb@ensure@blank[2] + {% + \expandafter\enverb@ifempty\expanded{{#1}}{}% + {% + \expanded + {% + \noexpand\enverb@error + {% + Line after #2 not empty.\noexpand\MessageBreak + Contains: \detokenize\expandafter{\romannumeral`\^^@#1}% + }% + {% + \noexpand\enverb will try to ignore this. You should clean up + your input.% + }% + }% + }% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal] +% {\enverb@ifempty,\enverb@ifempty@,\enverb@ifempty@true} +% This is just a quick argument-grabbing based test for an empty argument. +% \begin{macrocode} +\newcommand\enverb@ifempty[1] + {% + \enverb@ifempty@\enverb@ifempty@A#1\enverb@ifempty@B.\enverb@ifempty@true + \enverb@ifempty@A\enverb@ifempty@B + } +\def\enverb@ifempty@#1\enverb@ifempty@A\enverb@ifempty@B#2#3{#3} +\def\enverb@ifempty@true\enverb@ifempty@A\enverb@ifempty@B#1#2{#1} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\enverb@add,\enverb@pre,\enverb@body@add} +% These are just two functions to add things to a token list storing macro, +% one is available for arbitrary contents, the other is used for the |body|. +% \begin{macrocode} +\protected\long\def\enverb@add#1#2{\edef#1{\unexpanded\expandafter{#1#2}}} +\protected\long\def\enverb@pre#1#2% + {\edef#1{\unexpanded{#2}\unexpanded\expandafter{#1}}} +\protected\def\enverb@body@add{\enverb@add\enverbBody} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\enverb} +% This macro is the front facing command that starts the entire grabbing +% logic. The first thing we need to do is define the auxiliary we use to check +% whether we're done collecting the body, which is dependent on the current +% environment's name. Next we store the mandatory argument in |marg| and +% initialise the |oarg|-storage, category regime, and |firsteol|-boolean. +% Finally we start searching for the optional argument. +% \begin{macrocode} +\NewDocumentCommand \enverb { s +m } + {% + \expandafter\enverb@ifnotend@setup@perhaps\expanded + {{\string{\@currenvir\string}}}% + \let\enverb@collected@oarg\@empty + \edef\enverb@collected@marg{\unexpanded{#2}}% + \begingroup + \enverb@body@setup + \IfBooleanTF{#1}% + {\enverb@body@after@begin}% + {% + \enverb@firsteoltrue + \enverb@search@oarg + }% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal] +% {\ifenverb@firsteol,\enverb@firsteoltrue,\enverb@firsteolfalse} +% A simple \TeX-style boolean to keep track whether we're in front of the +% first newline. +% \begin{macrocode} +\newif\ifenverb@firsteol +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\enverb@search@oarg, \enverb@search@oarg@b} +% The core function to search for an optional argument was already defined +% above, these are the first and third step of that functionality (starting +% and resuming to search). +% \begin{macrocode} +\protected\def\enverb@search@oarg{\futurelet\@let@token\enverb@search@oarg@a} +\protected\def\enverb@search@oarg@b{\expandafter\enverb@search@oarg\@gobble} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\enverb@oarg, \enverb@oarg@} +% This is used once the opening brace of the optional argument is found. First +% we close the group in which the body's category code regime is active, then +% we actually collect the optional argument with the normal category codes, +% restore the body's regime and collect it. +% \begin{macrocode} +\protected\def\enverb@oarg{\endgroup\enverb@oarg@} +\NewDocumentCommand\enverb@oarg@{+O{}} + {% + \enverb@add\enverb@collected@oarg{#1}% + \begingroup + \enverb@body@setup + \enverb@body@after@oarg + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\enverb@ifnotend, \enverb@ifnotend} +% These functions check whether the input contains the string representation +% |\end|. If it does they invoke \cs[no-index]{enverb@ifnotend@maybe} with the +% tokens in front of |\end| and after it as two arguments. Otherwise the third +% argument after \cs{enverb@ifnotend@}'s expansion is directly used, which is +% the second (curried) argument to \cs{enverb@ifnotend}. +% \begin{macrocode} +\newcommand\enverb@ifnotend[1]% + {% + \def\enverb@ifnotend##1% + {% + \enverb@ifnotend@ + ##1\enverb@mark\enverb@ifnotend@maybe + #1\enverb@mark\@thirdofthree + \enverb@stop + }% + \def\enverb@ifnotend@##1#1##2\enverb@mark##3##4\enverb@stop{##3{##1}{##2}}% + } +\expandafter\enverb@ifnotend\expanded{{\expandafter\@gobble\string\\end}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\enverb@ifnotend@maybe} +% This function will be used if an |\end| was encountered and should check +% whether that is indeed the end of our environment, it uses a second stage +% \cs[no-index]{enverb@ifnotend@perhaps} for that check. The |\romannumeral| +% expansion it employs will strip any leading spaces or tabs from |#2|. +% \begin{macrocode} +\newcommand\enverb@ifnotend@maybe[2] + {\expandafter\enverb@ifnotend@perhaps\expandafter{\romannumeral`\^^@#2}{#1}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal] +% { +% \enverb@ifnotend@setup@perhaps, +% \enverb@ifnotend@perhaps, \enverb@ifnotend@perhaps@, +% \@thirdofthree +% } +% We need an expandable and fast check to see whether some input really +% contains the |\end| of our environment. Checking for |\end| itself is +% already done above, we need to check for the correct argument to it. The +% following does so by argument grabbing logic. +% \begin{macrocode} +\protected\def\enverb@ifnotend@setup@perhaps#1% + {% + \def\enverb@ifnotend@perhaps##1% + {% + \enverb@ifnotend@perhaps@\enverb@mark##1\enverb@mark\enverb@ifnotend@end + \enverb@mark#1\enverb@mark\@thirdofthree + \enverb@stop + }% + \def\enverb@ifnotend@perhaps@ + ##1\enverb@mark#1##2\enverb@mark##3##4\enverb@stop + {##3{##2}}% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\enverb@ifnotend@end} +% If the correct |\end| statement was found this function will be called by +% \cs[no-index]{enverb@ifnotend@perhaps}. It's first argument will be anything +% in that line following the |\end| statement, the second argument will be the +% material in front of it. And |#3| will be whatever the argument to +% \cs[no-index]{enverb@ifnotend} was. +% +% The first thing we need to do is end the body collection by placing the +% matching closing brace. After that we throw an error on lost content after +% the |\end| if it's non-blank. And finally we need to smuggle the collected +% body outside the current group's scope. +% \begin{macrocode} +\def\enverb@ifnotend@end#1#2#3% + {% + \iffalse{\fi}% + \enverb@ensure@blank{#1}{\string\end}% + \expandafter\enverb@finalise\expandafter{\enverbBody}{#2}% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\enverb@finalise} +% The finalising function closes the group containing the body's catcode +% regime. The already tokenised body is |#1|, and |#2| is the contents found +% in front of the |\end| statement, which we might use for the auto-ignore +% feature. +% +% It then does the key=val parsing, sets up the aftertreatment and assigns the +% final meaning to \cs{enverbBody}. Eventually it calls the end code of the +% enclosing environment. +% \begin{macrocode} +\protected\def\enverb@finalise#1#2% + {% + \endgroup + \expandafter\enverbsetup\expandafter{\enverb@collected@marg}% + \enverb@ifoargtokeyhandler + {% + \expandafter\enverb@keyhandler\expanded + {{% + \unexpanded\expandafter{\enverb@unknown@kv},% + \unexpanded\expandafter{\enverb@collected@oarg}% + }}% + }% + {% + \expandafter\enverbsetup\expandafter{\enverb@collected@oarg}% + \expandafter\enverb@keyhandler\expandafter{\enverb@unknown@kv}% + }% + \enverb@ifautoignore + {\enverb@setup@ignore{\enverb@count{#2}+\enverb@moreignore}}% + {\enverb@setup@ignore\enverb@ignore}% + \edef\enverb@line##1\enverb@eol + {% + \noexpand\unexpanded{##1}% + %\noexpand\detokenize{##1}% % TODO + \noexpand\unexpanded{\unexpanded\expandafter{\enverb@eol@content}}% + }% + \edef\enverbBody{#1}% + \expandafter\end\expandafter{\@currenvir}% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\enverb@setup@ignore, \enverb@setup@ignore@} +% \begin{macrocode} +\protected\def\enverb@setup@ignore#1% + {\expandafter\enverb@setup@ignore@\the\numexpr#1\relax;\enverb@line} +\protected\def\enverb@setup@ignore@#1;#2% + {% + \ifnum#1>9 + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi + {\expandafter\enverb@setup@ignore@\the\numexpr#1-8;{\@firstofnine{#2}}}% +% \end{macrocode} +% Just to make sure that |\renewcommand| works correctly, we ensure the macro +% exists. +% \begin{macrocode} + {% + \let\enverb@bol@gobble\@empty + \expanded + {% + \unexpanded{\renewcommand\enverb@bol@gobble}\ifnum#1>\z@[#1]\fi + {\unexpanded{#2}}% + \unexpanded{\def\enverb@bol##1\enverb@eol}% + {% + \noexpand\unexpanded + {\unexpanded\expandafter{\enverb@bol@content}}% + \unexpanded{\expandafter\enverb@ifempty\expanded}{{##1}}% + {\noexpand\enverb@line}% + {\noexpand\enverb@bol@gobble}% + ##1\noexpand\enverb@eol + }% + }% + }% + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Output Oriented Macros} +% +% \begin{macro}[internal]{\enverb@rmeol, \enverb@rmeol@} +% Many of our output routines require the |\scantokens| primitive. Since that +% one places an additional end of line at the end of its argument we need a +% way to remove it (this usually results in an additional space in the output +% otherwise). For that we place a comment character at the end of the input +% (if it's possible), if that's not available we hope that a stringified +% |\relax| will do. The code here will use \pkg{expl3} for ease of coding. +% \begin{macrocode} +\def\enverb@rmeol + {% + \ifnum\catcode`\%=14 + \enverb@chargen{`\%}{12}% + \expandafter\enverb@stop + \fi + \enverb@rmeol@0;% + \enverb@stop + } +\def\enverb@rmeol@#1;% + {% + \ifnum#1=128 + \string\relax + \expandafter\enverb@stop + \fi + \@firstofone + {% + \ifnum\catcode`\%=14 + \enverb@chargen{#1}{12}% + \expandafter\enverb@stop + \fi + \expandafter\enverb@rmeol@\the\numexpr#1+1;% + }% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\enverbExecute} +% \begin{macrocode} +\NewDocumentCommand\enverbExecute{} + {% + \begingroup + \newlinechar=`\^^M + \expandafter + \endgroup + \scantokens\expanded + {{% + \detokenize\expandafter{\enverbBody}% + \enverb@rmeol + }}% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\enverbListing} +% \begin{macro}[internal]{\enverbListing@} +% \begin{macrocode} +\NewDocumentCommand \enverbListing { m m } + {% + \scantokens\expanded + {{% + \string\begin{#1}\detokenize{#2}\enverb@othercr + \detokenize\expandafter{\enverbBody}% + \string\end{#1}\enverb@othercr + \enverb@rmeol + }}% + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \gobbledocstriptag +%</pkg> |