tex2typst 0.3.17 → 0.3.19
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 +2 -2
- package/dist/index.js +230 -172
- package/dist/tex-parser.d.ts +0 -1
- package/dist/tex-tokenizer.d.ts +4 -0
- package/dist/tex2typst.min.js +11 -11
- package/dist/types.d.ts +13 -7
- package/dist/typst-parser.d.ts +0 -1
- package/dist/typst-tokenizer.d.ts +2 -0
- package/dist/typst-writer.d.ts +3 -1
- package/package.json +1 -1
- package/src/convert.ts +129 -69
- package/src/index.ts +1 -1
- package/src/map.ts +2 -0
- package/src/tex-parser.ts +6 -137
- package/src/tex-tokenizer.ts +138 -0
- package/src/types.ts +20 -7
- package/src/typst-parser.ts +1 -74
- package/src/typst-tokenizer.ts +76 -0
- package/src/typst-writer.ts +36 -18
- package/TODO.md +0 -1
- package/docs/api-reference.md +0 -64
- package/tools/make-shorthand-map.py +0 -33
- package/tools/make-symbol-map.py +0 -35
package/src/types.ts
CHANGED
|
@@ -125,6 +125,13 @@ export class TexNode {
|
|
|
125
125
|
case 'ordgroup': {
|
|
126
126
|
return this.args!.map((n) => n.serialize()).flat();
|
|
127
127
|
}
|
|
128
|
+
case 'leftright': {
|
|
129
|
+
let tokens = this.args!.map((n) => n.serialize()).flat();
|
|
130
|
+
tokens.splice(0, 0, new TexToken(TexTokenType.COMMAND, '\\left'));
|
|
131
|
+
tokens.splice(tokens.length - 1, 0, new TexToken(TexTokenType.COMMAND, '\\right'));
|
|
132
|
+
|
|
133
|
+
return tokens;
|
|
134
|
+
}
|
|
128
135
|
case 'unaryFunc': {
|
|
129
136
|
let tokens: TexToken[] = [];
|
|
130
137
|
tokens.push(new TexToken(TexTokenType.COMMAND, this.content));
|
|
@@ -382,14 +389,20 @@ export const TYPST_NONE = new TypstNode('none', '#none');
|
|
|
382
389
|
export const TYPST_TRUE: TypstPrimitiveValue = true;
|
|
383
390
|
export const TYPST_FALSE: TypstPrimitiveValue = false;
|
|
384
391
|
|
|
392
|
+
/**
|
|
393
|
+
* ATTENTION:
|
|
394
|
+
* Don't use any options except those explicitly documented in
|
|
395
|
+
* https://github.com/qwinsi/tex2typst/blob/main/docs/api-reference.md
|
|
396
|
+
* Any undocumented options may be not working at present or break in the future!
|
|
397
|
+
*/
|
|
385
398
|
export interface Tex2TypstOptions {
|
|
386
|
-
nonStrict?: boolean;
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
nonAsciiWrapper?: string;
|
|
399
|
+
nonStrict?: boolean; /** default is true */
|
|
400
|
+
preferShorthands?: boolean; /** default is true */
|
|
401
|
+
keepSpaces?: boolean; /** default is false */
|
|
402
|
+
fracToSlash?: boolean; /** default is true */
|
|
403
|
+
inftyToOo?: boolean; /** default is false */
|
|
404
|
+
optimize?: boolean; /** default is true */
|
|
405
|
+
nonAsciiWrapper?: string; /** default is "" */
|
|
393
406
|
customTexMacros?: { [key: string]: string };
|
|
394
407
|
// TODO: custom typst functions
|
|
395
408
|
}
|
package/src/typst-parser.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|
import { array_find } from "./generic";
|
|
3
3
|
import { TYPST_NONE, TypstLrData, TypstNamedParams, TypstNode, TypstSupsubData, TypstToken, TypstTokenType } from "./types";
|
|
4
|
+
import { tokenize_typst } from "./typst-tokenizer";
|
|
4
5
|
import { assert, isalpha } from "./util";
|
|
5
|
-
import { reverseShorthandMap } from "./typst-shorthands";
|
|
6
|
-
import { JSLex, Scanner } from "./jslex";
|
|
7
6
|
|
|
8
|
-
const TYPST_SHORTHANDS = Array.from(reverseShorthandMap.keys());
|
|
9
7
|
|
|
10
8
|
// TODO: In Typst, y' ' is not the same as y''.
|
|
11
9
|
// The parser should be able to parse the former correctly.
|
|
@@ -18,77 +16,6 @@ function eat_primes(tokens: TypstToken[], start: number): number {
|
|
|
18
16
|
}
|
|
19
17
|
|
|
20
18
|
|
|
21
|
-
function generate_regex_for_shorthands(): string {
|
|
22
|
-
const regex_list = TYPST_SHORTHANDS.map((s) => {
|
|
23
|
-
s = s.replaceAll('|', '\\|');
|
|
24
|
-
s = s.replaceAll('.', '\\.');
|
|
25
|
-
s = s.replaceAll('[', '\\[');
|
|
26
|
-
s = s.replaceAll(']', '\\]');
|
|
27
|
-
return s;
|
|
28
|
-
});
|
|
29
|
-
return `(${regex_list.join('|')})`;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const REGEX_SHORTHANDS = generate_regex_for_shorthands();
|
|
34
|
-
|
|
35
|
-
const rules_map = new Map<string, (a: Scanner<TypstToken>) => TypstToken | TypstToken[]>([
|
|
36
|
-
[String.raw`//[^\n]*`, (s) => new TypstToken(TypstTokenType.COMMENT, s.text()!.substring(2))],
|
|
37
|
-
[String.raw`/`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
|
|
38
|
-
[String.raw`[_^&]`, (s) => new TypstToken(TypstTokenType.CONTROL, s.text()!)],
|
|
39
|
-
[String.raw`\r?\n`, (_s) => new TypstToken(TypstTokenType.NEWLINE, "\n")],
|
|
40
|
-
[String.raw`\s+`, (s) => new TypstToken(TypstTokenType.SPACE, s.text()!)],
|
|
41
|
-
[String.raw`\\[$&#_]`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
|
|
42
|
-
[String.raw`\\\n`, (s) => {
|
|
43
|
-
return [
|
|
44
|
-
new TypstToken(TypstTokenType.CONTROL, "\\"),
|
|
45
|
-
new TypstToken(TypstTokenType.NEWLINE, "\n"),
|
|
46
|
-
]
|
|
47
|
-
}],
|
|
48
|
-
[String.raw`\\\s`, (s) => {
|
|
49
|
-
return [
|
|
50
|
-
new TypstToken(TypstTokenType.CONTROL, "\\"),
|
|
51
|
-
new TypstToken(TypstTokenType.SPACE, " "),
|
|
52
|
-
]
|
|
53
|
-
}],
|
|
54
|
-
// this backslash is dummy and will be ignored in later stages
|
|
55
|
-
[String.raw`\\\S`, (_s) => new TypstToken(TypstTokenType.CONTROL, "")],
|
|
56
|
-
[
|
|
57
|
-
String.raw`"([^"]|(\\"))*"`,
|
|
58
|
-
(s) => {
|
|
59
|
-
const text = s.text()!.substring(1, s.text()!.length - 1);
|
|
60
|
-
// replace all escape characters with their actual characters
|
|
61
|
-
text.replaceAll('\\"', '"');
|
|
62
|
-
return new TypstToken(TypstTokenType.TEXT, text);
|
|
63
|
-
}
|
|
64
|
-
],
|
|
65
|
-
[
|
|
66
|
-
REGEX_SHORTHANDS,
|
|
67
|
-
(s) => {
|
|
68
|
-
const shorthand = s.text()!;
|
|
69
|
-
const symbol = reverseShorthandMap.get(shorthand)!;
|
|
70
|
-
return new TypstToken(TypstTokenType.SYMBOL, symbol);
|
|
71
|
-
}
|
|
72
|
-
],
|
|
73
|
-
[String.raw`[0-9]+(\.[0-9]+)?`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
|
|
74
|
-
[String.raw`[+\-*/=\'<>!.,;?()\[\]|]`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
|
|
75
|
-
[String.raw`[a-zA-Z\.]+`, (s) => {
|
|
76
|
-
return new TypstToken(s.text()!.length === 1? TypstTokenType.ELEMENT: TypstTokenType.SYMBOL, s.text()!);
|
|
77
|
-
}],
|
|
78
|
-
[String.raw`#none`, (s) => new TypstToken(TypstTokenType.NONE, s.text()!)],
|
|
79
|
-
[String.raw`.`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
|
|
80
|
-
]);
|
|
81
|
-
|
|
82
|
-
const spec = {
|
|
83
|
-
"start": rules_map
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
export function tokenize_typst(input: string): TypstToken[] {
|
|
87
|
-
const lexer = new JSLex<TypstToken>(spec);
|
|
88
|
-
return lexer.collect(input);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
19
|
function _find_closing_match(tokens: TypstToken[], start: number,
|
|
93
20
|
leftBrackets: TypstToken[], rightBrackets: TypstToken[]): number {
|
|
94
21
|
assert(tokens[start].isOneOf(leftBrackets));
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { TypstToken, TypstTokenType } from "./types";
|
|
2
|
+
import { reverseShorthandMap } from "./typst-shorthands";
|
|
3
|
+
import { JSLex, Scanner } from "./jslex";
|
|
4
|
+
|
|
5
|
+
const TYPST_SHORTHANDS = Array.from(reverseShorthandMap.keys());
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
function generate_regex_for_shorthands(): string {
|
|
9
|
+
const regex_list = TYPST_SHORTHANDS.map((s) => {
|
|
10
|
+
s = s.replaceAll('|', '\\|');
|
|
11
|
+
s = s.replaceAll('.', '\\.');
|
|
12
|
+
s = s.replaceAll('[', '\\[');
|
|
13
|
+
s = s.replaceAll(']', '\\]');
|
|
14
|
+
return s;
|
|
15
|
+
});
|
|
16
|
+
return `(${regex_list.join('|')})`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
const REGEX_SHORTHANDS = generate_regex_for_shorthands();
|
|
21
|
+
|
|
22
|
+
const rules_map = new Map<string, (a: Scanner<TypstToken>) => TypstToken | TypstToken[]>([
|
|
23
|
+
[String.raw`//[^\n]*`, (s) => new TypstToken(TypstTokenType.COMMENT, s.text()!.substring(2))],
|
|
24
|
+
[String.raw`/`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
|
|
25
|
+
[String.raw`[_^&]`, (s) => new TypstToken(TypstTokenType.CONTROL, s.text()!)],
|
|
26
|
+
[String.raw`\r?\n`, (_s) => new TypstToken(TypstTokenType.NEWLINE, "\n")],
|
|
27
|
+
[String.raw`\s+`, (s) => new TypstToken(TypstTokenType.SPACE, s.text()!)],
|
|
28
|
+
[String.raw`\\[$&#_]`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
|
|
29
|
+
[String.raw`\\\n`, (s) => {
|
|
30
|
+
return [
|
|
31
|
+
new TypstToken(TypstTokenType.CONTROL, "\\"),
|
|
32
|
+
new TypstToken(TypstTokenType.NEWLINE, "\n"),
|
|
33
|
+
]
|
|
34
|
+
}],
|
|
35
|
+
[String.raw`\\\s`, (s) => {
|
|
36
|
+
return [
|
|
37
|
+
new TypstToken(TypstTokenType.CONTROL, "\\"),
|
|
38
|
+
new TypstToken(TypstTokenType.SPACE, " "),
|
|
39
|
+
]
|
|
40
|
+
}],
|
|
41
|
+
// this backslash is dummy and will be ignored in later stages
|
|
42
|
+
[String.raw`\\\S`, (_s) => new TypstToken(TypstTokenType.CONTROL, "")],
|
|
43
|
+
[
|
|
44
|
+
String.raw`"([^"]|(\\"))*"`,
|
|
45
|
+
(s) => {
|
|
46
|
+
const text = s.text()!.substring(1, s.text()!.length - 1);
|
|
47
|
+
// replace all escape characters with their actual characters
|
|
48
|
+
text.replaceAll('\\"', '"');
|
|
49
|
+
return new TypstToken(TypstTokenType.TEXT, text);
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
[
|
|
53
|
+
REGEX_SHORTHANDS,
|
|
54
|
+
(s) => {
|
|
55
|
+
const shorthand = s.text()!;
|
|
56
|
+
const symbol = reverseShorthandMap.get(shorthand)!;
|
|
57
|
+
return new TypstToken(TypstTokenType.SYMBOL, symbol);
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
[String.raw`[0-9]+(\.[0-9]+)?`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
|
|
61
|
+
[String.raw`[+\-*/=\'<>!.,;?()\[\]|]`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
|
|
62
|
+
[String.raw`[a-zA-Z\.]+`, (s) => {
|
|
63
|
+
return new TypstToken(s.text()!.length === 1? TypstTokenType.ELEMENT: TypstTokenType.SYMBOL, s.text()!);
|
|
64
|
+
}],
|
|
65
|
+
[String.raw`#none`, (s) => new TypstToken(TypstTokenType.NONE, s.text()!)],
|
|
66
|
+
[String.raw`.`, (s) => new TypstToken(TypstTokenType.ELEMENT, s.text()!)],
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
const spec = {
|
|
70
|
+
"start": rules_map
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export function tokenize_typst(input: string): TypstToken[] {
|
|
74
|
+
const lexer = new JSLex<TypstToken>(spec);
|
|
75
|
+
return lexer.collect(input);
|
|
76
|
+
}
|
package/src/typst-writer.ts
CHANGED
|
@@ -11,6 +11,8 @@ const TYPST_RIGHT_PARENTHESIS: TypstToken = new TypstToken(TypstTokenType.ELEMEN
|
|
|
11
11
|
const TYPST_COMMA: TypstToken = new TypstToken(TypstTokenType.ELEMENT, ',');
|
|
12
12
|
const TYPST_NEWLINE: TypstToken = new TypstToken(TypstTokenType.SYMBOL, '\n');
|
|
13
13
|
|
|
14
|
+
const SOFT_SPACE = new TypstToken(TypstTokenType.CONTROL, ' ');
|
|
15
|
+
|
|
14
16
|
function typst_primitive_to_string(value: TypstPrimitiveValue) {
|
|
15
17
|
switch (typeof value) {
|
|
16
18
|
case 'string':
|
|
@@ -40,6 +42,7 @@ export interface TypstWriterOptions {
|
|
|
40
42
|
preferShorthands: boolean;
|
|
41
43
|
keepSpaces: boolean;
|
|
42
44
|
inftyToOo: boolean;
|
|
45
|
+
optimize: boolean;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
export class TypstWriter {
|
|
@@ -47,17 +50,19 @@ export class TypstWriter {
|
|
|
47
50
|
private preferShorthands: boolean;
|
|
48
51
|
private keepSpaces: boolean;
|
|
49
52
|
private inftyToOo: boolean;
|
|
53
|
+
private optimize: boolean;
|
|
50
54
|
|
|
51
55
|
protected buffer: string = "";
|
|
52
56
|
protected queue: TypstToken[] = [];
|
|
53
57
|
|
|
54
58
|
private insideFunctionDepth = 0;
|
|
55
59
|
|
|
56
|
-
constructor(
|
|
57
|
-
this.nonStrict =
|
|
58
|
-
this.preferShorthands =
|
|
59
|
-
this.keepSpaces =
|
|
60
|
-
this.inftyToOo =
|
|
60
|
+
constructor(options: TypstWriterOptions) {
|
|
61
|
+
this.nonStrict = options.nonStrict;
|
|
62
|
+
this.preferShorthands = options.preferShorthands;
|
|
63
|
+
this.keepSpaces = options.keepSpaces;
|
|
64
|
+
this.inftyToOo = options.inftyToOo;
|
|
65
|
+
this.optimize = options.optimize;
|
|
61
66
|
}
|
|
62
67
|
|
|
63
68
|
|
|
@@ -68,8 +73,6 @@ export class TypstWriter {
|
|
|
68
73
|
return;
|
|
69
74
|
}
|
|
70
75
|
|
|
71
|
-
// TODO: "C \frac{xy}{z}" should translate to "C (x y)/z" instead of "C(x y)/z"
|
|
72
|
-
|
|
73
76
|
let no_need_space = false;
|
|
74
77
|
// putting the first token in clause
|
|
75
78
|
no_need_space ||= /[\(\[\|]$/.test(this.buffer) && /^\w/.test(str);
|
|
@@ -163,7 +166,7 @@ export class TypstWriter {
|
|
|
163
166
|
// Put prime symbol before '_'. Because $y_1'$ is not displayed properly in Typst (so far)
|
|
164
167
|
// e.g.
|
|
165
168
|
// y_1' -> y'_1
|
|
166
|
-
// y_{a_1}' -> y'_
|
|
169
|
+
// y_{a_1}' -> y'_(a_1)
|
|
167
170
|
this.queue.push(new TypstToken(TypstTokenType.ELEMENT, '\''));
|
|
168
171
|
trailing_space_needed = false;
|
|
169
172
|
}
|
|
@@ -176,7 +179,7 @@ export class TypstWriter {
|
|
|
176
179
|
trailing_space_needed = this.appendWithBracketsIfNeeded(sup);
|
|
177
180
|
}
|
|
178
181
|
if (trailing_space_needed) {
|
|
179
|
-
this.queue.push(
|
|
182
|
+
this.queue.push(SOFT_SPACE);
|
|
180
183
|
}
|
|
181
184
|
break;
|
|
182
185
|
}
|
|
@@ -207,7 +210,16 @@ export class TypstWriter {
|
|
|
207
210
|
}
|
|
208
211
|
case 'fraction': {
|
|
209
212
|
const [numerator, denominator] = node.args!;
|
|
210
|
-
this.
|
|
213
|
+
const pos = this.queue.length;
|
|
214
|
+
const no_wrap = this.appendWithBracketsIfNeeded(numerator);
|
|
215
|
+
|
|
216
|
+
// This is a dirty hack to force `C \frac{xy}{z}`to translate to `C (x y)/z` instead of `C(x y)/z`
|
|
217
|
+
// To solve this properly, we should implement a Typst formatter
|
|
218
|
+
const wrapped = !no_wrap;
|
|
219
|
+
if (wrapped) {
|
|
220
|
+
this.queue.splice(pos, 0, SOFT_SPACE);
|
|
221
|
+
}
|
|
222
|
+
|
|
211
223
|
this.queue.push(new TypstToken(TypstTokenType.ELEMENT, '/'));
|
|
212
224
|
this.appendWithBracketsIfNeeded(denominator);
|
|
213
225
|
break;
|
|
@@ -331,20 +343,24 @@ export class TypstWriter {
|
|
|
331
343
|
}
|
|
332
344
|
|
|
333
345
|
protected flushQueue() {
|
|
334
|
-
const
|
|
346
|
+
const dummy_token = new TypstToken(TypstTokenType.SYMBOL, '');
|
|
335
347
|
|
|
336
348
|
// delete soft spaces if they are not needed
|
|
337
349
|
for(let i = 0; i < this.queue.length; i++) {
|
|
338
350
|
let token = this.queue[i];
|
|
339
351
|
if (token.eq(SOFT_SPACE)) {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
352
|
+
const to_delete = (i === 0)
|
|
353
|
+
|| (i === this.queue.length - 1)
|
|
354
|
+
|| this.queue[i - 1].isOneOf([TYPST_NEWLINE])
|
|
355
|
+
|| this.queue[i + 1].isOneOf([TYPST_RIGHT_PARENTHESIS, TYPST_COMMA, TYPST_NEWLINE]);
|
|
356
|
+
if (to_delete) {
|
|
357
|
+
this.queue[i] = dummy_token;
|
|
344
358
|
}
|
|
345
359
|
}
|
|
346
360
|
}
|
|
347
361
|
|
|
362
|
+
this.queue = this.queue.filter((token) => !token.eq(dummy_token));
|
|
363
|
+
|
|
348
364
|
this.queue.forEach((token) => {
|
|
349
365
|
this.writeBuffer(token)
|
|
350
366
|
});
|
|
@@ -375,9 +391,11 @@ export class TypstWriter {
|
|
|
375
391
|
res = res.replace(/round\(\)/g, 'round("")');
|
|
376
392
|
return res;
|
|
377
393
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
394
|
+
if (this.optimize) {
|
|
395
|
+
const all_passes = [smartFloorPass, smartCeilPass, smartRoundPass];
|
|
396
|
+
for (const pass of all_passes) {
|
|
397
|
+
this.buffer = pass(this.buffer);
|
|
398
|
+
}
|
|
381
399
|
}
|
|
382
400
|
return this.buffer;
|
|
383
401
|
}
|
package/TODO.md
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
- Typst math `limits(Y)^X` to TeX `\overset{X}{Y}`
|
package/docs/api-reference.md
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# API Reference of tex2typst.js
|
|
2
|
-
|
|
3
|
-
## Basic usage
|
|
4
|
-
|
|
5
|
-
```javascript
|
|
6
|
-
import { tex2typst, typst2tex } from 'tex2typst';
|
|
7
|
-
|
|
8
|
-
let tex = "e \\overset{\\text{def}}{=} \\lim_{{n \\to \\infty}} \left(1 + \\frac{1}{n}\\right)^n";
|
|
9
|
-
let typst = tex2typst(tex);
|
|
10
|
-
console.log(typst);
|
|
11
|
-
// e eq.def lim_(n -> infinity)(1 + 1/n)^n
|
|
12
|
-
|
|
13
|
-
let tex_recovered = typst2tex(typst);
|
|
14
|
-
console.log(tex_recovered);
|
|
15
|
-
// e \overset{\text{def}}{=} \lim_{n \rightarrow \infty} \left(1 + \frac{1}{n} \right)^n
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## Advanced options
|
|
19
|
-
|
|
20
|
-
`tex2typst` function accepts an optional second argument, which is an object containing options to customize the conversion.
|
|
21
|
-
|
|
22
|
-
```typescript
|
|
23
|
-
interface Tex2TypstOptions {
|
|
24
|
-
preferShorthands?: boolean;
|
|
25
|
-
fracToSlash?: boolean;
|
|
26
|
-
inftyToOo?: boolean;
|
|
27
|
-
}
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
- `preferShorthands`: If set to `true`, the function will prefer using shorthands in Typst (e.g., `->` instead of `arrow.r`, `<<` instead of `lt.double`) when converting TeX to Typst. Default is `ture`.
|
|
31
|
-
|
|
32
|
-
```javascript
|
|
33
|
-
let tex = "a \\rightarrow b \\ll c";
|
|
34
|
-
let typst1 = tex2typst(tex, { preferShorthands: false });
|
|
35
|
-
console.log(typst1);
|
|
36
|
-
// a arrow.r b lt.double c
|
|
37
|
-
let typst2 = tex2typst(tex, { preferShorthands: true });
|
|
38
|
-
console.log(typst2);
|
|
39
|
-
// a -> b << c
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
- `fracToSlash`: If set to `true`, the Typst result will use the slash notation for fractions. Default is `true`.
|
|
43
|
-
|
|
44
|
-
```javascript
|
|
45
|
-
let tex = "\\frac{a}{b}";
|
|
46
|
-
let tpyst1 = tex2typst(tex, { fracToSlash: false });
|
|
47
|
-
console.log(typst1);
|
|
48
|
-
// frac(a, b)
|
|
49
|
-
let typst2 = tex2typst(tex, { fracToSlash: true });
|
|
50
|
-
console.log(typst2);
|
|
51
|
-
// a / b
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
- `inftyToOo`: If set to `true`, `\infty` converts to `oo` instead of `infinity`. Default is `false`.
|
|
55
|
-
|
|
56
|
-
```javascript
|
|
57
|
-
let tex = "\\infty";
|
|
58
|
-
let typst1 = tex2typst(tex, { inftyToOo: false });
|
|
59
|
-
console.log(typst1);
|
|
60
|
-
// infinity
|
|
61
|
-
let typst2 = tex2typst(tex, { inftyToOo: true });
|
|
62
|
-
console.log(typst2);
|
|
63
|
-
// oo
|
|
64
|
-
```
|
|
@@ -1,33 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import urllib.request
|
|
2
|
-
from bs4 import BeautifulSoup
|
|
3
|
-
|
|
4
|
-
if __name__ == '__main__':
|
|
5
|
-
symbol_map = {}
|
|
6
|
-
|
|
7
|
-
url = "https://typst.app/docs/reference/symbols/sym/"
|
|
8
|
-
with urllib.request.urlopen(url) as response:
|
|
9
|
-
html_text = response.read().decode('utf-8')
|
|
10
|
-
|
|
11
|
-
soup = BeautifulSoup(html_text, 'html.parser')
|
|
12
|
-
# <ul class="symbol-grid">
|
|
13
|
-
ul = soup.find('ul', class_='symbol-grid')
|
|
14
|
-
li_list = ul.find_all('li')
|
|
15
|
-
for li in li_list:
|
|
16
|
-
# e.g. <li id="symbol-brace.r.double" data-latex-name="\rBrace" data-codepoint="10628"><button>...</button></li>
|
|
17
|
-
# ==> latex = rBrace
|
|
18
|
-
# ==> typst = brace.r.double
|
|
19
|
-
# ==> unicode = 10628 = \u2984
|
|
20
|
-
latex = li.get('data-latex-name', None)
|
|
21
|
-
typst = li['id'][7:]
|
|
22
|
-
unicode = int(li['data-codepoint'])
|
|
23
|
-
if latex is not None:
|
|
24
|
-
# some latex macro can be associated with multiple typst
|
|
25
|
-
# e.g. \equiv can be mapped to equal or equiv.triple
|
|
26
|
-
# We only keep the first one
|
|
27
|
-
if latex not in symbol_map:
|
|
28
|
-
symbol_map[latex] = typst
|
|
29
|
-
|
|
30
|
-
# sort the pairs with alphabetical order of latex
|
|
31
|
-
sorted_keys = sorted(list(symbol_map.keys()), key=str.lower)
|
|
32
|
-
sorted_symbol_map = [(key, symbol_map[key]) for key in sorted_keys]
|
|
33
|
-
for latex, typst in sorted_symbol_map:
|
|
34
|
-
print(f" ['{latex[1:]}', '{typst}'],")
|
|
35
|
-
# print(f'{latex[1:]} = "{typst}"')
|