1

I'm trying to separate the definition and placement of figures, tables, listings, etc. I find them highly disruptive when editing the prose of my document. They often take up a large number of lines in the middle of a collection of paragraphs making it hard to edit the text. Controlling the placement of figures often requires moving the entire environment somewhere else.

So far I have been able to do so with figures and tables by adapting the code given in this answer. See the unplacedfigure environment below. It uses xparse to capture the environment contents and store it in a token list. However, \NewDocumentEnvironment is unable to capture verbatim content. How can I create a unplacedlisting environment? Or are there any good alternative approaches?

Here is my code:

\documentclass{article}

\usepackage{xparse} \usepackage{listings} \usepackage{lstautogobble} \usepackage{graphicx} \usepackage{float}

% An unplaced environment and a place command % stolen from https://tex.stackexchange.com/a/561961/239612 \ExplSyntaxOn \prop_new:N\g_unplaced_prop \NewDocumentEnvironment{unplaced}{m +b} { \prop_gput:Nnn\g_unplaced_prop {#1} {#2} } {} \NewDocumentCommand{\place}{m} { \prop_item:Nn\g_unplaced_prop {#1} } \ExplSyntaxOff

% An unplacedfigure environment that specifies content of the listing % separately from its placement. Notice that float specifiers are % given at placement time. \NewDocumentEnvironment{unplacedfigure}{m +b} { \begin{unplaced}{#1} #2 } { \end{unplaced} } \NewDocumentCommand{\placefigure}{m O{}} { \begin{figure}[#2] \place{#1} \end{figure}% }

% I want to define a similar environment for verbatim content. \NewDocumentEnvironment{unplacedlisting}{m +b} { \begin{unplaced}{#1} #2 } { \end{unplaced} } \NewDocumentCommand{\placelisting}{m} { TODO }

\begin{document} \begin{unplacedfigure}{myfig1} \centering \caption{Two beautiful pictures.} \includegraphics[width=0.3\textwidth]{example-image-a} \includegraphics[width=0.2\textwidth]{example-image-b} \end{unplacedfigure} \begin{unplacedfigure}{myfig2} \centering \caption{Two pictures.} \includegraphics[width=0.15\textwidth]{example-image-a} \includegraphics[width=0.3\textwidth]{example-image-b} \end{unplacedfigure} % DOES NOT WORK: % \begin{unplacedlisting}{mylisting} % code code code code % code special characters like % and } % code code code code % code code code code % code code code code % \end{unplacedlisting}

text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text etc. % \placefigure{myfig1}[H] % text text text text text etc. % \placefigure{myfig2}[H] % text text text text text etc. % \placelisting{mylisting}[hbp] % text text text text text etc. % \placefigure{myfig1}[H]

\end{document}

  • Documentation (texdoc latex2e) says: "You cannot use the verbatim environment in the argument to macros, for instance in the argument to a \section." Perhaps verbatimbox package could help? (I haven't tried yet.) – Cicada Feb 25 '22 at 02:42
  • 2
    You can put each figure/table/listing in a separate file with just that figure/table/listing and use \input, or put them all together in one supplementary file file and use catchfilebetweentags. – Marijn Feb 25 '22 at 16:09
  • 1
    Or use an editor with decent code folding and fold the environments that you don't want to see. – Marijn Feb 25 '22 at 16:11

1 Answers1

1

It is possible to achieve what we want using the great scontents package. I had to change the usage pattern slightly because it seems to be impossible to wrap scontents environments in a custom environments.

Storing a figure is done exactly as before, except that we use the scontents environment instead of a custom unplacedfigure environment.

\begin{scontents}[store-env=myfig]
  <figure code>
\end{scontents}

To store a listing, we need to use the verbatim environment at the declaration site like so:

\begin{scontents}[store-env=mylst]
  \begin{verbatim}
   <verbatim content>
  \end{verbatim}
\end{scontents}

The placement interface is identical:

\placefigure{myfig}[htb!]
\placelisting{mylst}[H]

It works fairly well even though it is slightly uglier than the original suggestion since we cannot hide scontents as an implementation detail. Here is the full code:

\documentclass{article}

\usepackage{xparse} \usepackage{listings} \usepackage{lstautogobble} \usepackage{graphicx} \usepackage{float} \usepackage{scontents}

\NewDocumentCommand{\placefigure}{m O{}} { \begin{figure}[#2] \getstored{#1} \end{figure}% }

\newfloat{listingfloat}{tbp}{asdf}[section] \floatname{listingfloat}{Listing} \NewDocumentCommand{\placelisting}{m O{}} { \begin{listingfloat}[#2] \getstored{#1} \end{listingfloat}% }

\begin{document}

\begin{scontents}[store-env=myfig1] \centering \caption{Two beautiful pictures.} \includegraphics[width=0.3\textwidth]{example-image-a} \includegraphics[width=0.2\textwidth]{example-image-b} \end{scontents} \begin{scontents}[store-env=myfig2] \centering \caption{Two pictures.} \includegraphics[width=0.15\textwidth]{example-image-a} \includegraphics[width=0.3\textwidth]{example-image-b} \end{scontents} \begin{scontents}[store-env=mylisting] \caption{A very advanced program} \begin{lstlisting} code code code code code special characters like % and } code code code code code code code code code code code code \end{lstlisting} \end{scontents}

text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text etc. % \placefigure{myfig1}[H] % text text text text text etc. % \placefigure{myfig2}[H] % text text text text text etc. % \placelisting{mylisting}[hbp] % text text text text text etc. % \placefigure{myfig1}[H]

\end{document}

  • It appears that this technique (also in the original question) creates a new paragraph after each figure placement. How can I prevent this? It should be possible to use a \place command in the middle of a paragraph. – MyComputer Feb 26 '22 at 11:15