Los comandos fallan al procesar token por token

Los comandos fallan al procesar token por token

Estoy tratando de crear un comando que formatee \everymathciertos caracteres específicos (coloca automáticamente v, \mathbfetc.). Esa parte ya la he descubierto, pero lo que me está dando problemas es el procesamiento en sí. Parece estar separando comandos dentro del modo matemático, ya sea mostrándose incorrectamente o simplemente rompiéndose por completo.

Esta es una versión mínima que simplemente avanza y no cambia nada (en teoría):

\ExplSyntaxOn
\NewDocumentCommand{\mformat}{+m}{%
  \exp_after:wN #1 \mode_if_math:TF { \mformat } { }
}
\ExplSyntaxOff

Se usa así:

\everymath{\mformat}

Aquí hay algunos ejemplos de cómo se rompe:

\(\vec{v}\)

Esperado:Vec esperado

Actual:ActualVec(equivalente a \vec{}v)

\(\mathbf{v}\) % Just gives "Missing } inserted." error

¿Alguna idea sobre cómo solucionar este problema?

Editar: Algo nuevo que noté; Si rodeo los comandos problemáticos con llaves (como con mathbf, \({\mathbf{v}}\)funciona bien), de repente funcionan perfectamente. No tengo idea de por qué sucede esto.


Marqué la respuesta de egreg como la solución, ya que respondió la pregunta que hice, pero para la posteridad aquí está la solución a la pregunta que debería haber hecho (según los comentarios de PhelypeOleinik)

\ExplSyntaxOn

% Used to keep track of already active characters
\tl_new:N \g__mformat_mathactive_tl
% Used to figure out which characters need to be made normal again
\tl_new:N \l__mformat_remove_mathactive_tl
% Used to keep track of added characters from *this* iteration
\tl_new:N \l__mformat_used_tl

