Merge pull request #2232 from alixander/bad-latex

d2parser: escape backslashes for latex
This commit is contained in:
Alexander Wang 2024-11-24 13:07:23 -08:00 committed by GitHub
commit 50d048f0a8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 2564 additions and 633 deletions

View file

@ -7,6 +7,9 @@
- Composition: links pointing to own board are purged [#2203](https://github.com/terrastruct/d2/pull/2203) - Composition: links pointing to own board are purged [#2203](https://github.com/terrastruct/d2/pull/2203)
- Syntax: reserved keywords must be unquoted [#2231](https://github.com/terrastruct/d2/pull/2231) - Syntax: reserved keywords must be unquoted [#2231](https://github.com/terrastruct/d2/pull/2231)
- Latex: Backslashes in Latex blocks do not escape [#2232](https://github.com/terrastruct/d2/pull/2232)
- This is a breaking change. Previously Latex blocks required escaping the backslash. So
for older D2 versions, you should remove the excess backslashes.
#### Bugfixes ⛑️ #### Bugfixes ⛑️

View file

@ -1480,6 +1480,12 @@ func (p *parser) parseBlockString() *d2ast.BlockString {
} }
if r != endHint { if r != endHint {
if (bs.Tag == "latex" || bs.Tag == "tex") && r == '\\' {
// For LaTeX, where single backslash is common, we escape it so that users don't have to write double the backslashes
sb.WriteRune('\\')
sb.WriteRune('\\')
continue
}
sb.WriteRune(r) sb.WriteRune(r)
continue continue
} }

View file

@ -1381,30 +1381,24 @@ c: |md
{ {
name: "latex", name: "latex",
script: `a: |latex script: `a: |latex
\\Huge{\\frac{\\alpha g^2}{\\omega^5} e^{[ -0.74\\bigl\\{\\frac{\\omega U_\\omega 19.5}{g}\\bigr\\}^{\\!-4}\\,]}} \Huge{\frac{\alpha g^2}{\omega^5} e^{[ -0.74\bigl\{\frac{\omega U_\omega 19.5}{g}\bigr\}^{\!-4}\,]}}
| |
b: |latex b: |latex
e = mc^2 e = mc^2
| |
z: |latex z: |latex
gibberish\\; math:\\sum_{i=0}^\\infty i^2 gibberish\; math:\sum_{i=0}^\infty i^2
| |
z -> a z -> a
z -> b z -> b
a -> c a -> c
b -> c b -> c
sugar -> c sugar -> c
c: mixed together c: mixed together
c -> solution: we get c -> solution: we get
Linear program: { Linear program: {
formula: |latex formula: |latex
\\min_{ \\mathclap{\\substack{ x \\in \\mathbb{R}^n \\ x \\geq 0 \\ Ax \\leq b }}} c^T x \min_{ \mathclap{\substack{ x \in \mathbb{R}^n \ x \geq 0 \ Ax \leq b }}} c^T x
| |
} }
`, `,

View file

@ -4,61 +4,55 @@ container: ___________________________________container_________________________
amscd plugin: { amscd plugin: {
ex: |tex ex: |tex
\\begin{CD} B @>{\\text{very long label}}>> C S^{{\\mathcal{W}}_\\Lambda}\\otimes T @>j>> T\\\\ @VVV V \\end{CD} \begin{CD} B @>{\text{very long label}}>> C S^{{\mathcal{W}}_\Lambda}\otimes T @>j>> T\\ @VVV V \end{CD}
| |
} }
braket plugin: { braket plugin: {
style.3d: true style.3d: true
ex: |tex ex: |tex
\\bra{a}\\ket{b} \bra{a}\ket{b}
| |
} }
cancel plugin: { cancel plugin: {
ex: |tex ex: |tex
\\cancel{Culture + 5} \cancel{Culture + 5}
| |
} }
color plugin: { color plugin: {
icon: https://icons.terrastruct.com/essentials/profits.svg icon: https://icons.terrastruct.com/essentials/profits.svg
icon.near: outside-right-center icon.near: outside-right-center
ex: |tex ex: |tex
\\textcolor{red}{y} = \\textcolor{green}{\\sin} x \textcolor{red}{y} = \textcolor{green}{\sin} x
| |
} }
gensymb plugin: { gensymb plugin: {
ex: |tex ex: |tex
\\lambda = 10.6\\,\\micro\\mathrm{m} \lambda = 10.6\,\micro\mathrm{m}
| |
} }
mhchem plugin: { mhchem plugin: {
style.multiple: true style.multiple: true
ex: |tex ex: |tex
\ce{SO4^2- + Ba^2+ -> BaSO4 v} \ce{SO4^2- + Ba^2+ -> BaSO4 v}
| |
} }
physics plugin: { physics plugin: {
ex: |tex ex: |tex
\\var{F[g(x)]} \var{F[g(x)]}
\\dd(\\cos\\theta) \dd(\cos\theta)
| |
} }
multilines: { multilines: {
ex: |tex ex: |tex
\\displaylines{x = a + b \\\\ y = b + c} \displaylines{x = a + b \\ y = b + c}
\\sum_{k=1}^{n} h_{k} \\int_{0}^{1} \\bigl(\\partial_{k} f(x_{k-1}+t h_{k} e_{k}) -\\partial_{k} f(a)\\bigr) \\,dt \sum_{k=1}^{n} h_{k} \int_{0}^{1} \bigl(\partial_{k} f(x_{k-1}+t h_{k} e_{k}) -\partial_{k} f(a)\bigr) \,dt
| |
} }
asm: { asm: {
ex: |latex ex: |latex
\\min_{ \\mathclap{\\substack{ x \\in \\mathbb{R}^n \\ x \\geq 0 \\ Ax \\leq b }}} c^T x \min_{ \mathclap{\substack{ x \in \mathbb{R}^n \ x \geq 0 \ Ax \leq b }}} c^T x
| |
} }
} }

View file

@ -19,7 +19,7 @@ y: {
z: { z: {
grid-columns: 2 grid-columns: 2
lim: |latex lim: |latex
\\lim_{h \\rightarrow 0 } \\frac{f(x+h)-f(x)}{h} \lim_{h \rightarrow 0 } \frac{f(x+h)-f(x)}{h}
| |
add: |latex add: |latex
1 + 1 1 + 1

View file

@ -10,7 +10,7 @@
"x": 0, "x": 0,
"y": 0 "y": 0
}, },
"width": 1213, "width": 1184,
"height": 524, "height": 524,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
@ -294,7 +294,7 @@
"x": 385, "x": 385,
"y": 82 "y": 82
}, },
"width": 255, "width": 226,
"height": 103, "height": 103,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
@ -387,7 +387,7 @@
"x": 385, "x": 385,
"y": 241 "y": 241
}, },
"width": 324, "width": 295,
"height": 103, "height": 103,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
@ -468,7 +468,7 @@
"x": 385, "x": 385,
"y": 410 "y": 410
}, },
"width": 314, "width": 285,
"height": 93, "height": 93,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
@ -509,8 +509,8 @@
"x": 415, "x": 415,
"y": 440 "y": 440
}, },
"width": 254, "width": 225,
"height": 18, "height": 20,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -529,7 +529,7 @@
"fields": null, "fields": null,
"methods": null, "methods": null,
"columns": null, "columns": null,
"label": "\\ce{SO4^2- + Ba^2+ -> BaSO4 v}", "label": "\\\\ce{SO4^2- + Ba^2+ -> BaSO4 v}",
"fontSize": 16, "fontSize": 16,
"fontFamily": "DEFAULT", "fontFamily": "DEFAULT",
"language": "latex", "language": "latex",
@ -537,8 +537,8 @@
"italic": false, "italic": false,
"bold": false, "bold": false,
"underline": false, "underline": false,
"labelWidth": 254, "labelWidth": 225,
"labelHeight": 18, "labelHeight": 20,
"zIndex": 0, "zIndex": 0,
"level": 3 "level": 3
}, },
@ -546,7 +546,7 @@
"id": "container.physics plugin", "id": "container.physics plugin",
"type": "rectangle", "type": "rectangle",
"pos": { "pos": {
"x": 729, "x": 700,
"y": 82 "y": 82
}, },
"width": 464, "width": 464,
@ -587,7 +587,7 @@
"id": "container.physics plugin.ex", "id": "container.physics plugin.ex",
"type": "text", "type": "text",
"pos": { "pos": {
"x": 759, "x": 730,
"y": 112 "y": 112
}, },
"width": 128, "width": 128,
@ -627,7 +627,7 @@
"id": "container.multilines", "id": "container.multilines",
"type": "rectangle", "type": "rectangle",
"pos": { "pos": {
"x": 729, "x": 700,
"y": 233 "y": 233
}, },
"width": 464, "width": 464,
@ -668,7 +668,7 @@
"id": "container.multilines.ex", "id": "container.multilines.ex",
"type": "text", "type": "text",
"pos": { "pos": {
"x": 759, "x": 730,
"y": 263 "y": 263
}, },
"width": 404, "width": 404,
@ -708,7 +708,7 @@
"id": "container.asm", "id": "container.asm",
"type": "rectangle", "type": "rectangle",
"pos": { "pos": {
"x": 729, "x": 700,
"y": 401 "y": 401
}, },
"width": 464, "width": 464,
@ -749,7 +749,7 @@
"id": "container.asm.ex", "id": "container.asm.ex",
"type": "text", "type": "text",
"pos": { "pos": {
"x": 759, "x": 730,
"y": 431 "y": 431
}, },
"width": 62, "width": 62,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 110 KiB

