Skip to content

Commit ace5ea4

Browse files
authored
Make provideStatementRange() create a single chunk virtual doc (#914)
* Make `provideStatementRange()` create a single chunk virtual doc * CHANGELOG * Add basic virtual doc snapshot tests * Copyright year
1 parent a78ac6a commit ace5ea4

12 files changed

Lines changed: 244 additions & 24 deletions

File tree

apps/vscode/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## 1.130.0 (Unreleased)
44

5+
- Fixed a bug where a parse error in one chunk meant you could not perform statement execution in another chunk (<https://github.com/quarto-dev/quarto/pull/914>).
6+
57
## 1.129.0 (Release on 2026-01-29)
68

79
- Fixed Copilot completions in `.qmd` documents (<https://github.com/quarto-dev/quarto/pull/887>).

apps/vscode/src/host/hooks.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Positron-specific functionality.
55
*
6-
* Copyright (C) 2022 by Posit Software, PBC
6+
* Copyright (C) 2022-2026 by Posit Software, PBC
77
*
88
* Unless you have received this program directly from Posit Software pursuant
99
* to the terms of a commercial license agreement with Posit Software, then
@@ -22,7 +22,7 @@ import { ExtensionHost, HostWebviewPanel, HostStatementRangeProvider, HostHelpTo
2222
import { CellExecutor, cellExecutorForLanguage, executableLanguages, isKnitrDocument, pythonWithReticulate } from './executors';
2323
import { ExecuteQueue } from './execute-queue';
2424
import { MarkdownEngine } from '../markdown/engine';
25-
import { virtualDoc, adjustedPosition, unadjustedRange, withVirtualDocUri } from "../vdoc/vdoc";
25+
import { virtualDoc, adjustedPosition, unadjustedRange, withVirtualDocUri, VirtualDocStyle } from "../vdoc/vdoc";
2626
import { Position, Range } from 'vscode';
2727
import { Uri } from 'vscode';
2828

@@ -199,7 +199,7 @@ class EmbeddedStatementRangeProvider implements HostStatementRangeProvider {
199199
document: vscode.TextDocument,
200200
position: vscode.Position,
201201
token: vscode.CancellationToken): Promise<hooks.StatementRange | undefined> {
202-
const vdoc = await virtualDoc(document, position, this._engine);
202+
const vdoc = await virtualDoc(document, position, this._engine, VirtualDocStyle.Block);
203203
if (vdoc) {
204204
return await withVirtualDocUri(vdoc, document.uri, "statementRange", async (uri: vscode.Uri) => {
205205
const result = await vscode.commands.executeCommand<hooks.StatementRange>(

apps/vscode/src/test/codeBlocks.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as vscode from "vscode";
22
import * as assert from "assert";
3-
import { WORKSPACE_PATH, examplesOutUri, openAndShowTextDocument } from "./test-utils";
3+
import { WORKSPACE_PATH, examplesOutUri, openAndShowExamplesOutTextDocument } from "./test-utils";
44
import { isExecutableLanguageBlock, languageNameFromBlock } from "quarto-core";
55
import { MarkdownEngine } from "../markdown/engine";
66

@@ -17,7 +17,7 @@ suite("Code block detection", function () {
1717
// doesn't have a preceding blank line. This real-world example has many
1818
// .notes divs which caused later code blocks to not be detected.
1919
test("Detects code blocks in document with many divs (issue #521)", async function () {
20-
const { doc } = await openAndShowTextDocument("div-code-blocks.qmd");
20+
const { doc } = await openAndShowExamplesOutTextDocument("div-code-blocks.qmd");
2121

2222
const tokens = engine.parse(doc);
2323
const executableBlocks = tokens.filter(isExecutableLanguageBlock);
@@ -49,7 +49,7 @@ suite("Code block detection", function () {
4949
});
5050

5151
test("Detects code block in simple document", async function () {
52-
const { doc } = await openAndShowTextDocument("hello.qmd");
52+
const { doc } = await openAndShowExamplesOutTextDocument("hello.qmd");
5353

5454
const tokens = engine.parse(doc);
5555
const executableBlocks = tokens.filter(isExecutableLanguageBlock);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# type: ignore
2+
# flake8: noqa
3+
#
4+
#
5+
#
6+
#
7+
#
8+
#
9+
#
10+
#
11+
1 + 1
12+
#
13+
#
14+
#
15+
2 + 2
16+
#
17+
#
18+
#
19+
#
20+
#
21+
#
22+
#
23+
4 + 4
24+
#
25+
#
26+
#
27+
#
28+
#
29+
#
30+
#
31+
#
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#
2+
#
3+
#
4+
#
5+
#
6+
#
7+
#
8+
#
9+
#
10+
#
11+
#
12+
#
13+
#
14+
#
15+
#
16+
#
17+
3 + 3
18+
#
19+
#
20+
#
21+
#
22+
#
23+
#
24+
#
25+
5 + 5
26+
#
27+
#
28+
#
29+
#
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#
2+
#
3+
#
4+
#
5+
#
6+
#
7+
#
8+
#
9+
#
10+
#
11+
#
12+
#
13+
#
14+
#
15+
#
16+
#
17+
3 + 3
18+
#
19+
#
20+
#
21+
#
22+
#
23+
#
24+
#
25+
#
26+
#
27+
#
28+
#
29+
#
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
title: "Test all blocks for language at position"
3+
format: html
4+
---
5+
6+
## Header
7+
8+
```{python}
9+
1 + 1
10+
```
11+
12+
```{python}
13+
2 + 2
14+
```
15+
16+
```{r}
17+
3 + 3
18+
```
19+
20+
```{python}
21+
4 + 4
22+
```
23+
24+
```{r}
25+
5 + 5
26+
```
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
title: "OOB"
3+
format: html
4+
---
5+
6+
## Header
7+
8+
```{python}
9+
1 + 1
10+
```
11+
12+
Yo

apps/vscode/src/test/quartoDoc.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as vscode from "vscode";
22
import * as assert from "assert";
3-
import { WORKSPACE_PATH, readOrCreateSnapshot, examplesOutUri, wait, roundtrip, openAndShowTextDocument } from "./test-utils";
3+
import { WORKSPACE_PATH, readOrCreateSnapshot, examplesOutUri, wait, roundtrip, openAndShowExamplesOutTextDocument } from "./test-utils";
44
import { isQuartoDoc } from "../core/doc";
55

66

@@ -13,7 +13,7 @@ suite("Quarto basics", function () {
1313
});
1414

1515
test("Can open a Quarto document", async function () {
16-
const { editor } = await openAndShowTextDocument("hello.qmd");
16+
const { editor } = await openAndShowExamplesOutTextDocument("hello.qmd");
1717

1818
assert.strictEqual(editor?.document.languageId, "quarto");
1919
assert.strictEqual(isQuartoDoc(editor?.document), true);
@@ -23,7 +23,7 @@ suite("Quarto basics", function () {
2323
// test. That's okay for this test, but could cause issues if you expect a qmd to look how it
2424
// does in `/examples`.
2525
test("Roundtrip doesn't change hello.qmd", async function () {
26-
const { doc } = await openAndShowTextDocument("hello.qmd");
26+
const { doc } = await openAndShowExamplesOutTextDocument("hello.qmd");
2727

2828
const { before, after } = await roundtrip(doc);
2929

@@ -44,7 +44,7 @@ suite("Quarto basics", function () {
4444

4545
// a test to prevent situations like https://github.com/quarto-dev/quarto/issues/845
4646
test("Can open a non-qmd file normally", async function () {
47-
const { editor, doc } = await openAndShowTextDocument("hello.lua");
47+
const { editor, doc } = await openAndShowExamplesOutTextDocument("hello.lua");
4848

4949
editor.edit((editBuilder) => {
5050
editBuilder.insert(new vscode.Position(0, 0), 'print("hiyo")\n');
@@ -57,7 +57,7 @@ suite("Quarto basics", function () {
5757
});
5858

5959
test("Roundtrip doesn't change nested-checked-list.qmd", async function () {
60-
const { doc } = await openAndShowTextDocument("nested-checked-list.qmd");
60+
const { doc } = await openAndShowExamplesOutTextDocument("nested-checked-list.qmd");
6161

6262
const { before, after } = await roundtrip(doc);
6363

@@ -78,7 +78,7 @@ function roundtripSnapshotTest(filename: string) {
7878
const snapshotFileName = `roundtripped-${filename}`;
7979

8080
test(`Roundtripped ${filename} matches snapshot`, async function () {
81-
const { doc } = await openAndShowTextDocument(filename);
81+
const { doc } = await openAndShowExamplesOutTextDocument(filename);
8282

8383
const { after } = await roundtrip(doc);
8484

apps/vscode/src/test/test-utils.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,16 @@ export function wait(ms: number) {
2626
return new Promise(resolve => setTimeout(resolve, ms));
2727
}
2828

29-
export async function openAndShowTextDocument(fileName: string) {
30-
const doc = await vscode.workspace.openTextDocument(examplesOutUri(fileName));
29+
export async function openAndShowExamplesTextDocument(fileName: string) {
30+
return openAndShowUri(examplesUri(fileName));
31+
}
32+
33+
export async function openAndShowExamplesOutTextDocument(fileName: string) {
34+
return openAndShowUri(examplesOutUri(fileName));
35+
}
36+
37+
async function openAndShowUri(uri: vscode.Uri) {
38+
const doc = await vscode.workspace.openTextDocument(uri);
3139
const editor = await vscode.window.showTextDocument(doc);
3240
return { doc, editor };
3341
}

0 commit comments

Comments
 (0)