Aprendí que \parbox
tiene cinco argumentos, es decir: \parbox[<align>][<height>][<inner-align>]{<width>}{<text>}
. Entonces construí mi propio \myparbox en el que agrego \sloppy\setlength\parfillskip{0pt}
antes del n.° 5. Pero falla. ¿Cuál es el motivo y cómo redefinir \myparbox?
MWE:
\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\myparbox}{ooomm}{%
\parbox[#1][#2][#3]{#4}{\sloppy\setlength\parfillskip{0pt}#5}
}
\begin{document}
AAA\fbox{\parbox[][][]{4em}{aa bb cc dd ee ff}}AAA\\% parbox typesets nothing. why?
BBB\fbox{\myparbox{4em}{aa bb cc dd ee ff}}BBB% This fails to compile
\end{document}
EDITAR:
\documentclass{article}
\usepackage{xparse}
\let\oldparbox\parbox
\RenewDocumentCommand{\parbox}{sO{c}oO{t}mm}{%
\IfBooleanTF{#1}
{%
\IfNoValueTF{#3}
{\oldparbox[#2]{#5}{\sloppy\setlength\parfillskip{0pt}#6}}
{\oldparbox[#2][#3][#4]{#5}{\sloppy\setlength\parfillskip{0pt}#6}}
}
{%
\IfNoValueTF{#3}
{\oldparbox[#2]{#5}{#6}}
{\oldparbox[#2][#3][#4]{#5}{#6}}
}
}
\begin{document}\the\fboxsep
AAA\fbox{\parbox[t]{8em}{aa bb cc dd ee ff gg hh ii}}AAA\\% parbox typesets nothing why?.
BBB\fbox{\parbox*{6em}{aa bb cc dd ee ff}}BBB% This fails to compile
\end{document}
Respuesta1
Como se indicó en los comentarios, un argumento opcional vacío []
no tiene por qué ser equivalente a no dar ningún argumento opcional. Si no dar el argumento equivale a pasar un valor particular se debe verificar con la documentación o implementación del comando.
En el ejemplo, las cosas empeoran porque xparse
el argumento opcional de o
en realidad contiene el valor marcado especial -NoValue-
si no se proporcionó el argumento opcional correspondiente. Puede y debe probar la presencia de un valor con \IfNoValueTF
(como lo sugieredaleifcomentario de).
Esta es una solución muy viable cuando solo tienes que tratar con un argumento opcional, pero se vuelve complicada si aumenta el número de argumentos.
En el caso de \parbox
puede descubrir que los argumentos predeterminados son c
, \relax
como marcador especial y s
cuando busca la definición en sourc2e.pdf
.
Así que podrías intentarlo
\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\myparbox}{O{c}O{\relax}O{s}mm}{%
\parbox[#1][#2][#3]{#4}{\sloppy\setlength\parfillskip{0pt}#5}%
}
\begin{document}
BBB\fbox{\parbox{4em}{\sloppy\setlength\parfillskip{0pt}aa bb cc dd ee ff}}BBB
BBB\fbox{\myparbox{4em}{aa bb cc dd ee ff}}BBB
\end{document}
Normalmente, intentaría solucionar problemas como este que requieren que conozca los valores/comportamiento de los argumentos opcionales predeterminados y/o necesito una gran cantidad de \IfNoValueTF
pruebas para obtener los argumentos correctos, ya que el primer método parece frágil y el segundo muy detallado y repetitivo. Un enfoque similar alLa respuesta de Marijn.podría ser una alternativa, pero al menos en este caso también requiere un conocimiento profundo de la definición de \parbox
.
editar: Acabo de ver la nueva versión de la pregunta. \let
no es suficiente para comandos robustos con argumentos opcionales:¿Cuándo utilizar \LetLtxMacro?. También sugeriría encarecidamente no redefinir los comandos fundamentales, \parbox
incluso si la implementación podría ser compatible con versiones anteriores. Un nuevo nombre es mucho más seguro.
Respuesta2
Alternativamente, puede utilizar xpatch
para insertar el código adicional en el lugar correcto del comando, sin la necesidad de pasar variables. El \parbox
comando llama al \@iiiparbox
comando interno que procesa el contenido real, por lo que este comando interno es el que debe parchearse. MWE:
\documentclass{article}
\usepackage{xpatch}
\begin{document}
\makeatletter
\xpatchcmd{\@iiiparbox}{#5}{\sloppy\setlength\parfillskip{0pt}#5}{}{}
\makeatother
AAA\fbox{\parbox{4em}{aa bb cc dd ee ff}}AAA
\end{document}
Tenga en cuenta que esto cambia el comportamiento de todos los parboxes. Si desea un comando personalizado con la alineación justificada y también conservar el comando normal, puede definir el comando personalizado usando una copia del \@iiiparbox
comando y parchear la copia en lugar del original. MWE:
\documentclass{article}
\usepackage{xpatch}
\begin{document}
\makeatletter
\def\myparbox{\@ifnextchar [\@iparbox {\myiiiparbox c\relax [s]}}
\let\myiiiparbox\@iiiparbox
\xpatchcmd{\myiiiparbox}{#5}{\sloppy\setlength\parfillskip{0pt}#5}{}{}
\makeatother
AAA\fbox{\parbox{4em}{aa bb cc dd ee ff}}AAA
BBB\fbox{\myparbox{4em}{aa bb cc dd ee ff}}BBB
\end{document}
Resultado:
Respuesta3
Los argumentos opcionales \parbox
deben contener tokens específicos, si están presentes. El valor predeterminado para el primero es c
, por lo que podemos realizar algunas comprobaciones de la presencia de argumentos opcionales. Hay que empezar por el último.
El primer argumento opcional debe ser c
(predeterminado) t
o b
; el segundo debe ser largo; el último debe ser , c
o ( si no se proporciona, se usa el primero).t
b
s
Tenga en cuenta que el último argumento \myparbox
debe indicarse con +m
, para poder ingresar diferentes párrafos. La \deliverparbox
macro se utiliza para minimizar la duplicación de código.
\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\myparbox}{O{c}oom+m}{%
\IfNoValueTF{#3}
{%
\IfNoValueTF{#2}
{%
\parbox[#1]{#4}{\deliverparbox{#5}}%
}%
{%
\parbox[#1][#2]{#4}{\deliverparbox{#5}}%
}%
}%
{%
\parbox[#1][#2][#3]{#4}{\deliverparbox{#5}}%
}
}
\NewDocumentCommand{\deliverparbox}{+m}{%
\sloppy\setlength\parfillskip{0pt}#1%
}
\begin{document}
AAA\fbox{\parbox{4em}{aa bb cc dd ee ff}}AAA
BBB\fbox{\myparbox{4em}{aa bb cc dd ee ff}}BBB
BBB\fbox{\myparbox[t][12ex][s]{4em}{aa bb cc dd ee ff\par\vfil aa bb}}BBB
\end{document}