\NewDocumentCommand で定義されたコマンドによって生成されるエラー メッセージを制御する

\NewDocumentCommand で定義されたコマンドによって生成されるエラー メッセージを制御する

この\NewDocumentCommandコマンドは、より適切なエラー メッセージを作成するために巧妙なトリックを使用します。 の引数が\mycommand間違っている場合、結果として生じるエラーが「 の使用をスキャン中にファイルが終了しました\__xparse_grab_D:w」のような内容になるのは望ましくないため、xparse が別の引数を取得するときは常に、引数の取得を行う を定義し\mycommand<space>、それを使用して作業を行うため、何か問題が発生した場合、エラーは代わりに「\mycommand<space>が完了する前に段落が終了しました」のような内容になります。

\NewDocumentCommandAs私は、定義するマクロの名前と、エラー メッセージで使用されるコマンドの名前という 2 つの引数を取るようなコマンドを希望しています。

これには2つのユースケースがあります。1つは、特定の環境内でのみ使用されるコマンドを定義するパッケージがある場合です。そのため、パッケージのプライベート名前空間でコマンドを定義し、\let環境の開始時にコマンドのパブリック名をプライベートバージョンに設定します。明らかに、すべてのエラーメッセージをコマンドのパブリック名に基づいて表示したいので、次のようにします。

\NewDocumentCommandAs \__my_pkg_cmd:args \cmd {<args>}{<body>}

2 番目の使用例は、オプションの引数、最初の開き括弧までのすべて、そして最初の開き括弧から始まるバランスの取れた括弧で区切られた引数を持つコマンドがある場合です。「until」引数タイプは、スキャンしているトークンを吸収するため、開き括弧を再挿入して補助を使用する必要があります。

\NewDocumentCommand \mycommand { o u( } { \mycommand_aux{#1}{#2}( }
\NewDocumentCommandAs \mycommand_aux \mycommand { m m r() } { 
    % do stuff here
}

もちろん、削除したトークンを再挿入する u (おそらく U?) のバージョンを作成することでこれを修正できますが、これは珍しい使用例かもしれません。

フォーマット上の都合上、2 つの実装を回答として提出することにします。この問題に対処した人は他にいますか? 私が見逃している、もっと良いアプローチはありますか? これを行わずに、別の方法でこれらの問題を解決すべきでしょうか? これは、xparse の将来のバージョンに追加される可能性のある機能でしょうか?

答え1

私の最初の試みは次のようなものでした:

\cs_new_protected:Npn \NewDocumentCommandAs#1#2#3#4{
    \group_begin:
    % Store the original value of #2
    \cs_set_eq:cN { tempsave_ \cs_to_str:N #2 } #2
    \cs_set_eq:cc { tempsave_ \cs_to_str:N #2 \c_space_tl code } 
                  { \cs_to_str:N #2 \c_space_tl code }
    % Use \DeclareDocumentCommand with #2 so that error messages work
    \DeclareDocumentCommand#2{#3}{\group_end: #4}
    % Define #1 to be a wrapper command that sets #2<space>code equal to #1<space>code
    \cs_new:Npx #1{
        \group_begin:
        \exp_not:N \cs_set_eq:NN
            \exp_not:c { \cs_to_str:N #2 \c_space_tl code }
            \exp_not:c { \cs_to_str:N #1 \c_space_tl code }
        \exp_not:c { \cs_to_str:N #1 \c_space_tl inner }
    }
    % Save the value of #2 set by DeclareDocumentCommand
    \cs_gset_eq:cN { \cs_to_str:N #1 \c_space_tl inner } #2
    \cs_gset_eq:cc{ \cs_to_str:N #1 \c_space_tl code } { \cs_to_str:N #2 \c_space_tl code }
    % Restore the original value of #2
    \cs_gset_eq:Nc #2 { tempsave_ \cs_to_str:N #2 }
    \cs_gset_eq:cc { \cs_to_str:N #2 \c_space_tl code } { tempsave_ \cs_to_str:N #2 \c_space_tl code }
    \group_end:
}

これは少し面倒ですが、問題なく動作します。この方法の大きな利点は、\NewDocumentCommandマクロの中身が格納されている詳細以外の実装に依存せず#1<space>code、他の補助コマンドも使用されないことです。1 つの制限は、すべての引数が "m" 型の場合は動作しないことですが、これは気になりません。この方法は、拡張可能なマクロでは動作しません。

\__xparse_declare_cmd_mixed_aux:Nnもう 1 つの可能なアプローチは、エラー コマンド ( に格納) に別の名前を使用する のパッチ バージョンを作成し\l__xparse_fn_tl、 を使用するためにその定義を一時的にインストールすることです\NewDocumentCommand。この方法の利点は、 と同様の操作を実行して\__xparse_declare_cmd_mixed_expandable:Nn、拡張可能なバージョンを機能させることができることです。また、すべての引数が必須の場合でも機能します。欠点は、 の正確な実装に依存することです\__xparse_declare_cmd_mixed_aux:Nn

% Make two copies of \__xparse_declare_cmd_aux:Nn, one to patch, one as a save
% If \l_..._environment_bool is true, it forces xparse to use argument grabbers even when
% all arguments are mandatory. So we'll set it to be true for \NewDocumentCommandAs
\cs_new_eq:NN \__my_xparse_declare_cmd_aux_as:Nnn \__xparse_declare_cmd_aux:Nnn
\cs_new_eq:NN \__my_xparse_declare_cmd_aux_save:Nnn \__xparse_declare_cmd_aux:Nnn
\patchcmd \__my_xparse_declare_cmd_aux_as:Nnn { \bool_set_false:N \l__xparse_environment_bool } { \bool_set_true:N \l__xparse_environment_bool }{}{\oops}

\cs_new_eq:NN \__my_xparse_declare_cmd_mixed_aux_as:Nn   \__xparse_declare_cmd_mixed_aux:Nn
\cs_new_eq:NN \__my_xparse_declare_cmd_mixed_aux_save:Nn \__xparse_declare_cmd_mixed_aux:Nn

% Replace \l__xparse_function_tl with my own token list that I can set independently
\tl_new:N \l__my_xparse_function_as_tl
\patchcmd \__my_xparse_declare_as_cmd_mixed_aux:Nn 
    {{ \l__xparse_function_tl \c_space_tl }} 
    {{ \l__my_xparse_function_as_tl \c_space_tl }}{}{\oops}

\cs_new:Npn \NewDocumentCommandAs #1#2#3#4 {
    % Patch in my modified version of \__xparse_declare_cmd_mixed_aux
    \cs_set_eq:NN \__xparse_declare_cmd_mixed_aux:Nn \__my_xparse_declare_cmd_mixed_aux_as:Nn
    \tl_set:Nn \l__my_xparse_function_as_tl { \cs_to_str:N #2 } % Use #2 as the error name
    \NewDocumentCommand#1{#3}{#4}
    \cs_set_eq:NN \__xparse_declare_cmd_mixed_aux:Nn \__my_xparse_declare_as_cmd_mixed_aux_save:Nn
}

関連情報