Documentación de tcolorbox: documentar rutas clave dinámicas

Sep 27 2020

Estoy documentando un paquete que tiene ciertas rutas clave que se crean dinámicamente (ya sea por algún comando o sobre la marcha a través del .unknowncontrolador pgfkeys ).

Quiero documentar estas claves con el docKeyentorno de tcolorbox, pero los primeros argumentos (tanto el opcional como el obligatorio) no funcionan con macros como \meta{}.

¿Existe una forma adecuada de hacer esto?

MWE:

\documentclass{article}

\usepackage{tcolorbox}
\tcbuselibrary{documentation}

\begin{document}

\begin{docKey}
    [mypackage/keypath]
    {my key}
    {=value}
    {}
    The \texttt{keypath} part of the key path is dynamic. Using \meta{keypath} breaks.

    Putting both in the mandatory argument as \verb|{\meta{keypath}/my key}| also breaks.
    
    What is the best alternative?
\end{docKey}

\end{document}

Respuestas

5 muzimuzhiZ Sep 27 2020 at 12:53

tcolorboxasume que el valor del primer argumento opcional del docKeyentorno (también el valor de la clave /tcb/doc keypath) es completamente expandible y lo usa en la impresión, el nombre de la etiqueta y el nombre del índice. Dado \meta{...}que no es completamente expandible, se generan errores.

En el siguiente ejemplo, dividí el rol de doc keypathen cuatro:

  • nombre de clave impreso
  • nombre de la etiqueta, se puede configurar mediante doc keypath label
  • nombre de índice impreso, se puede configurar doc keypath index
  • nombre de índice ordenado, se puede establecer por doc keypath sort index.

Modified doc keypathestablecerá los cuatro, y una nueva clave doc formatted keypathestablece tanto el primero como el tercero.

Uso:

\begin{docKey}
    [keypath][doc formatted keypath=\meta{keypath}]
    {my key}
    {=value}
    {}
\end{docKey}

See \refKey{/keypath/my key}.

Ejemplo completo:

\documentclass{article}
\usepackage{tcolorbox}
\tcbuselibrary{documentation}
\makeindex

\makeatletter
\newif\iftcb@doc@formatted@keypath

