tex2typst 0.3.16 → 0.3.18
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 +176 -85
- package/dist/tex2typst.min.js +12 -12
- package/dist/types.d.ts +14 -7
- package/dist/typst-writer.d.ts +3 -1
- package/package.json +1 -1
- package/src/convert.ts +178 -62
- package/src/index.ts +1 -0
- package/src/map.ts +2 -0
- package/src/tex-parser.ts +17 -4
- package/src/types.ts +21 -7
- package/src/typst-writer.ts +17 -26
- 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/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# tex2typst.js
|
|
2
2
|
|
|
3
|
-
JavaScript library for conversion between TeX/LaTeX and Typst math
|
|
3
|
+
JavaScript library for conversion between TeX/LaTeX and Typst math code.
|
|
4
4
|
|
|
5
5
|
Despite the name `tex2typst` due to the initial goal of converting TeX to Typst, the library can also convert Typst to TeX since version 0.3.0.
|
|
6
6
|
|
|
@@ -44,7 +44,7 @@ console.log(tex_recovered);
|
|
|
44
44
|
|
|
45
45
|
If you are using the library in a web page via a `<script>` tag, you don't need the line of `import`, function `tex2typst` and `typst2tex` should be available in the global scope.
|
|
46
46
|
|
|
47
|
-
tex2typst.js supports some advanced options to customize the conversion. For
|
|
47
|
+
tex2typst.js supports some advanced options to customize the conversion. For details, please refer to the [API Reference](docs/api-reference.md).
|
|
48
48
|
|
|
49
49
|
## Open-source license
|
|
50
50
|
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// src/map.ts
|
|
2
2
|
var symbolMap = /* @__PURE__ */ new Map([
|
|
3
3
|
["displaystyle", "display"],
|
|
4
|
+
["|", "bar.v.double"],
|
|
5
|
+
["!", "#h(-math.thin.amount)"],
|
|
4
6
|
[",", "thin"],
|
|
5
7
|
[":", "med"],
|
|
6
8
|
[";", "thick"],
|
|
@@ -1185,6 +1187,12 @@ var TexNode = class {
|
|
|
1185
1187
|
case "ordgroup": {
|
|
1186
1188
|
return this.args.map((n) => n.serialize()).flat();
|
|
1187
1189
|
}
|
|
1190
|
+
case "leftright": {
|
|
1191
|
+
let tokens = this.args.map((n) => n.serialize()).flat();
|
|
1192
|
+
tokens.splice(0, 0, new TexToken(1 /* COMMAND */, "\\left"));
|
|
1193
|
+
tokens.splice(tokens.length - 1, 0, new TexToken(1 /* COMMAND */, "\\right"));
|
|
1194
|
+
return tokens;
|
|
1195
|
+
}
|
|
1188
1196
|
case "unaryFunc": {
|
|
1189
1197
|
let tokens = [];
|
|
1190
1198
|
tokens.push(new TexToken(1 /* COMMAND */, this.content));
|
|
@@ -1666,7 +1674,8 @@ var BINARY_COMMANDS = [
|
|
|
1666
1674
|
"dbinom",
|
|
1667
1675
|
"dfrac",
|
|
1668
1676
|
"tbinom",
|
|
1669
|
-
"overset"
|
|
1677
|
+
"overset",
|
|
1678
|
+
"underset"
|
|
1670
1679
|
];
|
|
1671
1680
|
var IGNORED_COMMANDS = [
|
|
1672
1681
|
"bigl",
|
|
@@ -1701,7 +1710,7 @@ function eat_whitespaces(tokens, start) {
|
|
|
1701
1710
|
}
|
|
1702
1711
|
function eat_parenthesis(tokens, start) {
|
|
1703
1712
|
const firstToken = tokens[start];
|
|
1704
|
-
if (firstToken.type === 0 /* ELEMENT */ && ["(", ")", "[", "]", "|", "\\{", "\\}", "."].includes(firstToken.value)) {
|
|
1713
|
+
if (firstToken.type === 0 /* ELEMENT */ && ["(", ")", "[", "]", "|", "\\{", "\\}", ".", "\\|"].includes(firstToken.value)) {
|
|
1705
1714
|
return firstToken;
|
|
1706
1715
|
} else if (firstToken.type === 1 /* COMMAND */ && ["lfloor", "rfloor", "lceil", "rceil", "langle", "rangle"].includes(firstToken.value.slice(1))) {
|
|
1707
1716
|
return firstToken;
|
|
@@ -1767,7 +1776,7 @@ var rules_map = /* @__PURE__ */ new Map([
|
|
|
1767
1776
|
],
|
|
1768
1777
|
[String.raw`%[^\n]*`, (s) => new TexToken(3 /* COMMENT */, s.text().substring(1))],
|
|
1769
1778
|
[String.raw`[{}_^&]`, (s) => new TexToken(6 /* CONTROL */, s.text())],
|
|
1770
|
-
[String.raw`\\[
|
|
1779
|
+
[String.raw`\\[\\,:;! ]`, (s) => new TexToken(6 /* CONTROL */, s.text())],
|
|
1771
1780
|
[String.raw`\r?\n`, (_s) => new TexToken(5 /* NEWLINE */, "\n")],
|
|
1772
1781
|
[String.raw`\s+`, (s) => new TexToken(4 /* SPACE */, s.text())],
|
|
1773
1782
|
[String.raw`\\[{}%$&#_|]`, (s) => new TexToken(0 /* ELEMENT */, s.text())],
|
|
@@ -1973,6 +1982,7 @@ var LatexParser = class {
|
|
|
1973
1982
|
case "}":
|
|
1974
1983
|
throw new LatexParserError("Unmatched '}'");
|
|
1975
1984
|
case "\\\\":
|
|
1985
|
+
case "\\!":
|
|
1976
1986
|
case "\\,":
|
|
1977
1987
|
case "\\:":
|
|
1978
1988
|
case "\\;":
|
|
@@ -2108,7 +2118,17 @@ var LatexParser = class {
|
|
|
2108
2118
|
assert(tokens[pos + 2].eq(RIGHT_CURLY_BRACKET));
|
|
2109
2119
|
const envName = tokens[pos + 1].value;
|
|
2110
2120
|
pos += 3;
|
|
2111
|
-
|
|
2121
|
+
const args = [];
|
|
2122
|
+
while (pos < tokens.length) {
|
|
2123
|
+
const whitespaceCount = eat_whitespaces(tokens, pos).length;
|
|
2124
|
+
pos += whitespaceCount;
|
|
2125
|
+
if (pos >= tokens.length || !tokens[pos].eq(LEFT_CURLY_BRACKET)) {
|
|
2126
|
+
break;
|
|
2127
|
+
}
|
|
2128
|
+
const [arg, newPos] = this.parseNextArg(tokens, pos);
|
|
2129
|
+
args.push(arg);
|
|
2130
|
+
pos = newPos;
|
|
2131
|
+
}
|
|
2112
2132
|
const exprInsideStart = pos;
|
|
2113
2133
|
const endIdx = find_closing_end_command(tokens, start);
|
|
2114
2134
|
if (endIdx === -1) {
|
|
@@ -2128,7 +2148,7 @@ var LatexParser = class {
|
|
|
2128
2148
|
exprInside.pop();
|
|
2129
2149
|
}
|
|
2130
2150
|
const body = this.parseAligned(exprInside);
|
|
2131
|
-
const res = new TexNode("beginend", envName,
|
|
2151
|
+
const res = new TexNode("beginend", envName, args, body);
|
|
2132
2152
|
return [res, pos];
|
|
2133
2153
|
}
|
|
2134
2154
|
parseAligned(tokens) {
|
|
@@ -2275,14 +2295,15 @@ var TypstWriterError = class extends Error {
|
|
|
2275
2295
|
}
|
|
2276
2296
|
};
|
|
2277
2297
|
var TypstWriter = class {
|
|
2278
|
-
constructor(
|
|
2298
|
+
constructor(options) {
|
|
2279
2299
|
this.buffer = "";
|
|
2280
2300
|
this.queue = [];
|
|
2281
2301
|
this.insideFunctionDepth = 0;
|
|
2282
|
-
this.nonStrict =
|
|
2283
|
-
this.preferShorthands =
|
|
2284
|
-
this.keepSpaces =
|
|
2285
|
-
this.inftyToOo =
|
|
2302
|
+
this.nonStrict = options.nonStrict;
|
|
2303
|
+
this.preferShorthands = options.preferShorthands;
|
|
2304
|
+
this.keepSpaces = options.keepSpaces;
|
|
2305
|
+
this.inftyToOo = options.inftyToOo;
|
|
2306
|
+
this.optimize = options.optimize;
|
|
2286
2307
|
}
|
|
2287
2308
|
writeBuffer(token) {
|
|
2288
2309
|
const str = token.toString();
|
|
@@ -2407,21 +2428,9 @@ var TypstWriter = class {
|
|
|
2407
2428
|
}
|
|
2408
2429
|
case "fraction": {
|
|
2409
2430
|
const [numerator, denominator] = node.args;
|
|
2410
|
-
|
|
2411
|
-
this.queue.push(TYPST_LEFT_PARENTHESIS);
|
|
2412
|
-
this.serialize(numerator);
|
|
2413
|
-
this.queue.push(TYPST_RIGHT_PARENTHESIS);
|
|
2414
|
-
} else {
|
|
2415
|
-
this.serialize(numerator);
|
|
2416
|
-
}
|
|
2431
|
+
this.appendWithBracketsIfNeeded(numerator);
|
|
2417
2432
|
this.queue.push(new TypstToken(2 /* ELEMENT */, "/"));
|
|
2418
|
-
|
|
2419
|
-
this.queue.push(TYPST_LEFT_PARENTHESIS);
|
|
2420
|
-
this.serialize(denominator);
|
|
2421
|
-
this.queue.push(TYPST_RIGHT_PARENTHESIS);
|
|
2422
|
-
} else {
|
|
2423
|
-
this.serialize(denominator);
|
|
2424
|
-
}
|
|
2433
|
+
this.appendWithBracketsIfNeeded(denominator);
|
|
2425
2434
|
break;
|
|
2426
2435
|
}
|
|
2427
2436
|
case "align": {
|
|
@@ -2506,7 +2515,7 @@ var TypstWriter = class {
|
|
|
2506
2515
|
}
|
|
2507
2516
|
}
|
|
2508
2517
|
appendWithBracketsIfNeeded(node) {
|
|
2509
|
-
let need_to_wrap = ["group", "supsub", "empty"].includes(node.type);
|
|
2518
|
+
let need_to_wrap = ["group", "supsub", "fraction", "empty"].includes(node.type);
|
|
2510
2519
|
if (node.type === "group") {
|
|
2511
2520
|
if (node.args.length === 0) {
|
|
2512
2521
|
need_to_wrap = true;
|
|
@@ -2561,9 +2570,11 @@ var TypstWriter = class {
|
|
|
2561
2570
|
res = res.replace(/round\(\)/g, 'round("")');
|
|
2562
2571
|
return res;
|
|
2563
2572
|
};
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2573
|
+
if (this.optimize) {
|
|
2574
|
+
const all_passes = [smartFloorPass, smartCeilPass, smartRoundPass];
|
|
2575
|
+
for (const pass of all_passes) {
|
|
2576
|
+
this.buffer = pass(this.buffer);
|
|
2577
|
+
}
|
|
2567
2578
|
}
|
|
2568
2579
|
return this.buffer;
|
|
2569
2580
|
}
|
|
@@ -2585,8 +2596,6 @@ function tex_token_to_typst(token) {
|
|
|
2585
2596
|
return token;
|
|
2586
2597
|
} else if (token === "/") {
|
|
2587
2598
|
return "\\/";
|
|
2588
|
-
} else if (token === "\\|") {
|
|
2589
|
-
return "parallel";
|
|
2590
2599
|
} else if (token === "\\\\") {
|
|
2591
2600
|
return "\\";
|
|
2592
2601
|
} else if (["\\$", "\\#", "\\&", "\\_"].includes(token)) {
|
|
@@ -2603,39 +2612,48 @@ function tex_token_to_typst(token) {
|
|
|
2603
2612
|
}
|
|
2604
2613
|
function convert_overset(node, options) {
|
|
2605
2614
|
const [sup, base] = node.args;
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
}
|
|
2610
|
-
if (n.type === "ordgroup" && n.args.length === 3) {
|
|
2611
|
-
const [a1, a2, a3] = n.args;
|
|
2612
|
-
const d = new TexNode("element", "d");
|
|
2613
|
-
const e = new TexNode("element", "e");
|
|
2614
|
-
const f = new TexNode("element", "f");
|
|
2615
|
-
if (a1.eq(d) && a2.eq(e) && a3.eq(f)) {
|
|
2615
|
+
if (options.optimize) {
|
|
2616
|
+
const is_def = (n) => {
|
|
2617
|
+
if (n.eq(new TexNode("text", "def"))) {
|
|
2616
2618
|
return true;
|
|
2617
2619
|
}
|
|
2620
|
+
if (n.type === "ordgroup" && n.args.length === 3) {
|
|
2621
|
+
const [a1, a2, a3] = n.args;
|
|
2622
|
+
const d = new TexNode("element", "d");
|
|
2623
|
+
const e = new TexNode("element", "e");
|
|
2624
|
+
const f = new TexNode("element", "f");
|
|
2625
|
+
if (a1.eq(d) && a2.eq(e) && a3.eq(f)) {
|
|
2626
|
+
return true;
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
return false;
|
|
2630
|
+
};
|
|
2631
|
+
const is_eq = (n) => n.eq(new TexNode("element", "="));
|
|
2632
|
+
if (is_def(sup) && is_eq(base)) {
|
|
2633
|
+
return new TypstNode("symbol", "eq.def");
|
|
2618
2634
|
}
|
|
2619
|
-
return false;
|
|
2620
|
-
};
|
|
2621
|
-
const is_eq = (n) => n.eq(new TexNode("element", "="));
|
|
2622
|
-
if (is_def(sup) && is_eq(base)) {
|
|
2623
|
-
return new TypstNode("symbol", "eq.def");
|
|
2624
2635
|
}
|
|
2625
2636
|
const limits_call = new TypstNode(
|
|
2626
2637
|
"funcCall",
|
|
2627
2638
|
"limits",
|
|
2628
2639
|
[convert_tex_node_to_typst(base, options)]
|
|
2629
2640
|
);
|
|
2630
|
-
return new TypstNode(
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2641
|
+
return new TypstNode("supsub", "", [], {
|
|
2642
|
+
base: limits_call,
|
|
2643
|
+
sup: convert_tex_node_to_typst(sup, options)
|
|
2644
|
+
});
|
|
2645
|
+
}
|
|
2646
|
+
function convert_underset(node, options) {
|
|
2647
|
+
const [sub, base] = node.args;
|
|
2648
|
+
const limits_call = new TypstNode(
|
|
2649
|
+
"funcCall",
|
|
2650
|
+
"limits",
|
|
2651
|
+
[convert_tex_node_to_typst(base, options)]
|
|
2638
2652
|
);
|
|
2653
|
+
return new TypstNode("supsub", "", [], {
|
|
2654
|
+
base: limits_call,
|
|
2655
|
+
sub: convert_tex_node_to_typst(sub, options)
|
|
2656
|
+
});
|
|
2639
2657
|
}
|
|
2640
2658
|
function convert_tex_node_to_typst(node, options = {}) {
|
|
2641
2659
|
switch (node.type) {
|
|
@@ -2695,39 +2713,51 @@ function convert_tex_node_to_typst(node, options = {}) {
|
|
|
2695
2713
|
return new TypstNode("supsub", "", [], data);
|
|
2696
2714
|
}
|
|
2697
2715
|
case "leftright": {
|
|
2698
|
-
const [left,
|
|
2716
|
+
const [left, _body, right] = node.args;
|
|
2717
|
+
const [typ_left, typ_body, typ_right] = node.args.map((n) => convert_tex_node_to_typst(n, options));
|
|
2718
|
+
if (options.optimize) {
|
|
2719
|
+
if (left.content === "\\|" && right.content === "\\|") {
|
|
2720
|
+
return new TypstNode("funcCall", "norm", [typ_body]);
|
|
2721
|
+
}
|
|
2722
|
+
if ([
|
|
2723
|
+
"[]",
|
|
2724
|
+
"()",
|
|
2725
|
+
"\\{\\}",
|
|
2726
|
+
"\\lfloor\\rfloor",
|
|
2727
|
+
"\\lceil\\rceil",
|
|
2728
|
+
"\\lfloor\\rceil"
|
|
2729
|
+
].includes(left.content + right.content)) {
|
|
2730
|
+
return new TypstNode("group", "", [typ_left, typ_body, typ_right]);
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
2699
2733
|
const group = new TypstNode(
|
|
2700
2734
|
"group",
|
|
2701
2735
|
"",
|
|
2702
|
-
|
|
2736
|
+
[typ_left, typ_body, typ_right]
|
|
2703
2737
|
);
|
|
2704
|
-
|
|
2705
|
-
"[]
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
].includes(left.content + right.content)) {
|
|
2712
|
-
return group;
|
|
2713
|
-
}
|
|
2738
|
+
const escape_curly_or_paren = function(s) {
|
|
2739
|
+
if (["(", ")", "{", "["].includes(s)) {
|
|
2740
|
+
return "\\" + s;
|
|
2741
|
+
} else {
|
|
2742
|
+
return s;
|
|
2743
|
+
}
|
|
2744
|
+
};
|
|
2714
2745
|
if (right.content === ".") {
|
|
2715
|
-
|
|
2716
|
-
|
|
2746
|
+
typ_left.content = escape_curly_or_paren(typ_left.content);
|
|
2747
|
+
group.args = [typ_left, typ_body];
|
|
2717
2748
|
} else if (left.content === ".") {
|
|
2718
|
-
|
|
2719
|
-
|
|
2749
|
+
typ_right.content = escape_curly_or_paren(typ_right.content);
|
|
2750
|
+
group.args = [typ_body, typ_right];
|
|
2720
2751
|
}
|
|
2721
|
-
return new TypstNode(
|
|
2722
|
-
"funcCall",
|
|
2723
|
-
"lr",
|
|
2724
|
-
[group]
|
|
2725
|
-
);
|
|
2752
|
+
return new TypstNode("funcCall", "lr", [group]);
|
|
2726
2753
|
}
|
|
2727
2754
|
case "binaryFunc": {
|
|
2728
2755
|
if (node.content === "\\overset") {
|
|
2729
2756
|
return convert_overset(node, options);
|
|
2730
2757
|
}
|
|
2758
|
+
if (node.content === "\\underset") {
|
|
2759
|
+
return convert_underset(node, options);
|
|
2760
|
+
}
|
|
2731
2761
|
if (node.content === "\\frac") {
|
|
2732
2762
|
if (options.fracToSlash) {
|
|
2733
2763
|
return new TypstNode(
|
|
@@ -2817,6 +2847,49 @@ function convert_tex_node_to_typst(node, options = {}) {
|
|
|
2817
2847
|
if (node.content === "cases") {
|
|
2818
2848
|
return new TypstNode("cases", "", [], data);
|
|
2819
2849
|
}
|
|
2850
|
+
if (node.content === "array") {
|
|
2851
|
+
const res = new TypstNode("matrix", "", [], data);
|
|
2852
|
+
const options2 = { "delim": TYPST_NONE };
|
|
2853
|
+
const align_args = node.args;
|
|
2854
|
+
if (align_args.length > 0) {
|
|
2855
|
+
const align_node = align_args[0];
|
|
2856
|
+
const align_str = (() => {
|
|
2857
|
+
if (align_node.type === "element") return align_node.content;
|
|
2858
|
+
if (align_node.type === "ordgroup") {
|
|
2859
|
+
return align_node.args.map((n) => n.type === "element" ? n.content : "").join("");
|
|
2860
|
+
}
|
|
2861
|
+
return "";
|
|
2862
|
+
})();
|
|
2863
|
+
if (align_str) {
|
|
2864
|
+
const alignMap = { l: "#left", c: "#center", r: "#right" };
|
|
2865
|
+
const chars = Array.from(align_str);
|
|
2866
|
+
const alignments = chars.map((c) => alignMap[c]).filter(Boolean).map((s) => new TypstNode("symbol", s));
|
|
2867
|
+
const vlinePositions = [];
|
|
2868
|
+
let columnIndex = 0;
|
|
2869
|
+
for (const c of chars) {
|
|
2870
|
+
if (c === "|") {
|
|
2871
|
+
vlinePositions.push(columnIndex);
|
|
2872
|
+
} else if (c === "l" || c === "c" || c === "r") {
|
|
2873
|
+
columnIndex++;
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2876
|
+
if (vlinePositions.length > 0) {
|
|
2877
|
+
if (vlinePositions.length === 1) {
|
|
2878
|
+
options2["augment"] = new TypstNode("symbol", `#${vlinePositions[0]}`);
|
|
2879
|
+
} else {
|
|
2880
|
+
options2["augment"] = new TypstNode("symbol", `#(vline: (${vlinePositions.join(", ")}))`);
|
|
2881
|
+
}
|
|
2882
|
+
}
|
|
2883
|
+
if (alignments.length > 0) {
|
|
2884
|
+
const first_align = alignments[0].content;
|
|
2885
|
+
const all_same = alignments.every((item) => item.content === first_align);
|
|
2886
|
+
options2["align"] = all_same ? alignments[0] : new TypstNode("symbol", "#center");
|
|
2887
|
+
}
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
res.setOptions(options2);
|
|
2891
|
+
return res;
|
|
2892
|
+
}
|
|
2820
2893
|
if (node.content.endsWith("matrix")) {
|
|
2821
2894
|
let delim;
|
|
2822
2895
|
switch (node.content) {
|
|
@@ -2881,7 +2954,9 @@ var TYPST_UNARY_FUNCTIONS = [
|
|
|
2881
2954
|
"cal",
|
|
2882
2955
|
"frak",
|
|
2883
2956
|
"floor",
|
|
2884
|
-
"ceil"
|
|
2957
|
+
"ceil",
|
|
2958
|
+
"norm",
|
|
2959
|
+
"limits"
|
|
2885
2960
|
];
|
|
2886
2961
|
var TYPST_BINARY_FUNCTIONS = [
|
|
2887
2962
|
"frac",
|
|
@@ -2898,8 +2973,6 @@ function apply_escape_if_needed2(c) {
|
|
|
2898
2973
|
function typst_token_to_tex(token) {
|
|
2899
2974
|
if (/^[a-zA-Z0-9]$/.test(token)) {
|
|
2900
2975
|
return token;
|
|
2901
|
-
} else if (token === "thin") {
|
|
2902
|
-
return "\\,";
|
|
2903
2976
|
} else if (reverseSymbolMap.has(token)) {
|
|
2904
2977
|
return "\\" + reverseSymbolMap.get(token);
|
|
2905
2978
|
}
|
|
@@ -2964,15 +3037,21 @@ function convert_typst_node_to_tex(node) {
|
|
|
2964
3037
|
return new TexNode("ordgroup", "", node.args.map(convert_typst_node_to_tex));
|
|
2965
3038
|
}
|
|
2966
3039
|
}
|
|
3040
|
+
if (node.content === "norm") {
|
|
3041
|
+
const arg0 = node.args[0];
|
|
3042
|
+
const tex_node_type = node.isOverHigh() ? "leftright" : "ordgroup";
|
|
3043
|
+
return new TexNode(tex_node_type, "", [
|
|
3044
|
+
new TexNode("symbol", "\\|"),
|
|
3045
|
+
convert_typst_node_to_tex(arg0),
|
|
3046
|
+
new TexNode("symbol", "\\|")
|
|
3047
|
+
]);
|
|
3048
|
+
}
|
|
2967
3049
|
if (node.content === "floor" || node.content === "ceil") {
|
|
2968
|
-
|
|
2969
|
-
|
|
3050
|
+
const left = "\\l" + node.content;
|
|
3051
|
+
const right = "\\r" + node.content;
|
|
2970
3052
|
const arg0 = node.args[0];
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
right = "\\right" + right;
|
|
2974
|
-
}
|
|
2975
|
-
return new TexNode("ordgroup", "", [
|
|
3053
|
+
const tex_node_type = node.isOverHigh() ? "leftright" : "ordgroup";
|
|
3054
|
+
return new TexNode(tex_node_type, "", [
|
|
2976
3055
|
new TexNode("symbol", left),
|
|
2977
3056
|
convert_typst_node_to_tex(arg0),
|
|
2978
3057
|
new TexNode("symbol", right)
|
|
@@ -3010,7 +3089,6 @@ function convert_typst_node_to_tex(node) {
|
|
|
3010
3089
|
}
|
|
3011
3090
|
case "supsub": {
|
|
3012
3091
|
const { base, sup, sub } = node.data;
|
|
3013
|
-
const base_tex = convert_typst_node_to_tex(base);
|
|
3014
3092
|
let sup_tex;
|
|
3015
3093
|
let sub_tex;
|
|
3016
3094
|
if (sup) {
|
|
@@ -3019,6 +3097,18 @@ function convert_typst_node_to_tex(node) {
|
|
|
3019
3097
|
if (sub) {
|
|
3020
3098
|
sub_tex = convert_typst_node_to_tex(sub);
|
|
3021
3099
|
}
|
|
3100
|
+
if (base.eq(new TypstNode("funcCall", "limits"))) {
|
|
3101
|
+
const body_in_limits = convert_typst_node_to_tex(base.args[0]);
|
|
3102
|
+
if (sup_tex !== void 0 && sub_tex === void 0) {
|
|
3103
|
+
return new TexNode("binaryFunc", "\\overset", [sup_tex, body_in_limits]);
|
|
3104
|
+
} else if (sup_tex === void 0 && sub_tex !== void 0) {
|
|
3105
|
+
return new TexNode("binaryFunc", "\\underset", [sub_tex, body_in_limits]);
|
|
3106
|
+
} else {
|
|
3107
|
+
const underset_call = new TexNode("binaryFunc", "\\underset", [sub_tex, body_in_limits]);
|
|
3108
|
+
return new TexNode("binaryFunc", "\\overset", [sup_tex, underset_call]);
|
|
3109
|
+
}
|
|
3110
|
+
}
|
|
3111
|
+
const base_tex = convert_typst_node_to_tex(base);
|
|
3022
3112
|
const res = new TexNode("supsub", "", [], {
|
|
3023
3113
|
base: base_tex,
|
|
3024
3114
|
sup: sup_tex,
|
|
@@ -3648,6 +3738,7 @@ function tex2typst(tex, options) {
|
|
|
3648
3738
|
keepSpaces: false,
|
|
3649
3739
|
fracToSlash: true,
|
|
3650
3740
|
inftyToOo: false,
|
|
3741
|
+
optimize: true,
|
|
3651
3742
|
nonAsciiWrapper: "",
|
|
3652
3743
|
customTexMacros: {}
|
|
3653
3744
|
};
|