1

Is there any way to allocate a placeholder and set the content later in the document? First of all I realize that this would require more than one pass to render correctly, but I see the references system does something similar:

See figure X on page Y.

The X and Y values are determined at some point later in the document and the next rendering pass fills in the proper numbers. I've looked in to hijacking the reference system, but couldn't figure out how to get it to back-fill anything but figure or page numbers.

To complicate matters, I would like two additional features beyond a generic back-reference.

  1. I would like to add more instances of the placeholder in multiple places as the document goes along and when a request to fill it comes it, have only the last delineated instance changed. All the previous place-holders should be basically locked down to whatever content they contained when a new placeholder slot is instantiated.

  2. Less important than #1, but I would like to be able to "fill" the back-reference multiple times and have only the last assignment stick. Being able to append would be a sweet bonus.

Pseudo code would look something like this:

\section*{Section 1 \namePlaceHolder{}}

Lorum ipsum...
\setLastName{-- my stuff}
Lorum ipsum...

\section*{Section 2 \namePlaceHolder{}}

Lorum ipsum...
Lorum ipsum...

\section*{Section 3 \namePlaceHolder{}}

Lorum ipsum...
\setLastName{-- your stuff}
Lorum ipsum...
\setLasteName{-- reassigned placeholder text}

\section*{Section 4 \namePlaceHolder{}}

Lorum ipsum...
\setLastName{-- his stuff}
Lorum ipsum...

Would render something like this:

desired output

The 'why' of this is that my content has a lot of \input{}s from other files and I want the content of these files to be able to go back and set some values that would have been in previously input text.

What mechanism can I pursue to make such a late substitution happen?

1

I'm still not completely sure precisely how you want this to work, but here's a stab at it.

Basic principle:

  1. The "user" interface operates by writing to the .aux file with a set of commands that get read-in at the beginning and end of the document, in the usual way.

  2. This would be super-simple if you just wanted the last command in time to be operative: each could just overwrite the previous definition. But you have rather complex requirements. So basically we use two counters and a toggle to keep track of things..

  3. There are two types of placeholder: \fixplaceholder which "blocks" material from filling backwards any more, and \useplaceholder, which doesn't. The MWE shows how those work.

  4. Obviously this means more than one run to get things straight.

MWE follows:

\documentclass{article}

