0

In object programming languages often structs exist which help you to reuse code twice or often, but writing that code only one time.

A convenient way to write Latex code if the author does not want to dive too deep into Latex is to simply use a template.

The use case here is that the author wants to have shared components to include which are template independent. For sections and subsection I think this is quite common. But the author wants to share the code for an element such as code for a figure and caption into for example a book template and a presentation template.

A file exampleFigure.tex has content

      \begin{figure}[h!]
        \includegraphics[width=0.6\paperwidth]{examplePath/exampleFigure.png}
        \caption{Example Section.}
      \end{figure}

and be included in exampleBookSection.tex

       The example BlaBla shows the ... and we can see in figure:
   \include{exampleFigure}

   but on the other hand ...

as well as in examplePresentationSlide.tex

    \begin{frame}{ExampleSlide}
       \framesubtitle{Random Bla}%
       \include{exampleFigure}
    \end{frame}

The named use case already gets pretty much more complex if we want to replace in exampleFigure.tex [width=0.6\paperwidth] to [width=0.8\paperwidth] in for example the include in examplePresentationSlide.tex. In programming we can simply reuse code fragments by having variables as parameters.

In every example I found for include mechanism a child.tex is included only one time in a parent.tex. Those examples have a tree structure. My use case allows child.tex included by two parents parent1.tex and parent2.tex. I want even multiple roots (template files).

  • Is such a structure maintainable or not?
  • Do helpful latex IDE's exist if it is maintainable?
  • Is there a helpful guide to follow here for recommendations how to solve things such as the parameterization problem named above?

How to solve the parameterization question?

  • 2
    This is quite confusing... anyway, it looks like that you just want to define a macro. (go read up and come back if you have more questions.) – user202729 Dec 24 '21 at 08:05
  • 2
    @moewe Actually, include does more (own aux file) and input would be what just takes the content. Imo, include is wrong in thas case. – TeXnician Dec 24 '21 at 08:19
  • @TeXnician Ach! I confused \include and \input again. Thanks for pointing that out. I'll delete the comments (too late to edit them now :-(). – moewe Dec 24 '21 at 08:21

3 Answers3

3

"Libraries" in LaTex are called packages and included via

\usepackage{mystuff}

With the code accessed by, for example \myfig{fig:zz}{myfigure}{my caption}

where, in this case mystuff.sty should have

