From 20a073a84b8ad158674ec46dfedacda5be62d348 Mon Sep 17 00:00:00 2001 From: Davis Vaughan Date: Wed, 18 Feb 2026 11:57:59 -0500 Subject: [PATCH 1/7] Add `'positron'` as "external" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To resolve ``` quarto:dev: ✘ [ERROR] Could not resolve "positron" quarto:dev: quarto:dev: src/host/hooks.ts:19:23: quarto:dev: 19 │ import * as hooks from 'positron'; ``` --- apps/vscode/build.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/vscode/build.ts b/apps/vscode/build.ts index 8595c118..7d4a3a5c 100644 --- a/apps/vscode/build.ts +++ b/apps/vscode/build.ts @@ -24,14 +24,14 @@ const testFiles = glob.sync("src/test/*.ts"); const testBuildOptions = { entryPoints: testFiles, outdir: 'test-out', - external: ['vscode', 'mocha', 'glob'], + external: ['vscode', 'positron', 'mocha', 'glob'], sourcemap: true, }; const defaultBuildOptions = { entryPoints: ['./src/main.ts'], outfile: './out/main.js', - external: ['vscode'], + external: ['vscode', 'positron'], minify: !dev, dev }; From cc7e0940e83686fdf81a7a46c42d55ef2766d39c Mon Sep 17 00:00:00 2001 From: Davis Vaughan Date: Wed, 18 Feb 2026 12:00:49 -0500 Subject: [PATCH 2/7] Rethrow new `StatementRangeSyntaxError` with unadjusted line number --- apps/vscode/src/@types/hooks.d.ts | 5 +++++ apps/vscode/src/host/hooks.ts | 24 +++++++++++++++++------- apps/vscode/src/vdoc/vdoc.ts | 14 +++++++++++--- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/apps/vscode/src/@types/hooks.d.ts b/apps/vscode/src/@types/hooks.d.ts index 32bf8a12..932e09a2 100644 --- a/apps/vscode/src/@types/hooks.d.ts +++ b/apps/vscode/src/@types/hooks.d.ts @@ -58,6 +58,11 @@ declare module 'positron' { readonly code?: string; } + export class StatementRangeSyntaxError extends Error { + readonly line?: number; + constructor(line?: number); + } + export interface PositronWindow { createPreviewPanel( viewType: string, diff --git a/apps/vscode/src/host/hooks.ts b/apps/vscode/src/host/hooks.ts index afcd8b34..ea2c89f4 100644 --- a/apps/vscode/src/host/hooks.ts +++ b/apps/vscode/src/host/hooks.ts @@ -22,7 +22,7 @@ import { ExtensionHost, HostWebviewPanel, HostStatementRangeProvider, HostHelpTo import { CellExecutor, cellExecutorForLanguage, executableLanguages, isKnitrDocument, pythonWithReticulate } from './executors'; import { ExecuteQueue } from './execute-queue'; import { MarkdownEngine } from '../markdown/engine'; -import { virtualDoc, adjustedPosition, unadjustedRange, withVirtualDocUri, VirtualDocStyle } from "../vdoc/vdoc"; +import { virtualDoc, adjustedPosition, unadjustedRange, withVirtualDocUri, VirtualDocStyle, unadjustedLine } from "../vdoc/vdoc"; import { Position, Range } from 'vscode'; import { Uri } from 'vscode'; @@ -200,18 +200,28 @@ class EmbeddedStatementRangeProvider implements HostStatementRangeProvider { position: vscode.Position, token: vscode.CancellationToken): Promise { const vdoc = await virtualDoc(document, position, this._engine, VirtualDocStyle.Block); - if (vdoc) { - return await withVirtualDocUri(vdoc, document.uri, "statementRange", async (uri: vscode.Uri) => { + + if (!vdoc) { + return undefined; + } + + return await withVirtualDocUri(vdoc, document.uri, "statementRange", async (uri: vscode.Uri) => { + try { const result = await vscode.commands.executeCommand( "vscode.executeStatementRangeProvider", uri, adjustedPosition(vdoc.language, position) ); return { range: unadjustedRange(vdoc.language, result.range), code: result.code }; - }); - } else { - return undefined; - } + } catch (err) { + if (err instanceof hooks.StatementRangeSyntaxError) { + // Rethrow syntax error with unadjusted line number, so Positron's notification will + // jump to the correct line + throw new hooks.StatementRangeSyntaxError(err.line ? unadjustedLine(vdoc.language, err.line) : undefined); + } + throw err; + } + }); }; } diff --git a/apps/vscode/src/vdoc/vdoc.ts b/apps/vscode/src/vdoc/vdoc.ts index 29a8c178..c17720e4 100644 --- a/apps/vscode/src/vdoc/vdoc.ts +++ b/apps/vscode/src/vdoc/vdoc.ts @@ -240,13 +240,21 @@ export function isBlockOfLanguage(language: EmbeddedLanguage) { }; } -// adjust position for inject +// adjust line for inject +export function adjustedLine(language: EmbeddedLanguage, line: number): number { + return line + (language.inject?.length || 0); +} + +export function unadjustedLine(language: EmbeddedLanguage, line: number): number { + return line - (language.inject?.length || 0); +} + export function adjustedPosition(language: EmbeddedLanguage, pos: Position) { - return new Position(pos.line + (language.inject?.length || 0), pos.character); + return new Position(adjustedLine(language, pos.line), pos.character); } export function unadjustedPosition(language: EmbeddedLanguage, pos: Position) { - return new Position(pos.line - (language.inject?.length || 0), pos.character); + return new Position(unadjustedLine(language, pos.line), pos.character); } export function unadjustedRange(language: EmbeddedLanguage, range: Range) { From 6bca2480c1d227dcd0afa5e51827825c73522e23 Mon Sep 17 00:00:00 2001 From: Davis Vaughan Date: Wed, 18 Feb 2026 13:12:43 -0500 Subject: [PATCH 3/7] Guard `StatementRangeSyntaxError` usage with version requirement --- apps/vscode/src/host/hooks.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/vscode/src/host/hooks.ts b/apps/vscode/src/host/hooks.ts index ea2c89f4..21cc1b02 100644 --- a/apps/vscode/src/host/hooks.ts +++ b/apps/vscode/src/host/hooks.ts @@ -18,6 +18,7 @@ import * as vscode from 'vscode'; import * as hooks from 'positron'; +import semver from "semver"; import { ExtensionHost, HostWebviewPanel, HostStatementRangeProvider, HostHelpTopicProvider } from '.'; import { CellExecutor, cellExecutorForLanguage, executableLanguages, isKnitrDocument, pythonWithReticulate } from './executors'; import { ExecuteQueue } from './execute-queue'; @@ -214,10 +215,14 @@ class EmbeddedStatementRangeProvider implements HostStatementRangeProvider { ); return { range: unadjustedRange(vdoc.language, result.range), code: result.code }; } catch (err) { - if (err instanceof hooks.StatementRangeSyntaxError) { - // Rethrow syntax error with unadjusted line number, so Positron's notification will - // jump to the correct line - throw new hooks.StatementRangeSyntaxError(err.line ? unadjustedLine(vdoc.language, err.line) : undefined); + // TODO: Remove this once `apps/vscode/package.json` bumps to `"positron": "^2026.03.0"` or higher. + // For now we avoid aggressive bumping due to https://github.com/posit-dev/positron/issues/11321. + if (semver.gte(hooks.version, "2026.03.0")) { + if (err instanceof hooks.StatementRangeSyntaxError) { + // Rethrow syntax error with unadjusted line number, so Positron's notification will + // jump to the correct line + throw new hooks.StatementRangeSyntaxError(err.line ? unadjustedLine(vdoc.language, err.line) : undefined); + } } throw err; } From 7a22bc3ac867ac84dba929d2675a073310613ce6 Mon Sep 17 00:00:00 2001 From: Davis Vaughan Date: Wed, 11 Mar 2026 13:06:39 -0400 Subject: [PATCH 4/7] Remove `'positron'` from list of externals I think this is causing test failures because in CI we run the tests as vscode, but in these externals we are trying to assert that positron will be available, and it's not It would be nice to figure this out though, because this was required for me to run dev quarto with dev positron. --- apps/vscode/build.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/vscode/build.ts b/apps/vscode/build.ts index 7d4a3a5c..8595c118 100644 --- a/apps/vscode/build.ts +++ b/apps/vscode/build.ts @@ -24,14 +24,14 @@ const testFiles = glob.sync("src/test/*.ts"); const testBuildOptions = { entryPoints: testFiles, outdir: 'test-out', - external: ['vscode', 'positron', 'mocha', 'glob'], + external: ['vscode', 'mocha', 'glob'], sourcemap: true, }; const defaultBuildOptions = { entryPoints: ['./src/main.ts'], outfile: './out/main.js', - external: ['vscode', 'positron'], + external: ['vscode'], minify: !dev, dev }; From 5f1287ffb486a72795d64d40e017d867316ee022 Mon Sep 17 00:00:00 2001 From: Davis Vaughan Date: Wed, 11 Mar 2026 14:17:22 -0400 Subject: [PATCH 5/7] Expose `StatementRangeSyntaxError` via `hooksAPI()` This is why I was needing `'positron'` as an "external" before. We've never had to expose a class that we need to construct before, and it requires using it as a "value" rather than just as a "type" so it needs to show up in `PositronApi` and be called via `hooksApi()` --- apps/vscode/src/@types/hooks.d.ts | 1 + apps/vscode/src/host/hooks.ts | 24 +++++++++++++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/apps/vscode/src/@types/hooks.d.ts b/apps/vscode/src/@types/hooks.d.ts index 932e09a2..c8b0c2b7 100644 --- a/apps/vscode/src/@types/hooks.d.ts +++ b/apps/vscode/src/@types/hooks.d.ts @@ -10,6 +10,7 @@ declare module 'positron' { runtime: PositronRuntime; languages: PositronLanguages; window: PositronWindow; + StatementRangeSyntaxError: typeof StatementRangeSyntaxError; } export interface PositronRuntime { diff --git a/apps/vscode/src/host/hooks.ts b/apps/vscode/src/host/hooks.ts index 21cc1b02..5f72bd98 100644 --- a/apps/vscode/src/host/hooks.ts +++ b/apps/vscode/src/host/hooks.ts @@ -215,16 +215,26 @@ class EmbeddedStatementRangeProvider implements HostStatementRangeProvider { ); return { range: unadjustedRange(vdoc.language, result.range), code: result.code }; } catch (err) { + let hooks = hooksApi(); + + if (!hooks) { + throw err; + } + // TODO: Remove this once `apps/vscode/package.json` bumps to `"positron": "^2026.03.0"` or higher. // For now we avoid aggressive bumping due to https://github.com/posit-dev/positron/issues/11321. - if (semver.gte(hooks.version, "2026.03.0")) { - if (err instanceof hooks.StatementRangeSyntaxError) { - // Rethrow syntax error with unadjusted line number, so Positron's notification will - // jump to the correct line - throw new hooks.StatementRangeSyntaxError(err.line ? unadjustedLine(vdoc.language, err.line) : undefined); - } + if (semver.lt(hooks.version, "2026.03.0")) { + throw err; + } + + if (err instanceof hooks.StatementRangeSyntaxError) { + // Rethrow syntax error with unadjusted line number, so Positron's notification will + // jump to the correct line + throw new hooks.StatementRangeSyntaxError(err.line ? unadjustedLine(vdoc.language, err.line) : undefined); + } else { + // Rethrow unrecognized error + throw err; } - throw err; } }); }; From ef2e03d88f17d175dea5cd5b59a1122a1f73a846 Mon Sep 17 00:00:00 2001 From: Davis Vaughan Date: Wed, 11 Mar 2026 14:18:04 -0400 Subject: [PATCH 6/7] Use lexicographic comparison for calendar versions --- apps/vscode/src/host/hooks.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/vscode/src/host/hooks.ts b/apps/vscode/src/host/hooks.ts index 5f72bd98..bd16a8bd 100644 --- a/apps/vscode/src/host/hooks.ts +++ b/apps/vscode/src/host/hooks.ts @@ -223,7 +223,10 @@ class EmbeddedStatementRangeProvider implements HostStatementRangeProvider { // TODO: Remove this once `apps/vscode/package.json` bumps to `"positron": "^2026.03.0"` or higher. // For now we avoid aggressive bumping due to https://github.com/posit-dev/positron/issues/11321. - if (semver.lt(hooks.version, "2026.03.0")) { + // We can't use `semver.lt()` because calendar versioning isn't compatible with semver due to the + // leading `0` in `03`. Instead, we use lexicographic string comparison and rely on the year and + // month to be zero padded so sorting always works correctly. + if (hooks.version < "2026.03.0") { throw err; } From d15d361ed5584a66b91b629eb0e74e46f0bc0a07 Mon Sep 17 00:00:00 2001 From: Davis Vaughan Date: Fri, 13 Mar 2026 15:47:26 -0400 Subject: [PATCH 7/7] CHANGELOG --- apps/vscode/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/vscode/CHANGELOG.md b/apps/vscode/CHANGELOG.md index f7f27bb3..a5e437cd 100644 --- a/apps/vscode/CHANGELOG.md +++ b/apps/vscode/CHANGELOG.md @@ -2,6 +2,7 @@ ## 1.131.0 (Unreleased) +- Added support for Positron's statement execution feature that reports the approximate line number of the parse error (). - Fixed a bug where `Quarto: Format Cell` would notify you that no formatter was available for code cells that were already formatted (). ## 1.130.0 (Release on 2026-02-18)