# Define macro for \Big, \bigg etc

Is it possible to make macro behave as if it was written directly?

\documentclass{article}
\usepackage{amsmath}

\newcommand{\veca}{|_{\vec{a}}}

\begin{document}

$\frac{f(\vec{x})}{g(\vec{x})}\bigg\veca \qquad \frac{f(\vec{x})}{g(\vec{x})}\bigg|_{\vec{a}}$

\end{document}


• better to use a syntax such as \newcommand{\veca}[1][]{#1|_{\vec{a}} then \veca[\bigg] when you want a size (see the paired delimiter commands in mahtools May 3 at 14:48
• \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. May 3 at 14:53
• @UlrichDiez It's not that it doesn't take expandable commands into account, it's that it's quite common to pass macros there which should not be expanded beforehand. (e.g. \expandafter\bigg\vert would break) May 3 at 15:05
• I understand that you want the size of the vertical bar to automatically adjust to what precedes. You could simply write \left.\frac{f(\vec{x})}{g(\vec{x})}\right\veca. May 5 at 19:33

The default definition of \Big and friends sets the delimiter as a left delimiter, so having a subscript on it ends up being the first element in the delimited list and therefore does not get placed relative to the delimiter. This can be avoided by defining \Big and friends in the opposite way: Make the delimiter a right delimiter, such that the subscript becomes a subscript of the whole delimited list.

While this fixes the placement, it can have side effects on how the subscript is placed (mostly \nulldelimiterskip is zero and the style is always scriptstyle) but for most usecases this shouldn't matter.

Given that amsmath defines \big based on \bBigg@ it's enough to change the definition of that macro:

\documentclass{article}
\usepackage{amsmath}

\makeatletter
\renewcommand \bBigg@[2]{%
{\@mathmeasure\z@{\nulldelimiterspace\z@}%
{\left.\vcenter to#1\big@size{}\right#2}%
\box\z@}}
\makeatother

\newcommand{\veca}{|_{\vec{a}}}

\begin{document}

$\frac{f(\vec{x})}{g(\vec{x})}\bigg\veca \qquad \frac{f(\vec{x})}{g(\vec{x})}\bigg|_{\vec{a}}$

\end{document}


• It's so clever. Thank you so much! I wish you had posted this before I spent lots of time doing it with expl3 May 12 at 13:22

Here's an implementation of @DavidCarlisle's suggestion to make veca take an optional argument, the difference being that I suggest setting \biggr as the default value of the optional argument.

\documentclass{article}
\usepackage{amssymb}
\providecommand{\veca}[1][\biggr]{#1\vert_{\vec{a}}}

\begin{document}
$\frac{f(\vec{x})}{g(\vec{x})}\veca \quad \frac{u(\vec{x})}{v(\vec{x})}\veca[\Bigr] \quad h(\vec{z})\veca[]$
\end{document}

• I wouldn't start a bounty if this solution satisfied me. May 5 at 17:02
• @antshar - You're certainly entirely free, and welcome, to edit your posting and clarifty what exactly your typesetting objective is.
– Mico
May 5 at 17:43

This is more of a comment than an answer, but such constructions work out of the box in ConTeXt LMTX (i.e., with the luametatex engine).

\define\veca{\rvert_{\vec{a}}}

\starttext
\startformula
\stopformula

\stoptext


which gives

I am not sure what is different beneath the hood for this to work correctly.

Note that the size of \bigg and \Bigg are different because ConTeXt does scaling of delimiters a bit differently, and the placement of the subscript is different (that is because luatex engine reads the spacing values from the font; you get similar spacing in lualatex as well).

Is it possible to make macro behave as if it was written directly?

Since TeX evaluate "left-to-right", if you have \outermacro{\innermacro} and keep outermacro intact (*1), nothing can force it to expand innermacro if it doesn't want to.

(*1): the OP's other question address the case of modifying the outer macro. Works as well.

Unless... \veca is not-quite a macro. Do this to do replacement on the source code before reading each line.

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

\begin{luacode*}

    function translate(line)
line=string.gsub(line, [[\veca([^A-Za-z])]], [[|_{\vec{a}}%1]])
line=string.gsub(line, [[\veca\$]], [[|_{\vec{a}}]])
return line
end

\end{luacode*}

\begin{document}

$\frac{f(\vec{x})}{g(\vec{x})}\bigg\veca \qquad \frac{f(\vec{x})}{g(\vec{x})}\bigg|_{\vec{a}}$

% test:
\def\vecab{\vec{ab}}
$\vecab % ^^ middle of a word, don't replace + x\veca % ^^ end of line, still replace$

\end{document}


Of course, this way it doesn't behave the same way a macro does, e.g. if it appear in \verb it will still be replaced with the result. And it's up to you to write the "parser" correctly.

• I'm not responsible if you forget about this replacement thing and wonder why you get mysterious errors when the code totally looks correctly. May 9 at 6:55
• Side note, things other than LuaTeX can do this replacement too, but there are some... drawbacks. May 9 at 6:56

\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 \bigs 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.