\documentclass{article}
\usepackage{verbatim}
%\usepackage{fancyvrb}
\usepackage{xcolor}
\usepackage{xkeyval}
%RE: LACK OF OPTIONAL ARGUMENT MAKES 1ST ITEM OF ENVIRONMENT GET EXECUTED AS IF IT WERE OPTIONAL ARGUMENT
\makeatletter
\newwrite\verbatim@out%
\def\verbatimout#1{
\begingroup%group to localise cat code reassignment?
\immediate\openout\verbatim@out#1%
\let\do\@makeother\dospecials%
\catcode`\^^M\active%
\def\verbatim@processline{%
%\the\verbatim@line%
%\typeout{VERBATIM: \the\verbatim@line}%
\immediate\write\verbatim@out{\the\verbatim@line}}%
\verbatim@start%
}
%\def\setverbatimout#1{
% \begingroup
% \immediate\openout\verbatim@out#1%
% \def\verbatim@processline{%
% \typeout{VERBATIM: \the\verbatim@line}%
% \immediate\write\verbatim@out{\the\verbatim@line}}%
%}
\def\endverbatimout{%
%\endverbatim
\immediate\closeout\verbatim@out%\@esphack%
\endgroup
}
\def\mykeys@color{black}
\define@key{mykeys}{color}{\def\mykeys@color{#1}}
\newenvironment{verboptfail}[1][]{\verbatim}{\endverbatim}
\newenvironment{verbopt}{\verbatim\verboptarg}{\endverbatim}
\newcommand\verboptarg[1][]{\setkeys{mykeys}{#1}\color{\mykeys@color}\typeout{:::#1:::}}
%NOTE: replacing \verbatim with \verbatimout{filename} and \endverbatim with \endverbatimout does not work, as \verboptarg is simply not picked up. Why? catcodes?
\gdef\opts{}
%\newenvironment{verbout}{\setverbatimout{1.temp}\verbatim\verboutarg}{\endverbatimout\setkeys{mykeys}{\opts}\color{\mykeys@color}\verbatiminput{1.temp}}
\newenvironment{verbout}{\verbatimout{1.temp}\verboutarg}{\endverbatimout\setkeys{mykeys}{\opts}\color{\mykeys@color}\verbatiminput{1.temp}}
%\newcommand\verboutarg[1][]{{\nfss@catcodes\scantokens{\gdef\opts{#1}\typeout{***\opts***}}}}%typeout never gets executed!
\newcommand\verboutarg[1][]{\gdef\opts{#1}\typeout{***\opts***}}%typeout never gets executed!
\makeatother
\begin{document}
standard verbatim environment with a problem - well that's where we started!
\begin{verbatim}\more\verb
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verbatim}
%the following fails to compile when we remove REMOVEME!
\begin{verboptfail}REMOVEME\more\verb
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verboptfail}
our verbopt environment works fine
\begin{verbopt}
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\| without arg
\end{verbopt}
\begin{verbopt}\more\verb
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\| without arg
\end{verbopt}
\begin{verbopt}[color=blue]\more\verb
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\| with arg
\end{verbopt}
\begin{verbopt}[]
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
with EMPTY optional arg
\end{verbopt}
************ we can't get our verbout environment to work - we find `[color=blue]' etc in the output file, and keyvalues have not been set! *************
\begin{verbout}
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verbout}
\begin{verbout}\more\verb
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verbout}
\begin{verbout}[color=blue]
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verbout}
\begin{verbout}[]
\x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
with EMPTY optional arg
\end{verbout}
\end{document}
标准逐字环境存在问题——好吧,这就是我们开始的地方!
\more\verb
\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\|
REMOVEME\more\verb
\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\|
我们的 verbopt 环境运行良好
\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\| without arg
\more\verb
\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\| without arg
\more\verb
\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\| with arg
\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\|
如果可选参数为空 ****,我们无法使 verbout 环境工作 - 我们在输出文件中发现 '[color=blue]' 等,并且键值尚未设置!************ ************* ************** *************** *************** *************** *************** *************** ***************
\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\|
\more\verb
\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\|
[color=blue]
\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\|
[]
\x\y\z !"$%^&*()_+-=[]{};’#:@~,./<>?\|
带有空的可选参数
答案1
这应该会让你更进一步。
首先,你的verbopt
环境确实不能正常工作。如果行中没有文本,它会产生一个空行\begin{verbopt}
。
环境verbiopt
通过使用环境的可选参数来定义它来解决这个问题。但是,如果在同一行中没有可选参数文本,\begin{verbiopt}
则会产生错误,如果它以 TeX 命令开头,\more
在示例中,该命令也会被吞掉。如果文本不是以命令开头,或者该行中没有文本,则没有问题。
对于verbout
环境,将参数提供给环境也更有意义。在您的示例中,您可以在环境的开头设置键(注释掉的版本)。但这可能并不总是可行的。因此,使用的版本使用环境末尾的参数。
这里需要注意的是,这\setkeys{mykeys}{\verbopts}
将不起作用,因为\verbopts
扩展得太晚了。\setkeys
将被color=blue
视为键(没有值),然后抱怨未知键。为了解决这个问题,\setmykeys
使用了宏。它使用已经扩展的来调用\verbopts
,使用\expandafter\setmykeys\expandafter{\verbopts}
。
新verbout
环境在文本在同一行时也存在问题\begin{verbout}
。但这里只是吞下了一个命令,没有错误。
还有环境verboutfile
,它为文件名添加了一个附加强制参数,因此文本可以存储在不同的文件中。此环境与 在同一行中没有文本问题\begin{verboutfile}
。
代码(会产生错误,见上文):
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{verbatim}
%\usepackage{fancyvrb}
\usepackage{xcolor}
\usepackage{xkeyval}
%RE: LACK OF OPTIONAL ARGUMENT MAKES 1ST ITEM OF ENVIRONMENT GET EXECUTED AS IF IT WERE OPTIONAL ARGUMENT
\makeatletter
\newwrite\verbatim@out%
\def\verbatimout#1{
\begingroup%group to localise cat code reassignment?
\immediate\openout\verbatim@out#1%
\let\do\@makeother\dospecials%
\catcode`\^^M\active%
\def\verbatim@processline{%
\immediate\write\verbatim@out{\the\verbatim@line}}%
\verbatim@start%
}
\def\endverbatimout{%
\immediate\closeout\verbatim@out
\endgroup
}
\def\mykeys@color{black}
\define@key{mykeys}{color}{\def\mykeys@color{#1}}
\newenvironment{verboptfail}[1][]{\verbatim}{\endverbatim}
\newenvironment{verbopt}{\verbatim\verboptarg}{\endverbatim}
\newcommand\verboptarg[1][]{\setkeys{mykeys}{#1}\color{\mykeys@color}\typeout{:::#1:::}}
\newenvironment{verbiopt}[1][]{%
\setkeys{mykeys}{#1}\typeout{:::#1:::}%
\color{\mykeys@color}%
\verbatim
}{%
\endverbatim
}
% with key set at start of environment, would work here
%\newenvironment{verbout}[1][]{%
% \setkeys{mykeys}{#1}\typeout{***#1***}\verbatimout{1.temp}%
%}{%
% \endverbatimout\color{\mykeys@color}\verbatiminput{1.temp}%
%}
% optional argument used at end of environment
\newenvironment{verbout}[1][]{%
\verboutarg{#1}\verbatimout{1.temp}%
}{%
\endverbatimout
\expandafter\setmykeys\expandafter{\verbopts}%
\color{\mykeys@color}\verbatiminput{1.temp}%
}
\newcommand\verboutarg[1]{\gdef\verbopts{#1}\typeout{***#1***}}
\newcommand\setmykeys[1]{\setkeys{mykeys}{#1}}
% file name as second mandatory argument, both used at end of environment
\newenvironment{verboutfile}[2][]{%
\verboutfilearg{#1}{#2}\verbatimout{#2}%
}{%
\endverbatimout
\expandafter\setmykeys\expandafter{\verbopts}%
\color{\mykeys@color}\verbatiminput{\verbfile}%
}
\newcommand\verboutfilearg[2]{%
\gdef\verbopts{#1}\typeout{***#1***}%
\gdef\verbfile{#2}\typeout{>>>#2<<<}%
}
%same as above
%\newcommand\setmykeys[1]{\setkeys{mykeys}{#1}}
\makeatother
\begin{document}
\noindent
using verbopt environment; issue: empty first line in (1) and (4) example
\noindent
XXXXXXXXXXXX
\begin{verbopt}
(1) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\| without arg
\end{verbopt}
XXXXXXXXXXXX
\begin{verbopt}\more\verb
(2) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\| without arg
\end{verbopt}
XXXXXXXXXXXX
\begin{verbopt}[color=blue]\more\verb
(3) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\| with arg
\end{verbopt}
XXXXXXXXXXXX
\begin{verbopt}[]
(4) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
with EMPTY optional arg
\end{verbopt}
XXXXXXXXXXXX
\vfill
\noindent
using verbiopt environment; issue: \verb|\more| in (2) is expanded, therefore error
\noindent
XXXXXXXXXXXX
\begin{verbiopt}
(1) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\| without arg
\end{verbiopt}
XXXXXXXXXXXX
\begin{verbiopt}\more\verb
(2) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\| without arg
\end{verbiopt}
XXXXXXXXXXXX
\begin{verbiopt}[color=blue]\more\verb
(3) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\| with arg
\end{verbiopt}
XXXXXXXXXXXX
\begin{verbiopt}[]
(4) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
with EMPTY optional arg
\end{verbiopt}
XXXXXXXXXXXX
\newpage
\noindent
using verbout environment, issue: swallows \verb|\more| in (2)
\noindent
XXXXXXXXXXXX
\begin{verbout}
(1) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verbout}
XXXXXXXXXXXX
\begin{verbout}\more\verb
(2) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verbout}
XXXXXXXXXXXX
\begin{verbout}[color=blue]
(3) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verbout}
XXXXXXXXXXXX
\begin{verbout}[]
(4) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
with EMPTY optional arg
\end{verbout}
XXXXXXXXXXXX
\vfill
\noindent
using verboutfile environment with file name as argument
\noindent
XXXXXXXXXXXX
\begin{verboutfile}{1.tmp}
(1) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verboutfile}
XXXXXXXXXXXX
\begin{verboutfile}{2.tmp}\more\verb
(2) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verboutfile}
XXXXXXXXXXXX
\begin{verboutfile}[color=blue]{3.tmp}
(3) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
\end{verboutfile}
XXXXXXXXXXXX
\begin{verboutfile}[]{4.tmp}
(4) \x\y\z !"£$%^&*()_+-=[]{};'#:@~,./<>?\|
with EMPTY optional arg
\end{verboutfile}
XXXXXXXXXXXX
\end{document}
答案2
关于强制参数的使用。我的非最小(或真实)环境实际上是根据计数机制发明文件名的,所以我不想要强制参数。我们总是可以写一个空的强制参数,但如果我们忘记了,那么我们就会回到起点!当然,如果我们假设“可选”参数是强制的,那就没有问题了——我的意思是,如果我们总是写可选参数,即使它是空的[]。这样我们就不会忘记写[],那么我们可以在环境定义中测试它并报告错误消息。话虽如此,我正在考虑以下解决方案:
\documentclass{article}
\usepackage{verbatim,xcolor,nopageno}
\makeatletter
\newwrite\verbatim@out%
\def\verbatimout#1{\begingroup\immediate\openout\verbatim@out#1\let\do\
@makeother\dospecials\catcode ` \^^M\active\def\verbatim@processline{\
typeout{VERBATIM: \the\verbatim@line}\immediate\write\verbatim@out{\the\
verbatim@line}}\verbatim@start}
\def\endverbatimout{\immediate\closeout\verbatim@out\endgroup}
\newenvironment{myenv}{\@ifnextchar[{\@myarg}{\errmessage{some error
message}\verbatimout{1.temp}}}{\endverbatimout\verbatiminput{1.temp}}
\def\@myarg[#1]{{\color{red}[#1]}\verbatimout{1.temp}}%delimited arg
\makeatother
\begin{document}\noindent
xxxxxxxxxxxxxxxxxxxx
\begin{myenv}\more\verb
\x\y\z␣!" $ %^&*() +
\end{myenv}
xxxxxxxxxxxxxxxxxxxx
\begin{myenv}[]\more\verb
\x\y\z␣!" $ %^&*() +
\end{myenv}
xxxxxxxxxxxxxxxxxxxx
\end{document}
这使
xxxxxxxxxxxxxxxxxxxx
\verb
\x\y\z !"$%^&*()_+
xxxxxxxxxxxxxxxxxxxx []
\more\verb
\x\y\z !"$%^&*()_+
xxxxxxxxxxxxxxxxxxxx
现在,它似乎表现得像 fan-cyvrb 包中的 (V)erbatim(O)out{} 宏。即使我们没有 [],甚至根本没有使用键值,fancyvrb 包也会给出乱码错误消息:“\beginmyenv[key-value] 和行尾之间有多余的输入”!