11

As I have stated already in other questions I am writing a problem/solution package. There are many of them, for sure, I have made much progress, using it in 'everydays' productivity for my needs, but is not designed for other users so far. I came across some strange behaviour, which I initially thought is my fault of wrong usage.

Basically I use a parent environment which is on one hand responsible for formatting the problem (configurable via xkeyval keys), on the other hand is is the driver, that stores the solution (contained in a similar environment, say called 'child') to an extern file, which is afterwards read at the position the user wants to have it.

The problem is now, that this will fail as soon as there are other commands handed over to the key values.

This is a MWE which fails during the \immediate\write process when the second parent call is done with the ChildOutputStyle=\YetAnotherOutputStyle.

\documentclass{article}
\usepackage{xkeyval}
\usepackage{xcolor}


\newcommand{\DefaultTextStyle}[1]{%
\textbf{\textcolor{blue}{#1}}%
}%

\newcommand{\YetAnotherOutputStyle}[1]{%
\textbf{\textcolor{green}{#1}}%
}%


\newwrite\OutputFileHandle%

\makeatletter%
\define@key{FamilyA}{ChildOutputStyle}[\DefaultTextStyle]{%
\def\KVMacroChildOutputStyle{#1}%
}%

\makeatother

\newcommand{\Child}[2][]{%
\setkeys{FamilyA}{#1}%

\KVMacroChildOutputStyle{#2}%

}% End of \newcommand{\Child} %



\newcommand{\Parent}[3][]{%
\setkeys{FamilyA}{#1}%

%  Do some stuff before with 2nd arg of command ('problem')
#2\par %%%%%
%%%%
%
% Now write solution ('child') content to filehandle
\immediate\write\OutputFileHandle{%
\string\Child[#1]{#3}%
}%
}%  End of \Parent command


\begin{document}
\presetkeys{FamilyA}{ChildOutputStyle={\DefaultOutputStyle}}{}%
\immediate\openout\OutputFileHandle=\jobname.myext


\textbf{\textcolor{violet}{First 'Parent' content}}% 
\par
\Parent{One Ring To Rule Them All}{One Ring To Find Them}  % I hope, Tolkien does not mind! 

%%% This code breaks when tried to save it immediately to another file!!!!
\Parent[ChildOutputStyle=\YetAnotherOutputStyle]{When shall we three meet again}{In Thunder, lightning or in rain} % William Shakespeare will not mind ;-)
%%%%


\immediate\closeout\OutputFileHandle

\textbf{\textcolor{red}{Now 'Child' content}}% 
\par
\input{\jobname.myext} % replace it afterwards with \IncludeIfFileExists... etc.

\end{document}

The compilation fails with this message

! Use of \XKV@resa doesn't match its definition.
\XKV@for@n #1#2#3->\XKV@tempa@toks {#1}\edef #2{
                                                \the \XKV@tempa@toks }\ifx #...
l.57 ...t again}{In Thunder, lightning or in rain}

Is there any workaround (besides using the verbatim/moreverb packages?)

Some remarks at the end:

  • I have replaced the \newenvironment statements from my original package by \newcommands, to make the example shorter, but I prefer the environment style.
  • The \DefaultTextStyle and \YetAnotherOutputStyle commands are just placeholders for some 'arbitrary' commands.
  • I omitted \AtBeginDocument for opening the file and AtEndDocument for closing it also to keep the code short.

I am sure other users will profit from a solution as well.

  • I am not fully sure whether your problem could be solved using these: http://tex.stackexchange.com/questions/8095/automatically-adding-potentially-referenced-macros-from-auxillary-file or http://tex.stackexchange.com/questions/52256/automatic-deletion-of-unused-macros/52264#52264 – nickpapior Mar 04 '14 at 18:26
  • 1
    You have to use the "immediate" version of \protected@write, but also to protect \textcolor which is fragile. See http://tex.stackexchange.com/questions/75951/how-to-write-the-symbol-into-a-file-when-using-package-utf8inputenc for \protected@iwrite. Add \protect before \textcolor or use \DeclareRobustCommand for the styles. – egreg Mar 04 '14 at 18:54
  • @zeroth: On a first glance I am not sure that topic/solution is connected to my question, but I will return to it. –  Mar 04 '14 at 20:20
  • @ChristianH. Ok, nevermind then... :) – nickpapior Mar 04 '14 at 20:28

1 Answers1

12

The big problem is that you want to pass to \write commands such as \textbf or \textcolor that don't survive it. The kernel has \protected@write for this, but no “immediate” version.

However, it's easy to define one as done in How to write the € symbol into a file, when using Package [utf8]{inputenc}

You also must ensure that \textcolor is protected, because it's fragile by itself; the easiest way is to define the styles with \DeclareRobustCommand:

\documentclass{article}
\usepackage{xkeyval}
\usepackage{xcolor}


\DeclareRobustCommand{\DefaultTextStyle}[1]{%
  \textbf{\textcolor{blue}{#1}}%
}

\DeclareRobustCommand{\YetAnotherOutputStyle}[1]{%
  \textbf{\textcolor{green}{#1}}%
}


\newwrite\OutputFileHandle

\makeatletter
\define@key{FamilyA}{ChildOutputStyle}[\DefaultTextStyle]{%
  \def\KVMacroChildOutputStyle{#1}%
}


\newcommand{\Child}[2][]{%
  \setkeys{FamilyA}{#1}
  \KVMacroChildOutputStyle{#2}%
}

%%% Helper macro
\long\def\protected@iwrite#1#2#3{%
      \begingroup
       \let\thepage\relax
       #2%
       \let\protect\@unexpandable@protect
       \edef\reserved@a{\immediate\write#1{#3}}%
       \reserved@a
      \endgroup
      \if@nobreak\ifvmode\nobreak\fi\fi
}

\newcommand{\Parent}[3][]{%
  \setkeys{FamilyA}{#1}%
  %  Do some stuff before with 2nd arg of command ('problem')
  #2\par %%%%%
  %%%%
  %
  % Now write solution ('child') content to filehandle
  \protected@iwrite\OutputFileHandle{}{%
    \string\Child[#1]{#3}%
  }%
}
\makeatother


\begin{document}
\presetkeys{FamilyA}{ChildOutputStyle={\DefaultTextStyle}}{}%
\immediate\openout\OutputFileHandle=\jobname.myext


\textbf{\textcolor{violet}{First 'Parent' content}}

\Parent{One Ring To Rule Them All}{One Ring To Find Them}  % I hope, Tolkien does not mind! 

%%% This code breaks when tried to save it immediately to another file!!!!
\Parent[ChildOutputStyle=\YetAnotherOutputStyle]{When shall we three meet again}{In Thunder, lightning or in rain} % William Shakespeare will not mind ;-)
%%%%


\immediate\closeout\OutputFileHandle

\textbf{\textcolor{red}{Now 'Child' content}}

\input{\jobname.myext} % replace it afterwards with \IncludeIfFileExists... etc.

\end{document}

enter image description here

Here's the content of the .myext file:

\Child[]{One Ring To Find Them}
\Child[ChildOutputStyle=\protect \YetAnotherOutputStyle  ]{In Thunder, lightning or in rain}

A different strategy uses \write, but accompanying it with \unexpanded:

\documentclass{article}
\usepackage{xkeyval}
\usepackage{xcolor}


\newcommand{\DefaultTextStyle}[1]{%
  \textbf{\textcolor{blue}{#1}}%
}

\newcommand{\YetAnotherOutputStyle}[1]{%
  \textbf{\textcolor{green}{#1}}%
}


\newwrite\OutputFileHandle

\makeatletter
\define@key{FamilyA}{ChildOutputStyle}[\DefaultTextStyle]{%
  \def\KVMacroChildOutputStyle{#1}%
}


\newcommand{\Child}[2][]{%
  \setkeys{FamilyA}{#1}
  \KVMacroChildOutputStyle{#2}%
}

\newcommand{\Parent}[3][]{%
  \setkeys{FamilyA}{#1}%
  %  Do some stuff before with 2nd arg of command ('problem')
  #2\par %%%%%
  %%%%
  %
  % Now write solution ('child') content to filehandle
  \immediate\write\OutputFileHandle{%
    \string\Child[\unexpanded\expandafter{#1}]{\unexpanded{#3}}%
  }%
}

\makeatother


\begin{document}
\presetkeys{FamilyA}{ChildOutputStyle={\DefaultTextStyle}}{}%
\immediate\openout\OutputFileHandle=\jobname.myext


\textbf{\textcolor{violet}{First 'Parent' content}}

\Parent{One Ring To Rule Them All}
       {One Ring To Find Them}  % I hope, Tolkien does not mind! 

%%% This code breaks when tried to save it immediately to another file!!!!
\Parent[ChildOutputStyle=\YetAnotherOutputStyle]
       {When shall we three meet again}
       {In Thunder, lightning or in rain} % William Shakespeare will not mind ;-)

\Parent[ChildOutputStyle=\DefaultTextStyle]
       {A formula}
       {\begin{math}\sqrt{2}^2=2\end{math}}

%%%%


\immediate\closeout\OutputFileHandle

\textbf{\textcolor{red}{Now 'Child' content}}

\input{\jobname.myext} % replace it afterwards with \IncludeIfFileExists... etc.

\end{document}

Here's the output in the .myext file:

\Child[]{One Ring To Find Them}
\Child[ChildOutputStyle=\YetAnotherOutputStyle ]{In Thunder, lightning or in rain}
\Child[ChildOutputStyle=\DefaultTextStyle ]{\begin {math}\sqrt {2}^2=2\end {math}}
egreg
  • 1,121,712
  • I tested your solution -- Unfortunately the compilation jumps out of the window precisely at the \showtoken statement. I am using TeXLive 2013, so it should not be an issue with an outdated version, but otherwise I see a very sophisticated solution. The \DeclareRobustCommand should probably applied to any 'style' or whatever command? –  Mar 04 '14 at 20:16
  • 1
    Sorry, I used \showtokens for debugging, it wasn't meant to be in the "production version". – egreg Mar 04 '14 at 20:25
  • It works now as a MWE, I want to test it in the true package tomorrow –  Mar 04 '14 at 22:45
  • I does not work since I use the 3rd argument of the parent environment as content for the child, which should be written to file, with any markup. If one changes the third argument of \Parent to \begin{math} E = mc^2 \end{math}, it will fail again, most probably due to the reason you stated alreay -- the complex content in an argument will break. Is there any way to robustify this argument right from the start such that the user does not have to do him/herself? –  Mar 05 '14 at 07:16
  • 1
    @ChristianH. I added an alternative version – egreg Mar 05 '14 at 09:26
  • I will try it in the afternoon, I have no access to my package code at the moment. –  Mar 05 '14 at 09:38
  • It works as desired -- I experimented before asking the question with \expandafter but not in combination with unexpanded, in a previous version I stored the options to a token and expanded it afterwards. –  Mar 06 '14 at 11:32