2

I'd like to inject a command into an arbitrary environment that uses the environment body as an argument.

Desired behavior

\begin{AnyEnvironment}{MandatoryEnvArg}[OptionalEnvArg]
  ...
\end{AnyEnvironment}

Should expand to

\begin{AnyEnvironment}{MandatoryEnvArg}[OptionalEnvArg]
  \MyMacro{...}
\end{AnyEnvironment}

Where ... are arbitrary contents (possibly including \pars and other environments and commands).

Use Case

My use case for this perhaps odd question is the following: I want to be able to "preprocess" the environment body with \MyMacro. In particular, \MyMacro would be a command which itself invokes a Lua command with \directlua that would receive the environment body as a string and perform some string manipulation on it before putting it back into TeX's input stream. As a basic example:

\NewDocumentCommand{\MyMacro}{m}
  {
    \directlua
      {
        local str = "\luaescapestring{\unexpanded{#1}}"
        tex.sprint(str .. ' ~ ' .. str)
      }
  }

Even more specifically, this all started because I was curious whether I could implement support for "shorthand" syntaxes (such as the one used in typst, a LaTeX-like typesetting program) in math mode. Basic experiments of mine yielded surprisingly nice results, so I became curious how far I could bring this kind of functionality in LaTeX, hence the generality of my question.

Requirements

  • AnyEnvironment may be any feasible LaTeX environment. In particular, it may:
    • Be user-defined.
    • Be defined by external packages.
    • Be inside of math mode (e.g., aligned), or activate math mode itself (e.g., align).
    • Have any kinds of arguments.
    • May have asterisks (*) or dashes (-) in its name.
    • Contain verbatin content and/or catcode changes — It seems that supporting this would be very difficult (as per comments to this question).

Approaches

Redefining environment

\let\oldAnyEnvironment\AnyEnvironment
\let\endoldAnyEnvironment\endAnyEnvironment
\RenewDocumentEnvironment{AnyEnvironment}{+b}
  {\oldAnyEnvironment\MyMacro{#1}}{\endoldAnyEnvironment}

Issues:

  • Doesn't work if AnyEnvironment has arguments
  • Doesn't work if AnyEnvironment has * (asterisk) or - (dash) in its name (though this might be easily fixable, I've seen starred environments be referred to by \<env>star and \end<env>star, and maybe there's something similar for dashes).

With hooks

\ExplSyntaxOn
\NewDocumentCommand { \MyMacro } { m } { Argument:~#1. }
\AtBeginEnvironment { AnyEnvironment } { \MyMacro \bgroup }
\AtEndEnvironment   { AnyEnvironment } { \egroup }
\ExplSyntaxOff

Issues:

  • Doesn't work; \bgroup and \egroup aren't the right thing to use for this purpose (also see Arguments possibly delimited by \bgroup and \egroup). However, this approach feels more promising to me. I tried reading into the l3basics and l3quark modules, since I was hopeful that I could find an answer there; for example, \use_none_delimit_by_q_stop:w ... \q_stop made me think that maybe something similar could be used to collect the environment body. However, I didn't manage to find a solution yet.

Related questions:

Related packages:

  • environ – A new interface for environments in LaTeX
    • Defines \BODY and \Collect@Body commands
  • xparse – A generic document command parser
    • Defines b and +b argument types
  • amsmath – AMS mathematical facilities for LaTeX
    • Defines \collect@body command

Basic non-working example:

\documentclass{article}

\ExplSyntaxOn \makeatletter

\NewDocumentEnvironment { AnyEnvironment } {} {} {} \NewDocumentCommand { \MyMacro } { m } { Contents: ~ #1. } \AtBeginEnvironment { AnyEnvironment } { \MyMacro \bgroup } \AtEndEnvironment { AnyEnvironment } { \egroup }

\makeatother \ExplSyntaxOff

\begin{document}

\begin{AnyEnvironment} Example. \end{AnyEnvironment}

\end{document}

steve
  • 2,154
  • 1
    Comments have been moved to chat; please do not continue the discussion here. Before posting a comment below this one, please review the purposes of comments. Comments that do not request clarification or suggest improvements usually belong as an answer, on [meta], or in [chat]. Comments continuing discussion may be removed. – Joseph Wright Feb 05 '24 at 14:18

0 Answers0