This is a fairly different method than the previous one, so I'm posting it separately. The idea here is to make (
, )
, [
, ]
active in the whole document. Of course, that breaks everything, so we need to repair it by redefining the interface of every command that we use which takes optional arguments. I chose the syntax to be as close to xparse
as possible. For instance,
\ChangeCommandInterface {\section} {t*d[]m} {s{#1}, o{#2}, m{#3}}%
will redefine \section
to take three arguments: an optional star (t*
), an optional argument delimited by active brackets (d[]
), and a mandatory argument (m
). Then the argument is reconstructed with the correct catcodes (we could also use that to swap arguments): in xparse
, s
means optional star, and here we put a star if and only if #1
is true (meaning that there was initially a star). Similarly, o{#2}
will mean "put #2
as an optional argument, enclosed in (normal) brackets", and if there was no argument #2
, then put no optional argument.
The example document, followed by the code.
% We put the body of the file here, and call it later using \input.
% Of course you can put the rest of this code in a style file
% and \usepackage{...} it in a normal document.
\begin{filecontents}{\jobname-body.tex}
\documentclass{article}
\usepackage{amsthm}
\usepackage{amsmath}
\newtheorem{theorem}{Theorem}
\begin{document}
\tableofcontents
\section[Short title]{Long title}
\begin{theorem}
Test theorem (yes, I'm not inspired \textbf{(at all)}).
\begin{align*}
a\left[ \frac{ \sqrt[3]{c} }{ \sqrt[2]{d} } \right] \\
\end{align*}
\end{theorem}
\end{document}
\end{filecontents}
\RequirePackage{xparse}
\ExplSyntaxOn
% We define functions to store the arguments into a token list
% for use later. Each type of argument has its own "put" function
%
\tl_new:N \l_PWparse_args_tl
\cs_new:Npn \PWparse_put_cmd:N #1 {
\tl_set:Nn \l_PWparse_args_tl {#1} }
\cs_generate_variant:Nn \PWparse_put_cmd:N {c}
\cs_new:Npn \PWparse_put_saved_cmd:N #1 {
\PWparse_put_cmd:c {PWparse_saved_cmd_ \cs_to_str:N #1} }
\cs_new:Npn \PWparse_save_cmd:N #1 {
\cs_new_eq:cN {PWparse_saved_cmd_ \cs_to_str:N #1} #1}
\cs_new:Npn \PWparse_put_arg:n #1 {
\tl_put_right:Nn \l_PWparse_args_tl {#1}}
\cs_new:Npn \PWparse_put_targ:Nn #1 #2 {
\IfBooleanT {#2} { \exp_args:No \PWparse_put_arg:n {\token_to_str:N #1} }
}
\cs_new:Npn \PWparse_put_sarg:n #1 { \PWparse_put_targ:Nn * {#1} }
\cs_new:Npn \PWparse_put_Darg:NNnn #1 #2 #3 #4 {
\IfNoValueTF {#4} {
\PWparse_put_Darg_aux:oon {\token_to_str:N #1} {\token_to_str:N #2} {#3}
}{
\PWparse_put_Darg_aux:oon {\token_to_str:N #1} {\token_to_str:N #2} {#4}
}
}
\cs_new:Npn \PWparse_put_Darg_aux:nnn #1 #2 #3 {
\PWparse_put_arg:n {#1 #3 #2} }
\cs_generate_variant:Nn \PWparse_put_Darg_aux:nnn {oo}
\cs_new:Npn \PWparse_put_Oarg:nn #1 #2 {\PWparse_put_Darg:NNnn [ ] {#1} {#2} }
\cs_new:Npn \PWparse_put_darg:NNn #1 #2 #3 {
\IfNoValueF {#3} { \PWparse_put_Darg:NNnn #1 #2 {} {#3} } }
\cs_new:Npn \PWparse_put_oarg:n #1 {\PWparse_put_darg:NNn [ ] {#1} }
\cs_new:Npn \PWparse_put_uarg:nn #1 #2 {
\PWparse_put_arg:n { #2 #1 } }
\cs_new:Npn \PWparse_put_marg:n #1 {
\PWparse_put_arg:n { {#1} }}
\cs_new_eq:NN \PWparse_put_larg:n \PWparse_put_arg:n
\cs_new:Npn \PWparse_put_garg:n #1 {
\IfNoValueF {#1} {\PWparse_put_marg:n {#1}} }
\cs_new:Npn \PWparse_put_Garg:nn #1 #2 {
\IfNoValueTF {#2} {
\PWparse_put_marg:n {#1}
} {
\PWparse_put_marg:n {#2}
}
}
\cs_new_eq:NN \PWparse_put_Darg:w \PWparse_put_Darg:NNnn
\cs_new_eq:NN \PWparse_put_darg:w \PWparse_put_darg:NNn
\cs_new_eq:NN \PWparse_put_garg:w \PWparse_put_garg:n
\cs_new_eq:NN \PWparse_put_larg:w \PWparse_put_larg:n
\cs_new_eq:NN \PWparse_put_marg:w \PWparse_put_marg:n
\cs_new_eq:NN \PWparse_put_oarg:w \PWparse_put_oarg:n
\cs_new_eq:NN \PWparse_put_Oarg:w \PWparse_put_Oarg:nn
\cs_new_eq:NN \PWparse_put_sarg:w \PWparse_put_sarg:n
\cs_new_eq:NN \PWparse_put_targ:w \PWparse_put_targ:Nn
\cs_new_eq:NN \PWparse_put_uarg:w \PWparse_put_uarg:nn
\cs_new:Npn \PWparse_put_one_arg:N #1 {\use:c{PWparse_put_ #1 arg:w}}
% To change the interface of a command, we save it (equivalent
% of the primitive \let), and then treat arguments one at a time).
%
\cs_new:Npn \ChangeCommandInterface #1 #2 #3 {
\PWparse_save_cmd:N #1
\DeclareDocumentCommand{#1}{#2}{%
\PWparse_put_saved_cmd:N #1
\clist_map_inline:nn {#3} {\PWparse_put_one_arg:N ####1}
\l_PWparse_args_tl
}
}
\ExplSyntaxOff
\begingroup
\catcode`\[=13\catcode`\]=13\relax
\catcode`\(=13\catcode`\)=13\relax
\AtBeginDocument{%
\catcode`\[=13\catcode`\]=13\relax
\catcode`\(=13\catcode`\)=13\relax
\def[{\ifmmode\string [\else\textup{\string [}\fi}%
\def]{\ifmmode\string ]\else\textup{\string ]}\fi}%
\def({\ifmmode\string (\else\textup{\string (}\fi}%
\def){\ifmmode\string )\else\textup{\string )}\fi}%
%
% Complete the list below with your own commands.
\ChangeCommandInterface {\section} {t*d[]m} {s{#1}, o{#2}, m{#3}}%
\ChangeCommandInterface {\subsection} {t*d[]m} {s{#1}, o{#2}, m{#3}}%
\ChangeCommandInterface {\sqrt} {d[]m} {o{#1}, m{#2}}%
}
\endgroup
\input\jobname-body.tex
[]
active will break optional arguments. Same for()
and picture environments.[(
active but\let
to themselves would not break\futurelet
parsing. Then, they can be redefined to grab the corresponding closing brace inside\emph
.