![Como definir _ou_ redefinir um comando (misturando \providecommand + \renewcommand)?](https://rvso.com/image/305894/Como%20definir%20_ou_%20redefinir%20um%20comando%20(misturando%20%5Cprovidecommand%20%2B%20%5Crenewcommand)%3F.png)
Em algumas situações eu gostaria que houvesse uma maneira de definir um comando \tmp
para que
- se
\tmp
não existir: Definido\tmp
- if
\tmp
sai: Redefinir\tmp
Minha abordagem atual é simplesmente usar \newcommand
ou \renewcommand
. No entanto, isso significa que muitas vezes terei que mudar de uma versão para outra se reordenar meus documentos e, às vezes, limitar a capacidade de reutilização geral do meu código.
Emessa questãoAprendi sobre \providecommand
, o que quase resolve meu problema: pode ser usado independentemente de estar \tmp
definido, mas só define na primeira ocorrência e não sobrescreve. Isso me levou à tentativa ingênua:
\newcommand{\overwritecommand}[2]{
\providecommand{#1}{#2}
\renewcommand{#1}{#2}
}
No entanto, esta abordagem obviamente não é suficientemente geral:
% it works for
\overwritecommand{\tmp}{test}
% but not for commands with arguments like
\overwritecommand{\tmp}[1]{test: #1}
% Error: You can't use `macro parameter character #' in horizontal mode.
Existe alguma outra maneira de conseguir odefinir ou substituircomportamento?
Responder1
Sim, existe um método:
\newcommand{\declarecommand}[1]{\providecommand{#1}{}\renewcommand{#1}}
Por que isso funciona? Porque o TeX usa expansão macro e é irrelevante o que \providecommand
define #1
ser, se #1
não foi definido, porque você o redefine imediatamente.
Agora que você sabe como fazer, experimente
\declarecommand{\box}[1]{\fbox{#1}}
e aproveite o naufrágio!
Láéuma razão pela qual o LaTeX não fornece uma \declarecommand
função: vocêDEVEesteja ciente se você está redefinindo um comando existente.
Se você quiser permitir o opcional *
, então
\makeatletter
\newcommand\declarecommand{\@star@or@long\@declarecommand}
\newcommand\@declarecommand[1]{%
\provide@command{#1}{}%
\renew@command{#1}%
}
\makeatother
vai fazer.
Responder2
Eu entendo que você precisa \def
, mas com parâmetros como \newcommand
. É possível definir o nosso próprio \newcommand
que ignora se a sequência de controle definida tem um significado. Por exemplo, podemos usar o código deesta página:
\def\newcommand#1{\isnextchar[{\newcommandA#1}{\newcommandA#1[0]}}
\def\newcommandA#1[#2]{\edef\tmpp{\ifcase#2%
\or1\or12\or123\or1234\or12345\or123456\or1234567\or12345678\or123456789\fi}%
\edef\tmpp{\expandafter\addhashs\tmpp.}%
\isnextchar[{\newcommandB#1}{\long\expandafter\def\expandafter#1\tmpp}%
}
\def\newcommandB#1[#2]{%
\def#1{\isnextchar[{\runcommand#1}{\runcommand#1[#2]}}%
\long\expandafter\def\csname\string#1X\expandafter\endcsname\tmpp
}
\def\addhashs#1{\ifx.#1\else #####1\expandafter\addhashs\fi}
\long\def\runcommand#1[#2]{\csname\string#1X\endcsname{#2}}
Responder3
Como os exemplos clássicos já foram mostrados, vou apenas acrescentar o xparse
caminho, que é bastante amigável:
\documentclass{article}
\usepackage{xparse}
\DeclareDocumentCommand{\foo}{m}
{Foo: #1}
\begin{document}
\foo{bar}
\DeclareDocumentCommand{\foo}{om}
{\IfNoValueTF{#1}%
{Bar: no optional, just #2}%
{Bar: optional = #1, plus #2}%
}%
\foo{Baz}
\foo[Bar]{Baz}
\end{document}