0

i have a multifile document, that is weirdly structured and i want to improve the structure.

the hierarchy looks like this:

dir0
├──header.tex
├──dir1
|  ├──main1.tex
|  └──img1.png
├──dir2
|  ├──main2.tex
|  └──img2.png
└──dir3
   └──sharedtext.tex

the files look like this:

header.tex:

    \usepackage[...]{...} % packages used in both main1 and main2 go here
    ... 
    \newcommand{\textblockForBoth}[]{textblock that is used in both main1 and main2}
    ...

main1.tex:

    \documentclass[a4paper,oneside]{scrbook}
    \usepackage[...]{...} % packages only used in main1
    ...
    \input{../header.tex}
    \newcommand{\textblockForMain1}[]{textblock that is used only in main1}
    ...
    \begin{document}
    \input{../dir3/sharedtext.tex}
    \end{document}

main2.tex:

\documentclass[a4paper,oneside]{scrbook}
\usepackage[...]{...} % packages only used in main2
...
\input{../header.tex}
\newcommand{\textblockForMain2}[]{textblock that is used only in main2}
...
\begin{document}
\input{../dir3/sharedtext.tex}
\end{document}

sharedtext.tex:

\tableofcontents
\chapter{chapter1}
sharedtext is written here and commands put some stuff here:
\textblockHere % textblocks or just words from main1 or main2 are added

so basically the preambel is located in the header.tex, shared text by all main files is stored in sharedtext.tex and document specific words/textblocks are added with macros that are defined in the respective main.tex and are called in the sharedtext.tex

another thing is that graphics are in the directory of the main.tex files and need to be referenced correctly. but i think this can be done easily using the following:

\graphicspath{...}

is there a better way to structure this? and which commands do you suggest using? i think \import or \include are better suited here then \input. The "subfile" package might also be an option

kind regards 63rrit

5
  • 1
    I tend to maintain the source for multiple related documents within a single text file (let's call it the "docstrip-file"). Within that docstrip-file I have (La)TeX load the docstrip-package and into that docstrip-file I place docstrip-tags denoting what goes into which document and in the beginning of that docstrip-file I place a sequence of docstrip's \generate-commands for generating a single .tex-input-file from the docstrip-file for each document. Sometimes I also place \write18-calls for compiling the generated .tex-files. Jul 20, 2020 at 12:27
  • My answer to the question "shared common text across many documents" provides an example on how to apply the docstrip-package. Jul 20, 2020 at 12:28
  • You might put any shared text in the same directory as the header. You could also put all the images into one directory to make a common \graphicspath. I tend to put multiple projects (organized by project files) into one directory if they share anything. BTW, in computer time, I/O takes forever, so it is better to get it over with in one go. Jul 20, 2020 at 14:34
  • This seems all quite complicated.Isn't it better to just fill the sharedtext.tex with parameterized macros (as common text blocks) and input those before the \begin{document} in main1.tex. then one could call those macros in main1.tex with appropriate arguments and also define+use "main1"-specific macros in the file.
    – 63rrit
    Jul 20, 2020 at 14:57
  • @63rrit You asked for "a better way to structure this". Deciding whether one way is better than another is up to you. This is because subjective criteria play a role here, which others cannot easily judge: Which workflow is best suited for which type of project, or what you find complicated and what not are such. One can point out possibilities. The decision is up to the questioner. ;-) Jul 20, 2020 at 17:54

1 Answer 1

1

When counting how many times shared.tex was \input, then you can combine shared.tex and header.tex:

File structure:

dir0
├──shared.tex
├──main1.tex
├──img1.png
├──main2.tex
└──img2.png

shared.tex

\csname @\ifx\inputcount\undefined first\else second\fi oftwo\endcsname{%
  \gdef\inputcount{0}%
}{%
  \xdef\inputcount{\number\numexpr\inputcount+1\relax}%
}%
%%
\ifnum\inputcount=0 %
  % This has formerly been header.tex:
  \usepackage[...]{...} % packages used in both main1 and main2 go here
  ... 
  \newcommand{\textblockForBoth}[]{textblock that is used in both main1 and main2}
  ...
  %%%%%%%%%%
  \expandafter\endinput
