temml 0.10.13 → 0.10.14

Sign up to get free protection for your applications and to get access to all the features.
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");