From 3c86596fd798f20aa2f5bba18812b6f432b13766 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Fri, 8 Jul 2022 21:53:34 +0000 Subject: saveenv (8jul22) git-svn-id: svn://tug.org/texlive/trunk@63843 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/tex/latex/saveenv/saveenv.sty | 147 ++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 Master/texmf-dist/tex/latex/saveenv/saveenv.sty (limited to 'Master/texmf-dist/tex') 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} -- cgit v1.2.3