8

LaTeX3 has some great concepts and functions. One is the ability to replace text in a token list. This opens up possibilities to create templates in a way that html templates are used for example by handlebars

The only reason for the existence of such templates is to simplify the entering of mark-up, being either by humans or computers. Consider the case of having mark-up for multiple images such as the one below:

enter image description here

The mark-up can get very tedious. A markup of the form:

!!img amato!! 
!!cap This is the first caption!!

would greatly simplify the mark-up. The !!img is a marker to pick-up images and !!cap to pickup captions. I have used the !! as a marker but of course anything can be used as long as is allowed by a token list. The three letters that follow denote different mark-up, i.e. img for image, cap for caption.

Here is the code:

\documentclass{article}
\usepackage{expl3, graphicx,caption}
\begin{document}

\ExplSyntaxOn
  \cs_set:Npn  \putimage#1!!{%
       \includegraphics[width=\linewidth]{./images/amato}%
   }

 \cs_set:Npn  \putsomecaption#1!!{
     \captionof{figure}{#1}
     \par\endminipage\hfill
  }  

  \tl_set:Nn \tempai {
      \centering
      !!img amato!! 
      !!cap This~is~the~first~caption!!

      !!img amato!!
      !!cap This~is~the~second~caption!!

      !!img amato.jpg!!
      !!cap This~is~the~third~caption!!

      !!img amato!!
      !!cap This~is~the~fourth~caption!!

      !!img amato!!
      !!cap This~is~the~fifth~caption!!

      !!img amato!!
      !!cap This~is~the~sixth~caption!!
}

   \tl_replace_all:Nnn\tempai {!!img}{\minipage{3.6cm}\centering\putimage}
   \tl_replace_all:Nnn\tempai {!!cap}{\putsomecaption}
   \tl_use:N \tempai
\ExplSyntaxOff   
\end{document}

