import * as vscode from 'vscode'; import { log } from "./util"; export type UpdatesChannel = "stable" | "nightly"; export const NIGHTLY_TAG = "nightly"; export class Config { readonly extensionId = "matklad.rust-analyzer"; private readonly rootSection = "rust-analyzer"; private readonly requiresReloadOpts = [ "serverPath", "cargoFeatures", "excludeGlobs", "useClientWatching", "highlighting", "updates.channel", ] .map(opt => `${this.rootSection}.${opt}`); readonly package: { version: string; releaseTag: string | null; enableProposedApi: boolean | undefined; } = vscode.extensions.getExtension(this.extensionId)!.packageJSON; readonly globalStoragePath: string; constructor(ctx: vscode.ExtensionContext) { this.globalStoragePath = ctx.globalStoragePath; vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, ctx.subscriptions); this.refreshLogging(); } private refreshLogging() { log.setEnabled(this.traceExtension); log.debug( "Extension version:", this.package.version, "using configuration:", this.cfg ); } private async onDidChangeConfiguration(event: vscode.ConfigurationChangeEvent) { this.refreshLogging(); const requiresReloadOpt = this.requiresReloadOpts.find( opt => event.affectsConfiguration(opt) ); if (!requiresReloadOpt) return; const userResponse = await vscode.window.showInformationMessage( `Changing "${requiresReloadOpt}" requires a reload`, "Reload now" ); if (userResponse === "Reload now") { await vscode.commands.executeCommand("workbench.action.reloadWindow"); } } // We don't do runtime config validation here for simplicity. More on stackoverflow: // https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension private get cfg(): vscode.WorkspaceConfiguration { return vscode.workspace.getConfiguration(this.rootSection); } get serverPath() { return this.cfg.get("serverPath")!; } get channel() { return this.cfg.get("updates.channel")!; } get askBeforeDownload() { return this.cfg.get("updates.askBeforeDownload")!; } get highlightingSemanticTokens() { return this.cfg.get("highlighting.semanticTokens")!; } get lruCapacity() { return this.cfg.get("lruCapacity")!; } get excludeGlobs() { return this.cfg.get("excludeGlobs")!; } get useClientWatching() { return this.cfg.get("useClientWatching")!; } get featureFlags() { return this.cfg.get>("featureFlags")!; } get rustfmtArgs() { return this.cfg.get("rustfmtArgs")!; } get loadOutDirsFromCheck() { return this.cfg.get("loadOutDirsFromCheck")!; } get traceExtension() { return this.cfg.get("trace.extension")!; } // for internal use get withSysroot() { return this.cfg.get("withSysroot", true)!; } get inlayHints() { return { typeHints: this.cfg.get("inlayHints.typeHints")!, parameterHints: this.cfg.get("inlayHints.parameterHints")!, chainingHints: this.cfg.get("inlayHints.chainingHints")!, maxLength: this.cfg.get("inlayHints.maxLength")!, }; } get cargoWatchOptions() { return { enable: this.cfg.get("cargo-watch.enable")!, arguments: this.cfg.get("cargo-watch.arguments")!, allTargets: this.cfg.get("cargo-watch.allTargets")!, command: this.cfg.get("cargo-watch.command")!, }; } get cargoFeatures() { return { noDefaultFeatures: this.cfg.get("cargoFeatures.noDefaultFeatures")!, allFeatures: this.cfg.get("cargoFeatures.allFeatures")!, features: this.cfg.get("cargoFeatures.features")!, loadOutDirsFromCheck: this.cfg.get("cargoFeatures.loadOutDirsFromCheck")!, }; } }