2

I've defined a new macro using xparse and expl3 to generate a set of two lists. The idea was to have a macro with the same output as an old macro which was very user unfriendly because I had to write a macro for different numbers of entries. With the help of the siunitx.dtx I was able to write a macro which generates an output that is quite similar but not yet equal to the output of the old macro. As you can see the old macro uses math mode which makes the distances between the entries slighly smaller.

Maybe because I did not fully understand every single detail of SplitList and the different control sequences I could not find a way to define every single item of the first list to be \text{A}, \textbf{B} and so on so that the output could be in math mode.

Is there a way to achieve this using the current code as a starting point?

Edit:

The first list should be mandatory and take at least one entry - if that is the case only the first list should be printed (entry "A" in the first list should print "A")

If there are at least to entries in the first list, there must be two entries in the second list (entry "A;B" in the first list requires entry "1;2" in the second list. This should print "A : B = 1 : 2").

Because letters in math mode are italic by default the entries in the first list should be wrapped in the \text{} macro.

(end Edit)

\documentclass{article}
\usepackage{expl3}
\usepackage{xparse}
\usepackage{nccmath}
\usepackage{listingsutf8}
\usepackage{siunitx}        % to be used
\usepackage{xspace}

\newcommand{\oldmacro}[6]{$\text{#1}:\text{#3}:\text{#5} = #2:#4:#6$\xspace}    % for comparison

\ExplSyntaxOn

%%% defining token list variables -----------------------------------

\tl_new:N \l_firstlist_tl
\tl_new:N \l_firstlist_current_tl
\tl_new:N \l_secondlist_tl
\tl_new:N \l_secondlist_current_tl

\tl_new:N \l_firstlist_separator_tl
\tl_new:N \l_secondlist_separator_tl
\tl_new:N \l_first_second_separator_tl

%%%%% setting the separators

\tl_set:Nn \l_firstlist_separator_tl {~:~}
\tl_set:Nn \l_secondlist_separator_tl {~:~}
\tl_set:Nn \l_first_second_separator_tl {~=~}

%%% defining boolean variables -----------------------------------

\bool_new:N \l_print_first_bool
\bool_new:N \l_print_first_second_bool
\bool_new:N \l_print_first_second_list_bool

%%% defining macros -----------------------------------

\NewDocumentCommand{\newmacro}{ >{ \SplitList { ; } } m     >{ \SplitList { ; } } g }
{

    \detailed_checks_func:nn {#1}{#2}
    \newmacro_process_func:nn {#1}{#2}
    \xspace
}

\cs_new_protected:Npn \detailed_checks_func:nn #1#2
{
    \bool_set_false:N \l_print_first_bool
    \bool_set_false:N \l_print_first_second_bool

    \tl_if_single:nTF {#1}
    {\tl_if_eq:nnTF {#1} {{}}
        {\textbf{Error~Message~1}}
        {\IfNoValueTF {#2}
            {\bool_set_true:N \l_print_first_bool}
            {\tl_if_single:nTF {#2}
                {\textbf{Error~Message~2}}
                {\textbf{Error~Message~3}}
            }
        }
    }
    {\detailed_nosingle_checks_func:nn {#1}{#2}}
}

\cs_new_protected:Npn \detailed_nosingle_checks_func:nn #1#2
{
    \IfNoValueTF {#2}
    {\textbf{Error~Message~4}}
    {\int_compare:nNnTF {\tl_count:n {#1}} = {\tl_count:n {#2}}
        {\bool_set_true:N \l_print_first_second_bool}
        {\int_compare:nNnTF {\tl_count:n {#1}} < {\tl_count:n {#2}}
            {\textbf{Error~Message~3}}
            {\int_compare:nNnTF {\tl_count:n {#1}} > {\tl_count:n {#2}}
                {\textbf{Error~Message~5}}
                {\textbf{Error~Message~6}}
            }
        }
    }
}

\cs_new_protected:Npn \newmacro_process_func:nn #1#2
{

    \bool_if:nT {\l_print_first_bool}
    {\firstlist_output_func:n {#1}}

        \bool_set_true:N {\l_print_first_second_list_bool}  % needed for testing purposes
    \bool_if:nT {\l_print_first_second_bool}
    {
        \bool_if:nT {\l_print_first_second_list_bool}
        {
            \tl_clear:N \l_firstlist_current_tl
            \tl_clear:N \l_firstlist_tl
            \tl_map_function:nN {#1} \firstlist_process_aux_func:n
            \l_firstlist_tl
            \l_firstlist_separator_tl
            \l_firstlist_current_tl
            \l_first_second_separator_tl
            \tl_clear:N \l_secondlist_current_tl
            \tl_clear:N \l_secondlist_tl
            \tl_map_function:nN {#2} \secondlist_process_aux_func:n
            \l_secondlist_tl
            \l_secondlist_separator_tl
            \l_secondlist_current_tl
        }
    }
}

%%% function for processing the firstlist -----
\cs_new_protected:Npn \firstlist_process_aux_func:n #1
{
    \tl_if_empty:NTF \l_firstlist_tl
    {\tl_set_eq:NN \l_firstlist_tl \l_firstlist_current_tl}             
    {
        \tl_put_right:NV \l_firstlist_tl \l_firstlist_separator_tl
        \tl_put_right:NV \l_firstlist_tl \l_firstlist_current_tl
    }
    \tl_set:Nn \l_firstlist_current_tl {\firstlist_output_func:n {#1}}
}

%%% function for printing the firstlist -----
\cs_new_protected:Npn \firstlist_output_func:n #1
{
    {#1}
}

%%% function for processing the secondlist -----
\cs_new_protected:Npn \secondlist_process_aux_func:n #1
{
    \tl_if_empty:NTF \l_secondlist_tl
    {\tl_set_eq:NN \l_secondlist_tl \l_secondlist_current_tl}               
    {
        \tl_put_right:NV \l_secondlist_tl \l_secondlist_separator_tl
        \tl_put_right:NV \l_secondlist_tl \l_secondlist_current_tl
    }
    \tl_set:Nn \l_secondlist_current_tl {\secondlist_output_func:n {#1}}
    }

%%% function for printing the secondlist -----
\cs_new_protected:Npn \secondlist_output_func:n #1
{
    {#1}
}

\ExplSyntaxOff

\begin{document}

    \section{Working Examples:}

    \lstinline|\newmacro{A}|: \newmacro{A}\\    
    \lstinline|\newmacro{A;B;C;D}{1;2;3;4}|: \newmacro{A;B;C;D}{1;2;3;4}

    \subsection{For Comparison:}

    $A:B:C=1:2:3$\\
    $\text{A}:\text{B}:\text{C}=1:2:3$ () \\
    \oldmacro{A}{1}{B}{2}{C}{3} (\lstinline|\oldmacro{A}{1}{B}{2}{C}{3}|)\\
    \newmacro{A;B;C}{1;2;3} (\lstinline|\newmacro{A;B;C}{1;2;3}|)\\
    A : B : C = 1 : 2 : 3\\

\end{document}

1 Answer 1

1

If you want to use math mode, call the macro in math mode.

Here's an implementation:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\newmacro}{mm}
 {
  \echo_newmacro:nn { #1 } { #2 }
 }

\seq_new:N \l_echo_newmacro_first_seq
\seq_new:N \l_echo_newmacro_second_seq

\cs_new_protected:Nn \echo_newmacro:nn
 {
  \seq_set_split:Nnn \l_echo_newmacro_first_seq { ; } { #1 }
  \seq_set_split:Nnn \l_echo_newmacro_second_seq { ; } { #2 }
  \seq_use:Nn \l_echo_newmacro_first_seq { : }
  =
  \seq_use:Nn \l_echo_newmacro_second_seq { : }
 }
\ExplSyntaxOff

\begin{document}

$\newmacro{A;B;C}{1;2;3}$

$\newmacro{A;B;C;D}{1;2;3;4}$

\end{document}

enter image description here

New version after full specification

Note that, since the second part is optional, it should be specified in square brackets.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\newmacro}{mo}
 {
  \IfNoValueTF{ #2 }
   {
    \mathrm{#1}
   }
   {
    \echo_newmacro:nn { #1 } { #2 }
   }
 }

\seq_new:N \l_echo_newmacro_first_seq
\seq_new:N \l_echo_newmacro_second_seq

\cs_new_protected:Nn \echo_newmacro:nn
 {
  \seq_set_split:Nnn \l_echo_newmacro_first_seq { ; } { #1 }
  \seq_set_split:Nnn \l_echo_newmacro_second_seq { ; } { #2 }
  \int_compare:nTF
   {
    \seq_count:N \l_echo_newmacro_first_seq == \seq_count:N \l_echo_newmacro_second_seq
   }
   {% OK, the number of items is the same
    \mathrm{ \seq_use:Nn \l_echo_newmacro_first_seq { : } }
     =
    \seq_use:Nn \l_echo_newmacro_second_seq { : }
   }
   {% Error
    \msg_error:nnnn { echo/ratio } { wrong-number } { #1 } { #2 }
   }
 }
\msg_new:nnnn { echo/ratio } { wrong-number}
 {
  Wrong~number~of~items
 }
 {
  You~have~specified~lists~of~different~lengths~"#1"~and~"#2"
 }
\ExplSyntaxOff

\begin{document}

$\newmacro{A}$

$\newmacro{A;B;C}[1;2;3]$

$\newmacro{A;B;C;D}[1;2;3;4]$

$\newmacro{A}[1;2]$

\end{document}

enter image description here

The last call triggers an error:

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! echo/ratio error: "wrong-number"
! 
! Wrong number of items
! 
! See the echo/ratio documentation for further information.
! 
! For immediate help type H <return>.
!...............................................  

l.54 $\newmacro{A}[1;2]
                       $
? h
|'''''''''''''''''''''''''''''''''''''''''''''''
| You have specified lists of different lengths "A" and "1;2"
|...............................................
7
  • Unfortunately I can't print the entry of the first list as "A" only - your code leads to "A =" in this case. I still can't use the \text{} macro so that letters are not printed italic. But thank you for your fast answer.
    – Echo
    Jan 18, 2016 at 21:57
  • @Echo Can you add a complete specification of what the macro should do? It's difficult to guess from the examples you gave.
    – egreg
    Jan 18, 2016 at 21:59
  • The first list should be mandatory and take at least one entry - if that is the case only the first list should be printed (entry "A" in the first list should print "A"), if there are at least to entries in the first list, there must be two entries in the second list (entry "A;B" in the first list requires entry "1;2" in the second list. this should print "A : B = 1 : 2"). Because letters in math mode are italic by default the entries in the first list should be wrapped in the \text{} macro. I will also edit my question accordingly.
    – Echo
    Jan 18, 2016 at 22:16
  • @Echo New version on line
    – egreg
    Jan 18, 2016 at 22:33
  • This seems to work. I will have a closer look at in tomorrow or wednesday. Again, thank you very much for this much shorter code.
    – Echo
    Jan 18, 2016 at 23:04

You must log in to answer this question.

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