tex2typst 0.3.1 → 0.3.2
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/README.md +5 -3
- package/dist/index.js +115 -73
- package/dist/tex2typst.min.js +15 -15
- package/dist/types.d.ts +3 -1
- package/dist/typst-shorthands.d.ts +3 -0
- package/dist/typst-writer.d.ts +9 -3
- package/docs/api-reference.md +64 -0
- package/package.json +1 -1
- package/src/convert.ts +15 -18
- package/src/index.ts +11 -14
- package/src/map.ts +13 -36
- package/src/types.ts +3 -1
- package/src/typst-parser.ts +22 -2
- package/src/typst-shorthands.ts +51 -0
- package/src/typst-writer.ts +29 -22
- package/tools/make-shorthand-map.py +33 -0
- package/tools/make-symbol-map.py +4 -3
package/src/convert.ts
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
|
-
import { TexNode, TypstNode, TexSupsubData, TypstSupsubData, TexSqrtData, Tex2TypstOptions, TYPST_NONE, TYPST_TRUE, TypstPrimitiveValue } from "./types";
|
|
2
|
-
import { TypstWriterError
|
|
1
|
+
import { TexNode, TypstNode, TexSupsubData, TypstSupsubData, TexSqrtData, Tex2TypstOptions, TYPST_NONE, TYPST_TRUE, TypstPrimitiveValue, TypstToken, TypstTokenType } from "./types";
|
|
2
|
+
import { TypstWriterError } from "./typst-writer";
|
|
3
3
|
import { symbolMap, reverseSymbolMap } from "./map";
|
|
4
4
|
|
|
5
|
+
// symbols that are supported by Typst but not by KaTeX
|
|
6
|
+
const TYPST_INTRINSIC_SYMBOLS = [
|
|
7
|
+
'dim',
|
|
8
|
+
'id',
|
|
9
|
+
'im',
|
|
10
|
+
'mod',
|
|
11
|
+
'Pr',
|
|
12
|
+
'sech',
|
|
13
|
+
'csch',
|
|
14
|
+
// 'sgn
|
|
15
|
+
];
|
|
5
16
|
|
|
6
17
|
function tex_token_to_typst(token: string): string {
|
|
7
18
|
if (/^[a-zA-Z0-9]$/.test(token)) {
|
|
@@ -260,22 +271,8 @@ export function convert_tex_node_to_typst(node: TexNode, options: Tex2TypstOptio
|
|
|
260
271
|
delim = '|';
|
|
261
272
|
break;
|
|
262
273
|
case 'Vmatrix': {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
// \begin{Vmatrix}
|
|
266
|
-
// a & b \\
|
|
267
|
-
// c & d
|
|
268
|
-
// \end{Vmatrix}
|
|
269
|
-
// to
|
|
270
|
-
// lr(||mat(delim: #none, a, b; c, d)||)
|
|
271
|
-
const matrix = new TypstNode('matrix', '', [], data);
|
|
272
|
-
matrix.setOptions({ 'delim': TYPST_NONE });
|
|
273
|
-
const group = new TypstNode('group', '', [
|
|
274
|
-
new TypstNode('symbol', '||'),
|
|
275
|
-
matrix,
|
|
276
|
-
new TypstNode('symbol', '||'),
|
|
277
|
-
]);
|
|
278
|
-
return new TypstNode('funcCall', 'lr', [ group ]);
|
|
274
|
+
delim = new TypstToken(TypstTokenType.SYMBOL, 'bar.v.double');
|
|
275
|
+
break;
|
|
279
276
|
}
|
|
280
277
|
default:
|
|
281
278
|
throw new TypstWriterError(`Unimplemented beginend: ${node.content}`, node);
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parseTex } from "./tex-parser";
|
|
2
2
|
import type { Tex2TypstOptions } from "./types";
|
|
3
|
-
import { TypstWriter } from "./typst-writer";
|
|
3
|
+
import { TypstWriter, type TypstWriterOptions } from "./typst-writer";
|
|
4
4
|
import { convert_tex_node_to_typst, convert_typst_node_to_tex } from "./convert";
|
|
5
5
|
import { symbolMap } from "./map";
|
|
6
6
|
import { parseTypst } from "./typst-parser";
|
|
@@ -11,27 +11,24 @@ export function tex2typst(tex: string, options?: Tex2TypstOptions): string {
|
|
|
11
11
|
const opt: Tex2TypstOptions = {
|
|
12
12
|
nonStrict: true,
|
|
13
13
|
preferTypstIntrinsic: true,
|
|
14
|
+
preferShorthands: true,
|
|
14
15
|
keepSpaces: false,
|
|
15
16
|
fracToSlash: true,
|
|
17
|
+
inftyToOo: false,
|
|
16
18
|
customTexMacros: {}
|
|
17
19
|
};
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
if (options.customTexMacros) {
|
|
26
|
-
opt.customTexMacros = options.customTexMacros;
|
|
27
|
-
}
|
|
28
|
-
if (options.fracToSlash !== undefined) {
|
|
29
|
-
opt.fracToSlash = options.fracToSlash;
|
|
20
|
+
|
|
21
|
+
if(options !== undefined) {
|
|
22
|
+
for (const key in opt) {
|
|
23
|
+
if (options[key] !== undefined) {
|
|
24
|
+
opt[key] = options[key];
|
|
25
|
+
}
|
|
30
26
|
}
|
|
31
27
|
}
|
|
28
|
+
|
|
32
29
|
const texTree = parseTex(tex, opt.customTexMacros!);
|
|
33
30
|
const typstTree = convert_tex_node_to_typst(texTree, opt);
|
|
34
|
-
const writer = new TypstWriter(opt
|
|
31
|
+
const writer = new TypstWriter(opt as TypstWriterOptions);
|
|
35
32
|
writer.serialize(typstTree);
|
|
36
33
|
return writer.finalize();
|
|
37
34
|
}
|
package/src/map.ts
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
const symbolMap = new Map<string, string>([
|
|
2
|
+
['cos', 'cos'],
|
|
3
|
+
['sin', 'sin'],
|
|
4
|
+
['tan', 'tan'],
|
|
5
|
+
['cot', 'cot'],
|
|
6
|
+
['sec', 'sec'],
|
|
7
|
+
['csc', 'csc'],
|
|
8
|
+
['mod', 'mod'],
|
|
9
|
+
['omicron', 'omicron'],
|
|
10
|
+
['Xi', 'Xi'],
|
|
11
|
+
['Upsilon', 'Upsilon'],
|
|
12
|
+
['lim', 'lim'],
|
|
13
|
+
|
|
2
14
|
['nonumber', ''],
|
|
3
15
|
['vec', 'arrow'],
|
|
4
16
|
['neq', 'eq.not'],
|
|
@@ -59,37 +71,11 @@ const symbolMap = new Map<string, string>([
|
|
|
59
71
|
|
|
60
72
|
/* arrows */
|
|
61
73
|
['gets', 'arrow.l'],
|
|
62
|
-
['hookleftarrow', 'arrow.l.hook'],
|
|
63
|
-
['leftharpoonup', 'harpoon.lt'],
|
|
64
|
-
['leftharpoondown', 'harpoon.lb'],
|
|
65
|
-
['rightleftharpoons', 'harpoons.rtlb'],
|
|
66
|
-
['longleftarrow', 'arrow.l.long'],
|
|
67
|
-
['longrightarrow', 'arrow.r.long'],
|
|
68
|
-
['longleftrightarrow', 'arrow.l.r.long'],
|
|
69
|
-
['Longleftarrow', 'arrow.l.double.long'],
|
|
70
|
-
['Longrightarrow', 'arrow.r.double.long'],
|
|
71
|
-
['Longleftrightarrow', 'arrow.l.r.double.long'],
|
|
72
74
|
// ['longmapsto', 'arrow.r.bar'],
|
|
73
|
-
['hookrightarrow', 'arrow.r.hook'],
|
|
74
|
-
['rightharpoonup', 'harpoon.rt'],
|
|
75
|
-
['rightharpoondown', 'harpoon.rb'],
|
|
76
75
|
['iff', 'arrow.l.r.double.long'],
|
|
77
76
|
['implies', 'arrow.r.double.long'],
|
|
78
|
-
['uparrow', 'arrow.t'],
|
|
79
|
-
['downarrow', 'arrow.b'],
|
|
80
|
-
['updownarrow', 'arrow.t.b'],
|
|
81
|
-
['Uparrow', 'arrow.t.double'],
|
|
82
|
-
['Downarrow', 'arrow.b.double'],
|
|
83
|
-
['Updownarrow', 'arrow.t.b.double'],
|
|
84
|
-
['nearrow', 'arrow.tr'],
|
|
85
|
-
['searrow', 'arrow.br'],
|
|
86
|
-
['swarrow', 'arrow.bl'],
|
|
87
|
-
['nwarrow', 'arrow.tl'],
|
|
88
77
|
['leadsto', 'arrow.squiggly'],
|
|
89
78
|
|
|
90
|
-
['leftleftarrows', 'arrows.ll'],
|
|
91
|
-
['rightrightarrows', 'arrows.rr'],
|
|
92
|
-
|
|
93
79
|
|
|
94
80
|
['Cap', 'sect.double'],
|
|
95
81
|
['Cup', 'union.double'],
|
|
@@ -97,9 +83,6 @@ const symbolMap = new Map<string, string>([
|
|
|
97
83
|
['Gamma', 'Gamma'],
|
|
98
84
|
['Join', 'join'],
|
|
99
85
|
['Lambda', 'Lambda'],
|
|
100
|
-
['Leftarrow', 'arrow.l.double'],
|
|
101
|
-
['Leftrightarrow', 'arrow.l.r.double'],
|
|
102
|
-
['Longrightarrow', 'arrow.r.double.long'],
|
|
103
86
|
['Omega', 'Omega'],
|
|
104
87
|
['P', 'pilcrow'],
|
|
105
88
|
['Phi', 'Phi'],
|
|
@@ -153,7 +136,6 @@ const symbolMap = new Map<string, string>([
|
|
|
153
136
|
['div', 'div'],
|
|
154
137
|
['divideontimes', 'times.div'],
|
|
155
138
|
['dotplus', 'plus.dot'],
|
|
156
|
-
['downarrow', 'arrow.b'],
|
|
157
139
|
['ell', 'ell'],
|
|
158
140
|
['emptyset', 'nothing'],
|
|
159
141
|
['epsilon', 'epsilon.alt'],
|
|
@@ -186,8 +168,6 @@ const symbolMap = new Map<string, string>([
|
|
|
186
168
|
['lbrack', 'bracket.l'],
|
|
187
169
|
['ldots', 'dots.h'],
|
|
188
170
|
['le', 'lt.eq'],
|
|
189
|
-
['leadsto', 'arrow.squiggly'],
|
|
190
|
-
['leftarrow', 'arrow.l'],
|
|
191
171
|
['leftthreetimes', 'times.three.l'],
|
|
192
172
|
['leftrightarrow', 'arrow.l.r'],
|
|
193
173
|
['leq', 'lt.eq'],
|
|
@@ -224,7 +204,6 @@ const symbolMap = new Map<string, string>([
|
|
|
224
204
|
['nu', 'nu'],
|
|
225
205
|
['ntriangleleft', 'lt.tri.not'],
|
|
226
206
|
['ntriangleright', 'gt.tri.not'],
|
|
227
|
-
['nwarrow', 'arrow.tl'],
|
|
228
207
|
['odot', 'dot.circle'],
|
|
229
208
|
['oint', 'integral.cont'],
|
|
230
209
|
['oiint', 'integral.surf'],
|
|
@@ -277,7 +256,6 @@ const symbolMap = new Map<string, string>([
|
|
|
277
256
|
['supset', 'supset'],
|
|
278
257
|
['supseteq', 'supset.eq'],
|
|
279
258
|
['supsetneq', 'supset.neq'],
|
|
280
|
-
['swarrow', 'arrow.bl'],
|
|
281
259
|
['tau', 'tau'],
|
|
282
260
|
['theta', 'theta'],
|
|
283
261
|
['times', 'times'],
|
|
@@ -288,8 +266,6 @@ const symbolMap = new Map<string, string>([
|
|
|
288
266
|
// ['triangleleft', 'triangle.l.small'],
|
|
289
267
|
// ['triangleright', 'triangle.r.small'],
|
|
290
268
|
['twoheadrightarrow', 'arrow.r.twohead'],
|
|
291
|
-
['uparrow', 'arrow.t'],
|
|
292
|
-
['updownarrow', 'arrow.t.b'],
|
|
293
269
|
['upharpoonright', 'harpoon.tr'],
|
|
294
270
|
['uplus', 'union.plus'],
|
|
295
271
|
['upsilon', 'upsilon'],
|
|
@@ -1086,6 +1062,7 @@ for(const [key, value] of Array.from(symbolMap.entries()).reverse()) {
|
|
|
1086
1062
|
reverseSymbolMap.set(value, key);
|
|
1087
1063
|
}
|
|
1088
1064
|
reverseSymbolMap.set('dif', 'mathrm{d}');
|
|
1065
|
+
reverseSymbolMap.set('oo', 'infty');
|
|
1089
1066
|
|
|
1090
1067
|
// force override some one-to-multiple mappings
|
|
1091
1068
|
const typst_to_tex_map = new Map<string, string>([
|
package/src/types.ts
CHANGED
|
@@ -352,7 +352,7 @@ export type TypstArrayData = TypstNode[][];
|
|
|
352
352
|
type TypstNodeType = 'atom' | 'symbol' | 'text' | 'control' | 'comment' | 'whitespace'
|
|
353
353
|
| 'empty' | 'group' | 'supsub' | 'funcCall' | 'fraction' | 'align' | 'matrix' | 'unknown';
|
|
354
354
|
|
|
355
|
-
export type TypstPrimitiveValue = string | boolean | null;
|
|
355
|
+
export type TypstPrimitiveValue = string | boolean | null | TypstToken;
|
|
356
356
|
export type TypstNamedParams = { [key: string]: TypstPrimitiveValue };
|
|
357
357
|
|
|
358
358
|
// #none
|
|
@@ -389,8 +389,10 @@ export class TypstNode {
|
|
|
389
389
|
export interface Tex2TypstOptions {
|
|
390
390
|
nonStrict?: boolean; // default is true
|
|
391
391
|
preferTypstIntrinsic?: boolean; // default is true,
|
|
392
|
+
preferShorthands?: boolean; // default is true
|
|
392
393
|
keepSpaces?: boolean; // default is false
|
|
393
394
|
fracToSlash?: boolean; // default is true
|
|
395
|
+
inftyToOo?: boolean; // default is false
|
|
394
396
|
customTexMacros?: { [key: string]: string };
|
|
395
397
|
// TODO: custom typst functions
|
|
396
398
|
}
|
package/src/typst-parser.ts
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
import { array_find } from "./generic";
|
|
3
3
|
import { TYPST_NONE, TypstNamedParams, TypstNode, TypstSupsubData, TypstToken, TypstTokenType } from "./types";
|
|
4
4
|
import { assert, isalpha, isdigit } from "./util";
|
|
5
|
+
import { reverseShorthandMap } from "./typst-shorthands";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
const TYPST_EMPTY_NODE = new TypstNode('empty', '');
|
|
10
|
+
|
|
11
|
+
const TYPST_SHORTHANDS = Array.from(reverseShorthandMap.keys());
|
|
5
12
|
|
|
6
13
|
// TODO: In Typst, y' ' is not the same as y''.
|
|
7
14
|
// The parser should be able to parse the former correctly.
|
|
@@ -22,8 +29,14 @@ function eat_identifier_name(typst: string, start: number): string {
|
|
|
22
29
|
return typst.substring(start, pos);
|
|
23
30
|
}
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
const
|
|
32
|
+
function try_eat_shorthand(typst: string, start: number): string | null {
|
|
33
|
+
for (const shorthand of TYPST_SHORTHANDS) {
|
|
34
|
+
if (typst.startsWith(shorthand, start)) {
|
|
35
|
+
return shorthand;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
27
40
|
|
|
28
41
|
|
|
29
42
|
export function tokenize_typst(typst: string): TypstToken[] {
|
|
@@ -115,6 +128,13 @@ export function tokenize_typst(typst: string): TypstToken[] {
|
|
|
115
128
|
break;
|
|
116
129
|
}
|
|
117
130
|
default: {
|
|
131
|
+
const shorthand = try_eat_shorthand(typst, pos);
|
|
132
|
+
if (shorthand !== null) {
|
|
133
|
+
token = new TypstToken(TypstTokenType.SYMBOL, reverseShorthandMap.get(shorthand)!);
|
|
134
|
+
pos += shorthand.length;
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
|
|
118
138
|
if (isdigit(firstChar)) {
|
|
119
139
|
let newPos = pos;
|
|
120
140
|
while (newPos < typst.length && isdigit(typst[newPos])) {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const shorthandMap = new Map<string, string>([
|
|
2
|
+
['arrow.l.r.double.long', '<==>'],
|
|
3
|
+
['arrow.l.r.long', '<-->'],
|
|
4
|
+
['arrow.r.bar', '|->'],
|
|
5
|
+
['arrow.r.double.bar', '|=>'],
|
|
6
|
+
['arrow.r.double.long', '==>'],
|
|
7
|
+
['arrow.r.long', '-->'],
|
|
8
|
+
['arrow.r.long.squiggly', '~~>'],
|
|
9
|
+
['arrow.r.tail', '>->'],
|
|
10
|
+
['arrow.r.twohead', '->>'],
|
|
11
|
+
['arrow.l.double.long', '<=='],
|
|
12
|
+
['arrow.l.long', '<--'],
|
|
13
|
+
['arrow.l.long.squiggly', '<~~'],
|
|
14
|
+
['arrow.l.tail', '<-<'],
|
|
15
|
+
['arrow.l.twohead', '<<-'],
|
|
16
|
+
['arrow.l.r', '<->'],
|
|
17
|
+
['arrow.l.r.double', '<=>'],
|
|
18
|
+
['colon.double.eq', '::='],
|
|
19
|
+
['dots.h', '...'],
|
|
20
|
+
['gt.triple', '>>>'],
|
|
21
|
+
['lt.triple', '<<<'],
|
|
22
|
+
['arrow.r', '->'],
|
|
23
|
+
['arrow.r.double', '=>'],
|
|
24
|
+
['arrow.r.squiggly', '~>'],
|
|
25
|
+
['arrow.l', '<-'],
|
|
26
|
+
['arrow.l.squiggly', '<~'],
|
|
27
|
+
['bar.v.double', '||'],
|
|
28
|
+
['bracket.l.double', '[|'],
|
|
29
|
+
['bracket.r.double', '|]'],
|
|
30
|
+
['colon.eq', ':='],
|
|
31
|
+
['eq.colon', '=:'],
|
|
32
|
+
['eq.not', '!='],
|
|
33
|
+
['gt.double', '>>'],
|
|
34
|
+
['gt.eq', '>='],
|
|
35
|
+
['lt.double', '<<'],
|
|
36
|
+
['lt.eq', '<='],
|
|
37
|
+
['ast.op', '*'],
|
|
38
|
+
['minus', '-'],
|
|
39
|
+
['tilde.op', '~'],
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
const reverseShorthandMap = new Map<string, string>();
|
|
44
|
+
for (const [key, value] of shorthandMap.entries()) {
|
|
45
|
+
// filter out single character values ('-', '~', '*')
|
|
46
|
+
if(value.length > 1) {
|
|
47
|
+
reverseShorthandMap.set(value, key);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { shorthandMap, reverseShorthandMap };
|
package/src/typst-writer.ts
CHANGED
|
@@ -1,24 +1,10 @@
|
|
|
1
1
|
import { TexNode, TypstNode, TypstPrimitiveValue, TypstSupsubData, TypstToken, TypstTokenType } from "./types";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
// symbols that are supported by Typst but not by KaTeX
|
|
5
|
-
export const TYPST_INTRINSIC_SYMBOLS = [
|
|
6
|
-
'dim',
|
|
7
|
-
'id',
|
|
8
|
-
'im',
|
|
9
|
-
'mod',
|
|
10
|
-
'Pr',
|
|
11
|
-
'sech',
|
|
12
|
-
'csch',
|
|
13
|
-
// 'sgn
|
|
14
|
-
];
|
|
15
|
-
|
|
2
|
+
import { shorthandMap } from "./typst-shorthands";
|
|
16
3
|
|
|
17
4
|
function is_delimiter(c: TypstNode): boolean {
|
|
18
5
|
return c.type === 'atom' && ['(', ')', '[', ']', '{', '}', '|', '⌊', '⌋', '⌈', '⌉'].includes(c.content);
|
|
19
6
|
}
|
|
20
7
|
|
|
21
|
-
|
|
22
8
|
const TYPST_LEFT_PARENTHESIS: TypstToken = new TypstToken(TypstTokenType.ELEMENT, '(');
|
|
23
9
|
const TYPST_RIGHT_PARENTHESIS: TypstToken = new TypstToken(TypstTokenType.ELEMENT, ')');
|
|
24
10
|
const TYPST_COMMA: TypstToken = new TypstToken(TypstTokenType.ELEMENT, ',');
|
|
@@ -35,6 +21,8 @@ function typst_primitive_to_string(value: TypstPrimitiveValue) {
|
|
|
35
21
|
default:
|
|
36
22
|
if (value === null) {
|
|
37
23
|
return '#none';
|
|
24
|
+
} else if (value instanceof TypstToken) {
|
|
25
|
+
return value.toString();
|
|
38
26
|
}
|
|
39
27
|
throw new TypstWriterError(`Invalid primitive value: ${value}`, value);
|
|
40
28
|
}
|
|
@@ -50,20 +38,29 @@ export class TypstWriterError extends Error {
|
|
|
50
38
|
}
|
|
51
39
|
}
|
|
52
40
|
|
|
41
|
+
export interface TypstWriterOptions {
|
|
42
|
+
nonStrict: boolean;
|
|
43
|
+
preferShorthands: boolean;
|
|
44
|
+
keepSpaces: boolean;
|
|
45
|
+
inftyToOo: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
53
48
|
export class TypstWriter {
|
|
54
49
|
private nonStrict: boolean;
|
|
55
|
-
private
|
|
50
|
+
private preferShorthands: boolean;
|
|
56
51
|
private keepSpaces: boolean;
|
|
52
|
+
private inftyToOo: boolean;
|
|
57
53
|
|
|
58
54
|
protected buffer: string = "";
|
|
59
55
|
protected queue: TypstToken[] = [];
|
|
60
56
|
|
|
61
57
|
private insideFunctionDepth = 0;
|
|
62
58
|
|
|
63
|
-
constructor(
|
|
64
|
-
this.nonStrict = nonStrict;
|
|
65
|
-
this.
|
|
66
|
-
this.keepSpaces = keepSpaces;
|
|
59
|
+
constructor(opt: TypstWriterOptions) {
|
|
60
|
+
this.nonStrict = opt.nonStrict;
|
|
61
|
+
this.preferShorthands = opt.preferShorthands;
|
|
62
|
+
this.keepSpaces = opt.keepSpaces;
|
|
63
|
+
this.inftyToOo = opt.inftyToOo;
|
|
67
64
|
}
|
|
68
65
|
|
|
69
66
|
|
|
@@ -123,9 +120,19 @@ export class TypstWriter {
|
|
|
123
120
|
}
|
|
124
121
|
break;
|
|
125
122
|
}
|
|
126
|
-
case 'symbol':
|
|
127
|
-
|
|
123
|
+
case 'symbol': {
|
|
124
|
+
let content = node.content;
|
|
125
|
+
if(this.preferShorthands) {
|
|
126
|
+
if (shorthandMap.has(content)) {
|
|
127
|
+
content = shorthandMap.get(content)!;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (this.inftyToOo && content === 'infinity') {
|
|
131
|
+
content = 'oo';
|
|
132
|
+
}
|
|
133
|
+
this.queue.push(new TypstToken(TypstTokenType.SYMBOL, content));
|
|
128
134
|
break;
|
|
135
|
+
}
|
|
129
136
|
case 'text':
|
|
130
137
|
this.queue.push(new TypstToken(TypstTokenType.TEXT, node.content));
|
|
131
138
|
break;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import urllib.request
|
|
2
|
+
import html
|
|
3
|
+
from bs4 import BeautifulSoup
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
if __name__ == '__main__':
|
|
7
|
+
shorthand_map = []
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
url = "https://typst.app/docs/reference/symbols/"
|
|
11
|
+
with urllib.request.urlopen(url) as response:
|
|
12
|
+
html_text = response.read().decode('utf-8')
|
|
13
|
+
|
|
14
|
+
soup = BeautifulSoup(html_text, 'html.parser')
|
|
15
|
+
|
|
16
|
+
# <ul class="symbol-grid">
|
|
17
|
+
ul_list = soup.find_all('ul', class_='symbol-grid')
|
|
18
|
+
# ul_shorthands_markup = ul_list[0]
|
|
19
|
+
ul_shorthands_math = ul_list[1]
|
|
20
|
+
|
|
21
|
+
li_list = ul_shorthands_math.find_all('li')
|
|
22
|
+
for li in li_list:
|
|
23
|
+
# e.g. <li id="symbol-arrow.r" data-math-shorthand="->"><button>...</button></li>
|
|
24
|
+
# ==> typst = "arrow.r"
|
|
25
|
+
# ==> shorthand = "->"
|
|
26
|
+
typst = li['id'][7:]
|
|
27
|
+
shorthand = html.unescape(li['data-math-shorthand'])
|
|
28
|
+
shorthand_map.append((typst, shorthand))
|
|
29
|
+
|
|
30
|
+
# Sort by length of shorthand, order from longest to shortest
|
|
31
|
+
shorthand_map.sort(key=lambda x: len(x[1]), reverse=True)
|
|
32
|
+
for typst, shorthand in shorthand_map:
|
|
33
|
+
print(f"['{typst}', '{shorthand}'],")
|
package/tools/make-symbol-map.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import urllib.request
|
|
2
2
|
from bs4 import BeautifulSoup
|
|
3
3
|
|
|
4
|
-
|
|
5
4
|
if __name__ == '__main__':
|
|
6
5
|
symbol_map = {}
|
|
7
6
|
|
|
8
7
|
url = "https://typst.app/docs/reference/symbols/sym/"
|
|
9
|
-
|
|
8
|
+
with urllib.request.urlopen(url) as response:
|
|
9
|
+
html_text = response.read().decode('utf-8')
|
|
10
|
+
|
|
10
11
|
soup = BeautifulSoup(html_text, 'html.parser')
|
|
11
12
|
# <ul class="symbol-grid">
|
|
12
13
|
ul = soup.find('ul', class_='symbol-grid')
|