3

Context

The current question arises:

Aim (sum up)

I have a main (beamer) document, say main.tex, the content of which varying, depending on the targeted audience. For this, main.tex inputs one or more of, say, 5 slave files: topic1.tex, topic2.tex, topic3.tex, topic4.tex, topic5.tex.

Each topic (file) has a topic title and I want the title of the main document to automatically be the list of the titles of the topics that are input (and only the ones that are input).

For this, I used the following strategy:

  • At the beginning of each topic file, the topic title is specified, thanks to a \topictitle macro.
  • Each time it is used, this macro appends the corresponding topic title to the right of a \g_topics_seq sequence.
  • At the end of the (main) document:
    • the content of \g_topics_seq sequence is placed in a \g_presentation_title_tl token list,
    • the (not expanded: \exp_not:V) content of \g_presentation_title_tl is x-written to an auxiliary .sbj file.
  • At the end of the preamble of the (main) document (hence at the next compilation):
    • a scratch token list is x-set to contain the content of the auxiliary file,
    • the content of this scratch token list is passed to \title.

The following MCE is the implementation of this strategy but I wonder if expl3 could provide a better one.

\documentclass{beamer}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{filecontents}
\usepackage[check-declarations]{expl3}
\usepackage{xparse}

\begin{filecontents*}{topic1}
\topictitle{% \TeX{},
 \LaTeX{} and café%
}
\begin{frame}
  \TeX{}, \LaTeX{} and café are nice!
\end{frame}
\end{filecontents*}

\begin{filecontents*}{topic2}
\topictitle{Topic 2}
\begin{frame}
  Topic 2 is nice!
\end{frame}
\end{filecontents*}

\begin{filecontents*}{topic3}
\topictitle{Topic 3}
\begin{frame}
  Topic 3 is nice!
\end{frame}
\end{filecontents*}

\begin{filecontents*}{topic4}
\topictitle{Topic 4}
\begin{frame}
  Topic 4 is nice!
\end{frame}
\end{filecontents*}

\begin{filecontents*}{topic5}
\topictitle{Topic 5}
\begin{frame}
  Topic 5 is nice!
\end{frame}
\end{filecontents*}

\ExplSyntaxOn

\seq_new:N \g_topics_seq
\tl_new:N \g_presentation_title_tl
\iow_new:N \g_output_stream

