Skip to content

Commit 119fb6b

Browse files
authored
Merge pull request #1060 from mathjax/issue3184
Fix handling of _ and ^ followed by command that doesn't push content (mathjax/MathJax#3184)
2 parents dcef69d + d1a0907 commit 119fb6b

File tree

13 files changed

+54
-15
lines changed

13 files changed

+54
-15
lines changed

ts/input/tex/Stack.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ export default class Stack {
9999
this.Push(...top);
100100
continue;
101101
}
102-
this.stack.push(item);
102+
if (!item.isKind('null')) {
103+
this.stack.push(item);
104+
}
103105
if (item.env) {
104106
if (item.copyEnv) {
105107
Object.assign(item.env, this.env);

ts/input/tex/StackItem.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ export abstract class BaseItem extends MmlStack implements StackItem {
414414
/**
415415
* @return {string} The type of the stack item.
416416
*/
417-
public get kind(): string {
417+
public get kind(): string {
418418
return 'base';
419419
}
420420

ts/input/tex/TexParser.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -570,11 +570,13 @@ export default class TexParser {
570570
}
571571
// These are the cases to handle sub and superscripts.
572572
if (node.attributes.get(TexConstant.Attr.LATEX) === '^' &&
573-
str !== '^' && str !== '\\^') {
574-
if (str === '}') {
575-
this.composeBraces(node.childNodes[2]);
576-
} else {
577-
node.childNodes[2].attributes.set(TexConstant.Attr.LATEX, str);
573+
str !== '^' && str !== '\\^') {
574+
if (node.childNodes[2]) {
575+
if (str === '}') {
576+
this.composeBraces(node.childNodes[2]);
577+
} else {
578+
node.childNodes[2].attributes.set(TexConstant.Attr.LATEX, str);
579+
}
578580
}
579581
if (node.childNodes[1]) {
580582
const sub = node.childNodes[1].attributes.get(TexConstant.Attr.LATEX);
@@ -585,11 +587,13 @@ export default class TexParser {
585587
return;
586588
}
587589
if (node.attributes.get(TexConstant.Attr.LATEX) === '_' &&
588-
str !== '_' && str !== '\\_') {
589-
if (str === '}') {
590-
this.composeBraces(node.childNodes[1]);
591-
} else {
592-
node.childNodes[1].attributes.set(TexConstant.Attr.LATEX, str);
590+
str !== '_' && str !== '\\_') {
591+
if (node.childNodes[1]) {
592+
if (str === '}') {
593+
this.composeBraces(node.childNodes[1]);
594+
} else {
595+
node.childNodes[1].attributes.set(TexConstant.Attr.LATEX, str);
596+
}
593597
}
594598
if (node.childNodes[2]) {
595599
const sub = node.childNodes[2].attributes.get(TexConstant.Attr.LATEX);
@@ -616,6 +620,7 @@ export default class TexParser {
616620
*/
617621
private composeLatex(
618622
node: MmlNode, comp: string, pos1: number, pos2: number) {
623+
if (!node.childNodes[pos1] || !node.childNodes[pos2]) return;
619624
const expr = node.childNodes[pos1].attributes.get(TexConstant.Attr.LATEX) + comp +
620625
node.childNodes[pos2].attributes.get(TexConstant.Attr.LATEX);
621626
node.attributes.set(TexConstant.Attr.LATEX, expr);

ts/input/tex/ams/AmsMethods.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ AmsMethods.HandleDeclareOp = function (parser: TexParser, name: string) {
220220
let op = parser.GetArgument(name);
221221
(parser.configuration.handlers.retrieve(NEW_OPS) as CommandMap).
222222
add(cs, new Macro(cs, AmsMethods.Macro, [`\\operatorname${star}{${op}}`]));
223+
parser.Push(parser.itemFactory.create('null'));
223224
};
224225

225226

@@ -586,6 +587,7 @@ AmsMethods.HandleTag = function(parser: TexParser, name: string) {
586587
let star = parser.GetStar();
587588
let tagId = ParseUtil.trimSpaces(parser.GetArgument(name));
588589
parser.tags.tag(tagId, star);
590+
parser.Push(parser.itemFactory.create('null'));
589591
};
590592

591593

ts/input/tex/base/BaseConfiguration.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ export const BaseConfiguration: Configuration = Configuration.create(
168168
[bitem.StopItem.prototype.kind]: bitem.StopItem,
169169
[bitem.OpenItem.prototype.kind]: bitem.OpenItem,
170170
[bitem.CloseItem.prototype.kind]: bitem.CloseItem,
171+
[bitem.NullItem.prototype.kind]: bitem.NullItem,
171172
[bitem.PrimeItem.prototype.kind]: bitem.PrimeItem,
172173
[bitem.SubsupItem.prototype.kind]: bitem.SubsupItem,
173174
[bitem.OverItem.prototype.kind]: bitem.OverItem,

ts/input/tex/base/BaseItems.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,18 @@ export class CloseItem extends BaseItem {
176176

177177
}
178178

179+
/**
180+
* Item pushed when a macro doesn't produce any output.
181+
*/
182+
export class NullItem extends BaseItem {
183+
/**
184+
* @override
185+
*/
186+
public get kind() {
187+
return 'null';
188+
}
189+
}
190+
179191

180192
/**
181193
* Item indicating an we are currently dealing with a prime mark.

ts/input/tex/base/BaseMethods.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,7 @@ BaseMethods.Prime = function(parser: TexParser, c: string) {
268268
} while (c === '\'' || c === entities.rsquo);
269269
sup = ['', '\u2032', '\u2033', '\u2034', '\u2057'][sup.length] || sup;
270270
const node = parser.create('token', 'mo', {variantForm: true}, sup);
271-
parser.Push(
272-
parser.itemFactory.create('prime', base, node) );
271+
parser.Push(parser.itemFactory.create('prime', base, node));
273272
};
274273

275274

@@ -327,6 +326,7 @@ BaseMethods.MathFont = function(parser: TexParser, name: string, variant: string
327326
*/
328327
BaseMethods.SetFont = function(parser: TexParser, _name: string, font: string) {
329328
parser.stack.env['font'] = font;
329+
parser.Push(parser.itemFactory.create('null'));
330330
};
331331

332332
/**
@@ -811,6 +811,7 @@ BaseMethods.VBox = function(parser: TexParser, name: string, align: string) {
811811
BaseMethods.Hsize = function (parser: TexParser, name: string) {
812812
parser.GetNext() === '=' && parser.i++;
813813
parser.stack.env.hsize = parser.GetDimen(name);
814+
parser.Push(parser.itemFactory.create('null'));
814815
};
815816

816817
/**
@@ -1538,10 +1539,11 @@ BaseMethods.NewColumnType = function (parser: TexParser, name: string) {
15381539
throw new TexError('BadColumnName', 'Column specifier must be exactly one character: %1', c);
15391540
}
15401541
if (!n.match(/^\d+$/)) {
1541-
throw new TexError('PositiveIntegerArg', 'Argument to %1 must me a positive integer', n);
1542+
throw new TexError('PositiveIntegerArg', 'Argument to %1 must be a positive integer', n);
15421543
}
15431544
const cparser = parser.configuration.columnParser;
15441545
cparser.columnHandler[c] = (state: ColumnState) => cparser.macroColumn(state, macro, parseInt(n));
1546+
parser.Push(parser.itemFactory.create('null'));
15451547
}
15461548

15471549

ts/input/tex/color/ColorMethods.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ ColorMethods.DefineColor = function (parser: TexParser, name: string) {
112112

113113
const colorModel: ColorModel = parser.configuration.packageData.get('color').model;
114114
colorModel.defineColor(model, cname, def);
115+
parser.Push(parser.itemFactory.create('null'));
115116
};
116117

117118
/**

ts/input/tex/extpfeil/ExtpfeilConfiguration.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ ExtpfeilMethods.NewExtArrow = function(parser: TexParser, name: string) {
6767
let spaces = space.split(',');
6868
NewcommandUtil.addMacro(parser, cs, ExtpfeilMethods.xArrow,
6969
[parseInt(chr), parseInt(spaces[0]), parseInt(spaces[1])]);
70+
parser.Push(parser.itemFactory.create('null'));
7071
};
7172

7273

ts/input/tex/mathtools/MathtoolsMethods.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ export const MathtoolsMethods: Record<string, ParseMethod> = {
516516
const open = parser.GetArgument(name);
517517
const close = parser.GetArgument(name);
518518
MathtoolsUtil.addPairedDelims(parser.configuration, cs, [open, close]);
519+
parser.Push(parser.itemFactory.create('null'));
519520
},
520521

521522
/**
@@ -531,6 +532,7 @@ export const MathtoolsMethods: Record<string, ParseMethod> = {
531532
const close = parser.GetArgument(name);
532533
const body = parser.GetArgument(name);
533534
MathtoolsUtil.addPairedDelims(parser.configuration, cs, [open, close, body, n]);
535+
parser.Push(parser.itemFactory.create('null'));
534536
},
535537

536538
/**
@@ -548,6 +550,7 @@ export const MathtoolsMethods: Record<string, ParseMethod> = {
548550
const post = parser.GetArgument(name);
549551
const body = parser.GetArgument(name);
550552
MathtoolsUtil.addPairedDelims(parser.configuration, cs, [open, close, body, n, pre, post]);
553+
parser.Push(parser.itemFactory.create('null'));
551554
},
552555

553556
/**
@@ -711,6 +714,7 @@ export const MathtoolsMethods: Record<string, ParseMethod> = {
711714
throw new TexError('DuplicateTagForm', 'Duplicate tag form: %1', id);
712715
}
713716
tags.mtFormats.set(id, [left, right, format]);
717+
parser.Push(parser.itemFactory.create('null'));
714718
},
715719

716720
/**
@@ -727,12 +731,14 @@ export const MathtoolsMethods: Record<string, ParseMethod> = {
727731
const id = parser.GetArgument(name).trim();
728732
if (!id) {
729733
tags.mtCurrent = null;
734+
parser.Push(parser.itemFactory.create('null'));
730735
return;
731736
}
732737
if (!tags.mtFormats.has(id)) {
733738
throw new TexError('UndefinedTagForm', 'Undefined tag form: %1', id);
734739
}
735740
tags.mtCurrent = tags.mtFormats.get(id);
741+
parser.Push(parser.itemFactory.create('null'));
736742
},
737743

738744
/**
@@ -757,6 +763,7 @@ export const MathtoolsMethods: Record<string, ParseMethod> = {
757763
for (const id of Object.keys(keys)) {
758764
options[id] = keys[id];
759765
}
766+
parser.Push(parser.itemFactory.create('null'));
760767
},
761768

762769
/**

0 commit comments

Comments
 (0)