View file

@ -10,7 +10,7 @@
"x": 12, "x": 12,
"y": 12 "y": 12
}, },
"width": 1323, "width": 1294,
"height": 521, "height": 521,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
@ -294,7 +294,7 @@
"x": 437, "x": 437,
"y": 58 "y": 58
}, },
"width": 285, "width": 256,
"height": 148, "height": 148,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
@ -387,7 +387,7 @@
"x": 437, "x": 437,
"y": 226 "y": 226
}, },
"width": 354, "width": 325,
"height": 133, "height": 133,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
@ -468,8 +468,8 @@
"x": 437, "x": 437,
"y": 389 "y": 389
}, },
"width": 344, "width": 315,
"height": 123, "height": 124,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -509,8 +509,8 @@
"x": 482, "x": 482,
"y": 434 "y": 434
}, },
"width": 254, "width": 225,
"height": 18, "height": 20,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -529,7 +529,7 @@
"fields": null, "fields": null,
"methods": null, "methods": null,
"columns": null, "columns": null,
"label": "\\ce{SO4^2- + Ba^2+ -> BaSO4 v}", "label": "\\\\ce{SO4^2- + Ba^2+ -> BaSO4 v}",
"fontSize": 16, "fontSize": 16,
"fontFamily": "DEFAULT", "fontFamily": "DEFAULT",
"language": "latex", "language": "latex",
@ -537,8 +537,8 @@
"italic": false, "italic": false,
"bold": false, "bold": false,
"underline": false, "underline": false,
"labelWidth": 254, "labelWidth": 225,
"labelHeight": 18, "labelHeight": 20,
"zIndex": 0, "zIndex": 0,
"level": 3 "level": 3
}, },
@ -546,7 +546,7 @@
"id": "container.physics plugin", "id": "container.physics plugin",
"type": "rectangle", "type": "rectangle",
"pos": { "pos": {
"x": 811, "x": 782,
"y": 58 "y": 58
}, },
"width": 504, "width": 504,
@ -587,7 +587,7 @@
"id": "container.physics plugin.ex", "id": "container.physics plugin.ex",
"type": "text", "type": "text",
"pos": { "pos": {
"x": 861, "x": 832,
"y": 108 "y": 108
}, },
"width": 128, "width": 128,
@ -627,7 +627,7 @@
"id": "container.multilines", "id": "container.multilines",
"type": "rectangle", "type": "rectangle",
"pos": { "pos": {
"x": 811, "x": 782,
"y": 204 "y": 204
}, },
"width": 504, "width": 504,
@ -668,7 +668,7 @@
"id": "container.multilines.ex", "id": "container.multilines.ex",
"type": "text", "type": "text",
"pos": { "pos": {
"x": 861, "x": 832,
"y": 254 "y": 254
}, },
"width": 404, "width": 404,
@ -708,7 +708,7 @@
"id": "container.asm", "id": "container.asm",
"type": "rectangle", "type": "rectangle",
"pos": { "pos": {
"x": 811, "x": 782,
"y": 376 "y": 376
}, },
"width": 504, "width": 504,
@ -749,7 +749,7 @@
"id": "container.asm.ex", "id": "container.asm.ex",
"type": "text", "type": "text",
"pos": { "pos": {
"x": 861, "x": 832,
"y": 426 "y": 426
}, },
"width": 62, "width": 62,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 110 KiB

