To illustrate, the two-step process described by Joseph Wright allows #1 to be open-ended: for example, it could be a data-structure:
The same foo
, three different outputs:
(Somewhat on the analogy of DNA\RNA.)
MWE
\documentclass{article}
\usepackage{xcolor}
\ExplSyntaxOn
\keys_define:nn { foo }
{
my-key .code:n = \__foo_process_my_key:n {#1}
}
\cs_new_protected:Npn \my_func:n #1 {
\tl_set:Nx
\l_tmpb_tl
{
\seq_item:Nn
\_tmpa_seq
{ #1 }
}
\seq_set_split:NnV
\_tmpb_seq
{ ; }
\l_tmpb_tl
% \seq_show:N
% \_tmpb_seq
\tl_set:Nn
\l_tmpb_tl
{
\textcolor { \seq_item:Nn \_tmpb_seq { 3 }} { \seq_item:Nn \_tmpb_seq { 1 } }
}
\tl_use:N
\l_tmpb_tl
}
\cs_new_protected:Npn \__foo_process_my_key:n #1
{
% Whatever is appropriate here
\tl_set:Nn \l_tmpa_tl { #1 }
\seq_set_split:NnV
\_tmpa_seq
{ / }
\l_tmpa_tl
\int_step_function:nnnN { 1 } { 1 } { \seq_count:N \_tmpa_seq } \my_func:n
}
\NewDocumentCommand { \foo } { o } {
\keys_set:nn { foo } { #1 }
}
\ExplSyntaxOff
\begin{document}
\foo[my-key=
ABCDE $\mapsto$~;;black
/A;z;red
/B;y;green
/C;x;blue
/D;w;yellow
/E;v;cyan
]
\foo[my-key=
The cat;;black
/~sat;;red
/~on the mat;;black
].
\foo[my-key=
The quick~;;black
/{\large brown};;red
/\kern-0.4pt\llap{{\large brown}};;blue
/~jumps over the lazy dog;;black
].
\end{document}
EDIT
In relation to the comment about code obscurity, a help option could be built into the code itself, separating code from front-end. A bit like the back and front of a tapestry.
This is from an attempt at expl3-ing an SE answer about multi-coloured letters.
As an aside, expl3 makes some things, like lettrining something, almost trivial (but not uncomplex - the problem to be solved drives the complexity-level of any solution; here it was legibility and something pleasant enough to read).
MWE
\documentclass{article}
\usepackage{fontspec}
\usepackage{xcolor}
\setmainfont{NotoSerif}
\newfontfamily\fcmd{NotoSans}[Colour=blue]
\newcommand\cmd[1]{{\fcmd#1}}
\newcommand\trimahelptext{%
letter in the string of characters can be overprinted up to \cmd{number-of-colours=} times (max of 4) using colours \cmd{trimacolour[a-d]=} clipped from the left in increasing order with \cmd{trimawidth[a-d]=} and formatted with switches such as \cmd{\textbackslash bfseries} (bold) and \cmd{\textbackslash itshape} (italic) using \cmd{format=}. For example, the above heading's trima scheme was done with:\\\\
{\ttfamily
\textbackslash trima[\\
trimawidtha=1pt,\\
trimawidthb=2.5pt,\\
trimawidthc=5pt,\\
trimawidthd=8pt,\\
trimacoloura=red,\\
trimacolourb=blue,\\
trimacolourc=red!60!yellow,\\
trimacolourd=green,\\
]\{\} \\
}
}
\ExplSyntaxOn
\tl_new:N \l_trima_coloura_tl
\tl_new:N \l_trima_colourb_tl
\tl_new:N \l_trima_colourc_tl
\tl_new:N \l_trima_colourd_tl
\dim_new:N \l_trima_widtha_dim
\dim_new:N \l_trima_widthb_dim
\dim_new:N \l_trima_widthc_dim
\dim_new:N \l_trima_widthd_dim
\int_new:N \l_trima_numcolours_int
\tl_new:N \l_trima_format_tl
\keys_define:nn { trima }
{
trimacoloura .tl_set:N = \l_trima_coloura_tl,
trimacolourb .tl_set:N = \l_trima_colourb_tl,
trimacolourc .tl_set:N = \l_trima_colourc_tl,
trimacolourd .tl_set:N = \l_trima_colourd_tl,
trimacoloura .default:n = { \tl_set:Nn \l_trima_coloura_tl {red} },
trimacolourb .default:n = { \tl_set:Nn \l_trima_colourb_tl {blue} },
trimacolourc .default:n = { \tl_set:Nn \l_trima_colourc_tl {red!40!yellow} },
trimacolourd .default:n = { \tl_set:Nn \l_trima_colourd_tl {black} },
trimacoloura .initial:n = { \tl_set:Nn \l_trima_coloura_tl {red} },
trimacolourb .initial:n = { \tl_set:Nn \l_trima_colourb_tl {blue} },
trimacolourc .initial:n = { \tl_set:Nn \l_trima_colourc_tl {red!40!yellow} },
trimacolourd .initial:n = { \tl_set:Nn \l_trima_colourd_tl {black} },
number-of-colours .int_set:N = \l_trima_numcolours_int,
number-of-colours .initial:n = 4,
number-of-colours .default:n = 4,
format .tl_set:N = \l_trima_format_tl,
trimawidtha .dim_set:N = \l_trima_widtha_dim,
trimawidthb .dim_set:N = \l_trima_widthb_dim,
trimawidthc .dim_set:N = \l_trima_widthc_dim,
trimawidthd .dim_set:N = \l_trima_widthd_dim,
trimawidtha .default:n = 2em,
trimawidthb .default:n = 1.5pt,
trimawidthc .default:n = 3.0pt,
trimawidthd .default:n = 4.0pt,
trimawidtha .initial:n = 2em,
trimawidthb .initial:n = 1.5pt,
trimawidthc .initial:n = 3.0pt,
trimawidthd .initial:n = 4.0pt,
help .code:n = { \trimahelp },
}
\box_new:N \l_trima_cola_box
\box_new:N \l_trima_colb_box
\box_new:N \l_trima_colc_box
\box_new:N \l_trima_cold_box
\tl_new:N \l_trima_result_tl
\tl_new:N \l_trima_text_tl
%--------------------------
\cs_new_protected:Npn \trima_dotrim:n #1 {
\tl_set:Nn \l_trima_text_tl {
\group_begin:
\tl_use:N \l_trima_format_tl
#1
\group_end:
}
%\tl_show:N \l_trima_coloura_tl
\hbox_set:Nn
\l_trima_cola_box
{ \textcolor{\tl_use:N \l_trima_coloura_tl}{ \tl_use:N \l_trima_text_tl } }
\hbox_set:Nn
\l_trima_colb_box
{ \textcolor{\tl_use:N \l_trima_colourb_tl}{ \tl_use:N \l_trima_text_tl } }
\box_set_trim:Nnnnn
\l_trima_colb_box
{\dim_use:N \l_trima_widthb_dim} {0pt} {0pt} {0pt}
\box_clip:N
\l_trima_colb_box
\hbox_set:Nn
\l_trima_colc_box {
\textcolor{\tl_use:N \l_trima_colourc_tl}{ \tl_use:N \l_trima_text_tl } }
\box_set_trim:Nnnnn
\l_trima_colc_box
{\dim_use:N \l_trima_widthc_dim}
{0pt} {0pt} {0pt}
\box_clip:N
\l_trima_colc_box
\hbox_set:Nn
\l_trima_cold_box
{ \textcolor{\tl_use:N \l_trima_colourd_tl}{ \tl_use:N \l_trima_text_tl } }
\box_set_trim:Nnnnn
\l_trima_cold_box
{\dim_use:N \l_trima_widthd_dim}
{0pt} {0pt} {0pt}
\box_clip:N
\l_trima_cold_box
\tl_clear:N \l_trima_result_tl
\int_case:nnTF
{ \l_trima_numcolours_int }
{
{ 1 } {
\tl_set:Nn
\l_trima_result_tl
{
\box_use:N \l_trima_cola_box
}
}
{ 2 } {
\tl_set:Nn
\l_trima_result_tl
{
\box_use:N \l_trima_cola_box
\llap{\box_use:N \l_trima_colb_box}
}
}
{ 3 } {
\tl_set:Nn
\l_trima_result_tl
{
\box_use:N \l_trima_cola_box
\llap{\box_use:N \l_trima_colb_box}
\llap{\box_use:N \l_trima_colc_box}
}
}
{ 4 } {
\tl_set:Nn
\l_trima_result_tl
{
\box_use:N \l_trima_cola_box
\llap{\box_use:N \l_trima_colb_box}
\llap{\box_use:N \l_trima_colc_box}
\llap{\box_use:N \l_trima_cold_box}
}
}
}
{}{}
% {
\tl_use:N
\l_trima_result_tl
% }
}
\NewDocumentCommand { \trimahelp } { } {
\trima[
trimawidtha=1pt,
trimawidthb=2.5pt,
trimawidthc=5pt,
trimawidthd=8pt,
trimacoloura=red,
trimacolourb=blue,
trimacolourc=red!60!yellow,
trimacolourd=green,
]{{\rule{\textwidth}{0.5pt}}}
\section*{\trima{Introductory \ Tutorial\ to\ \textbackslash} trima\ \trima{Command}}
\input Acorn.fd
\hbox_set:Nn
\l_tmpa_box
{
\fontsize{60pt}{72pt}\usefont{U}{Acorn}{xl}{n}
E
}
\box_use:N \l_tmpa_box
\vspace{-1.3\box_ht:N \l_tmpa_box}
\hangindent=\dim_eval:n {0.4em+\box_wd:N \l_tmpa_box}
\hangafter=-\fp_to_int:n { 2 + \box_ht:N \l_tmpa_box / \baselineskip }
\noindent
\kern-0.3em\textsc{ach}\ \trimahelptext
\tex_par:D
\noindent
:\hfill\rule{0.32\textwidth}{0.5pt}\hfill :
}
\NewDocumentCommand { \trima } { o m } {
% \tl_show:N \l_trima_colourd_tl
% \dim_show:N \l_trima_widthc_dim
\tl_if_novalue:nF{#1}
{\keys_set:nn { trima } { #1 } }
% \tl_show:N \l_trima_colourd_tl
\tl_set:Nn \l_tmpa_tl { #2 }
\mode_leave_vertical:
\tl_map_function:NN
\l_tmpa_tl
\trima_dotrim:n
}
\ExplSyntaxOff
%\newcommand\trima[1]{%
% \textcolor{red}{#1}%
%\llap{\clipbox{2.5pt 0pt 0pt 0pt}{\textcolor{blue}{#1}}}%
%\llap{\clipbox{3.0pt 0pt 0pt 0pt}{\textcolor{red!40!yellow}{#1}}}%
%\llap{\clipbox{4.0pt 0pt 0pt 0pt}{\textcolor{black}{#1}}}%
%}
\begin{document}
\large
a
\trima[
trimacoloura=red,
trimacolourb=blue,
trimacolourc=red!40!yellow,
trimacolourd=black,
number-of-colours=4,
trimawidtha,
trimawidthb,
trimawidthc,
trimawidthd,
format=\itshape,
]{abxyz}
\trima{abxyz}
\trima[number-of-colours=2,
]{QWERTY}
\trima{uiop}
\trima[
number-of-colours=4,
trimacolourd=green,%!60!yellow!40,
]{qazdxc}
\trima[
format=\Huge,
]{Q}
\trima[format=\normalsize,
]{{\rule{1.5em}{1em}}}
The
\trima[
trimacoloura=black,
trimacolourb=black,
trimacolourc=black,
trimacolourd=black,
format=\itshape\bfseries,
]{cat}
sat on the
\trima{mat}.
\trima[
trimawidtha=1pt,
trimawidthb=2.5pt,
trimawidthc=5pt,
trimawidthd=8pt,
trimacoloura=red,
trimacolourb=blue,
trimacolourc=red!60!yellow,
trimacolourd=green,
]{{\rule{1.5em}{1em}}}
\section{\trima{Introduction}}
\trima[help]{}
\end{document}
\newcommand[9]{...}
is that it makes it difficult to remember which argument is which and what syntax it uses. Of course, you can have as many arguments with\NewDocumentCommand
or the like, but I think the ideal is intended to be minimising the number of distinct arguments by having one accept a list of key-values for processing. If your keys allow multiple arguments, people will use them and you'll end up recreating the opacity of\newcommand[9]...
.notebraces={<left brace>}{<right brace>}
makes more sense to me than two separate keysleftbrace
andrightbrace
\keys_set:nn
. I'm not sure this fully addresses the issue, but it ought to go some way towards doing so.