This is not a minimal example, there are ten different questions here! The code given below works. Following the request in your comment, I have made more changes than strictly necessary in order to better adhere to LaTeX3 coding conventions (to the best of my knowledge).
Note that the _private_
naming scheme in \keys_define:nn { tikzmkpd/_private_/config-#1 }
is an invention of mine; I don't know if there is a standard naming scheme for such situations. I did this way because I believe the keys defined under this hierarchy are an implementation detail of your macros and shouldn't be used directly by “users”.
LaTeX3 coding conventions are presented in expl3.pdf, l3styleguide.pdf and at the beginning of interface3.pdf. The indentation style suggested there is a bit different from yours (in particular, it uses a basic offset of two spaces). But the code below is already fairly readable, so I let you decide for yourself whether you want to strictly follow the indentation guidelines too.
For functions, I used:
a \__tikzmkpd_
prefix for private ones;
a \tikzmkpd_
prefix for public ones (only \tikzmkpd:nnn
, which I added as the programming-layer backend function corresponding to the user-layer \tikzmkpd
command you had already defined).
This way, it is very easy to turn all this code into a package that will play well with the rest of the LaTeX ecosystem. Your \_case_one:n
and \_case_two:n
functions had an incorrect name for two reasons:
- the prefix;
- the
:n
suffix which indicated they were supposed to take an argument, whereas they actually don't.
I renamed these two functions to \__tikzmkpd_case_one:
and \__tikzmkpd_case_two:
, respectively.
\documentclass{article}
\usepackage{xparse}
\usepackage{tikz}
\usetikzlibrary{arrows.meta, bending, calc, tikzmark}
\ExplSyntaxOn
\cs_new_protected:Npn \__tikzmkpd_define_numeric_keys:nnnnnnnnn
#1#2#3#4#5#6#7#8#9
{
\keys_define:nn { tikzmkpd/_private_/config-#1 }
{
yshift-#1C .tl_set:c = { l_yshift_#1C_tl }, yshift-#1C .initial:n = {#2},
yshift-#1D .tl_set:c = { l_yshift_#1D_tl }, yshift-#1D .initial:n = {#3},
yshift-#1E .tl_set:c = { l_yshift_#1E_tl }, yshift-#1E .initial:n = {#4},
distan-#1C .tl_set:c = { l_distan_#1C_tl }, distan-#1C .initial:n = {#5},
distan-#1D .tl_set:c = { l_distan_#1D_tl }, distan-#1D .initial:n = {#6},
distan-#1E .tl_set:c = { l_distan_#1E_tl }, distan-#1E .initial:n = {#7},
angles-#1C .tl_set:c = { l_angles_#1C_tl }, angles-#1C .initial:n = {#8},
angles-#1D .tl_set:c = { l_angles_#1D_tl }, angles-#1D .initial:n = {#8},
angles-#1E .tl_set:c = { l_angles_#1E_tl }, angles-#1E .initial:n = {#8},
anglee-#1C .tl_set:c = { l_anglee_#1C_tl }, anglee-#1C .initial:n = {#9},
anglee-#1D .tl_set:c = { l_anglee_#1D_tl }, anglee-#1D .initial:n = {#9},
anglee-#1E .tl_set:c = { l_anglee_#1E_tl }, anglee-#1E .initial:n = {#9},
}
}
\__tikzmkpd_define_numeric_keys:nnnnnnnnn
{ A } { 1.7ex } { 1.7ex } { 1.7ex } { 1ex } { 2ex } { 3ex } { 60 } { 120 }
\__tikzmkpd_define_numeric_keys:nnnnnnnnn
{ B }{ -0.5ex }{ -0.5ex }{ -0.5ex } { 1ex } { 2ex } { 3ex } {-60 } {-120 }
\cs_new_protected:Npn \__tikzmkpd_define_colour_keys:nnnn #1#2#3#4
{
\keys_define:nn { tikzmkpd/_private_/config-#1 }
{
colour-#1C .tl_set:c = { l_colour_#1C_tl }, colour-#1C .initial:n = {#2},
colour-#1D .tl_set:c = { l_colour_#1D_tl }, colour-#1D .initial:n = {#3},
colour-#1E .tl_set:c = { l_colour_#1E_tl }, colour-#1E .initial:n = {#4},
}
}
\__tikzmkpd_define_colour_keys:nnnn { A } { red } { green } { blue }
\__tikzmkpd_define_colour_keys:nnnn { B } { red } { green } { blue }
\keys_define:nn { tikzmkpd / config-A }
{
yshift-A .tl_set:c = { l_yshift_A_tl },
yshift-A .initial:n = { 1.7ex },
end-yshift .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { yshift } {#1} },
angle-star .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { angles } {#1} },
angle-end .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { anglee } {#1} },
distance .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { distan } {#1} },
color .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { colour } {#1} },
raise .meta:n = { yshift-A = {#1}, end-yshift = {#1,#1,#1} },
}
\keys_define:nn { tikzmkpd / config-B }
{
yshift-B .tl_set:c = { l_yshift_B_tl },
yshift-B .initial:n = { -0.5ex },
end-yshift .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { yshift } {#1} },
angle-star .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { angles } {#1} },
angle-end .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { anglee } {#1} },
distance .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { distan } {#1} },
color .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { colour } {#1} },
raise .meta:n = { yshift-B = {#1}, end-yshift = {#1,#1,#1} },
}
\cs_new:Npn \__tikzmkpd_subs_i:nnn #1#2#3
{ \exp_not:n { #1-#2C = {#3} } }
\cs_new:Npn \__tikzmkpd_subs_ii:nnnn #1#2#3#4
{ \exp_not:n { #1-#2C= {#3}, #1-#2D= {#4} } }
\cs_new:Npn \__tikzmkpd_subs_iii:nnnnn #1#2#3#4#5
{ \exp_not:n { #1-#2C= {#3}, #1-#2D= {#4}, #1-#2E= {#5} } }
\cs_generate_variant:Nn \__tikzmkpd_subs_i:nnn { nnV }
\cs_generate_variant:Nn \__tikzmkpd_subs_ii:nnnn { nnVV }
\cs_generate_variant:Nn \__tikzmkpd_subs_iii:nnnnn { nnVVV }
\cs_generate_variant:Nn \keys_set:nn { nx }
\tl_new:N \l__tikzmkpd_tmp_tl
\cs_new_protected:Npn \__tikzmkpd_set_subkeys:nnn #1#2#3
{
\clist_set:Nn \l_tmpa_clist {#3}
\bool_if:nT { \int_compare_p:n { \clist_count:n {#3} = 1 } }
{
\tl_set:Nx \l_tmpa_tl { \clist_item:Nn \l_tmpa_clist {1} }
\keys_set:nx
{ tikzmkpd/_private_/config-#1 }
{ \__tikzmkpd_subs_i:nnV {#2} {#1} \l_tmpa_tl }
}
\bool_if:nT { \int_compare_p:n { \clist_count:n {#3} = 2 } }
{
\tl_set:Nx \l_tmpa_tl { \clist_item:Nn \l_tmpa_clist {1} }
\tl_set:Nx \l_tmpb_tl { \clist_item:Nn \l_tmpa_clist {2} }
\keys_set:nx
{ tikzmkpd/_private_/config-#1 }
{ \__tikzmkpd_subs_ii:nnVV {#2} {#1} \l_tmpa_tl \l_tmpb_tl }
}
\bool_if:nT { \int_compare_p:n { \clist_count:n {#3} = 3 } }
{
\tl_set:Nx \l_tmpa_tl { \clist_item:Nn \l_tmpa_clist {1} }
\tl_set:Nx \l_tmpb_tl { \clist_item:Nn \l_tmpa_clist {2} }
\tl_set:Nx \l__tikzmkpd_tmp_tl { \clist_item:Nn \l_tmpa_clist {3} }
\keys_set:nx
{ tikzmkpd/_private_/config-#1 }
{ \__tikzmkpd_subs_iii:nnVVV {#2} {#1} \l_tmpa_tl \l_tmpb_tl
\l__tikzmkpd_tmp_tl }
}
}
\seq_new:N \l__tikzmkpd_mycmd_seq
\cs_new_protected:Npn \__tikzmkpd_store_node_names:nn #1#2
{
\seq_set_from_clist:Nn \l__tikzmkpd_mycmd_seq {#2}
\seq_indexed_map_inline:Nn \l__tikzmkpd_mycmd_seq
{
\tl_clear_new:c { l__tikzmkpd_nodename_#1##1_tl }
\tl_set:cn { l__tikzmkpd_nodename_#1##1_tl } {##2}
}
}
% case 1: a(c+d) A1(B1+B2)
\cs_new_protected:Npn \__tikzmkpd_case_one:
{
\draw[->, \use:c{l_colour_AC_tl}]
($(\tl_use:c { l__tikzmkpd_nodename_A1_tl }) + (0, \use:c{l_yshift_A_tl})$)
to[out=\use:c{l_angles_AC_tl}, in=\use:c{l_anglee_AC_tl},
distance=\use:c{l_distan_AC_tl}]
([yshift=\use:c{l_yshift_AC_tl}] \tl_use:c { l__tikzmkpd_nodename_B1_tl });
\draw[->,\use:c{l_colour_AD_tl}]
($(\tl_use:c { l__tikzmkpd_nodename_A1_tl }) + (0, \use:c{l_yshift_A_tl})$)
to[out=\use:c{l_angles_AD_tl}, in=\use:c{l_anglee_AD_tl},
distance=\use:c{l_distan_AD_tl}]
([yshift=\use:c{l_yshift_AD_tl}] \tl_use:c { l__tikzmkpd_nodename_B2_tl });
}
% case 2: a(c+d+e) A1(B1+B2+B3)
\cs_new_protected:Npn \__tikzmkpd_case_two:
{
\__tikzmkpd_case_one:
\draw[->, \use:c{l_colour_AE_tl}]
($(\tl_use:c { l__tikzmkpd_nodename_A1_tl }) + (0, \use:c{l_yshift_A_tl})$)
to[out=\use:c{l_angles_AE_tl}, in=\use:c{l_anglee_AE_tl},
distance=\use:c{l_distan_AE_tl}]
([yshift=\use:c{l_yshift_AE_tl}] \tl_use:c { l__tikzmkpd_nodename_B3_tl });
}
\keys_define:nn { tikzmkpd }
{
config-A .code:n = { \keys_set:nn { tikzmkpd / config-A } {#1} },
config-B .code:n = { \keys_set:nn { tikzmkpd / config-B } {#1} },
}
\cs_new_protected:Npn \tikzmkpd:nnn #1#2#3
{
\group_begin:
\keys_set:nn { tikzmkpd } {#1}
\__tikzmkpd_store_node_names:nn {A} {#2}
\__tikzmkpd_store_node_names:nn {B} {#3}
\tikzset{>={Straight ~ Barb[length=1.5pt,round,bend]}}
\begin{tikzpicture}[overlay, remember ~ picture]
\bool_if:nT
{
\int_compare_p:n { \clist_count:n {#2} = 1 } &&
\int_compare_p:n { \clist_count:n {#3} = 2 }
}
{ \__tikzmkpd_case_one: }
\bool_if:nT
{
\int_compare_p:n { \clist_count:n {#2} = 1 } &&
\int_compare_p:n { \clist_count:n {#3} = 3 }
}
{ \__tikzmkpd_case_two: }
\end{tikzpicture}
\group_end:
}
\NewDocumentCommand \tikzmkpd { O{} m m }
{
\tikzmkpd:nnn {#1} {#2} {#3}
}
\ExplSyntaxOff
\newcommand*{\TkM}[2]{\tikzmarknode{#1}{#2}} % short :)
\setlength{\parindent}{0pt} % just for the example
\pagestyle{empty}
\begin{document}
\section{case 1}
$\TkM{A}{2a^2}(\TkM{B}{b}+\TkM{D}{3q})$%
\tikzmkpd[config-A={end-yshift={8pt,9pt}, yshift-A=8pt, color={gray,red}}]%
{A}{B, D}
\section{case 2}
$\TkM{a1}{2p}\left(\TkM{b1}{3q}+\TkM{c1}{4r}+\TkM{d1}{1}\right)$%
\tikzmkpd[config-A={color={gray,gray,gray}, end-yshift={5pt,5pt,5pt}}]%
{a1}{b1, c1, d1}
\end{document}
I tested the preceding code, it gives the screenshot below. At the end of the post, you'll find a variant with improvements from Pablo that deals with more cases of the distributive property of multiplication (cases “one” to “four” instead of just “one” and “two”). However, I can't completely validate that version myself, as it apparently relies on recent bug fixes or features of PGF/TikZ—too recent for the version I have here, which is 2019/02/02 v3.1.1
.

I believe you can make progress regarding your debugging methodology: had you tested the output of every single function of yours, you'd have done:
\tl_show:N \l_yshift_AC_tl
\tl_show:N \l_yshift_AD_tl
\tl_show:N \l_colour_AC_tl
\tl_show:N \l_colour_AD_tl
right after the \keys_set:nn { tikzmkpd } {#1}
call, which would have shown that your \__testkeys:nnn
(now called \__tikzmkpd_set_subkeys:nnn
) was not working properly. The main problem there was that you were passing single tokens such as \l_tmpa_tl
in arguments where you actually wanted their value (something equivalent to the result of expanding \l_tmpa_tl
or \tl_use:N \l_tmpa_tl
; see how I did). Also, more bracing was desirable in some places in case some parameter values were to contain commas. For instance, this:
\cs_new:Npn \__tikzmkpd_subs_i:nnn #1#2#3
{ #1-#2C = {#3}, }
is preferable to this:
\cs_new:Npn \__tikzmkpd_subs_i:nnn #1#2#3
{ #1-#2C= #3, }
in case #3
were to contain commas. In fact, unless you plan to use macros in #1
, #2
or #3
, the following is maybe preferable in order to avoid unwanted expansions (since we later use it inside an x
argument), which is what I did above:
\cs_new:Npn \__tikzmkpd_subs_i:nnn #1#2#3
{ \exp_not:n { #1-#2C = {#3} } }
The other problem that prevented the code from working is that for nodes created with \tikzmarknode
, the pic cs
syntax you used doesn't work—at least in my setup. The good news is, this can be simplified a lot (see my changes to \_case_one:n
and \_case_two:n
[now renamed to \__tikzmkpd_case_one:
and \__tikzmkpd_case_two:
]).
Your question is so complex with all the parameters, the TikZ code mixed up with the l3keys
code, that I fear no one is going to reuse my answer. :-( I don't criticize the use of l3keys
for TikZ work (for one, I'm much more comfortable myself with l3keys
than with pgfkeys
), but in the interest of other users of this site, I think you should have isolated the parsing problem from the TikZ issue—as people already told you.
Your LaTeX coding skills seem good; my main advice would be:
Read a bit more documentation, in particular on the LaTeX3 naming conventions, expansion and variants (see the first chapters of interface3.pdf).
Whenever you face again a problem like that, use \tracingmacros=1 \tracingonline=1\relax
, and if this isn't enough to understand what is happening, print the value of every “thing” that your functions prepare1 (for each of your functions). For example, before even trying to typeset the tikzpicture
, print all options and all parameters that you are going to use therein. This method would have helped you find the errors in your \__testkeys:nnn
(now renamed to \__tikzmkpd_set_subkeys:nnn
).
As promised, here is the expanded code with additions from Pablo:
\documentclass{article}
\usepackage{xparse}
\usepackage{tikz}
\usetikzlibrary{arrows.meta, bending, calc, tikzmark}
\ExplSyntaxOn
\cs_new_protected:Npn \__tikzmkpd_define_numeric_keys:nnnnnnnnn
#1#2#3#4#5#6#7#8#9
{
\keys_define:nn { tikzmkpd/_private_/config-#1 }
{
yshift-#1C .tl_set:c = { l_yshift_#1C_tl }, yshift-#1C .initial:n = {#2},
yshift-#1D .tl_set:c = { l_yshift_#1D_tl }, yshift-#1D .initial:n = {#3},
yshift-#1E .tl_set:c = { l_yshift_#1E_tl }, yshift-#1E .initial:n = {#4},
distan-#1C .tl_set:c = { l_distan_#1C_tl }, distan-#1C .initial:n = {#5},
distan-#1D .tl_set:c = { l_distan_#1D_tl }, distan-#1D .initial:n = {#6},
distan-#1E .tl_set:c = { l_distan_#1E_tl }, distan-#1E .initial:n = {#7},
angles-#1C .tl_set:c = { l_angles_#1C_tl }, angles-#1C .initial:n = {#8},
angles-#1D .tl_set:c = { l_angles_#1D_tl }, angles-#1D .initial:n = {#8},
angles-#1E .tl_set:c = { l_angles_#1E_tl }, angles-#1E .initial:n = {#8},
anglee-#1C .tl_set:c = { l_anglee_#1C_tl }, anglee-#1C .initial:n = {#9},
anglee-#1D .tl_set:c = { l_anglee_#1D_tl }, anglee-#1D .initial:n = {#9},
anglee-#1E .tl_set:c = { l_anglee_#1E_tl }, anglee-#1E .initial:n = {#9},
}
}
\__tikzmkpd_define_numeric_keys:nnnnnnnnn
{ A } { 1.7ex } { 1.7ex } { 1.7ex } { 1ex } { 2ex } { 3ex } { 60 } { 120 }
\__tikzmkpd_define_numeric_keys:nnnnnnnnn
{ B }{ -0.5ex }{ -0.5ex }{ -0.5ex } { 1ex } { 2ex } { 3ex } {-60 } {-120 }
\cs_new_protected:Npn \__tikzmkpd_define_colour_keys:nnnn #1#2#3#4
{
\keys_define:nn { tikzmkpd/_private_/config-#1 }
{
colour-#1C .tl_set:c = { l_colour_#1C_tl }, colour-#1C .initial:n = {#2},
colour-#1D .tl_set:c = { l_colour_#1D_tl }, colour-#1D .initial:n = {#3},
colour-#1E .tl_set:c = { l_colour_#1E_tl }, colour-#1E .initial:n = {#4},
}
}
\__tikzmkpd_define_colour_keys:nnnn { A } { red } { green } { blue }
\__tikzmkpd_define_colour_keys:nnnn { B } { red } { green } { blue }
\keys_define:nn { tikzmkpd / config-A }
{
yshift-A .tl_set:c = { l_yshift_A_tl },
yshift-A .initial:n = { 1.7ex },
end-yshift .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { yshift } {#1} },
angle-star .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { angles } {#1} },
angle-end .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { anglee } {#1} },
distance .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { distan } {#1} },
color .code:n = { \__tikzmkpd_set_subkeys:nnn { A } { colour } {#1} },
raise .meta:n = { yshift-A = {#1}, end-yshift = {#1,#1,#1} },
}
\keys_define:nn { tikzmkpd / config-B }
{
yshift-B .tl_set:c = { l_yshift_B_tl },
yshift-B .initial:n = { -0.5ex },
end-yshift .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { yshift } {#1} },
angle-star .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { angles } {#1} },
angle-end .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { anglee } {#1} },
distance .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { distan } {#1} },
color .code:n = { \__tikzmkpd_set_subkeys:nnn { B } { colour } {#1} },
raise .meta:n = { yshift-B = {#1}, end-yshift = {#1,#1,#1} },
}
\cs_new:Npn \__tikzmkpd_subs_i:nnn #1#2#3
{ \exp_not:n { #1-#2C = {#3} } }
\cs_new:Npn \__tikzmkpd_subs_ii:nnnn #1#2#3#4
{ \exp_not:n { #1-#2C= {#3}, #1-#2D= {#4} } }
\cs_new:Npn \__tikzmkpd_subs_iii:nnnnn #1#2#3#4#5
{ \exp_not:n { #1-#2C= {#3}, #1-#2D= {#4}, #1-#2E= {#5} } }
\cs_generate_variant:Nn \__tikzmkpd_subs_i:nnn { nnV }
\cs_generate_variant:Nn \__tikzmkpd_subs_ii:nnnn { nnVV }
\cs_generate_variant:Nn \__tikzmkpd_subs_iii:nnnnn { nnVVV }
\cs_generate_variant:Nn \keys_set:nn { nx }
\tl_new:N \l__tikzmkpd_tmp_tl
\cs_new_protected:Npn \__tikzmkpd_set_subkeys:nnn #1#2#3
{
\clist_set:Nn \l_tmpa_clist {#3}
\bool_if:nT { \int_compare_p:n { \clist_count:n {#3} = 1 } }
{
\tl_set:Nx \l_tmpa_tl { \clist_item:Nn \l_tmpa_clist {1} }
\keys_set:nx
{ tikzmkpd/_private_/config-#1 }
{ \__tikzmkpd_subs_i:nnV {#2} {#1} \l_tmpa_tl }
}
\bool_if:nT { \int_compare_p:n { \clist_count:n {#3} = 2 } }
{
\tl_set:Nx \l_tmpa_tl { \clist_item:Nn \l_tmpa_clist {1} }
\tl_set:Nx \l_tmpb_tl { \clist_item:Nn \l_tmpa_clist {2} }
\keys_set:nx
{ tikzmkpd/_private_/config-#1 }
{ \__tikzmkpd_subs_ii:nnVV {#2} {#1} \l_tmpa_tl \l_tmpb_tl }
}
\bool_if:nT { \int_compare_p:n { \clist_count:n {#3} = 3 } }
{
\tl_set:Nx \l_tmpa_tl { \clist_item:Nn \l_tmpa_clist {1} }
\tl_set:Nx \l_tmpb_tl { \clist_item:Nn \l_tmpa_clist {2} }
\tl_set:Nx \l__tikzmkpd_tmp_tl { \clist_item:Nn \l_tmpa_clist {3} }
\keys_set:nx
{ tikzmkpd/_private_/config-#1 }
{ \__tikzmkpd_subs_iii:nnVVV {#2} {#1} \l_tmpa_tl \l_tmpb_tl
\l__tikzmkpd_tmp_tl }
}
}
\seq_new:N \l__tikzmkpd_mycmd_seq
\cs_new_protected:Npn \__tikzmkpd_store_node_names:nn #1#2
{
\seq_set_from_clist:Nn \l__tikzmkpd_mycmd_seq {#2}
\seq_indexed_map_inline:Nn \l__tikzmkpd_mycmd_seq
{
\tl_clear_new:c { l__tikzmkpd_nodename_#1##1_tl }
\tl_set:cn { l__tikzmkpd_nodename_#1##1_tl } {##2}
}
}
% case 1: a(c+d) A1(B1+B2)
\cs_new_protected:Npn \__tikzmkpd_case_one:
{
\draw[->, \tl_use:c{l_colour_AC_tl}]
([yshift=\tl_use:c{l_yshift_A_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_A1_tl})$)
to[out=\tl_use:c{l_angles_AC_tl}, in=\tl_use:c{l_anglee_AC_tl},
distance=\tl_use:c{l_distan_AC_tl}]
([yshift=\tl_use:c{l_yshift_AC_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_B1_tl})$);
\draw[->,\tl_use:c{l_colour_AD_tl}]
([yshift=\tl_use:c{l_yshift_A_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_A1_tl})$)
to[out=\tl_use:c{l_angles_AD_tl}, in=\tl_use:c{l_anglee_AD_tl},
distance=\tl_use:c{l_distan_AD_tl}]
([yshift=\tl_use:c{l_yshift_AD_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_B2_tl})$);
}
% case 2: a(c+d+e) A1(B1+B2+B3)
\cs_new_protected:Npn \__tikzmkpd_case_two:
{
\__tikzmkpd_case_one:
\draw[->, \tl_use:c{l_colour_AE_tl}]
([yshift=\tl_use:c{l_yshift_A_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_A1_tl})$)
to[out=\tl_use:c{l_angles_AE_tl}, in=\tl_use:c{l_anglee_AE_tl},
distance=\tl_use:c{l_distan_AE_tl}]
([yshift=\tl_use:c{l_yshift_AE_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_B3_tl})$);
}
% case 3: (a+b)(c+d) (A1+A2)(B1+B2)
\cs_new_protected:Npn \__tikzmkpd_case_three:
{
\__tikzmkpd_case_one:
\draw[->,\tl_use:c{l_colour_BC_tl}]
([yshift=\tl_use:c{l_yshift_B_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_A2_tl})$)
to[out=\tl_use:c{l_angles_BC_tl},in=\tl_use:c{l_anglee_BC_tl},
distance=\tl_use:c{l_distan_BC_tl}]
([yshift=\tl_use:c{l_yshift_BC_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_B1_tl})$);
\draw[->,\tl_use:c{l_colour_BD_tl}]
([yshift=\tl_use:c{l_yshift_B_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_A2_tl})$)
to[out=\tl_use:c{l_angles_BD_tl},in=\tl_use:c{l_anglee_BD_tl},
distance=\tl_use:c{l_distan_BD_tl}]
([yshift=\tl_use:c{l_yshift_BD_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_B2_tl})$);
}
% case 4: (a+b)(c+d+e) (A1+A2)(B1+B2+B3)
\cs_new_protected:Npn \__tikzmkpd_case_four:
{
\__tikzmkpd_case_three:
\draw[->,\tl_use:c{l_colour_AE_tl}]
([yshift=\tl_use:c{l_yshift_A_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_A1_tl})$)
to[out=\tl_use:c{l_angles_AE_tl},in=\tl_use:c{l_anglee_AE_tl},
distance=\tl_use:c{l_distan_AE_tl}]
([yshift=\tl_use:c{l_yshift_AE_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_B3_tl})$);
\draw[->,\tl_use:c{l_colour_BE_tl}]
([yshift=\tl_use:c{l_yshift_B_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_A2_tl})$)
to[out=\tl_use:c{l_angles_BE_tl},in=\tl_use:c{l_anglee_BE_tl},
distance=\tl_use:c{l_distan_BE_tl}]
([yshift=\tl_use:c{l_yshift_BE_tl}]$(pic ~ cs \tl_to_str:n { : } \tl_use:c { l__tikzmkpd_nodename_B3_tl})$);
}
\keys_define:nn { tikzmkpd }
{
config-A .code:n = { \keys_set:nn { tikzmkpd / config-A } {#1} },
config-B .code:n = { \keys_set:nn { tikzmkpd / config-B } {#1} },
}
\cs_new_protected:Npn \tikzmkpd:nnn #1#2#3
{
\group_begin:
\keys_set:nn { tikzmkpd } {#1}
\__tikzmkpd_store_node_names:nn {A} {#2}
\__tikzmkpd_store_node_names:nn {B} {#3}
\tikzset{>={Straight ~ Barb[length=1.5pt,round,bend]}}
\begin{tikzpicture}[overlay, remember ~ picture]
\bool_if:nT
{
\int_compare_p:n { \clist_count:n {#2} = 1 } &&
\int_compare_p:n { \clist_count:n {#3} = 2 }
}
{ \__tikzmkpd_case_one: }
\bool_if:nT
{
\int_compare_p:n { \clist_count:n {#2} = 1 } &&
\int_compare_p:n { \clist_count:n {#3} = 3 }
}
{ \__tikzmkpd_case_two: }
\bool_if:nT
{
\int_compare_p:n { \clist_count:n {#2} = 2 } &&
\int_compare_p:n { \clist_count:n {#3} = 2 }
}
{ \__tikzmkpd_case_three: }
\bool_if:nT
{
\int_compare_p:n { \clist_count:n {#2} = 2 } &&
\int_compare_p:n { \clist_count:n {#3} = 3 }
}
{ \__tikzmkpd_case_four: }
\end{tikzpicture}
\group_end:
}
\NewDocumentCommand \tikzmkpd { O{} m m }
{
\tikzmkpd:nnn {#1} {#2} {#3}
}
\ExplSyntaxOff
\newcommand*{\TkM}[2]{\tikzmarknode{#1}{#2}} % short :)
\setlength{\parindent}{0pt} % just for the example
\pagestyle{empty}
\begin{document}
\section{case 1}
$\TkM{A}{2a^2}(\TkM{B}{b}+\TkM{D}{3q})$%
\tikzmkpd[config-A={raise=12pt}]%
{A}{B, D}
\section{case 2}
$\TkM{a1}{2p}\left(\TkM{b1}{3q}+\TkM{c1}{4r}+\TkM{d1}{1}\right)$%
\tikzmkpd[config-A={color={gray,gray,gray}, end-yshift={5pt,5pt,5pt}}]%
{a1}{b1, c1, d1}
\section{case 3}
$(\TkM{X1}{2a^2}+\TkM{X2}{n})(\TkM{Y1}{b}+\TkM{Y2}{3q})$%
\tikzmkpd{X1,X2}{Y1,Y2}
\section{case 4}
$(\TkM{a}{x}-\TkM{b}{2})(\TkM{c}{x^2}+\TkM{d}{2x}+\TkM{e}{4})$
\tikzmkpd[config-B={end-yshift={-15pt,-15pt},color={gray,red}}]{a,b}{c, d, e}
\tikzmkpd[config-A={raise=4pt,color={gray,gray,gray}}]%
{A}{B, D}
\end{document}

Footnote
- For such temporary code, you can use TeX or LaTeX2e commands such as
\show
or \typeout
, as well as LaTeX3 ones such as \tl_show:N
or \box_show:N
.