2

I'm trying to reduce the redundant lines of code of a custom package. I have two commands that do nearly the same thing : one is creating a tabular and fills it with lines, and the other one is just generating the lines.

I would like to create a command that calls the other one.

Instead of this :

\def\RWAddTableRow#1/#2!{
 & \textbf{#1} \\
 & #2 \\ }

 \newcommand{\RemarksWriterRows}[1]{
    \renewcommand*{\do}[1]{\RWAddTableRow##1!}
        Remarks :
        \docsvlist{#1}
}


\newcommand{\RemarksWriterFull}[1]{
    \renewcommand*{\do}[1]{\RWAddTableRow##1!}
    \begin{tabular}{p{7cm} p{10cm}}
        Remarks :
        \docsvlist{#1}
    \end{tabular}
}

I'm trying to do something like this :

\def\RWAddTableRow#1/#2!{
 & \textbf{#1} \\
 & #2 \\ }

 \newcommand{\RemarksWriterRows}[1]{
    \renewcommand*{\do}[1]{\RWAddTableRow##1!}
        Remarks :
        \docsvlist{#1}
}

\newcommand{\RemarksWriterSmall}[1]{
    \begin{tabular}{p{7cm} p{10cm}}
        \RemarksWriterRows{\protect \noexpand #1}
    \end{tabular}
}

But each time I pass multiple arguments to \RemarksWriter, only the first argument is well formatted. The second and third arguments are concatenated...

I call it like this : \RemarksWriter{Author1/My remarks, Author2/My other remarks, Author3/Last remarks}

I tried to use \protect and \noexpand, but each time the arguments are broken... I'm pretty sure there is something with the protection of the arguments. Am I asking too much things to LaTeX ? Or am I misusing something ? Thank you !

%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%

EDIT :

Here are the complete code.

Example.tex

\documentclass[12pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{lmodern}
\usepackage[left=2cm,right=2cm,top=2cm,bottom=2cm]{geometry}

\usepackage{etoolbox}

\usepackage{My}

\begin{document}

Test0.

\medskip

\RemarksWriterSmall{Author1/My remarks, Author2/My other remarks, Author3/Last remarks}

Test1.

\medskip

\RemarksWriterFull{Author1/My remarks, Author2/My other remarks, Author3/Last remarks}

\medskip

Test2.

\medskip

\RemarksWriterSmall{Author1/My remarks, Author2/My other remarks, Author3/Last remarks}

\medskip

Test3.

\end{document}

My.sty

\NeedsTeXFormat{LaTeX2e}

\ProvidesPackage{My}[Test.]

\RequirePackage{etoolbox}

\def\RWAddTableRow#1/#2!{
 & \textbf{#1} \\
 & #2 \\ }

\newcommand{\RemarksWriterRows}[1]{
    \renewcommand*{\do}[1]{\RWAddTableRow##1!}
        Remarks :
        \docsvlist{#1}
}


\newcommand{\RemarksWriterFull}[1]{
    \renewcommand*{\do}[1]{\RWAddTableRow##1!}
    \begin{tabular}{p{7cm} p{10cm}}
        Remarks :
        \docsvlist{#1}
    \end{tabular}
}


\newcommand{\RemarksWriterSmall}[1]{
    \begin{tabular}{p{7cm} p{10cm}}
        \RemarksWriterRows{#1}
    \end{tabular}
}

As you can see if you compile, the first \RemarksWriterSmall (between Test0 and Test1) will make a strange layout, but not the second one (between Test2 and Test3). I don't know why.

Strange Layout

  • Please provide the minimal document that has this issue, not only fragments – user31729 Aug 26 '17 at 18:31
  • You're right, after a few tests, I found cases where everything "seems" to work, and other where it didn't work at all. I corrected it and added the best example of strange behavior.... probably because of my misunderstand of LaTeX. – Metalman Aug 26 '17 at 22:21
  • I think this is a grouping problem: \renewcommand{\do} inside the table cell groups will not expand over the table cells – user31729 Aug 26 '17 at 22:26
  • The reason why it works in the 2nd usage of \RemarksWriterSmall is that it has the meaning of \RWAddTableRow from the \RemarksWriterFull – user31729 Aug 26 '17 at 22:32
2

The reason why \RemarksWriterSmall does not work in the first case is that it uses \RemarksWriterRows inside, there being \do redefined in the first table cell. This is a local change only, in the next table cell \do has the old meaning of \noexpand and not what was expected.

The second usage of \RemarksWriterSmall works because it has taken over the global change of \do from the \RemarksWriterFull, which is a 'bad' idea without grouping.

If the \do change should persist in the tabular cells, store the old definition of \do with \let\origdo\do first, then use a \gdef\do in \RemarksWriterRows and restore the definition after the \end{tabular} with \let\do\origdo.

I prefer the \RemarksWriterFull version, however.

\documentclass[12pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{lmodern}
\usepackage[left=2cm,right=2cm,top=2cm,bottom=2cm]{geometry}

\usepackage{etoolbox}

\usepackage{My}

\begin{document}

Test0.

\medskip

\meaning\do
\RemarksWriterSmall{Author1/My remarks, Author2/My other remarks, Author3/Last remarks}
\meaning\do
Test1.

\medskip

\meaning\do
\RemarksWriterFull{Author1/My remarks, Author2/My other remarks, Author3/Last remarks}
\meaning\do
\medskip

Test2.

\medskip

\meaning\do
\RemarksWriterSmall{Author1/My remarks, Author2/My other remarks, Author3/Last remarks}
\meaning\do

\medskip

Test3.

\end{document}

My.sty

\NeedsTeXFormat{LaTeX2e}

\ProvidesPackage{My}[Test.]

\RequirePackage{etoolbox}

\def\RWAddTableRow#1/#2!{%
 & \textbf{#1} \\
 & #2 \\ }

\newcommand{\RemarksWriterRows}[1]{
  \gdef\do##1{\RWAddTableRow##1!}
  Remarks Original:
  \docsvlist{#1}%
}




\newcommand{\RemarksWriterFull}[1]{%
  \begingroup
  \renewcommand*{\do}[1]{\RWAddTableRow##1!}
  \begin{tabular}{p{7cm} p{10cm}}
    Remarks :
    \docsvlist{#1}
  \end{tabular}
  \endgroup
}


\newcommand{\RemarksWriterSmall}[1]{
  \let\origdo\do
    \begin{tabular}{p{7cm} p{10cm}}
      \RemarksWriterRows{#1}
    \end{tabular}
  \let\do\origdo
}

enter image description here

  • A better variant might be using expl3 features! – user31729 Aug 26 '17 at 22:44
  • @Metalman: \let is some kind of Black TeX Magic ;-) – user31729 Aug 26 '17 at 22:55
  • Whoa. Thank you. I'm still a learner on LaTeX. I saw things with "\let" and co, but I was pretty lost. I'm still interested to know : why the "\do" changed of meaning in the Full and not the Small ? When did it was "activated" ? (I want to see the debug/traces of latex, but I don't know how to do it) How/Where exactly the lines are copied ? By which command ? To be honest : I copy/paste this code, and I tried to understand it... but as you can see : I didn't understand it. – Metalman Aug 26 '17 at 22:57
  • @Metalman: \renewcommand does change the meaning of a macro only in the current TeX group. A table cell is such a group, i.e. the redefined meaning of a certain macro is lost after the & which starts the next table cell. \docsvlist splits your comma-separated list according to your \RWAddTableRow macro applying the \do command, i.e. using \do for each element of the list. This works in the Small version only for the first table cell, then \do having the meaning of \RWAddTableRow is 'forgotten` and the rest of the list is squeezed into the first table cell of the next row. – user31729 Aug 26 '17 at 23:02
  • 1
    Okay, I need to read more on the TeX group... I was convinced it was linked with the environment (I quickly checked the RobustDeclaration and others, without deep reading), and it's even more complex than what I expected. Thank you a lot ! (I don't have enough reputation for putting a "+1", but I'll do when I'll be able !) – Metalman Aug 26 '17 at 23:06

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.