
\documentclass{article}
\usepackage{amsmath}
\usepackage{expl3}
\makeatletter
\ExplSyntaxOn
\cs_set_eq:NN \better_big:nn \bBigg@
\cs_set:Npn \bBigg@ #1#2 {
\tl_set:Nx \arg_rest_tokens { \tl_tail:N {#2} }
\tl_set:Nx \arg_first_token { \tl_head:N {#2} }
\tl_set:Nx \arg_first_token_exp { \tl_head:f {#2} }
\exp_last_unbraced:No \token_if_eq_meaning:NNT \arg_first_token \delimiter {
\use_none_delimit_by_q_nil:w
}
\exp_last_unbraced:No \token_if_eq_meaning:NNF \arg_first_token_exp \delimiter {
\exp_last_unbraced:Nno \str_if_in:nnF {\{\}} {\arg_first_token} {
\int_compare:nF { \exp_last_unbraced:NNV \delcode`\arg_first_token > 0 } {
\use_none_delimit_by_q_nil:w
}
}
}
\better_big:nn {#1} {\arg_first_token} \arg_rest_tokens
\use_none_delimit_by_q_stop:w
\use_none_delimit_by_q_nil:w \q_nil
\better_big:nn {#1}{#2}
\use_none_delimit_by_q_stop:w \q_stop
}
\ExplSyntaxOff
\makeatother
\newcommand{\veca}{|_{\vec{a}}}
\newcommand{\ketb}{\rangle^*}
\newcommand{\lnorm}{\|}
\newcommand{\rnorm}{\|_\infty}
\begin{document}
Custom macros next to \verb|\Big, \bigg|, etc
\[
\frac{f(\vec{x})}{g(\vec{x})}\bigg\veca \qquad
\big\lnorm A\vec{x} \big\rnorm \qquad
\Big|\Phi(t)\Big\ketb
\]
Doesn't break the regular behaviour
\[
\frac{f(\vec{x})}{g(\vec{x})}\bigg|_{\vec{a}} \qquad
\big\| A\vec{x} \big\|_\infty \qquad
\Big|\Phi(t)\Big\rangle^*
\]
\end{document}
The question itself seems pretty simple, doesn't it. However, it appeared way harder to achieve that I firstly though, to be honest.
It took me lots of effort to finally solve the problem. I have to thank everyone who contributed to this and helped me to solve adjacent questions.
Special thanks to egreg that come up with the way to detect delimiters in general.
Explanation
All \big
, \bigg
, \Big
, \Bigg
are defined in amsmath
like so
\renewcommand{\big}{\bBigg@\@ne}
\renewcommand{\Big}{\bBigg@{1.5}}
\renewcommand{\bigg}{\bBigg@\tw@}
\renewcommand{\Bigg}{\bBigg@{2.5}}
\ifx\leavevmode@ifvmode\@undefined
\def\bBigg@#1#2{%
{\@mathmeasure\z@{\nulldelimiterspace\z@}%
{\left#2\vcenter to#1\big@size{}\right.}%
\box\z@}}
\else
\def\bBigg@#1#2{\leavevmode@ifvmode
{\@mathmeasure\z@{\nulldelimiterspace\z@}%
{\left#2\vcenter to#1\big@size{}\right.}%
\box\z@}}
\fi
so the changes need to apply only to \bBigg@
First what comes to mind is to simply expand the argument of \big
s commands. It works at the first sight, but actually it breaks some of cases, for example \big\vert
would led to an error.
Therefore, the idea that eventually implemented is the following:
Check whether the argument is expandable and if so, check the first argument of the expansion, i.e \veca
's expansion is {|_\vec{a}}
and then I check the first token of that list and if it's a delimiter then I pass only it to the \big
command and everything else just appends rightwards.
\newcommand{\veca}[1][]{#1|_{\vec{a}}
then\veca[\bigg]
when you want a size (see the paired delimiter commands inmahtools
\frac{f(\vec{x})}{g(\vec{x})}\expandafter\bigg\veca
works out, so I suppose\bigg
triggers some lookahead at the next token not taking into account that that could be expandable.\expandafter\bigg\vert
would break)\left.\frac{f(\vec{x})}{g(\vec{x})}\right\veca
.