Skip to content

Commit

Permalink
Update \operatorname to work more like in LaTeX. (mathjax/MathJax#2830)
Browse files Browse the repository at this point in the history
  • Loading branch information
dpvc committed Feb 23, 2022
1 parent 6d286c2 commit a7ed394
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 25 deletions.
7 changes: 4 additions & 3 deletions ts/input/tex/ParseMethods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ namespace ParseMethods {
export function variable(parser: TexParser, c: string) {
// @test Identifier Font
const def = ParseUtil.getFontDef(parser);
if (parser.stack.env.multiLetterIdentifiers && parser.stack.env.font !== '') {
c = parser.string.substr(parser.i - 1).match(/^[a-z]+/i)[0];
const env = parser.stack.env;
if (env.multiLetterIdentifiers && env.font !== '') {
c = parser.string.substr(parser.i - 1).match(env.multiLetterIdentifiers as RegExp)[0];
parser.i += c.length - 1;
if (def.mathvariant === TexConstant.Variant.NORMAL) {
if (def.mathvariant === TexConstant.Variant.NORMAL && env.noAutoOP && c.length > 1) {
def.autoOP = false;
}
}
Expand Down
2 changes: 1 addition & 1 deletion ts/input/tex/StackItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import TexError from './TexError.js';
import StackItemFactory from './StackItemFactory.js';

// Union types for abbreviation.
export type EnvProp = string | number | boolean;
export type EnvProp = string | number | boolean | RegExp;

export type EnvList = {[key: string]: EnvProp};

Expand Down
1 change: 1 addition & 0 deletions ts/input/tex/ams/AmsConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ let init = function(config: ParserConfiguration) {
export const AmsConfiguration = Configuration.create(
'ams', {
handler: {
character: ['AMSmath-operatorLetter'],
delimiter: ['AMSsymbols-delimiter', 'AMSmath-delimiter'],
macro: ['AMSsymbols-mathchar0mi', 'AMSsymbols-mathchar0mo',
'AMSsymbols-delimiter', 'AMSsymbols-macros',
Expand Down
4 changes: 4 additions & 0 deletions ts/input/tex/ams/AmsMappings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ new sm.CharacterMap('AMSmath-mathchar0mo', ParseMethods.mathchar0mo, {
iiiint: ['\u2A0C', {texClass: TEXCLASS.OP}]
});

/**
* Extra characters that are letters in \operatorname
*/
new sm.RegExpMap('AMSmath-operatorLetter', AmsMethods.operatorLetter, /[-*]/i);

/**
* Macros from the AMS Math package.
Expand Down
57 changes: 37 additions & 20 deletions ts/input/tex/ams/AmsMethods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import {StackItem} from '../StackItem.js';
import {ParseMethod} from '../Types.js';
import ParseUtil from '../ParseUtil.js';
import ParseMethods from '../ParseMethods.js';
import NodeUtil from '../NodeUtil.js';
import {TexConstant} from '../TexConstants.js';
import TexParser from '../TexParser.js';
Expand Down Expand Up @@ -202,17 +203,14 @@ export const NEW_OPS = 'ams-declare-ops';
* @param {string} name The macro name.
*/
AmsMethods.HandleDeclareOp = function (parser: TexParser, name: string) {
let limits = (parser.GetStar() ? '' : '\\nolimits\\SkipLimits');
let star = (parser.GetStar() ? '*' : '');
let cs = ParseUtil.trimSpaces(parser.GetArgument(name));
if (cs.charAt(0) === '\\') {
cs = cs.substr(1);
}
let op = parser.GetArgument(name);
if (!op.match(/\\text/)) {
op = op.replace(/\*/g, '\\text{*}').replace(/-/g, '\\text{-}');
}
(parser.configuration.handlers.retrieve(NEW_OPS) as CommandMap).
add(cs, new Macro(cs, AmsMethods.Macro, ['\\mathop{\\rm ' + op + '}' + limits]));
add(cs, new Macro(cs, AmsMethods.Macro, [`\\operatorname${star}{${op}}`]));
};


Expand All @@ -223,28 +221,47 @@ AmsMethods.HandleDeclareOp = function (parser: TexParser, name: string) {
*/
AmsMethods.HandleOperatorName = function(parser: TexParser, name: string) {
// @test Operatorname
const limits = (parser.GetStar() ? '' : '\\nolimits\\SkipLimits');
const star = parser.GetStar();
//
// Parse the argument using operator letters and grouping multiple letters.
//
let op = ParseUtil.trimSpaces(parser.GetArgument(name));
if (!op.match(/\\text/)) {
op = op.replace(/\*/g, '\\text{*}').replace(/-/g, '\\text{-}');
let mml = new TexParser(op, {
...parser.stack.env,
font: TexConstant.Variant.NORMAL,
multiLetterIdentifiers: /^[-*a-z]+/i,
operatorLetters: true
}, parser.configuration).mml();
//
// If we get something other than a single mi, wrap in a TeXAtom.
//
if (!mml.isKind('mi')) {
mml = parser.create('node', 'TeXAtom', [mml]);
}
parser.string = '\\mathop{\\rm ' + op + '}' + limits + ' ' +
parser.string.slice(parser.i);
parser.i = 0;
//
// Mark the limit properties and the TeX class.
//
NodeUtil.setProperties(mml, {movesupsub: star, movablelimits: true, texClass: TEXCLASS.OP});
//
// Skip a following \limits macro if not a starred operator
//
if (!star) {
const c = parser.GetNext(), i = parser.i;
if (c === '\\' && ++parser.i && parser.GetCS() !== 'limits') {
parser.i = i;
}
}
//
parser.Push(mml);
};


/**
* Handle SkipLimits.
* Handle extra letters in \operatorname (- and *), default to normal otherwise.
* @param {TexParser} parser The calling parser.
* @param {string} name The macro name.
* @param {string} c The letter being checked
*/
AmsMethods.SkipLimits = function(parser: TexParser, _name: string) {
// @test Operatorname
const c = parser.GetNext(), i = parser.i;
if (c === '\\' && ++parser.i && parser.GetCS() !== 'limits') {
parser.i = i;
}
AmsMethods.operatorLetter = function (parser: TexParser, c: string) {
return parser.stack.env.operatorLetters ? ParseMethods.variable(parser, c) : false;
};


Expand Down
3 changes: 2 additions & 1 deletion ts/input/tex/base/BaseMethods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,8 @@ BaseMethods.MathFont = function(parser: TexParser, name: string, variant: string
let mml = new TexParser(text, {
...parser.stack.env,
font: variant,
multiLetterIdentifiers: true
multiLetterIdentifiers: /^[a-z]+/i,
noAutoOP: true
}, parser.configuration).mml();
parser.Push(parser.create('node', 'TeXAtom', [mml]));
};
Expand Down

0 comments on commit a7ed394

Please sign in to comment.