5

I'm trying to define a flexible "delimiter styling" command. I tried it in a package, and \str_case:nnF returned Undefined Control Sequence, whereas using \str_case:nnn went further and caused a different problem, which seemed to be related to the command itself. So I moved it into the document, getting the following code:

\documentclass[a4paper]{report}
\usepackage{amsthm,xparse}
\ExplSyntaxOn
\newcommand{\delim}[3][lr]{
 \str_case:nnF { #1 }
    {
    { b }{\def\lsize{\big}\def\rsize{\big}}
    { B }{\def\lsize{\Big}\def\rsize{\Big}}
    { x }{\def\lsize{\bigg}\def\rsize{\bigg}}
    { X }{\def\lsize{\Bigg}\def\rsize{\Bigg}}
    { lr }{\def\lsize{\left}\def\rsize{\right}}
    { bB }{\def\lsize{\big}\def\rsize{\Big}}
    { Bb }{\def\lsize{\Big}\def\rsize{\big}}
    { xb }{\def\lsize{\bigg}\def\rsize{\big}}
    { xB }{\def\lsize{\bigg}\def\rsize{\Big}}
    { bx }{\def\lsize{\big}\def\rsize{\bigg}}
    { Bx }{\def\lsize{\Big}\def\rsize{\bigg}}
    { bX }{\def\lsize{\big}\def\rsize{\Bigg}}
    { BX }{\def\lsize{\Big}\def\rsize{\Bigg}}
    { xX }{\def\lsize{\bigg}\def\rsize{\Bigg}}
    { Xb }{\def\lsize{\Bigg}\def\rsize{\big}}
    { XB }{\def\lsize{\Bigg}\def\rsize{\Big}}
    { Xx }{\def\lsize{\Bigg}\def\rsize{\bigg}}
}
 \str_case:nnF { #2 }
    {
    { s }{\def\ldel{[}\def\rdel{]}}
    { r }{\def\ldel{(}\def\rdel{)}}
    { b }{\def\ldel{\lbrace}\def\rdel{\rbrace}}
    { v }{\def\ldel{|}\def\rdel{|}}
    { a }{\def\ldel{\langle}\def\rdel{\rangle}}
    { dv }{\def\ldel{\|}\def\rdel{\|}}
    { rs }{\def\ldel{(}\def\rdel{]}}
    { sr }{\def\ldel{[}\def\rdel{)}}
    { rb }{\def\ldel{(}\def\rdel{\rbrace}}
    { sb }{\def\ldel{[}\def\rdel{\rbrace}}
    { br }{\def\ldel{\lbrace}\def\rdel{)}}
    { bs }{\def\ldel{\lbrace}\def\rdel{]}}
    { ra }{\def\ldel{(}\def\rdel{\rangle}}
    { sa }{\def\ldel{[}\def\rdel{\rangle}}
    { ba }{\def\ldel{\lbrace}\def\rdel{\rangle}}
    { ar }{\def\ldel{\langle}\def\rdel{)}}
    { as }{\def\ldel{\langle}\def\rdel{]}}
    { ab }{\def\ldel{\langle}\def\rdel{\rbrace}}
    { rv }{\def\ldel{(}\def\rdel{|}}
    { sv }{\def\ldel{[}\def\rdel{|}}
    { bv }{\def\ldel{\lbrace}\def\rdel{|}}
    { av }{\def\ldel{\langle}\def\rdel{|}}
    { vr }{\def\ldel{|}\def\rdel{)}}
    { vs }{\def\ldel{|}\def\rdel{]}}
    { vb }{\def\ldel{|}\def\rdel{\rbrace}}
    { va }{\def\ldel{|}\def\rdel{\rangle}}
    { rdv }{\def\ldel{(}\def\rdel{\|}}
    { sdv }{\def\ldel{[}\def\rdel{\|}}
    { bdv }{\def\ldel{\lbrace}\def\rdel{\|}}
    { adv }{\def\ldel{\langle}\def\rdel{\|}}
    { vdv }{\def\ldel{|}\def\rdel{\|}}
    { dvr }{\def\ldel{\|}\def\rdel{)}}
    { dvs }{\def\ldel{\|}\def\rdel{]}}
    { dvb }{\def\ldel{\|}\def\rdel{\rbrace}}
    { dva }{\def\ldel{\|}\def\rdel{\rangle}}
    { dvv }{\def\ldel{\|}\def\rdel{|}}
    { lr }{\def\ldel{(}\def\rdel{\@empty}}
    { rr }{\def\ldel{)}\def\rdel{\@empty}}
    { ls }{\def\ldel{[}\def\rdel{\@empty}}
    { rs }{\def\ldel{]}\def\rdel{\@empty}}
    { lb }{\def\ldel{\lbrace}\def\rdel{\@empty}}
    { rb }{\def\ldel{\rbrace}\def\rdel{\@empty}}
    { la }{\def\ldel{\langle}\def\rdel{\@empty}}
    { ra }{\def\ldel{\rangle}\def\rdel{\@empty}}
    { ov }{\def\ldel{|}\def\rdel{\@empty}}
    { odv }{\def\ldel{\|}\def\rdel{\@empy}}
    { ssi }{\def\ldel{[}\def\rdel{\mathclose{[}}}
    { sis }{\def\ldel{\mathopen{]}}\def\rdel{]}}
    { sisi }{\def\ldel{\mathopen{]}}\def\rdel{\mathclose{[}}}
}
\ifx\rdel\@empty
    \lsize\ldel
\else
    \lsize\ldel #3 \rsize\rdel
\fi
}
\ExplSyntaxOff
%\ignopt{greek}

\begin{document}
$$\delim[lr]{r}{\fr{a}{b}}$$
\end{document}

And then the strangest thing happened:

./delim_attempt.tex:3: Undefined control sequence.
<recently read> \ExplSyntaxOn 

l.3 \ExplSyntaxOn

And I'm like, "WHAT????" How is that possible?

Update: Having taken the comments below into account, I corrected [r] to {r}, loaded xparse, and updated Expl, meaning \str_case:nnF now works. So the code has been changed accordingly. Btw suspecting the spaces might be troublesome I tried removing them (e.g. { lr }->{lr}), and the wrong typesetting of the code above is still there. That is, as it is, the code gives:

./delim_attempt.tex:87: Undefined control sequence.
\\delim ...\@empty\lsize \ldel \else \lsize \ldel 
                                                  #3\rsize \rdel \fi 
l.87 $$\delim[lr]{r}{\frac{a}{b}}
                                 $$

and by commenting the \lsize\ldel #3 \rsize\rdel in the \else branch, I get to typeset:

rsrbvadvrssrrbsbbrbsrasabaarasabrvsvbvavvrvsvbvardvsdvbdvadvvdvdvrdvsdvbdvadvvlrrrlsrslbrblaraovod

which of course simpy isn't what I want.

  • 2
    You haven't loaded the expl3 package (xparse) so the commands are not defined – David Carlisle Apr 17 '14 at 15:50
  • On \str_case:nnn: we renamed this a while ago to \str_case:nnF, so if you don't have the latter you've got an out-of-date l3kernel. – Joseph Wright Apr 17 '14 at 16:00
  • Right @David Carlisle. Loading it and commenting the line \lsize\ldel #3 \rsize\rdel causes the given code to typeset to [srbvadvrssrrbsbbrbsrasabaarasabrvsvbvavvrvsvbvardvsdvbdvadvvdvdvrdvsdvbdvadvvlrrrlsrslbrblaraovod, even with {r}, as if the cases were interpreted as text to be typeset. Am I misusing the \str_case:nnn? And @Joseph Wright how long was this "while"? No because I updated my TeX distribution around New Year's Day 2014. Anyway if it's been "renamed" as such it should function in the same way, so I'll just use \str_case:nnn. – MickG Apr 17 '14 at 16:03
  • 1
    also you have defined \newcommand{\delim}[3][lr]{ so \delim has one optional argument and 2 mandatory ones so in \delim[lr][r the optional argument is lr #2 is [ and #3 is r I suspect you want to use xparse declarations to define a command with 2 optional arguments? – David Carlisle Apr 17 '14 at 16:08
  • As I said in the comment before, I noticed that error and corrected it to {r}. Let me edit the question. – MickG Apr 17 '14 at 16:23
8

You're misusing expl3; here's a conforming version:

\documentclass[a4paper]{report}
\usepackage{amsthm,xparse}
\ExplSyntaxOn
\NewDocumentCommand{\delim}{ O{lr} m m }
 {
  \mickg_delim:nnn { #1 } { #2 } { #3 }
 }

\tl_new:N \l_mickg_lsize_tl
\tl_new:N \l_mickg_rsize_tl
\tl_new:N \l_mickg_ldel_tl
\tl_new:N \l_mickg_rdel_tl

\cs_new_protected:Npn \mickg_delim:nnn #1 #2 #3
 {
  \str_case:nnF { #1 }
   {
    { b }{\tl_set:Nn \l_mickg_lsize_tl {\big} \tl_set:Nn \l_mickg_rsize_tl {\big}}
    { B }{\tl_set:Nn \l_mickg_lsize_tl {\Big} \tl_set:Nn \l_mickg_rsize_tl {\Big}}
    { x }{\tl_set:Nn \l_mickg_lsize_tl {\bigg} \tl_set:Nn \l_mickg_rsize_tl {\bigg}}
    { X }{\tl_set:Nn \l_mickg_lsize_tl {\Bigg} \tl_set:Nn \l_mickg_rsize_tl {\Bigg}}
    { lr }{\tl_set:Nn \l_mickg_lsize_tl {\left} \tl_set:Nn \l_mickg_rsize_tl {\right}}
    { bB }{\tl_set:Nn \l_mickg_lsize_tl {\big} \tl_set:Nn \l_mickg_rsize_tl {\Big}}
    { Bb }{\tl_set:Nn \l_mickg_lsize_tl {\Big} \tl_set:Nn \l_mickg_rsize_tl {\big}}
    { xb }{\tl_set:Nn \l_mickg_lsize_tl {\bigg} \tl_set:Nn \l_mickg_rsize_tl {\big}}
    { xB }{\tl_set:Nn \l_mickg_lsize_tl {\bigg} \tl_set:Nn \l_mickg_rsize_tl {\Big}}
    { bx }{\tl_set:Nn \l_mickg_lsize_tl {\big} \tl_set:Nn \l_mickg_rsize_tl {\bigg}}
    { Bx }{\tl_set:Nn \l_mickg_lsize_tl {\Big} \tl_set:Nn \l_mickg_rsize_tl {\bigg}}
    { bX }{\tl_set:Nn \l_mickg_lsize_tl {\big} \tl_set:Nn \l_mickg_rsize_tl {\Bigg}}
    { BX }{\tl_set:Nn \l_mickg_lsize_tl {\Big} \tl_set:Nn \l_mickg_rsize_tl {\Bigg}}
    { xX }{\tl_set:Nn \l_mickg_lsize_tl {\bigg} \tl_set:Nn \l_mickg_rsize_tl {\Bigg}}
    { Xb }{\tl_set:Nn \l_mickg_lsize_tl {\Bigg} \tl_set:Nn \l_mickg_rsize_tl {\big}}
    { XB }{\tl_set:Nn \l_mickg_lsize_tl {\Bigg} \tl_set:Nn \l_mickg_rsize_tl {\Big}}
    { Xx }{\tl_set:Nn \l_mickg_lsize_tl {\Bigg} \tl_set:Nn \l_mickg_rsize_tl {\bigg}}
   }
   { \tl_clear:N \l_mickg_lsize_tl \tl_clear:N \l_mickg_rsize_tl }
  \str_case:nnF { #2 }
   {
    { s }{\tl_set:Nn \l_mickg_ldel_tl {[} \tl_set:Nn \l_mickg_rdel_tl {]}}
    { r }{\tl_set:Nn \l_mickg_ldel_tl {(} \tl_set:Nn \l_mickg_rdel_tl {)}}
    { b }{\tl_set:Nn \l_mickg_ldel_tl {\lbrace} \tl_set:Nn \l_mickg_rdel_tl {\rbrace}}
    { v }{\tl_set:Nn \l_mickg_ldel_tl {|} \tl_set:Nn \l_mickg_rdel_tl {|}}
    { a }{\tl_set:Nn \l_mickg_ldel_tl {\langle} \tl_set:Nn \l_mickg_rdel_tl {\rangle}}
    { dv }{\tl_set:Nn \l_mickg_ldel_tl {\|} \tl_set:Nn \l_mickg_rdel_tl {\|}}
    { rs }{\tl_set:Nn \l_mickg_ldel_tl {(} \tl_set:Nn \l_mickg_rdel_tl {]}}
    { sr }{\tl_set:Nn \l_mickg_ldel_tl {[} \tl_set:Nn \l_mickg_rdel_tl {)}}
    { rb }{\tl_set:Nn \l_mickg_ldel_tl {(} \tl_set:Nn \l_mickg_rdel_tl {\rbrace}}
    { sb }{\tl_set:Nn \l_mickg_ldel_tl {[} \tl_set:Nn \l_mickg_rdel_tl {\rbrace}}
    { br }{\tl_set:Nn \l_mickg_ldel_tl {\lbrace} \tl_set:Nn \l_mickg_rdel_tl {)}}
    { bs }{\tl_set:Nn \l_mickg_ldel_tl {\lbrace} \tl_set:Nn \l_mickg_rdel_tl {]}}
    { ra }{\tl_set:Nn \l_mickg_ldel_tl {(} \tl_set:Nn \l_mickg_rdel_tl {\rangle}}
    { sa }{\tl_set:Nn \l_mickg_ldel_tl {[} \tl_set:Nn \l_mickg_rdel_tl {\rangle}}
    { ba }{\tl_set:Nn \l_mickg_ldel_tl {\lbrace} \tl_set:Nn \l_mickg_rdel_tl {\rangle}}
    { ar }{\tl_set:Nn \l_mickg_ldel_tl {\langle} \tl_set:Nn \l_mickg_rdel_tl {)}}
    { as }{\tl_set:Nn \l_mickg_ldel_tl {\langle} \tl_set:Nn \l_mickg_rdel_tl {]}}
    { ab }{\tl_set:Nn \l_mickg_ldel_tl {\langle} \tl_set:Nn \l_mickg_rdel_tl {\rbrace}}
    { rv }{\tl_set:Nn \l_mickg_ldel_tl {(} \tl_set:Nn \l_mickg_rdel_tl {|}}
    { sv }{\tl_set:Nn \l_mickg_ldel_tl {[} \tl_set:Nn \l_mickg_rdel_tl {|}}
    { bv }{\tl_set:Nn \l_mickg_ldel_tl {\lbrace} \tl_set:Nn \l_mickg_rdel_tl {|}}
    { av }{\tl_set:Nn \l_mickg_ldel_tl {\langle} \tl_set:Nn \l_mickg_rdel_tl {|}}
    { vr }{\tl_set:Nn \l_mickg_ldel_tl {|} \tl_set:Nn \l_mickg_rdel_tl {)}}
    { vs }{\tl_set:Nn \l_mickg_ldel_tl {|} \tl_set:Nn \l_mickg_rdel_tl {]}}
    { vb }{\tl_set:Nn \l_mickg_ldel_tl {|} \tl_set:Nn \l_mickg_rdel_tl {\rbrace}}
    { va }{\tl_set:Nn \l_mickg_ldel_tl {|} \tl_set:Nn \l_mickg_rdel_tl {\rangle}}
    { rdv }{\tl_set:Nn \l_mickg_ldel_tl {(} \tl_set:Nn \l_mickg_rdel_tl {\|}}
    { sdv }{\tl_set:Nn \l_mickg_ldel_tl {[} \tl_set:Nn \l_mickg_rdel_tl {\|}}
    { bdv }{\tl_set:Nn \l_mickg_ldel_tl {\lbrace} \tl_set:Nn \l_mickg_rdel_tl {\|}}
    { adv }{\tl_set:Nn \l_mickg_ldel_tl {\langle} \tl_set:Nn \l_mickg_rdel_tl {\|}}
    { vdv }{\tl_set:Nn \l_mickg_ldel_tl {|} \tl_set:Nn \l_mickg_rdel_tl {\|}}
    { dvr }{\tl_set:Nn \l_mickg_ldel_tl {\|} \tl_set:Nn \l_mickg_rdel_tl {)}}
    { dvs }{\tl_set:Nn \l_mickg_ldel_tl {\|} \tl_set:Nn \l_mickg_rdel_tl {]}}
    { dvb }{\tl_set:Nn \l_mickg_ldel_tl {\|} \tl_set:Nn \l_mickg_rdel_tl {\rbrace}}
    { dva }{\tl_set:Nn \l_mickg_ldel_tl {\|} \tl_set:Nn \l_mickg_rdel_tl {\rangle}}
    { dvv }{\tl_set:Nn \l_mickg_ldel_tl {\|} \tl_set:Nn \l_mickg_rdel_tl {|}}
    { lr }{\tl_set:Nn \l_mickg_ldel_tl {(} \tl_clear:N \l_mickg_rdel_tl}
    { rr }{\tl_set:Nn \l_mickg_ldel_tl {)} \tl_clear:N \l_mickg_rdel_tl}
    { ls }{\tl_set:Nn \l_mickg_ldel_tl {[} \tl_clear:N \l_mickg_rdel_tl}
    { rs }{\tl_set:Nn \l_mickg_ldel_tl {]} \tl_clear:N \l_mickg_rdel_tl}
    { lb }{\tl_set:Nn \l_mickg_ldel_tl {\lbrace} \tl_clear:N \l_mickg_rdel_tl}
    { rb }{\tl_set:Nn \l_mickg_ldel_tl {\rbrace} \tl_clear:N \l_mickg_rdel_tl}
    { la }{\tl_set:Nn \l_mickg_ldel_tl {\langle} \tl_clear:N \l_mickg_rdel_tl}
    { ra }{\tl_set:Nn \l_mickg_ldel_tl {\rangle} \tl_clear:N \l_mickg_rdel_tl}
    { ov }{\tl_set:Nn \l_mickg_ldel_tl {|} \tl_clear:N \l_mickg_rdel_tl}
    { odv }{\tl_set:Nn \l_mickg_ldel_tl {\|} \tl_clear:N \l_mickg_rdel_tl}
    { ssi }{\tl_set:Nn \l_mickg_ldel_tl {[} \tl_set:Nn \l_mickg_rdel_tl {\mathclose{[}}}
    { sis }{\tl_set:Nn \l_mickg_ldel_tl {\mathopen{]}} \tl_set:Nn \l_mickg_rdel_tl {]}}
    { sisi }{\tl_set:Nn \l_mickg_ldel_tl {\mathopen{]}} \tl_set:Nn \l_mickg_rdel_tl {\mathclose{[}}}
   }
   { \tl_set:Nn \l_mickg_ldel_tl {(} \tl_set:Nn \l_mickg_rdel_tl {)} } % some default
  \tl_if_empty:NTF \l_mickg_rdel_tl
   {
    \l_mickg_lsize_tl \l_mickg_ldel_tl #3
   }
   {
    \l_mickg_lsize_tl \l_mickg_ldel_tl #3 \l_mickg_rsize_tl \l_mickg_rdel_tl
   }
 }
\ExplSyntaxOff

\begin{document}
\[
\delim[lr]{r}{\frac{a}{b}}
\]
\end{document}

Check texdoc interface3 for more information. The \str_case:nnF function requires three arguments: the first is the string to check, the second is a set of pairs {<string>}{<code>} for deciding what to do; the final argument is for code to be executed in the “none of the above” case.

Please, don't use $$ in LaTeX. It's wrong.

enter image description here

  • I've taken a look at interface3.pdf. Why do you make \delim protected? – MickG Aug 12 '14 at 11:08
  • @MickG Because it does assignments (\tl_set:Nn). – egreg Aug 12 '14 at 11:28
4

Here is an alternative to egreg's answer, which mainly aims to tidy up your proposed syntax a bit and adds some warnings and error messages.

Notice also that there is still a problem in egreg's answer with cases like \delim{ssi}{\frac{a}{b}} that carries over from your code to his (the \mathopen and \mathclose are the culprits).

In this version, both the size and the delimiter options take two letters. If only one letter is given, it is used for both delimiters (the only exceptions are "l" and "r" for size, either of which will give a \left and \right pairing).

For delimiter types, lowercase letters give the standard orientation and uppercase letters give the inverted orientation (e.g. "rr" will give "(" and ")", while "RR" will give ")" and "(" ). The exception are "v" and "V", which give a single bar and a double bar, respectively. When "-" is given, the corresponding delimiter is omitted.

Both the specification arguments are optional and default to "lr" and "rr", respectively.

\documentclass[a4paper]{report}
\usepackage{xparse,pgffor}

\ExplSyntaxOn

\tl_new:N \l_mickg_left_delim_size_tl
\tl_new:N \l_mickg_right_delim_size_tl
\tl_new:N \l_mickg_left_delim_tl
\tl_new:N \l_mickg_right_delim_tl

\msg_new:nnnn { MickG } { Left ~ delimiter ~ size }
  { Incorrectly ~ specified ~ left ~ delimiter ~ size.  } {}
\msg_new:nnnn { MickG } { Right ~ delimiter ~ size }
  { Incorrectly ~ specified ~ right ~ delimiter ~ size. } {}
\msg_new:nnnn { MickG } { Delimiter ~ size }
  { Incorrect ~ delimiter ~ size ~ specification. } {}
\msg_new:nnnn { MickG } { Left ~ delimiter }
  { Incorrectly ~ specified ~ left ~ delimiter.  } {}
\msg_new:nnnn { MickG } { Right ~ delimiter }
  { Incorrectly ~ specified ~ right ~ delimiter. } {}
\msg_new:nnnn { MickG } { Delimiters }
  { Incorrect ~ delimiter ~ specification. } {}

\cs_new_protected:Npn \mickg_delims_size_set:n #1
  {
    % Test if one or two letters provided.
    \int_case:nnF { \tl_count:n {#1} }
      {
        { \c_two } { \tl_set:Nn \l_tmpa_tl {#1}   } % If two, use both.
        { \c_one } { \tl_set:Nn \l_tmpa_tl {#1#1} } % If one, use it twice.
      }
      % If not one or two letters, set to 'lr' and issue error.
      {
        \tl_set:Nn \l_tmpa_tl { lr }
        \msg_error:nn { MickG } { Delimiter ~ size }
      }
    % Ensure \left is always paired with \right
    \str_case_x:nnTF { \l_tmpa_tl }
      {
        { lr } { \prg_do_nothing: }
        { ll } { \msg_warning:nn { MickG } { Delimiter ~ size } } % Warn if 'l' was copied.
        { rr } { \msg_warning:nn { MickG } { Delimiter ~ size } } % Warn if 'r' was copied.
      }
      {
        \tl_set_eq:NN \l_mickg_left_delim_size_tl  \left
        \tl_set_eq:NN \l_mickg_right_delim_size_tl \right
      }
      % If not using \left and \rigth, set sizes independently.
      {
        \str_case_x:nnF { \tl_head:N \l_tmpa_tl }
          {
            { b } { \tl_set_eq:NN \l_mickg_left_delim_size_tl \bigl  }
            { B } { \tl_set_eq:NN \l_mickg_left_delim_size_tl \Bigl  }
            { x } { \tl_set_eq:NN \l_mickg_left_delim_size_tl \biggl }
            { X } { \tl_set_eq:NN \l_mickg_left_delim_size_tl \Biggl }
          }
          % Error if no match; default to empty token list.
          { 
            \tl_clear:N \l_mickg_left_delim_size_tl
            \msg_error:nn { MickG } { Left ~ delimiter ~ size } 
          } 
        \str_case_x:nnF { \tl_tail:N \l_tmpa_tl }
          {
            { b } { \tl_set_eq:NN \l_mickg_right_delim_size_tl \bigr   }
            { B } { \tl_set_eq:NN \l_mickg_right_delim_size_tl \Bigr   }
            { x } { \tl_set_eq:NN \l_mickg_right_delim_size_tl \biggr  }
            { X } { \tl_set_eq:NN \l_mickg_right_delim_size_tl \Biggr  }
          }
          % Error if no match; default to empty token list. 
          { 
            \tl_clear:N \l_mickg_right_delim_size_tl
            \msg_error:nn { MickG } { Right ~ delimiter ~ size } 
          }
      }
  }

\cs_new_protected:Npn \mickg_delims_type_set:n #1
  {
    % Test if one or two letters provided.
    \int_case:nnF { \tl_count:n {#1} }
      {
        { \c_two } { \tl_set:Nn \l_tmpa_tl {#1}   } % If two, use both.
        { \c_one } { \tl_set:Nn \l_tmpa_tl {#1#1} } % If one, use it twice.
      }
      % If not one or two letters, set to 'rr' and issue error.
      {
        \tl_set:Nn \l_tmpa_tl { rr }
        \msg_error:nn { MickG } { Delimiters }
      }
    % Test first letter.
    \str_case_x:nnF { \tl_head:N \l_tmpa_tl }
      {
        { r } { \tl_set_eq:NN \l_mickg_left_delim_tl (       }
        { R } { \tl_set_eq:NN \l_mickg_left_delim_tl )       }
        { s } { \tl_set_eq:NN \l_mickg_left_delim_tl [       }
        { S } { \tl_set_eq:NN \l_mickg_left_delim_tl ]       }
        { b } { \tl_set_eq:NN \l_mickg_left_delim_tl \lbrace }
        { B } { \tl_set_eq:NN \l_mickg_left_delim_tl \rbrace }
        { a } { \tl_set_eq:NN \l_mickg_left_delim_tl \langle }
        { A } { \tl_set_eq:NN \l_mickg_left_delim_tl \rangle }
        { v } { \tl_set_eq:NN \l_mickg_left_delim_tl |       }
        { V } { \tl_set_eq:NN \l_mickg_left_delim_tl \|      }
        { - } { \tl_set_eq:NN \l_mickg_left_delim_tl .       }
      }
      % Error if no match; default to "(" 
      { 
        \tl_set_eq:NN \l_mickg_left_delim_tl (
        \msg_error:nn { MickG } { Left ~ delimiter } 
      }
    % Test second letter.
    \str_case_x:nnF { \tl_tail:N \l_tmpa_tl }
      {
        { r } { \tl_set_eq:NN \l_mickg_right_delim_tl )       }
        { R } { \tl_set_eq:NN \l_mickg_right_delim_tl (       }
        { s } { \tl_set_eq:NN \l_mickg_right_delim_tl ]       }
        { S } { \tl_set_eq:NN \l_mickg_right_delim_tl [       }
        { b } { \tl_set_eq:NN \l_mickg_right_delim_tl \rbrace }
        { B } { \tl_set_eq:NN \l_mickg_right_delim_tl \lbrace }
        { a } { \tl_set_eq:NN \l_mickg_right_delim_tl \rangle }
        { A } { \tl_set_eq:NN \l_mickg_right_delim_tl \langle }
        { v } { \tl_set_eq:NN \l_mickg_right_delim_tl |       }
        { V } { \tl_set_eq:NN \l_mickg_right_delim_tl \|      }
        { - } { \tl_set_eq:NN \l_mickg_right_delim_tl .       }
      }
      % Error if no match; default to ")" 
      { 
        \tl_set_eq:NN \l_mickg_right_delim_tl )
        \msg_error:nn { MickG } { Right ~ delimiter } 
      }
  }

\cs_new_protected:Npn \mickg_delims_print:nnn #1 #2 #3
  {
    \mickg_delims_size_set:n {#1}
    \mickg_delims_type_set:n {#2}
    \l_mickg_left_delim_size_tl  \l_mickg_left_delim_tl
    #3
    \l_mickg_right_delim_size_tl \l_mickg_right_delim_tl
  }

\NewDocumentCommand \delim { O{ lr } O{ r } m }
  {
    \mickg_delims_print:nnn {#1} {#2} {#3}
  }

\ExplSyntaxOff

\begin{document}

% Test by iterating through the combinations.
\foreach \x in {b,B,x,X} {
  \foreach \y in {b,B,x,X} {
    \foreach \z in {r,R,s,S,b,B,a,A,v,V,-} {
      \foreach \w in {r,R,s,S,b,B,a,A,v,V,-} {
        % \delim does not expand the optional arguments but this could
        % easily be changed; I expand them here with an \edef
        \edef\foo{\noexpand\delim[\x\y][\z\w]}
        $\displaystyle\foo{\frac{a}{b}}$\quad
      }
    }
  }
}

\end{document}
  • May be the result is the same, but don't you want \tl_set_eq:Nn \… { \… } instead of \tl_set_eq:NN \… \…? E.g., you don't want the token list to have what \left have inside but \left itself. In the end the result may be the same but it's not right, I think. By the way, great answer. – Manuel Apr 18 '14 at 9:38
  • @Manuel: That's a good question, and I admit I'm not really sure. Let's say we want to uniformly produce the same effect as \foo\buzz. Then I take it that \tl_set_eq:NN \l_foo_tl \foo will ensure that \l_foo_tl\bar yields whatever \foo\buzz does, in any expansion scenario, which is not guaranteed with \tl_set:Nn \l_foo_tl { \foo }. I suppose using \tl_set_eq:NN could mess things up if there's some macro scanning ahead to look for \foo, but are there any other cases? – Jura Pintar Apr 18 '14 at 13:22
  • I thought exactly what you said (both, the expansion scenario, and the scanning macro). But then… then you are not looking for \tl_set_eq:NN but \cs_set_eq:NN… I think (I know it works, but I'm just looking for an explanation of what is “right”). I'm not sure of what I just said… Let me know what you think ;) – Manuel Apr 18 '14 at 20:24
  • You might well be right that \cs_set_eq:NN comes somewhat closer to following the rules, but I'm not really confident in either solution (though both produce the desired outcome, of course). For \cs_set_eq:NN, a problem is that there are no control sequence variables, and things defined with \cs_new... are meant to be functions anyway, not arbitrary control sequences. The issue of function-valued variables was recently discussed on the LaTeX3 mailing list, without a clear resolution. In comparison, token lists seem more neutral to me. Maybe this should be posed as a new question? – Jura Pintar Apr 19 '14 at 2:47
0

1) xparse or a similar package is needed for Expl.

2) The second argument is mandatory, so \delim[lr]{r}{\fr{a}{b}} is right. By the way, \fr=\displaystyle\frac.

3) You need a "non of those cases" code, otherwise strange errors are produced with \str_case:nnF; alternately, you can use \str_case:nn.

4) Btw, without updating Expl I don't know if those two functions are both available. One thing is sure: \str_case:nnF is called \str_case:nnn, or such a name is borne by a similar function.

Now I'll just test the rest of this command's possibilities.

  • Now the strange thing is that \delim[X]{ov}{} typesets to a plain |, without the \Bigg` that should be there. Why can that be? – MickG Apr 17 '14 at 17:07
  • It seems that \lsize\ldel works fine after \delim[X]{ov}{}, but inside the command something different happens. It should expand to \lsize\ldel with the prevously given definition of those two commands, but \delim[X]{ov}{}\lsize\ldel doesn't give the same thing, as regardless of the optional argument the \delim always typesets to a plain |, without size control. Oh, and I forgot a backtick in the previous comment, which should go after {}. – MickG Apr 17 '14 at 17:21
  • And PS I'm loading the command from a package, so \makeatletter should be automatic, right? – MickG Apr 17 '14 at 18:31
  • I don't think the experimental syntax defines changes to @, so you would still need that command. This said, please don't :) read texdoc expl3. – Sean Allred Apr 18 '14 at 1:04
  • @SeanAllred no, Expl doesn't do that, but if the command is in a package I think it isn't necessary to use \makeatletter. Besides, even using it doesn't solve the problem. It seems the actual problem is in the \ifx, which invariably leads to the wrong branch. Indeed, defining \rdel as . in those cases where it is defined as \@empty above gets the desired result, while defining it as \relax or \foo where \def\foo{a} gives problems. @Jura Printar I noticed the problem of \mathopen and solved it by an extra conditional. That said, I prefer my original cases. – MickG Apr 18 '14 at 6:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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