Aktualisieren

Aktualisieren

Bearbeitung 2:Unten habe ich die Frage aktualisiert, nachdem ich die Antwort von hier integriert habe:Der neue Befehl für den Index fügt bei Verwendung von {} unerwünschte Leerzeichen ein.

Ich habe eine Funktion erstellt, um einen Befehl fett anzuzeigen und optional den Manpage-Abschnitt in Klammern anzugeben.

\usepackage{xparse}
\newcommand*{\man}[2][]{%
   \textbf{#2}\IfNoValueF{#1}{(#1)}%
}

Nun möchte ich auch in der Lage sein, einen Indexeintrag für diese Befehle zu erstellen. Also habe ich einen Wrapper-Befehl erstellt:

\newcommand*{\mani}[2][]{%
   \man[#1]{#2}%
   \index{#2@\man[#1]{#2}}%
}

Manchmal möchte ich jedoch einen Indexeintrag mit derselben Formatierung erstellen, den Befehl aber nicht im Fließtext drucken. Hier ist ein 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}

Die Datei output.idxenthält zwei Zeilen, von denen die zweite ein zusätzliches Leerzeichen enthält. Die Frage ist daher, warum es ein zusätzliches Leerzeichen gibt und wie ich es beheben kann, sodass es kein zusätzliches Leerzeichen gibt?

\indexentry{ssh-keygen@\man[1]{ssh-keygen}}{1}
\indexentry{ssh-keygen@\man [1]{ssh-keygen}}{1}

Bearbeitung 1:Ich habe einen Screenshot des Ergebnisses dieses zusätzlichen Platzes hinzugefügt: Es werden zwei identische Indexeinträge gedruckt.

Doppelter Indexeintrag

Aktualisieren

Ich habe meinen Code gemäß der bereitgestellten Lösung aktualisiert, erhalte jetzt jedoch eine Fehlermeldung, die ich nicht verstehe.

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

OverLeaf erklärt:

Der Compiler hat Probleme, einen von Ihnen verwendeten Befehl zu verstehen. Überprüfen Sie, ob der Befehl richtig geschrieben ist. Wenn der Befehl Teil eines Pakets ist, stellen Sie sicher, dass Sie das Paket mit \usepackage{...} in Ihre Präambel aufgenommen haben.

Die Protokolldatei enthält folgende Informationen:

! 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.)

Antwort1

Der Befehl \indexsoll sein Argument erhalten, indem er Dinge aus der .tex-input-Datei unter \@sanitize-category-code-régime liest und tokenisiert. ( \@sanitize-category-code-régime bedeutet: Leerzeichen, \, $, , &, #, ^, und habe den Kategoriecode 12 (andere). _) Dafür gibt es mehrere Gründe – z. B.%~

  • Vermeidung einer unerwünschten Erweiterung erweiterbarer Token.
  • Vermeidung des Anhängens eines Leerzeichens beim nicht erweiterten Schreiben eines Steuerwort-Tokens in eine externe Datei.

Aber mit Ihrem Befehl erhält \manider Befehl sein Argument von . Wenn das Argument von gesammelt/zusammengestellt wird , werden die Token, die dieses Argument bilden, nicht unter dem -Kategoriecode-Regime tokenisiert, sondern unter dem normalen Kategoriecode-Regime.\index\mani\mani\index\@sanitize

Unter anderem bedeutet die Tokenisierung unter dem normalen Kategorie-Code-Regime, dass Ausdrücke wie \manals Kontrollwort-Token tokenisiert werden, nicht als Zeichenfolgen \, m, a, n. Wenn Kontrollwort-Token unerweitert in eine Textdatei geschrieben werden, z. B. in eine .idxDatei, die zum Prozess der Indexerstellung gehört, wird ein Leerzeichen angehängt. D. h., die Zeichenfolge \, m, a, n, ⟨space character⟩wird geschrieben.

Innerhalb der Definition von \manikönnen Sie \stringauf den Befehl anwenden \man, um ihn in eine Folge von Zeichen-Tokens umzuwandeln. (Dabei wird vorausgesetzt, dass nur ein Eingabezeichen den Kategoriecode 0 (Escape) hat und der Wert des Integer-Parameters \escapecharder Nummer des Codepunkts dieses Zeichens im internen Zeichenkodierungsschema der TeX-Engine entspricht. Normalerweise \ist das Backslash-Zeichen das einzige Zeichen mit dem Kategoriecode 0 (Escape) und \escapecharhat normalerweise den Wert 92, was der Nummer des Codepunkts des Backslash-Zeichens im internen Zeichenkodierungsschema der TeX-Engine entspricht.)

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

Mit dem obigen Beispiel sieht die resultierende .idx-Datei folgendermaßen aus:

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

Bei diesem Ansatz ist das einzige, was innerhalb des Arguments von \index, das über das Makro bereitgestellt wird \mani, „stringifiziert“ wird, die Phrase \man.

Dinge, die aus \manidem ersten oder zweiten Argument von kommen, werden nicht in Zeichenfolgen umgewandelt. Falls die über diese Argumente bereitgestellten Token-Sets auch Kontrollwort-Token enthalten, können auch hier unerwünschte Leerzeichen auftreten.

Ich kann eine Routine anbieten \StringifyNAct, die \stringauf jedes Token innerhalb seines Arguments angewendet wird:

\StringifyNAct{⟨action⟩}{⟨token 1⟩⟨token 2⟩...⟨token n⟩}

ergibt:

⟨action⟩{⟨stringification of token 1⟩}%
⟨action⟩{⟨stringification of token 2⟩}%
...
⟨action⟩{⟨stringification of token n⟩}%

wobei mit "Stringifizierung des Tokens" das Ergebnis der Anwendung \stringauf das betreffende Token gemeint ist.
Durch die \romannumeral-Expansion wird das Ergebnis durch das Auslösen zweier Expansionsschritte (z.B. über zwei \expandafter-Chains) geliefert.

Ich schlage vor, dass der Befehl \maniseine Argumente im normalen Kategoriecode-Regime liest und tokenisiert, aber mit dem Leerzeichen (und wahrscheinlich auch dem horizontalen Tabulatorzeichen, das wie ^^Imit der -Notation von TeX adressierbar ist ^^) mit dem Kategoriecode 12 (andere), und dass er dies dann \StringifyNActauf die Argumente anwendet und das Ergebnis anschließend an den \index-Befehl und – verschachtelt darin \scantokens– an den \man-Befehl übergibt:

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

Mit dem obigen Beispiel sieht die resultierende .idx-Datei folgendermaßen aus:

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

Antwort2

Der Name des \writefür die .idx-Datei mit Memoiren verwendeten Handles unterscheidet sich vom Namen des \writemit dem LaTeX 2ε-Makro verwendeten Handles \@wrindex.

Daher müssen Sie den Namen des „Kernel- \writeHandles“ für den Index dem „Memoir- \writeHandle“ für den Index zuordnen:

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

Die .idx-Datei sieht folgendermaßen aus:

\indexentry{ssh-keygen@\man[1]{ssh-keygen}}{1}
\indexentry{ssh-keygen@\man[1]{ssh-keygen}}{1}

Beachten Sie, dass – anders als bei dem in meiner anderen Antwort vorgestellten Ansatz der Stringifizierung nach der Tokenisierung – \@sanitizeder Ausgleich der geschweiften Klammern nicht behandelt wird, wenn die Argumente das control-symbol-token und/oder das control-symbol-token \manienthalten sollen .\{\}

verwandte Informationen