4

With commands such as \usepackage, all options can be given within the same pair of square brackets, using only commas as delimiters.

I'd like to achieve the same thing, here for example with the \coolphase command, i.e. write \coolphase[-77,2]{nab}.

How do I do it ?

I tried this but it doesn't work :

\NewDocumentCommand{\coolphasesplit}{>{\SplitArgument{4}{,}}o}{\coolphase#1}

MWE

\documentclass{article}

\usepackage[linguistics]{forest}

\NewDocumentCommand{\coolphase}{
    O{-58}
    O{0}
    O{8}
    O{150}
    O{110}
    m}
{\draw[dotted,thick]([xshift=#1pt,yshift=#2pt]#6) arc[start angle=#4,end angle=#5,radius=#3cm];}


\begin{document}
    
\begin{forest}
    [ASP[\textit{subject}][Asp 
    [asp][POL
    [AdvP[\textit{non},roof]][Pol
    [pol, name=nab][aP
    [~][a′
    [a][root]]]]]]]
    \coolphase[-77][2]{nab}
\end{forest}
    
\end{document}
2
  • 2
    It would be better from a UX perspective to supply the optional arguments as a set of keys. Your current setup requires the first optional arguments to be specified in order to specify other optional arguments. For example, you need to specify <1> in order to specify <2> in \coolphase[<1>][<2>]{...}. However, a key-value approach would allow you to \coolphase[yshift=<2>]{...} without having to specify xshift. Of course, if you're the only user, then UX is probably not a consideration...
    – Werner
    Dec 28, 2022 at 21:47
  • Would be awesome, no idea how to achieve this. Dec 29, 2022 at 2:03

3 Answers 3

6

It might be possible to do it without \ExplSyntaxOn, but it would be really cumbersome.

With \SplitArgument{4}{,}, the missing values are replaced by the special -NoValue- string, that can be tested with \tl_if_novalue:nTF.

We need to expand the test before \__krebs_coolphase:nnnnnn sees the actual arguments.

\documentclass{article}

\usepackage[linguistics]{forest}

% this uses TikZ so it cannot go in \ExplSyntaxOn
\NewDocumentCommand{\coolphaseaux}{mmmmmm}{%
  \draw[dotted,thick]([xshift=#1pt,yshift=#2pt]#6) arc[start angle=#4,end angle=#5,radius=#3cm];
}

\ExplSyntaxOn
\NewDocumentCommand{\coolphase}{>{\SplitArgument{4}{,}}om}
 {
  \krebs_coolphase:nnnnnn #1{#2}
 }
\cs_new_protected:Nn \krebs_coolphase:nnnnnn
 {
  \__krebs_coolphase:eeeeen
   { \tl_if_novalue:nTF { #1 } { -58 } { #1 } }
   { \tl_if_novalue:nTF { #2 } {   0 } { #2 } }
   { \tl_if_novalue:nTF { #3 } {   8 } { #3 } }
   { \tl_if_novalue:nTF { #4 } { 150 } { #4 } }
   { \tl_if_novalue:nTF { #5 } { 110 } { #5 } }
   { #6 }
 }
% make an internal version of \coolphaseaux
\cs_set_eq:NN \__krebs_coolphase:nnnnnn \coolphaseaux
% generate the needed variant
\cs_generate_variant:Nn \__krebs_coolphase:nnnnnn { eeeee }
\ExplSyntaxOff

\begin{document}
    
\begin{forest}
    [ASP[\textit{subject}][Asp 
    [asp][POL
    [AdvP[\textit{non},roof]][Pol
    [pol, name=nab][aP
    [~][a'
    [a][root]]]]]]]
    \coolphase[-77,2]{nab}
\end{forest}
    
\end{document}

enter image description here

However, it is much better if you use a key-value system, so you need not remember the precise order of the options.

\documentclass{article}

\usepackage[linguistics]{forest}

% this uses TikZ so it cannot go in \ExplSyntaxOn
\NewDocumentCommand{\coolphaseaux}{mmmmmm}{%
  \draw[dotted,thick]([xshift=#1pt,yshift=#2pt]#6) arc[start angle=#4,end angle=#5,radius=#3cm];
}

\ExplSyntaxOn
\NewDocumentCommand{\coolphase}{O{}m}
 {
  \group_begin:
  \keys_set:nn { krebs/coolphase } { #1 }
  \krebs_coolphase:VVVVVn
   \l__krebs_coolphase_x_tl
   \l__krebs_coolphase_y_tl
   \l__krebs_coolphase_sa_tl
   \l__krebs_coolphase_ea_tl
   \l__krebs_coolphase_r_tl
   {#2}
   \group_end:
 }
\keys_define:nn { krebs/coolphase }
 {
  x  .tl_set:N = \l__krebs_coolphase_x_tl,
  y  .tl_set:N = \l__krebs_coolphase_y_tl,
  sa .tl_set:N = \l__krebs_coolphase_sa_tl,
  ea .tl_set:N = \l__krebs_coolphase_ea_tl,
  r  .tl_set:N = \l__krebs_coolphase_r_tl,
  x  .initial:n = -58,
  y  .initial:n = 0,
  sa .initial:n = 8,
  ea .initial:n = 150,
  r  .initial:n = 110,
 }
% make an internal version of \coolphaseaux
\cs_set_eq:NN \krebs_coolphase:nnnnnn \coolphaseaux
% generate the needed variant
\cs_generate_variant:Nn \krebs_coolphase:nnnnnn { VVVVV }
\ExplSyntaxOff

\begin{document}
    
\begin{forest}
    [ASP[\textit{subject}][Asp 
    [asp][POL
    [AdvP[\textit{non},roof]][Pol
    [pol, name=nab][aP
    [~][a'
    [a][root]]]]]]]
    \coolphase[x=-77,y=2]{nab}
\end{forest}
    
\end{document}

You could pass r=110,sa=150,x=-77,ea=110,y=2, say, without worrying about the right order.

2
  • @VincentKrebs Do you plan to use also decimal values or just integers?
    – egreg
    Jan 2 at 10:09
  • Your first code has a bug due to the (very unfortunate) design decision to not use an argument processor on the no-value-flag, your optional argument is actually mandatory this way or else \coolphase will expand to \krebs_coolphase:nnnnnn -NoValue- {#2}.
    – Skillmon
    Jan 18 at 10:15
1

I know it is possible using TeX. Something like this should work:

\def\coolphase(#1, #2){
    %function definition
}
1
  • 1
    This should be the case for [...] as well, but it doesn't make it optional.
    – Werner
    Dec 28, 2022 at 22:04
1

Using PythonTeX:

%! TEX program = lualatex
\documentclass{article}
\usepackage{pythontex}

\usepackage[linguistics]{forest}

\begin{pycode}
def coolphase(opt_parts, arg2):
    opt_default=[-58, 0, 8, 150, 110]
    if len(opt_parts)>len(opt_default):
        raise ValueError("Too many arguments")
    opt_parts+=opt_default[len(opt_parts):]  # fill in default arguments.
    # Now opt_parts = [77, 2, 8, 150, 110]

    print(
            r"\draw[dotted,thick]([xshift={xshift}pt,yshift={yshift}pt]{extra}) arc[start angle={start_angle},end angle={end_angle},radius={radius}cm];"
            .format(
                xshift=opt_parts[0],
                yshift=opt_parts[1],
                radius=opt_parts[2],
                start_angle=opt_parts[3],
                end_angle=opt_parts[4],
                extra=arg2
                )
            )
\end{pycode}
\NewDocumentCommand\coolphase{om}{\pyc{coolphase([#1],r"""#2""")}}


\begin{document}
    
\begin{forest}
    [ASP[\textit{subject}][Asp 
    [asp][POL
    [AdvP[\textit{non},roof]][Pol
    [pol, name=nab][aP
    [~][a′
    [a][root]]]]]]]
    \coolphase[-77,2]{nab}
\end{forest}
    
\end{document}

Output is as you expect.

1
  • or use my pythonimmediate package. In this case there's not much difference (my package only require one compilation and works even if there's triple quote inside the second argument)
    – user202729
    Jan 10 at 1:58

You must log in to answer this question.

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