2

I'm trying to build a macro to generate a whole changelog table dynamically (template for professional document - prototype). I've found several useful answers to achieve it, but I'm stuck on a macro reset inside another.

Warning : I've detailled everything so that the path I took is clear, instead of posting the code not working and expect an answer...

My goal :

Have a macro to build dynamically a changelog table in the document :

  • Declare the version in the preamble :

    \newrow{A}{H. Potter,R. Weasley}{First release for Snape}
    \newrow{B}{H. Granger}{Fixed tons of typos}
    

    => Comma-separated list of authors and/or modifications on sepearate table lines.

  • Build the table in the core (with the macro \modifications being the point of this question) :

    \setlength\extrarowheight{4.5pt}
    \begin{tabularx}{\textwidth}{|c|c|X|}
        \hline
        \multicolumn{3}{|c|}{\textbf{LOG OF CHANGES}}\\[2.25pt]
        \hline
        Version & \centering{Author} & {Modification} \\[2.25pt] \hline
       \modifications     % <-- TABLE BUILD HERE DEPENDING ON HOW MANY ROWS THEY ARE...
    \end{tabularx}
    

This should done this : Goal to achieve

Currently, this table is achieved with this code. Nothing fancy except the \specialcell that allows line breaks.

% Command to brake line in a cell.
\newcommand{\specialcell}[2][c]{
    \begin{tabular}{@{}#1@{}}#2\end{tabular}
}

% Construction of the tabular
\setlength\extrarowheight{4.5pt}
\begin{tabularx}{\textwidth}{|c|c|X|}
    \hline
    \multicolumn{3}{|c|}{\textbf{LOG OF CHANGES}}\\[2.25pt]
    \hline
    Version & \centering{Author} & {Modification} \\[2.25pt] \hline
    A & \specialcell{H. Potter\\R. Weasley} & \specialcell[l]{First release for Snape\\Additions to Fred's old version} \\ \hline
    B & \specialcell{H. Granger} & Fixed tons of typos ! \\ \hline
\end{tabularx}

Problem 0 : Break the line when a comma-separated list of authors and/or modification is entered. This has been solved with this answer.

Problem 1 : I don't know beforehand how much version are they going to be created !

I found this answer to build a table "dynamically", in function of the number of commands \addtotable{} passed. Seems the right way! I tried thus to combine that with my case, and it worked.

Here's the code :

\documentclass{article}
\RequirePackage{tabularx}
\usepackage[top=3cm,bottom=4.5cm,left=2.5cm,right=2.5cm]{geometry}

\makeatletter

% Command to brake line in a cell.
\newcommand{\specialcell}[2][c]{
    \begin{tabular}{@{}#1@{}}#2\end{tabular}
}

\newcommand\modifications{} % macro containing whole code to build all the lines of the table
\newcommand\authorsList{}   % macro containing the code for the authors list
\newcommand\modifList{}     % macro containing the code for the modifications list

\newcommand{\newrow}[3]{
    % Version cell of the table
    \g@addto@macro\modifications{#1 &}
    % build \specialcell{Element1\\Element2} and put it the second cell
    \g@addto@macro\authorsList{\@gobble}
    \@for\tmp:=#2\do{%
        \expandafter\g@addto@macro\expandafter\authorsList
        \expandafter{\expandafter\\\tmp}
    }%
    \g@addto@macro\modifications{\specialcell{\authorsList}&}
    % build \specialcell{Element1\\Element2} and put it the third cell
    \g@addto@macro\modifList{\@gobble}
    \@for\tmp:=#3\do{%
        \expandafter\g@addto@macro\expandafter\modifList
        \expandafter{\expandafter\\\tmp}
    }%
    \g@addto@macro\modifications{\specialcell[l]{\modifList}}
    % end table
    \g@addto@macro\modifications{\\\hline}
}
\makeatother

% Version definitions
\newrow{A}{H. Potter,R. Weasley}{First release for Snape, Additions to Fred's old version}
%\newrow{B}{H. Granger}{Fixed tons of typos}

\begin{document}
    \setlength\extrarowheight{4.5pt}
    \begin{tabularx}{\textwidth}{|c|c|X|}
        \hline
        \multicolumn{3}{|c|}{\textbf{LOG OF CHANGES}}\\[2.25pt]
        \hline
        Version & \centering{Author} & {Modification} \\[2.25pt] \hline
       \modifications     % <-- build of the table
    \end{tabularx}
\end{document}

It work pretty well with 1 line in the table.Then I ran into another problem when I added

Main problem

The macros modifList and authorsList are not reset and then it meesses everything up. I tired forceing them to reset in the begin with \let\authorsList\@empty and with \let\modifList\@empty, but then it only keeps the last value.

At some point, the values that goes into the \specialcell are not the current ones, but all from the beginning...

Here's the current output :

Wrong output

and the code :

\documentclass{article}
\usepackage{tabularx}
\usepackage[top=3cm,bottom=4.5cm,left=2.5cm,right=2.5cm]{geometry}

\makeatletter

% Command to brake line in a cell.
\newcommand{\specialcell}[2][c]{
    \begin{tabular}{@{}#1@{}}#2\end{tabular}
}

\newcommand\modifications{} % macro containing whole code to build all the lines of the table
\newcommand\authorsList{}   % macro containing the code for the authors list
\newcommand\modifList{}     % macro containing the code for the modifications list

\newcommand{\newrow}[3]{
    % Version cell of the table
    \g@addto@macro\modifications{#1 &}
    % build \specialcell{Element1\\Element2} and put it the second cell
    \g@addto@macro\authorsList{\@gobble}
    \@for\tmp:=#2\do{%
        \expandafter\g@addto@macro\expandafter\authorsList
        \expandafter{\expandafter\\\tmp}
    }%
    \g@addto@macro\modifications{\specialcell{\authorsList}&}
    % build \specialcell{Element1\\Element2} and put it the third cell
    \g@addto@macro\modifList{\@gobble}
    \@for\tmp:=#3\do{%
        \expandafter\g@addto@macro\expandafter\modifList
        \expandafter{\expandafter\\\tmp}
    }%
    \g@addto@macro\modifications{\specialcell[l]{\modifList}}
    % end table
    \g@addto@macro\modifications{\\\hline}
}
\makeatother

% Version definitions
\newrow{A}{H. Potter,R. Weasley}{First release for Snape, Additions to Fred's old version}
\newrow{B}{H. Granger}{Fixed tons of typos}

\begin{document}
    \setlength\extrarowheight{4.5pt}
    \begin{tabularx}{\textwidth}{|c|c|X|}
        \hline
        \multicolumn{3}{|c|}{\textbf{LOG OF CHANGES}}\\[2.25pt]
        \hline
        Version & \centering{Author} & {Modification} \\[2.25pt] \hline
       \modifications     % <-- build of the table
    \end{tabularx}
\end{document}

Any ideas on how to make this work with multiple versions ?

2 Answers 2

3

The problem is that \authorsList and \modifList must be expanded, when you add them to \modifications. Otherwise their last meaning will be used. Adding a lot of \expandafters does it:

\documentclass{article}
\usepackage{tabularx}
\usepackage[top=3cm,bottom=4.5cm,left=2.5cm,right=2.5cm]{geometry}

\makeatletter

% Command to brake line in a cell.
\newcommand{\specialcell}[2][c]{
    \begin{tabular}{@{}#1@{}}#2\end{tabular}
}

\newcommand\modifications{} % macro containing whole code to build all the lines of the table
\newcommand\authorsList{}   % macro containing the code for the authors list
\newcommand\modifList{}     % macro containing the code for the modifications list

\newcommand{\newrow}[3]{
    % Version cell of the table
    \g@addto@macro\modifications{#1 &}
    % build \specialcell{Element1\\Element2} and put it the second cell
    \gdef\authorsList{\@gobble}
    \@for\tmp:=#2\do{%
        \expandafter\g@addto@macro\expandafter\authorsList
        \expandafter{\expandafter\\\tmp}
    }%
    % added \expandafter's here
    \expandafter\g@addto@macro\expandafter\modifications
        \expandafter{\expandafter\specialcell\expandafter{\authorsList}&}
    % build \specialcell{Element1\\Element2} and put it the third cell
    \gdef\modifList{\@gobble}
    \@for\tmp:=#3\do{%
        \expandafter\g@addto@macro\expandafter\modifList
        \expandafter{\expandafter\\\tmp}
    }%
    % added \expandafter's here
    \expandafter\g@addto@macro\expandafter\modifications
        \expandafter{\expandafter\specialcell
        \expandafter[\expandafter l\expandafter]\expandafter{\modifList}}
    % end table
    \g@addto@macro\modifications{\\\hline}
}
\makeatother

% Version definitions
\newrow{A}{H. Potter,R. Weasley}{First release for Snape, Additions to Fred's old version}
\newrow{B}{H. Granger}{Fixed tons of typos}

\begin{document}
    \setlength\extrarowheight{4.5pt}
    \begin{tabularx}{\textwidth}{|c|c|X|}
        \hline
        \multicolumn{3}{|c|}{\textbf{LOG OF CHANGES}}\\[2.25pt]
        \hline
        Version & \centering{Author} & {Modification} \\[2.25pt] \hline
       \modifications     % <-- build of the table
    \end{tabularx}
\end{document}
3

It's a problem of expansion: you have to add the expansion of \AuthorsList and \modifList.

You should also be careful with spaces in your code: a new line in the body of a definition counts for a space in the output unless it is masked by %.

I propose an expl3 based code that, besides easing the expansion problems, avoids worrying about unprotected end-of-lines.

You may appreciate the easier code for transforming the comma separated list into a \\ separated list for \specialcell.

\documentclass{article}
\usepackage{tabularx}
\usepackage[top=3cm,bottom=4.5cm,left=2.5cm,right=2.5cm]{geometry}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\printchanges}{}
 {
  \group_begin:
  \par\noindent
  \setlength{\extrarowheight}{2.5pt}
  \begin{tabularx}{\textwidth}{|c|c|X|}
  \hline
  \multicolumn{3}{|c|}{\textbf{LOG~OF~CHANGES}}\\[2.5pt]
  \hline
  Version & Author & Modification \\[2.5pt]
  \hline
  \tl_use:N \g_eisenheim_modifications_tl
  \end{tabularx}
  \group_end:
 }

\NewDocumentCommand{\newrow}{mmm}
 {
  \eisenheim_newrow:nnn { #1 } { #2 } { #3 }
 }

\NewDocumentCommand{\specialcell}{O{c}m}
 {
  \eisenheim_specialcell:nn { #1 } { #2 }
 }

\tl_new:N \g_eisenheim_modifications_tl
\seq_new:N \l__eisenheim_specialcell_seq

\cs_new_protected:Nn \eisenheim_newrow:nnn
 {
  % add the tag
  \tl_put_right:Nn \g_eisenheim_modifications_tl { #1 & }
  % add the authors
  % first split the text at commas
  \seq_set_from_clist:Nn \l__eisenheim_specialcell_seq { #2 }
  % then add the items separated by \\
  \tl_put_right:Nx \g_eisenheim_modifications_tl
   {
     \specialcell { \seq_use:Nn \l__eisenheim_specialcell_seq { \\ } } &
   }
  % add the description
  \tl_put_right:Nn \g_eisenheim_modifications_tl { #3 \\[2.5pt] \hline }
 }

\cs_new_protected:Nn \eisenheim_specialcell:nn
 {
  \begin{tabular}{@{}#1@{}}#2\end{tabular}
 }
\ExplSyntaxOff

% Version definitions
\newrow{A}{H. Potter,R. Weasley}{First release for Snape, Additions to Fred's old version}
\newrow{B}{H. Granger}{Fixed tons of typos}

\begin{document}

\printchanges

\end{document}

enter image description here

You must log in to answer this question.

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