mathlive
Version:
Render and edit beautifully typeset math
261 lines (232 loc) • 7.69 kB
JavaScript
const SPECIAL_IDENTIFIERS = {
'\u2212': '-', // MINUS SIGN
'-': '-',
'\\alpha': 'alpha',
'\\beta': 'beta',
'\\gamma': 'gamma',
'\\delta': 'delta',
'\\epsilon': 'epsilon',
'\\varepsilon': 'varepsilon',
'\\zeta': 'zeta',
'\\eta': 'eta',
'\\theta': 'theta',
'\\vartheta': 'vartheta',
'\\iota': 'iota',
'\\kappa': 'kappa',
'\\lambda': 'lambda',
'\\mu': 'mu',
'\\nu': 'nu',
'\\xi': 'xi',
'\\pi': 'pi',
'\\rho': 'rho',
'\\sigma': 'sigma',
'\\tau': 'tau',
'\\upsilon': 'upsilon',
'\\phi': 'phi',
'\\varphi': 'varphi',
'\\chi': 'chi',
'\\psi': 'psi',
'\\omega': 'omega',
'\\Gamma': 'Gamma',
'\\Delta': 'Delta',
'\\Theta': 'Theta',
'\\Lambda': 'Lambda',
'\\Xi': 'Xi',
'\\Pi': 'Pi',
'\\Sigma': 'Sigma',
'\\Phi': 'Phi',
'\\Psi': 'Psi',
'\\Omega': 'Omega',
};
const SPECIAL_OPERATORS = {
'\\pm': '+-',
'\\times': 'xx',
'\\colon': ':',
'\\vert': '|',
'\\Vert': '||',
'\\mid': '|',
'\\lbrace': '{',
'\\rbrace': '}',
'\\langle': '(:',
'\\rangle': ':)',
// '\\lfloor': '\u230a',
// '\\rfloor': '\u230b',
// '\\lceil': '\u2308',
// '\\rceil': '\u2309',
// '\\vec': '⃗',
// '\\acute': '´',
// '\\grave': '`',
// '\\dot': '˙',
// '\\ddot': '¨',
// '\\tilde': '~',
// '\\bar': '¯',
// '\\breve': '˘',
// '\\check': 'ˇ',
// '\\hat': '^'
};
export function toASCIIMath(atom, options){
if (!atom) return '';
if (Array.isArray(atom)) {
let result = '';
if (atom.length === 0) return '';
if (atom[0].type === 'first') atom.shift();
if (atom[0].mode === 'text') {
// Text mode... put it in (ASCII) quotes
let i = 0;
result = '"';
while (atom[i] && atom[i].mode === 'text') {
result += atom[i].body;
i++;
}
result += '"' + toASCIIMath(atom.slice(i), options);
} else {
let i = 0;
while (atom[i] && atom[i].mode === 'math') {
result += toASCIIMath(atom[i], options);
i++;
}
result += toASCIIMath(atom.slice(i), options);
}
return result.trim();
}
let result = '';
const command = atom.latex ? atom.latex.trim() : null;
let m;
switch(atom.type) {
case 'group':
case 'root':
result = toASCIIMath(atom.body, options);
break;
case 'array':
break;
case 'genfrac':
if (atom.leftDelim || atom.rightDelim) {
result += (atom.leftDelim === '.' || !atom.leftDelim) ? '{:' : atom.leftDelim;
}
if (atom.hasBarLine) {
result += '(';
result += toASCIIMath(atom.numer, options);
result += ')/(';
result += toASCIIMath(atom.denom, options);
result += ')';
} else {
// No bar line, i.e. \choose, etc...
result += '(' + toASCIIMath(atom.numer, options) + '),';
result += '(' + toASCIIMath(atom.denom, options) + ')';
}
if (atom.leftDelim || atom.rightDelim) {
result += (atom.rightDelim === '.' || !atom.rightDelim) ? '{:' : atom.rightDelim;
}
break;
case 'surd':
if (atom.index) {
result += 'root(' + toASCIIMath(atom.index, options) + ')(' +
toASCIIMath(atom.body, options) + ')';
} else {
result += 'sqrt(' + toASCIIMath(atom.body, options) + ')';
}
break;
case 'leftright':
result += (atom.leftDelim === '.' || !atom.leftDelim) ? '{:' : atom.leftDelim;
result += toASCIIMath(atom.body, options);
result += (atom.rightDelim === '.' || !atom.rightDelim) ? '{:' : atom.rightDelim;
break;
case 'sizeddelim':
case 'delim':
// result += '<mo separator="true"' + makeID(atom.id, options) + '>' + (SPECIAL_OPERATORS[atom.delim] || atom.delim) + '</mo>';
break;
case 'accent':
break;
case 'line':
case 'overlap':
break;
case 'overunder':
break;
case 'mord':
// @todo, deal with some special identifiers: \alpha, etc...
result = SPECIAL_IDENTIFIERS[command] || command ||
(typeof atom.body === 'string' ? atom.body : '');
if (result[0] === '\\') result += '';
m = command ? command.match(/[{]?\\char"([0-9abcdefABCDEF]*)[}]?/) : null;
if (m) {
// It's a \char command
result = String.fromCharCode(parseInt('0x' + m[1]))
} else if (result.length > 0 && result.charAt(0) === '\\') {
// atom is an identifier with no special handling. Use the
// Unicode value
if (typeof atom.body === 'string') {
result = atom.body.charAt(0);
} else {
result = atom.latex;
}
}
// result = '<mi' + variant + makeID(atom.id, options) + '>' + xmlEscape(result) + '</mi>';
break;
case 'mbin':
case 'mrel':
case 'textord':
case 'minner':
if (command && SPECIAL_IDENTIFIERS[command]) {
// Some 'textord' are actually identifiers. Check them here.
result = SPECIAL_IDENTIFIERS[command];
} else if (command && SPECIAL_OPERATORS[command]) {
result = SPECIAL_OPERATORS[command];
} else {
result = atom.body;
}
break;
case 'mopen':
case 'mclose':
result += atom.body;
break;
case 'mpunct':
result = SPECIAL_OPERATORS[command] || command;
break;
case 'mop':
if (atom.body !== '\u200b') {
// Not ZERO-WIDTH
result = '';
if (command === '\\operatorname') {
result += atom.body;
} else {
result += atom.body || command;
}
result += ' ';
}
break;
case 'mathstyle':
break;
case 'box':
break;
case 'spacing':
break;
case 'enclose':
break;
case 'space':
result = ' '
break;
}
// Subscripts before superscripts (according to the ASCIIMath spec)
if (atom.subscript) {
result += '_';
const arg = toASCIIMath(atom.subscript, options);
if (arg.length > 1 && !/^(-)?\d+(\.\d*)?$/.test(arg)) {
result += '(' + arg + ')'
} else {
result += arg;
}
}
if (atom.superscript) {
result += '^';
const arg = toASCIIMath(atom.superscript, options);
if (arg.length > 1 && !/^(-)?\d+(\.\d*)?$/.test(arg)) {
result += '(' + arg + ')'
} else {
result += arg;
}
}
return result;
}
export default {
toASCIIMath
}