View file

@ -0,0 +1,129 @@
{
"name": "",
"isFolderOnly": false,
"fontFamily": "SourceSansPro",
"shapes": [
{
"id": "formula",
"type": "rectangle",
"pos": {
"x": 10,
"y": 20
},
"width": 142,
"height": 142,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "formula",
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 92,
"labelHeight": 36,
"labelPosition": "OUTSIDE_TOP_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "formula.equation",
"type": "text",
"pos": {
"x": 40,
"y": 50
},
"width": 82,
"height": 82,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "transparent",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\begin{equation} \\\\label{eq1}\n\\\\begin{split}\nA & = \\\\frac{\\\\\\\\pi r^2}{2} \\\\\\\\\n & = \\\\frac{1}{2} \\\\pi r^2\n\\\\end{split}\n\\\\end{equation}",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 82,
"labelHeight": 82,
"zIndex": 0,
"level": 2
}
],
"connections": [],
"root": {
"id": "",
"type": "",
"pos": {
"x": 0,
"y": 0
},
"width": 0,
"height": 0,
"opacity": 0,
"strokeDash": 0,
"strokeWidth": 0,
"borderRadius": 0,
"fill": "N7",
"stroke": "",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "",
"fontSize": 0,
"fontFamily": "",
"language": "",
"color": "",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"zIndex": 0,
"level": 0
}
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 31 KiB

View file

@ -0,0 +1,129 @@
{
"name": "",
"isFolderOnly": false,
"fontFamily": "SourceSansPro",
"shapes": [
{
"id": "formula",
"type": "rectangle",
"pos": {
"x": 12,
"y": 12
},
"width": 182,
"height": 182,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "formula",
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 92,
"labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "formula.equation",
"type": "text",
"pos": {
"x": 62,
"y": 62
},
"width": 82,
"height": 82,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "transparent",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\begin{equation} \\\\label{eq1}\n\\\\begin{split}\nA & = \\\\frac{\\\\\\\\pi r^2}{2} \\\\\\\\\n & = \\\\frac{1}{2} \\\\pi r^2\n\\\\end{split}\n\\\\end{equation}",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 82,
"labelHeight": 82,
"zIndex": 0,
"level": 2
}
],
"connections": [],
"root": {
"id": "",
"type": "",
"pos": {
"x": 0,
"y": 0
},
"width": 0,
"height": 0,
"opacity": 0,
"strokeDash": 0,
"strokeWidth": 0,
"borderRadius": 0,
"fill": "N7",
"stroke": "",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "",
"fontSize": 0,
"fontFamily": "",
"language": "",
"color": "",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"zIndex": 0,
"level": 0
}
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 31 KiB

View file

@ -111,8 +111,8 @@ func main() {
markdown -> code -> ex markdown -> code -> ex
ex: |tex ex: |tex
\\displaylines{x = a + b \\\\ y = b + c} \displaylines{x = a + b \\ y = b + c}
\\sum_{k=1}^{n} h_{k} \\int_{0}^{1} \\bigl(\\partial_{k} f(x_{k-1}+t h_{k} e_{k}) -\\partial_{k} f(a)\\bigr) \\,dt \sum_{k=1}^{n} h_{k} \int_{0}^{1} \bigl(\partial_{k} f(x_{k-1}+t h_{k} e_{k}) -\partial_{k} f(a)\bigr) \,dt
| |
`, `,
}, },
@ -218,8 +218,8 @@ func main() {
markdown -> code -> ex markdown -> code -> ex
ex: |tex ex: |tex
\\displaylines{x = a + b \\\\ y = b + c} \displaylines{x = a + b \\ y = b + c}
\\sum_{k=1}^{n} h_{k} \\int_{0}^{1} \\bigl(\\partial_{k} f(x_{k-1}+t h_{k} e_{k}) -\\partial_{k} f(a)\\bigr) \\,dt \sum_{k=1}^{n} h_{k} \int_{0}^{1} \bigl(\partial_{k} f(x_{k-1}+t h_{k} e_{k}) -\partial_{k} f(a)\bigr) \,dt
| |
`, `,
}, },

View file

@ -657,3 +657,15 @@ my_table: {
} }
x -> my_table."shape" x -> my_table."shape"
-- single-backslash-latex --
formula: {
equation: |latex
\begin{equation} \label{eq1}
\begin{split}
A & = \frac{\\pi r^2}{2} \\
& = \frac{1}{2} \pi r^2
\end{split}
\end{equation}
|
}