summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/latex/saveenv
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2022-07-08 21:53:34 +0000
committerKarl Berry <karl@freefriends.org>2022-07-08 21:53:34 +0000
commit3c86596fd798f20aa2f5bba18812b6f432b13766 (patch)
treef42b247c8995ce1baceed33be52d9519ee2b31a7 /Master/texmf-dist/tex/latex/saveenv
parent136fa6ccfd2eea815bf528abe6635d5d1ef401d7 (diff)
saveenv (8jul22)
git-svn-id: svn://tug.org/texlive/trunk@63843 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/saveenv')
-rw-r--r--Master/texmf-dist/tex/latex/saveenv/saveenv.sty147
1 files changed, 147 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/latex/saveenv/saveenv.sty b/Master/texmf-dist/tex/latex/saveenv/saveenv.sty
new file mode 100644
index 00000000000..454275c878e
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/saveenv/saveenv.sty
@@ -0,0 +1,147 @@
+% File: saveenv.sty
+% Copyright 2022 user202729
+%
+% 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 has the LPPL maintenance status `maintained'.
+%
+% The Current Maintainer of this work is user202729.
+
+\ProvidesExplPackage{saveenv}{2022/07/08}{0.0.0}{Save environment content verbatim}
+\RequirePackage{precattl}
+\msg_new:nnn {saveenv} {trailing-content-or-pretokenized}
+ {Trailing~content~found~on~line,~or~content~pretokenized!}
+
+\msg_new:nnn {saveenv} {trailing-content-end-line}
+ {Trailing~content~found~on~environment~last~line}
+
+\msg_new:nnn {saveenv} {currfile-package-not-loaded}
+ {currfile~package~is~needed~for~this~functionality}
+
+\precattl_exec:n{
+% args: char code, content, environment name
+\msg_new:nnn {saveenv} {leading-content-last-line}
+ {Leading~content~found~on~\cO\\end{#3}~line,~first~char~code~=~#1,~content~=~'#2'}
+}
+
+\makeatletter
+
+\seq_new:N \_senv_lines
+\ior_new:N \_senv_file
+
+\precattl_exec:n {
+
+\NewDocumentEnvironment {saveenvghost} {m} {
+ \edef \_senv_firstline {\the\inputlineno}
+} {
+
+ \cs_if_free:NT \currfilename {
+ \msg_error:nn {saveenv} {currfile-package-not-loaded}
+ }
+ \ior_open:Nn \_senv_file {\currfilename}
+
+ \prg_replicate:nn {\_senv_firstline} {
+ \ior_str_get:NN \_senv_file \_senv_line
+ }
+
+ \tl_build_gbegin:N #1
+
+ \prg_replicate:nn {\the\inputlineno-\_senv_firstline-2} {
+ \ior_str_get:NN \_senv_file \_senv_line
+ \exp_args:NNo \tl_build_gput_right:Nn #1 {\_senv_line \cO\^^J}
+ }
+
+ \ior_str_get:NN \_senv_file \_senv_line
+ \exp_args:NNo \tl_build_gput_right:Nn #1 {\_senv_line}
+
+ \ior_close:N \_senv_file
+
+ \tl_build_gend:N #1
+
+}
+
+
+% #1: target macro
+\NewDocumentEnvironment {saveenvkeeplast} {m} {
+ \begingroup
+ \edef \_senv_old_endlinechar {\the\endlinechar}
+ \cctab_select:N \c_other_cctab % note that this changes the value of \endlinechar as well
+ \int_compare:nNnTF {\_senv_old_endlinechar} < {0} {
+ \_senv_start_get_body:N #1
+ } {
+ \exp_last_unbraced:Nf \peek_meaning_remove:NTF { \char_generate:nn{\_senv_old_endlinechar}{12} } %12 is other
+ {
+ \_senv_start_get_body:N #1
+ }
+ {
+ \msg_error:nn {saveenv} {trailing-content-or-pretokenized}
+ }
+ }
+} {
+}
+
+% #1: target macro
+\cs_new_protected:Npn \_senv_start_get_body:N #1 {
+ \endlinechar=10~
+ \str_set:NV \_senv_env \@currenvir
+ \tl_replace_all:Nnn \_senv_env {~} {\cO\ }
+ \exp_args:NNVV \_senv_helper #1 \_senv_env \@currenvir
+}
+
+% #1: target macro
+% #2: value of \@currenvir but with all tokens catcode 12 (other)
+% #3: value of \@currenvir
+\def \_senv_helper #1 #2 #3 {
+ \cs_set_protected:cpn {[saveenv]~verbatim~body~scanner~for~#2} ##1 \cO{ \\end\{ } #2 \cO\} {
+ % ##1: the body
+ \peek_meaning_remove:NTF \cO\^^J {
+ \endgroup
+ \str_gset:Nn #1 {##1}
+ \end{#3}
+ } {
+ \msg_error:nn {saveenv} {trailing-content-end-line}
+ }
+ }
+
+ \use:c {[saveenv]~verbatim~body~scanner~for~#2}
+}
+
+% set variable #1 to have content of #2, but with last line dropped.
+% lines are separated by \^^J.
+
+\cs_new_protected:Npn \saveenv_set_drop_last:Nn #1 #2 {
+ \tl_set:Nn \_senv_body {#2}
+ \tl_replace_all:Nnn \_senv_body {~} {\cO\ } % keep spaces in seq_set_split (support older expl3 versions)
+ \seq_set_split:NnV \_senv_lines {\cO\^^J} \_senv_body
+ \seq_pop_right:NN \_senv_lines \_senv_lastline
+ \tl_map_inline:Nn \_senv_lastline { % debug check, ensure last line is empty
+ \int_case:nnF {`##1} {
+ {32} {} %space
+ {9} {} %tab
+ }
+ {
+ \msg_error:nnoVV {saveenv} {leading-content-last-line} {\number`##1} \_senv_lastline \@currenvir
+ }
+ }
+ \str_gset:Nx #1 {\seq_use:Nn \_senv_lines {\cO\^^J}}
+}
+
+\cs_generate_variant:Nn \saveenv_set_drop_last:Nn {NV}
+
+
+\NewDocumentEnvironment {saveenv} {m} {
+ \saveenvkeeplast \_senv_content
+} {
+ \endsaveenvkeeplast
+ \saveenv_set_drop_last:NV #1 \_senv_content
+}
+
+
+}
+
+\cs_generate_variant:Nn \msg_error:nnnnn {nnoVV}