From 5452f21af75527428637a322c47b59de295fbaac Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 4 Nov 2025 15:36:51 +0000 Subject: [PATCH 1/9] Initial plan From 6d5e85f112e29b6306c719b78af180b6b22e7c01 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 4 Nov 2025 15:48:12 +0000 Subject: [PATCH 2/9] Fix math formula color detection with autoDetectColorScheme - Add notification system to send actual theme kind from VS Code to LSP - Track active color theme kind in LSP ConfigurationManager - Send theme notifications on startup and when theme changes - Use actual theme kind instead of parsing theme name Co-authored-by: kv9898 <105025148+kv9898@users.noreply.github.com> --- apps/lsp/src/config.ts | 20 ++++++++- apps/lsp/src/index.ts | 6 +++ ...vite.config.ts.timestamp-1762271143169.mjs | 43 +++++++++++++++++++ apps/vscode/src/lsp/client.ts | 21 ++++++++- 4 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 apps/vscode-editor/vite.config.ts.timestamp-1762271143169.mjs diff --git a/apps/lsp/src/config.ts b/apps/lsp/src/config.ts index 031e440e..ad065c5e 100644 --- a/apps/lsp/src/config.ts +++ b/apps/lsp/src/config.ts @@ -136,6 +136,7 @@ export class ConfigurationManager extends Disposable { private _settings: Settings; private _logger: ILogger; + private _activeColorThemeKind: "light" | "dark" = "dark"; constructor( private readonly connection_: Connection, @@ -177,6 +178,13 @@ export class ConfigurationManager extends Disposable { } } }; + + // Fallback: try to detect theme from name if we haven't received an explicit notification yet + // This is a best-effort approach for compatibility, but won't work with autoDetectColorScheme + if (settings.workbench.colorTheme.includes("Light")) { + this._activeColorThemeKind = "light"; + } + this._onDidChangeConfiguration.fire(this._settings); } @@ -202,6 +210,15 @@ export class ConfigurationManager extends Disposable { public getSettings(): Settings { return this._settings; } + + public setActiveColorThemeKind(kind: "light" | "dark") { + this._activeColorThemeKind = kind; + this._onDidChangeConfiguration.fire(this._settings); + } + + public getActiveColorThemeKind(): "light" | "dark" { + return this._activeColorThemeKind; + } } export function lsConfiguration(configManager: ConfigurationManager): LsConfiguration { @@ -226,8 +243,7 @@ export function lsConfiguration(configManager: ConfigurationManager): LsConfigur } }, get colorTheme(): "light" | "dark" { - const settings = configManager.getSettings(); - return settings.workbench.colorTheme.includes("Light") ? "light" : "dark"; + return configManager.getActiveColorThemeKind(); }, get mathjaxScale(): number { return configManager.getSettings().quarto.mathjax.scale; diff --git a/apps/lsp/src/index.ts b/apps/lsp/src/index.ts index 0aabee6a..ba406d3e 100644 --- a/apps/lsp/src/index.ts +++ b/apps/lsp/src/index.ts @@ -224,6 +224,12 @@ connection.onInitialized(async () => { logger.setConfigurationManager(configManager); } + // listen for color theme changes from the client + connection.onNotification("quarto/didChangeActiveColorTheme", (params: { kind: "light" | "dark" }) => { + logger.logNotification('didChangeActiveColorTheme'); + configManager.setActiveColorThemeKind(params.kind); + }); + // initialize connection to quarto const workspaceFolders = await connection.workspace.getWorkspaceFolders(); const workspaceDir = workspaceFolders?.length diff --git a/apps/vscode-editor/vite.config.ts.timestamp-1762271143169.mjs b/apps/vscode-editor/vite.config.ts.timestamp-1762271143169.mjs new file mode 100644 index 00000000..3b54a475 --- /dev/null +++ b/apps/vscode-editor/vite.config.ts.timestamp-1762271143169.mjs @@ -0,0 +1,43 @@ +// vite.config.ts +import path from "path"; +import { defineConfig, normalizePath } from "file:///home/runner/work/quarto/quarto/node_modules/vite/dist/node/index.js"; +import { viteStaticCopy } from "file:///home/runner/work/quarto/quarto/node_modules/vite-plugin-static-copy/dist/index.js"; +var __vite_injected_original_dirname = "/home/runner/work/quarto/quarto/apps/vscode-editor"; +var vite_config_default = defineConfig((env) => { + const dev = env.mode === "development"; + return { + define: { + "process.env.DEBUG": '""', + "process.env.NODE_ENV": '"production"', + "process.env.TERM": '""', + "process.platform": '""' + }, + plugins: [ + viteStaticCopy({ + targets: [ + { + src: normalizePath(path.resolve(__vite_injected_original_dirname, "./dist/*")), + dest: normalizePath(path.resolve(__vite_injected_original_dirname, "../vscode/assets/www/editor")) + } + ] + }) + ], + build: { + watch: dev ? {} : null, + lib: { + entry: "src/index.tsx", + formats: ["umd"], + name: "QuartoVisualEditor", + fileName: () => "index.js" + }, + rollupOptions: { + external: ["vscode-webview"] + }, + sourcemap: dev ? "inline" : false + } + }; +}); +export { + vite_config_default as default +}; +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvaG9tZS9ydW5uZXIvd29yay9xdWFydG8vcXVhcnRvL2FwcHMvdnNjb2RlLWVkaXRvclwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL2hvbWUvcnVubmVyL3dvcmsvcXVhcnRvL3F1YXJ0by9hcHBzL3ZzY29kZS1lZGl0b3Ivdml0ZS5jb25maWcudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL2hvbWUvcnVubmVyL3dvcmsvcXVhcnRvL3F1YXJ0by9hcHBzL3ZzY29kZS1lZGl0b3Ivdml0ZS5jb25maWcudHNcIjtpbXBvcnQgcGF0aCBmcm9tICdwYXRoJ1xuaW1wb3J0IHsgZGVmaW5lQ29uZmlnLCBub3JtYWxpemVQYXRoIH0gZnJvbSAndml0ZSdcbmltcG9ydCB7IHZpdGVTdGF0aWNDb3B5IH0gZnJvbSAndml0ZS1wbHVnaW4tc3RhdGljLWNvcHknXG5cblxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKGVudiA9PiB7XG4gIFxuICBjb25zdCBkZXYgPSBlbnYubW9kZSA9PT0gXCJkZXZlbG9wbWVudFwiO1xuXG4gIHJldHVybiB7XG4gICAgZGVmaW5lOiB7XG4gICAgICAncHJvY2Vzcy5lbnYuREVCVUcnOiAnXCJcIicsXG4gICAgICAncHJvY2Vzcy5lbnYuTk9ERV9FTlYnOiAnXCJwcm9kdWN0aW9uXCInLFxuICAgICAgJ3Byb2Nlc3MuZW52LlRFUk0nOiAnXCJcIicsXG4gICAgICAncHJvY2Vzcy5wbGF0Zm9ybSc6ICdcIlwiJ1xuICAgIH0sXG4gICAgcGx1Z2luczogW1xuICAgICAgdml0ZVN0YXRpY0NvcHkoe1xuICAgICAgICB0YXJnZXRzOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgc3JjOiBub3JtYWxpemVQYXRoKHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICcuL2Rpc3QvKicpKSxcbiAgICAgICAgICAgIGRlc3Q6IG5vcm1hbGl6ZVBhdGgocGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJy4uL3ZzY29kZS9hc3NldHMvd3d3L2VkaXRvcicpKVxuICAgICAgICAgIH1cbiAgICAgICAgXVxuICAgICAgfSlcbiAgICBdLFxuICAgIGJ1aWxkOiB7XG4gICAgICB3YXRjaDogZGV2ID8ge30gOiBudWxsLFxuICAgICAgbGliOiB7XG4gICAgICAgIGVudHJ5OiAnc3JjL2luZGV4LnRzeCcsXG4gICAgICAgIGZvcm1hdHM6IFsndW1kJ10sXG4gICAgICAgIG5hbWU6IFwiUXVhcnRvVmlzdWFsRWRpdG9yXCIsXG4gICAgICAgIGZpbGVOYW1lOiAoKSA9PiAnaW5kZXguanMnIFxuICAgICAgfSxcbiAgICAgIHJvbGx1cE9wdGlvbnM6IHtcbiAgICAgICAgZXh0ZXJuYWw6IFsndnNjb2RlLXdlYnZpZXcnXSxcbiAgICAgIH0sXG4gICAgICBzb3VyY2VtYXA6IGRldiA/ICdpbmxpbmUnIDogZmFsc2VcbiAgICB9XG4gIH07XG4gXG59KTtcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBd1UsT0FBTyxVQUFVO0FBQ3pWLFNBQVMsY0FBYyxxQkFBcUI7QUFDNUMsU0FBUyxzQkFBc0I7QUFGL0IsSUFBTSxtQ0FBbUM7QUFLekMsSUFBTyxzQkFBUSxhQUFhLFNBQU87QUFFakMsUUFBTSxNQUFNLElBQUksU0FBUztBQUV6QixTQUFPO0FBQUEsSUFDTCxRQUFRO0FBQUEsTUFDTixxQkFBcUI7QUFBQSxNQUNyQix3QkFBd0I7QUFBQSxNQUN4QixvQkFBb0I7QUFBQSxNQUNwQixvQkFBb0I7QUFBQSxJQUN0QjtBQUFBLElBQ0EsU0FBUztBQUFBLE1BQ1AsZUFBZTtBQUFBLFFBQ2IsU0FBUztBQUFBLFVBQ1A7QUFBQSxZQUNFLEtBQUssY0FBYyxLQUFLLFFBQVEsa0NBQVcsVUFBVSxDQUFDO0FBQUEsWUFDdEQsTUFBTSxjQUFjLEtBQUssUUFBUSxrQ0FBVyw2QkFBNkIsQ0FBQztBQUFBLFVBQzVFO0FBQUEsUUFDRjtBQUFBLE1BQ0YsQ0FBQztBQUFBLElBQ0g7QUFBQSxJQUNBLE9BQU87QUFBQSxNQUNMLE9BQU8sTUFBTSxDQUFDLElBQUk7QUFBQSxNQUNsQixLQUFLO0FBQUEsUUFDSCxPQUFPO0FBQUEsUUFDUCxTQUFTLENBQUMsS0FBSztBQUFBLFFBQ2YsTUFBTTtBQUFBLFFBQ04sVUFBVSxNQUFNO0FBQUEsTUFDbEI7QUFBQSxNQUNBLGVBQWU7QUFBQSxRQUNiLFVBQVUsQ0FBQyxnQkFBZ0I7QUFBQSxNQUM3QjtBQUFBLE1BQ0EsV0FBVyxNQUFNLFdBQVc7QUFBQSxJQUM5QjtBQUFBLEVBQ0Y7QUFFRixDQUFDOyIsCiAgIm5hbWVzIjogW10KfQo= diff --git a/apps/vscode/src/lsp/client.ts b/apps/vscode/src/lsp/client.ts index 07f92e9f..62fbc234 100644 --- a/apps/vscode/src/lsp/client.ts +++ b/apps/vscode/src/lsp/client.ts @@ -24,7 +24,9 @@ import { Definition, LogOutputChannel, Uri, - Diagnostic + Diagnostic, + window, + ColorThemeKind } from "vscode"; import { LanguageClient, @@ -151,12 +153,29 @@ export async function activateLsp( clientOptions ); + // Helper to send current theme to LSP server + const sendThemeNotification = () => { + if (client) { + const kind = window.activeColorTheme.kind === ColorThemeKind.Light ? "light" : "dark"; + client.sendNotification("quarto/didChangeActiveColorTheme", { kind }); + } + }; + + // Listen for theme changes and notify the server + context.subscriptions.push( + window.onDidChangeActiveColorTheme(() => { + sendThemeNotification(); + }) + ); + // return once the server is running return new Promise((resolve, reject) => { const handler = client.onDidChangeState(e => { if (e.newState === State.Running) { handler.dispose(); + // Send initial theme on startup + sendThemeNotification(); resolve(client); } else if (e.newState === State.Stopped) { reject(new Error("Failed to start Quarto LSP Server")); From 2512fd0d4ddce1570700238216e1143af1680cb4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 4 Nov 2025 15:48:31 +0000 Subject: [PATCH 3/9] Remove timestamp file and update .gitignore --- .gitignore | 1 + ...vite.config.ts.timestamp-1762271143169.mjs | 43 ------------------- 2 files changed, 1 insertion(+), 43 deletions(-) delete mode 100644 apps/vscode-editor/vite.config.ts.timestamp-1762271143169.mjs diff --git a/.gitignore b/.gitignore index eb0a1102..d87a955e 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ public/dist /.luarc.json .vscode-test *.vsix +*.timestamp-*.mjs diff --git a/apps/vscode-editor/vite.config.ts.timestamp-1762271143169.mjs b/apps/vscode-editor/vite.config.ts.timestamp-1762271143169.mjs deleted file mode 100644 index 3b54a475..00000000 --- a/apps/vscode-editor/vite.config.ts.timestamp-1762271143169.mjs +++ /dev/null @@ -1,43 +0,0 @@ -// vite.config.ts -import path from "path"; -import { defineConfig, normalizePath } from "file:///home/runner/work/quarto/quarto/node_modules/vite/dist/node/index.js"; -import { viteStaticCopy } from "file:///home/runner/work/quarto/quarto/node_modules/vite-plugin-static-copy/dist/index.js"; -var __vite_injected_original_dirname = "/home/runner/work/quarto/quarto/apps/vscode-editor"; -var vite_config_default = defineConfig((env) => { - const dev = env.mode === "development"; - return { - define: { - "process.env.DEBUG": '""', - "process.env.NODE_ENV": '"production"', - "process.env.TERM": '""', - "process.platform": '""' - }, - plugins: [ - viteStaticCopy({ - targets: [ - { - src: normalizePath(path.resolve(__vite_injected_original_dirname, "./dist/*")), - dest: normalizePath(path.resolve(__vite_injected_original_dirname, "../vscode/assets/www/editor")) - } - ] - }) - ], - build: { - watch: dev ? {} : null, - lib: { - entry: "src/index.tsx", - formats: ["umd"], - name: "QuartoVisualEditor", - fileName: () => "index.js" - }, - rollupOptions: { - external: ["vscode-webview"] - }, - sourcemap: dev ? "inline" : false - } - }; -}); -export { - vite_config_default as default -}; -//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvaG9tZS9ydW5uZXIvd29yay9xdWFydG8vcXVhcnRvL2FwcHMvdnNjb2RlLWVkaXRvclwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL2hvbWUvcnVubmVyL3dvcmsvcXVhcnRvL3F1YXJ0by9hcHBzL3ZzY29kZS1lZGl0b3Ivdml0ZS5jb25maWcudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL2hvbWUvcnVubmVyL3dvcmsvcXVhcnRvL3F1YXJ0by9hcHBzL3ZzY29kZS1lZGl0b3Ivdml0ZS5jb25maWcudHNcIjtpbXBvcnQgcGF0aCBmcm9tICdwYXRoJ1xuaW1wb3J0IHsgZGVmaW5lQ29uZmlnLCBub3JtYWxpemVQYXRoIH0gZnJvbSAndml0ZSdcbmltcG9ydCB7IHZpdGVTdGF0aWNDb3B5IH0gZnJvbSAndml0ZS1wbHVnaW4tc3RhdGljLWNvcHknXG5cblxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKGVudiA9PiB7XG4gIFxuICBjb25zdCBkZXYgPSBlbnYubW9kZSA9PT0gXCJkZXZlbG9wbWVudFwiO1xuXG4gIHJldHVybiB7XG4gICAgZGVmaW5lOiB7XG4gICAgICAncHJvY2Vzcy5lbnYuREVCVUcnOiAnXCJcIicsXG4gICAgICAncHJvY2Vzcy5lbnYuTk9ERV9FTlYnOiAnXCJwcm9kdWN0aW9uXCInLFxuICAgICAgJ3Byb2Nlc3MuZW52LlRFUk0nOiAnXCJcIicsXG4gICAgICAncHJvY2Vzcy5wbGF0Zm9ybSc6ICdcIlwiJ1xuICAgIH0sXG4gICAgcGx1Z2luczogW1xuICAgICAgdml0ZVN0YXRpY0NvcHkoe1xuICAgICAgICB0YXJnZXRzOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgc3JjOiBub3JtYWxpemVQYXRoKHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICcuL2Rpc3QvKicpKSxcbiAgICAgICAgICAgIGRlc3Q6IG5vcm1hbGl6ZVBhdGgocGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJy4uL3ZzY29kZS9hc3NldHMvd3d3L2VkaXRvcicpKVxuICAgICAgICAgIH1cbiAgICAgICAgXVxuICAgICAgfSlcbiAgICBdLFxuICAgIGJ1aWxkOiB7XG4gICAgICB3YXRjaDogZGV2ID8ge30gOiBudWxsLFxuICAgICAgbGliOiB7XG4gICAgICAgIGVudHJ5OiAnc3JjL2luZGV4LnRzeCcsXG4gICAgICAgIGZvcm1hdHM6IFsndW1kJ10sXG4gICAgICAgIG5hbWU6IFwiUXVhcnRvVmlzdWFsRWRpdG9yXCIsXG4gICAgICAgIGZpbGVOYW1lOiAoKSA9PiAnaW5kZXguanMnIFxuICAgICAgfSxcbiAgICAgIHJvbGx1cE9wdGlvbnM6IHtcbiAgICAgICAgZXh0ZXJuYWw6IFsndnNjb2RlLXdlYnZpZXcnXSxcbiAgICAgIH0sXG4gICAgICBzb3VyY2VtYXA6IGRldiA/ICdpbmxpbmUnIDogZmFsc2VcbiAgICB9XG4gIH07XG4gXG59KTtcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBd1UsT0FBTyxVQUFVO0FBQ3pWLFNBQVMsY0FBYyxxQkFBcUI7QUFDNUMsU0FBUyxzQkFBc0I7QUFGL0IsSUFBTSxtQ0FBbUM7QUFLekMsSUFBTyxzQkFBUSxhQUFhLFNBQU87QUFFakMsUUFBTSxNQUFNLElBQUksU0FBUztBQUV6QixTQUFPO0FBQUEsSUFDTCxRQUFRO0FBQUEsTUFDTixxQkFBcUI7QUFBQSxNQUNyQix3QkFBd0I7QUFBQSxNQUN4QixvQkFBb0I7QUFBQSxNQUNwQixvQkFBb0I7QUFBQSxJQUN0QjtBQUFBLElBQ0EsU0FBUztBQUFBLE1BQ1AsZUFBZTtBQUFBLFFBQ2IsU0FBUztBQUFBLFVBQ1A7QUFBQSxZQUNFLEtBQUssY0FBYyxLQUFLLFFBQVEsa0NBQVcsVUFBVSxDQUFDO0FBQUEsWUFDdEQsTUFBTSxjQUFjLEtBQUssUUFBUSxrQ0FBVyw2QkFBNkIsQ0FBQztBQUFBLFVBQzVFO0FBQUEsUUFDRjtBQUFBLE1BQ0YsQ0FBQztBQUFBLElBQ0g7QUFBQSxJQUNBLE9BQU87QUFBQSxNQUNMLE9BQU8sTUFBTSxDQUFDLElBQUk7QUFBQSxNQUNsQixLQUFLO0FBQUEsUUFDSCxPQUFPO0FBQUEsUUFDUCxTQUFTLENBQUMsS0FBSztBQUFBLFFBQ2YsTUFBTTtBQUFBLFFBQ04sVUFBVSxNQUFNO0FBQUEsTUFDbEI7QUFBQSxNQUNBLGVBQWU7QUFBQSxRQUNiLFVBQVUsQ0FBQyxnQkFBZ0I7QUFBQSxNQUM3QjtBQUFBLE1BQ0EsV0FBVyxNQUFNLFdBQVc7QUFBQSxJQUM5QjtBQUFBLEVBQ0Y7QUFFRixDQUFDOyIsCiAgIm5hbWVzIjogW10KfQo= From cba7695e4b579ece9e97e55e1fd882f400fa8f38 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 4 Nov 2025 15:51:37 +0000 Subject: [PATCH 4/9] Address code review feedback - Add explicit check for 'Dark' in theme name fallback - Only fire configuration change event if theme actually changed Co-authored-by: kv9898 <105025148+kv9898@users.noreply.github.com> --- apps/lsp/src/config.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/lsp/src/config.ts b/apps/lsp/src/config.ts index ad065c5e..b0a6e1af 100644 --- a/apps/lsp/src/config.ts +++ b/apps/lsp/src/config.ts @@ -181,8 +181,11 @@ export class ConfigurationManager extends Disposable { // Fallback: try to detect theme from name if we haven't received an explicit notification yet // This is a best-effort approach for compatibility, but won't work with autoDetectColorScheme + // Default to dark theme if neither Light nor Dark is in the theme name if (settings.workbench.colorTheme.includes("Light")) { this._activeColorThemeKind = "light"; + } else if (settings.workbench.colorTheme.includes("Dark")) { + this._activeColorThemeKind = "dark"; } this._onDidChangeConfiguration.fire(this._settings); @@ -212,8 +215,10 @@ export class ConfigurationManager extends Disposable { } public setActiveColorThemeKind(kind: "light" | "dark") { - this._activeColorThemeKind = kind; - this._onDidChangeConfiguration.fire(this._settings); + if (this._activeColorThemeKind !== kind) { + this._activeColorThemeKind = kind; + this._onDidChangeConfiguration.fire(this._settings); + } } public getActiveColorThemeKind(): "light" | "dark" { From 2f7d83b8c18d8f288eea3a79db6d50c93abdc8a4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 4 Nov 2025 16:01:23 +0000 Subject: [PATCH 5/9] Address additional code review feedback - Add validation for theme kind parameter in notification handler - Document HighContrast theme handling (treated as dark) - Prevent fallback detection from overriding explicit theme notifications - Add flag to track whether theme was explicitly set Co-authored-by: kv9898 <105025148+kv9898@users.noreply.github.com> --- apps/lsp/src/config.ts | 14 +++++++++----- apps/lsp/src/index.ts | 9 +++++++-- apps/vscode/src/lsp/client.ts | 2 ++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/apps/lsp/src/config.ts b/apps/lsp/src/config.ts index b0a6e1af..1bae2f24 100644 --- a/apps/lsp/src/config.ts +++ b/apps/lsp/src/config.ts @@ -137,6 +137,7 @@ export class ConfigurationManager extends Disposable { private _settings: Settings; private _logger: ILogger; private _activeColorThemeKind: "light" | "dark" = "dark"; + private _themeExplicitlySet = false; constructor( private readonly connection_: Connection, @@ -181,11 +182,13 @@ export class ConfigurationManager extends Disposable { // Fallback: try to detect theme from name if we haven't received an explicit notification yet // This is a best-effort approach for compatibility, but won't work with autoDetectColorScheme - // Default to dark theme if neither Light nor Dark is in the theme name - if (settings.workbench.colorTheme.includes("Light")) { - this._activeColorThemeKind = "light"; - } else if (settings.workbench.colorTheme.includes("Dark")) { - this._activeColorThemeKind = "dark"; + // Only apply fallback if theme hasn't been explicitly set via notification + if (!this._themeExplicitlySet) { + if (settings.workbench.colorTheme.includes("Light")) { + this._activeColorThemeKind = "light"; + } else if (settings.workbench.colorTheme.includes("Dark")) { + this._activeColorThemeKind = "dark"; + } } this._onDidChangeConfiguration.fire(this._settings); @@ -217,6 +220,7 @@ export class ConfigurationManager extends Disposable { public setActiveColorThemeKind(kind: "light" | "dark") { if (this._activeColorThemeKind !== kind) { this._activeColorThemeKind = kind; + this._themeExplicitlySet = true; this._onDidChangeConfiguration.fire(this._settings); } } diff --git a/apps/lsp/src/index.ts b/apps/lsp/src/index.ts index ba406d3e..bd3b243d 100644 --- a/apps/lsp/src/index.ts +++ b/apps/lsp/src/index.ts @@ -225,9 +225,14 @@ connection.onInitialized(async () => { } // listen for color theme changes from the client - connection.onNotification("quarto/didChangeActiveColorTheme", (params: { kind: "light" | "dark" }) => { + connection.onNotification("quarto/didChangeActiveColorTheme", (params: { kind: string }) => { logger.logNotification('didChangeActiveColorTheme'); - configManager.setActiveColorThemeKind(params.kind); + // Validate the theme kind before using it + if (params.kind === "light" || params.kind === "dark") { + configManager.setActiveColorThemeKind(params.kind); + } else { + logger.logError(`Invalid theme kind received: ${params.kind}`); + } }); // initialize connection to quarto diff --git a/apps/vscode/src/lsp/client.ts b/apps/vscode/src/lsp/client.ts index 62fbc234..054ca9be 100644 --- a/apps/vscode/src/lsp/client.ts +++ b/apps/vscode/src/lsp/client.ts @@ -156,6 +156,8 @@ export async function activateLsp( // Helper to send current theme to LSP server const sendThemeNotification = () => { if (client) { + // Map VS Code theme kinds to light/dark. HighContrast themes are treated as dark + // since they typically have light text on dark backgrounds const kind = window.activeColorTheme.kind === ColorThemeKind.Light ? "light" : "dark"; client.sendNotification("quarto/didChangeActiveColorTheme", { kind }); } From 4f1bb7494131b281a5076baa98d57b720b1a079f Mon Sep 17 00:00:00 2001 From: Dianyi Yang Date: Tue, 4 Nov 2025 16:14:37 +0000 Subject: [PATCH 6/9] Consider high contrast light --- apps/vscode/src/lsp/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/vscode/src/lsp/client.ts b/apps/vscode/src/lsp/client.ts index 054ca9be..d6c69343 100644 --- a/apps/vscode/src/lsp/client.ts +++ b/apps/vscode/src/lsp/client.ts @@ -158,7 +158,7 @@ export async function activateLsp( if (client) { // Map VS Code theme kinds to light/dark. HighContrast themes are treated as dark // since they typically have light text on dark backgrounds - const kind = window.activeColorTheme.kind === ColorThemeKind.Light ? "light" : "dark"; + const kind = (window.activeColorTheme.kind === ColorThemeKind.Light || window.activeColorTheme.kind === ColorThemeKind.HighContrastLight) ? "light" : "dark"; client.sendNotification("quarto/didChangeActiveColorTheme", { kind }); } }; From bc7fa19a2d4d33274e21b4ba6d2c0959565ce949 Mon Sep 17 00:00:00 2001 From: Dianyi Yang Date: Wed, 5 Nov 2025 20:28:01 +0000 Subject: [PATCH 7/9] Add small timeout --- apps/lsp/src/index.ts | 2 +- apps/vscode/src/lsp/client.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/lsp/src/index.ts b/apps/lsp/src/index.ts index bd3b243d..2b0b356e 100644 --- a/apps/lsp/src/index.ts +++ b/apps/lsp/src/index.ts @@ -225,7 +225,7 @@ connection.onInitialized(async () => { } // listen for color theme changes from the client - connection.onNotification("quarto/didChangeActiveColorTheme", (params: { kind: string }) => { + connection.onNotification("quarto/didChangeActiveColorTheme", (params: { kind: string; }) => { logger.logNotification('didChangeActiveColorTheme'); // Validate the theme kind before using it if (params.kind === "light" || params.kind === "dark") { diff --git a/apps/vscode/src/lsp/client.ts b/apps/vscode/src/lsp/client.ts index d6c69343..a8fa79f1 100644 --- a/apps/vscode/src/lsp/client.ts +++ b/apps/vscode/src/lsp/client.ts @@ -177,7 +177,9 @@ export async function activateLsp( if (e.newState === State.Running) { handler.dispose(); // Send initial theme on startup - sendThemeNotification(); + setTimeout(() => { + sendThemeNotification(); + }, 50); resolve(client); } else if (e.newState === State.Stopped) { reject(new Error("Failed to start Quarto LSP Server")); From 9ef0d32ed87193dd750f139f48fe9a42b3c29b9b Mon Sep 17 00:00:00 2001 From: Dianyi Yang Date: Wed, 5 Nov 2025 20:28:11 +0000 Subject: [PATCH 8/9] Add explanation --- apps/vscode/src/lsp/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/vscode/src/lsp/client.ts b/apps/vscode/src/lsp/client.ts index a8fa79f1..d6bd111f 100644 --- a/apps/vscode/src/lsp/client.ts +++ b/apps/vscode/src/lsp/client.ts @@ -176,7 +176,7 @@ export async function activateLsp( const handler = client.onDidChangeState(e => { if (e.newState === State.Running) { handler.dispose(); - // Send initial theme on startup + // Send initial theme on startup, slightly delayed to ensure server is ready setTimeout(() => { sendThemeNotification(); }, 50); From 42feabaf457543f0c7afc855ac6be3d9ef776e14 Mon Sep 17 00:00:00 2001 From: Dianyi Yang Date: Thu, 6 Nov 2025 17:05:57 +0000 Subject: [PATCH 9/9] Increase timeout for 100ms --- apps/vscode/src/lsp/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/vscode/src/lsp/client.ts b/apps/vscode/src/lsp/client.ts index d6bd111f..ed61500b 100644 --- a/apps/vscode/src/lsp/client.ts +++ b/apps/vscode/src/lsp/client.ts @@ -179,7 +179,7 @@ export async function activateLsp( // Send initial theme on startup, slightly delayed to ensure server is ready setTimeout(() => { sendThemeNotification(); - }, 50); + }, 100); resolve(client); } else if (e.newState === State.Stopped) { reject(new Error("Failed to start Quarto LSP Server"));