temml 0.10.13 → 0.10.14

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/temml.mjs CHANGED
@@ -1115,6 +1115,7 @@ defineSymbol(math, rel, "\u2ab7", "\\precapprox", true);
1115
1115
  defineSymbol(math, rel, "\u22b2", "\\vartriangleleft");
1116
1116
  defineSymbol(math, rel, "\u22b4", "\\trianglelefteq");
1117
1117
  defineSymbol(math, rel, "\u22a8", "\\vDash", true);
1118
+ defineSymbol(math, rel, "\u22ab", "\\VDash", true);
1118
1119
  defineSymbol(math, rel, "\u22aa", "\\Vvdash", true);
1119
1120
  defineSymbol(math, rel, "\u2323", "\\smallsmile");
1120
1121
  defineSymbol(math, rel, "\u2322", "\\smallfrown");
@@ -1764,13 +1765,16 @@ for (let i = 0; i < 10; i++) {
1764
1765
  * much of this module.
1765
1766
  */
1766
1767
 
1768
+ const openDelims = "([{⌊⌈⟨⟮⎰⟦⦃";
1769
+ const closeDelims = ")]}⌋⌉⟩⟯⎱⟦⦄";
1770
+
1767
1771
  function setLineBreaks(expression, wrapMode, isDisplayMode) {
1768
1772
  const mtrs = [];
1769
1773
  let mrows = [];
1770
1774
  let block = [];
1771
1775
  let numTopLevelEquals = 0;
1772
- let canBeBIN = false; // The first node cannot be an infix binary operator.
1773
1776
  let i = 0;
1777
+ let level = 0;
1774
1778
  while (i < expression.length) {
1775
1779
  while (expression[i] instanceof DocumentFragment) {
1776
1780
  expression.splice(i, 1, ...expression[i].children); // Expand the fragment.
@@ -1793,7 +1797,12 @@ function setLineBreaks(expression, wrapMode, isDisplayMode) {
1793
1797
  }
1794
1798
  block.push(node);
1795
1799
  if (node.type && node.type === "mo" && node.children.length === 1) {
1796
- if (wrapMode === "=" && node.children[0].text === "=") {
1800
+ const ch = node.children[0].text;
1801
+ if (openDelims.indexOf(ch) > -1) {
1802
+ level += 1;
1803
+ } else if (closeDelims.indexOf(ch) > -1) {
1804
+ level -= 1;
1805
+ } else if (level === 0 && wrapMode === "=" && ch === "=") {
1797
1806
  numTopLevelEquals += 1;
1798
1807
  if (numTopLevelEquals > 1) {
1799
1808
  block.pop();
@@ -1802,59 +1811,48 @@ function setLineBreaks(expression, wrapMode, isDisplayMode) {
1802
1811
  mrows.push(element);
1803
1812
  block = [node];
1804
1813
  }
1805
- } else if (wrapMode === "tex") {
1806
- // This may be a place for a soft line break.
1807
- if (canBeBIN && !node.attributes.form) {
1808
- // Check if the following node is a \nobreak text node, e.g. "~""
1809
- const next = i < expression.length - 1 ? expression[i + 1] : null;
1810
- let glueIsFreeOfNobreak = true;
1811
- if (
1812
- !(
1813
- next &&
1814
- next.type === "mtext" &&
1815
- next.attributes.linebreak &&
1816
- next.attributes.linebreak === "nobreak"
1817
- )
1818
- ) {
1819
- // We may need to start a new block.
1820
- // First, put any post-operator glue on same line as operator.
1821
- for (let j = i + 1; j < expression.length; j++) {
1822
- const nd = expression[j];
1814
+ } else if (level === 0 && wrapMode === "tex") {
1815
+ // Check if the following node is a \nobreak text node, e.g. "~""
1816
+ const next = i < expression.length - 1 ? expression[i + 1] : null;
1817
+ let glueIsFreeOfNobreak = true;
1818
+ if (
1819
+ !(
1820
+ next &&
1821
+ next.type === "mtext" &&
1822
+ next.attributes.linebreak &&
1823
+ next.attributes.linebreak === "nobreak"
1824
+ )
1825
+ ) {
1826
+ // We may need to start a new block.
1827
+ // First, put any post-operator glue on same line as operator.
1828
+ for (let j = i + 1; j < expression.length; j++) {
1829
+ const nd = expression[j];
1830
+ if (
1831
+ nd.type &&
1832
+ nd.type === "mspace" &&
1833
+ !(nd.attributes.linebreak && nd.attributes.linebreak === "newline")
1834
+ ) {
1835
+ block.push(nd);
1836
+ i += 1;
1823
1837
  if (
1824
- nd.type &&
1825
- nd.type === "mspace" &&
1826
- !(nd.attributes.linebreak && nd.attributes.linebreak === "newline")
1838
+ nd.attributes &&
1839
+ nd.attributes.linebreak &&
1840
+ nd.attributes.linebreak === "nobreak"
1827
1841
  ) {
1828
- block.push(nd);
1829
- i += 1;
1830
- if (
1831
- nd.attributes &&
1832
- nd.attributes.linebreak &&
1833
- nd.attributes.linebreak === "nobreak"
1834
- ) {
1835
- glueIsFreeOfNobreak = false;
1836
- }
1837
- } else {
1838
- break;
1842
+ glueIsFreeOfNobreak = false;
1839
1843
  }
1844
+ } else {
1845
+ break;
1840
1846
  }
1841
1847
  }
1842
- if (glueIsFreeOfNobreak) {
1843
- // Start a new block. (Insert a soft linebreak.)
1844
- const element = new mathMLTree.MathNode("mrow", block);
1845
- mrows.push(element);
1846
- block = [];
1847
- }
1848
- canBeBIN = false;
1849
1848
  }
1850
- const isOpenDelimiter = node.attributes.form && node.attributes.form === "prefix";
1851
- // Any operator that follows an open delimiter is unary.
1852
- canBeBIN = !(node.attributes.separator || isOpenDelimiter);
1853
- } else {
1854
- canBeBIN = true;
1849
+ if (glueIsFreeOfNobreak) {
1850
+ // Start a new block. (Insert a soft linebreak.)
1851
+ const element = new mathMLTree.MathNode("mrow", block);
1852
+ mrows.push(element);
1853
+ block = [];
1854
+ }
1855
1855
  }
1856
- } else {
1857
- canBeBIN = true;
1858
1856
  }
1859
1857
  i += 1;
1860
1858
  }
@@ -2133,7 +2131,10 @@ function buildMathML(tree, texExpression, style, settings) {
2133
2131
  math.setAttribute("display", "block");
2134
2132
  math.style.display = math.children.length === 1 && math.children[0].type === "mtable"
2135
2133
  ? "inline"
2136
- : "block math";
2134
+ : "block math"; // necessary in Chromium.
2135
+ // Firefox and Safari do not recognize display: "block math".
2136
+ // Set a class so that the CSS file can set display: block.
2137
+ math.classes = ["tml-display"];
2137
2138
  }
2138
2139
  return math;
2139
2140
  }
@@ -3662,10 +3663,9 @@ defineFunction({
3662
3663
  // so we have to explicitly set stretchy to true.
3663
3664
  node.setAttribute("stretchy", "true");
3664
3665
  }
3665
-
3666
3666
  node.setAttribute("symmetric", "true"); // Needed for tall arrows in Firefox.
3667
3667
  node.setAttribute("minsize", sizeToMaxHeight[group.size] + "em");
3668
- // Don't set the maxsize attribute. It's broken in Chromium.
3668
+ node.setAttribute("maxsize", sizeToMaxHeight[group.size] + "em");
3669
3669
  return node;
3670
3670
  }
3671
3671
  });
@@ -3800,33 +3800,31 @@ const padding$1 = _ => {
3800
3800
 
3801
3801
  const mathmlBuilder$8 = (group, style) => {
3802
3802
  let node;
3803
- if (group.label.indexOf("colorbox") > -1) {
3804
- // Chrome mpadded +width attribute is broken. Insert <mspace>
3805
- node = new mathMLTree.MathNode("mpadded", [
3803
+ if (group.label.indexOf("colorbox") > -1 || group.label === "\\boxed") {
3804
+ // MathML core does not support +width attribute in <mpadded>.
3805
+ // Firefox does not reliably add side padding.
3806
+ // Insert <mspace>
3807
+ node = new mathMLTree.MathNode("mrow", [
3806
3808
  padding$1(),
3807
3809
  buildGroup$1(group.body, style),
3808
3810
  padding$1()
3809
3811
  ]);
3810
3812
  } else {
3811
- node = new mathMLTree.MathNode("menclose", [buildGroup$1(group.body, style)]);
3813
+ node = new mathMLTree.MathNode("mrow", [buildGroup$1(group.body, style)]);
3812
3814
  }
3813
3815
  switch (group.label) {
3814
3816
  case "\\overline":
3815
- node.setAttribute("notation", "top");
3816
3817
  node.style.padding = "0.1em 0 0 0";
3817
3818
  node.style.borderTop = "0.065em solid";
3818
3819
  break
3819
3820
  case "\\underline":
3820
- node.setAttribute("notation", "bottom");
3821
3821
  node.style.padding = "0 0 0.1em 0";
3822
3822
  node.style.borderBottom = "0.065em solid";
3823
3823
  break
3824
3824
  case "\\cancel":
3825
- node.setAttribute("notation", "updiagonalstrike");
3826
3825
  node.classes.push("cancel");
3827
3826
  break
3828
3827
  case "\\bcancel":
3829
- node.setAttribute("notation", "downdiagonalstrike");
3830
3828
  node.classes.push("bcancel");
3831
3829
  break
3832
3830
  /*
@@ -3837,18 +3835,21 @@ const mathmlBuilder$8 = (group, style) => {
3837
3835
  node.setAttribute("notation", "phasorangle");
3838
3836
  break */
3839
3837
  case "\\angl":
3840
- node.setAttribute("notation", "actuarial");
3841
3838
  node.style.padding = "0.03889em 0.03889em 0 0.03889em";
3842
3839
  node.style.borderTop = "0.049em solid";
3843
3840
  node.style.borderRight = "0.049em solid";
3844
3841
  node.style.marginRight = "0.03889em";
3845
3842
  break
3846
3843
  case "\\sout":
3847
- node.setAttribute("notation", "horizontalstrike");
3848
3844
  node.style["text-decoration"] = "line-through 0.08em solid";
3849
3845
  break
3846
+ case "\\boxed":
3847
+ // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} from amsmath.sty
3848
+ node.style = { padding: "3pt 0 3pt 0", border: "1px solid" };
3849
+ node.setAttribute("scriptlevel", "0");
3850
+ node.setAttribute("displaystyle", "true");
3851
+ break
3850
3852
  case "\\fbox":
3851
- node.setAttribute("notation", "box");
3852
3853
  node.style = { padding: "3pt", border: "1px solid" };
3853
3854
  break
3854
3855
  case "\\fcolorbox":
@@ -3868,7 +3869,6 @@ const mathmlBuilder$8 = (group, style) => {
3868
3869
  break
3869
3870
  }
3870
3871
  case "\\xcancel":
3871
- node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
3872
3872
  node.classes.push("xcancel");
3873
3873
  break
3874
3874
  }
@@ -3963,7 +3963,7 @@ defineFunction({
3963
3963
 
3964
3964
  defineFunction({
3965
3965
  type: "enclose",
3966
- names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline"],
3966
+ names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline", "\\boxed"],
3967
3967
  // , "\\phase", "\\longdiv"
3968
3968
  props: {
3969
3969
  numArgs: 1
@@ -6829,8 +6829,6 @@ defineFunction({
6829
6829
  }
6830
6830
  });
6831
6831
 
6832
- const sign = num => num >= 0 ? "+" : "-";
6833
-
6834
6832
  // \raise, \lower, and \raisebox
6835
6833
 
6836
6834
  const mathmlBuilder = (group, style) => {
@@ -6838,11 +6836,13 @@ const mathmlBuilder = (group, style) => {
6838
6836
  const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, newStyle)]);
6839
6837
  const dy = calculateSize(group.dy, style);
6840
6838
  node.setAttribute("voffset", dy.number + dy.unit);
6841
- const dyAbs = Math.abs(dy.number);
6842
- // The next two lines do not work in Chromium.
6843
- // TODO: Find some other way to adjust height and depth.
6844
- node.setAttribute("height", sign(dy.number) + dyAbs + dy.unit);
6845
- node.setAttribute("depth", sign(-dy.number) + dyAbs + dy.unit);
6839
+ // Add padding, which acts to increase height in Chromium.
6840
+ // TODO: Figure out some way to change height in Firefox w/o breaking Chromium.
6841
+ if (dy.number > 0) {
6842
+ node.style.padding = dy.number + dy.unit + " 0 0 0";
6843
+ } else {
6844
+ node.style.padding = "0 0 " + Math.abs(dy.number) + dy.unit + " 0";
6845
+ }
6846
6846
  return node
6847
6847
  };
6848
6848
 
@@ -8471,9 +8471,6 @@ defineMacro("\u22ee", "\\vdots");
8471
8471
  //\newcommand{\substack}[1]{\subarray{c}#1\endsubarray}
8472
8472
  defineMacro("\\substack", "\\begin{subarray}{c}#1\\end{subarray}");
8473
8473
 
8474
- // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}}
8475
- defineMacro("\\boxed", "\\fbox{$\\displaystyle{#1}$}");
8476
-
8477
8474
  // \def\iff{\DOTSB\;\Longleftrightarrow\;}
8478
8475
  // \def\implies{\DOTSB\;\Longrightarrow\;}
8479
8476
  // \def\impliedby{\DOTSB\;\Longleftarrow\;}
@@ -8722,7 +8719,7 @@ defineMacro(
8722
8719
  defineMacro(
8723
8720
  "\\Temml",
8724
8721
  // eslint-disable-next-line max-len
8725
- "\\textrm{T}\\kern-0.2em\\lower{0.2em}\\textrm{E}\\kern-0.08em{\\textrm{M}\\kern-0.08em\\raise{0.2em}\\textrm{M}\\kern-0.08em\\textrm{L}}"
8722
+ "\\textrm{T}\\kern-0.2em\\lower{0.2em}{\\textrm{E}}\\kern-0.08em{\\textrm{M}\\kern-0.08em\\raise{0.2em}\\textrm{M}\\kern-0.08em\\textrm{L}}"
8726
8723
  );
8727
8724
 
8728
8725
  // \DeclareRobustCommand\hspace{\@ifstar\@hspacer\@hspace}
@@ -12902,7 +12899,7 @@ class Style {
12902
12899
  * https://mit-license.org/
12903
12900
  */
12904
12901
 
12905
- const version = "0.10.13";
12902
+ const version = "0.10.14";
12906
12903
 
12907
12904
  function postProcess(block) {
12908
12905
  const labelMap = {};
@@ -14,7 +14,7 @@
14
14
  * https://mit-license.org/
15
15
  */
16
16
 
17
- const version = "0.10.13";
17
+ const version = "0.10.14";
18
18
 
19
19
  function postProcess(block) {
20
20
  const labelMap = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "temml",
3
- "version": "0.10.13",
3
+ "version": "0.10.14",
4
4
  "description": "TeX to MathML conversion in JavaScript.",
5
5
  "main": "dist/temml.js",
6
6
  "engines": {
@@ -262,7 +262,10 @@ export default function buildMathML(tree, texExpression, style, settings) {
262
262
  math.setAttribute("display", "block");
263
263
  math.style.display = math.children.length === 1 && math.children[0].type === "mtable"
264
264
  ? "inline"
265
- : "block math"
265
+ : "block math" // necessary in Chromium.
266
+ // Firefox and Safari do not recognize display: "block math".
267
+ // Set a class so that the CSS file can set display: block.
268
+ math.classes = ["tml-display"]
266
269
  }
267
270
  return math;
268
271
  }
@@ -178,10 +178,9 @@ defineFunction({
178
178
  // so we have to explicitly set stretchy to true.
179
179
  node.setAttribute("stretchy", "true")
180
180
  }
181
-
182
181
  node.setAttribute("symmetric", "true"); // Needed for tall arrows in Firefox.
183
- node.setAttribute("minsize", sizeToMaxHeight[group.size] + "em");
184
- // Don't set the maxsize attribute. It's broken in Chromium.
182
+ node.setAttribute("minsize", sizeToMaxHeight[group.size] + "em")
183
+ node.setAttribute("maxsize", sizeToMaxHeight[group.size] + "em")
185
184
  return node;
186
185
  }
187
186
  });
@@ -12,33 +12,31 @@ const padding = _ => {
12
12
 
13
13
  const mathmlBuilder = (group, style) => {
14
14
  let node
15
- if (group.label.indexOf("colorbox") > -1) {
16
- // Chrome mpadded +width attribute is broken. Insert <mspace>
17
- node = new mathMLTree.MathNode("mpadded", [
15
+ if (group.label.indexOf("colorbox") > -1 || group.label === "\\boxed") {
16
+ // MathML core does not support +width attribute in <mpadded>.
17
+ // Firefox does not reliably add side padding.
18
+ // Insert <mspace>
19
+ node = new mathMLTree.MathNode("mrow", [
18
20
  padding(),
19
21
  mml.buildGroup(group.body, style),
20
22
  padding()
21
23
  ])
22
24
  } else {
23
- node = new mathMLTree.MathNode("menclose", [mml.buildGroup(group.body, style)])
25
+ node = new mathMLTree.MathNode("mrow", [mml.buildGroup(group.body, style)])
24
26
  }
25
27
  switch (group.label) {
26
28
  case "\\overline":
27
- node.setAttribute("notation", "top")
28
29
  node.style.padding = "0.1em 0 0 0"
29
30
  node.style.borderTop = "0.065em solid"
30
31
  break
31
32
  case "\\underline":
32
- node.setAttribute("notation", "bottom")
33
33
  node.style.padding = "0 0 0.1em 0"
34
34
  node.style.borderBottom = "0.065em solid"
35
35
  break
36
36
  case "\\cancel":
37
- node.setAttribute("notation", "updiagonalstrike");
38
37
  node.classes.push("cancel")
39
38
  break
40
39
  case "\\bcancel":
41
- node.setAttribute("notation", "downdiagonalstrike");
42
40
  node.classes.push("bcancel")
43
41
  break
44
42
  /*
@@ -49,18 +47,21 @@ const mathmlBuilder = (group, style) => {
49
47
  node.setAttribute("notation", "phasorangle");
50
48
  break */
51
49
  case "\\angl":
52
- node.setAttribute("notation", "actuarial")
53
50
  node.style.padding = "0.03889em 0.03889em 0 0.03889em"
54
51
  node.style.borderTop = "0.049em solid"
55
52
  node.style.borderRight = "0.049em solid"
56
53
  node.style.marginRight = "0.03889em"
57
54
  break
58
55
  case "\\sout":
59
- node.setAttribute("notation", "horizontalstrike");
60
56
  node.style["text-decoration"] = "line-through 0.08em solid"
61
57
  break
58
+ case "\\boxed":
59
+ // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} from amsmath.sty
60
+ node.style = { padding: "3pt 0 3pt 0", border: "1px solid" }
61
+ node.setAttribute("scriptlevel", "0")
62
+ node.setAttribute("displaystyle", "true")
63
+ break
62
64
  case "\\fbox":
63
- node.setAttribute("notation", "box");
64
65
  node.style = { padding: "3pt", border: "1px solid" }
65
66
  break
66
67
  case "\\fcolorbox":
@@ -80,7 +81,6 @@ const mathmlBuilder = (group, style) => {
80
81
  break
81
82
  }
82
83
  case "\\xcancel":
83
- node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
84
84
  node.classes.push("xcancel")
85
85
  break
86
86
  }
@@ -175,7 +175,7 @@ defineFunction({
175
175
 
176
176
  defineFunction({
177
177
  type: "enclose",
178
- names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline"],
178
+ names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline", "\\boxed"],
179
179
  // , "\\phase", "\\longdiv"
180
180
  props: {
181
181
  numArgs: 1
@@ -5,8 +5,6 @@ import { assertNodeType } from "../parseNode"
5
5
  import { calculateSize } from "../units"
6
6
  import * as mml from "../buildMathML"
7
7
 
8
- const sign = num => num >= 0 ? "+" : "-"
9
-
10
8
  // \raise, \lower, and \raisebox
11
9
 
12
10
  const mathmlBuilder = (group, style) => {
@@ -14,11 +12,13 @@ const mathmlBuilder = (group, style) => {
14
12
  const node = new mathMLTree.MathNode("mpadded", [mml.buildGroup(group.body, newStyle)])
15
13
  const dy = calculateSize(group.dy, style)
16
14
  node.setAttribute("voffset", dy.number + dy.unit)
17
- const dyAbs = Math.abs(dy.number)
18
- // The next two lines do not work in Chromium.
19
- // TODO: Find some other way to adjust height and depth.
20
- node.setAttribute("height", sign(dy.number) + dyAbs + dy.unit)
21
- node.setAttribute("depth", sign(-dy.number) + dyAbs + dy.unit)
15
+ // Add padding, which acts to increase height in Chromium.
16
+ // TODO: Figure out some way to change height in Firefox w/o breaking Chromium.
17
+ if (dy.number > 0) {
18
+ node.style.padding = dy.number + dy.unit + " 0 0 0"
19
+ } else {
20
+ node.style.padding = "0 0 " + Math.abs(dy.number) + dy.unit + " 0"
21
+ }
22
22
  return node
23
23
  }
24
24
 
@@ -26,13 +26,16 @@ import { DocumentFragment } from "./tree"
26
26
  * much of this module.
27
27
  */
28
28
 
29
+ const openDelims = "([{⌊⌈⟨⟮⎰⟦⦃"
30
+ const closeDelims = ")]}⌋⌉⟩⟯⎱⟦⦄"
31
+
29
32
  export default function setLineBreaks(expression, wrapMode, isDisplayMode) {
30
33
  const mtrs = [];
31
34
  let mrows = [];
32
35
  let block = [];
33
36
  let numTopLevelEquals = 0
34
- let canBeBIN = false // The first node cannot be an infix binary operator.
35
37
  let i = 0
38
+ let level = 0
36
39
  while (i < expression.length) {
37
40
  while (expression[i] instanceof DocumentFragment) {
38
41
  expression.splice(i, 1, ...expression[i].children) // Expand the fragment.
@@ -55,7 +58,12 @@ export default function setLineBreaks(expression, wrapMode, isDisplayMode) {
55
58
  }
56
59
  block.push(node);
57
60
  if (node.type && node.type === "mo" && node.children.length === 1) {
58
- if (wrapMode === "=" && node.children[0].text === "=") {
61
+ const ch = node.children[0].text
62
+ if (openDelims.indexOf(ch) > -1) {
63
+ level += 1
64
+ } else if (closeDelims.indexOf(ch) > -1) {
65
+ level -= 1
66
+ } else if (level === 0 && wrapMode === "=" && ch === "=") {
59
67
  numTopLevelEquals += 1
60
68
  if (numTopLevelEquals > 1) {
61
69
  block.pop()
@@ -64,59 +72,48 @@ export default function setLineBreaks(expression, wrapMode, isDisplayMode) {
64
72
  mrows.push(element)
65
73
  block = [node];
66
74
  }
67
- } else if (wrapMode === "tex") {
68
- // This may be a place for a soft line break.
69
- if (canBeBIN && !node.attributes.form) {
70
- // Check if the following node is a \nobreak text node, e.g. "~""
71
- const next = i < expression.length - 1 ? expression[i + 1] : null;
72
- let glueIsFreeOfNobreak = true;
73
- if (
74
- !(
75
- next &&
76
- next.type === "mtext" &&
77
- next.attributes.linebreak &&
78
- next.attributes.linebreak === "nobreak"
79
- )
80
- ) {
81
- // We may need to start a new block.
82
- // First, put any post-operator glue on same line as operator.
83
- for (let j = i + 1; j < expression.length; j++) {
84
- const nd = expression[j];
75
+ } else if (level === 0 && wrapMode === "tex") {
76
+ // Check if the following node is a \nobreak text node, e.g. "~""
77
+ const next = i < expression.length - 1 ? expression[i + 1] : null;
78
+ let glueIsFreeOfNobreak = true;
79
+ if (
80
+ !(
81
+ next &&
82
+ next.type === "mtext" &&
83
+ next.attributes.linebreak &&
84
+ next.attributes.linebreak === "nobreak"
85
+ )
86
+ ) {
87
+ // We may need to start a new block.
88
+ // First, put any post-operator glue on same line as operator.
89
+ for (let j = i + 1; j < expression.length; j++) {
90
+ const nd = expression[j];
91
+ if (
92
+ nd.type &&
93
+ nd.type === "mspace" &&
94
+ !(nd.attributes.linebreak && nd.attributes.linebreak === "newline")
95
+ ) {
96
+ block.push(nd);
97
+ i += 1;
85
98
  if (
86
- nd.type &&
87
- nd.type === "mspace" &&
88
- !(nd.attributes.linebreak && nd.attributes.linebreak === "newline")
99
+ nd.attributes &&
100
+ nd.attributes.linebreak &&
101
+ nd.attributes.linebreak === "nobreak"
89
102
  ) {
90
- block.push(nd);
91
- i += 1;
92
- if (
93
- nd.attributes &&
94
- nd.attributes.linebreak &&
95
- nd.attributes.linebreak === "nobreak"
96
- ) {
97
- glueIsFreeOfNobreak = false;
98
- }
99
- } else {
100
- break;
103
+ glueIsFreeOfNobreak = false;
101
104
  }
105
+ } else {
106
+ break;
102
107
  }
103
108
  }
104
- if (glueIsFreeOfNobreak) {
105
- // Start a new block. (Insert a soft linebreak.)
106
- const element = new mathMLTree.MathNode("mrow", block)
107
- mrows.push(element)
108
- block = [];
109
- }
110
- canBeBIN = false
111
109
  }
112
- const isOpenDelimiter = node.attributes.form && node.attributes.form === "prefix"
113
- // Any operator that follows an open delimiter is unary.
114
- canBeBIN = !(node.attributes.separator || isOpenDelimiter);
115
- } else {
116
- canBeBIN = true
110
+ if (glueIsFreeOfNobreak) {
111
+ // Start a new block. (Insert a soft linebreak.)
112
+ const element = new mathMLTree.MathNode("mrow", block)
113
+ mrows.push(element)
114
+ block = [];
115
+ }
117
116
  }
118
- } else {
119
- canBeBIN = true
120
117
  }
121
118
  i += 1
122
119
  }
package/src/macros.js CHANGED
@@ -238,9 +238,6 @@ defineMacro("\u22ee", "\\vdots");
238
238
  //\newcommand{\substack}[1]{\subarray{c}#1\endsubarray}
239
239
  defineMacro("\\substack", "\\begin{subarray}{c}#1\\end{subarray}");
240
240
 
241
- // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}}
242
- defineMacro("\\boxed", "\\fbox{$\\displaystyle{#1}$}");
243
-
244
241
  // \def\iff{\DOTSB\;\Longleftrightarrow\;}
245
242
  // \def\implies{\DOTSB\;\Longrightarrow\;}
246
243
  // \def\impliedby{\DOTSB\;\Longleftarrow\;}
@@ -489,7 +486,7 @@ defineMacro(
489
486
  defineMacro(
490
487
  "\\Temml",
491
488
  // eslint-disable-next-line max-len
492
- "\\textrm{T}\\kern-0.2em\\lower{0.2em}\\textrm{E}\\kern-0.08em{\\textrm{M}\\kern-0.08em\\raise{0.2em}\\textrm{M}\\kern-0.08em\\textrm{L}}"
489
+ "\\textrm{T}\\kern-0.2em\\lower{0.2em}{\\textrm{E}}\\kern-0.08em{\\textrm{M}\\kern-0.08em\\raise{0.2em}\\textrm{M}\\kern-0.08em\\textrm{L}}"
493
490
  );
494
491
 
495
492
  // \DeclareRobustCommand\hspace{\@ifstar\@hspacer\@hspace}
@@ -8,7 +8,7 @@
8
8
  * https://mit-license.org/
9
9
  */
10
10
 
11
- export const version = "0.10.13";
11
+ export const version = "0.10.14";
12
12
 
13
13
  export function postProcess(block) {
14
14
  const labelMap = {}
package/src/symbols.js CHANGED
@@ -356,6 +356,7 @@ defineSymbol(math, rel, "\u2ab7", "\\precapprox", true);
356
356
  defineSymbol(math, rel, "\u22b2", "\\vartriangleleft");
357
357
  defineSymbol(math, rel, "\u22b4", "\\trianglelefteq");
358
358
  defineSymbol(math, rel, "\u22a8", "\\vDash", true);
359
+ defineSymbol(math, rel, "\u22ab", "\\VDash", true);
359
360
  defineSymbol(math, rel, "\u22aa", "\\Vvdash", true);
360
361
  defineSymbol(math, rel, "\u2323", "\\smallsmile");
361
362
  defineSymbol(math, rel, "\u2322", "\\smallfrown");