Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions apps/vscode/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## 1.133.0

- Add custom pair colorization and highlighting for divs in qmds (<https://github.com/quarto-dev/quarto/pull/973>).
Comment thread
vezwork marked this conversation as resolved.
Outdated


## 1.132.0 (Release on 2026-05-05)

- Added clickable document links for file paths in `_quarto.yml` files. File paths are now clickable and navigate directly to the referenced file (<https://github.com/quarto-dev/quarto/pull/906>).
Expand Down
41 changes: 41 additions & 0 deletions apps/vscode/src/core/throttle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* throttle.ts
*
* 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
* this program is licensed to you under the terms of version 3 of the
* GNU Affero General Public License. This program is distributed WITHOUT
* ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
* AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
*
*/

/**
* Creates a throttled version of a function.
* First call executes immediately, subsequent calls within the delay are coalesced.
*/
export function createThrottle(
fn: () => any,
getDelay: () => number
): () => any {
let timer: NodeJS.Timeout | undefined;
let pending = false;

return () => {
if (timer === undefined) {
fn();
timer = setTimeout(() => {
if (pending) {
fn();
pending = false;
}
timer = undefined;
}, getDelay());
} else {
pending = true;
}
};
}
4 changes: 4 additions & 0 deletions apps/vscode/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { activateBackgroundHighlighter } from "./providers/background";
import { activateYamlLinks } from "./providers/yaml-links";
import { activateYamlFilepathCompletions } from "./providers/yaml-filepath-completions";
import { activateContextKeySetter } from "./providers/context-keys";
import { activateDivBracketDecorations } from "./providers/div-brackets";
import { CommandManager } from "./core/command";
import { createQuartoExtensionApi, QuartoExtensionApi } from "./api";

Expand Down Expand Up @@ -221,6 +222,9 @@ export async function activate(context: vscode.ExtensionContext): Promise<Quarto
// context setter
activateContextKeySetter(context, engine);

// div bracket decorations
activateDivBracketDecorations(context);

// commands
const commandManager = new CommandManager();
for (const cmd of commands) {
Expand Down
62 changes: 31 additions & 31 deletions apps/vscode/src/providers/background.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* background.ts
*
* Copyright (C) 2022 by Posit Software, PBC
* Copyright (C) 2026 by Posit Software, PBC
* Copyright (c) [2021] [Chris Bain] (https://github.com/baincd/vscode-markdown-color-plus/)
*
* Unless you have received this program directly from Posit Software pursuant
Expand All @@ -16,12 +16,12 @@


import * as vscode from "vscode";
import debounce from "lodash.debounce";

import { isQuartoDoc, kQuartoDocSelector } from "../core/doc";
import { MarkdownEngine } from "../markdown/engine";
import { isExecutableLanguageBlock } from "quarto-core";
import { vscRange } from "../core/range";
import { createThrottle } from "../core/throttle";

export function activateBackgroundHighlighter(
context: vscode.ExtensionContext,
Expand All @@ -32,7 +32,7 @@ export function activateBackgroundHighlighter(
vscode.workspace.onDidChangeConfiguration(
() => {
highlightingConfig.sync();
triggerUpdateAllEditorsDecorations(engine);
updateAllEditorsDecorationsThrottled(engine);
},
null,
context.subscriptions
Expand All @@ -45,10 +45,9 @@ export function activateBackgroundHighlighter(
if (!isQuartoDoc(doc)) {
clearEditorHighlightDecorations(vscode.window.activeTextEditor);
} else {
triggerUpdateActiveEditorDecorations(
updateActiveEditorDecorationsThrottled(
vscode.window.activeTextEditor,
engine,
highlightingConfig.delayMs()
engine
);
}
}
Expand All @@ -59,8 +58,13 @@ export function activateBackgroundHighlighter(

// update highlighting when visible text editors change
vscode.window.onDidChangeVisibleTextEditors(
(_editors) => {
triggerUpdateAllEditorsDecorations(engine);
(visibleEditors) => {
for (const editor of editorThrottledFunctions.keys()) {
if (!visibleEditors.includes(editor)) {
editorThrottledFunctions.delete(editor);
}
}
updateAllEditorsDecorationsThrottled(engine);
},
null,
context.subscriptions
Expand All @@ -73,11 +77,9 @@ export function activateBackgroundHighlighter(
return editor.document.uri.toString() === event.document.uri.toString();
});
if (visibleEditor) {
triggerUpdateActiveEditorDecorations(
updateActiveEditorDecorationsThrottled(
visibleEditor,
engine,
highlightingConfig.delayMs(),
true,
event.contentChanges.length === 1
? event.contentChanges[0].range.start
: undefined
Expand All @@ -97,11 +99,9 @@ export function activateBackgroundHighlighter(
token: vscode.CancellationToken
) {
if (document === vscode.window.activeTextEditor?.document) {
triggerUpdateActiveEditorDecorations(
updateActiveEditorDecorationsThrottled(
vscode.window.activeTextEditor,
engine,
highlightingConfig.delayMs(),
true,
position,
token
);
Expand All @@ -112,32 +112,32 @@ export function activateBackgroundHighlighter(
);

// highlight all editors at activation time
triggerUpdateAllEditorsDecorations(engine);
updateAllEditorsDecorationsThrottled(engine);
}

function triggerUpdateActiveEditorDecorations(
// Map of editors to their throttled update functions
const editorThrottledFunctions = new Map<vscode.TextEditor, () => void>();
function updateActiveEditorDecorationsThrottled(
editor: vscode.TextEditor,
engine: MarkdownEngine,
delay: number,
immediate?: boolean,
pos?: vscode.Position,
token?: vscode.CancellationToken
) {
debounce(
() => setEditorHighlightDecorations(editor, engine, pos, token),
delay,
{
leading: !!immediate,
}
)();
let throttled = editorThrottledFunctions.get(editor);
if (!throttled) {
throttled = createThrottle(
() => setEditorHighlightDecorations(editor, engine, pos, token),
() => highlightingConfig.delayMs()
);
editorThrottledFunctions.set(editor, throttled);
}
throttled();
}

function triggerUpdateAllEditorsDecorations(engine: MarkdownEngine) {
debounce(async () => {
for (const editor of vscode.window.visibleTextEditors) {
await setEditorHighlightDecorations(editor, engine);
}
}, highlightingConfig.delayMs())();
function updateAllEditorsDecorationsThrottled(engine: MarkdownEngine) {
for (const editor of vscode.window.visibleTextEditors) {
updateActiveEditorDecorationsThrottled(editor, engine);
}
}

async function setEditorHighlightDecorations(
Expand Down
1 change: 1 addition & 0 deletions apps/vscode/src/providers/context-keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export function activateContextKeySetter(
vscode.workspace.onDidChangeTextDocument(event => {
const activeEditor = vscode.window.activeTextEditor;
if (activeEditor) {
// TODO: this debounce is being created and called immediately, which is not correct.
debounce(
() => {
setEditorContextKeys(activeEditor, engine);
Expand Down
Loading
Loading