\makeatletter
\newcommand{\DeclarePlaceHolder}[1]{%
  \expandafter\newcount\csname ph#1\endcsname
  \expandafter\newcount\csname phset#1\endcsname
  \csname phset#1\endcsname 0\relax}

\newcommand{\makeplaceholder}[3]{%
  \@ifundefined{ph#1}
    {\phwarnundefined{#1}}
    {\global\expandafter\def\csname #2\endcsname{#3}}}

\newcommand{\pherrorundefined}[1]{\GenericError{}
  {Undefined placeholder type '#1'}
  {You need to define a class of placeholders using \string\DeclarePlaceHolder{} 
  ^^Jbefore using them. (This could just be a typing error.)}}

\newcommand{\phwarnundefined}[1]{\GenericWarning{}
  {Warning: Reference to placeholder of type '#1' which has not been filled.}}

\newcommand{\useplaceholder}[1]{%
    \@ifundefined{ph#1}
      {\pherrorundefined{#1}}
      {\global\csname ph#1\endcsname\csname phset#1\endcsname\relax
       \def\@tempa{\expandafter\the\csname phset#1\endcsname}%
       \global\expandafter\def\csname ph\@tempa#1used\endcsname{}%
       \@ifundefined{ph@\@tempa#1value}
         {\phwarnundefined{#1}}
         {\csname ph@\@tempa #1value\endcsname}}}

\newcommand{\fixplaceholder}[1]{%
    \@ifundefined{ph#1}
      {\pherrorundefined{#1}}
      {\global\advance\csname phset#1\endcsname 1\relax
       \global\csname ph#1\endcsname\csname phset#1\endcsname\relax
       \def\@tempa{\expandafter\the\csname phset#1\endcsname}%
       \global\expandafter\def\csname ph\@tempa#1used\endcsname{}%
       \@ifundefined{ph@\@tempa#1value}
         {\phwarnundefined{#1}}
         {\csname ph@\@tempa #1value\endcsname}}}

\newcommand{\fillplaceholder}[2]{%
  \@ifundefined{ph#1}
    {\pherrorundefined{#1}}
    {\def\@tempa{\expandafter\the\csname ph#1\endcsname}%
       \@ifundefined{ph@\@tempa#1used}
       {\@ifundefined{ph@\@tempa#1set}
        {\global\advance\csname phset#1\endcsname 1\relax
         \global\expandafter\def\csname ph@\@tempa#1set\endcsname{}}%
         {}}%
       {}%
        \def\@tempa{\expandafter\the\csname ph#1\endcsname}%
        \protected@write\@auxout
       {}{\string\makeplaceholder{#1}{ph@\@tempa #1value}{#2}}}}


\makeatother

\DeclarePlaceHolder{name}

\begin{document}

\setlength{\parindent}{1em}

Placeholder labels must be pre-declared with \verb+\DeclarePlaceHolder{label}+.
Unless so declared an error will be produced.
% As can be verified by commenting out this line \setplaceholder{foo}

Placeholders are set with \verb+\fillplaceholder{label}{text}+. They only ever
\emph{backfill}, so if one is filled before any
have been used, it is effectively `dead', as the following
placeholder will be%
\fillplaceholder{name}{This will never be printed.} 
(not that there's anything to see).

Placeholders are used with either \verb+\useplaceholder{label}+ 
or with \verb+\fixplaceholder{label}+.

You can have a succession of \verb+\useplaceholder+ commands, 
and all will be `filled' back by the last \emph{active} 
\verb+\fillplaceholder+.

So these two will both be filled with \useplaceholder{name}! 
\useplaceholder{name}! \fillplaceholder{name}{happiness}


On the other hand if we use a succession of \verb+\fixplaceholder+
before a \verb+\fillplaceholder+ only the latest
will be filled (and any \verb+\useplaceholders+ \emph{before} it 
will also be empty): So these two will produce nothing
[\fixplaceholder{name}\useplaceholder{name}], 
whereas these two will: 
[\fixplaceholder{name}\useplaceholder{name}].
In other words a \verb+\fixplaceholder+ is a sort of dam, past which backfilling 
will not take place.\fillplaceholder{name}{filled}

If there are a succession of \verb+\fillplaceholder+ commands, with no 
intervening \verb+\useplaceholder+, only the last in time will `take': so 
this little placeholder will be filled with \useplaceholder{name}.

\fillplaceholder{name}{dread}% no!
\fillplaceholder{name}{unease}% no!!
\fillplaceholder{name}{satisfaction}

\section*{Section 1 \fixplaceholder{name}}

Lorum ipsum...
\fillplaceholder{name}{My Stuff}
Lorum ipsum...

\section*{Section 2 \fixplaceholder{name}}

Lorum ipsum...
Lorum ipsum...

\section*{Section 3 \fixplaceholder{name}}

Lorum ipsum...
\fillplaceholder{name}{Your Stuff}
Lorum ipsum...
\fillplaceholder{name}{Reassigned Text}

\section*{Section 4 \fixplaceholder{name}}

Lorum ipsum...
\fillplaceholder{name}{His Stuff}
Lorum ipsum...

But because placeholders only ever \emph{backfill}, 
a marooned \verb+\useplaceholder+ after everything has 
been set will be left undefined, in which case it will show 
nothing [\useplaceholder{name}] (and you get a warning).

\end{document}

Output (and instructions for use) follow. As I say, I'm not sure I've totally grasped your "use case".

enter image description here

  • This looks like it will do the trick. I spent days fiddling with this and couldn't hit on the right combination of tools. I'm sorry I couldn't describe more clearly what I wanted, but from skimming this you actually hit the nail on the head! I'll play with your MWE later today. – Caleb Apr 29 '14 at 11:02
  • The MWE here works brilliantly, but I'm having conniptions integrating it into my actual document environment. I actually got it to work, but not without doing some things that I cannot account for like always doing a \useplaceholder before using \fixplaceholder in a section tag, and more importantly having a \userplaceholder for each name I'm going to use in the order that they will first be filled in. This sort of monkey business does not seem to effect the MWE and I cannot figure out why its so touchy in my full environment. Any suggestions? Do either of those symptoms ring a bell? – Caleb May 5 '14 at 13:04
  • I don't know about the second problem. Could the first be caused by the table of contents in some way? Can you generate a MWE which exhibits the problem? – Paul Stanley May 5 '14 at 15:50
  • No, I've failed to get a MWE of any sort to fail, and my compile process is pretty involved because of some pre-processing and lilypond stuff. If I get one I'll post about it. For now all I can figure is the first line that fails is from \fixplaceholder: ` \def\@tempa{\expandafter\the\csname phset#1\endcsname}%`. That makes not just that line but all sorts of things throw "Undefined control sequence" errors. – Caleb May 5 '14 at 16:25
  • Thanks, that was actually a good clue. I still don't know what's wrong, but having to \use... first is eliminated by using starred versions of \section, etc. I'm using {titlesec} to adjust display of headers so using the starred versions isn't going to kill me, but it would be nice to know what is actually going on. – Caleb May 5 '14 at 20:59
1

While the awesome answer from Paul Stanley solves this problem and deserves the 'accept' credit and more upvotes, I ran into a few hiccups using it in my document environment. Following are the adjustments I made to the solution that might be of use to others with similar scenarios.

  • I changed the way place holders are instantiated. Instead of having to manually instantiate each place holder before use and throwing an error if it does not exist, I simply adapted the error code to instantiate placeholders on first use.

  • Two of the functions had a large amount of common code and only one minor difference between them. I replaced the repeated code with a call to the more generic function from inside the specialized one.

  • Placing a place holder inside a section title causes problems with the TOC. Specifically using section numbering conflicts with something in the counters.

    For example this works:

    \section*{My Section Name\FixPlaceHolder{name}}
    

    ...but this does not:

    \section{My Section Name\FixPlaceHolder{name}}
    

    The solution I came up with (hack alert!) was to put the place holder in the section header formatting like so:

    % Use package for customizing title formats
    \usepackage{tocloft}
    
    % Add a placeholder to the end of a string
    \newcommand*\InjectSectionPlaceHolder[1]{#1\FixPlaceHolder{name}}
    
    % Note the trailing function in the {before} section will get
    % passed the title contents as an argument
    \titleformat{section}[block]{}{}{}\InjectSectionPlaceHolder}[]
    

    After adding a numbered section is as easy as:

    \section{My Section}
    

    ...and all sections will have a placeholder specifically injected in them. Of course you will also need to insert the correct formatting for your section headers, but I was doing that anyway.

  • I ran into some name-space conflicts (as best I can figure related to Lilypond and pre-processing with lilypond-book) and adjusted some of the counter names to avoid this. More cosmetically, I used consistent casing for all the user-facing function names at the top level.

Here are my adjusted versions of the functions:

\newcommand*\DeclarePlaceHolder[1]{%
        \expandafter\newcount\csname ph#1\endcsname
        \expandafter\newcount\csname phset#1\endcsname
        \csname phset#1\endcsname 0\relax
}

\newcommand*\MakePlaceHolder[2]{%
        \global\expandafter\def\csname #1\endcsname{#2}
}

\newcommand*\UsePlaceHolder[1]{%
        \@ifundefined{ph#1}{\DeclarePlaceHolder{#1}}{}%
        \global\csname ph#1\endcsname\csname phset#1\endcsname\relax
        \def\@phtempa{\expandafter\the\csname phset#1\endcsname}%
        \global\expandafter\def\csname ph\@phtempa#1used\endcsname{}%
        \@ifundefined{ph@\@phtempa#1value}{%
        }{%
                \csname ph@\@phtempa #1value\endcsname
        }%
}

\newcommand*\FixPlaceHolder[1]{%
        \@ifundefined{ph#1}{\DeclarePlaceHolder{#1}}{}%
        \global\advance\csname phset#1\endcsname 1\relax
        \UsePlaceHolder{#1}
}

\newcommand\FillPlaceHolder[2]{%
        \@ifundefined{ph#1}{\DeclarePlaceHolder{#1}}{}%
        \def\@phtempa{\expandafter\the\csname ph#1\endcsname}%
        \@ifundefined{ph@\@phtempa#1used}{%
                \@ifundefined{ph@\@phtempa#1set}{%
                        \global\advance\csname phset#1\endcsname 1\relax
                        \global\expandafter\def\csname ph@\@phtempa#1set\endcsname{}%
                }{}%
        }{}%
        \def\@phtempa{\expandafter\the\csname ph#1\endcsname}%
        \protected@write\@mainaux{}{\string\MakePlaceHolder{ph@\@phtempa #1value}{#2}}
}
  • That's obviously much better than mine! But I'm glad I could get you started: it was a surprisingly difficult thing. – Paul Stanley May 14 '14 at 17:17
  • @PaulStanley I believe you! I hacked on a lot of different methods before giving up and asking here. The way you've convinced latex to implement the concept of variable-variable-names here was certainly over my head. – Caleb May 15 '14 at 8:03

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.