xparse (\NewDocumentCommand)

Cuando quieres una orden con varios argumentos opcionales o una variante con estrella bien definida, contar argumentos al estilo de \newcommand ya no escala. La respuesta moderna es \NewDocumentCommand, que declara el *tipo* de cada argumento como una cadena de letras. Nació en el paquete xparse, pero ahora forma parte del núcleo de LaTeX. Esta página cubre el mini-lenguaje de especificación de argumentos y los comandos de prueba que inspeccionan qué proporcionó realmente el usuario.

Ahora forma parte del núcleo

Antes hacía falta \usepackage{xparse}, pero desde la versión de LaTeX de octubre de 2020 esta maquinaria vive en el propio núcleo. Comandos como \NewDocumentCommand están disponibles de entrada, y rara vez hace falta cargar xparse. El archivo del núcleo que lo implementa se llama ltcmd, y el paquete xparse se describe oficialmente como “obsolete”. Salvo unos pocos tipos de argumento obsoletos, el código nuevo puede usar estos comandos sin cargar nada.

La idea de esta interfaz es separar significado, o interfaz, de implementación. Declaras la secuencia de argumentos que ve el usuario —obligatorios, opcionales, con estrella— como especificación de argumentos (arg-spec), y el cuerpo recibe siempre argumentos normalizados como #1, #2, etc. Las bases de \newcommand están en la página “Definir macros”; leerla antes ayuda a ver el contraste.

Definir comandos y entornos

La forma básica es \NewDocumentCommand{\cmd}{⟨arg-spec⟩}{⟨code⟩}: nombre del comando, especificación de argumentos y cuerpo. Como \newcommand, tiene parientes para distintos propósitos; cambia cómo se comportan ante un nombre ya definido.

ComandoAnte un nombre existente
\NewDocumentCommandDa error si ya está definido
\RenewDocumentCommandDa error si aún no está definido (lo rehace)
\ProvideDocumentCommandDefine solo si no existe
\DeclareDocumentCommandSiempre sobrescribe (úsalo con cautela)

Los entornos reciben el mismo tratamiento con \NewDocumentEnvironment{⟨env⟩}{⟨arg-spec⟩}{⟨start code⟩}{⟨end code⟩} (y \Renew…, \Provide…, \Declare…). Los argumentos se dan después de \begin{⟨env⟩} y son visibles tanto para el código inicial como para el final; consulta la página de entornos personalizados. Además, todo comando creado así es automáticamente robusto (usa internamente el mecanismo \protected de ε-TeX), así que no debes preocuparte por \protect en títulos o leyendas.

También existe una variante expandible, \NewExpandableDocumentCommand. Puede usarse en contextos donde una orden se *expande*, como dentro de \edef o \write, pero a cambio limita los tipos de argumento permitidos: pruebas booleanas como s/t y verbatim v no están disponibles. Para documentos normales, la forma estándar es la adecuada.

El lenguaje de especificación de argumentos

Una especificación de argumentos es una cadena en la que cada letra nombra el tipo de un argumento: obligatorio, opcional, con estrella, delimitado por caracteres concretos, etc. Cada tipo llega al cuerpo como #1, #2, y así sucesivamente; la sutileza clave es que un argumento opcional no proporcionado recibe un valor especial. Los tipos principales se resumen abajo.

TipoSe escribeSignificadoCómo llega
mmArgumento obligatorio {}Un #1 ordinario
ooArgumento opcional [...]-NoValue- si falta
OO{default}Opcional con valor por defectodefault si falta
ssEstrella opcional *\BooleanTrue / \BooleanFalse
tt⟨char⟩Token de carácter opcional dado\BooleanTrue / \BooleanFalse
rr⟨d1⟩⟨d2⟩Obligatorio, delimitado por d1d2-NoValue- tras un error si falta
dd⟨d1⟩⟨d2⟩Opcional, delimitado por d1d2-NoValue- si falta
ee{⟨tokens⟩}Adornos, por ejemplo ^, _Cada uno -NoValue- si falta
vvArgumento verbatimLos caracteres literales

m es el argumento obligatorio básico; acepta un grupo entre llaves o un token único, y las {} exteriores se quitan antes de llegar al cuerpo. o es el argumento opcional [...] estándar, y O{default} el mismo con valor por defecto. Los tipos en mayúscula como O y D permiten dar un valor por defecto, mientras que las minúsculas o/d devuelven el marcador especial -NoValue-.

