Merge pull request #2328 from alixander/latex-backslash

d2latex: fix latex backslashes doubling
This commit is contained in:
Alexander Wang 2025-02-03 17:09:07 -08:00 committed by GitHub
commit 4733d81d64
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 3394 additions and 3392 deletions

View file

@ -30,3 +30,4 @@
- Sequence diagrams: fixes alignment of notes when self messages are above it [#2264](https://github.com/terrastruct/d2/pull/2264)
- Null: fixes `null`ing a connection with absolute syntax [#2318](https://github.com/terrastruct/d2/issues/2318)
- Gradients: works with connection fills [#2326](https://github.com/terrastruct/d2/pull/2326)
- Latex: fixes backslashes doubling on successive parses [#2328](https://github.com/terrastruct/d2/pull/2328)

View file

@ -1480,12 +1480,6 @@ func (p *parser) parseBlockString() *d2ast.BlockString {
}
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)
continue
}

View file

@ -6,6 +6,7 @@ import (
"math"
"regexp"
"strconv"
"strings"
"oss.terrastruct.com/d2/lib/jsrunner"
"oss.terrastruct.com/util-go/xdefer"
@ -28,6 +29,7 @@ var svgRe = regexp.MustCompile(`<svg[^>]+width="([0-9\.]+)ex" height="([0-9\.]+)
func Render(s string) (_ string, err error) {
defer xdefer.Errorf(&err, "latex failed to parse")
s = doubleBackslashes(s)
runner := jsrunner.NewJSRunner()
if _, err := runner.RunString(polyfillsJS); err != nil {
@ -82,3 +84,15 @@ func Measure(s string) (width, height int, err error) {
return int(math.Ceil(wf * float64(pxPerEx))), int(math.Ceil(hf * float64(pxPerEx))), nil
}
func doubleBackslashes(s string) string {
var result strings.Builder
for i := 0; i < len(s); i++ {
if s[i] == '\\' {
result.WriteString("\\\\")
} else {
result.WriteByte(s[i])
}
}
return result.String()
}

View file

@ -8,7 +8,7 @@ import (
func TestRender(t *testing.T) {
txts := []string{
`a + b = c`,
`\\frac{1}{2}`,
`\frac{1}{2}`,
`a + b
= c
`,
@ -24,10 +24,3 @@ func TestRender(t *testing.T) {
}
}
}
func TestRenderError(t *testing.T) {
_, err := Render(`\frac{1}{2}`)
if err == nil {
t.Fatal("expected to error on invalid latex syntax")
}
}

View file

@ -333,7 +333,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\lim_{h \\\\rightarrow 0 } \\\\frac{f(x+h)-f(x)}{h}",
"label": "\\lim_{h \\rightarrow 0 } \\frac{f(x+h)-f(x)}{h}",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View file

@ -333,7 +333,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\lim_{h \\\\rightarrow 0 } \\\\frac{f(x+h)-f(x)}{h}",
"label": "\\lim_{h \\rightarrow 0 } \\frac{f(x+h)-f(x)}{h}",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View file

@ -123,7 +123,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\begin{CD} B @>{\\\\text{very long label}}>> C S^{{\\\\mathcal{W}}_\\\\Lambda}\\\\otimes T @>j>> T\\\\\\\\ @VVV V \\\\end{CD}",
"label": "\\begin{CD} B @>{\\text{very long label}}>> C S^{{\\mathcal{W}}_\\Lambda}\\otimes T @>j>> T\\\\ @VVV V \\end{CD}",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -206,7 +206,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\bra{a}\\\\ket{b}",
"label": "\\bra{a}\\ket{b}",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -289,7 +289,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\cancel{Culture + 5}",
"label": "\\cancel{Culture + 5}",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -384,7 +384,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\textcolor{red}{y} = \\\\textcolor{green}{\\\\sin} x",
"label": "\\textcolor{red}{y} = \\textcolor{green}{\\sin} x",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -467,7 +467,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\lambda = 10.6\\\\,\\\\micro\\\\mathrm{m}",
"label": "\\lambda = 10.6\\,\\micro\\mathrm{m}",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -550,7 +550,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\ce{SO4^2- + Ba^2+ -> BaSO4 v}",
"label": "\\ce{SO4^2- + Ba^2+ -> BaSO4 v}",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -633,7 +633,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\var{F[g(x)]}\n\\\\dd(\\\\cos\\\\theta)",
"label": "\\var{F[g(x)]}\n\\dd(\\cos\\theta)",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -716,7 +716,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\displaylines{x = a + b \\\\\\\\ y = b + c}\n\\\\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",
"label": "\\displaylines{x = a + b \\\\ y = b + c}\n\\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",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -799,7 +799,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\min_{ \\\\mathclap{\\\\substack{ x \\\\in \\\\mathbb{R}^n \\\\ x \\\\geq 0 \\\\ Ax \\\\leq b }}} c^T x",
"label": "\\min_{ \\mathclap{\\substack{ x \\in \\mathbb{R}^n \\ x \\geq 0 \\ Ax \\leq b }}} c^T x",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

View file

@ -123,7 +123,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\begin{CD} B @>{\\\\text{very long label}}>> C S^{{\\\\mathcal{W}}_\\\\Lambda}\\\\otimes T @>j>> T\\\\\\\\ @VVV V \\\\end{CD}",
"label": "\\begin{CD} B @>{\\text{very long label}}>> C S^{{\\mathcal{W}}_\\Lambda}\\otimes T @>j>> T\\\\ @VVV V \\end{CD}",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -206,7 +206,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\bra{a}\\\\ket{b}",
"label": "\\bra{a}\\ket{b}",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -289,7 +289,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\cancel{Culture + 5}",
"label": "\\cancel{Culture + 5}",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -384,7 +384,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\textcolor{red}{y} = \\\\textcolor{green}{\\\\sin} x",
"label": "\\textcolor{red}{y} = \\textcolor{green}{\\sin} x",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -467,7 +467,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\lambda = 10.6\\\\,\\\\micro\\\\mathrm{m}",
"label": "\\lambda = 10.6\\,\\micro\\mathrm{m}",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -550,7 +550,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\ce{SO4^2- + Ba^2+ -> BaSO4 v}",
"label": "\\ce{SO4^2- + Ba^2+ -> BaSO4 v}",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -633,7 +633,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\var{F[g(x)]}\n\\\\dd(\\\\cos\\\\theta)",
"label": "\\var{F[g(x)]}\n\\dd(\\cos\\theta)",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -716,7 +716,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\displaylines{x = a + b \\\\\\\\ y = b + c}\n\\\\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",
"label": "\\displaylines{x = a + b \\\\ y = b + c}\n\\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",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -799,7 +799,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\min_{ \\\\mathclap{\\\\substack{ x \\\\in \\\\mathbb{R}^n \\\\ x \\\\geq 0 \\\\ Ax \\\\leq b }}} c^T x",
"label": "\\min_{ \\mathclap{\\substack{ x \\in \\mathbb{R}^n \\ x \\geq 0 \\ Ax \\leq b }}} c^T x",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

View file

@ -39,7 +39,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\Huge{\\\\frac{\\\\alpha g^2}{\\\\omega^5} e^{[ -0.74\\\\bigl\\\\{\\\\frac{\\\\omega U_\\\\omega 19.5}{g}\\\\bigr\\\\}^{\\\\!-4}\\\\,]}}",
"label": "\\Huge{\\frac{\\alpha g^2}{\\omega^5} e^{[ -0.74\\bigl\\{\\frac{\\omega U_\\omega 19.5}{g}\\bigr\\}^{\\!-4}\\,]}}",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -121,7 +121,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "gibberish\\\\; math:\\\\sum_{i=0}^\\\\infty i^2",
"label": "gibberish\\; math:\\sum_{i=0}^\\infty i^2",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -330,7 +330,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\min_{ \\\\mathclap{\\\\substack{ x \\\\in \\\\mathbb{R}^n \\\\ x \\\\geq 0 \\\\ Ax \\\\leq b }}} c^T x",
"label": "\\min_{ \\mathclap{\\substack{ x \\in \\mathbb{R}^n \\ x \\geq 0 \\ Ax \\leq b }}} c^T x",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View file

@ -39,7 +39,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\Huge{\\\\frac{\\\\alpha g^2}{\\\\omega^5} e^{[ -0.74\\\\bigl\\\\{\\\\frac{\\\\omega U_\\\\omega 19.5}{g}\\\\bigr\\\\}^{\\\\!-4}\\\\,]}}",
"label": "\\Huge{\\frac{\\alpha g^2}{\\omega^5} e^{[ -0.74\\bigl\\{\\frac{\\omega U_\\omega 19.5}{g}\\bigr\\}^{\\!-4}\\,]}}",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -121,7 +121,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "gibberish\\\\; math:\\\\sum_{i=0}^\\\\infty i^2",
"label": "gibberish\\; math:\\sum_{i=0}^\\infty i^2",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",
@ -330,7 +330,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\min_{ \\\\mathclap{\\\\substack{ x \\\\in \\\\mathbb{R}^n \\\\ x \\\\geq 0 \\\\ Ax \\\\leq b }}} c^T x",
"label": "\\min_{ \\mathclap{\\substack{ x \\in \\mathbb{R}^n \\ x \\geq 0 \\ Ax \\leq b }}} c^T x",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View file

@ -833,7 +833,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\displaylines{x = a + b \\\\\\\\ y = b + c}\n\\\\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",
"label": "\\displaylines{x = a + b \\\\ y = b + c}\n\\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",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 119 KiB

View file

@ -833,7 +833,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\displaylines{x = a + b \\\\\\\\ y = b + c}\n\\\\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",
"label": "\\displaylines{x = a + b \\\\ y = b + c}\n\\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",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "latex",

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 118 KiB

View file

@ -837,7 +837,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\displaylines{x = a + b \\\\\\\\ y = b + c}\n\\\\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",
"label": "\\displaylines{x = a + b \\\\ y = b + c}\n\\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",
"fontSize": 16,
"fontFamily": "mono",
"language": "latex",

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 122 KiB

View file

@ -837,7 +837,7 @@
"fields": null,
"methods": null,
"columns": null,
"label": "\\\\displaylines{x = a + b \\\\\\\\ y = b + c}\n\\\\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",
"label": "\\displaylines{x = a + b \\\\ y = b + c}\n\\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",
"fontSize": 16,
"fontFamily": "mono",
"language": "latex",

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 121 KiB

After

Width:  |  Height:  |  Size: 121 KiB

View file

@ -81,7 +81,7 @@
"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}",
"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",

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View file

@ -81,7 +81,7 @@
"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}",
"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",

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB