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}
5
  • 1
    it sounds a bit overdoing to use an extra file for this. Why don't you write to the aux-file? May 10, 2019 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. May 10, 2019 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, 2019 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. May 10, 2019 at 15:38
  • Proof needed. :-)
    – frougon
    May 10, 2019 at 15:40

2 Answers 2

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

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}
2
  • Very nice explanations about expansions, that I still find hard to understand correctly. May 10, 2019 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. May 10, 2019 at 15:40

You must log in to answer this question.

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