\newcommand\myfig[4][htp]{%
\begin{figure}[#1]%
\includegraphics[width=0.6\paperwidth]{#3}%
\caption{#4\label{#2}}%
\end{figure}}

note I made the positional argument optional so you can go \myfig[!ht] when needed. You shouldn't routinely add ! as it is for exceptional use to over-ride the document wide settings, it doesn't make sense to set document wide settings then always ignore them. Also using h on its own is usually an error and LaTeX will warn about it and change it, so htp is a better default.

David Carlisle
  • 757,742
1

Some valiant attempts have been made to do this (cf. Passing parameters to \input{text} (included text file) as a starting point), but I find it's usually not worth it.

What you can do, however, is have variables/macros in the parent document (even change them on the fly, as it were) and reference that in the child.

\begin{figure}[h!]
        \includegraphics[width=\mywidth]{\myfigure}
        \caption{\mycaption}
\end{figure}

… in conjunction with, say,

\def\mywidth{.6\paperwidth}
\def\myfigure{examplePath/exampleFigure} % usually best to omit the .png etc suffix
\def\mycaption{This is a caption!}
\input{exampleFigure.tex}

% using the same width, so no need to redefine \def\myfigure{examplePath/exampleFigure2} \def\mycaption{Another caption!} \input{exampleFigure.tex}

As you can see, you'd have to redefine your variables before \inputing your snippet, as needed. That said, I am a copy & paste guy myself when it comes to these things. The most tedious part, in my book, is the preamble anyway (don't get me started on font setup), and I certainly reuse those.

Ingmar
  • 6,690
  • 5
  • 26
  • 47
1

I can offer an interface where template-files are of pattern

\filesection{⟨name of section⟩}{⟨replacement for the token \default⟩}
⟨code⟩
\endfilesection
%-------------------------------------------------------------
\filesection{⟨name of section⟩}{⟨replacement for the token \default⟩}
⟨code⟩
\endfilesection
%-------------------------------------------------------------
\filesection{⟨name of section⟩}{⟨replacement for the token \default⟩}
⟨code⟩
\endfilesection
%-------------------------------------------------------------
\endinput

You input the template-files with the command

\inputfilesection{⟨name of template-file⟩}%
                 {⟨name of section⟩}%
                 [⟨replacement for the token \default⟩]

The ⟨code⟩ of a file-section will be executed only if both the \inputfilesection-command and the \filesection-comand have the same ⟨name of section⟩-argument.

In this case ⟨code⟩ will be read under verbatim-catcode-régime and the sequence \default will be replaced: If the \inputfilesection-command specifies a ⟨replacement for the token \default-argument, then the replacement will come from that argument.
Otherwise the replacement will come from the \filesection-command's ⟨replacement for the token \default-argument.

The result is passed to \scantokens for re-tokenization and normal processing.

Several \filesections can have the same ⟨name of section⟩. In this case all file-sections of the name in question occurring in the template-file are delivered by \inputfilesection. In this case if the \inputfilesection-provides a ⟨replacement for the token \default-argument, this argument will be used as replacement for the token \default with all file-sections delivered.

CAVEATS I AM AWARE OF:

!!!Don't do \inputfilesection inside files that are called by \inputfilesection!!!

!!!\inputfilesection attempts to read the ⟨replacement for the token \default-argument under verbatim-catcode-régime. Therefore \inputfilesection should not be used inside arguments of other macros and the like.!!!

%
% A exemplary template-file:
%
\begin{filecontents*}[overwrite]{MyTemplates.tex}
%\begin{filecontents*}{MyTemplates.tex}
\filesection{example-image-a}{width=0.6\textwidth}
\begin{figure}[!ht]
\centering
\includegraphics[\default]{example-image-a}
\caption{Example Section.}
\end{figure}
\endfilesection
%-------------------------------------------------------------
\filesection{example-image-b}{width=0.6\textwidth}
\begin{figure}[!ht]
\centering
\includegraphics[\default]{example-image-b}
\caption{Example Section.}
\end{figure}
\endfilesection
%-------------------------------------------------------------
\filesection{example-image-c}{width=0.6\textwidth}
\begin{figure}[!ht]
\centering
\includegraphics[\default]{example-image-c}
\caption{Example Section.}
\end{figure}
%\show\defaultABC %% This yields \show\defaultABC 
                  % , resulting in > \defaultABC=undefined.
                  % This is a test to make sure that replacing
                  % is not done if the sequence \default is
                  % trailed by a character whose catcode at the
                  % time of replacing is 11.
\endfilesection
%-------------------------------------------------------------
\endinput
\end{filecontents*}

\documentclass{article} \usepackage{graphicx}

\makeatletter %///// start of code that could go into a package / .sty-file////////////////// \newcommand\UD@ifnextcharspace[3]{% \let\reserved@d= #1% \edef\reserved@a{\unexpanded{#2}}% \edef\reserved@b{\unexpanded{#3}}% \futurelet@let@token\UD@ifnch }% \newcommand\UD@ifnch{% \ifx@let@token\reserved@d\expandafter\reserved@a\else\expandafter\reserved@b\fi }%

\NewDocumentCommand\inputfilesection{mm}{% % Use \UD@ifnextcharspace for ensuring the next token is read under % normal catcode-régime: \begingroup \UD@ifnextcharspace[{% \let\do@makeother\dospecials \do^^I% \do^^M% @inputfilesection{#1}{#2}% }{% \let\do@makeother\dospecials \do^^I% \do^^M% @inputfilesection{#1}{#2}% }% }% \NewDocumentCommand@inputfilesection{mm!o}{% \endgroup \def@stringincommand{#2}% \IfNoValueF{#3}{\def\default{#3}}% \input{#1}% \global\let\default\UndeFinEd }% \newcommand@stringincommand{}% \newcommand@stringinfile{}% \NewDocumentCommand\filesection{m}{% \begingroup@makeother^^I\relax @filesection{#1}% }% \NewDocumentCommand@filesection{mv}{% \endgroup \begingroup \let\do@makeother\dospecials \do^^I% \do^^M% @@filesection{#1}{#2}% }% \begingroup \newcommand@@filesection[3]{% \endgroup \def@@filesection##1##2##3#1{% \def@stringinfile{##1}% \expandafter\endgroup \ifx@stringinfile@stringincommand\expandafter@firstofone\else\expandafter@gobble\fi {% \begingroup @ifundefined{default}{\def\default{##2}}{}% \newlinechar=\endlinechar \scantokens \expandafter\expandafter \expandafter\expandafter \expandafter\expandafter \expandafter{\expandafter\UD@Replacedefault\expandafter{\default}{##3}{#3}#2}% }\ignorespaces }% }% @firstofone{% \let\do@makeother\dospecials \do^^I% \catcode\{=1 % \catcode}=2 % @@filesection }{\endfilesection}{%}{\endgroup\ignorespaces }% % % %%/////////// code for \UD@Replacedefault ///////////////////////////////////// %%============================================================================= %% PARAPHERNALIA: %% \UD@firstoftwo, \UD@secondoftwo, \UD@PassFirstToSecond, \UD@Exchange, %% \UD@stopromannumeral, \UD@CheckWhetherNull, \UD@ExtractFirstArg %%============================================================================= \newcommand\UD@firstoftwo[2]{#1}% \newcommand\UD@secondoftwo[2]{#2}% \newcommand\UD@firstoftwobraced[2]{{#1}}% \newcommand\UD@PassFirstToSecond[2]{#2{#1}}% \newcommand\UD@Exchange[2]{#2#1}% @ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=\^^00}% %%----------------------------------------------------------------------------- %% Check whether argument is empty: %%............................................................................. %% \UD@CheckWhetherNull{<Argument which is to be checked>}% %% {<Tokens to be delivered in case that argument %% which is to be checked is empty>}% %% {<Tokens to be delivered in case that argument %% which is to be checked is not empty>}% %% %% The gist of this macro comes from Robert R. Schneck's \ifempty-macro: %% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J> \newcommand\UD@CheckWhetherNull[1]{% \romannumeral\expandafter\UD@secondoftwo\string{\expandafter \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter \UD@secondoftwo\string}\expandafter\UD@stopromannumeral\UD@secondoftwo}{% \expandafter\UD@stopromannumeral\UD@firstoftwo}% }% %%----------------------------------------------------------------------------- %% Extract first inner undelimited argument: %%............................................................................. %% \UD@ExtractFirstArg{ABCDE} yields {A} %% %% \UD@ExtractFirstArg{{AB}CDE} yields {{AB}} %% %% Due to \romannumeral-expansion the result is delivered after two %% expansion-steps/after "hitting" \UD@ExtractFirstArg with \expandafter %% twice. %% %% \UD@ExtractFirstArg's argument must not be blank. %% This case can be cranked out via \UD@CheckWhetherBlank before calling %% \UD@ExtractFirstArg. %% %% Use frozen-\relax as delimiter for speeding things up. %% Frozen-\relax is chosen because David Carlisle pointed out in %% <https://tex.stackexchange.com/a/578877> %% that frozen-\relax cannot be (re)defined in terms of \outer and cannot be %% affected by \uppercase/\lowercase. %% %% \UD@ExtractFirstArg's argument may contain frozen-\relax: %% The only effect is that internally more iterations are needed for %% obtaining the result. %%............................................................................. \@ifdefinable\UD@RemoveTillFrozenrelax{% \expandafter\expandafter\expandafter\UD@Exchange \expandafter\expandafter\expandafter{% \expandafter\expandafter\ifnum0=0\fi}% {\long\def\UD@RemoveTillFrozenrelax#1#2}{{#1}}% }% \expandafter\UD@PassFirstToSecond\expandafter{% \romannumeral\expandafter \UD@PassFirstToSecond\expandafter{\romannumeral \expandafter\expandafter\expandafter\UD@Exchange \expandafter\expandafter\expandafter{% \expandafter\expandafter\ifnum0=0\fi}{\UD@stopromannumeral#1}% }{% \UD@stopromannumeral\romannumeral\UD@ExtractFirstArgLoop }% }{% \newcommand\UD@ExtractFirstArg[1]% }% \newcommand\UD@ExtractFirstArgLoop[1]{% \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}% {\UD@stopromannumeral#1}% {\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillFrozenrelax#1}}% }% %%============================================================================= %% \UD@ForkDefaultPhrase{<tokens to check>} %% {<tokens in case <tokens to check> equal \default>} %% {<tokens in case <tokens to check> are sub-phrase of \default>} %% {<tokens in other cases>} %%============================================================================= \@ifdefinable\UD@gobbletoexclam{\long\def\UD@gobbletoexclam#1!{}}% \begingroup \newcommand\UD@ForkDefaultPhrase[8]{% \endgroup \newcommand\UD@ForkDefaultPhrase[1]{% \expandafter\UD@CheckWhetherNull\expandafter{\UD@gobbletoexclam##1!}% {% \UD@DefaultPhraseFork !##1!#2!#3!#4!#5!#6!#7!#8!{\expandafter\UD@firstoftwo\UD@firstoftwo{}}% !#1!##1!#3!#4!#5!#6!#7!#8!{\expandafter\UD@firstoftwo\UD@firstoftwo{}}% !#1!#2!##1!#4!#5!#6!#7!#8!{\expandafter\UD@firstoftwo\UD@firstoftwo{}}% !#1!#2!#3!##1!#5!#6!#7!#8!{\expandafter\UD@firstoftwo\UD@firstoftwo{}}% !#1!#2!#3!#4!##1!#6!#7!#8!{\expandafter\UD@firstoftwo\UD@firstoftwo{}}% !#1!#2!#3!#4!#5!##1!#7!#8!{\expandafter\UD@firstoftwo\UD@firstoftwo{}}% !#1!#2!#3!#4!#5!#6!##1!#8!{\expandafter\UD@firstoftwo\UD@firstoftwo{}}% !#1!#2!#3!#4!#5!#6!#7!##1!{\expandafter\UD@firstoftwo\UD@firstoftwobraced}% !#1!#2!#3!#4!#5!#6!#7!#8!{\expandafter\UD@secondoftwo\UD@firstoftwo{}}% !!!!% }{\expandafter\UD@secondoftwo\UD@firstoftwo{}}% }% \@ifdefinable\UD@DefaultPhraseFork{% \long\def\UD@DefaultPhraseFork##1!#1!#2!#3!#4!#5!#6!#7!#8!##2##3!!!!{##2}% }% }% \@firstofone{% \let\do\@makeother\dospecials \do\^^I \catcode{=1 % \catcode\}=2 % \UD@ForkDefaultPhrase }{\}{\d}{\de}{\def}{\defa}{\defau}{\defaul}{\default}% %%============================================================================= %% \UD@Replacedefault{<Replacement>}% %% {<List of character-tokens where the sequence %% \default is to be replaced>}% %% {<tokens to prepend to result>}% %%============================================================================= \newcommand\UD@Replacedefault[3]{% % #1 - <Replacement> % #2 - <List where the token \default is to be replaced> % #3 - <tokens to prepend to result> \romannumeral\UD@Replacedefaultloop{}{}{\UD@secondoftwo}{#2}{#3}{#1}% }% \newcommand\UD@Replacedefaultloop[6]{% % #1 - <Result collected so far> % #2 - <sub-phrase of \default collected so far> % #3 - <flag for checking catcode of subsequent character if phrase \default is collected> % #4 - <List of character-tokens> % #5 - <tokens to prepend to result> % #6 - <Replacement> \UD@CheckWhetherNull{#4}{% \UD@ForkDefaultPhrase{#2}\UD@firstoftwo\UD@secondoftwo\UD@secondoftwo {\UD@stopromannumeral#5#1#6}{\UD@stopromannumeral#5#1#2}% }{% \expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}#4}{% \expandafter\expandafter\expandafter\UD@PassFirstToSecond\UD@ExtractFirstArg{#4}{% \UD@defaultreplace{#5}{#6}{#1}{#2}{#3}% }% }% }% }% \newcommand\UD@defaultreplace[7]{% % #1 - <tokens to prepend to result> % #2 - <Replacement> % #3 - <Result collected so far> % #4 - <sub-phrase of \default collected so far> % #5 - <flag for checking catcode of subsequent character if phrase \default is collected> % #6 - <Character in this iteration> % #7 - <Remaining List of character-tokens> \expandafter\UD@firstoftwo\expandafter{% \expandafter\UD@Replacedefaultloop\romannumeral #5{% \ifnum\the\catcode\expandafter\csname\string#6\endcsname=11 % \expandafter\UD@firstoftwo\else\expandafter\UD@secondoftwo\fi {\UD@stopromannumeral{#3#4}}{\UD@stopromannumeral{#3#2}}{}{\UD@secondoftwo}{#6#7}% }{% \UD@ForkDefaultPhrase{#4#6}% {\UD@stopromannumeral{#3}{#4#6}{\UD@firstoftwo}}% {\UD@stopromannumeral{#3}{#4#6}{\UD@secondoftwo}}% {\UD@stopromannumeral{#3#4#6}{}{\UD@secondoftwo}}% {#7}% }% }{}{#1}{#2}% }% %%/////////// end of code for \UD@Replacedefault ////////////////////////////// %///// end of code that could go into a package / .sty-file//////////////////// \makeatother

\begin{document}

\inputfilesection{MyTemplates.tex}{example-image-a}

\inputfilesection{MyTemplates.tex}{example-image-b}

\inputfilesection{MyTemplates.tex}{example-image-c}

\inputfilesection{MyTemplates.tex}{example-image-a}[width=.3\textwidth]

\inputfilesection{MyTemplates.tex}{example-image-b}[width=.3\textwidth]

\inputfilesection{MyTemplates.tex}{example-image-c}[width=.3\textwidth]

\end{document}

enter image description here

Ulrich Diez
  • 28,770