4

I Kong that it’s impossible to have verbatim content in \BODY but is it possible to use an active character at least?

I define <x> as a shortcut for \fbox{x} and would like to be able to activate this with \activebox. Generally it works fine in normal environments and even if I use a wrapper but not if the activation is done directly in an environ environment.

\documentclass[ngerman]{article}

\usepackage{environ}
\begingroup
\catcode`< = \active
\gdef<#1>{
   \fbox{#1}
}
\endgroup
\def\activatebox{
   \catcode`<=\active
}

\NewEnviron{test}{
   \begin{itemize}
   \BODY
   \end{itemize}
}

\newenvironment{testwrapper}[1]{
   #1
   \test
} {
   \endtest
}

\begin{document}
   Test <Box>

   \begin{itemize}
      \activatebox
      \item Test <Box>
   \end{itemize}

   \begin{test}
      \activatebox
      \item Test <Box>
   \end{test}

   \begin{testwrapper}{\activatebox}
      \item Test <Box>
   \end{testwrapper}
\end{document}

In my real example it is of curse a bit more complicated: The \BODY is printed out in the document and also written to a file. I can’t use \lst@BeginWriteFile here because there is a single file saving multiple \BODYs. Here’s the original definition of my environment:

More context MWE

\documentclass{article}

\usepackage{environ,xparse, etoolbox}

\begingroup
\catcode`< = \active
\gdef<#1>{
   \fbox{#1}
}
\endgroup
\def\activatebox{
   \catcode`<=\active
}

\ExplSyntaxOn% ============================================================

\bool_new:N \tobi_in_group_of_boxes_bool
\bool_set_false:N \tobi_in_group_of_boxes_bool

