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/lsp/src/config.ts b/apps/lsp/src/config.ts index 031e440e..1bae2f24 100644 --- a/apps/lsp/src/config.ts +++ b/apps/lsp/src/config.ts @@ -136,6 +136,8 @@ export class ConfigurationManager extends Disposable { private _settings: Settings; private _logger: ILogger; + private _activeColorThemeKind: "light" | "dark" = "dark"; + private _themeExplicitlySet = false; constructor( private readonly connection_: Connection, @@ -177,6 +179,18 @@ 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 + // 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); } @@ -202,6 +216,18 @@ export class ConfigurationManager extends Disposable { public getSettings(): Settings { return this._settings; } + + public setActiveColorThemeKind(kind: "light" | "dark") { + if (this._activeColorThemeKind !== kind) { + this._activeColorThemeKind = kind; + this._themeExplicitlySet = true; + this._onDidChangeConfiguration.fire(this._settings); + } + } + + public getActiveColorThemeKind(): "light" | "dark" { + return this._activeColorThemeKind; + } } export function lsConfiguration(configManager: ConfigurationManager): LsConfiguration { @@ -226,8 +252,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..2b0b356e 100644 --- a/apps/lsp/src/index.ts +++ b/apps/lsp/src/index.ts @@ -224,6 +224,17 @@ connection.onInitialized(async () => { logger.setConfigurationManager(configManager); } + // listen for color theme changes from the client + connection.onNotification("quarto/didChangeActiveColorTheme", (params: { kind: string; }) => { + logger.logNotification('didChangeActiveColorTheme'); + // 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 const workspaceFolders = await connection.workspace.getWorkspaceFolders(); const workspaceDir = workspaceFolders?.length diff --git a/apps/vscode/src/lsp/client.ts b/apps/vscode/src/lsp/client.ts index 07f92e9f..ed61500b 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,33 @@ export async function activateLsp( clientOptions ); + // 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 || window.activeColorTheme.kind === ColorThemeKind.HighContrastLight) ? "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, slightly delayed to ensure server is ready + setTimeout(() => { + sendThemeNotification(); + }, 100); resolve(client); } else if (e.newState === State.Stopped) { reject(new Error("Failed to start Quarto LSP Server"));