\fi
%%
\ifnum\inputcount=1 %
  % This has formerly been shared.tex:
  \tableofcontents
  \chapter{chapter1}
  sharedtext is written here and commands put some stuff here:
  \textblockHere % textblocks or just words from main1 or main2 are added
  %%%%%%%%%%
  \expandafter\endinput
\fi

main1.tex

\documentclass[a4paper,oneside]{scrbook}
\usepackage[...]{...} % packages only used in main1
...
% This time \inputcount will be defined 0...
\input{./shared.tex}
\newcommand{\textblockForMain1}[]{textblock that is used only in main1}
...
\begin{document}
% This time \inputcount will be incremented to 1...
\input{./shared.tex}
\end{document}

main2.tex

\documentclass[a4paper,oneside]{scrbook}
\usepackage[...]{...} % packages only used in main2
...
% This time \inputcount will be defined 0...
\input{./shared.tex}
\newcommand{\textblockForMain2}[]{textblock that is used only in main2}
...
\begin{document}
% This time \inputcount will be incremented to 1...
\input{./shared.tex}
\end{document}

With the things proposed in the following it is relied on the commandline-option --jobname not(!) being used when compiling a .tex-file. This implies that the things proposed in the following do not(!) work out on online-platforms like overleaf where the commandline-option --jobname is used by the underlying "machinery".

The following is similar to my first answer to the question shared common text across many documents.

The concept of counting how many times a file is loaded via \input is useful also when creating many documents of the same pattern.

It is possible

  • to have TeX stop reading an input-file at a specific point. This is done via \endinput. You need to make sure that \if....\fi are balanced before applying \endinput. You can use \expandafter for having TeX process \fi (and thus balance things) before processing \endinput.
  • to input an input-file several times, hereby increasing a counter-macro with each \input for deciding which portion of the file to process with the current call to \input.

When loading the same file several times you can keep all things ("variables", sequences of text) specific to a document within the same file.

Loading that same file several times can be done outgoing from a "framework" common to all documents.

In order to get the jobname/the name of the resulting .pdf-file right, that framework can be loaded from the file which afterwards is to be loaded several times by the framework.

With the following templates all files main⟨K⟩.tex are of the same pattern.

Compiling main⟨K⟩.tex yields defining the counter-macro \inputcount and loading framework.tex.
framework.tex contains the framework (preamble, text-snippets etc) common to all documents.

As framework.tex is loaded by main⟨K⟩.tex, \jobname will yield the phrase "main⟨K⟩".
framework.tex in turn can—via \input—load \jobname.tex = main⟨K⟩.tex again and again, each time incrementing \inputcount and therefore processing another portion of main⟨K⟩.tex.
The first portion of main⟨K⟩.tex might contain definitions(=values specific to the document main⟨K⟩) for macros that serve as variables.
The second portion of main⟨K⟩.tex might contain a snippet of text specific to the document main⟨K⟩.
The third portion of main⟨K⟩.tex might contain another snippet of text specific to the document main⟨K⟩.
Etc...

With the following template you can compile the file main1.tex and the file main2.tex.

Each of these loads framework.tex which in turn provides the framework for all documents and reloads main1.tex respective file main2.tex twice.
The first time only the portion with the definitions of macros that serve as variables is processed.
The second time only the text-snippet specific to main1.tex respective main2.tex is processed.

File: framework.tex:

% This file is \input from within main1.tex or main2.tex, thus
% \jobname will be "main1" or "main2"...

\documentclass{article}
%\usepackage...
%...

% The value of \inputcount will be increased to 1, thus 
% Portion 1 will be processed and
% \VariableA, \VariableB and \VariableC will be defined:
\input\jobname.tex

\begin{document}

\tableofcontents

\section{A section which all documents have in common}

This is a section which all documents have in common.

Now let's within the section which all documents have in common
use the variables specific to each document:

\begin{itemize}
\item \verb|\VariableA| is: \VariableA
\item \verb|\VariableB| is: \VariableB
\item \verb|\VariableC| is: \VariableC
\end{itemize}

\section{Another section which all documents have in common}
This is another section which all documents have in common.

