I've been trying to write a LaTeX3 function to make arbitrary unicode characters math active and give them a definition. I'm using XeLaTeX. My solution inexplicably works for some examples but not for others.
It works for the ascii letter q
:
\ExplSyntaxOn
\cs_new_protected:Npn \my_set_math_active:Nn #1 {
\char_set_mathcode:nn {`#1} {"8000}
\tl_rescan:nn {\char_set_catcode_active:N #1} {\def #1}
}
\my_set_math_active:Nn q {(test)}
\ExplSyntaxOff
`q' is used in $q$. % works
It also works for all non-letters I've tried (uncomplicated ones, anyway; not counting \
, #
, etc.). But it doesn't work for any letter in the mathematical alphanumeric symbols range. For example, with a double-struck π’:
\my_set_math_active:Nn π’ {(test)} % error
I get the error ! Missing control sequence inserted.
. It doesn't recognize that the letter I'm trying to define is an active character. The following, however, works:
\char_set_mathcode:nn {`π’} {"8000}
{\char_set_catcode_active:N π’ \gdef π’ {(test)}}
\ExplSyntaxOff
`π’' is used in $π’$. % works, sort of
But this solution has its own problems:
If π’ appears in its own definition, it will have catcode 13 and thus cause non-termination.
It makes the definition global. I'd like to avoid global definitions whenever possible.
So why doesn't the original code work? I can only guess that π’ doesn't survive \tl_rescan:nn
. But I'm not sure what to try at this point.
I'd appreciate some help!
Motivation
I want to let you know why I need this: I'm basically writing a 'math-mode lexical analyzer'. That is to say, I want to make LaTeX a bit smarter and more flexible in interpreting character sequences in math mode. This will allow, among other things:
combinations of symbols to be interpreted as a single command. This is especially useful with unicode. I am, for example, defining the combination
βββΊ
as\longrightarrow
, so that it is visually distinguishable fromβ
(\rightarrow
) in a monospaced editor font. The lexer uses maximal munch matching, so I can also defineβββΊβΊ
as\longtwoheadrightarrow
.(strings of) letters to be understood in the semantic context of your theory, automatically give them the right font, and perhaps hyperlink them to their definition, all with minimal input. For example, in
$sin(x)$
, LaTeX might automatically setsin
upright andx
in italics.
This already works. But it's a shame that the full unicode range cannot yet be used.
I am still particularly interested why the code above works for q
but not for π’
. It would allow the definitions to remain local. Below is a somewhat more elegant way to code it, but still with the same result (without the code for \normal
):
\tl_new:N \l__my_active_tl
\cs_new_protected:Nn \my_set_math_active:Nn {
\tl_set_rescan:Nnn
\l__my_active_tl
{\char_set_catcode_active:N #1}
{#1}
\exp_last_unbraced:NV
\cs_set:Npn~\l__my_active_tl~{ #2 }
\char_set_mathcode:nn {`#1} {"8000}
}
\my_set_math_active:Nn q {(testa)} % fine
\my_set_math_active:Nn π’ {(testb)} % error
Is it a \tl_set_rescan:nn
bug?