summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/saveenv
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/saveenv')
-rw-r--r--macros/latex/contrib/saveenv/DEPENDS.txt1
-rw-r--r--macros/latex/contrib/saveenv/README24
-rw-r--r--macros/latex/contrib/saveenv/saveenv.pdfbin0 -> 384203 bytes
-rw-r--r--macros/latex/contrib/saveenv/saveenv.sty147
-rw-r--r--macros/latex/contrib/saveenv/saveenv.tex189
5 files changed, 361 insertions, 0 deletions
diff --git a/macros/latex/contrib/saveenv/DEPENDS.txt b/macros/latex/contrib/saveenv/DEPENDS.txt
new file mode 100644
index 0000000000..dd4fa25323
--- /dev/null
+++ b/macros/latex/contrib/saveenv/DEPENDS.txt
@@ -0,0 +1 @@
+precattl
diff --git a/macros/latex/contrib/saveenv/README b/macros/latex/contrib/saveenv/README
new file mode 100644
index 0000000000..e7e5d6d0e0
--- /dev/null
+++ b/macros/latex/contrib/saveenv/README
@@ -0,0 +1,24 @@
+saveenv -- Save environment content verbatim
+Allow users to collect environment content verbatim.
+
+Released under the LaTeX Project Public License v1.3c or later
+See http://www.latex-project.org/lppl.txt
+
+Report bugs at https://github.com/user202729/TeXlib
+
+========
+
+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.
+
+This work consists of the files saveenv.sty.
diff --git a/macros/latex/contrib/saveenv/saveenv.pdf b/macros/latex/contrib/saveenv/saveenv.pdf
new file mode 100644
index 0000000000..20bf11c9fd
--- /dev/null
+++ b/macros/latex/contrib/saveenv/saveenv.pdf
Binary files differ
diff --git a/macros/latex/contrib/saveenv/saveenv.sty b/macros/latex/contrib/saveenv/saveenv.sty
new file mode 100644
index 0000000000..454275c878
--- /dev/null
+++ b/macros/latex/contrib/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}
diff --git a/macros/latex/contrib/saveenv/saveenv.tex b/macros/latex/contrib/saveenv/saveenv.tex
new file mode 100644
index 0000000000..c6d4ba87bb
--- /dev/null
+++ b/macros/latex/contrib/saveenv/saveenv.tex
@@ -0,0 +1,189 @@
+%%! TEX program = lualatex
+\ProvidesFile{saveenv.tex} [2022/07/08 v0.0.0 ]
+\documentclass{l3doc}
+\EnableCrossrefs
+\CodelineIndex
+\RecordChanges
+\fvset{gobble=0,tabsize=4,frame=single,numbers=left,numbersep=3pt}
+\usepackage{hyperref}
+\usepackage{csquotes}
+
+%\MakeOuterQuote{"}
+\begin{document}
+\GetFileInfo{\jobname.tex}
+\DoNotIndex{\begin,\end,\detokenize,\ExplSyntaxOn}
+
+\iffalse\ExplSyntaxOff\fi % (fix some syntax highlighting issue)
+
+\title{\textsf{saveenv} --- Save environment content verbatim
+\thanks{This file describes version \fileversion, last revised \filedate.}
+}
+\author{user202729%
+%\thanks{E-mail: (not set)}
+}
+\date{Released \filedate}
+
+\maketitle
+
+
+\let\backtick=`
+\MakeShortVerb{`} % something wrong with \DefineShortVerb
+
+\begin{abstract}
+Allow users to collect environment content verbatim.
+\end{abstract}
+
+\section{Motivation}
+
+This package provides tools to create your own verbatim environments, and works in all values of \cs{endlinechar}.
+
+\section{Comparison to existing similar packages}
+
+\begin{itemize}
+ \item \pkg{scontents} package is similar; however it does not allow programmer to programmatically retrieve the macro content, only do a limited number of actions with them (execute, typeset as verbatim code, etc.).
+ \item \pkg{fancyvrb} and \pkg{verbatimcopy} provides some internal macro for defining similar environments, however they're internal.
+ \item \pkg{filecontentsdef} and \pkg{newverbs} provides very similar facilities (\env{filecontentsdefmacro} environment and \tn{Collectverbenv} command respectively); however it requires \verb+\endlinechar=13+ and does not support \cs{ExplSyntaxOn} environment.
+ \item \pkg{verbatim} provides facilities to define custom verbatim environment that processes the content line-by-line, however the interface is more complicated.
+
+ For comparison, the following code
+
+\begin{verbatim}
+\ExplSyntaxOn
+\makeatletter
+\cs_generate_variant:Nn \tl_build_gput_right:Nn {No}
+\NewDocumentEnvironment{}{}{
+ \@bsphack
+
+ \endlinechar=`\^^M ~ \let\do\@makeother \dospecials
+ \@makeother \^^I
+ %\cctab_select:N \c_other_cctab
+ % the above cannot be used, as \verbatim@ relies on
+ % the environment name having letter catcode
+
+ \catcode `\^^M \active
+
+ \tl_build_gbegin:N \__all_data
+ \def\verbatim@processline{
+ \tl_build_gput_right:No \__all_data{\the\verbatim@line ^^J}
+ }
+ \verbatim@
+}{
+ \tl_build_gend:N \__all_data
+ \str_gset:NV \__all_data \__all_data
+
+ % can do something else with \__all_data here
+
+ \@esphack
+}
+\makeatother
+\ExplSyntaxOff
+\end{verbatim}
+
+defines an environment that saves the data similar to \env{saveenv} environment described below (with the overhead of |\tl_build_*| functions),
+but inside \cs{ExplSyntaxOn} environment it generates a spurious space at the beginning of the string.
+\end{itemize}
+
+
+
+\section{Main environment}
+
+\DescribeEnv{saveenv}
+ Environment that saves its body.
+
+ For example, the following code
+
+\begin{verbatim}
+\begin{saveenv}{\data}
+123
+456
+\end{saveenv}
+\end{verbatim}
+
+will save the string \texttt{123\meta{newline}456} globally into \cs{data}.
+
+The braces around \verb+{\data}+ is optional; however, in the unlikely case if \cs{endlinechar} has the \enquote{letter} catcode, it might be absorbed and gives unexpected result.
+
+A newline is represented as a token with charcode 10 (|^^J|) and catcode other.
+
+\textbf{Note} that this is unusual, for comparison \pkg{filecontentsdef} stores it as an active |^^M|.
+
+In the current implementation, it can be used in functions such as \cs{iow_now:Nn} and newline characters will appear as newline.
+(the number 10 is hard coded in the implementation of |\iow_now:Nn|,
+nevertheless I'm not sure if this behavior is guaranteed. Manually replacing them with |\iow_newline:| tokens and |x|-expand the result
+would be guaranteed to work)
+
+The assignment is global, and done before the macro \cs{endsaveenv} is executed.
+
+The data is represented as an \pkg{expl3}-string, that is, a sequence of tokens with catcode 12 (for non-space characters) or 10 (for space character).
+
+In other words, the token list is equal to its own \cs{detokenize}.
+
+\DescribeEnv{saveenvghost}
+Similar to above; however the content inside is still typesetted/executed, and the Sync\TeX\ information is preserved.
+
+Note that this environment is implemented by reading the whole file from the beginning, therefore there might be some performance hit for large files and multiple usages of the environment. Use sparingly.
+
+\DescribeEnv{saveenvkeeplast}
+Similar to above; however the final newline and the space characters before \texttt{\cs{end}\{\meta{environment name}\}} are preserved.
+
+For example, the example above with \texttt{saveenv} replaced with \texttt{saveenvkeeplast}
+will save the string \texttt{123\meta{newline}456\meta{newline}} into \cs{data} instead.
+
+\section{Extending the environments}
+
+All of the environments are extensible.
+
+Follow the instruction in \url{https://tex.stackexchange.com/q/14683/250119} to define an environment based on an existing one.
+
+For example, the following definition
+
+\begin{verbatim}
+\ExplSyntaxOn
+\NewDocumentEnvironment{custom}{}{
+ \saveenv \data
+}{
+ \endsaveenv
+ \tl_show:N \data
+}
+\end{verbatim}
+will define an environment \env{custom} that prints out the content inside the environment using |\tl_show:N|.
+
+\section{Limitation}
+
+\begin{itemize}
+ \item This package does not process the content line-by-line. Therefore:
+ \begin{itemize}
+ \item The memory consumption might be larger than approaches that process the content line-by-line, in case you only need to do something with the line.
+
+ Nevertheless, in modern computers, the overhead is negligible.
+ \item In case it's desired to typeset the content afterwards, it's difficult to preserve the Sync\TeX\ data.
+ \end{itemize}
+
+ \item Currently nested environments with the same name are not supported (unlike \pkg{scontents} package).
+
+ \item Note that there must be nothing after the \texttt{\cs{begin}\{\meta{environment name}\}} or the \texttt{\cs{end}\{\meta{environment name}\}} line.
+
+ \item Note that \texttt{\cs{end}\{\meta{environment name}\}} must not be in the middle of any line.
+
+ \item The \cs{endlinechar} must not be tokenized in advance (or if it is, its catcode must be 12/other).
+ This might happen when for example your environment looks ahead for optional argument.
+ See \url{https://tex.stackexchange.com/q/649331/250119} for an example and one way how to fix it.
+
+ Alternatively, you can
+ \begin{itemize}
+ \item manually remove the end line token,
+ \item set \verb+\endlinechar=-1\relax+ before calling \cs{saveenv}
+ \item (optional) reset the value of \cs{endlinechar} afterwards.
+
+ \end{itemize}
+\end{itemize}
+
+
+
+\StopEventually{%
+ \PrintChanges
+ \PrintIndex
+}
+\Finale
+\end{document}
+