4

Let's say I have the following

\newcommand\app[1]{\textbf{#1}} % <- #1 is appended's macro's parameter
\apptocmd{\app}{#1}{}{} % <- passing appended macro's parameter to appended macro again

\app{Food App}

Macro \app will look like -> \textbf{#1}#1

Let's say I want to write every occurrence of \app to a file:

\newwrite\appfile
\AtBeginDocument{\immediate\openout\appfile=\jobname-app.txt}
\AtEndDocument{\immediate\closeout\appfile} 
\apptocmd{\app}{\immediate\write\appfile{#1}}{}{}

Problem

Now let's say I want to be schnazzy and write every occurrence of app to a file, but only when "debug" mode is on.

So I could

  1. surround this in a macro
  2. surround this in an conditional

For option number 1, I do not know what to do with my parameter #1. I tried using \noexpand#1, but it does not work. I need to pass the #1 to the original \app macro.

\newcommand\debugmode{
  \newwrite\appfile
  \AtBeginDocument{\immediate\openout\appfile=\jobname-app.txt}
  \AtEndDocument{\immediate\closeout\appfile} 
  \apptocmd{\app}{\immediate\write\appfile{#1}}{}{}
}
\debugmode

Option 2, is applied real-time while parsing, which is not ideal for my situation (my situation is not shown here):

  \newif\ifdebugmode
  \ifdebugmode %
  \newwrite\appfile
  \AtBeginDocument{\immediate\openout\appfile=\jobname-app.txt}
  \AtEndDocument{\immediate\closeout\appfile} 
  \apptocmd{\app}{\immediate\write\appfile{#1}}{}{}
  \fi

  \debugmodetrue

Example

See remarks in code.

\documentclass{article}
\usepackage{fontspec}% typeset with xelatex
\usepackage{etoolbox}

\newcommand\app[1]{\textbf{#1}}

\newcommand\debugmode{
  \newwrite\appfile
  \AtBeginDocument{\immediate\openout\appfile=\jobname-app.txt}
  \AtEndDocument{\immediate\closeout\appfile} 
  \apptocmd{\app}{\immediate\write\appfile{#1}}{}{} % <-- #1 not expanded correctly, because it is embedded. LaTeX expects ##1
}
\debugmode

\begin{document}
\app{Food App}
\app{Dictionary App}
\end{document}

And by the way, to my disappointment, I actually had to revert to LaTeX2e because LaTeX3 does not really support patching. :( I find myself going back to the roots...TeX

  • You need ##1 in place of #1 for option (1). – cfr May 2 '16 at 14:20
  • @cfr Tried that. Doesnt work. I should have mentioned that. This is because ##1 gets passed to the original (appended macro). You end up with \textbf{#1}##1. I think this is the case. – Jonathan Komar May 2 '16 at 14:21
  • Actually, the patch to \app fails. The definition remains just \textbf{#1}. Two ways to see this: use the empty arguments of \apptocmd; add \show\app at the end of the \debugmode definition. – cfr May 2 '16 at 14:25
  • The no-patching in l3 is status-by-design if you are referring to macros defined with \DeclareDocumentCommand and friends. As I understand it, if you want to patch, you're doing it wrong. (I haven't wanted to patch, but I'm also doing it wrong, as I understand it ;).) – cfr May 2 '16 at 16:04
  • Is fontspec reqlly required to demonstrate this issue? – cfr May 2 '16 at 16:04
1

\apptocmd doesn't like to be in the argument to another command when # is involved.

You can do it with a conditional:

\documentclass{article}
\usepackage{etoolbox}

\newcommand\app[1]{\textbf{#1}}

\newif\ifdebugmode
\debugmodetrue % comment for not applying the patches
\ifdebugmode
  \newwrite\appfile
  \AtBeginDocument{\immediate\openout\appfile=\jobname-app.txt} 
  \AtEndDocument{\immediate\closeout\appfile} 
  \apptocmd\app{\immediate\write\appfile{\unexpanded{\app{#1}}}}{}{} 
\fi

\begin{document}

\app{Food App}
\app{Dictionary App}

\end{document}

(I left off fontspec that's not relevant to the application).

The contents of the -app.txt file will be

\app {Food App}
\app {Dictionary App}

Alternatively, use regexpatch:

\documentclass{article}
\usepackage{regexpatch}

\newcommand\app[1]{\textbf{#1}}

\newcommand\debugmode{%
  \newwrite\appfile
  \AtBeginDocument{\immediate\openout\appfile=\jobname-app.txt}
  \AtEndDocument{\immediate\closeout\appfile}
  \xapptocmd\app{\immediate\write\appfile{\unexpanded{\app{##1}}}}{}{}
}
\debugmode

\begin{document}

\app{Food App}
\app{Dictionary App}

\end{document}
2

I am unclear on the detailed behavior desired, but...

Is this what is desired?

\documentclass{article}
\usepackage{xpatch}
\newcommand\app[1]{\textbf{#1}} % <- #1 is appended's macro's parameter
\def\addtoapp#1{%
  \apptocmd{\app}{#1}{}{} % <- passing appended macro's parameter to appended macro again
}
\begin{document}
\app{Food App}
\addtoapp{This is a test}

\app{Food App}
\end{document}

enter image description here

Or this??

\documentclass{article}
\usepackage{xpatch}
\newcommand\app[1]{\def\tmp{#1}\textbf{\tmp}} % <- #1 is appended's macro's parameter
\def\addtoapp#1{%
  \xpatchcmd{\app}{{\tmp}}{{#1}}{}{} % <- passing appended macro's parameter to appended macro again
}
\begin{document}
\app{Food App}
\addtoapp{This is a test}

\app{Food App}
\end{document}

enter image description here

  • @macmadness86 I am not sure of the issue. I can add xparse to my MWE, either before or after xpatch and get no option clash. Perhaps you can edit your MWE to reflect it. – Steven B. Segletes May 2 '16 at 15:27
  • @macmadness86 Carry on bravely. We will await an eventual edit. – Steven B. Segletes May 2 '16 at 15:29
  • I used \usepackage[log-declarations=false]{xparse}, but \RequirePackage{xpatch} in my package loads it without that parameter I suppose. There is some \PassOptionToPackage trick maybe for this. – Jonathan Komar May 2 '16 at 15:50
  • 1
    @macmadness86 I only have the problem cited if I load xparse after xpatch. Try loading those two packages in the reverse order. – Steven B. Segletes May 2 '16 at 15:52
  • 1
    @macmadness86 Just for some perspective, there is nothing TeXwise blasphemous about requiring a certain package load order. It is well known, for example, that hyperref should always be loaded as late as possible. – Steven B. Segletes May 2 '16 at 15:57

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.