
Edición 2:En la parte inferior he actualizado la pregunta después de incorporar la respuesta desde aquí:El nuevo comando para índice inserta espacios no deseados cuando se usa {}
Creé una función para mostrar un comando en negrita y, opcionalmente, colocar la sección de la página de manual entre paréntesis.
\usepackage{xparse}
\newcommand*{\man}[2][]{%
\textbf{#2}\IfNoValueF{#1}{(#1)}%
}
Ahora también quiero poder crear una entrada de índice para estos comandos. Entonces creé un comando contenedor:
\newcommand*{\mani}[2][]{%
\man[#1]{#2}%
\index{#2@\man[#1]{#2}}%
}
Sin embargo, a veces quiero crear una entrada de índice usando el mismo formato, pero no imprimir el comando en el texto en ejecución. Aquí hay un MWE:
\documentclass{memoir}
\usepackage{xparse}
\newcommand*{\man}[2][]{%
\textbf{#2}\IfNoValueF{#1}{(#1)}%
}
\newcommand*{\mani}[2][]{%
\man[#1]{#2}%
\index{#2@\man[#1]{#2}}%
}
\makeindex
\begin{document}
Only an index entry: \index{ssh-keygen@\man[1]{ssh-keygen}}
Hello world
Command and index entry: \mani[1]{ssh-keygen}
\printindex
\end{document}
El archivo output.idx
contiene dos líneas y la segunda contiene un espacio adicional. La pregunta entonces es, ¿por qué hay espacio adicional y cómo puedo solucionarlo para que no haya espacio adicional?
\indexentry{ssh-keygen@\man[1]{ssh-keygen}}{1}
\indexentry{ssh-keygen@\man [1]{ssh-keygen}}{1}
Edición 1:Agregué una captura de pantalla del resultado de este espacio adicional: se imprimen dos entradas de índice idénticas.
Actualizar
Actualicé mi código según la solución proporcionada, pero ahora aparece un mensaje de error que no entiendo.
\documentclass{memoir}
\usepackage{xparse}
\makeindex
\NewDocumentCommand\man{om}{%
\textbf{#2}\IfNoValueF{#1}{(#1)}%
}
\makeatletter
\newcommand*{\mani}{%
\@bsphack
\begingroup
\@sanitize
\@mani
}
\newcommand*{\@mani}[2][]{%
\man[#1]{#2}%
\@wrindex{#2@\string\man[#1]{#2}}%
}
\makeatletter
\begin{document}
Two separate commands: \man[1]{ssh-keygen}\index{ssh-keygen@\man[1]{ssh-keygen}}
Hello world
One command: \mani[1]{ssh-keygen}
\printindex
\end{document}
Estados OverLeaf:
El compilador tiene problemas para comprender un comando que ha utilizado. Compruebe que el comando esté escrito correctamente. Si el comando es parte de un paquete, asegúrese de haber incluido el paquete en su preámbulo usando \usepackage{...}.
El archivo de registro informa:
! Missing number, treated as zero.
<to be read again>
{
l.25 One command: \mani[1]{ssh-keygen}
A number should have been here; I inserted `0'.
(If you can't figure out why I needed to see a number,
look up `weird error' in the index to The TeXbook.)
Respuesta1
Se espera que el comando \index
obtenga su argumento leyendo y tokenizando elementos del archivo de entrada .tex en \@sanitize
-category-code-régime. ( \@sanitize
-régimen de código de categoría significa: carácter de espacio, \
, $
, &
, #
, ^
, y tiene el código de categoría 12 (otro).) Esto se debe a varias razones, por ejemplo _
,%
~
- evitando la expansión no deseada de tokens expandibles.
- evitando agregar un carácter de espacio cuando no se expande: escribir un token de palabra de control en un archivo externo.
Pero con su comando, \mani
el comando \index
obtiene su argumento de \mani
. Cuando \mani
reúne/compone \index
el argumento, los tokens que forman ese argumento no se tokenizan bajo el \@sanitize
régimen de código de categoría, sino que se tokenizan bajo el régimen de código de categoría normal.
Entre otras cosas, la tokenización bajo el régimen de código de categoría normal implica que frases como \man
se tokenizan como tokens de palabras de control, no como secuencias de caracteres \
, m
, a
, n
. Cuando los tokens de palabras de control se escriben sin expandir en un archivo de texto, por ejemplo, algún .idx
archivo que pertenece al proceso de creación del índice, se agregará un carácter de espacio. Es decir, se escribirá la secuencia de caracteres \
, m
, a
, n
.⟨space character⟩
Dentro de la definición de, \mani
puede aplicar \string
el comando \man
para convertirlo en una secuencia de tokens de caracteres. (Por la presente, se confía en que solo un carácter de entrada tenga el código de categoría 0 (escape) y el valor del parámetro entero \escapechar
sea igual al número del punto de código de ese carácter en el esquema de codificación de caracteres interno del motor TeX. Por lo general, el carácter de barra invertida \
es el único carácter del código de categoría 0 (escape) y generalmente \escapechar
tiene el valor 92, que es el número del punto de código del carácter de barra invertida en el esquema de codificación de caracteres interno del motor TeX).
\documentclass{memoir}
\usepackage{xparse}
\NewDocumentCommand{\man}{om}{%
\textbf{#2}\IfNoValueF{#1}{(#1)}%
}
\NewDocumentCommand{\mani}{om}{%
\IfNoValueTF{#1}{%
\man{#2}%
\index{#2@\string\man{#2}}%
}{%
\man[#1]{#2}%
\index{#2@\string\man[#1]{#2}}%
}%
}%
\makeindex
\begin{document}
Only an index entry: \index{ssh-keygen@\man[1]{ssh-keygen}}
Hello world
Command and index entry: \mani[1]{ssh-keygen}
Only an index entry: \index{ssh-keygen-no-optional-argument@\man{ssh-keygen-no-optional-argument}}
Hello world
Command and index entry: \mani{ssh-keygen-no-optional-argument}
\printindex
\end{document}
Con el ejemplo anterior, el archivo .idx resultante se ve así:
\indexentry{ssh-keygen@\man[1]{ssh-keygen}}{1}
\indexentry{ssh-keygen@\man[1]{ssh-keygen}}{1}
\indexentry{ssh-keygen-no-optional-argument@\man{ssh-keygen-no-optional-argument}}{1}
\indexentry{ssh-keygen-no-optional-argument@\man{ssh-keygen-no-optional-argument}}{1}
Con este enfoque, lo único "encadenado" dentro del argumento de \index
, que se proporciona a través de la macro \mani
, es la frase \man
.
Las cosas que provienen del \mani
primer o segundo argumento de no están encadenadas. En caso de que los conjuntos de tokens proporcionados a través de estos argumentos también contengan tokens de palabras de control, es posible que aquí también obtenga espacios no deseados.
Puedo ofrecer una rutina \StringifyNAct
que se aplica \string
a cada token dentro de su argumento:
\StringifyNAct{⟨action⟩}{⟨token 1⟩⟨token 2⟩...⟨token n⟩}
rendimientos:
⟨action⟩{⟨stringification of token 1⟩}%
⟨action⟩{⟨stringification of token 2⟩}%
...
⟨action⟩{⟨stringification of token n⟩}%
por lo que "stringificación del token" significa el resultado de aplicarlo \string
al token en cuestión.
Debido a \romannumeral
la expansión, el resultado se obtiene activando dos pasos de expansión (por ejemplo, a través de dos \expandafter
cadenas).
Sugiero que el comando \mani
lea y tokenice sus argumentos bajo el régimen de código de categoría normal, pero con el carácter de espacio (y probablemente también el carácter de tabulación horizontal, direccionable como ^^I
con la notación de TeX ^^
) siendo del código de categoría 12 (otro ), luego aplicar \StringifyNAct
a los argumentos, luego pasar el resultado de los mismos al \index
-comando y, anidado en \scantokens
, al \man
-comando:
\documentclass{memoir}
\makeatletter
%%========================Code for \StringifyNAct==============================
%%
%% Copyright (C) 2019, 2020 by Ulrich Diez ([email protected])
%%
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public Licence (LPPL), either
%% version 1.3 of this license or (at your option) any later
%% version. (The latest version of this license is in:
%% http://www.latex-project.org/lppl.txt
%% and version 1.3 or later is part of all distributions of LaTeX
%% version 1999/12/01 or later.)
%% The author of this work is Ulrich Diez.
%% This work has the LPPL maintenance status 'not maintained'.
%% Usage of any/every component of this work is at your own risk.
%% There is no warranty - neither for probably included
%% documentation nor for any other part/component of this work.
%% If something breaks, you usually may keep the pieces.
%%
%%=============================================================================
%% Paraphernalia:
%% \UD@firstoftwo, \UD@secondoftwo,
%% \UD@PassFirstToSecond, \UD@Exchange, \UD@removespace
%% \UD@CheckWhetherNull, \UD@CheckWhetherBrace,
%% \UD@CheckWhetherLeadingSpace, \UD@ExtractFirstArg
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@Exchange[2]{#2#1}%
\newcommand\UD@removespace{}\UD@firstoftwo{\def\UD@removespace}{} {}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
\UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
\UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%.............................................................................
%% \UD@CheckWhetherBrace{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked has leading
%% catcode-1-token>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked has no leading
%% catcode-1-token>}%
\newcommand\UD@CheckWhetherBrace[1]{%
\romannumeral0\expandafter\UD@secondoftwo\expandafter{\expandafter{%
\string#1.}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
\UD@firstoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether brace-balanced argument starts with a space-token
%%.............................................................................
%% \UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case <argument
%% which is to be checked>'s 1st token is a
%% space-token>}%
%% {<Tokens to be delivered in case <argument
%% which is to be checked>'s 1st token is not
%% a space-token>}%
\newcommand\UD@CheckWhetherLeadingSpace[1]{%
\romannumeral0\UD@CheckWhetherNull{#1}%
{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
{\expandafter\UD@secondoftwo\string{\UD@CheckWhetherLeadingSpaceB.#1 }{}}%
}%
\newcommand\UD@CheckWhetherLeadingSpaceB{}%
\long\def\UD@CheckWhetherLeadingSpaceB#1 {%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@secondoftwo#1{}}%
{\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
{\UD@Exchange{ }{\expandafter\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter}\expandafter\expandafter
\expandafter}\expandafter\UD@secondoftwo\expandafter{\string}%
}%
%%-----------------------------------------------------------------------------
%% Extract first inner undelimited argument:
%%
%% \UD@ExtractFirstArg{ABCDE} yields {A}
%%
%% \UD@ExtractFirstArg{{AB}CDE} yields {AB}
%%.............................................................................
\newcommand\UD@RemoveTillUD@SelDOm{}%
\long\def\UD@RemoveTillUD@SelDOm#1#2UD@SelDOm{{#1}}%
\newcommand\UD@ExtractFirstArg[1]{%
\romannumeral0%
\UD@ExtractFirstArgLoop{#1UD@SelDOm}%
}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
{ #1}%
{\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}%
}%
%%-----------------------------------------------------------------------------
%% In case an argument's first token is an opening brace, stringify that and
%% add another opening brace before that and remove everything behind the
%% matching closing brace:
%% \UD@StringifyOpeningBrace{{Foo}bar} yields {{Foo} whereby the second
%% opening brace is stringified:
%%.............................................................................
\newcommand\UD@StringifyOpeningBrace[1]{%
\romannumeral0%
\expandafter\UD@ExtractFirstArgLoop\expandafter{%
\romannumeral0\UD@Exchange{ }{\expandafter\expandafter\expandafter}%
\expandafter\expandafter
\expandafter {%
\expandafter\UD@firstoftwo
\expandafter{%
\expandafter}%
\romannumeral0\UD@Exchange{ }{\expandafter\expandafter\expandafter}%
\expandafter\string
\expandafter}%
\string#1%
UD@SelDOm}%
}%
%%-----------------------------------------------------------------------------
%% In case an argument's first token is an opening brace, remove everything till
%% finding the corresponding closing brace. Then stringify that closing brace:
%% \UD@StringifyClosingBrace{{Foo}bar} yields: {}bar} whereby the first closing
%% brace is stringified:
%%.............................................................................
\newcommand\UD@StringifyClosingBrace[1]{%
\romannumeral0\expandafter\expandafter\expandafter
\UD@StringifyClosingBraceloop
\UD@ExtractFirstArg{#1}{#1}%
}%
\newcommand\UD@CheckWhetherStringifiedOpenBraceIsSpace[1]{%
%% This can happen when character 32 (space) has catcode 1...
\expandafter\UD@CheckWhetherLeadingSpace\expandafter{%
\romannumeral0\UD@Exchange{ }{\expandafter\expandafter\expandafter}%
\expandafter\UD@secondoftwo
\expandafter{%
\expandafter}%
\expandafter{%
\romannumeral0\UD@Exchange{ }{\expandafter\expandafter\expandafter}%
\expandafter\UD@firstoftwo
\expandafter{%
\expandafter}%
\romannumeral0\UD@Exchange{ }{\expandafter\expandafter\expandafter}%
\expandafter\string
\expandafter}%
\string#1%
}%
}%
\newcommand\UD@TerminateStringifyClosingBraceloop[2]{%
\UD@Exchange{ }{\expandafter\expandafter\expandafter}%
\expandafter\expandafter
\expandafter{%
\expandafter\string
\romannumeral0\UD@Exchange{ }{\expandafter\expandafter\expandafter}%
\expandafter#1%
\string#2%
}%
}%
\newcommand\UD@StringifyClosingBraceloopRemoveElement[4]{%
\expandafter\UD@PassFirstToSecond\expandafter{\expandafter
{\romannumeral0\expandafter\UD@secondoftwo\string}{}%
\UD@CheckWhetherStringifiedOpenBraceIsSpace{#4}{%
\UD@Exchange{\UD@removespace}%
}{%
\UD@Exchange{\UD@firstoftwo\expandafter{\expandafter}}%
}{%
\UD@Exchange{ }{\expandafter\expandafter\expandafter}%
\expandafter#1%
\romannumeral0\UD@Exchange{ }{\expandafter\expandafter\expandafter}%
\expandafter
}%
\string#4%
}{\expandafter\UD@StringifyClosingBraceloop\expandafter{#2#3}}%
}%
\newcommand\UD@StringifyClosingBraceloop[2]{%
\UD@CheckWhetherNull{#1}{%
\UD@CheckWhetherStringifiedOpenBraceIsSpace{#2}{%
\UD@TerminateStringifyClosingBraceloop{\UD@removespace}%
}{%
\UD@TerminateStringifyClosingBraceloop{\UD@firstoftwo\expandafter{\expandafter}}%
}%
{#2}%
}{%
\UD@CheckWhetherLeadingSpace{#1}{%
\UD@StringifyClosingBraceloopRemoveElement
{\UD@removespace}{\UD@removespace}%
}{%
\UD@StringifyClosingBraceloopRemoveElement
{\UD@firstoftwo\expandafter{\expandafter}}{\UD@firstoftwo{}}%
}%
{#1}{#2}%
}%
}%
%%-----------------------------------------------------------------------------
%% Apply <action> to the stringification of each token of the argument:
%%
%% \StringifyNAct{<action>}{<token 1><token 2>...<token n>}
%%
%% yields: <action>{<stringification of token 1>}%
%% <action>{<stringification of token 2>}%
%% ...
%% <action>{<stringification of token n>}%
%%
%% whereby "stringification of token" means the result of applying \string
%% to the token in question.
%% Due to \romannumeral-expansion the result is delivered after two
%% \expandafter-chains.
%% If you leave <action> empty, you can apply a loop on the list formed by
%% {<stringification of token 1>}%
%% {<stringification of token 2>}%
%% ...
%% {<stringification of token n>}%
%%
%% Below a macro \ConcatenateStringifiedtokens is implemented which loops
%% on that list for concatenating.
%%.............................................................................
\newcommand\StringifyNAct{%
\romannumeral0\StringifyNActLoop{}%
}%
%%.............................................................................
%% \StringifyNActLoop{{<stringification of token 1>}...{<stringification of token k-1>}}%
%% {<action>}%
%% {<token k>...<token n>}
%%.............................................................................
\newcommand\StringifyNActLoop[3]{%
\UD@CheckWhetherNull{#3}{%
\UD@firstoftwo{ }{}#1%
}{%
\UD@CheckWhetherBrace{#3}{%
\expandafter\expandafter\expandafter\UD@Exchange
\expandafter\expandafter\expandafter{%
\UD@StringifyClosingBrace{#3}%
}{%
\expandafter\StringifyNActLoop\expandafter{%
\romannumeral0%
\expandafter\expandafter\expandafter\UD@Exchange
\expandafter\expandafter\expandafter{\UD@StringifyOpeningBrace{#3}}{\StringifyNActLoop{#1}{#2}}%
}{#2}%
}%
}{%
\UD@CheckWhetherLeadingSpace{#3}{%
\expandafter\UD@PassFirstToSecond\expandafter{\UD@removespace#3}{%
\StringifyNActLoop{#1#2{ }}{#2}%
}%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}#3}{%
\expandafter\StringifyNActLoop\expandafter{%
\romannumeral0%
\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\UD@PassFirstToSecond
\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter{%
\expandafter\expandafter\expandafter\string
\expandafter\UD@Exchange
\romannumeral0\UD@ExtractFirstArgLoop{#3UD@SelDOm}{}%
}{ #1#2}%
}%
{#2}%
}%
}%
}%
}%
}%
%% The promised loop for concatenating stringified tokens - apply as:
%%
%% \romannumeral0%
%% \expandafter\expandafter\expandafter
%% \ConcatenateStringifiedtokens
%% \StringifyNAct{}{<tokens to stringify>}\relax
%%
\newcommand*\ConcatenateStringifiedtokens{%
\ConcatenateStringifiedtokensloop{ }%
}%
\newcommand\ConcatenateStringifiedtokensloop[2]{%
\ifx\relax#2\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{#1}{%
\ConcatenateStringifiedtokensloop{#1#2}%
}%
}%
%%=================== End of code for \StringifyNAct ==========================
\makeatother
\usepackage{xparse}
\makeatletter
\NewDocumentCommand{\man}{om}{%
\UD@CheckWhetherNull{#2}{}{%
\toks@{#2}%
\textbf{\the\toks@}%
}%
\IfNoValueF{#1}{(#1)}%
}%
\NewDocumentCommand{\mani}{}{%
\begingroup
\catcode`\ =12\relax
\catcode`\^^I=12\relax
\maniinner
}%
\NewDocumentCommand{\maniinner}{om}{%
\endgroup
\IfNoValueTF{#1}{%
\expandafter\maniinnerinner\expandafter{%
\romannumeral0%
\expandafter\expandafter\expandafter
\ConcatenateStringifiedtokens
\StringifyNAct{}{#2}\relax
}%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{%
\romannumeral0%
\expandafter\expandafter\expandafter
\ConcatenateStringifiedtokens
\StringifyNAct{}{#2}\relax
}{%
\expandafter\maniinnerinner\expandafter[\expandafter{%
\romannumeral0%
\expandafter\expandafter\expandafter
\ConcatenateStringifiedtokens
\StringifyNAct{}{#1}\relax
}]%
}%
}%
}%
\makeatother
\begingroup
\newcommand\maniinnerinner[1]{%
\endgroup
\NewDocumentCommand{\maniinnerinner}{om}{%
\IfNoValueTF{##1}{%
\scantokens{\man{##2}#1}%
\index{##2@\string\man{##2}}%
}{%
\scantokens{\man[##1]{##2}#1}%
\index{##2@\string\man[##1]{##2}}%
}%
}%
}%
\catcode`\%=12\relax
\maniinnerinner{%}%
\makeindex
\begin{document}
Only an index entry: \index{ssh-keygen@\man[1]{ssh-keygen}}
Hello world
Command and index entry: \mani[1]{ssh-keygen}
Only an index entry: \index{ssh-keygen-no-optional-argument@\man{ssh-keygen-no-optional-argument}}
Hello world
Command and index entry: \mani{ssh-keygen-no-optional-argument}
\newcommand\ke{ke}%
\newcommand\one{1}%
Only an index entry: \index{ssh-\ke y\string#gen@\man[\one]{ssh-\ke y\string#gen}}
Hello world
Command and index entry: \mani[\one]{ssh-\ke y\string#gen}
\printindex
\end{document}
Con el ejemplo anterior, el archivo .idx resultante se ve así:
\indexentry{ssh-keygen@\man[1]{ssh-keygen}}{1}
\indexentry{ssh-keygen@\man[1]{ssh-keygen}}{1}
\indexentry{ssh-keygen-no-optional-argument@\man{ssh-keygen-no-optional-argument}}{1}
\indexentry{ssh-keygen-no-optional-argument@\man{ssh-keygen-no-optional-argument}}{1}
\indexentry{ssh-\ke y\string#gen@\man[\one]{ssh-\ke y\string#gen}}{1}
\indexentry{ssh-\ke y\string#gen@\man[\one]{ssh-\ke y\string#gen}}{1}
Respuesta2
El nombre del \write
identificador utilizado para el archivo .idx con memorias difiere del nombre del \write
identificador utilizado con la macro LaTeX 2ε \@wrindex
.
Por lo tanto, es necesario asignar el nombre del "kernel- \write
-handle" para el índice al "memoir- \write
-handle" para el índice:
\documentclass{memoir}
\usepackage{xparse}
\makeindex
\NewDocumentCommand\man{om}{%
\textbf{#2}\IfNoValueF{#1}{(#1)}%
}
\makeatletter
\newcommand*{\mani}{%
\@bsphack
\begingroup
\@sanitize
\@mani
}
\NewDocumentCommand{\@mani}{om}{%
\@ifundefined{@indexfile}{%
\expandafter\let\expandafter\@indexfile\csname\jobname @idxfile\endcsname
}{}%
\IfNoValueTF{#1}{%
\man{#2}%
\@wrindex{#2@\string\man{#2}}%
}{%
\man[#1]{#2}%
\@wrindex{#2@\string\man[#1]{#2}}%
}%
}
\makeatletter
\begin{document}
Two separate commands: \man[1]{ssh-keygen}\index{ssh-keygen@\man[1]{ssh-keygen}}
Hello world
One command: \mani[1]{ssh-keygen}
\printindex
\end{document}
El archivo .idx se ve así:
\indexentry{ssh-keygen@\man[1]{ssh-keygen}}{1}
\indexentry{ssh-keygen@\man[1]{ssh-keygen}}{1}
Tenga en cuenta que, a diferencia del enfoque de encadenamiento después de la tokenización presentado en mi otra respuesta, \@sanitize
no maneja el equilibrio de llaves en caso de que los argumentos de \mani
contengan el token de símbolo de control \{
y/o el token de símbolo de control \}
.