\NewDocumentCommand로 정의된 명령으로 생성된 오류 메시지 제어

\NewDocumentCommand로 정의된 명령으로 생성된 오류 메시지 제어

\NewDocumentCommand명령은 더 나은 오류 메시지를 만들기 위해 영리한 트릭을 사용합니다. 인수가 \mycommand엉망인 경우 결과 오류가 "사용을 검색하는 동안 파일이 종료되었습니다"와 같은 것은 바람직하지 않으므로 \__xparse_grab_D:wxparse가 다른 메시지를 가져올 때마다 인수의 경우 인수 가져오기를 수행하도록 정의한 \mycommand<space>다음 이를 사용하여 작업을 수행하므로 문제가 발생하면 대신 "단락이 \mycommand<space>완료되기 전에 종료되었습니다"와 같은 오류가 발생합니다.

나는 이와 같은 명령이 \NewDocumentCommandAs두 개의 인수, 즉 정의할 매크로 이름과 오류 메시지에 사용할 명령 이름을 사용하기를 원합니다.

이에 대한 두 가지 사용 사례가 있습니다. 하나는 특정 환경 내에서만 사용되는 명령을 정의하는 패키지가 있다는 것입니다. 따라서 패키지의 비공개 네임스페이스에 있는 명령을 정의하고 \let환경 시작 시 비공개 버전에 대한 명령의 공개 이름을 정의합니다. 분명히 나는 ​​명령의 공개 이름을 중심으로 모든 오류 메시지를 기반으로 하고 싶기 때문에 다음과 같이 말하고 싶습니다.

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

두 번째 사용 사례는 선택적 인수, 첫 번째 여는 괄호까지의 모든 인수, 첫 번째 여는 괄호로 시작하는 균형 잡힌 괄호로 구분된 인수가 있는 명령이 있다는 것입니다. "until" 인수 유형은 스캔 중인 토큰을 흡수하므로 여는 괄호를 다시 삽입하고 보조를 사용해야 합니다.

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

물론 이 문제는 제거한 토큰을 다시 삽입하는 u 버전(어쩌면 U?)을 만들어 해결할 수 있지만 이는 특이한 사용 사례일 수 있습니다.

형식화를 위해 두 가지 구현을 답변으로 제출하겠습니다. 다른 사람이 이 문제를 처리한 적이 있나요? 내가 놓친 더 나은 접근 방식이 있습니까? 이렇게 하지 말고 다른 방법으로 이러한 문제를 해결해야 합니까? 이것은 향후 버전의 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있고 다른 보조 명령이 사용되지 않는다는 세부 사항 이상의 구현에 의존하지 않는다는 것입니다 . 한 가지 제한 사항은 모든 인수가 "m" 유형이면 작동하지 않는다는 것입니다. 그러나 이것이 나를 괴롭히지는 않습니다. 이 접근 방식은 확장 가능한 매크로에도 작동하지 않습니다.

\__xparse_declare_cmd_mixed_aux:Nn또 다른 가능한 접근 방식은 오류 명령( 에 저장됨)에 다른 이름을 사용하는 패치 버전을 만들고 \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
}

관련 정보