I have difficulties turning the above code in a suitable environment. Can someone provide a solution. Say to have an environment multimages.

  • May be a double map? (It's in the documentation interface3.pdf I think) like \foo{ {amato}{The ~ caption} {amato}{Another ~ caption} .. } and let expl3 handle all? – Manuel May 14 '15 at 18:58
  • @Manuel Thanks. user input must be as I have shown it. Problem is to define a suitable environment. \begin{multimages}...\end{multimages} to hold the user input. – Yiannis Lazarides May 14 '15 at 19:02
  • you presumably don't want user input to be in the scope of the l3 programming conventions where space has to be entered as ~ ? That was never intended for entering any kind of user text, although can be used for small fixed texts such as error messages within the program code of course. – David Carlisle May 14 '15 at 19:05
  • environ package allows to create a token list from an environment “\BODY”, there, you replace {!!img} and {!!cap} and I think you are done. To be more “free”, you could take a look at l3regex. – Manuel May 14 '15 at 19:06
  • @DavidCarlisle Sure that is why I am looking at a suitable environment. – Yiannis Lazarides May 14 '15 at 19:13
4

I don't think this is simpler input. However, pursuing further Manuel's idea, here's a version with full featured options.

\documentclass{article}
\usepackage{showframe}
\usepackage{xparse,mwe,graphicx,caption,environ}

\ExplSyntaxOn
\NewEnviron{multiimages}[1][]
 {
  \keys_set:nn { yl/multiimages } { #1 }
  \tl_use:N \l_yl_multi_start_tl
  \dim_set:Nn \parindent { 0pt }
  \skip_set:Nn \leftskip { 0pt plus 1fil }
  \skip_set:Nn \rightskip { 0pt plus -1fil }
  \skip_set:Nn \lineskip { \l_yl_multi_skip_skip }
  \yl_multiimages:V \BODY
  \tl_use:N \l_yl_multi_end_tl
 }

\tl_new:N \l_yl_multi_start_tl
\tl_new:N \l_yl_multi_end_tl

\keys_define:nn { yl/multiimages }
 {
  env .choice:,
  env/none .code:n =
   \tl_set:Nn \l_yl_multi_start_tl { \par\addvspace{\topsep} }
   \tl_set:Nn \l_yl_multi_end_tl { \par\addvspace{\topsep} },
  env/figure .code:n =
   \tl_set:Nn \l_yl_multi_start_tl { \__yl_multi_beginfigure:V \l_yl_multi_pos_tl }
   \tl_set:Nn \l_yl_multi_end_tl { \end{figure} },
  env .initial:n = none,

  pos .tl_set:N = \l_yl_multi_pos_tl,
  pos .initial:n = { htp },

  outer .dim_set:N = \l_yl_multi_outer_dim,
  outer .initial:n = 3.6cm,
  inner .dim_set:N = \l_yl_multi_inner_dim,
  inner .initial:n = 3.6cm,

  skip .dim_set:N = \l_yl_multi_skip_skip,
  skip .initial:n = \lineskip,

  last .choice:,
  last/fill .code:n = 
   \tl_set:Nn \l_yl_multi_last_tl { { \parfillskip=0pt\par } },
  last/center .code:n =
   \tl_set:Nn \l_yl_multi_last_tl { { \parfillskip=0pt plus 2fil\par } },
  last .initial:n = fill,
 }

\cs_new_protected:Npn \__yl_multi_beginfigure:n #1
 {
  \begin{figure}[#1]
 }
\cs_generate_variant:Nn \__yl_multi_beginfigure:n { V }

\cs_new_protected:Npn \yl_multiimages:n #1
 {
  \tl_set:Nn \l_tmpa_tl { #1 }
  \tl_remove_all:Nn \l_tmpa_tl { \par }
  \tl_replace_all:Nnn \l_tmpa_tl { !!img ~ } { \__yl_multi_img:w }
  \tl_replace_all:Nnn \l_tmpa_tl { !!cap ~ } { \__yl_multi_cap:w }
  \tl_use:N \l_tmpa_tl \tl_use:N \l_yl_multi_last_tl
 }
\cs_generate_variant:Nn \yl_multiimages:n { V }

\cs_new_protected:Npn \__yl_multi_img:w #1 !!
 {
  \begin{minipage}{\l_yl_multi_outer_dim}\centering
  \includegraphics[width=\l_yl_multi_inner_dim]{ #1 }
 }
\cs_new_protected:Npn \__yl_multi_cap:w #1 !!
 {
  \captionof{figure}{#1}
  \end{minipage}\hspace{1pc plus 3pc}
 }
\ExplSyntaxOff   

\begin{document}

\begin{multiimages}[env=figure,pos=ht]
  !!img example-image-a!! 
  !!cap This is the first caption!!

  !!img example-image-a!!
  !!cap This is the second caption!!

  !!img example-image-a!!
  !!cap This is the third caption!!

  !!img example-image-a!!
  !!cap This is the fourth caption!!

  !!img example-image-a!!
  !!cap This is the fifth caption!!

  !!img example-image-a!!
  !!cap This is the sixth caption!!
\end{multiimages}

\begin{multiimages}[last=center]
  !!img example-image-a!! 
  !!cap This is the first caption!!

  !!img example-image-a!!
  !!cap This is the second caption!!

  !!img example-image-a!!
  !!cap This is the third caption!!

  !!img example-image-a!!
  !!cap This is the fourth caption!!

  !!img example-image-a!!
  !!cap This is the fifth caption!!

\end{multiimages}

\begin{multiimages}[last=center,env=figure,pos=p,inner=3cm,skip=10ex]
  !!img example-image-a!! 
  !!cap This is the first caption!!

  !!img example-image-a!!
  !!cap This is the second caption!!

  !!img example-image-a!!
  !!cap This is the third caption!!

  !!img example-image-a!!
  !!cap This is the fourth caption!!

  !!img example-image-a!!
  !!cap This is the fifth caption!!

\end{multiimages}

\end{document}

enter image description here

  • Thanks. Is there no way to collect the BODY other than using the environ package? It is kind of sad that environ uses toks and the idea behind the expl3 token lists was to avoid and improve them by recreating them with tl. – Yiannis Lazarides May 15 '15 at 1:55
  • Should it be \begin{figure}[\l_yl_multi_pos] or \begin{figure}[\l_yl_multi_pos_tl]? – Yiannis Lazarides May 15 '15 at 4:00
  • @YiannisLazarides Yes, but it should be done in a less direct way. Fixed. – egreg May 15 '15 at 9:17
7
\documentclass{article}
\usepackage{xparse,mwe,graphicx,caption,environ}

\NewEnviron{multiimages}{\processmultiimages{\BODY}}

\ExplSyntaxOn
\NewDocumentCommand \processmultiimages { m }
 { \par \centering \yl_multiimages:N #1 }
\cs_new_protected:Npn \yl_multiimages:N #1
 {
  \tl_set_eq:NN \l_tmpa_tl #1
  \tl_remove_all:Nn \l_tmpa_tl { \par }
  \tl_replace_all:Nnn \l_tmpa_tl { !!img ~ } 
   { \begin{minipage}{3.6cm}\centering\multiimg }
  \tl_replace_all:Nnn \l_tmpa_tl { !!cap ~ } 
   { \multiimgcapt }
  \tl_use:N \l_tmpa_tl
 }
\NewDocumentCommand \multiimg { u{!!} }
 { \includegraphics[width=\linewidth]{ #1 } }

\NewDocumentCommand \multiimgcapt { u{!!} }
 { \captionof{figure}{#1} \par\end{minipage}\hfill }
\ExplSyntaxOff   

\begin{document}

\begin{multiimages}
  !!img example-image-a!! 
  !!cap This is the first caption!!

  !!img example-image-a!!
  !!cap This is the second caption!!

  !!img example-image-a!!
  !!cap This is the third caption!!

  !!img example-image-a!!
  !!cap This is the fourth caption!!

  !!img example-image-a!!
  !!cap This is the fifth caption!!

  !!img example-image-a!!
  !!cap This is the sixth caption!!
\end{multiimages}

\end{document}

enter image description here

I don't see the real point of this though. And I think you should take a look at l3regex's regular expressions.

  • Thanks. I had a look at Bruno's l3regex sometime back. At the time I thought that if one needs such complexity it was better tto use Lua and lpeg. The point of my request is to simplify user input. – Yiannis Lazarides May 14 '15 at 19:35
  • You already had it (I just added the environ). In any case, the thing about l3regex is that you replace at once everything like \regex_replace_all:nnN { \!\!img\ (.+?)\!\! } { \c{whatevercommand} \cB\{\1\cE\} } \l_tmpa_tl (sorry if there's a mistake, this is from memory, I'm not an expert either) and you don't have “weird delimited arguments”. – Manuel May 14 '15 at 19:38
  • May be you have the opportunity to have a full-featured-keys-included-solution from egreg :) – Manuel May 14 '15 at 19:46
6

To be honest an input syntax like !!img zzz!! seems more complicated than a simple tex syntax such as \img{zzz} but anyway expl3 is of course useful for lots of things but it seems inefficient to grab the environment body and then do token replacements in a second pass and then finally execute the modified list in the third pass, you could simply typeset it in one pass, something like

\documentclass{article}
\usepackage{graphicx,capt-of}

\def\multiimages{\centering\zzz}
\def\endmultiimages{\par}

\long\def\zz#1!img #2!!#3!!cap #4!!{%
\begin{minipage}{3.6cm}\centering
\includegraphics[width=\linewidth]{#2}%
\captionof{figure}{#4}%
\end{minipage}\hfill\zzz}

\def\zzs{!}
\def\zzp{\par}

\long\def\zzz#1{%
\def\tmp{#1}%
\ifx\tmp\zzs\expandafter\zz
\else
\ifx\tmp\zzp\expandafter\expandafter\expandafter\zzz
\else
\expandafter\expandafter\expandafter\end
\fi
\fi}

\begin{document}

\begin{multiimages}
  !!img example-image-b!! 
  !!cap This is the first caption!!

  !!img example-image-b!!
  !!cap This is the second caption!!

  !!img example-image-b!!
  !!cap This is the third caption!!

  !!img example-image-b!!
  !!cap This is the fourth caption!!

  !!img example-image-b!!
  !!cap This is the fifth caption!!

  !!img example-image-b!!
  !!cap This is the sixth caption!!
\end{multiimages}

\end{document} 
  • Thanks for the compliment regarding the more complicated part, I must be now truly getting into the spirit of expl3! One of course could delimit with one !. – Yiannis Lazarides May 14 '15 at 20:39
5

My example don't use expl3, but simply \replacestring from OPmac.

\input opmac

\long\def\putimages#1{\def\tmpb{#1}%
   \replacestrings{!!img }{\img}%
   \replacestrings{!!cap }{\cap}%
   \replacestrings{.jpg!!}{!!}%
   \tmpnum=0
   \hbox to\hsize{\tmpb}% three imeges per line
}
\def\img#1!!#2\cap#3!!{%
  \ifnum\tmpnum=3 \egroup\bigskip\hbox to\hsize\bgroup \tmpnum=0 \fi
  \advance\tmpnum by1  
  \vbox{\hsize=.3\hsize
     \centerline{\picw=4cm \inspic #1.jpg }
     \caption/f \emergencystretch=2em #3\par
  }\hss
}
\def\thefnum{\the\fnum}

\putimages{
      !!img amato!!
      !!cap This is the first caption!!

      !!img amato!!
      !!cap This is the second caption!!

      !!img amato.jpg!!
      !!cap This is the third caption!!

      !!img amato!!
      !!cap This is the fourth caption!!

      !!img amato!!
      !!cap This is the fifth caption!!

      !!img amato!!
      !!cap This is the sixth caption!!
}   
\bye

The result is the same as in your 3x2 picture.

Explanation: The first pass converts the data to:

\img amato!! \cap This is the first caption!! \par\img amato!! \cap ...

This is stored in \tmpb. Then \hbox{\tmpb} creates 3x2 picture matrix because \ifnum\tmpnum=3 then \hbox is closed and new \hbox is opened.

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.