tcolorbox documentation: documenting dynamic keypaths

tcolorbox assumes the value of first optional argument of docKey environment (also the value of key /tcb/doc keypath) is fully expandable and uses it in printing, label name, and index name. Since \meta{...} is not fully expandable, errors are raised.

In the following example, I split the role of doc keypath into four:

  • printed key name
  • label name, can be set by doc keypath label
  • printed index name, can be set by doc keypath index
  • sorted index name, can be set by doc keypath sort index.

Modified doc keypath will set all four of them, and a new key doc formatted keypath sets both the first and the third.

Usage:

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

See \refKey{/keypath/my key}.

Full example:

\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}

enter image description here enter image description here


Thanks for the detailed answers, @Marijn & @mushimushiZ! I am studying them for ideas and techniques.

As for this specific problem, it turns out that it is possible to do with the options provided by tcolorbox itself, via the doc label key, if the macros are kept to the key itself (and not in the optional path argument):

\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}

document

index


The issue is that both the optional and the mandatory argument are used to create a label for referencing with \refKey, i.e., \refKey{/mypackage/keypath/my key}. In the value of a label commands such as \meta are not allowed.

You can modify the definition of docKey slightly to circumvent the issue, by defining the label to be just the name without the optional prefix. One way of doing that is to copy the definition from the tcolorbox source and use \RenewDocumentEnvironment to make the changes.

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}

Result:

enter image description here

Remark: maybe \textit{<keypath>} is nicer than \meta{keypath}:

enter image description here