@drghaliasri/butex 3.2.2 → 4.0.0

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.
@@ -531,6 +531,7 @@ function createInlineField2(value = "", mathObjects = [], options = {}, path = "
531
531
  opening: span.opening,
532
532
  closing: span.closing,
533
533
  source: span.source,
534
+ sourceSide: mode,
534
535
  math: fromMathObjectJson(mathJson, mode),
535
536
  editable: true,
536
537
  sourceOwner: "imported-structured"
@@ -1133,6 +1134,24 @@ var ATOMIC_OPERATOR_COMMANDS = {
1133
1134
  title: "\u0623\u0643\u0628\u0631 \u0645\u0646 \u0623\u0648 \u064A\u0633\u0627\u0648\u064A",
1134
1135
  svg_path: null
1135
1136
  },
1137
+ coloneqq: {
1138
+ id: "coloneqq",
1139
+ category: "operators1",
1140
+ Tex: "\\coloneqq",
1141
+ mirror: true,
1142
+ Label: "\u2254",
1143
+ title: "\u064A\u0639\u0631\u0641 \u0628\u0623\u0646\u0647 \u064A\u0633\u0627\u0648\u064A",
1144
+ svg_path: null
1145
+ },
1146
+ eqqcolon: {
1147
+ id: "eqqcolon",
1148
+ category: "operators1",
1149
+ Tex: "\\eqqcolon",
1150
+ mirror: true,
1151
+ Label: "\u2255",
1152
+ title: "\u064A\u0633\u0627\u0648\u064A \u0628\u0627\u0644\u062A\u0639\u0631\u064A\u0641",
1153
+ svg_path: null
1154
+ },
1136
1155
  ///// Operators 2
1137
1156
  propto: {
1138
1157
  id: "propto",
@@ -1299,6 +1318,60 @@ var ATOMIC_OPERATOR_COMMANDS = {
1299
1318
  title: "\u064A\u0643\u0627\u0641\u0626",
1300
1319
  svg_path: null
1301
1320
  },
1321
+ implies: {
1322
+ id: "implies",
1323
+ category: "operators3",
1324
+ Tex: "\\implies",
1325
+ mirror: true,
1326
+ Label: "\u21D2",
1327
+ title: "\u064A\u0633\u062A\u0644\u0632\u0645",
1328
+ svg_path: null
1329
+ },
1330
+ impliedby: {
1331
+ id: "impliedby",
1332
+ category: "operators3",
1333
+ Tex: "\\impliedby",
1334
+ mirror: true,
1335
+ Label: "\u21D0",
1336
+ title: "\u0645\u0633\u062A\u0644\u0632\u0645 \u0645\u0646",
1337
+ svg_path: null
1338
+ },
1339
+ iff: {
1340
+ id: "iff",
1341
+ category: "operators3",
1342
+ Tex: "\\iff",
1343
+ mirror: false,
1344
+ Label: "\u21D4",
1345
+ title: "\u0625\u0630\u0627 \u0648\u0641\u0642\u0637 \u0625\u0630\u0627",
1346
+ svg_path: null
1347
+ },
1348
+ Longrightarrow: {
1349
+ id: "Longrightarrow",
1350
+ category: "operators3",
1351
+ Tex: "\\Longrightarrow",
1352
+ mirror: true,
1353
+ Label: "\u27F9",
1354
+ title: "\u0633\u0647\u0645 \u0645\u0632\u062F\u0648\u062C \u0637\u0648\u064A\u0644 \u0625\u0644\u0649 \u0627\u0644\u064A\u0645\u064A\u0646",
1355
+ svg_path: null
1356
+ },
1357
+ Longleftarrow: {
1358
+ id: "Longleftarrow",
1359
+ category: "operators3",
1360
+ Tex: "\\Longleftarrow",
1361
+ mirror: true,
1362
+ Label: "\u27F8",
1363
+ title: "\u0633\u0647\u0645 \u0645\u0632\u062F\u0648\u062C \u0637\u0648\u064A\u0644 \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631",
1364
+ svg_path: null
1365
+ },
1366
+ to: {
1367
+ id: "to",
1368
+ category: "operators3",
1369
+ Tex: "\\to",
1370
+ mirror: true,
1371
+ Label: "\u2192",
1372
+ title: "\u064A\u0624\u0648\u0644 \u0625\u0644\u0649",
1373
+ svg_path: null
1374
+ },
1302
1375
  rightleftharpoons: {
1303
1376
  id: "rightleftharpoons",
1304
1377
  category: "operators3",
@@ -1639,6 +1712,23 @@ function formatDigits(value, digitForm = "western") {
1639
1712
  function selectedDigitForm(options) {
1640
1713
  return options?.digitForm ?? "western";
1641
1714
  }
1715
+ function latinScripts(node, options) {
1716
+ let scripts = "";
1717
+ if (node.superscript) {
1718
+ scripts += `^{${renderChainEnglish(node.superscript, options)}}`;
1719
+ }
1720
+ if (node.subscript) {
1721
+ scripts += `_{${renderChainEnglish(node.subscript, options)}}`;
1722
+ }
1723
+ return scripts;
1724
+ }
1725
+ function optionalRootIndexEnglish(node, options) {
1726
+ if (!node.rootIndex) {
1727
+ return "";
1728
+ }
1729
+ const rendered = renderChainEnglish(node.rootIndex, options);
1730
+ return rendered === "" ? "" : `[${rendered}]`;
1731
+ }
1642
1732
  function optionalRootIndexArabic(node, options) {
1643
1733
  if (!node.rootIndex) {
1644
1734
  return "";
@@ -1654,6 +1744,21 @@ function arabicScripts(node, content, options) {
1654
1744
  }
1655
1745
  return content;
1656
1746
  }
1747
+ function renderMatrixRowsEnglish(node, options) {
1748
+ if (!node.matrixRows) {
1749
+ return "";
1750
+ }
1751
+ const envName = node.envName ?? node.matrixStyle;
1752
+ if (!envName) {
1753
+ return "";
1754
+ }
1755
+ const rows = node.matrixRows.map((row) => row.map((cell) => renderChainEnglish(cell, options)).join(" & "));
1756
+ if (envName === "array") {
1757
+ const spec = (node.columnAlignments ?? []).slice(0, node.matrixRows[0]?.length ?? 0).join("");
1758
+ return `\\begin{array}{${spec || "c"}}${rows.join(" \\\\\n")}\\end{array}`;
1759
+ }
1760
+ return `\\begin{${envName}}${rows.join(" \\\\\n")}\\end{${envName}}`;
1761
+ }
1657
1762
  function reverseAlignmentForArabic(alignment) {
1658
1763
  if (alignment === "l") {
1659
1764
  return "r";
@@ -1697,6 +1802,34 @@ function renderCharContent(node, options) {
1697
1802
  }
1698
1803
  return expr;
1699
1804
  }
1805
+ function renderNodeEnglish(node, options) {
1806
+ if (node.kind === "delimiter" && node.innerExpr) {
1807
+ return `${node.leftDelimExpr}${renderChainEnglish(node.innerExpr, options)}${node.rightDelimExpr}${latinScripts(node, options)}`;
1808
+ }
1809
+ if (node.kind === "frac" && node.numerator && node.denominator) {
1810
+ const body = `\\frac{${renderChainEnglish(node.numerator, options)}}{${renderChainEnglish(node.denominator, options)}}`;
1811
+ return `${body}${latinScripts(node, options)}`;
1812
+ }
1813
+ if (node.kind === "sqrt" && node.radicand) {
1814
+ const body = `\\sqrt${optionalRootIndexEnglish(node, options)}{${renderChainEnglish(node.radicand, options)}}`;
1815
+ return `${body}${latinScripts(node, options)}`;
1816
+ }
1817
+ if (node.kind === "env") {
1818
+ return `${renderMatrixRowsEnglish(node, options)}${latinScripts(node, options)}`;
1819
+ }
1820
+ if (node.kind === "atomicCommand") {
1821
+ const body = atomicCommandSpec(node.expr)?.englishTex ?? node.expr;
1822
+ return `${body}${latinScripts(node, options)}`;
1823
+ }
1824
+ if (node.kind === "atomicOperatorCommand") {
1825
+ const body = atomicOperatorCommandSpec(node.expr)?.Tex ?? node.expr;
1826
+ return `${body}${latinScripts(node, options)}`;
1827
+ }
1828
+ if (node.kind === "char") {
1829
+ return `${renderCharContent(node, options)}${latinScripts(node, options)}`;
1830
+ }
1831
+ return `${formatDigits(node.expr, selectedDigitForm(options))}${latinScripts(node, options)}`;
1832
+ }
1700
1833
  function renderNodeArabic(node, options) {
1701
1834
  if (node.kind === "delimiter" && node.innerExpr) {
1702
1835
  const content = `${node.leftDelimExpr}${renderChainArabic(node.innerExpr, options)}${node.rightDelimExpr}`;
@@ -1731,9 +1864,15 @@ function renderNodeArabic(node, options) {
1731
1864
  }
1732
1865
  return arabicScripts(node, formatDigits(node.expr, selectedDigitForm(options)), options);
1733
1866
  }
1867
+ function renderChainEnglish(chain, options) {
1868
+ return chain.nodes.map((node) => renderNodeEnglish(node, options)).join(" ");
1869
+ }
1734
1870
  function renderChainArabic(chain, options) {
1735
1871
  return chain.nodes.slice().reverse().map((node) => renderNodeArabic(node, options)).join(" ");
1736
1872
  }
1873
+ function renderEnglishLatexFromSession(session) {
1874
+ return renderChainEnglish(session.englishTree, { digitForm: session.currentDigitForm ?? "western" });
1875
+ }
1737
1876
  function renderArabicLatexFromSession(session) {
1738
1877
  return renderChainArabic(session.arabicTree, { digitForm: session.currentDigitForm ?? "western" });
1739
1878
  }
@@ -2664,15 +2803,18 @@ function mathNodeFromEditorSession(session, mathMode = "$", closing = "$") {
2664
2803
  }
2665
2804
 
2666
2805
  // src/document2/mathBridge.ts
2667
- function createEmptyArabicEquationSession() {
2806
+ function createEmptyEquationSession(side = "arabic") {
2668
2807
  const english = createEditorChain();
2669
2808
  const arabic = createEditorChain();
2670
2809
  arabic.id = english.id;
2671
- const session = createEditorSession(english, arabic, "arabic");
2810
+ const session = createEditorSession(english, arabic, side);
2672
2811
  session.sync = buildInitialSyncMap(session.englishTree, session.arabicTree);
2673
2812
  return session;
2674
2813
  }
2675
- function mathTokenToArabicEditorSession(math) {
2814
+ function createEmptyArabicEquationSession() {
2815
+ return createEmptyEquationSession("arabic");
2816
+ }
2817
+ function mathTokenToEditorSession(math, side = "arabic") {
2676
2818
  if (!math) {
2677
2819
  return { editable: false, reason: "\u0647\u0630\u0647 \u0627\u0644\u0645\u0639\u0627\u062F\u0644\u0629 \u0645\u062D\u0641\u0648\u0638\u0629 \u0643\u0646\u0635 \u062E\u0627\u0645 \u0641\u0642\u0637 \u062D\u0627\u0644\u064A\u0627" };
2678
2820
  }
@@ -2680,12 +2822,15 @@ function mathTokenToArabicEditorSession(math) {
2680
2822
  if (!result.editable) {
2681
2823
  return result;
2682
2824
  }
2683
- result.session.activeSide = "arabic";
2825
+ result.session.activeSide = side;
2684
2826
  result.session.sync = buildInitialSyncMap(result.session.englishTree, result.session.arabicTree);
2685
2827
  return result;
2686
2828
  }
2687
- function mathSourceFromArabicSession(session, opening = "$", closing = "$") {
2688
- const inner = renderArabicLatexFromSession(session);
2829
+ function mathTokenToArabicEditorSession(math) {
2830
+ return mathTokenToEditorSession(math, "arabic");
2831
+ }
2832
+ function mathSourceFromSession(session, side, opening = "$", closing = "$") {
2833
+ const inner = side === "english" ? renderEnglishLatexFromSession(session) : renderArabicLatexFromSession(session);
2689
2834
  if (opening === "$" || opening === "\\(") {
2690
2835
  return opening + inner + closing;
2691
2836
  }
@@ -2698,13 +2843,32 @@ ${closing}`;
2698
2843
  ${inner}
2699
2844
  ${closing}`;
2700
2845
  }
2701
- function mathNodeFromArabicSession(session, opening = "$", closing = "$") {
2846
+ function mathSourceFromArabicSession(session, opening = "$", closing = "$") {
2847
+ return mathSourceFromSession(session, "arabic", opening, closing);
2848
+ }
2849
+ function mathNodeFromSession(session, opening = "$", closing = "$") {
2702
2850
  const converted = mathNodeFromEditorSession(session, opening, closing);
2703
2851
  if (converted.ok) {
2704
2852
  return converted.math;
2705
2853
  }
2706
2854
  return { nodeType: "MathObject", mathMode: opening, lines: [], closing };
2707
2855
  }
2856
+ function mathNodeFromArabicSession(session, opening = "$", closing = "$") {
2857
+ return mathNodeFromSession(session, opening, closing);
2858
+ }
2859
+ function mathTokenSourceForSide(token, side) {
2860
+ if (!token.math || token.sourceOwner === "raw") {
2861
+ return token.source;
2862
+ }
2863
+ if (token.sourceSide === side) {
2864
+ return token.source;
2865
+ }
2866
+ const result = mathTokenToEditorSession(token.math, side);
2867
+ if (!result.editable) {
2868
+ return token.source;
2869
+ }
2870
+ return mathSourceFromSession(result.session, side, token.opening, token.closing);
2871
+ }
2708
2872
 
2709
2873
  // src/document2/commands.ts
2710
2874
  function cloneToken(token) {
@@ -2789,15 +2953,16 @@ function updateTextToken(document2, fieldId, tokenId, text) {
2789
2953
  });
2790
2954
  return next;
2791
2955
  }
2792
- function mathTokenFromSession(session, opening = "$", closing = "$") {
2956
+ function mathTokenFromSession(session, opening = "$", closing = "$", side = "arabic") {
2793
2957
  return {
2794
2958
  id: document2Id("math"),
2795
2959
  kind: "math",
2796
2960
  display: opening === "$$" || opening === "\\[" || opening.startsWith("\\begin{"),
2797
2961
  opening,
2798
2962
  closing,
2799
- source: mathSourceFromArabicSession(session, opening, closing),
2800
- math: mathNodeFromArabicSession(session, opening, closing),
2963
+ source: mathSourceFromSession(session, side, opening, closing),
2964
+ sourceSide: side,
2965
+ math: mathNodeFromSession(session, opening, closing),
2801
2966
  editable: true,
2802
2967
  sourceOwner: "editor"
2803
2968
  };
@@ -2883,9 +3048,9 @@ function splitTextTokenAt(token, offset) {
2883
3048
  { id: document2Id("text"), kind: "text", text: token.text.slice(safeOffset) }
2884
3049
  ];
2885
3050
  }
2886
- function insertMathTokenAtCaret(document2, fieldId, textTokenId, caretOffset, session, opening = "$", closing = "$") {
3051
+ function insertMathTokenAtCaret(document2, fieldId, textTokenId, caretOffset, session, opening = "$", closing = "$", side = "arabic") {
2887
3052
  const next = cloneDocument(document2);
2888
- const mathToken = mathTokenFromSession(session, opening, closing);
3053
+ const mathToken = mathTokenFromSession(session, opening, closing, side);
2889
3054
  visitFields(next.blocks, (field) => {
2890
3055
  if (field.id !== fieldId) {
2891
3056
  return false;
@@ -2910,9 +3075,9 @@ function insertMathTokenAtCaret(document2, fieldId, textTokenId, caretOffset, se
2910
3075
  });
2911
3076
  return next;
2912
3077
  }
2913
- function insertMathToken(document2, fieldId, insertIndex, session, opening = "$", closing = "$") {
3078
+ function insertMathToken(document2, fieldId, insertIndex, session, opening = "$", closing = "$", side = "arabic") {
2914
3079
  const next = cloneDocument(document2);
2915
- const mathToken = mathTokenFromSession(session, opening, closing);
3080
+ const mathToken = mathTokenFromSession(session, opening, closing, side);
2916
3081
  visitFields(next.blocks, (field) => {
2917
3082
  if (field.id !== fieldId) {
2918
3083
  return false;
@@ -2930,7 +3095,7 @@ function insertMathToken(document2, fieldId, insertIndex, session, opening = "$"
2930
3095
  });
2931
3096
  return next;
2932
3097
  }
2933
- function replaceMathTokenFromSession(document2, tokenId, session, opening, closing) {
3098
+ function replaceMathTokenFromSession(document2, tokenId, session, opening, closing, side = "arabic") {
2934
3099
  const next = cloneDocument(document2);
2935
3100
  visitFields(next.blocks, (field) => {
2936
3101
  const index = field.tokens.findIndex((token) => token.id === tokenId && token.kind === "math");
@@ -2940,7 +3105,7 @@ function replaceMathTokenFromSession(document2, tokenId, session, opening, closi
2940
3105
  const current = field.tokens[index];
2941
3106
  const open = opening ?? current.opening;
2942
3107
  const close = closing ?? current.closing;
2943
- field.tokens[index] = mathTokenFromSession(session, open, close);
3108
+ field.tokens[index] = mathTokenFromSession(session, open, close, side);
2944
3109
  field.tokens[index].id = current.id;
2945
3110
  return true;
2946
3111
  });
@@ -3152,23 +3317,20 @@ function document2HistoryCanRedo(stacks) {
3152
3317
  }
3153
3318
 
3154
3319
  // src/document2/previewModel.ts
3155
- function mathTex(token) {
3320
+ function mathTex(token, equationSide) {
3156
3321
  if (token.kind === "text") {
3157
3322
  return token.text;
3158
3323
  }
3159
- if (!token.math || token.sourceOwner === "raw" || token.sourceOwner === "editor") {
3160
- return token.source;
3161
- }
3162
- return renderMathNodeLatex(token.math);
3324
+ return mathTokenSourceForSide(token, equationSide);
3163
3325
  }
3164
- function previewInlines(field, islands, output) {
3326
+ function previewInlines(field, islands, output, equationSide) {
3165
3327
  return field.tokens.map((token) => {
3166
3328
  if (token.kind === "text") {
3167
3329
  return { kind: "text", text: token.text };
3168
3330
  }
3169
3331
  const island = {
3170
3332
  id: token.id,
3171
- tex: mathTex(token),
3333
+ tex: mathTex(token, equationSide),
3172
3334
  display: token.display,
3173
3335
  output,
3174
3336
  editable: token.editable
@@ -3177,21 +3339,21 @@ function previewInlines(field, islands, output) {
3177
3339
  return { kind: "math", ...island };
3178
3340
  });
3179
3341
  }
3180
- function textBlockPreview(block, islands, output) {
3342
+ function textBlockPreview(block, islands, output, equationSide) {
3181
3343
  if (block.command === "\\section") {
3182
- return { kind: "heading", id: block.id, level: 1, inlines: previewInlines(block.field, islands, output) };
3344
+ return { kind: "heading", id: block.id, level: 1, inlines: previewInlines(block.field, islands, output, equationSide) };
3183
3345
  }
3184
3346
  if (block.command === "\\subsection") {
3185
- return { kind: "heading", id: block.id, level: 2, inlines: previewInlines(block.field, islands, output) };
3347
+ return { kind: "heading", id: block.id, level: 2, inlines: previewInlines(block.field, islands, output, equationSide) };
3186
3348
  }
3187
3349
  if (block.command === "\\subsubsection") {
3188
- return { kind: "heading", id: block.id, level: 3, inlines: previewInlines(block.field, islands, output) };
3350
+ return { kind: "heading", id: block.id, level: 3, inlines: previewInlines(block.field, islands, output, equationSide) };
3189
3351
  }
3190
- return { kind: "paragraph", id: block.id, inlines: previewInlines(block.field, islands, output) };
3352
+ return { kind: "paragraph", id: block.id, inlines: previewInlines(block.field, islands, output, equationSide) };
3191
3353
  }
3192
- function blockPreview(block, islands, output) {
3354
+ function blockPreview(block, islands, output, equationSide) {
3193
3355
  if (block.kind === "textBlock") {
3194
- return textBlockPreview(block, islands, output);
3356
+ return textBlockPreview(block, islands, output, equationSide);
3195
3357
  }
3196
3358
  if (block.kind === "list") {
3197
3359
  return {
@@ -3200,23 +3362,23 @@ function blockPreview(block, islands, output) {
3200
3362
  ordered: block.command === "\\begin{enumerate}",
3201
3363
  items: block.items.map((item) => ({
3202
3364
  id: item.id,
3203
- inlines: previewInlines(item.field, islands, output),
3204
- blocks: item.blocks.map((child) => blockPreview(child, islands, output))
3365
+ inlines: previewInlines(item.field, islands, output, equationSide),
3366
+ blocks: item.blocks.map((child) => blockPreview(child, islands, output, equationSide))
3205
3367
  }))
3206
3368
  };
3207
3369
  }
3208
3370
  if (block.kind === "table") {
3209
- return { kind: "table", id: block.id, rows: block.rows.map((row) => row.map((cell) => previewInlines(cell, islands, output))) };
3371
+ return { kind: "table", id: block.id, rows: block.rows.map((row) => row.map((cell) => previewInlines(cell, islands, output, equationSide))) };
3210
3372
  }
3211
3373
  if (block.kind === "image") {
3212
3374
  return { kind: "image", id: block.id, src: block.value, options: block.options };
3213
3375
  }
3214
3376
  return { kind: "omit", id: block.id };
3215
3377
  }
3216
- function document2Preview(document2, output = "svg") {
3378
+ function document2Preview(document2, output = "svg", equationSide = "arabic") {
3217
3379
  const mathIslands = [];
3218
3380
  return {
3219
- blocks: document2.blocks.map((block) => blockPreview(block, mathIslands, output)),
3381
+ blocks: document2.blocks.map((block) => blockPreview(block, mathIslands, output, equationSide)),
3220
3382
  mathIslands
3221
3383
  };
3222
3384
  }
@@ -3231,6 +3393,7 @@ export {
3231
3393
  createDocument2History,
3232
3394
  createEmptyArabicEquationSession,
3233
3395
  createEmptyDocument2,
3396
+ createEmptyEquationSession,
3234
3397
  createInlineField2,
3235
3398
  detectMathSpans2,
3236
3399
  document2HistoryCanRedo,
@@ -3244,8 +3407,12 @@ export {
3244
3407
  insertMathToken,
3245
3408
  insertMathTokenAtCaret,
3246
3409
  mathNodeFromArabicSession,
3410
+ mathNodeFromSession,
3247
3411
  mathSourceFromArabicSession,
3412
+ mathSourceFromSession,
3413
+ mathTokenSourceForSide,
3248
3414
  mathTokenToArabicEditorSession,
3415
+ mathTokenToEditorSession,
3249
3416
  moveDocument2BlockById,
3250
3417
  pushDocument2Snapshot,
3251
3418
  removeDocument2BlockById,