From 526211999e01b0315dd0b85d3b1cffc81dcf7506 Mon Sep 17 00:00:00 2001 From: Emil Hvitfeldt Date: Tue, 3 Feb 2026 14:12:01 -0800 Subject: [PATCH 1/8] Add document link provider for _quarto.yml files in vscode extension --- apps/vscode/package.json | 7 ++ apps/vscode/src/main.ts | 4 + apps/vscode/src/providers/yaml-links.ts | 117 ++++++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 apps/vscode/src/providers/yaml-links.ts diff --git a/apps/vscode/package.json b/apps/vscode/package.json index e1a9b804..15b00e83 100644 --- a/apps/vscode/package.json +++ b/apps/vscode/package.json @@ -1258,6 +1258,13 @@ "default": false, "markdownDescription": "Write markdown links as references rather than inline. Reference links are written to the location specified in `#quarto.visualEditor.markdownReferences#`." }, + "quarto.yaml.documentLinks.enabled": { + "order": 45, + "scope": "window", + "type": "boolean", + "default": true, + "markdownDescription": "Enable clickable file links in `_quarto.yml` files." + }, "quarto.zotero.library": { "order": 50, "scope": "window", diff --git a/apps/vscode/src/main.ts b/apps/vscode/src/main.ts index 7f170f5e..810202bb 100644 --- a/apps/vscode/src/main.ts +++ b/apps/vscode/src/main.ts @@ -42,6 +42,7 @@ import { activateDiagram } from "./providers/diagram/diagram"; import { activateCodeFormatting } from "./providers/format"; import { activateOptionEnterProvider } from "./providers/option"; import { activateBackgroundHighlighter } from "./providers/background"; +import { activateYamlLinks } from "./providers/yaml-links"; import { activateContextKeySetter } from "./providers/context-keys"; import { CommandManager } from "./core/command"; import { createQuartoExtensionApi, QuartoExtensionApi } from "./api"; @@ -168,6 +169,9 @@ export async function activate(context: vscode.ExtensionContext): Promise("yaml.documentLinks.enabled", true)) { + context.subscriptions.push( + languages.registerDocumentLinkProvider( + { language: "yaml", scheme: "file" }, + new QuartoYamlLinkProvider() + ) + ); + } +} + +class QuartoYamlLinkProvider implements DocumentLinkProvider { + provideDocumentLinks( + document: TextDocument, + _token: CancellationToken + ): DocumentLink[] { + if (!isQuartoYaml(document)) { + return []; + } + + const links: DocumentLink[] = []; + const text = document.getText(); + const lines = text.split('\n'); + const documentDir = path.dirname(document.uri.fsPath); + + for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) { + const line = lines[lineIndex]; + const lineLinks = this.findLinksInLine(line, lineIndex, documentDir); + links.push(...lineLinks); + } + + return links; + } + + private findLinksInLine( + line: string, + lineIndex: number, + documentDir: string + ): DocumentLink[] { + const links: DocumentLink[] = []; + + // Match file paths in YAML values + // Pattern: looks for paths after ': ' or '- ' that end with known extensions + const extensionPattern = FILE_EXTENSIONS.join('|'); + const regex = new RegExp( + `(?:^\\s*-\\s*|:\\s*)([\\w./-]+\\.(?:${extensionPattern}))`, + 'gi' + ); + + let match; + while ((match = regex.exec(line)) !== null) { + const filePath = match[1]; + const startIndex = match.index + match[0].length - filePath.length; + const endIndex = startIndex + filePath.length; + + // Resolve the full path + const fullPath = path.isAbsolute(filePath) + ? filePath + : path.resolve(documentDir, filePath); + + // Check if the file exists + if (fs.existsSync(fullPath)) { + const range = new Range( + new Position(lineIndex, startIndex), + new Position(lineIndex, endIndex) + ); + + const link = new DocumentLink( + range, + Uri.file(fullPath) + ); + link.tooltip = `Open ${filePath}`; + links.push(link); + } + } + + return links; + } +} From 2c03e13090552652fe8e8d55b97506cb9350cb5c Mon Sep 17 00:00:00 2001 From: Emil Hvitfeldt Date: Tue, 3 Feb 2026 16:26:39 -0800 Subject: [PATCH 2/8] add quarto yaml file completions --- apps/vscode/package.json | 7 + apps/vscode/src/main.ts | 4 + apps/vscode/src/providers/yaml-completions.ts | 125 ++++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 apps/vscode/src/providers/yaml-completions.ts diff --git a/apps/vscode/package.json b/apps/vscode/package.json index 15b00e83..e8fdd882 100644 --- a/apps/vscode/package.json +++ b/apps/vscode/package.json @@ -1265,6 +1265,13 @@ "default": true, "markdownDescription": "Enable clickable file links in `_quarto.yml` files." }, + "quarto.yaml.completions.enabled": { + "order": 46, + "scope": "window", + "type": "boolean", + "default": true, + "markdownDescription": "Enable file path autocomplete in `_quarto.yml` files." + }, "quarto.zotero.library": { "order": 50, "scope": "window", diff --git a/apps/vscode/src/main.ts b/apps/vscode/src/main.ts index 810202bb..7ee9fa8c 100644 --- a/apps/vscode/src/main.ts +++ b/apps/vscode/src/main.ts @@ -43,6 +43,7 @@ import { activateCodeFormatting } from "./providers/format"; import { activateOptionEnterProvider } from "./providers/option"; import { activateBackgroundHighlighter } from "./providers/background"; import { activateYamlLinks } from "./providers/yaml-links"; +import { activateYamlCompletions } from "./providers/yaml-completions"; import { activateContextKeySetter } from "./providers/context-keys"; import { CommandManager } from "./core/command"; import { createQuartoExtensionApi, QuartoExtensionApi } from "./api"; @@ -172,6 +173,9 @@ export async function activate(context: vscode.ExtensionContext): Promise("yaml.completions.enabled", true)) { + context.subscriptions.push( + languages.registerCompletionItemProvider( + { language: "yaml", scheme: "file" }, + new QuartoYamlCompletionProvider(), + "/", "." // Trigger on path separators + ) + ); + } +} + +class QuartoYamlCompletionProvider implements CompletionItemProvider { + async provideCompletionItems( + document: TextDocument, + position: Position, + _token: CancellationToken, + _context: CompletionContext + ): Promise { + if (!isQuartoYaml(document)) { + return []; + } + + const line = document.lineAt(position).text; + const linePrefix = line.substring(0, position.character); + + // Only provide completions after ': ' or '- ' + if (!this.shouldProvideCompletions(linePrefix)) { + return []; + } + + const documentDir = path.dirname(document.uri.fsPath); + const projectFiles = await getProjectFiles(documentDir); + + // Get current input to filter completions + const currentInput = this.getCurrentInput(linePrefix); + + return projectFiles + .filter(file => file.toLowerCase().includes(currentInput.toLowerCase())) + .map(file => { + const item = new CompletionItem(file, CompletionItemKind.File); + item.detail = "Quarto project file"; + item.insertText = file; + + // If there's existing input, replace it + if (currentInput) { + const startPos = position.character - currentInput.length; + item.range = new Range( + new Position(position.line, startPos), + position + ); + } + + return item; + }); + } + + private shouldProvideCompletions(linePrefix: string): boolean { + // Check if we're in a position where file path completions make sense + // After ': ' for key-value pairs or after '- ' for list items + return /(?::\s+|^\s*-\s+)\S*$/.test(linePrefix); + } + + private getCurrentInput(linePrefix: string): string { + // Extract the current partial input after ': ' or '- ' + const match = linePrefix.match(/(?::\s+|^\s*-\s+)(\S*)$/); + return match ? match[1] : ""; + } +} + +async function getProjectFiles(projectDir: string): Promise { + const extensionPattern = `**/*.{${FILE_EXTENSIONS.join(',')}}`; + + try { + const files = await glob(extensionPattern, { + cwd: projectDir, + ignore: IGNORE_PATTERNS.map(p => `**/${p}/**`), + nodir: true, + }); + + return files.sort(); + } catch { + return []; + } +} From ce064ce64500b8122938aeb1acbd96af6129b54c Mon Sep 17 00:00:00 2001 From: Emil Hvitfeldt Date: Tue, 3 Feb 2026 16:33:38 -0800 Subject: [PATCH 3/8] activateYamlCompletions -> activateYamlFilepathCompletions --- apps/vscode/package.json | 2 +- apps/vscode/src/main.ts | 6 +++--- ...aml-completions.ts => yaml-filepath-completions.ts} | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) rename apps/vscode/src/providers/{yaml-completions.ts => yaml-filepath-completions.ts} (91%) diff --git a/apps/vscode/package.json b/apps/vscode/package.json index e8fdd882..42dd4d48 100644 --- a/apps/vscode/package.json +++ b/apps/vscode/package.json @@ -1265,7 +1265,7 @@ "default": true, "markdownDescription": "Enable clickable file links in `_quarto.yml` files." }, - "quarto.yaml.completions.enabled": { + "quarto.yaml.filepathCompletions.enabled": { "order": 46, "scope": "window", "type": "boolean", diff --git a/apps/vscode/src/main.ts b/apps/vscode/src/main.ts index 7ee9fa8c..bd58266f 100644 --- a/apps/vscode/src/main.ts +++ b/apps/vscode/src/main.ts @@ -43,7 +43,7 @@ import { activateCodeFormatting } from "./providers/format"; import { activateOptionEnterProvider } from "./providers/option"; import { activateBackgroundHighlighter } from "./providers/background"; import { activateYamlLinks } from "./providers/yaml-links"; -import { activateYamlCompletions } from "./providers/yaml-completions"; +import { activateYamlFilepathCompletions } from "./providers/yaml-filepath-completions"; import { activateContextKeySetter } from "./providers/context-keys"; import { CommandManager } from "./core/command"; import { createQuartoExtensionApi, QuartoExtensionApi } from "./api"; @@ -173,8 +173,8 @@ export async function activate(context: vscode.ExtensionContext): Promise("yaml.completions.enabled", true)) { + if (config.get("yaml.filepathCompletions.enabled", true)) { context.subscriptions.push( languages.registerCompletionItemProvider( { language: "yaml", scheme: "file" }, - new QuartoYamlCompletionProvider(), + new QuartoYamlFilepathCompletionProvider(), "/", "." // Trigger on path separators ) ); } } -class QuartoYamlCompletionProvider implements CompletionItemProvider { +class QuartoYamlFilepathCompletionProvider implements CompletionItemProvider { async provideCompletionItems( document: TextDocument, position: Position, From b3eb2e2bffe1bbca6278fcc7b0f4a112eebfb15c Mon Sep 17 00:00:00 2001 From: Emil Hvitfeldt Date: Wed, 4 Feb 2026 07:51:07 -0800 Subject: [PATCH 4/8] update copyright years --- apps/vscode/src/providers/yaml-filepath-completions.ts | 2 +- apps/vscode/src/providers/yaml-links.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/vscode/src/providers/yaml-filepath-completions.ts b/apps/vscode/src/providers/yaml-filepath-completions.ts index 29742995..16fa2e94 100644 --- a/apps/vscode/src/providers/yaml-filepath-completions.ts +++ b/apps/vscode/src/providers/yaml-filepath-completions.ts @@ -1,7 +1,7 @@ /* * yaml-filepath-completions.ts * - * Copyright (C) 2022 by Posit Software, PBC + * Copyright (C) 2026 by Posit Software, PBC * * Unless you have received this program directly from Posit Software pursuant * to the terms of a commercial license agreement with Posit Software, then diff --git a/apps/vscode/src/providers/yaml-links.ts b/apps/vscode/src/providers/yaml-links.ts index 3e4e52ef..84de27d9 100644 --- a/apps/vscode/src/providers/yaml-links.ts +++ b/apps/vscode/src/providers/yaml-links.ts @@ -1,7 +1,7 @@ /* * yaml-links.ts * - * Copyright (C) 2022 by Posit Software, PBC + * Copyright (C) 2026 by Posit Software, PBC * * Unless you have received this program directly from Posit Software pursuant * to the terms of a commercial license agreement with Posit Software, then From 6c26d5e738f8776305bc2ca7c74d730902f21e14 Mon Sep 17 00:00:00 2001 From: Emil Hvitfeldt Date: Thu, 5 Feb 2026 18:21:55 -0800 Subject: [PATCH 5/8] activate vscode yaml providers on _quarto.ya?ml instead of on yaml files --- apps/vscode/src/providers/yaml-filepath-completions.ts | 8 +------- apps/vscode/src/providers/yaml-links.ts | 8 +------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/apps/vscode/src/providers/yaml-filepath-completions.ts b/apps/vscode/src/providers/yaml-filepath-completions.ts index 16fa2e94..388ac8c1 100644 --- a/apps/vscode/src/providers/yaml-filepath-completions.ts +++ b/apps/vscode/src/providers/yaml-filepath-completions.ts @@ -31,8 +31,6 @@ import { workspace, } from "vscode"; -import { isQuartoYaml } from "../core/doc"; - const FILE_EXTENSIONS = ['qmd', 'scss', 'css', 'html', 'js', 'bib', 'tex', 'md']; const IGNORE_PATTERNS = ['.git', 'node_modules', '_site', '_freeze', '.quarto']; @@ -42,7 +40,7 @@ export function activateYamlFilepathCompletions(context: ExtensionContext) { if (config.get("yaml.filepathCompletions.enabled", true)) { context.subscriptions.push( languages.registerCompletionItemProvider( - { language: "yaml", scheme: "file" }, + { scheme: "file", pattern: "**/_quarto.{yml,yaml}" }, new QuartoYamlFilepathCompletionProvider(), "/", "." // Trigger on path separators ) @@ -57,10 +55,6 @@ class QuartoYamlFilepathCompletionProvider implements CompletionItemProvider { _token: CancellationToken, _context: CompletionContext ): Promise { - if (!isQuartoYaml(document)) { - return []; - } - const line = document.lineAt(position).text; const linePrefix = line.substring(0, position.character); diff --git a/apps/vscode/src/providers/yaml-links.ts b/apps/vscode/src/providers/yaml-links.ts index 84de27d9..2cb29c8e 100644 --- a/apps/vscode/src/providers/yaml-links.ts +++ b/apps/vscode/src/providers/yaml-links.ts @@ -29,8 +29,6 @@ import { workspace, } from "vscode"; -import { isQuartoYaml } from "../core/doc"; - const FILE_EXTENSIONS = ['qmd', 'scss', 'css', 'html', 'js', 'bib', 'tex', 'md']; const IGNORE_PATTERNS = ['.git', 'node_modules', '_site', '_freeze', '.quarto']; @@ -40,7 +38,7 @@ export function activateYamlLinks(context: ExtensionContext) { if (config.get("yaml.documentLinks.enabled", true)) { context.subscriptions.push( languages.registerDocumentLinkProvider( - { language: "yaml", scheme: "file" }, + { scheme: "file", pattern: "**/_quarto.{yml,yaml}" }, new QuartoYamlLinkProvider() ) ); @@ -52,10 +50,6 @@ class QuartoYamlLinkProvider implements DocumentLinkProvider { document: TextDocument, _token: CancellationToken ): DocumentLink[] { - if (!isQuartoYaml(document)) { - return []; - } - const links: DocumentLink[] = []; const text = document.getText(); const lines = text.split('\n'); From 20be4977b25444c36d65548d27547b2fd9cfabb0 Mon Sep 17 00:00:00 2001 From: Emil Hvitfeldt Date: Fri, 6 Feb 2026 12:04:28 -0800 Subject: [PATCH 6/8] document yaml providers --- .../src/providers/yaml-filepath-completions.ts | 16 ++++++++++++++++ apps/vscode/src/providers/yaml-links.ts | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/apps/vscode/src/providers/yaml-filepath-completions.ts b/apps/vscode/src/providers/yaml-filepath-completions.ts index 388ac8c1..37447086 100644 --- a/apps/vscode/src/providers/yaml-filepath-completions.ts +++ b/apps/vscode/src/providers/yaml-filepath-completions.ts @@ -13,6 +13,22 @@ * */ +/** + * Filepath Completion Provider for Quarto YAML Configuration Files + * + * This module provides filepath autocompletion for `_quarto.yml` and `_quarto.yaml` + * configuration files. When editing YAML values (after `: ` or `- `), the extension + * suggests project files that match what you're typing. + * + * The provider: + * - Triggers completions after `: ` (key-value pairs) or `- ` (list items) + * - Scans the project directory for matching files + * - Filters suggestions based on current input + * - Ignores common non-content directories (.git, node_modules, _site, _freeze, .quarto) + * + * Can be disabled via the `quarto.yaml.filepathCompletions.enabled` setting. + */ + import * as path from "path"; import { glob } from "glob"; diff --git a/apps/vscode/src/providers/yaml-links.ts b/apps/vscode/src/providers/yaml-links.ts index 2cb29c8e..89a85f4f 100644 --- a/apps/vscode/src/providers/yaml-links.ts +++ b/apps/vscode/src/providers/yaml-links.ts @@ -13,6 +13,22 @@ * */ +/** + * Document Link Provider for Quarto YAML Configuration Files + * + * This module provides clickable document links for file paths referenced in + * `_quarto.yml` and `_quarto.yaml` configuration files. When a file path is + * detected in the YAML content (e.g., `render: hello.qmd` or `css: styles.css`), + * it becomes a clickable link that navigates directly to that file. + * + * The provider: + * - Scans YAML content for file paths after `: ` (key-value) or `- ` (list items) + * - Verifies that referenced files exist before creating links + * - Resolves relative paths from the location of the _quarto.yml file + * + * Can be disabled via the `quarto.yaml.documentLinks.enabled` setting. + */ + import path from "node:path"; import fs from "node:fs"; From e9981bbe94113cff530ac12bb0ea82f6eb226213 Mon Sep 17 00:00:00 2001 From: Emil Hvitfeldt Date: Fri, 6 Feb 2026 12:10:24 -0800 Subject: [PATCH 7/8] add tests for providers --- apps/vscode/src/test/examples/_quarto.yml | 15 +++ apps/vscode/src/test/yamlProviders.test.ts | 129 +++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 apps/vscode/src/test/examples/_quarto.yml create mode 100644 apps/vscode/src/test/yamlProviders.test.ts diff --git a/apps/vscode/src/test/examples/_quarto.yml b/apps/vscode/src/test/examples/_quarto.yml new file mode 100644 index 00000000..3a25ab2c --- /dev/null +++ b/apps/vscode/src/test/examples/_quarto.yml @@ -0,0 +1,15 @@ +project: + type: default + +metadata: + title: "Test Project" + +render: + - hello.qmd + - valid-basics.qmd + +bibliography: references.bib + +format: + html: + css: styles.css diff --git a/apps/vscode/src/test/yamlProviders.test.ts b/apps/vscode/src/test/yamlProviders.test.ts new file mode 100644 index 00000000..5a35be5a --- /dev/null +++ b/apps/vscode/src/test/yamlProviders.test.ts @@ -0,0 +1,129 @@ +import * as vscode from "vscode"; +import * as assert from "assert"; +import { WORKSPACE_PATH, examplesOutUri } from "./test-utils"; + +suite("YAML Providers", function () { + suiteSetup(async function () { + await vscode.workspace.fs.delete(examplesOutUri(), { recursive: true }); + await vscode.workspace.fs.copy(vscode.Uri.file(WORKSPACE_PATH), examplesOutUri()); + }); + + suite("Document Links", function () { + test("Provides document links for existing files in _quarto.yml", async function () { + const quartoYmlUri = examplesOutUri("_quarto.yml"); + const doc = await vscode.workspace.openTextDocument(quartoYmlUri); + + const links = await vscode.commands.executeCommand( + "vscode.executeLinkProvider", + doc.uri + ); + + assert.ok(links, "Should return document links"); + assert.ok(links.length >= 3, `Expected at least 3 links, found ${links.length}`); + + const helloLink = links.find( + (link) => link.target?.fsPath.endsWith("hello.qmd") + ); + assert.ok(helloLink, "Should have a link for hello.qmd"); + + const validBasicsLink = links.find( + (link) => link.target?.fsPath.endsWith("valid-basics.qmd") + ); + assert.ok(validBasicsLink, "Should have a link for valid-basics.qmd"); + + const bibLink = links.find( + (link) => link.target?.fsPath.endsWith("references.bib") + ); + assert.ok(bibLink, "Should have a link for references.bib"); + }); + + test("Does not provide links for non-existent files", async function () { + const quartoYmlUri = examplesOutUri("_quarto.yml"); + const doc = await vscode.workspace.openTextDocument(quartoYmlUri); + + const links = await vscode.commands.executeCommand( + "vscode.executeLinkProvider", + doc.uri + ); + + const stylesLink = links?.find( + (link) => link.target?.fsPath.endsWith("styles.css") + ); + assert.ok(!stylesLink, "Should not have a link for non-existent styles.css"); + }); + }); + + suite("Filepath Completions", function () { + test("Provides file path completions in _quarto.yml", async function () { + const quartoYmlUri = examplesOutUri("_quarto.yml"); + const doc = await vscode.workspace.openTextDocument(quartoYmlUri); + await vscode.window.showTextDocument(doc); + + const position = new vscode.Position(7, 4); + const completions = await vscode.commands.executeCommand( + "vscode.executeCompletionItemProvider", + doc.uri, + position + ); + + assert.ok(completions, "Should return completions"); + assert.ok(completions.items.length > 0, "Should have completion items"); + + const qmdCompletions = completions.items.filter( + (item) => item.label.toString().endsWith(".qmd") + ); + assert.ok(qmdCompletions.length > 0, "Should suggest .qmd files"); + }); + + test("Completion replaces partial input with dot correctly", async function () { + const testDir = examplesOutUri("test-completion"); + const tempYmlUri = vscode.Uri.joinPath(testDir, "_quarto.yml"); + + const content = `project: + type: default + +render: + - hello.q`; + + await vscode.workspace.fs.createDirectory(testDir); + await vscode.workspace.fs.copy( + examplesOutUri("hello.qmd"), + vscode.Uri.joinPath(testDir, "hello.qmd") + ); + await vscode.workspace.fs.writeFile(tempYmlUri, Buffer.from(content, "utf-8")); + + try { + const doc = await vscode.workspace.openTextDocument(tempYmlUri); + await vscode.window.showTextDocument(doc); + + const position = new vscode.Position(4, 11); + const completions = await vscode.commands.executeCommand( + "vscode.executeCompletionItemProvider", + doc.uri, + position + ); + + assert.ok(completions, "Should return completions"); + + const helloCompletion = completions.items.find( + (item) => item.label.toString() === "hello.qmd" + ); + assert.ok(helloCompletion, "Should have hello.qmd completion for partial 'hello.q'"); + + const range = helloCompletion.range; + assert.ok(range, "Completion should have a range"); + + if (range instanceof vscode.Range) { + assert.strictEqual(range.start.character, 4, "Range should start at column 4 (after ' - ')"); + assert.strictEqual(range.end.character, 11, "Range should end at column 11"); + } else if (range && typeof range === "object" && "replacing" in range) { + const replacingRange = (range as { replacing: vscode.Range }).replacing; + assert.strictEqual(replacingRange.start.character, 4, "Replacing range should start at column 4 to replace 'hello.q'"); + assert.strictEqual(replacingRange.end.character, 11, "Replacing range should end at column 11"); + } + } finally { + await vscode.workspace.fs.delete(testDir, { recursive: true }); + } + }); + }); +}); From 2254fddb6407b2710f4dd06be082fb067d0042f8 Mon Sep 17 00:00:00 2001 From: Emil Hvitfeldt Date: Fri, 6 Feb 2026 12:10:35 -0800 Subject: [PATCH 8/8] update changelog --- apps/vscode/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/vscode/CHANGELOG.md b/apps/vscode/CHANGELOG.md index f5bacbd9..88365b0b 100644 --- a/apps/vscode/CHANGELOG.md +++ b/apps/vscode/CHANGELOG.md @@ -2,6 +2,9 @@ ## 1.130.0 (Unreleased) +- Added clickable document links for file paths in `_quarto.yml` files. File paths are now clickable and navigate directly to the referenced file (). +- Added filepath autocompletion in `_quarto.yml` files. When editing YAML values, the extension now suggests project files as you type (). + ## 1.129.0 (Release on 2026-01-29) - Fixed Copilot completions in `.qmd` documents ().