\tcbset{
  doc keypath/.style={%
    doc@keypath={#1},
    doc keypath label={#1},
    doc keypath index={#1},doc keypath sort index={#1},
  },
  doc@keypath/.store in=\kvtcb@doc@keypath,
  doc formatted keypath/.code=%
    \tcb@doc@formatted@keypathtrue
    \pgfkeysalso{doc@keypath=#1,doc keypath index=#1},
%  doc keypath name/.store in=\kvtcb@doc@keypath,
  doc keypath label/.store in=\kvtcb@doc@keypath@label,
  doc keypath index/.store in=\kvtcb@doc@keypath@index,
  doc keypath sort index/.store in=\kvtcb@doc@keypath@sortindex,
}

\ExplSyntaxOn
\cs_set_nopar:Npn \__tcobox_print_key:
  {
    \textcolor{\kvtcb@col@key}{\tcb@doc@bfseries\ttfamily
    \tl_if_empty:NF \kvtcb@doc@keypath
      {
        \iftcb@doc@formatted@keypath
          /\kvtcb@doc@keypath/
        \else
          /\__tcobox_sanitize_tl:V\kvtcb@doc@keypath/
        \fi
      }
    \__tcobox_sanitize_tl:V\kvtcb@doc@name}
  }

\cs_set_nopar:Npn \__tcobox_index_key:
  {
    \iftcb@doc@toindex
      \kvtcb@index@command{\kvtcb@doc@sortindex\idx@actual\tcbIndexPrintKeyCA{\kvtcb@doc@index}}
      \tl_if_empty:NTF \kvtcb@doc@keypath@index
        {
          \kvtcb@index@command{\kvtcb@text@keys\idx@level\kvtcb@doc@sortindex\idx@actual\tcbIndexPrintKeyC{\kvtcb@doc@index}}
        }
        {
          \kvtcb@index@command{\kvtcb@text@keys\idx@level\kvtcb@doc@keypath@sortindex\idx@actual\tcbIndexPrintKeyC{/\kvtcb@doc@keypath@index/}
            \idx@level\kvtcb@doc@sortindex\idx@actual\tcbIndexPrintKeyC{\kvtcb@doc@index}}
        }
    \fi
  }

\cs_set:Npn \__tcobox_doc_head_key:
  {
    \__tcobox_print_key:
    \__tcobox_index_key:
    \tl_if_empty:NTF \kvtcb@doc@keypath@label
      {
        \seq_if_in:NVF \g__tcobox_label_seq \kvtcb@doc@label
          {
            \protected@edef\@currentlabel{\kvtcb@doc@name}
            \label{key:\kvtcb@doc@label}
            \seq_gput_left:NV \g__tcobox_label_seq \kvtcb@doc@label
          }
      }
      {
        \tl_set:Nx \l_tmpa_tl {/\kvtcb@doc@keypath@label/\kvtcb@doc@label}
        \seq_if_in:NVF \g__tcobox_label_seq \l_tmpa_tl
          {
            \protected@edef\@currentlabel{/\kvtcb@doc@keypath/\kvtcb@doc@name}
            \label{key:/\kvtcb@doc@keypath@label/\kvtcb@doc@label}
            \seq_gput_left:NV \g__tcobox_label_seq \l_tmpa_tl
          }
      }
    {\ttfamily\kvtcb@doc@parameter}
    \tcb@doc@do@description
  }
\ExplSyntaxOff
\makeatother


\begin{document}

\begin{docKey}
    [keypath][doc formatted keypath=\meta{keypath}]
    {my key}
    {=value}
    {}
    The \texttt{keypath} part of the key path is dynamic. Using \meta{keypath} breaks.

    Putting both in the mandatory argument as \verb|{\meta{keypath}/my key}| also breaks.
    
    What is the best alternative?
\end{docKey}

See \refKey{/keypath/my key}.

\printindex

\end{document}

4 meide Sep 27 2020 at 19:30

¡Gracias por las respuestas detalladas, @Marijn y @mushimushiZ! Los estoy estudiando en busca de ideas y técnicas.

En cuanto a este problema específico, resulta que es posible hacerlo con las opciones proporcionadas por el propio tcolorbox, a través de la doc labelclave, si las macros se mantienen en la clave misma (y no en el argumento de ruta opcional):

\documentclass{article}

\usepackage{tcolorbox}
\tcbuselibrary{documentation}

\makeindex

\begin{document}

\begin{docKey}
    [mypackage]
    [doc label=keypath/mykey]
    {\meta{keypath}/my key}
    {=value}
    {}
    The \texttt{keypath} part of the key path is dynamic and corresponds to ...
\end{docKey}

Can be referenced: \refKey{/mypackage/keypath/mykey}

\printindex

\end{document}

3 Marijn Sep 27 2020 at 11:54

La cuestión es que tanto el opcional y el argumento obligatorio se utilizan para crear una etiqueta para referenciar con \refKey, es decir, \refKey{/mypackage/keypath/my key}. En el valor de una etiqueta, los comandos como \metano están permitidos.

Puede modificar docKeyligeramente la definición de para eludir el problema, definiendo la etiqueta como solo el nombre sin el prefijo opcional. Una forma de hacerlo es copiar la definición de la tcolorboxfuente y utilizarla \RenewDocumentEnvironmentpara realizar los cambios.

MWE:

\documentclass{article}

\usepackage{tcolorbox}
\tcbuselibrary{documentation}
\makeatletter
\RenewDocumentEnvironment{docKey}{ O{} +O{} m m +m }{\tcbset{#2,doc description={#5}}%
  \begin{tcb@manual@entry}%
  \begin{tcb@doc@head}{doc@head@key}%
  \ifblank{#1}{%
    \tcb@Print@Key{#3}\tcb@index@Key{#3}\protected@edef\@currentlabel{#3}\label{key:#3}{\ttfamily #4}%
  }{%
    \tcb@Print@Key{/#1/#3}%
    % CHANGE OF LABEL IN FOLLOWING LINE %
    \tcb@index@KeyPath{#1}{#3}\protected@edef\@currentlabel{/#1/#3}\label{key:#3}{\ttfamily #4}%
  }%
  \tcb@doc@do@description%
  \end{tcb@doc@head}\nobreak\tcbset{before upper=}\kvtcb@doc@body@key@before\ignorespaces}%
  {\ifvmode\else\unskip\fi\kvtcb@doc@body@key@after\end{tcb@manual@entry}}
\makeatother


\begin{document}
\begin{docKey}
    [mypackage/\meta{keypath}]
    {my key}
    {=value}
    {}
    The \texttt{keypath} part of the key path is dynamic. Using \meta{keypath} breaks.

    Putting both in the mandatory argument as \verb|{\meta{keypath}/my key}| also breaks.
    
    What is the best alternative?
\end{docKey}

See \refKey{my key}.

\end{document}

Resultado:

Observación: tal vez \textit{<keypath>}sea ​​mejor que \meta{keypath}: