4

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 child 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}

Denis Bitouzé
  • 9,652
  • 4
  • 27
  • 85

2 Answers2

6

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 '19 at 15:35
  • 1
    @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 '19 at 15:40
5

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

Ulrike Fischer
  • 327,261