% Using https://tex.stackexchange.com/a/611898/261875
% and https://tex.stackexchange.com/a/299805/261875
\NewDocumentCommand{\mformat}{m}{
  % By default remove all previous active characters
  \tl_set_eq:NN \l__mformat_remove_mathactive_tl \g__mformat_mathactive_tl
  \tl_set:Nn \l__mformat_used_tl {}

  \tl_if_empty:nTF { #1 } {} {
    % Parse the formatting
    \cs_set:Npn \__mformat_parse:w ##1[##2]##3\relax {
      % Process each character in the set
      \tl_map_inline:nn { ##2 } {
        \tl_if_in:NnTF \g__mformat_mathactive_tl { ####1 } {
          % If this character is already active, keep it active
          \tl_remove_once:Nn \l__mformat_remove_mathactive_tl { ####1 }

          % Check if the character has been used this iteration
          \tl_if_in:NnTF \l__mformat_used_tl {####1} {
            % Helper needed to have something expandable once
            \cs_set_eq:Nc \__mformat_letter_helper: 
            { __mformat_letter_new_####1: }
            % Add a formatting option to the letter
            \cs_set:cx { __mformat_letter_new_####1: }  { 
              \exp_not:N ##1 { \exp_not:o \__mformat_letter_helper: } 
            }
          } {
            % Record that this has been used
            \tl_put_right:Nn \l__mformat_used_tl { ####1 }
            % Define what the letter will now resolve to
            \cs_set:cx { __mformat_letter_new_####1: }  { 
              \exp_not:N ##1 {\mathchar\use:c { __mformat_mathcode_####1: }} 
            }
          }
          
          \char_gset_active_eq:nc { `####1 } { __mformat_letter_new_####1: }
        } {
          % Record that this is now an active character
          \tl_gput_right:Nn \g__mformat_mathactive_tl { ####1 }
          % Record that this has been used
          \tl_put_right:Nn \l__mformat_used_tl { ####1 }
          
          % Record the normal character so it can be used later
          \cs_new:cx { __mformat_mathcode_####1: } 
          { \the\mathcode`####1 }
          
          % Define what the letter will now resolve to
          \cs_new:cx { __mformat_letter_new_####1: }  { 
            \exp_not:N ##1 {\mathchar\use:c { __mformat_mathcode_####1: }} 
          }
          \char_gset_active_eq:nc { `####1 } { __mformat_letter_new_####1: }
          
          % Set the character to be active in math mode
          \char_set_mathcode:nn { `####1 } { "8000 }
        }
      }

      % If there's no more character sets, finish, otherwise recurse
      \tl_if_empty:nTF { ##3 } { } { \__mformat_parse:w ##3\relax }
    }

    % Begin recursive parsing
    \__mformat_parse:w #1\relax
  }

  % \tl_show:N \l__mformat_remove_mathactive_tl
  % Remove the active status from the characters that need it
  \tl_map_inline:Nn \l__mformat_remove_mathactive_tl {
    \tl_gremove_once:Nn \g__mformat_mathactive_tl {##1}
    
    % Reset the math code
    \char_set_mathcode:nn { `##1 } { \use:c { __mformat_mathcode_##1: } }

    % Deregister functions
    \cs_undefine:c { __mformat_letter_new_##1: }
    \cs_undefine:c { __mformat_mathcode_##1: }
  }
}

\NewDocumentCommand{\std}{m}{ \mathchar\use:c { __mformat_mathcode_#1: } }

\ExplSyntaxOff

que se usa como

\mformat{\mathbb[R]\mathbf[vw]}

Respuesta1

Esto se parece mucho a un problema XY. Tu dices

y no cambia nada (en teoría)

Lo siento, eso no es cierto. La expansión de primer nivel de

\mode_if_math:TF { \mformat } { }

es

\if_mode_math: \__prg_TF_true:w \fi: \use_ii:nn {\mformat}{}

Si tienes $\vec{v}$obtienes

\vec\if_mode_math: \__prg_TF_true:w \fi: \use_ii:nn {\mformat}{}

y entonces el argumento \veces \if_mode_math:. Ejemplo:

\documentclass{article}

\ExplSyntaxOn
\NewDocumentCommand{\mformat}{+m}{%
  \exp_after:wN #1 \mode_if_math:TF { \mformat } { }
}
\ExplSyntaxOff

\everymath{\mformat}

\renewcommand{\vec}[1]{\showtokens{#1}}

\begin{document}

$\vec{v}$

\end{document}

En la consola me sale

No file mform.aux.
> \if_mode_math: .
\vec #1->\showtokens {#1}

l.13 $\vec

Sería mejor con\exp_last_unbraced:Nf

\documentclass{article}

\ExplSyntaxOn
\NewDocumentCommand{\mformat}{+m}{%
  \exp_last_unbraced:Nf #1 { \mode_if_math:TF { \mformat } { } }
}
\ExplSyntaxOff

\everymath{\mformat}

\renewcommand{\vec}[1]{\showtokens{#1}}

\begin{document}

$\vec{v}$

\end{document}

donde imprime la consola

> v.
\vec #1->\showtokens {#1}

Pero eso tampoco es muy bueno: con algo como

\mathrm{x}

el resultado es una larga serie de errores. E incluso si los arregla haciendo una larga lista de casos, algo como

\mathrm{abc}

se convertiría en

\exp_last_unbraced:Nf abc { \mode_if_math:TF { \mformat } { } }

que definitivamente no es lo que quieres ver.

Respuesta2

La fuente predeterminada para cada carácter en el modo matemático ya está declarada explícitamente, por lo que solo necesita ajustar las declaraciones para v. Aquí uso negrita romana (coincidente \mathbf), aunque su imagen "esperada" estaba en cursiva.

ingrese la descripción de la imagen aquí

\documentclass{article}

\DeclareSymbolFont{boldrm}     {OT1}{cmr}{bx}{n}
\DeclareSymbolFontAlphabet{\mathbf}   {boldrm}
\DeclareMathSymbol{v}{\mathalpha}{boldrm}{`v}

\begin{document}

$\vec{v} + \vec{w}$


\end{document}

información relacionada