Skip to content

Commit

Permalink
Merge pull request #998 from mathjax/issue3095
Browse files Browse the repository at this point in the history
Set TeX class OP for multi-letter mo elements, as in v2.  (mathjax/MathJax#3095)
  • Loading branch information
dpvc committed Sep 15, 2023
2 parents 4d2f170 + 8f43fb6 commit ec419a0
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 36 deletions.
70 changes: 40 additions & 30 deletions ts/core/MmlTree/MmlNodes/mo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {PropertyList} from '../../Tree/Node.js';
import {AbstractMmlTokenNode, MmlNode, AttributeList, TEXCLASS} from '../MmlNode.js';
import {MmlMrow} from './mrow.js';
import {MmlMover, MmlMunder, MmlMunderover} from './munderover.js';
import {OperatorList, OPTABLE, getRange, MMLSPACING} from '../OperatorDictionary.js';
import {OperatorList, OPTABLE, OPDEF, getRange, MMLSPACING} from '../OperatorDictionary.js';
import {unicodeChars, unicodeString} from '../../../util/string.js';

/*****************************************************************/
Expand Down Expand Up @@ -101,6 +101,11 @@ export class MmlMo extends AbstractMmlTokenNode {
']+$'
].join(''));

/**
* Pattern to use to identify a multiletter operator
*/
protected static opPattern = /^[a-zA-Z]{2,}$/;

/**
* Default map for remapping prime characters
*/
Expand Down Expand Up @@ -150,11 +155,7 @@ export class MmlMo extends AbstractMmlTokenNode {
*/
public get texClass() {
if (this._texClass === null) {
let mo = this.getText();
let [form1, form2, form3] = this.handleExplicitForm(this.getForms());
let OPTABLE = (this.constructor as typeof MmlMo).OPTABLE;
let def = OPTABLE[form1][mo] || OPTABLE[form2][mo] || OPTABLE[form3][mo];
return def ? def[2] : TEXCLASS.REL;
return this.getOperatorDef(this.getText())[2];
}
return this._texClass;
}
Expand Down Expand Up @@ -348,35 +349,44 @@ export class MmlMo extends AbstractMmlTokenNode {
}

/**
* Set the attributes from the operator table
* get the operator definition from the operator table
*
* @param {string} mo The test of the mo element
* @param {string} mo The text of the mo element
*/
protected checkOperatorTable(mo: string) {
let [form1, form2, form3] = this.handleExplicitForm(this.getForms());
protected getOperatorDef(mo: string) {
const [form1, form2, form3] = this.handleExplicitForm(this.getForms());
this.attributes.setInherited('form', form1);
let OPTABLE = (this.constructor as typeof MmlMo).OPTABLE;
let def = OPTABLE[form1][mo] || OPTABLE[form2][mo] || OPTABLE[form3][mo];
const CLASS = this.constructor as typeof MmlMo
const OPTABLE = CLASS.OPTABLE;
const def = OPTABLE[form1][mo] || OPTABLE[form2][mo] || OPTABLE[form3][mo];
if (def) {
if (this.getProperty('texClass') === undefined) {
this.texClass = def[2];
}
for (const name of Object.keys(def[3] || {})) {
this.attributes.setInherited(name, def[3][name]);
}
this.lspace = (def[0] + 1) / 18;
this.rspace = (def[1] + 1) / 18;
} else {
let range = getRange(mo);
if (range) {
if (this.getProperty('texClass') === undefined) {
this.texClass = range[2];
}
const spacing = (this.constructor as typeof MmlMo).MMLSPACING[range[2]];
this.lspace = (spacing[0] + 1) / 18;
this.rspace = (spacing[1] + 1) / 18;
}
return def;
}
const limits = this.attributes.get('movablelimits');
const isOP = !!mo.match(CLASS.opPattern);
if ((isOP || limits) && this.getProperty('texClass') === undefined) {
return OPDEF(1, 2, TEXCLASS.OP);
}
const range = getRange(mo);
const [l, r] = CLASS.MMLSPACING[range[2]];
return OPDEF(l, r, range[2]);
}

/**
* Set the attributes from the operator table
*
* @param {string} mo The text of the mo element
*/
protected checkOperatorTable(mo: string) {
const def = this.getOperatorDef(mo);
if (this.getProperty('texClass') === undefined) {
this.texClass = def[2];
}
for (const name of Object.keys(def[3] || {})) {
this.attributes.setInherited(name, def[3][name]);
}
this.lspace = (def[0] + 1) / 18;
this.rspace = (def[1] + 1) / 18;
}

/**
Expand Down
8 changes: 4 additions & 4 deletions ts/core/MmlTree/OperatorDictionary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,10 @@ export const RANGES: RangeDef[] = [
/**
* Get the Unicode range for the first character of a string
*
* @param {string} text The character to check
* @return {RangeDef|null} The range containing that character, or null
* @param {string} text The character to check
* @return {RangeDef} The range containing that character, or null
*/
export function getRange(text: string): RangeDef | null {
export function getRange(text: string): RangeDef {
const n = text.codePointAt(0);
for (const range of RANGES) {
if (n <= range[1]) {
Expand All @@ -149,7 +149,7 @@ export function getRange(text: string): RangeDef | null {
break;
}
}
return null;
return [0, 0, TEXCLASS.REL, 'mo'];
}

/**
Expand Down
4 changes: 2 additions & 2 deletions ts/input/tex/base/BaseConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ export function Other(parser: TexParser, char: string) {
{mathvariant: parser.stack.env['font']} : {};
const remap = (MapHandler.getMap('remap') as CharacterMap).lookup(char);
const range = getRange(char);
const type = (range ? range[3] : 'mo');
const type = range[3]
// @test Other
// @test Other Remap
let mo = parser.create('token', type, def, (remap ? remap.char : char));
const variant = (range?.[4] ||
const variant = (range[4] ||
(ParseUtil.isLatinOrGreekChar(char) ? parser.configuration.mathStyle(char, true) : ''));
if (variant) {
mo.attributes.set('mathvariant', variant);
Expand Down

0 comments on commit ec419a0

Please sign in to comment.