Aprendi que \parbox
tem cinco argumentos, ou seja: \parbox[<align>][<height>][<inner-align>]{<width>}{<text>}
. Então eu construo meu próprio \myparbox no qual adiciono \sloppy\setlength\parfillskip{0pt}
antes do número 5. Mas falha. Qual é o motivo e como 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}
Responder1
Conforme observado nos comentários, um argumento opcional vazio []
não precisa ser equivalente a não fornecer nenhum argumento opcional. Se não fornecer o argumento equivale a passar um valor específico, deve ser verificado com a documentação ou implementação do comando.
No exemplo, as coisas pioram porque xparse
o argumento opcional de o
na verdade contém o valor marcado especial -NoValue-
se o argumento opcional correspondente não for fornecido. Você pode e deve testar a presença de um valor com \IfNoValueTF
(como sugerido pordaleifcomentário).
Essa é uma solução muito viável quando você tem apenas um argumento opcional para lidar, mas fica confuso se o número de argumentos aumentar.
Caso \parbox
você possa descobrir que os argumentos padrão são c
, \relax
como marcador especial e s
quando você procura a definição em sourc2e.pdf
.
Então você poderia tentar
\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 eu tentaria contornar problemas como esse que exigem que eu conheça os valores/comportamento dos argumentos opcionais padrão e/ou precise de um grande número de \IfNoValueTF
testes para acertar os argumentos, pois o primeiro método parece frágil e o segundo muito detalhado e repetitivo. Uma abordagem semelhante aA resposta de Marijnpode ser uma alternativa, mas pelo menos neste caso também requer conhecimento íntimo da definição de \parbox
.
editar: Acabei de ver a nova versão da pergunta. \let
não é suficiente para comandos robustos com argumentos opcionais:Quando usar \LetLtxMacro?. Eu também sugeriria fortemente não redefinir comandos fundamentais, como \parbox
mesmo que a implementação possa ser compatível com versões anteriores. Um novo nome é muito mais seguro.
Responder2
Alternativamente, você pode xpatch
inserir o código extra no lugar certo do comando, sem a necessidade de passar variáveis. O \parbox
comando chama o \@iiiparbox
comando interno que processa o conteúdo real, portanto este comando interno é aquele que deve ser corrigido. 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}
Observe que isso altera o comportamento de todos os parboxes. Se você deseja um comando personalizado com alinhamento justificado e também manter o comando regular, então você pode definir o comando personalizado usando uma cópia do \@iiiparbox
comando e corrigir a cópia em vez do 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:
Responder3
Os argumentos opcionais devem \parbox
conter tokens específicos, se presentes. O valor padrão para o primeiro é c
, portanto podemos poupar algumas verificações quanto à presença dos argumentos opcionais. É preciso começar do último.
O primeiro argumento opcional deve ser c
(padrão) t
ou b
; o segundo deve ter comprimento; o último deve ser c
, t
, b
ou s
(se não for fornecido, o primeiro será usado).
Observe que o último argumento \myparbox
deve ser denotado por +m
, para poder inserir parágrafos diferentes. A \deliverparbox
macro é usada para minimizar a duplicação 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}