import { getInfo , mathVariantToUnicode , } from '../core-definitions/definitions-utils' ; import { Atom , ToLatexOptions } from './atom' ; import { joinLatex } from './tokenizer' ; import { getPropertyRuns , Mode } from './modes-utils' ; import { Style } from '../public/core' ; import { Box } from './box' ; import { BoxAtom } from '../core-atoms/box' ; const VARIANTS = { 'main' : [ 'Main-Regular' , 'ML__cmr' ] , 'main-italic' : [ 'Main-Italic' , 'ML__cmr ML__it' ] , 'main-bold' : [ 'Main-Bold' , 'ML__cmr ML__bold' ] , 'main-bolditalic' : [ 'Main-BoldItalic' , 'ML__cmr ML__bold ML__it' ] , 'normal' : [ 'Main-Regular' , 'ML__cmr' ] , 'normal-bold' : [ 'Main-Bold' , 'ML__mathbf' ] , 'normal-italic' : [ 'Math-Italic' , 'ML__mathit' ] , 'normal-bolditalic' : [ 'Math-BoldItalic' , 'ML__mathbfit' ] , 'ams' : [ 'AMS-Regular' , 'ML__ams' ] , 'ams-bold' : [ 'AMS-Regular' , 'ML__ams' ] , 'ams-italic' : [ 'AMS-Regular' , 'ML__ams' ] , 'ams-bolditalic' : [ 'AMS-Regular' , 'ML__ams' ] , 'sans-serif' : [ 'SansSerif-Regular' , 'ML__sans' ] , 'sans-serif-bold' : [ 'SansSerif-Regular' , 'ML__sans ML__bold' ] , 'sans-serif-italic' : [ 'SansSerif-Regular' , 'ML__sans' ] , 'sans-serif-bolditalic' : [ 'SansSerif-Regular' , 'ML__sans' ] , 'calligraphic' : [ 'Caligraphic-Regular' , 'ML__cal' ] , 'calligraphic-bold' : [ 'Caligraphic-Regular' , 'ML__cal ML__bold' ] , 'calligraphic-italic' : [ 'Caligraphic-Regular' , 'ML__cal ML__it' ] , 'calligraphic-bolditalic' : [ 'Caligraphic-Regular' , 'ML__cal ML__bold ML__it' ] , 'script' : [ 'Script-Regular' , 'ML__script' ] , 'script-bold' : [ 'Script-Regular' , 'ML__script ML__bold' ] , 'script-italic' : [ 'Script-Regular' , 'ML__script ML__it' ] , 'script-bolditalic' : [ 'Script-Regular' , 'ML__script ML__bold ML__it' ] , 'fraktur' : [ 'Fraktur-Regular' , 'ML__frak' ] , 'fraktur-bold' : [ 'Fraktur-Regular' , 'ML__frak' ] , 'fraktur-italic' : [ 'Fraktur-Regular' , 'ML__frak' ] , 'fraktur-bolditalic' : [ 'Fraktur-Regular' , 'ML__frak' ] , 'monospace' : [ 'Typewriter-Regular' , 'ML__tt' ] , 'monospace-bold' : [ 'Typewriter-Regular' , 'ML__tt ML__bold' ] , 'monospace-italic' : [ 'Typewriter-Regular' , 'ML__tt ML__it' ] , 'monospace-bolditalic' : [ 'Typewriter-Regular' , 'ML__tt ML__bold ML__it' ] , 'double-struck' : [ 'AMS-Regular' , 'ML__bb' ] , 'double-struck-bold' : [ 'AMS-Regular' , 'ML__bb' ] , 'double-struck-italic' : [ 'AMS-Regular' , 'ML__bb' ] , 'double-struck-bolditalic' : [ 'AMS-Regular' , 'ML__bb' ] , } ; const VARIANT_REPERTOIRE = { 'double-struck' : /^[A-Z ]$/ , 'script' : /^[A-Z ]$/ , 'calligraphic' : /^[\dA-Z ]$/ , 'fraktur' : /^[\dA-Za-z ]$|^[!"#$%&'()*+,\-./:;=?[]^’‘]$/ , 'monospace' : /^[\dA-Za-z ]$|^[!"&'()*+,\-./:;=?@[\]^_~\u0131\u0237\u0393\u0394\u0398\u039B\u039E\u03A0\u03A3\u03A5\u03A8\u03A9]$/ , 'sans-serif' : /^[\dA-Za-z ]$|^[!"&'()*+,\-./:;=?@[\]^_~\u0131\u0237\u0393\u0394\u0398\u039B\u039E\u03A0\u03A3\u03A5\u03A8\u03A9]$/ , } ; const GREEK_LOWERCASE = /^[\u03B1-\u03C9]|\u03D1|\u03D5|\u03D6|\u03F1|\u03F5]$/ ; const GREEK_UPPERCASE = /^[\u0393|\u0394\u0398\u039B\u039E\u03A0\u03A3\u03A5\u03A6\u03A8\u03A9]$/ ; const LETTER_SHAPE_RANGES = [ /^[a-z]$/ , /^[A-Z]$/ , GREEK_LOWERCASE , GREEK_UPPERCASE , ] ; const LETTER_SHAPE_MODIFIER = { iso : [ 'it' , 'it' , 'it' , 'it' ] , tex : [ 'it' , 'it' , 'it' , 'up' ] , french : [ 'it' , 'up' , 'up' , 'up' ] , upright : [ 'up' , 'up' , 'up' , 'up' ] , } ; export class MathMode extends Mode { constructor ( ) { super ( 'math' ) ; } createAtom ( command , style ) { const info = getInfo ( command , 'math' ) ; const result = new Atom ( info ?. type ?? 'mord' , { mode : 'math' , command , value : info ?. codepoint ? String . fromCodePoint ( info ?. codepoint ) : command , style , } ) ; if ( info ?. isFunction ?? false ) { result . isFunction = true ; } if ( command . startsWith ( '\\' ) ) { result . verbatimLatex = command ; } return result ; } serialize ( run , options ) { const { parent } = run [ 0 ] ; const contextFontsize = parent ?. computedStyle . fontSize ; return joinLatex ( getPropertyRuns ( run , 'fontSize' ) . map ( ( x ) => { const result = this . emitBackgroundColorRun ( x , options ) ; const fontsize = x [ 0 ] . computedStyle . fontSize ; if ( fontsize && ( ! parent || contextFontsize !== fontsize ) ) { return ( '\\' + [ '' , 'tiny' , 'scriptsize' , 'footnotesize' , 'small' , 'normalsize' , 'large' , 'Large' , 'LARGE' , 'huge' , 'Huge' , ] [ fontsize ] + ' ' + result ) ; } return result ; } ) ) ; } emitBackgroundColorRun ( run , options ) { const { parent } = run [ 0 ] ; const parentColor = parent ?. computedStyle . backgroundColor ; return joinLatex ( getPropertyRuns ( run , 'backgroundColor' ) . map ( ( x ) => { let result = this . emitColorRun ( x , options ) ; const style = x [ 0 ] . computedStyle ; if ( style . backgroundColor && ( ! parent || parentColor !== style . backgroundColor ) && ( x . length > 0 || ! ( x [ 0 ] instanceof BoxAtom ) ) ) { if ( options . defaultMode === 'inline-math' ) { result = `\\( ${ result } \\)` ; } else { result = `\\[ ${ result } \\]` ; } result = `\\colorbox{${ style . verbatimBackgroundColor ?? style . backgroundColor }}{${ result }}` ; } return result ; } ) ) ; } emitColorRun ( run , options ) { const { parent } = run [ 0 ] ; const parentMode = parent ?. mode ?? 'math' ; const contextVariant = variantString ( parent ! ) ; const contextColor = parent ?. computedStyle . color ; return joinLatex ( getPropertyRuns ( run , 'color' ) . map ( ( x ) => { const result = joinLatex ( getPropertyRuns ( x , 'variant' ) . map ( ( x ) => { const variant = variantString ( x [ 0 ] ) ; if ( x . every ( ( x ) => { const info = getInfo ( x . command ! , parentMode ) ; if ( ! info || ! info . variant ) return false ; return variantString ( x ) === variant ; } ) ) { return joinLatex ( x . map ( ( x ) => Atom . serialize ( x , options ) ) ) ; } let command = '' ; if ( variant && variant !== contextVariant ) { command = { 'calligraphic' : '\\mathcal{' , 'fraktur' : '\\mathfrak{' , 'double-struck' : '\\mathbb{' , 'script' : '\\mathscr{' , 'monospace' : '\\mathtt{' , 'sans-serif' : '\\mathsf{' , 'normal' : '\\mathrm{' , 'normal-italic' : '\\mathit{' , 'normal-bold' : '\\mathbf{' , 'normal-bolditalic' : '\\mathbfit{' , 'ams' : '' , 'ams-italic' : '\\mathit{' , 'ams-bold' : '\\mathbf{' , 'ams-bolditalic' : '\\mathbfit{' , 'main' : '' , 'main-italic' : '\\mathit{' , 'main-bold' : '\\mathbf{' , 'main-bolditalic' : '\\mathbfit{' , } [ variant ! ] ! ; console . assert ( command !== undefined ) ; } return ( joinLatex ( [ command , ... x . map ( ( x ) => Atom . serialize ( x , options ) ) , ] ) + ( command ? '}' : '' ) ) ; } ) ) ; const style = x [ 0 ] . computedStyle ; if ( style . color && ( ! parent || contextColor !== style . color ) ) { return ( '\\textcolor{' + ( style . verbatimColor ?? style . color ) + '}{' + result + '}' ) ; } return result ; } ) ) ; } applyStyle ( box , style ) { if ( style . variant === undefined ) return '' ; const letterShapeStyle = style . letterShapeStyle === 'auto' || ! style . letterShapeStyle ? 'tex' : style . letterShapeStyle ; let { variant } = style ; let { variantStyle } = style ; if ( variant === 'normal' && ! variantStyle && /[\u00A3\u0131\u0237]/ . test ( box . value ) ) { variant = 'main' ; variantStyle = 'italic' ; } if ( variant === 'normal' && ! variantStyle && box . value . length === 1 ) { LETTER_SHAPE_RANGES . forEach ( ( x , i ) => { if ( x . test ( box . value ) && LETTER_SHAPE_MODIFIER [ letterShapeStyle ] [ i ] === 'it' ) { variantStyle = 'italic' ; } } ) ; } if ( variantStyle === 'up' ) { variantStyle = undefined ; } const styledVariant = variantStyle ? variant + '-' + variantStyle : variant ; console . assert ( VARIANTS [ styledVariant ] !== undefined ) ; const [ fontName , classes ] = VARIANTS [ styledVariant ] ; if ( VARIANT_REPERTOIRE [ variant ] && ! VARIANT_REPERTOIRE [ variant ] . test ( box . value ) ) { box . value = mathVariantToUnicode ( box . value , variant , variantStyle ) ; return null ; } if ( GREEK_LOWERCASE . test ( box . value ) ) { box . classes += ' lcGreek' ; } if ( classes ) { box . classes += ' ' + classes ; } return fontName ; } } function variantString ( atom ) { if ( ! atom ) return '' ; const { style } = atom ; if ( style . variant === undefined ) return '' ; let result = style . variant ; if ( style . variantStyle && style . variantStyle !== 'up' ) { result += '-' + style . variantStyle ; } return result ; } new MathMode ( ) ;