import type { ArgumentType , Parser } from '../core/parser' ; import type { Atom , AtomType , BBoxParameter } from '../core/atom-class' ; import type { ColumnFormat } from '../core-atoms/array' ; import type { ParseMode , Variant , VariantStyle , MacroDictionary , MacroDefinition , MacroPackageDefinition , Dimension , Glue , } from '../public/core' ; import { supportRegexPropertyEscape } from '../common/capabilities' ; import { PrivateStyle } from '../core/context' ; import { MathstyleName } from '../core/mathstyle' ; export type FunctionArgumentDefiniton = { isOptional : boolean ; type : ArgumentType ; } ; export type Argument = string | number | Dimension | Glue | BBoxParameter | ColumnFormat [ ] | Atom [ ] ; export type CreateAtomOptions = { colorMap ? : ( name : string ) => string | undefined ; backgroundColorMap ? : ( name : string ) => string | undefined ; } ; export type ApplyStyleDefinitionOptions = { colorMap ? : ( name : string ) => string | undefined ; backgroundColorMap ? : ( name : string ) => string | undefined ; } ; export type ParseResult = Atom | PrivateStyle | ParseMode | MathstyleName | { error : string ; } ; export type CommandDefinition = { parse : ( parser : Parser ) => ParseResult ; } ; export type FunctionDefinition = { params : FunctionArgumentDefiniton [ ] ; infix : boolean ; isFunction : boolean ; ifMode ? : ParseMode ; applyMode ? : ParseMode ; createAtom ? : ( command : string , args : ( null | Argument ) [ ] , style : PrivateStyle , options : CreateAtomOptions ) => Atom ; applyStyle ? : ( command : string , args : ( null | Argument ) [ ] , options : ApplyStyleDefinitionOptions ) => PrivateStyle ; frequency ? : number ; category ? : string ; template ? : string ; } ; type EnvironmentDefinition = { /** If true, the 'content' of the environment is parsed in tabular mode,
     *  i.e. wiht '&' creating a new column and '\\' creating a new row.
     */ tabular : boolean ; params : FunctionArgumentDefiniton [ ] ; createAtom : EnvironmentConstructor ; } ; export type SymbolDefinition = { type : AtomType ; codepoint : number ; variant ? : Variant ; frequency ? : number ; category ? : string ; template ? : string ; } ; export const MATH_SYMBOLS = { } ; const REVERSE_MATH_SYMBOLS = { 0x003C : '<' , 0x003E : '>' , 0x006F : 'o' , 0x0026 : '\\&' , 0x007B : '\\lbrace' , 0x007D : '\\rbrace' , 0x005B : '\\lbrack' , 0x005D : '\\rbrack' , 0x003A : '\\colon' , 0x00A0 : '~' , 0x00AC : '\\neg' , 0x00B7 : '\\cdot' , 0x00BC : '\\frac{1}{4}' , 0x00BD : '\\frac{1}{2}' , 0x00BE : '\\frac{3}{4}' , 0x2070 : '^{0}' , 0x2071 : '^{i}' , 0x00B9 : '^{1}' , 0x00B2 : '^{2}' , 0x00B3 : '^{3}' , 0x2020 : '\\dagger' , 0x2021 : '\\ddagger' , 0x2026 : '\\ldots' , 0x2074 : '^{4}' , 0x2075 : '^{5}' , 0x2076 : '^{6}' , 0x2077 : '^{7}' , 0x2078 : '^{8}' , 0x2079 : '^{9}' , 0x207A : '^{+}' , 0x207B : '^{-}' , 0x207C : '^{=}' , 0x207F : '^{n}' , 0x2080 : '_{0}' , 0x2081 : '_{1}' , 0x2082 : '_{2}' , 0x2083 : '_{3}' , 0x2084 : '_{4}' , 0x2085 : '_{5}' , 0x2086 : '_{6}' , 0x2087 : '_{7}' , 0x2088 : '_{8}' , 0x2089 : '_{9}' , 0x208A : '_{+}' , 0x208B : '_{-}' , 0x208C : '_{=}' , 0x2090 : '_{a}' , 0x2091 : '_{e}' , 0x2092 : '_{o}' , 0x2093 : '_{x}' , 0x2032 : '\\prime' , 0x0027 : '\\prime' , 0x2190 : '\\gets' , 0x2192 : '\\to' , 0x25B3 : '\\triangle' , 0x25BD : '\\triangledown' , 0x220B : '\\owns' , 0x2217 : '\\ast' , 0x2223 : '\\vert' , 0x2225 : '\\Vert' , 0x2227 : '\\land' , 0x2228 : '\\lor' , 0x22C5 : '\\cdot' , 0x22C8 : '\\bowtie' , 0x2260 : '\\ne' , 0x2264 : '\\le' , 0x2265 : '\\ge' , 0x22A5 : '\\bot' , 0x27F7 : '\\biconditional' , 0x27F8 : '\\impliedby' , 0x27F9 : '\\implies' , 0x27fa : '\\iff' , 0x2102 : '\\C' , 0x2115 : '\\N' , 0x2119 : '\\P' , 0x211A : '\\Q' , 0x211D : '\\R' , 0x2124 : '\\Z' , } ; export const LEGACY_COMMANDS = { } ; export const COMMANDS = { } ; export const ENVIRONMENTS = { } ; type EnvironmentConstructor = ( name : string , array : Atom [ ] [ ] [ ] , rowGaps : Dimension [ ] , args : ( null | Argument ) [ ] ) => Atom | null ; export type NormalizedMacroDictionary = Record < string , MacroDefinition > ; export const TEXVC_MACROS = { darr : '\\downarrow' , dArr : '\\Downarrow' , Darr : '\\Downarrow' , lang : '\\langle' , rang : '\\rangle' , uarr : '\\uparrow' , uArr : '\\Uparrow' , Uarr : '\\Uparrow' , N : '\\mathbb{N}' , R : '\\mathbb{R}' , Z : '\\mathbb{Z}' , alef : '\\aleph' , alefsym : '\\aleph' , Alpha : '\\mathrm{A}' , Beta : '\\mathrm{B}' , bull : '\\bullet' , Chi : '\\mathrm{X}' , clubs : '\\clubsuit' , cnums : '\\mathbb{C}' , Complex : '\\mathbb{C}' , Dagger : '\\ddagger' , diamonds : '\\diamondsuit' , empty : '\\emptyset' , Epsilon : '\\mathrm{E}' , Eta : '\\mathrm{H}' , exist : '\\exists' , harr : '\\leftrightarrow' , hArr : '\\Leftrightarrow' , Harr : '\\Leftrightarrow' , hearts : '\\heartsuit' , image : '\\Im' , infin : '\\infty' , Iota : '\\mathrm{I}' , isin : '\\in' , Kappa : '\\mathrm{K}' , larr : '\\leftarrow' , lArr : '\\Leftarrow' , Larr : '\\Leftarrow' , lrarr : '\\leftrightarrow' , lrArr : '\\Leftrightarrow' , Lrarr : '\\Leftrightarrow' , Mu : '\\mathrm{M}' , natnums : '\\mathbb{N}' , Nu : '\\mathrm{N}' , Omicron : '\\mathrm{O}' , plusmn : '\\pm' , rarr : '\\rightarrow' , rArr : '\\Rightarrow' , Rarr : '\\Rightarrow' , real : '\\Re' , reals : '\\mathbb{R}' , Reals : '\\mathbb{R}' , Rho : '\\mathrm{P}' , sdot : '\\cdot' , sect : '\\S' , spades : '\\spadesuit' , sub : '\\subset' , sube : '\\subseteq' , supe : '\\supseteq' , Tau : '\\mathrm{T}' , thetasym : '\\vartheta' , weierp : '\\wp' , Zeta : '\\mathrm{Z}' , } ; export const AMSMATH_MACROS = { varGamma : '\\mathit{\\Gamma}' , varDelta : '\\mathit{\\Delta}' , varTheta : '\\mathit{\\Theta}' , varLambda : '\\mathit{\\Lambda}' , varXi : '\\mathit{\\Xi}' , varPi : '\\mathit{\\Pi}' , varSigma : '\\mathit{\\Sigma}' , varUpsilon : '\\mathit{\\Upsilon}' , varPhi : '\\mathit{\\Phi}' , varPsi : '\\mathit{\\Psi}' , varOmega : '\\mathit{\\Omega}' , pmod : { def : '\\quad(\\operatorname{mod}\\ #1)' , args : 1 , expand : false , captureSelection : false , } , mod : { def : '\\quad\\operatorname{mod}\\,\\,#1' , args : 1 , expand : false , captureSelection : false , } , bmod : { def : '\\;\\mathbin{\\operatorname{mod }}' , expand : false , } , } ; export const BRAKET_MACROS = { bra : '\\mathinner{\\langle{#1}|}' , ket : '\\mathinner{|{#1}\\rangle}' , braket : '\\mathinner{\\langle{#1}\\rangle}' , set : '\\mathinner{\\lbrace #1 \\rbrace}' , Bra : '\\left\\langle #1\\right|' , Ket : '\\left|#1\\right\\rangle' , Braket : '\\left\\langle{#1}\\right\\rangle' , Set : '\\left\\lbrace #1 \\right\\rbrace' , } ; const DEFAULT_MACROS = { 'iff' : '\\;\u27FA\\;' , 'nicefrac' : '^{#1}\\!\\!/\\!_{#2}' , 'rd' : '\\mathrm{d}' , 'rD' : '\\mathrm{D}' , 'doubleStruckCapitalN' : '\\mathbb{N}' , 'doubleStruckCapitalR' : '\\mathbb{R}' , 'doubleStruckCapitalQ' : '\\mathbb{Q}' , 'doubleStruckCapitalZ' : '\\mathbb{Z}' , 'doubleStruckCapitalP' : '\\mathbb{P}' , 'scriptCapitalE' : '\\mathscr{E}' , 'scriptCapitalH' : '\\mathscr{H}' , 'scriptCapitalL' : '\\mathscr{L}' , 'gothicCapitalC' : '\\mathfrak{C}' , 'gothicCapitalH' : '\\mathfrak{H}' , 'gothicCapitalI' : '\\mathfrak{I}' , 'gothicCapitalR' : '\\mathfrak{R}' , 'imaginaryI' : '\\mathrm{i}' , 'imaginaryJ' : '\\mathrm{j}' , 'exponentialE' : '\\mathrm{e}' , 'differentialD' : '\\mathrm{d}' , 'capitalDifferentialD' : '\\mathrm{D}' , 'braket.sty' : { package : BRAKET_MACROS } as MacroPackageDefinition , 'amsmath.sty' : { package : AMSMATH_MACROS , expand : false , } as MacroPackageDefinition , 'texvc.sty' : { package : TEXVC_MACROS , expand : false , } as MacroPackageDefinition , } ; export const TEXT_SYMBOLS = { ' ' : 0x0020 , '\\#' : 0x0023 , '\\&' : 0x0026 , '\\$' : 0x0024 , '\\%' : 0x0025 , '\\_' : 0x005f , '\\euro' : 0x20ac , '\\maltese' : 0x2720 , '\\{' : 0x007b , '\\}' : 0x007d , '\\nobreakspace' : 0x00a0 , '\\ldots' : 0x2026 , '\\textellipsis' : 0x2026 , '\\backslash' : 0x005c , '`' : 0x2018 , "'" : 0x2019 , '``' : 0x201c , "''" : 0x201d , '\\degree' : 0x00b0 , '\\textasciicircum' : 0x005e , '\\textasciitilde' : 0x007e , '\\textasteriskcentered' : 0x002a , '\\textbackslash' : 0x005c , '\\textbraceleft' : 0x007b , '\\textbraceright' : 0x007d , '\\textbullet' : 0x2022 , '\\textdollar' : 0x0024 , '\\textsterling' : 0x00a3 , '\\textdagger' : 0x2020 , '\\textdaggerdbl' : 0x2021 , '–' : 0x2013 , '—' : 0x2014 , '‘' : 0x2018 , '’' : 0x2019 , '“' : 0x201c , '”' : 0x201d , '"' : 0x201d , '\\ss' : 0x00df , '\\ae' : 0x00e6 , '\\oe' : 0x0153 , '\\AE' : 0x00c6 , '\\OE' : 0x0152 , '\\O' : 0x00d8 , '\\i' : 0x0131 , '\\j' : 0x0237 , '\\aa' : 0x00e5 , '\\AA' : 0x00c5 , } ; export const COMMAND_MODE_CHARACTERS = /[\w!@*()-=+{}[\]\\';:?/.,~<>`|$%#&^" ]/ ; export const LETTER = supportRegexPropertyEscape ( ) ? new RegExp ( '\\p{Letter}' , 'u' ) : /[a-zA-ZаАбБвВгГдДеЕёЁжЖзЗиИйЙкКлЛмМнНоОпПрРсСтТуУфФхХцЦчЧшШщЩъЪыЫьЬэЭюЮяĄąĆćĘęŁłŃńÓóŚśŹźŻżàâäôéèëêïîçùûüÿæœÀÂÄÔÉÈËÊÏÎŸÇÙÛÜÆŒößÖẞìíòúÌÍÒÚáñÁÑ]/ ; export const LETTER_AND_DIGITS = supportRegexPropertyEscape ( ) ? new RegExp ( '[0-9\\p{Letter}]' , 'u' ) : /[\da-zA-ZаАбБвВгГдДеЕёЁжЖзЗиИйЙкКлЛмМнНоОпПрРсСтТуУфФхХцЦчЧшШщЩъЪыЫьЬэЭюЮяĄąĆćĘęŁłŃńÓóŚśŹźŻżàâäôéèëêïîçùûüÿæœÀÂÄÔÉÈËÊÏÎŸÇÙÛÜÆŒößÖẞìíòúÌÍÒÚáñÁÑ]/ ; param symbol function newSymbol ( symbol , value , type = 'mord' , variant ? ) { if ( value === undefined ) return ; MATH_SYMBOLS [ symbol ] = { type , variant , codepoint : value , } ; if ( ! REVERSE_MATH_SYMBOLS [ value ] && ! variant ) { REVERSE_MATH_SYMBOLS [ value ] = symbol ; } if ( ! TEXT_SYMBOLS [ symbol ] ) { TEXT_SYMBOLS [ symbol ] = value ; } } /**
 * Define a set of single-character symbols
 */ export function newSymbols ( value , inType ? , inVariant ? ) { if ( typeof value === 'string' ) { for ( let i = 0 ; i < value . length ; i ++ ) { const ch = value . charAt ( i ) ; newSymbol ( ch , ch . codePointAt ( 0 ) ) ; } return ; } for ( const [ symbol , val , type , variant ] of value ) { newSymbol ( symbol , val , type ?? inType , variant ?? inVariant ) ; } } param from param to export function newSymbolRange ( from , to ) { for ( let i = from ; i <= to ; i ++ ) { newSymbol ( String . fromCodePoint ( i ) , i ) ; } } /**
 * Given a codepoint, return a matching LaTeX expression.
 * If there is a matching command (e.g. `\alpha`) it is returned.
 */ export function charToLatex ( parseMode , codepoint ) { if ( codepoint === undefined ) return '' ; if ( parseMode === 'math' && REVERSE_MATH_SYMBOLS [ codepoint ] ) { return REVERSE_MATH_SYMBOLS [ codepoint ] ; } if ( parseMode === 'text' ) { let textSymbol = Object . keys ( TEXT_SYMBOLS ) . find ( ( x ) => TEXT_SYMBOLS [ x ] === codepoint ) ; if ( ! textSymbol ) { const hex = codepoint . toString ( 16 ) ; textSymbol = '^' . repeat ( hex . length ) + hex ; } return textSymbol ; } return String . fromCodePoint ( codepoint ) ; } const MATH_LETTER_EXCEPTIONS = { 0x1d455 : 0x0210e , 0x1d49d : 0x0212c , 0x1d4a0 : 0x02130 , 0x1d4a1 : 0x02131 , 0x1d4a3 : 0x0210b , 0x1d4a4 : 0x02110 , 0x1d4a7 : 0x02112 , 0x1d4a8 : 0x02133 , 0x1d4ad : 0x0211b , 0x1d4ba : 0x0212f , 0x1d4bc : 0x0210a , 0x1d4c4 : 0x02134 , 0x1d506 : 0x0212d , 0x1d50b : 0x0210c , 0x1d50c : 0x02111 , 0x1d515 : 0x0211c , 0x1d51d : 0x02128 , 0x1d53a : 0x02102 , 0x1d53f : 0x0210d , 0x1d545 : 0x02115 , 0x1d547 : 0x02119 , 0x1d548 : 0x0211a , 0x1d549 : 0x0211d , 0x1d551 : 0x02124 , } ; const MATH_UNICODE_BLOCKS = [ { start : 0x1d400 , len : 26 , offset : 65 , style : 'bold' } , { start : 0x1d41a , len : 26 , offset : 97 , style : 'bold' } , { start : 0x1d434 , len : 26 , offset : 65 , style : 'italic' } , { start : 0x1d44e , len : 26 , offset : 97 , style : 'italic' } , { start : 0x1d468 , len : 26 , offset : 65 , style : 'bolditalic' } , { start : 0x1d482 , len : 26 , offset : 97 , style : 'bolditalic' } , { start : 0x1d49c , len : 26 , offset : 65 , variant : 'script' } , { start : 0x1d4b6 , len : 26 , offset : 97 , variant : 'script' } , { start : 0x1d4d0 , len : 26 , offset : 65 , variant : 'script' , style : 'bold' } , { start : 0x1d4ea , len : 26 , offset : 97 , variant : 'script' , style : 'bold' } , { start : 0x1d504 , len : 26 , offset : 65 , variant : 'fraktur' } , { start : 0x1d51e , len : 26 , offset : 97 , variant : 'fraktur' } , { start : 0x1d56c , len : 26 , offset : 65 , variant : 'fraktur' , style : 'bold' } , { start : 0x1d586 , len : 26 , offset : 97 , variant : 'fraktur' , style : 'bold' } , { start : 0x1d538 , len : 26 , offset : 65 , variant : 'double-struck' } , { start : 0x1d552 , len : 26 , offset : 97 , variant : 'double-struck' } , { start : 0x1d5a0 , len : 26 , offset : 65 , variant : 'sans-serif' } , { start : 0x1d5ba , len : 26 , offset : 97 , variant : 'sans-serif' } , { start : 0x1d5d4 , len : 26 , offset : 65 , variant : 'sans-serif' , style : 'bold' , } , { start : 0x1d5ee , len : 26 , offset : 97 , variant : 'sans-serif' , style : 'bold' , } , { start : 0x1d608 , len : 26 , offset : 65 , variant : 'sans-serif' , style : 'italic' , } , { start : 0x1d622 , len : 26 , offset : 97 , variant : 'sans-serif' , style : 'italic' , } , { start : 0x1d63c , len : 26 , offset : 65 , variant : 'sans-serif' , style : 'bolditalic' , } , { start : 0x1d656 , len : 26 , offset : 97 , variant : 'sans-serif' , style : 'bolditalic' , } , { start : 0x1d670 , len : 26 , offset : 65 , variant : 'monospace' } , { start : 0x1d68a , len : 26 , offset : 97 , variant : 'monospace' } , { start : 0x1d6a8 , len : 25 , offset : 0x391 , style : 'bold' } , { start : 0x1d6c2 , len : 25 , offset : 0x3b1 , style : 'bold' } , { start : 0x1d6e2 , len : 25 , offset : 0x391 , style : 'italic' } , { start : 0x1d6fc , len : 25 , offset : 0x3b1 , style : 'italic' } , { start : 0x1d71c , len : 25 , offset : 0x391 , style : 'bolditalic' } , { start : 0x1d736 , len : 25 , offset : 0x3b1 , style : 'bolditalic' } , { start : 0x1d756 , len : 25 , offset : 0x391 , variant : 'sans-serif' , style : 'bold' , } , { start : 0x1d770 , len : 25 , offset : 0x3b1 , variant : 'sans-serif' , style : 'bold' , } , { start : 0x1d790 , len : 25 , offset : 0x391 , variant : 'sans-serif' , style : 'bolditalic' , } , { start : 0x1d7aa , len : 25 , offset : 0x3b1 , variant : 'sans-serif' , style : 'bolditalic' , } , { start : 0x1d7ce , len : 10 , offset : 48 , variant : 'main' , style : 'bold' } , { start : 0x1d7d8 , len : 10 , offset : 48 , variant : 'double-struck' } , { start : 0x1d7e3 , len : 10 , offset : 48 , variant : 'sans-serif' } , { start : 0x1d7ec , len : 10 , offset : 48 , variant : 'sans-serif' , style : 'bold' , } , { start : 0x1d7f6 , len : 10 , offset : 48 , variant : 'monospace' } , ] ; function unicodeToMathVariant ( codepoint ) { if ( ( codepoint < 0x1d400 || codepoint > 0x1d7ff ) && ( codepoint < 0x2100 || codepoint > 0x214f ) ) { return { char : String . fromCodePoint ( codepoint ) } ; } for ( const c in MATH_LETTER_EXCEPTIONS ) { if ( MATH_LETTER_EXCEPTIONS [ c ] === codepoint ) { codepoint = c . codePointAt ( 0 ) ?? 0 ; break ; } } for ( const MATH_UNICODE_BLOCK of MATH_UNICODE_BLOCKS ) { if ( codepoint >= MATH_UNICODE_BLOCK . start && codepoint < MATH_UNICODE_BLOCK . start + MATH_UNICODE_BLOCK . len ) { return { char : String . fromCodePoint ( codepoint - MATH_UNICODE_BLOCK . start + MATH_UNICODE_BLOCK . offset ) , variant : MATH_UNICODE_BLOCK . variant , style : MATH_UNICODE_BLOCK . style , } ; } } return { char : String . fromCodePoint ( codepoint ) } ; } /**
 * Given a character and variant ('double-struck', 'fraktur', etc...)
 * return the corresponding unicode character (a string)
 */ export function mathVariantToUnicode ( char , variant , style ? ) { if ( ! /[A-Za-z\d]/ . test ( char ) ) return char ; if ( ! variant && ! style ) return char ; const codepoint = char . codePointAt ( 0 ) ; if ( codepoint === undefined ) return char ; for ( const MATH_UNICODE_BLOCK of MATH_UNICODE_BLOCKS ) { if ( ! variant || MATH_UNICODE_BLOCK . variant === variant ) { if ( ! style || MATH_UNICODE_BLOCK . style === style ) { if ( codepoint >= MATH_UNICODE_BLOCK . offset && codepoint < MATH_UNICODE_BLOCK . offset + MATH_UNICODE_BLOCK . len ) { const result = MATH_UNICODE_BLOCK . start + codepoint - MATH_UNICODE_BLOCK . offset ; return String . fromCodePoint ( MATH_LETTER_EXCEPTIONS [ result ] || result ) ; } } } } return char ; } export function unicodeCharToLatex ( parseMode , char ) { if ( parseMode === 'text' ) { return charToLatex ( parseMode , char . codePointAt ( 0 ) ) ?? char ; } let result ; result = charToLatex ( parseMode , char . codePointAt ( 0 ) ) ; if ( result ) return result ; const cp = char . codePointAt ( 0 ) ! ; const v = unicodeToMathVariant ( cp ) ; if ( ! v . style && ! v . variant ) return '' ; result = v . char ; if ( v . variant ) { result = '\\' + v . variant + '{' + result + '}' ; } if ( v . style === 'bold' ) { result = '\\mathbf{' + result + '}' ; } else if ( v . style === 'italic' ) { result = '\\mathit{' + result + '}' ; } else if ( v . style === 'bolditalic' ) { result = '\\mathbfit{' + result + '}' ; } return '\\mathord{' + result + '}' ; } export function unicodeStringToLatex ( parseMode , s ) { let result = '' ; let needSpace = false ; for ( const c of s ) { if ( needSpace ) { result += parseMode === 'text' ? '{}' : ' ' ; } needSpace = false ; const latex = unicodeCharToLatex ( parseMode , c ) ; if ( latex ) { result += latex ; needSpace = /\\[a-zA-Z\d]+\*?$/ . test ( latex ) ; } else { result += c ; } } return result ; } /**
 * Gets the value of a symbol in math mode
 */ export function getEnvironmentDefinition ( name ) { return ENVIRONMENTS [ name ] ?? null ; } param symbol param parseMode param macros return { object } export function getInfo ( symbol , parseMode , macros ? ) { if ( ! symbol || symbol . length === 0 ) return null ; let info = null ; if ( symbol . startsWith ( '\\' ) ) { info = LEGACY_COMMANDS [ symbol ] ?? null ; if ( info ) { return info ; } if ( parseMode === 'math' ) { info = MATH_SYMBOLS [ symbol ] ; } else if ( TEXT_SYMBOLS [ symbol ] ) { info = { type : 'mord' , codepoint : TEXT_SYMBOLS [ symbol ] } ; } if ( ! info ) { const command = symbol . slice ( 1 ) ; if ( macros ?. [ command ] ) { let argCount = macros [ command ] . args ?? 0 ; info = { type : 'group' , params : [ ] , infix : false , } ; while ( argCount >= 1 ) { info ! . params ! . push ( { isOptional : false , type : 'math' , } ) ; argCount -= 1 ; } } } } else if ( parseMode === 'math' ) { info = MATH_SYMBOLS [ symbol ] ; } else if ( TEXT_SYMBOLS [ symbol ] ) { info = { codepoint : TEXT_SYMBOLS [ symbol ] , type : 'mord' } ; } else if ( parseMode === 'text' ) { info = { codepoint : symbol . codePointAt ( 0 ) ! , type : 'mord' } ; } if ( info && info . type === 'mord' && ( info . codepoint === 0x66 || info . codepoint === 0x67 || info . codepoint === 0x68 ) ) { info . isFunction = true ; } return info ; } /**
 * Return an array of suggestion for completing string 's'.
 * For example, for 'si', it could return ['sin', 'sinh', 'sim', 'simeq', 'sigma']
 * Infix operators are excluded, since they are deprecated commands.
 */ export function suggest ( s ) { if ( s === '\\' ) return [ ] ; const result = [ ] ; for ( const p in LEGACY_COMMANDS ) { if ( p . startsWith ( s ) && ! LEGACY_COMMANDS [ p ] . infix ) { result . push ( { match : p , frequency : LEGACY_COMMANDS [ p ] . frequency ?? 0 } ) ; } } for ( const p in MATH_SYMBOLS ) { if ( p . startsWith ( s ) ) { result . push ( { match : p , frequency : MATH_SYMBOLS [ p ] . frequency ?? 0 } ) ; } } result . sort ( ( a , b ) => { if ( a . frequency === b . frequency ) { if ( a . match . length === b . match . length ) { return a . match . localeCompare ( b . match ) ; } return a . match . length - b . match . length ; } return ( b . frequency ?? 0 ) - ( a . frequency ?? 0 ) ; } ) ; return result ; } /**
 * An argument template has the following syntax:
 *
 * <placeholder>:<type>
 *
 * where
 * - <placeholder> is a string whose value is displayed when the argument
 *   is missing
 * - <type> is one of 'string', 'color', 'dimen', 'auto', 'text', 'math'
 *
 */ function parseParameterTemplateArgument ( argTemplate ) { let type = 'auto' ; const r = argTemplate . match ( /:([^=]+)/ ) ; if ( r ) type = r [ 1 ] . trim ( ) as ArgumentType ; return type ; } function parseParameterTemplate ( parameterTemplate ) { if ( ! parameterTemplate ) return [ ] ; let result = [ ] ; let parameters = parameterTemplate . split ( ']' ) ; if ( parameters [ 0 ] . startsWith ( '[' ) ) { result . push ( { isOptional : true , type : parseParameterTemplateArgument ( parameters [ 0 ] . slice ( 1 ) ) , } ) ; for ( let i = 1 ; i <= parameters . length ; i ++ ) { result = result . concat ( parseParameterTemplate ( parameters [ i ] ) ) ; } } else { parameters = parameterTemplate . split ( '}' ) ; if ( parameters [ 0 ] . startsWith ( '{' ) ) { result . push ( { isOptional : false , type : parseParameterTemplateArgument ( parameters [ 0 ] . slice ( 1 ) ) , } ) ; for ( let i = 1 ; i <= parameters . length ; i ++ ) { result = result . concat ( parseParameterTemplate ( parameters [ i ] ) ) ; } } } return result ; } /**
 * If possible, i.e. if they are all simple atoms, return a string made up of
 * their body
 */ export function parseArgAsString ( atoms ) { if ( ! atoms ) return '' ; let result = '' ; let success = true ; for ( const atom of atoms ) { if ( typeof atom . value === 'string' ) { result += atom . value ; } else { success = false ; } } return success ? result : '' ; } param params export function defineEnvironment ( names , parameters , parser , isTabular = false ) { if ( typeof names === 'string' ) { names = [ names ] ; } const parsedParameters = parseParameterTemplate ( parameters ) ; const data = { tabular : isTabular , params : parsedParameters , createAtom : parser , } ; for ( const name of names ) { ENVIRONMENTS [ name ] = data ; } } /**
 * Like defineEnvironment, but for a tabular environment, i.e.
 * one whose content is in tabular mode, where '&' indicata a new column
 * and '\\' indicate a new row.
 */ export function defineTabularEnvironment ( names , parameters , parser ) { defineEnvironment ( names , parameters , parser , true ) ; } /**
 * Define one of more commands.
 *
 * The name of the commands should not include the leading `\`
 */ export function newCommand ( name , parse ) { if ( typeof name === 'string' ) { COMMANDS [ name ] = { parse } ; return ; } for ( const x of name ) COMMANDS [ x ] = { parse } ; } param names param params export function defineFunction ( names , parameters , options ) { if ( ! options ) options = { } ; const data = { params : parseParameterTemplate ( parameters ) , ifMode : options . ifMode , isFunction : options . isFunction ?? false , applyMode : options . applyMode , infix : options . infix ?? false , createAtom : options . createAtom , applyStyle : options . applyStyle , } ; if ( typeof names === 'string' ) { LEGACY_COMMANDS [ '\\' + names ] = data ; } else { for ( const name of names ) LEGACY_COMMANDS [ '\\' + name ] = data ; } } let _DEFAULT_MACROS ; export function getMacros ( otherMacros ? ) { if ( ! _DEFAULT_MACROS ) { _DEFAULT_MACROS = normalizeMacroDictionary ( DEFAULT_MACROS ) ; } if ( ! otherMacros ) return _DEFAULT_MACROS ; return { ... _DEFAULT_MACROS , ... normalizeMacroDictionary ( otherMacros ) } ; } function normalizeMacroDefinition ( def , options ? ) { if ( typeof def === 'string' ) { let argCount = 0 ; const defString = def as string ; if ( /(^|[^\\])#1/ . test ( defString ) ) argCount = 1 ; if ( /(^|[^\\])#2/ . test ( defString ) ) argCount = 2 ; if ( /(^|[^\\])#3/ . test ( defString ) ) argCount = 3 ; if ( /(^|[^\\])#4/ . test ( defString ) ) argCount = 4 ; if ( /(^|[^\\])#5/ . test ( defString ) ) argCount = 5 ; if ( /(^|[^\\])#6/ . test ( defString ) ) argCount = 6 ; if ( /(^|[^\\])#7/ . test ( defString ) ) argCount = 7 ; if ( /(^|[^\\])#8/ . test ( defString ) ) argCount = 8 ; if ( /(^|[^\\])#9/ . test ( defString ) ) argCount = 9 ; return { expand : options ?. expand ?? true , captureSelection : options ?. captureSelection ?? true , args : argCount , def : defString , } ; } return { expand : options ?. expand ?? true , captureSelection : options ?. captureSelection ?? true , args : 0 , ... ( def as MacroDefinition ) , } ; } export function normalizeMacroDictionary ( macros ) { if ( ! macros ) return { } ; const result = { } ; for ( const macro of Object . keys ( macros ) ) { const macroDef = macros [ macro ] ; if ( macroDef === undefined || macroDef === null ) { delete result [ macro ] ; } else if ( typeof macroDef === 'object' && 'package' in macroDef ) { for ( const packageMacro of Object . keys ( macroDef . package ) ) { result [ packageMacro ] = normalizeMacroDefinition ( macroDef . package [ packageMacro ] , { expand : macroDef . expand , captureSelection : macroDef . captureSelection , } ) ; } } else { result [ macro ] = normalizeMacroDefinition ( macroDef ) ; } } return result ; }