-
Notifications
You must be signed in to change notification settings - Fork 239
Expand file tree
/
Copy pathMathtoolsUtil.ts
More file actions
165 lines (156 loc) · 5.43 KB
/
MathtoolsUtil.ts
File metadata and controls
165 lines (156 loc) · 5.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*************************************************************
* Copyright (c) 2021-2025 MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file Utility functions for the mathtools package.
*
* @author dpvc@mathjax.org (Davide P. Cervone)
*/
import { EqnArrayItem } from '../base/BaseItems.js';
import { UnitUtil } from '../UnitUtil.js';
import TexParser from '../TexParser.js';
import TexError from '../TexError.js';
import { lookup } from '../../../util/Options.js';
import { MmlNode } from '../../../core/MmlTree/MmlNode.js';
import { HandlerType } from '../HandlerTypes.js';
import { NewcommandUtil } from '../newcommand/NewcommandUtil.js';
import { MathtoolsMethods } from './MathtoolsMethods.js';
/**
* Utility functions for the Mathtools package.
*/
export const MathtoolsUtil = {
/**
* Set the displaystyle and scriptlevel attributes of an mstyle element
*
* @param {MmlNode} mml The mstyle node to modify.
* @param {string} style The TeX style macro to apply.
*/
setDisplayLevel(mml: MmlNode, style: string) {
if (!style) return;
const [display, script] = lookup(
style,
{
'\\displaystyle': [true, 0],
'\\textstyle': [false, 0],
'\\scriptstyle': [false, 1],
'\\scriptscriptstyle': [false, 2],
},
[null, null]
);
if (display !== null) {
mml.attributes.set('displaystyle', display);
mml.attributes.set('scriptlevel', script);
}
},
/**
* Check that the top stack item is an alignment table.
*
* @param {TexParser} parser The current TeX parser.
* @param {string} name The name of the macro doing the checking.
* @returns {EqnArrayItem} The top item (an EqnArrayItem).
*/
checkAlignment(parser: TexParser, name: string): EqnArrayItem {
const top = parser.stack.Top() as EqnArrayItem;
if (top.kind !== EqnArrayItem.prototype.kind) {
throw new TexError(
'NotInAlignment',
'%1 can only be used in aligment environments',
name
);
}
return top;
},
/**
* Add a paired delimiter to the list of them.
*
* @param {TexParser} parser The current TeX parser
* @param {string} cs The control sequence for the paired delimiters.
* @param {string[]} args The definition for the paired delimiters. One of:
* [left, right]
* [left, right, body, argcount]
* [left, right, body, argcount, pre, post]
*/
addPairedDelims(parser: TexParser, cs: string, args: string[]) {
if (parser.configuration.handlers.get(HandlerType.MACRO).contains(cs)) {
throw new TexError(
'CommadExists',
'Command %1 already defined',
`\\${cs}`
);
}
NewcommandUtil.addMacro(
parser,
cs,
MathtoolsMethods.PairedDelimiters,
args
);
},
/**
* Adjust the line spacing for a table.
*
* @param {MmlNode} mtable The mtable node to adjust (if it is a table).
* @param {string} spread The dimension to change by (number-with-units).
*/
spreadLines(mtable: MmlNode, spread: string) {
if (!mtable.isKind('mtable')) return;
let rowspacing = mtable.attributes.get('rowspacing') as string;
const add = UnitUtil.dimen2em(spread);
rowspacing = rowspacing
.split(/ /)
.map((s) => UnitUtil.em(Math.max(0, UnitUtil.dimen2em(s) + add)))
.join(' ');
mtable.attributes.set('rowspacing', rowspacing);
},
/**
* Check if a string is a number and return it with an explicit plus if there isn't one.
*
* @param {string} name The name of the macro doing the checking.
* @param {string} n The string to test as a number.
* @returns {string} The number with an explicit sign.
*/
plusOrMinus(name: string, n: string): string {
n = n.trim();
if (!n.match(/^[-+]?(?:\d+(?:\.\d*)?|\.\d+)$/)) {
throw new TexError('NotANumber', 'Argument to %1 is not a number', name);
}
return n.match(/^[-+]/) ? n : '+' + n;
},
/**
* Parse a \prescript argument, with its associated format, if any.
*
* @param {TexParser} parser The active tex parser.
* @param {string} name The name of the calling macro (\prescript).
* @param {string} pos The position for the argument (sub, sup, arg).
* @returns {MmlNode} The parsed MML version of the argument.
*/
getScript(parser: TexParser, name: string, pos: string): MmlNode {
let arg = UnitUtil.trimSpaces(parser.GetArgument(name));
if (arg === '') {
return parser.create('node', 'none');
}
const format = parser.options.mathtools[`prescript-${pos}-format`];
if (format) {
arg = `${format}{${arg}}`;
}
const mml = new TexParser(
arg,
parser.stack.env,
parser.configuration
).mml();
return mml.isKind('TeXAtom') && mml.isEmpty
? parser.create('node', 'none')
: mml;
},
};