s detecta una estrella inicial *: presente da \BooleanTrue, ausente da \BooleanFalse. Generalizado a un carácter único, t⟨char⟩ prueba ese token; t+, por ejemplo, informa la presencia de + como booleano. r⟨d1⟩⟨d2⟩ es un argumento delimitado obligatorio, encerrado entre delimitadores elegidos por ti, por ejemplo r() para paréntesis; si falta el delimitador inicial, emite un error e inserta -NoValue-. La versión delimitada opcional es d⟨d1⟩⟨d2⟩.

Uno más inusual es e{⟨tokens⟩}, que recoge adornos como ^ y _. Con e{^_} toma ^{...} y _{...} en cualquier orden, y los que no se dan se vuelven -NoValue-; los tokens listados deben ser distintos. v lee un argumento verbatim, como \verb. Los delimitadores de los tipos delimitados (r, d, …) no pueden ser los caracteres de agrupación TeX { y }, así que se suelen elegir pares naturales como [], () o "".

Inspeccionar argumentos: las pruebas

Para manejar un argumento opcional o una estrella, necesitas probar dentro del cuerpo si se proporcionó. Hay dos familias de comandos. \IfNoValueTF{#1}{⟨if no value⟩}{⟨if value⟩} comprueba si el argumento es -NoValue-, es decir, si no se dio: si falta, ejecuta la primera rama; si hay valor, la segunda. También existe la inversa \IfValueTF, y formas de una sola rama (\IfNoValueT / \IfNoValueF, \IfValueT / \IfValueF).

Para el booleano producido por s o t, usa \IfBooleanTF{#1}{⟨if starred⟩}{⟨if not⟩}: si #1 es \BooleanTrue, ejecuta la primera rama; si es \BooleanFalse, la segunda. También existen \IfBooleanT / \IfBooleanF. Regla práctica: \IfNoValueTF y familia son para argumentos opcionales como o/d; \IfBooleanTF y familia para los booleanos de s/t. Además, -NoValue- está construido para no coincidir con el texto literal -NoValue-; pruébalo siempre con \IfNoValueTF, no comparando cadenas.

Ejemplo: estrella más opción con valor por defecto

Construyamos una orden con variante con estrella y argumento opcional con valor por defecto usando la especificación s O{} m. El ejemplo es una orden de título: #1 es la estrella, probada con \IfBooleanTF; #2 es un título corto opcional, vacío por defecto; y #3 es el título principal.

latex
\NewDocumentCommand{\heading}{s O{} m}{%
  \IfBooleanTF{#1}%
    {\textbf{#3}}%                       星つき: 番号なしの見出し / starred: unnumbered
    {\section%
       \IfNoValueTF{#2}%
         {{#3}}%                          短縮見出しなし / no short title
         {[#2]{#3}}%                       短縮見出しあり / with short title
    }%
}

% 使用例 / usage
\heading{Introduction}             % 通常の番号つき節
\heading[Intro]{A Long Introduction} % 目次用に短縮見出しを指定
\heading*{Preface}                 % 星つき: 太字の無番号見出し

Sutileza: no confundas o y O{}. Con o, un argumento omitido se vuelve -NoValue-, así que se ramifica con \IfNoValueTF como arriba. Con O{}, en cambio, siempre hay un valor, vacío si se omitió; ahí se prueba si está vacío, con \tl_if_blank:nTF (expl3) o \ifblank (etoolbox), no con \IfNoValueTF. En el ejemplo, hacer que el argumento opcional sea o sin valor por defecto es lo que hace que la rama \IfNoValueTF se comporte como se pretende.

Por qué supera a \newcommand

\newcommand solo permite un argumento opcional, el primero, y no ofrece variante con estrella integrada. La solución clásica era escribir a mano tuberías de bajo nivel como \@ifstar y \@ifnextchar, pero requieren \makeatletter, son frágiles con espacios y anidamientos, y se leen mal.

  • Múltiples argumentos opcionales independientes (o o m, O{a} O{b} m, …).
  • Variantes con estrella reales mediante s más \IfBooleanTF, sin el truco \@ifstar.
  • Valores por defecto declarativos: escribir O{default} basta para fijar el valor cuando se omite.
  • Robusto desde el principio: sin \protect en títulos o leyendas.
  • Sintaxis de entrada que \newcommand no puede expresar: argumentos delimitados (r, d) y adornos (e).

En resumen, una abreviatura simple va bien con \newcommand, pero en cuanto la estructura de argumentos se vuelve un poco elaborada, \NewDocumentCommand es la primera opción. Cuando además quieras escribir el cuerpo como un pequeño programa, combinarlo con expl3, la capa de programación LaTeX3, es el siguiente paso natural. Para crear clases y paquetes, consulta la página de autoría.