\NewDocumentCommand { \mybox } { m } {
   \fbox { #1 }
   \bool_if:NF \tobi_in_group_of_boxes_bool {
   \iow_shipout_x:Nx \tobi_solutions_iow {
      \tl_to_str:n { \boxline }
         { \exp_not:n { \exp_not:N #1 } }
         { \exp_not:N \thepage }
   }
   }
}

\cs_generate_variant:Nn \iow_shipout:Nn { No }

\NewEnviron { boxgroup } {
   \bool_set_true:N \tobi_in_group_of_boxes_bool
   \iow_shipout_x:Nx \tobi_solutions_iow {
      \tl_to_str:n { \begin { boxgroup } } { \exp_not:N \thepage }
   }
   \iow_shipout:No \tobi_solutions_iow { \BODY }
   \iow_shipout_x:Nx \tobi_solutions_iow {
      \tl_to_str:n { \end { boxgroup } }
   }
   \par\textsf{\color{black!35}GROUP~START}\par
   \BODY
   \par\textsf{\color{black!35}GROUP~END}\par
}

\iow_new:N \tobi_solutions_iow
\iow_open:Nn \tobi_solutions_iow { \c_sys_jobname_str . boxes }
\AfterEndDocument {
   \iow_close:N \tobi_solutions_iow
}

\ExplSyntaxOff% ============================================================

\begin{document}
   Test <Box A> \mybox{Box B}

   \begin{itemize}
      \activatebox
      \item Test <Box C>
   \end{itemize}

   \begin{boxgroup}
      \activatebox
      Test <Box D>
   \end{boxgroup}

   \activatebox% must be part of the *.boxes file, thus can’t be
   % outside of the environment
   \begin{boxgroup}
      Test <Box E>
   \end{boxgroup}
\end{document}
  • You need to make the char active before the enironment grabs its body (= reads its argument which fixes catcodes): \activatebox\begin{test} \item Test <Box> \end{test}. Your testwrapper actually shows this nicely… – cgnieder May 20 '17 at 10:27
  • @clemens: I know, but I hoped that there is a way or working around this. E.g. hooking into environ somehow to check wether < is active or not. The problem with activating it outside the env (or in a wrapper) is that \activebox isn’t written to the file, which it has to be. (With the wrapper this would be possible, but I’d prefer a more elegant solution … – Tobi May 20 '17 at 10:32
  • \tl_set_rescan:Nnn might help you – cgnieder May 20 '17 at 10:34
  • @clemens: Hm … in that case I’d have to test within the environment body if \activateboxes is present and then do the rescan, however that won’t work if \activateboxes should be usable somewhere mid environment. I just tried \tl_rescan:nx { \activateboxed } { \BODY }, but it didn’t work. – Tobi May 20 '17 at 10:43
  • It works if I define new environment with the activation build in (see edited OP). – Tobi May 20 '17 at 10:43
1

Substitute something to < when it's time to typeset the contents.

\documentclass{article}
\usepackage[T1]{fontenc}

\usepackage{environ,xparse, etoolbox}

\ExplSyntaxOn
\cs_new_protected:Npn \tobi_active_less:w #1 >
 {
  \fbox{#1}
 }
\char_set_active_eq:NN < \tobi_active_less:w
\NewDocumentCommand{\activatebox}{}
 {
  \char_set_catcode_active:N <
  \bool_set_true:N \l_tobi_active_less_bool
 }

\cs_new:Npn \tobi_perhaps_active_less:
 {
  \bool_if:NTF \l_tobi_active_less_bool { \tobi_active_less:w } { < }
 }

\bool_new:N \l_tobi_active_less_bool
\bool_new:N \l_tobi_in_group_of_boxes_bool
\bool_set_false:N \l_tobi_in_group_of_boxes_bool

\NewDocumentCommand { \mybox } { m }
 {
  \fbox { #1 }
  \bool_if:NF \l_tobi_in_group_of_boxes_bool
   {
    \iow_shipout:Nx \tobi_solutions_iow
     {
      \exp_not:n { \boxline{#1} } { \thepage }
     }
   }
 }

\cs_generate_variant:Nn \iow_shipout:Nn { NV }

\NewEnviron { boxgroup }
 {
  \bool_set_true:N \l_tobi_in_group_of_boxes_bool
  \iow_shipout:Nx \tobi_solutions_iow
   {
    \exp_not:N \begin{boxgroup}{\thepage}
   }
   \iow_shipout:NV \tobi_solutions_iow \BODY
   \iow_shipout:Nn \tobi_solutions_iow
    {
     \end{boxgroup}
    }
   \par\textsf{\color{black!35}GROUP~START}\par
   \tl_replace_all:Nnn \BODY { < } { \tobi_perhaps_active_less: }
   \BODY
   \par\textsf{\color{black!35}GROUP~END}\par
 }

\iow_new:N \tobi_solutions_iow
\iow_open:Nn \tobi_solutions_iow { \c_sys_jobname_str . boxes }
\AfterEndDocument
 {
  \iow_close:N \tobi_solutions_iow
 }

\ExplSyntaxOff

\begin{document}

Test <Box A> \mybox{Box B}

\begin{itemize}
  \activatebox
  \item Test <Box C>
\end{itemize}

\begin{boxgroup}
  \activatebox
  Test <Box D>
\end{boxgroup}

\mybox{Abc\textbf{def}}

\end{document}

This is what will be written in the .boxes file; note I changed the code so that \thepage gets expanded, which your code doesn't.

\boxline {Box B}{1}
\begin {boxgroup}{1}
\activatebox Test <Box D>
\end {boxgroup}
\boxline {Abc\textbf {def}}{1}
| improve this answer | |
  • Thanks! This works fine. // Why do you say, that in my code \thepage is unexpanded? It seems to work in my code as I use \iow_shipout_x:Nx, thus \theblanknumber is immediately expanded but the expansion of \thepage is delayed until the shipout to make sure I get the correct number. At least that’s my plan and I couldn’t find a problem when testing. – Tobi May 21 '17 at 8:51
  • @Tobi \iow_shipout:Nn is simpler anyway. – egreg May 21 '17 at 9:07
  • Yeah, but while testing I had the problem that in that case the pagenumber wasn’t always correct, that why I switched to \iow_shipout_x – Tobi May 21 '17 at 9:30
  • I found a problem with your code, if the environment contains Test <Box D> $x = <5> = \frac{<10>}{<2>}$ it doesn’t work in the \frac parts … – Tobi May 21 '17 at 9:31
  • @Tobi No, but I'm not clairvoyant. You need l3regex if you want to do the substitution at any nesting level. – egreg May 21 '17 at 9:34
2

I'd probably do something along the following lines (not knowing what the final goal will be):

\documentclass{article}

\usepackage{environ,xparse,etoolbox}

\ExplSyntaxOn

\cs_new_protected:Npn \tobi_frame_box:w #1 > { \fbox {#1} }
\char_set_active_eq:NN < \tobi_frame_box:w


\tl_new:N \l__tobi_tmpa_tl
\bool_new:N \l_tobi_in_group_of_boxes_bool
\bool_set_false:N \l_tobi_in_group_of_boxes_bool

\cs_new_protected:Npn \tobi_handle_boxgroup:n #1
  {
    \bool_set_true:N \l_tobi_in_group_of_boxes_bool
    \iow_shipout_x:Nx \l_tobi_solutions_iow {
      \tl_to_str:n { \begin { boxgroup } } { \exp_not:N \thepage }
    }
    \iow_shipout:Nn \l_tobi_solutions_iow {#1}
    \iow_shipout_x:Nx \l_tobi_solutions_iow {
      \tl_to_str:n { \end { boxgroup } }
    }
    \par\textsf{\color{black!35}GROUP~START}\par
    #1
    \par\textsf{\color{black!35}GROUP~END}\par
  }
\cs_generate_variant:Nn \tobi_handle_boxgroup:n {V}

\NewEnviron {boxgroup} {
  \tl_set_rescan:NnV \l__tobi_tmpa_tl
    { \char_set_catcode_active:N < }
    \BODY
  \tobi_handle_boxgroup:V \l__tobi_tmpa_tl
}
\cs_generate_variant:Nn \tl_set_rescan:Nnn {NnV}

\iow_new:N \l_tobi_solutions_iow
\iow_open:Nn \l_tobi_solutions_iow { \c_sys_jobname_str . boxes }
\AfterEndDocument {
  \iow_close:N \l_tobi_solutions_iow
}

\ExplSyntaxOff

\begin{document}

\begin{boxgroup}
  Test <Box D>
\end{boxgroup}

\begin{boxgroup}
  Test <Box E>
\end{boxgroup}

\end{document}

test.boxes

\begin {boxgroup}{1}
Test <Box D>
\end {boxgroup}
\begin {boxgroup}{1}
Test <Box E>
\end {boxgroup}

document

enter image description here

| improve this answer | |
  • Thanks for your example. But as far as I can see in that case the active character is hard wired in the definition of {boxgroup}, while I’d like a version where I can use \activateboxes inside the environment to decide wether < is active or not. – Tobi May 21 '17 at 8:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.