diff --git a/apps/vscode/CHANGELOG.md b/apps/vscode/CHANGELOG.md index dec41cd9..c2e8266c 100644 --- a/apps/vscode/CHANGELOG.md +++ b/apps/vscode/CHANGELOG.md @@ -2,6 +2,8 @@ ## 1.125.0 (Unreleased) +- Fixed an issue where attribute values containing '='s could be truncated in some scenarios (). + ## 1.124.0 (Release on 2025-08-20) - Fix Base64 leak when no empty line between text and code block (). diff --git a/apps/vscode/src/test/examples/.gitignore b/apps/vscode/src/test/examples/.gitignore new file mode 100644 index 00000000..d56b24c2 --- /dev/null +++ b/apps/vscode/src/test/examples/.gitignore @@ -0,0 +1,2 @@ +*.html +*_files diff --git a/apps/vscode/src/test/examples/attr-equals.qmd b/apps/vscode/src/test/examples/attr-equals.qmd new file mode 100644 index 00000000..75e62432 --- /dev/null +++ b/apps/vscode/src/test/examples/attr-equals.qmd @@ -0,0 +1,52 @@ +# Testing equals signs in attribute values + +This test document validates that equals signs in attribute values are handled correctly. + +This prose contains some equals signs, just in case. A=B=C. D=E=F. = + +## Basic examples + +- Basic link with equals in value: [Link text](https://example.com){key=value=with=equals} + +- Link with URL parameter: [Query link](https://example.com?param=value){.class key=query=param} + +- Span with complex value: [Span text]{#id .class key=complex=value} + +- Other weird examples: [Span text](key=) [Span](===) + +## More complex examples + +- CSS style with equals: [Styled text]{style=color:red;font-size=12px} + +- Math expression value: [Math formula]{formula=E=mc^2} + +- Code with equals: `code sample`{lang=c++ key=value=val} + +## Code blocks + +```{python key=value=equals} +print("Testing equals in attribute values") +``` + +```{r eval=1+1=2} +print("R code with equals in attributes") +``` + +## Div with attributes + +:::{#div-id key=value=with=multiple=equals} +This is a div with multiple equals signs in attribute values. +::: + +## Image with equals signs + +![Image caption](image.png){width=50% height=30% key=value=equals} + +## Table with equals signs + +| Col1 | Col2 | +|------|------| +| A | B | +| C | D | + +: Table caption {#tbl-id tbl-colwidths="[50,50]" key=value=with=equals} diff --git a/apps/vscode/src/test/examples/generated_snapshots/roundtripped-attr-equals.qmd b/apps/vscode/src/test/examples/generated_snapshots/roundtripped-attr-equals.qmd new file mode 100644 index 00000000..8c333d9f --- /dev/null +++ b/apps/vscode/src/test/examples/generated_snapshots/roundtripped-attr-equals.qmd @@ -0,0 +1,52 @@ +# Testing equals signs in attribute values + +This test document validates that equals signs in attribute values are handled correctly. + +This prose contains some equals signs, just in case. A=B=C. D=E=F. = + +## Basic examples + +- Basic link with equals in value: [Link text](https://example.com){key="value=with=equals"} + +- Link with URL parameter: [Query link](https://example.com?param=value){.class key="query=param"} + +- Span with complex value: [Span text]{#id .class key="complex=value"} + +- Other weird examples: [Span text](key=) [Span](===) + +## More complex examples + +- CSS style with equals: [Styled text]{style="color:red;font-size=12px"} + +- Math expression value: [Math formula]{formula="E=mc^2"} + +- Code with equals: `code sample`{lang="c++" key="value=val"} + +## Code blocks + +```{python key=value=equals} +print("Testing equals in attribute values") +``` + +```{r eval=1+1=2} +print("R code with equals in attributes") +``` + +## Div with attributes + +::: {#div-id key="value=with=multiple=equals"} +This is a div with multiple equals signs in attribute values. +::: + +## Image with equals signs + +![Image caption](image.png){width="50%" height="30%" key="value=equals"} + +## Table with equals signs + +| Col1 | Col2 | +|------|------| +| A | B | +| C | D | + +: Table caption {#tbl-id tbl-colwidths="\[50,50\]" key=value=with=equals} \ No newline at end of file diff --git a/apps/vscode/src/test/quartoDoc.test.ts b/apps/vscode/src/test/quartoDoc.test.ts index aeb88526..d4ca47aa 100644 --- a/apps/vscode/src/test/quartoDoc.test.ts +++ b/apps/vscode/src/test/quartoDoc.test.ts @@ -39,6 +39,8 @@ suite("Quarto basics", function () { roundtripSnapshotTest('invalid.qmd'); roundtripSnapshotTest('capsule-leak.qmd'); + + roundtripSnapshotTest('attr-equals.qmd'); }); /** diff --git a/packages/editor/src/api/pandoc_attr.ts b/packages/editor/src/api/pandoc_attr.ts index 75ee81b7..0b606beb 100644 --- a/packages/editor/src/api/pandoc_attr.ts +++ b/packages/editor/src/api/pandoc_attr.ts @@ -311,8 +311,14 @@ export function pandocAttrKeyvalueFromText(text: string, separator: ' ' | '\n'): const lines = text.trim().split('\n'); return lines.map(line => { - const parts = line.trim().split('='); - return [parts[0], (parts[1] || '').replace(/^"/, '').replace(/"$/, '')]; + const idx = line.indexOf('='); + if (idx === -1) { + return [line.trim(), ""] + } else { + const lhs = line.substring(0, idx).trim(); + const rhs = line.substring(idx + 1).trim(); + return [lhs, rhs.replace(/^"/, '').replace(/"$/, '')]; + } }); } diff --git a/packages/quarto-core/src/context.ts b/packages/quarto-core/src/context.ts index 80cc7a83..878df102 100644 --- a/packages/quarto-core/src/context.ts +++ b/packages/quarto-core/src/context.ts @@ -206,7 +206,7 @@ function scanForQuarto(additionalSearchPaths?: string[]): QuartoInstallation | u } scanPaths.push("C:\\Program Files\\RStudio\\bin\\quarto\\bin"); } else if (os.platform() === "darwin") { - scanPaths.push("/Applications/quarto/bin/"); + scanPaths.push("/Applications/quarto/bin"); const home = process.env.HOME; if (home) { scanPaths.push(path.join(home, "Applications", "quarto", "bin"));