Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

What is the right way to map each optional argument to a function that applies a specific style to it?

In the example below, optional arguments are typeset in bold face preceded by a colon. But I want users to be able to define what style #2 is to be typeset in, what style #3 is to be typeset in, and so on:

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand {\mystyle} { m } {:\textbf{#1}}
\NewDocumentCommand {\mycs} { moooooooo }
 {
  #1
  \tl_set:Nn \l_my_tl { {#2} {#3} {#4} {#5} {#6} {#7} {#8} {#9} }
  \tl_map_inline:Nn \l_my_tl {\IfValueT{##1}{\mystyle{##1}}}
 }
\ExplSyntaxOff

\begin{document}
\mycs{1}[2][3][4][5][6][7][8][9]
\end{document}
share|improve this question
add comment

1 Answer

up vote 2 down vote accepted

The following might be an option. The \setstyle macro takes a comma separated list of commands names possibly preceded by characters. By default the list is comma separated, but the optional argument can change the separator to whatever. In the example below I used

\setstyle{:\textbf,.\emph,\textsc}

The \usestyles macro takes two mandatory arguments. The first corresponds to your mandatory argument above, the second is a list of arguments. By default the list is comma separated, but this can be changed with the optional argument. The first n styles are then mapped to the first n arguments.

enter image description here

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn

% optional arg1 changes the separator for arg2
\NewDocumentCommand{\setstyle}{ O{,} m }{
    \ss_set_my_styles:nn {#1}{#2}
}

% optional arg1 changes the separator for arg3
\NewDocumentCommand{\usestyles}{ O{,} m m }{
    \ss_use_my_styles:nnn {#1}{#2}{#3}
}

% split style list at separator and store
\seq_new:N \g__ss_my_styles_seq
\cs_new:Npn \ss_set_my_styles:nn #1#2
    {
        \seq_set_split:Nnn \g__ss_my_styles_seq {#1}{#2}
    }

\cs_new:Npn \ss_use_my_styles:nnn #1#2#3
    {
        #2\par
        % split arg list at separator
        \seq_set_split:Nnn \l_tmpa_seq {#1}{#3}
        % map styles to list items in order
        \seq_mapthread_function:NNN \g__ss_my_styles_seq \l_tmpa_seq \__ss_use:nn
    }

\cs_new:Npn \__ss_use:nn #1#2
    {
        % applies arg1 to arg2
        #1{#2}\par
    }

\ExplSyntaxOff
\begin{document}

\setstyle{:\textbf,.\emph,\textsc}
\usestyles{first}{arg1,arg2,arg3}

\end{document}


Another option using l3regex. With this you can add characters before and after the arguments.

  • \setstyle[<separator>][<string to replace>]{<style list>}

The first optional sets the separator for the <style list> which defaults to a comma, the second sets the string to be replaced by the argument and defaults to thearg.

  • \usestyles[<separator>]{<1st mand>}{<list of args>}

The optional again sets the separator for the third argument.

enter image description here

\documentclass{article}
\usepackage{xparse}
\usepackage{l3regex}
\ExplSyntaxOn

\tl_new:N \c__ss_repl_symb_tl
\seq_new:N \g__ss_my_styles_seq

% optional #1 sets separator
% optional #2 sets string to replace
\NewDocumentCommand{\setstyle}{ O{,} O{thearg} m }{
    \ss_set_my_styles:nn {#1}{#2}{#3}
}

% split style list at separator and store
\cs_new:Npn \ss_set_my_styles:nn #1#2#3 {
    \tl_gset:Nn \c__ss_repl_symb_tl {#2}
    \seq_set_split:Nnn \g__ss_my_styles_seq {#1}{#3}
}

% optional #1 sets separator to use when
% splitting #3
\NewDocumentCommand{\usestyles}{ O{,} m m }{
    \ss_use_my_styles:nnn {#1}{#2}{#3}
}

\cs_new:Npn \ss_use_my_styles:nnn #1#2#3 {
    #2\par
    % split arg list at separator
    \seq_set_split:Nnn \l_tmpa_seq {#1}{#3}
    % map styles to list items in order
    \seq_mapthread_function:NNN \g__ss_my_styles_seq \l_tmpa_seq \__ss_use:nn
}

\cs_generate_variant:Nn \regex_replace_all:nnN {VnN}    
\cs_new:Npn \__ss_use:nn #1#2 {
    \tl_set:Nn \l_tmpa_tl {#1}
    \regex_replace_all:VnN {\c__ss_repl_symb_tl} {#2} \l_tmpa_tl
    \tl_use:N \l_tmpa_tl\par
}

\ExplSyntaxOff
\begin{document}

\setstyle{before \textbf{thearg} after,before \emph{thearg} after,before \textsc{thearg} after}
\usestyles{first}{arg1,arg2,arg3}

\end{document}
share|improve this answer
    
This is great! Thank you. But how can I allow users define complex styles as in the original example? For instance, one style inserts a colon before arg1 and makes it bold face, while style 2 inserts a period before arg2 and makes it italic. 1:**2**.__3__ –  nicolai.rostov Jan 21 '13 at 4:20
1  
With a small change you can put additional characters in front of the argument (but not after). I edited the answer to indicate how. –  Scott H. Jan 21 '13 at 5:06
    
@nicolairostov Added an option that should allow additional formatting. –  Scott H. Jan 21 '13 at 6:05
    
I'm just beginning to learn latex3. So, I'm curious about your naming convention: why \c__ss_repl_symb_tl instead of \c_ss_repl_symb_tl. ? why \g__ss_my_styles_seq instead of \g_ss_my_styles_seq? I'm also curious about the choice of ss in the command name. –  A.Ellett Jan 21 '13 at 6:42
    
@A.Ellett In an effort to be a good l3 citizen, I've been trying to follow the style conventions as laid out in this answer (from a member of the l3 team). The choice of ss was to reflect set style. Looking now, it think that I failed with \c__ss_repl_symb_tl which I believe should have only 1 underscore: single underscore for macro's/tl's called by "document" commands, double underscores for anything not accessed directly by a "document" command as I understand it. –  Scott H. Jan 21 '13 at 6:54
show 2 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.