Estou tentando aplicar uma expl3
função ao conteúdo de um ambiente. No LaTeX2e isso pode ser conseguido usando \bgroup
e \egroup
. Em expl3
, algo não funciona.
Eu esperaria que o código a seguir imprimisse "AAA ei BBB". Em vez disso, imprime "AAA BBB ei".
\ExplSyntaxOn
\cs_new:Npn \bar:n #1 {
AAA #1 BBB
}
\NewDocumentEnvironment{foo}{}{
\bar:n \bgroup
}{
\egroup
}
\ExplSyntaxOff
\begin{document}
\begin{foo}
hey
\end{foo}
\end{document}
Alguma idéia de por que isso acontece e possíveis soluções alternativas?
Editar
Esta é minha abordagem atual:
\cs_new:Npn \env_new:Nn #1#2 {
\tl_new:N #1
\tl_set:Nn #1 { #2 }
}
\cs_new:Npn \env_begin:N #1 {}
\cs_new:Npn \env_end:N #1 {}
\cs_new:Npn \env_capture_on: {
\global \let \env_begin:N \group_begin:
\global \let \env_end:N \group_end:
}
\cs_new:Npn \env_capture_off: {
\global\let\env_begin:N\env_original_begin:N
\global\let\env_end:N\env_original_end:N
}
\cs_new:Npn \env_original_begin:N #1 {
\env_capture_on:
\tl_use:N #1
\group_begin:
\env_capture_off:
}
\cs_new:Npn \env_original_end:N #1 {
}
\env_capture_off:
\cs_new:Npn \foo:n #1 {
AAA #1 BBB
}
\env_new:Nn \baf {
\foo:n
}
\env_begin:N \baf
hey
\env_end:N \baf
Isso não funcionará, já que \group_begin: e \group_end: não podem ser usados para capturar argumentos de funções (ou seja, \foo \group_begin: A \group_end:
funcionam de maneira diferente de \foo { A }
).
Existe alguma maneira de uma sequência de controle ser temporariamente forçada a se comportar como se fosse uma chave explícita?
Uma solução
Acho que tenho uma solução. Como mencionei nos comentários, pode-se combinar a correspondência de padrões com a contagem do número de \begin
s para capturar o conteúdo de um ambiente. Foi um pouco surpreendente para mim que isso sejaprecisamenteo que está acontecendo em environ
, logo abaixo de umMUITOde notação.
Como sei que isso environ
falhou na aplicação pretendida, decidi reimplementá-lo da maneira mais simples possível, para poder descobrir onde meu código falhou (agora tenho uma ideia do que deu errado, mas esse não é o ponto). Abaixo você pode encontrar uma implementação em expl3
. Não testei completamente, mas acredito que funciona.
Quaisquer comentários ou críticas são extremamente apreciados.
\int_new:N \env_count
\cs_new:Npn \env_new:Nn #1#2 {
\cs_new:cpn { env_defined@ \cs_to_str:N #1 :nn } ##1##2 {
#2
}
}
\cs_new:Npn \env_countbegin:w #1\xbegin#2 {
\cs_if_free:NTF #2 {
\int_incr:N \env_count
\env_countbegin:w
} {
\cs_if_eq:NNTF #2 \xend {} {
\int_incr:N \env_count
\env_countbegin:w
}
}
}
\cs_new:Npn \env_collect:w #1#2#3#4\xend#5 {
\env_countbegin:w #4\xbegin\xend
\int_compare:nTF { \env_count = 0 } {
\use:c { env_defined@ \cs_to_str:N #1 :nn } { #3 #4 } { #2 }
}{
\int_decr:N \env_count
\env_collect:w {#1} {#2} { #3 #4 \xend{#5} }
}
}
\NewDocumentCommand \xbegin {mo} {
\int_zero:N \env_count
\env_collect:w {#1} {#2} {}
}
\NewDocumentCommand \xend {} {}
\env_new:Nn \foo {
AAA #1 BBB
}
\xbegin{\foo}
\xbegin{\foo}
hey
\xend{\foo}
\xend{\foo}
Responder1
Temnuncafoi possível argumentar com \bgroup
e \egroup
. A versão
\newenvironment{foo}{%
\baz\bgroup
}{%
\egroup
}
\newcommand{\baz}[1]{AAA #1 BBB}
falharia exatamente da mesma maneira. O argumento para \baz
seria \bgroup
, então a saída de
x\begin{foo}
key
\end{foo}y
seria
xAAA<space><space>BBB<space>key<space>y
Um dos espaços inesperados vem do final de linha depois de \begin{foo}
, o outro do final de linha depois de key
.
É possível usar environ
, como mostra Christian Hupfer:
\usepackage{xparse,environ}
\ExplSyntaxOn
\NewEnviron{foo}
{
\jaeya_baz:V \BODY
}
\cs_new:Nn \jaeya_baz:n { AAA~#1~BBB }
\cs_generate_variant:Nn \jaeya_baz:n { V }
\ExplSyntaxOff
e a saída do código acima seria a esperada
xAAA<space>key<space}BBBy
Adicionar recursos semelhantes a \NewEnviron
este xparse
deve estar na lista de tarefas da equipe LaTeX.
Responder2
Esta é uma maneira de environ
and \NewEnviron
, capturá-lo \BODY
e aplicá-lo em um ambiente wrapper, definido com xparse
's \NewDocumentEnvironment
, o que significa que todos os recursos dos xparse
especificadores de argumento ainda podem ser usados.
\documentclass{article}
\usepackage{environ}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new:Nn \bar:n {
AAA #1 BBB
}
\NewEnviron{foointernal}{
\bar:n {\BODY}
}
\ExplSyntaxOff
\let\origfoointernal\foointernal
\let\origendfoointernal\endfoointernal
\NewDocumentEnvironment{foo}{}{%
\origfoointernal%
}{%
\origendfoointernal%
}
\begin{document}
\begin{foo}
hey
\end{foo}
\begin{foo}
\blindtext
Hello World
\end{foo}
\end{document}
Responder3
Você sabe que deseja usar \bar:n
em um ambiente para capturar o conteúdo. Portanto, basta digitalizar adiante \end
e inserir \end
novamente no final do texto de substituição.
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new:Npn \bar:n #1 \end {
AAA #1 BBB \end
}
\NewDocumentEnvironment{foo}{}{\bar:n}{}
\ExplSyntaxOff
\begin{document}
\begin{foo}
hey
\end{foo}
\end{document}
Responder4
Sinceramente, não sei se funcionará depois que todo o pacote for reescrito, mas pelo menos agora posso entender o que está acontecendo. Existem algumas limitações: os ambientes definidos possuem apenas dois parâmetros. #1 representa o conteúdo do ambiente; #2 representa um parâmetro entre colchetes, que em princípio pode ser usado para conter valores-chave e assim superar essa limitação.
Além disso, meus ambientes funcionam com comandos \xbegin{\foo} e \xend{\foo}. A estrutura subjacente desses comandos é diferente daquela dos ambientes LaTeX, então decidi usar palavras-chave diferentes. De qualquer forma, acho que a abordagem poderia ser estendida para ser aplicada a ambientes LaTeX.
Qualquer revisão ou comentário sobre o código é extremamente bem-vindo e apreciado!
\documentclass[10pt]{article}
\usepackage{expl3}
\ExplSyntaxOn
\int_new:N \env_count
\cs_new:Npn \env_new:Nn #1#2 {
\cs_new:cpn { env_defined@ \cs_to_str:N #1 :nn } ##1##2 {
#2
}
}
\cs_new:Npn \env_countbegin:w #1\xbegin#2 {
\cs_if_free:NTF #2 {
\int_incr:N \env_count
\env_countbegin:w
} {
\cs_if_eq:NNTF #2 \xend {} {
\int_incr:N \env_count
\env_countbegin:w
}
}
}
\cs_new:Npn \env_collect:w #1#2#3#4\xend#5 {
\env_countbegin:w #4\xbegin\xend
\int_compare:nTF { \env_count = 0 } {
\use:c { env_defined@ \cs_to_str:N #1 :nn } { #3 #4 } { #2 }
}{
\int_decr:N \env_count
\env_collect:w {#1} {#2} { #3 #4 \xend{#5} }
}
}
\NewDocumentCommand \xbegin {mo} {
\int_zero:N \env_count
\env_collect:w {#1} {#2} {}
}
\NewDocumentCommand \xend {} {}
\env_new:Nn \foo {
AAA #1 BBB
}
\ExplSyntaxOff
\begin{document}
\xbegin{\foo}
\xbegin{\foo}
hey
\xend{\foo}
\xend{\foo}
\end{document}