tex2typst 0.3.24 → 0.3.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +270 -212
- package/dist/map.d.ts +1 -1
- package/dist/tex-types.d.ts +11 -7
- package/dist/tex2typst.min.js +13 -13
- package/dist/typst-types.d.ts +19 -16
- package/package.json +1 -1
- package/src/convert.ts +131 -101
- package/src/map.ts +4 -2
- package/src/tex-parser.ts +13 -18
- package/src/tex-tokenizer.ts +3 -2
- package/src/tex-types.ts +28 -17
- package/src/typst-parser.ts +39 -19
- package/src/typst-tokenizer.ts +2 -2
- package/src/typst-types.ts +46 -37
- package/src/typst-writer.ts +73 -73
package/src/tex-tokenizer.ts
CHANGED
|
@@ -46,6 +46,7 @@ export const TEX_BINARY_COMMANDS = [
|
|
|
46
46
|
'tbinom',
|
|
47
47
|
'overset',
|
|
48
48
|
'underset',
|
|
49
|
+
'textcolor',
|
|
49
50
|
]
|
|
50
51
|
|
|
51
52
|
|
|
@@ -58,7 +59,7 @@ function unescape(str: string): string {
|
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
const rules_map = new Map<string, (a: Scanner<TexToken>) => TexToken | TexToken[]>([
|
|
61
|
-
//
|
|
62
|
+
// match `\begin{array}{cc}`
|
|
62
63
|
[
|
|
63
64
|
String.raw`\\begin{(array|subarry)}{(.+?)}`, (s) => {
|
|
64
65
|
const match = s.reMatchArray()!;
|
|
@@ -74,7 +75,7 @@ const rules_map = new Map<string, (a: Scanner<TexToken>) => TexToken | TexToken[
|
|
|
74
75
|
}
|
|
75
76
|
],
|
|
76
77
|
[
|
|
77
|
-
String.raw`\\(text|operatorname|begin|end|hspace|array){(.+?)}`, (s) => {
|
|
78
|
+
String.raw`\\(text|operatorname|textcolor|begin|end|hspace|array){(.+?)}`, (s) => {
|
|
78
79
|
const match = s.reMatchArray()!;
|
|
79
80
|
return [
|
|
80
81
|
new TexToken(TexTokenType.COMMAND, '\\' + match[1]),
|
package/src/tex-types.ts
CHANGED
|
@@ -18,7 +18,7 @@ export enum TexTokenType {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export class TexToken {
|
|
21
|
-
type: TexTokenType;
|
|
21
|
+
readonly type: TexTokenType;
|
|
22
22
|
value: string;
|
|
23
23
|
|
|
24
24
|
constructor(type: TexTokenType, value: string) {
|
|
@@ -55,6 +55,7 @@ export interface TexSupsubData {
|
|
|
55
55
|
|
|
56
56
|
// \left. or \right. will be represented as null.
|
|
57
57
|
export interface TexLeftRightData {
|
|
58
|
+
body: TexNode;
|
|
58
59
|
left: TexToken | null;
|
|
59
60
|
right: TexToken | null;
|
|
60
61
|
}
|
|
@@ -68,14 +69,12 @@ type TexNodeType = 'terminal' | 'text' | 'ordgroup' | 'supsub'
|
|
|
68
69
|
|
|
69
70
|
|
|
70
71
|
export abstract class TexNode {
|
|
71
|
-
type: TexNodeType;
|
|
72
|
+
readonly type: TexNodeType;
|
|
72
73
|
head: TexToken;
|
|
73
|
-
args?: TexNode[];
|
|
74
74
|
|
|
75
|
-
constructor(type: TexNodeType, head: TexToken | null
|
|
75
|
+
constructor(type: TexNodeType, head: TexToken | null) {
|
|
76
76
|
this.type = type;
|
|
77
77
|
this.head = head ? head : TexToken.EMPTY;
|
|
78
|
-
this.args = args;
|
|
79
78
|
}
|
|
80
79
|
|
|
81
80
|
// Note that this is only shallow equality.
|
|
@@ -148,12 +147,14 @@ export class TexText extends TexNode {
|
|
|
148
147
|
}
|
|
149
148
|
|
|
150
149
|
export class TexGroup extends TexNode {
|
|
151
|
-
|
|
152
|
-
|
|
150
|
+
public items: TexNode[];
|
|
151
|
+
constructor(items: TexNode[]) {
|
|
152
|
+
super('ordgroup', TexToken.EMPTY);
|
|
153
|
+
this.items = items;
|
|
153
154
|
}
|
|
154
155
|
|
|
155
156
|
public serialize(): TexToken[] {
|
|
156
|
-
return this.
|
|
157
|
+
return this.items.map((n) => n.serialize()).flat();
|
|
157
158
|
}
|
|
158
159
|
}
|
|
159
160
|
|
|
@@ -163,7 +164,7 @@ export class TexSupSub extends TexNode {
|
|
|
163
164
|
public sub: TexNode | null;
|
|
164
165
|
|
|
165
166
|
constructor(data: TexSupsubData) {
|
|
166
|
-
super('supsub', TexToken.EMPTY
|
|
167
|
+
super('supsub', TexToken.EMPTY);
|
|
167
168
|
this.base = data.base;
|
|
168
169
|
this.sup = data.sup;
|
|
169
170
|
this.sub = data.sub;
|
|
@@ -211,11 +212,14 @@ export class TexSupSub extends TexNode {
|
|
|
211
212
|
}
|
|
212
213
|
|
|
213
214
|
export class TexFuncCall extends TexNode {
|
|
215
|
+
public args: TexNode[];
|
|
216
|
+
|
|
214
217
|
// For type="sqrt", it's additional argument wrapped square bracket. e.g. 3 in \sqrt[3]{x}
|
|
215
218
|
public data: TexNode | null;
|
|
216
219
|
|
|
217
220
|
constructor(head: TexToken, args: TexNode[], data: TexNode | null = null) {
|
|
218
|
-
super('funcCall', head
|
|
221
|
+
super('funcCall', head);
|
|
222
|
+
this.args = args;
|
|
219
223
|
this.data = data;
|
|
220
224
|
}
|
|
221
225
|
|
|
@@ -230,7 +234,7 @@ export class TexFuncCall extends TexNode {
|
|
|
230
234
|
tokens.push(new TexToken(TexTokenType.ELEMENT, ']'));
|
|
231
235
|
}
|
|
232
236
|
|
|
233
|
-
for (const arg of this.args
|
|
237
|
+
for (const arg of this.args) {
|
|
234
238
|
tokens.push(new TexToken(TexTokenType.ELEMENT, '{'));
|
|
235
239
|
tokens = tokens.concat(arg.serialize());
|
|
236
240
|
tokens.push(new TexToken(TexTokenType.ELEMENT, '}'));
|
|
@@ -241,11 +245,13 @@ export class TexFuncCall extends TexNode {
|
|
|
241
245
|
}
|
|
242
246
|
|
|
243
247
|
export class TexLeftRight extends TexNode {
|
|
248
|
+
public body: TexNode;
|
|
244
249
|
public left: TexToken | null;
|
|
245
250
|
public right: TexToken | null;
|
|
246
251
|
|
|
247
|
-
constructor(
|
|
248
|
-
super('leftright', TexToken.EMPTY
|
|
252
|
+
constructor(data: TexLeftRightData) {
|
|
253
|
+
super('leftright', TexToken.EMPTY);
|
|
254
|
+
this.body = data.body;
|
|
249
255
|
this.left = data.left;
|
|
250
256
|
this.right = data.right;
|
|
251
257
|
}
|
|
@@ -254,7 +260,7 @@ export class TexLeftRight extends TexNode {
|
|
|
254
260
|
let tokens: TexToken[] = [];
|
|
255
261
|
tokens.push(new TexToken(TexTokenType.COMMAND, '\\left'));
|
|
256
262
|
tokens.push(new TexToken(TexTokenType.ELEMENT, this.left? this.left.value: '.'));
|
|
257
|
-
tokens = tokens.concat(this.
|
|
263
|
+
tokens = tokens.concat(this.body.serialize());
|
|
258
264
|
tokens.push(new TexToken(TexTokenType.COMMAND, '\\right'));
|
|
259
265
|
tokens.push(new TexToken(TexTokenType.ELEMENT, this.right? this.right.value: '.'));
|
|
260
266
|
return tokens;
|
|
@@ -263,11 +269,14 @@ export class TexLeftRight extends TexNode {
|
|
|
263
269
|
|
|
264
270
|
export class TexBeginEnd extends TexNode {
|
|
265
271
|
public matrix: TexNode[][];
|
|
272
|
+
// for environment="array" or "subarray", there's additional data like {c|c} right after \begin{env}
|
|
273
|
+
public data: TexNode | null;
|
|
266
274
|
|
|
267
|
-
constructor(head: TexToken,
|
|
275
|
+
constructor(head: TexToken, matrix: TexNode[][], data: TexNode | null = null) {
|
|
268
276
|
assert(head.type === TexTokenType.LITERAL);
|
|
269
|
-
super('beginend', head
|
|
270
|
-
this.matrix =
|
|
277
|
+
super('beginend', head);
|
|
278
|
+
this.matrix = matrix;
|
|
279
|
+
this.data = data;
|
|
271
280
|
}
|
|
272
281
|
|
|
273
282
|
public serialize(): TexToken[] {
|
|
@@ -330,6 +339,8 @@ export function writeTexTokenBuffer(buffer: string, token: TexToken): string {
|
|
|
330
339
|
no_need_space ||= /[\(\[{]\s*(-|\+)$/.test(buffer) || buffer === '-' || buffer === '+';
|
|
331
340
|
// "&=" instead of "& ="
|
|
332
341
|
no_need_space ||= buffer.endsWith('&') && str === '=';
|
|
342
|
+
// "2y" instead of "2 y"
|
|
343
|
+
no_need_space ||= /\d$/.test(buffer) && /^[a-zA-Z]$/.test(str);
|
|
333
344
|
}
|
|
334
345
|
|
|
335
346
|
if (!no_need_space) {
|
package/src/typst-parser.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import { array_find } from "./generic";
|
|
3
|
-
import {
|
|
3
|
+
import { TypstFraction, TypstFuncCall, TypstGroup, TypstLeftright, TypstLeftRightData, TypstMarkupFunc, TypstMatrixLike, TypstNode, TypstSupsub, TypstTerminal } from "./typst-types";
|
|
4
4
|
import { TypstNamedParams } from "./typst-types";
|
|
5
5
|
import { TypstSupsubData } from "./typst-types";
|
|
6
6
|
import { TypstToken } from "./typst-types";
|
|
@@ -19,7 +19,6 @@ function eat_primes(tokens: TypstToken[], start: number): number {
|
|
|
19
19
|
return pos - start;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
23
22
|
function _find_closing_match(tokens: TypstToken[], start: number,
|
|
24
23
|
leftBrackets: TypstToken[], rightBrackets: TypstToken[]): number {
|
|
25
24
|
assert(tokens[start].isOneOf(leftBrackets));
|
|
@@ -168,10 +167,10 @@ function process_operators(nodes: TypstNode[], parenthesis = false): TypstNode {
|
|
|
168
167
|
let numerator = args.pop()!;
|
|
169
168
|
|
|
170
169
|
if(denominator.type === 'leftright') {
|
|
171
|
-
denominator =
|
|
170
|
+
denominator = (denominator as TypstLeftright).body;
|
|
172
171
|
}
|
|
173
172
|
if(numerator.type === 'leftright') {
|
|
174
|
-
numerator =
|
|
173
|
+
numerator = (numerator as TypstLeftright).body;
|
|
175
174
|
}
|
|
176
175
|
|
|
177
176
|
args.push(new TypstFraction([numerator, denominator]));
|
|
@@ -181,15 +180,24 @@ function process_operators(nodes: TypstNode[], parenthesis = false): TypstNode {
|
|
|
181
180
|
}
|
|
182
181
|
}
|
|
183
182
|
}
|
|
183
|
+
const body = args.length === 1? args[0]: new TypstGroup(args);
|
|
184
184
|
if(parenthesis) {
|
|
185
|
-
return new TypstLeftright(null,
|
|
185
|
+
return new TypstLeftright(null, { body: body, left: LEFT_PARENTHESES, right: RIGHT_PARENTHESES } as TypstLeftRightData);
|
|
186
186
|
} else {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
187
|
+
return body;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function parse_named_params(groups: TypstGroup[]): TypstNamedParams {
|
|
192
|
+
const COLON = new TypstToken(TypstTokenType.ELEMENT, ':').toNode();
|
|
193
|
+
|
|
194
|
+
const np: TypstNamedParams = {};
|
|
195
|
+
for (const group of groups) {
|
|
196
|
+
assert(group.items.length == 3);
|
|
197
|
+
assert(group.items[1].eq(COLON));
|
|
198
|
+
np[group.items[0].toString()] = new TypstTerminal(new TypstToken(TypstTokenType.LITERAL, group.items[2].toString()));
|
|
192
199
|
}
|
|
200
|
+
return np;
|
|
193
201
|
}
|
|
194
202
|
|
|
195
203
|
export class TypstParserError extends Error {
|
|
@@ -322,19 +330,31 @@ export class TypstParser {
|
|
|
322
330
|
if (start + 1 < tokens.length && tokens[start + 1].eq(LEFT_PARENTHESES)) {
|
|
323
331
|
if(firstToken.value === 'mat') {
|
|
324
332
|
const [matrix, named_params, newPos] = this.parseMatrix(tokens, start + 1, SEMICOLON, COMMA);
|
|
325
|
-
const mat = new
|
|
333
|
+
const mat = new TypstMatrixLike(firstToken, matrix);
|
|
326
334
|
mat.setOptions(named_params);
|
|
327
335
|
return [mat, newPos];
|
|
328
336
|
}
|
|
329
337
|
if(firstToken.value === 'cases') {
|
|
330
338
|
const [cases, named_params, newPos] = this.parseMatrix(tokens, start + 1, COMMA, CONTROL_AND);
|
|
331
|
-
const casesNode = new
|
|
339
|
+
const casesNode = new TypstMatrixLike(firstToken, cases);
|
|
332
340
|
casesNode.setOptions(named_params);
|
|
333
341
|
return [casesNode, newPos];
|
|
334
342
|
}
|
|
335
343
|
if (firstToken.value === 'lr') {
|
|
336
344
|
return this.parseLrArguments(tokens, start + 1);
|
|
337
345
|
}
|
|
346
|
+
if (['#heading', '#text'].includes(firstToken.value)) {
|
|
347
|
+
const [args, newPos] = this.parseArguments(tokens, start + 1);
|
|
348
|
+
const named_params = parse_named_params(args as TypstGroup[]);
|
|
349
|
+
assert(tokens[newPos].eq(LEFT_BRACKET));
|
|
350
|
+
const DOLLAR = new TypstToken(TypstTokenType.ELEMENT, '$');
|
|
351
|
+
const end = _find_closing_match(tokens, newPos + 1, [DOLLAR], [DOLLAR]);
|
|
352
|
+
const [group, _] = this.parseGroup(tokens, newPos + 2, end);
|
|
353
|
+
assert(tokens[end + 1].eq(RIGHT_BRACKET));
|
|
354
|
+
const markup_func = new TypstMarkupFunc(firstToken, [group]);
|
|
355
|
+
markup_func.setOptions(named_params);
|
|
356
|
+
return [markup_func, end + 2];
|
|
357
|
+
}
|
|
338
358
|
const [args, newPos] = this.parseArguments(tokens, start + 1);
|
|
339
359
|
const func_call = new TypstFuncCall(firstToken, args);
|
|
340
360
|
return [func_call, newPos];
|
|
@@ -359,13 +379,13 @@ export class TypstParser {
|
|
|
359
379
|
const inner_end = find_closing_delim(tokens, inner_start);
|
|
360
380
|
const inner_args= this.parseArgumentsWithSeparator(tokens, inner_start + 1, inner_end, COMMA);
|
|
361
381
|
return [
|
|
362
|
-
new TypstLeftright(lr_token, inner_args,
|
|
382
|
+
new TypstLeftright(lr_token, { body: new TypstGroup(inner_args), left: tokens[inner_start], right: tokens[inner_end]}),
|
|
363
383
|
end + 1,
|
|
364
384
|
];
|
|
365
385
|
} else {
|
|
366
386
|
const [args, end] = this.parseArguments(tokens, start);
|
|
367
387
|
return [
|
|
368
|
-
new TypstLeftright(lr_token, args,
|
|
388
|
+
new TypstLeftright(lr_token, { body: new TypstGroup(args), left: null, right: null }),
|
|
369
389
|
end,
|
|
370
390
|
];
|
|
371
391
|
}
|
|
@@ -400,18 +420,18 @@ export class TypstParser {
|
|
|
400
420
|
continue;
|
|
401
421
|
}
|
|
402
422
|
|
|
403
|
-
const g = arr[i];
|
|
404
|
-
const pos_colon = array_find(g.
|
|
423
|
+
const g = arr[i] as TypstGroup;
|
|
424
|
+
const pos_colon = array_find(g.items, COLON);
|
|
405
425
|
if(pos_colon === -1 || pos_colon === 0) {
|
|
406
426
|
continue;
|
|
407
427
|
}
|
|
408
428
|
to_delete.push(i);
|
|
409
|
-
const param_name = g.
|
|
429
|
+
const param_name = g.items[pos_colon - 1];
|
|
410
430
|
if(param_name.eq(new TypstToken(TypstTokenType.SYMBOL, 'delim').toNode())) {
|
|
411
|
-
if(g.
|
|
431
|
+
if(g.items.length !== 3) {
|
|
412
432
|
throw new TypstParserError('Invalid number of arguments for delim');
|
|
413
433
|
}
|
|
414
|
-
np['delim'] = g.
|
|
434
|
+
np['delim'] = g.items[pos_colon + 1];
|
|
415
435
|
} else {
|
|
416
436
|
throw new TypstParserError('Not implemented for other named parameters');
|
|
417
437
|
}
|
package/src/typst-tokenizer.ts
CHANGED
|
@@ -69,10 +69,10 @@ const rules_map = new Map<string, (a: Scanner<TypstToken>) => TypstToken | Typst
|
|
|
69
69
|
new TypstToken(TypstTokenType.ELEMENT, ")"),
|
|
70
70
|
];
|
|
71
71
|
}],
|
|
72
|
-
[String.raw
|
|
72
|
+
[String.raw`#none`, (s) => new TypstToken(TypstTokenType.NONE, s.text()!)],
|
|
73
|
+
[String.raw`#?[a-zA-Z\.]+`, (s) => {
|
|
73
74
|
return new TypstToken(s.text()!.length === 1? TypstTokenType.ELEMENT: TypstTokenType.SYMBOL, s.text()!);
|
|
74
75
|
}],
|
|
75
|
-
[String.raw`#none`, (s) => new TypstToken(TypstTokenType.NONE, s.text()!)],
|
|
76
76
|
[String.raw`.`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
|
|
77
77
|
]);
|
|
78
78
|
|
package/src/typst-types.ts
CHANGED
|
@@ -14,7 +14,7 @@ export enum TypstTokenType {
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
export class TypstToken {
|
|
17
|
-
type: TypstTokenType;
|
|
17
|
+
readonly type: TypstTokenType;
|
|
18
18
|
value: string;
|
|
19
19
|
|
|
20
20
|
constructor(type: TypstTokenType, content: string) {
|
|
@@ -46,6 +46,7 @@ export class TypstToken {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
public static readonly NONE = new TypstToken(TypstTokenType.NONE, '#none');
|
|
49
|
+
public static readonly EMPTY = new TypstToken(TypstTokenType.ELEMENT, '');
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
export interface TypstSupsubData {
|
|
@@ -56,6 +57,7 @@ export interface TypstSupsubData {
|
|
|
56
57
|
|
|
57
58
|
|
|
58
59
|
export interface TypstLeftRightData {
|
|
60
|
+
body: TypstNode;
|
|
59
61
|
left: TypstToken | null;
|
|
60
62
|
right: TypstToken | null;
|
|
61
63
|
}
|
|
@@ -64,22 +66,21 @@ export interface TypstLeftRightData {
|
|
|
64
66
|
* fraction: `1/2`, `(x + y)/2`, `(1+x)/(1-x)`
|
|
65
67
|
* group: `a + 1/3`
|
|
66
68
|
* leftright: `(a + 1/3)`, `[a + 1/3)`, `lr(]sum_(x=1)^n])`
|
|
69
|
+
* markupFunc: `#heading(level: 2)[something]`, `#text(fill: red)[some text and math $x + y$]`
|
|
67
70
|
*/
|
|
68
|
-
export type TypstNodeType = 'terminal' | 'group' | 'supsub' | 'funcCall' | 'fraction'| 'leftright' | '
|
|
71
|
+
export type TypstNodeType = 'terminal' | 'group' | 'supsub' | 'funcCall' | 'fraction'| 'leftright' | 'matrixLike'| 'markupFunc';
|
|
69
72
|
|
|
70
73
|
export type TypstNamedParams = { [key: string]: TypstNode; };
|
|
71
74
|
|
|
72
75
|
export abstract class TypstNode {
|
|
73
76
|
readonly type: TypstNodeType;
|
|
74
77
|
head: TypstToken;
|
|
75
|
-
args?: TypstNode[];
|
|
76
78
|
// Some Typst functions accept additional options. e.g. mat() has option "delim", op() has option "limits"
|
|
77
79
|
options?: TypstNamedParams;
|
|
78
80
|
|
|
79
|
-
constructor(type: TypstNodeType, head: TypstToken | null
|
|
81
|
+
constructor(type: TypstNodeType, head: TypstToken | null) {
|
|
80
82
|
this.type = type;
|
|
81
83
|
this.head = head ? head : TypstToken.NONE;
|
|
82
|
-
this.args = args;
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
// whether the node is over high so that if it's wrapped in braces, \left and \right should be used in its TeX form
|
|
@@ -115,12 +116,14 @@ export class TypstTerminal extends TypstNode {
|
|
|
115
116
|
}
|
|
116
117
|
|
|
117
118
|
export class TypstGroup extends TypstNode {
|
|
118
|
-
|
|
119
|
-
|
|
119
|
+
public items: TypstNode[];
|
|
120
|
+
constructor(items: TypstNode[]) {
|
|
121
|
+
super('group', TypstToken.NONE);
|
|
122
|
+
this.items = items;
|
|
120
123
|
}
|
|
121
124
|
|
|
122
125
|
public isOverHigh(): boolean {
|
|
123
|
-
return this.
|
|
126
|
+
return this.items.some((n) => n.isOverHigh());
|
|
124
127
|
}
|
|
125
128
|
}
|
|
126
129
|
|
|
@@ -130,7 +133,7 @@ export class TypstSupsub extends TypstNode {
|
|
|
130
133
|
public sub: TypstNode | null;
|
|
131
134
|
|
|
132
135
|
constructor(data: TypstSupsubData) {
|
|
133
|
-
super('supsub', TypstToken.NONE
|
|
136
|
+
super('supsub', TypstToken.NONE);
|
|
134
137
|
this.base = data.base;
|
|
135
138
|
this.sup = data.sup;
|
|
136
139
|
this.sub = data.sub;
|
|
@@ -142,21 +145,26 @@ export class TypstSupsub extends TypstNode {
|
|
|
142
145
|
}
|
|
143
146
|
|
|
144
147
|
export class TypstFuncCall extends TypstNode {
|
|
148
|
+
public args: TypstNode[];
|
|
145
149
|
constructor(head: TypstToken, args: TypstNode[]) {
|
|
146
|
-
super('funcCall', head
|
|
150
|
+
super('funcCall', head);
|
|
151
|
+
this.args = args;
|
|
147
152
|
}
|
|
148
153
|
|
|
149
154
|
public isOverHigh(): boolean {
|
|
150
155
|
if (this.head.value === 'frac') {
|
|
151
156
|
return true;
|
|
152
157
|
}
|
|
153
|
-
return this.args
|
|
158
|
+
return this.args.some((n) => n.isOverHigh());
|
|
154
159
|
}
|
|
155
160
|
}
|
|
156
161
|
|
|
157
162
|
export class TypstFraction extends TypstNode {
|
|
163
|
+
public args: TypstNode[];
|
|
164
|
+
|
|
158
165
|
constructor(args: TypstNode[]) {
|
|
159
|
-
super('fraction', TypstToken.NONE
|
|
166
|
+
super('fraction', TypstToken.NONE);
|
|
167
|
+
this.args = args;
|
|
160
168
|
}
|
|
161
169
|
|
|
162
170
|
public isOverHigh(): boolean {
|
|
@@ -166,56 +174,57 @@ export class TypstFraction extends TypstNode {
|
|
|
166
174
|
|
|
167
175
|
|
|
168
176
|
export class TypstLeftright extends TypstNode {
|
|
177
|
+
public body: TypstNode;
|
|
169
178
|
public left: TypstToken | null;
|
|
170
179
|
public right: TypstToken | null;
|
|
171
180
|
|
|
172
|
-
|
|
173
|
-
|
|
181
|
+
// head is either null or 'lr'
|
|
182
|
+
constructor(head: TypstToken | null, data: TypstLeftRightData) {
|
|
183
|
+
super('leftright', head);
|
|
184
|
+
this.body = data.body;
|
|
174
185
|
this.left = data.left;
|
|
175
186
|
this.right = data.right;
|
|
176
187
|
}
|
|
177
188
|
|
|
178
189
|
public isOverHigh(): boolean {
|
|
179
|
-
return this.
|
|
190
|
+
return this.body.isOverHigh();
|
|
180
191
|
}
|
|
181
192
|
}
|
|
182
193
|
|
|
183
|
-
export class TypstAlign extends TypstNode {
|
|
184
|
-
public matrix: TypstNode[][];
|
|
185
194
|
|
|
186
|
-
|
|
187
|
-
super('align', TypstToken.NONE, []);
|
|
188
|
-
this.matrix = data;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
public isOverHigh(): boolean {
|
|
192
|
-
return true;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
export class TypstMatrix extends TypstNode {
|
|
195
|
+
export class TypstMatrixLike extends TypstNode {
|
|
197
196
|
public matrix: TypstNode[][];
|
|
198
197
|
|
|
199
|
-
|
|
200
|
-
|
|
198
|
+
// head is 'mat', 'cases' or null
|
|
199
|
+
constructor(head: TypstToken | null, data: TypstNode[][]) {
|
|
200
|
+
super('matrixLike', head);
|
|
201
201
|
this.matrix = data;
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
public isOverHigh(): boolean {
|
|
205
205
|
return true;
|
|
206
206
|
}
|
|
207
|
+
|
|
208
|
+
static readonly MAT = new TypstToken(TypstTokenType.SYMBOL, 'mat');
|
|
209
|
+
static readonly CASES = new TypstToken(TypstTokenType.SYMBOL, 'cases');
|
|
207
210
|
}
|
|
208
211
|
|
|
209
|
-
export class
|
|
210
|
-
|
|
212
|
+
export class TypstMarkupFunc extends TypstNode {
|
|
213
|
+
/*
|
|
214
|
+
In idealized situations, for `#heading([some text and math $x + y$ example])`,
|
|
215
|
+
fragments would be [TypstMarkup{"some text and math "}, TypstNode{"x + y"}, TypstMarkup{" example"}]
|
|
216
|
+
At present, we haven't implemented anything about TypstMarkup.
|
|
217
|
+
So only pattens like `#heading(level: 2)[$x+y$]`, `#text(fill: red)[$x + y$]` are supported.
|
|
218
|
+
Therefore, fragments is always a list containing exactly 1 TypstNode in well-working situations.
|
|
219
|
+
*/
|
|
220
|
+
public fragments: TypstNode[];
|
|
211
221
|
|
|
212
|
-
constructor(
|
|
213
|
-
super('
|
|
214
|
-
this.
|
|
222
|
+
constructor(head: TypstToken, fragments: TypstNode[]) {
|
|
223
|
+
super('markupFunc', head);
|
|
224
|
+
this.fragments = fragments;
|
|
215
225
|
}
|
|
216
226
|
|
|
217
227
|
public isOverHigh(): boolean {
|
|
218
|
-
return
|
|
228
|
+
return this.fragments.some((n) => n.isOverHigh());
|
|
219
229
|
}
|
|
220
230
|
}
|
|
221
|
-
|