\NewDocumentCommand{\topictitle}{m}
{
  \__topic_title:n {#1}
}

\cs_new_protected:Npn \__topic_title:n #1
{
  \seq_gput_right:Nn \g_topics_seq {#1}
}

\AtEndDocument
{
  \tl_gset:Nx \g_presentation_title_tl
  {
    \seq_use:Nn\g_topics_seq {,~}
  }
  \iow_open:Nn \g_output_stream { \c_sys_jobname_str.sbj }
  \iow_now:Nx \g_output_stream { \exp_not:V\g_presentation_title_tl }
  \iow_close:N \g_output_stream
}

\AtEndPreamble{%
  \file_if_exist:nTF {\c_sys_jobname_str.sbj} {
    \tl_set:Nx \l_tmpa_tl {\file_input:n {\c_sys_jobname_str.sbj}}
    \exp_args:NV \title \l_tmpa_tl
  }{
    \title{No topic!}
  }
}
\ExplSyntaxOff

\begin{document}
\maketitle{}
%
\input{topic1}
% \input{topic2}
\input{topic3}
% \input{topic4}
\input{topic5}
\end{document}
  • 1
    it sounds a bit overdoing to use an extra file for this. Why don't you write to the aux-file? – Ulrike Fischer May 10 at 14:57
  • @UlrikeFischer I agree. That is what I tried first but, when I wanted to read the content of the .aux file, it was empty (I probably didn't read it at the right moment). IIRC, I also had some difficulties to write both a verbatim text (e.g.\title{ and }) and, inside, the (not expanded: \exp_not:V) content of \g_presentation_title_tl. – Denis Bitouzé May 10 at 15:05
  • 1
    You don't have to manually read the .aux file: it is automatically \input as part of the work done by \begin{document}, before the \AtBeginDocument hooks are run. – frougon May 10 at 15:17
  • @frougon Yes, I know that but when I tried to exploit what was in it, it simply didn't exist according to LaTeX's message. – Denis Bitouzé May 10 at 15:38
  • Proof needed. :-) – frougon May 10 at 15:40
4

I would simply write to the aux-file:

\documentclass{beamer}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{filecontents}
\usepackage[check-declarations]{expl3}
\usepackage{xparse}

\begin{filecontents*}{topic1}
\topictitle{% \TeX{},
 \LaTeX{} and café%
}
\begin{frame}
  \TeX{}, \LaTeX{} and café are nice!
\end{frame}
\end{filecontents*}

\begin{filecontents*}{topic2}
\topictitle{Topic 2}
\begin{frame}
  Topic 2 is nice!
\end{frame}
\end{filecontents*}

\begin{filecontents*}{topic3}
\topictitle{Topic 3}
\begin{frame}
  Topic 3 is nice!
\end{frame}
\end{filecontents*}

\begin{filecontents*}{topic4}
\topictitle{Topic 4}
\begin{frame}
  Topic 4 is nice!
\end{frame}
\end{filecontents*}

\begin{filecontents*}{topic5}
\topictitle{Topic 5}
\begin{frame}
  Topic 5 is nice!
\end{frame}
\end{filecontents*}

\ExplSyntaxOn

\seq_new:N \g_topics_seq


\NewDocumentCommand\addtopictitle{m}
{
 \seq_gput_right:Nn\g_topics_seq {#1} 
}

\makeatletter
\NewDocumentCommand{\topictitle}{m}
{
  \iow_now:Nx \@mainaux
   {
    \exp_not:n {\addtopictitle{#1}}
   }
}

\title{\seq_use:Nn\g_topics_seq {,~}}

\ExplSyntaxOff

\begin{document}
\maketitle{}
%
\input{topic1}
% \input{topic2}
\input{topic3}
\input{topic4}
\input{topic5}
\end{document}

enter image description here

5

I'd do as Ulrike suggests, writing to the \@mainaux to avoid polluting the file streams. I'd also avoid expansion (mainly x-type) of the text, as this is likely to cause you trouble.

Note also that in your code the \tl_set:Nx \l_tmpa_tl {\file_input:n {\c_sys_jobname_str.sbj}} didn't do anything because \input is not expandable, so you ended up with \title{\input{\jobname.sbj}}.

The approach I propose is to, at the end of the document, write a \gdef\@input@topics{<stuff>} to the \@mainaux, which will be read in the next run. After the file is read then the \@input@topics is already known and can be simply used in the title. The written definition has to be global because the contents of the .aux file are read inside a group.

At the writing step I used e-type expansion in \seq_use:Nn because x-type expansion is too much, and because f-type would try to expand the first tokens of the title, which would expand \TeX unless there was a space before it. Everything is put in \exp_not:e to avoid the x expansion of \write. An extra \exp_not:N is needed before \@input@topics for later runs, where it is already defined.

Here's the code:

\documentclass{beamer}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{filecontents}
\usepackage[check-declarations]{expl3}
\usepackage{xparse}

\begin{filecontents*}{topic1}
\topictitle{\TeX{},
 \LaTeX{} and café%
}
\begin{frame}
  \TeX{}, \LaTeX{} and café are nice!
\end{frame}
\end{filecontents*}

\begin{filecontents*}{topic2}
\topictitle{Topic 2}
\begin{frame}
  Topic 2 is nice!
\end{frame}
\end{filecontents*}

\begin{filecontents*}{topic3}
\topictitle{Topic 3}
\begin{frame}
  Topic 3 is nice!
\end{frame}
\end{filecontents*}

\begin{filecontents*}{topic4}
\topictitle{Topic 4}
\begin{frame}
  Topic 4 is nice!
\end{frame}
\end{filecontents*}

\begin{filecontents*}{topic5}
\topictitle{Topic 5}
\begin{frame}
  Topic 5 is nice!
\end{frame}
\end{filecontents*}

\ExplSyntaxOn

\seq_new:N \g_topics_seq

\NewDocumentCommand{\topictitle}{m}
  { \__topic_title:n {#1} }
\cs_new_protected:Npn \__topic_title:n #1
  { \seq_gput_right:Nn \g_topics_seq {#1} }

\makeatletter
\AtEndDocument
  {
    \iow_now:Nx \@auxout
      {
        \gdef \exp_not:N \@input@topics
            { \exp_not:e { \seq_use:Nn \g_topics_seq {,~} } }
      }
  }

\AtBeginDocument
  {
    \cs_if_exist:NTF \@input@topics
      { \exp_args:NV \title \@input@topics }
      { \title { No~topic! } }
  }
\makeatother

\ExplSyntaxOff

\begin{document}
\maketitle{}
%
\input{topic1}
% \input{topic2}
\input{topic3}
% \input{topic4}
\input{topic5}
\end{document}
  • Very nice explanations about expansions, that I still find hard to understand correctly. – Denis Bitouzé May 10 at 15:35
  • @DenisBitouzé Sorry if I couldn't explain it right. You mean the types of expansion (e, f, x)? If so you can take a look at interface3.pdf (texdoc interface3), section 3 Introducing the variants. – Phelype Oleinik May 10 at 15:40

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.