Now let's come to a snippet of text which differs from document
to document:
% The value of \inputcount will be increased to 2, thus 
% Portion 2 will be processed.

\input\jobname.tex

\end{document}

File: main1.tex:

\csname @\ifx\inputcount\undefined first\else second\fi oftwo\endcsname{%
  % You could move the following \newcommand to framework.tex.
  \newcommand\inputcount{0}%
  %%%%%%%%%
  \input framework.tex
}{%
  \xdef\inputcount{\number\numexpr\inputcount+1\relax}%
}%
%%
%% Portion 1 - Variables:
%%
\ifnum\inputcount=1  %
  \makeatletter
  \newcommand\VariableA{%
    This is Variable A with main1.tex.
  }%
  \newcommand\VariableB{%
    This is Variable B with main1.tex.
  }%
  \newcommand\VariableC{%
    This is Variable C with main1.tex.
  }%
  %...
  \makeatother
  \expandafter\endinput
\fi 
%%
%% Portion 2 - First text snippet:
%%
\ifnum\inputcount=2 %
  \section{A section that is produced by processing 
           Portion 2 of \texttt{main1.tex}}

  Compiling \texttt{main1.tex} yields a nice document.\\
  Compiling \texttt{main1.tex} yields a nice document.\\
  Compiling \texttt{main1.tex} yields a nice document.\\
  Compiling \texttt{main1.tex} yields a nice document.\\

  That's the end of the section coming from Portion 2 of \texttt{main1.tex}.
  \expandafter\endinput
\fi

File: main2.tex:

\csname @\ifx\inputcount\undefined first\else second\fi oftwo\endcsname{%
  % You could move the following \newcommand to framework.tex.
  \newcommand\inputcount{0}%
  %%%%%%%%%
  \input framework.tex
}{%
  \xdef\inputcount{\number\numexpr\inputcount+1\relax}%
}%
%%
%% Portion 1 - Variables:
%%
\ifnum\inputcount=1  %
  \makeatletter
  \newcommand\VariableA{%
    This is Variable A with main2.tex.
  }%
  \newcommand\VariableB{%
    This is Variable B with main2.tex.
  }%
  \newcommand\VariableC{%
    This is Variable C with main2.tex.
  }%
  %...
  \makeatother
  \expandafter\endinput
\fi 
%%
%% Portion 2 - First text snippet:
%%
\ifnum\inputcount=2 %
  \section{A section that is produced by processing 
           Portion 2 of \texttt{main2.tex}}

  Compiling \texttt{main2.tex} yields a nice document.\\
  Compiling \texttt{main2.tex} yields a nice document.\\
  Compiling \texttt{main2.tex} yields a nice document.\\
  Compiling \texttt{main2.tex} yields a nice document.\\

  That's the end of the section coming from Portion 2 of \texttt{main2.tex}.
  \expandafter\endinput
\fi

When compiling main1.tex I get main1.pdf which looks like this:

enter image description here

When compiling main2.tex I get main2.pdf which looks like this:

enter image description here

All files are kept in the same directory.

If necessary you can have files with images/whatsoever content specific to each document in a separate sub-directory whose name somehow can be deduced from the result of expanding \jobname. E.g.,
images for document main1 in subdirectory main1_images,
images for document main2 in subdirectory main2_images,
...

This way evaluating \jobname can be a "generic" way of specifying sub-directories with files belonging to one of the documents—e.g., within the \graphicspath-directive or within file-paths directly.

Therefore again:

With the things just proposed it is relied on the commandline-option --jobname not(!) being used when compiling a .tex-file. This implies that the things just proposed do not(!) work out on online-platforms like overleaf where the commandline-option --jobname is used by the underlying "machinery".

On such platforms/in situations where you cannot rely on \jobname delivering the name of the main .tex-input-file you could within each file main⟨K⟩.tex define a macro \jobfile right before the command \input framework.tex to expand to the phrase main⟨K⟩ and within framework.tex use that \jobfile-macro instead of the \jobname-primitive.
The disadvantage with this approach is that renaming a file main⟨K⟩.tex implies the need of editing that file for changing the definition of the \jobfile-macro.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .