From 9b47124e6e5d32a676961c05661934215e98012c Mon Sep 17 00:00:00 2001 From: Veetaha Date: Thu, 13 Feb 2020 22:47:31 +0200 Subject: vscode: added more type safety to package.json config --- editors/code/package.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/editors/code/package.json b/editors/code/package.json index f687eb8d4..12d32cef7 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -181,6 +181,9 @@ }, "rust-analyzer.excludeGlobs": { "type": "array", + "items": { + "type": "string" + }, "default": [], "description": "Paths to exclude from analysis" }, @@ -196,6 +199,9 @@ }, "rust-analyzer.cargo-watch.arguments": { "type": "array", + "items": { + "type": "string" + }, "description": "`cargo-watch` arguments. (e.g: `--features=\"shumway,pdf\"` will run as `cargo watch -x \"check --features=\"shumway,pdf\"\"` )", "default": [] }, @@ -241,6 +247,7 @@ "rust-analyzer.maxInlayHintLength": { "type": "number", "default": 20, + "exclusiveMinimum": 0, "description": "Maximum length for inlay hints" }, "rust-analyzer.cargoFeatures.noDefaultFeatures": { @@ -255,6 +262,9 @@ }, "rust-analyzer.cargoFeatures.features": { "type": "array", + "items": { + "type": "string" + }, "default": [], "description": "List of features to activate" } -- cgit v1.2.3 From 7ad15c396286376c4a439b2dec4ec452b5f28dda Mon Sep 17 00:00:00 2001 From: Veetaha Date: Thu, 13 Feb 2020 22:48:20 +0200 Subject: vscode: redesigned config with simplicity and Dart extension config implementation in mind --- editors/code/src/client.ts | 36 +++--- editors/code/src/config.ts | 258 ++++++++++--------------------------- editors/code/src/highlighting.ts | 6 +- editors/code/src/inlay_hints.ts | 6 +- editors/code/src/status_display.ts | 6 +- 5 files changed, 96 insertions(+), 216 deletions(-) diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 2e3d4aba2..a6fb04536 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -1,6 +1,6 @@ import * as lc from 'vscode-languageclient'; +import * as vscode from 'vscode'; -import { window, workspace } from 'vscode'; import { Config } from './config'; import { ensureLanguageServerBinary } from './installation/language_server'; @@ -8,37 +8,39 @@ export async function createClient(config: Config): Promise `${Config.rootSection}.${opt}`); + + private cfg!: vscode.WorkspaceConfiguration; + + private refreshConfig() { + this.cfg = vscode.workspace.getConfiguration(Config.rootSection); + console.log("Using configuration:", this.cfg); + } - highlightingOn = true; - rainbowHighlightingOn = false; - enableEnhancedTyping = true; - lruCapacity: null | number = null; - displayInlayHints = true; - maxInlayHintLength: null | number = null; - excludeGlobs: string[] = []; - useClientWatching = true; - featureFlags: Record = {}; - // for internal use - withSysroot: null | boolean = null; - cargoWatchOptions: CargoWatchOptions = { - enable: true, - arguments: [], - command: '', - allTargets: true, - }; - cargoFeatures: CargoFeatures = { - noDefaultFeatures: false, - allFeatures: true, - features: [], - }; + constructor(private ctx: vscode.ExtensionContext) { + vscode.workspace.onDidChangeConfiguration(this.onConfigChange, this, ctx.subscriptions); + this.refreshConfig(); + } + + async onConfigChange(event: vscode.ConfigurationChangeEvent) { + this.refreshConfig(); + + const requiresReloadOpt = Config.requiresReloadOpts.find( + opt => event.affectsConfiguration(opt) + ); - private prevEnhancedTyping: null | boolean = null; - private prevCargoFeatures: null | CargoFeatures = null; - private prevCargoWatchOptions: null | CargoWatchOptions = null; + if (!requiresReloadOpt) return; - constructor(ctx: vscode.ExtensionContext) { - vscode.workspace.onDidChangeConfiguration(_ => this.refresh(ctx), null, ctx.subscriptions); - this.refresh(ctx); + const userResponse = await vscode.window.showInformationMessage( + `Changing "${requiresReloadOpt}" requires a reload`, + "Reload now" + ); + + if (userResponse === "Reload now") { + vscode.commands.executeCommand("workbench.action.reloadWindow"); + } } - private static expandPathResolving(path: string) { - if (path.startsWith('~/')) { - return path.replace('~', os.homedir()); + private static replaceTildeWithHomeDir(path: string) { + if (path.startsWith("~/")) { + return os.homedir() + path.slice("~".length); } return path; } @@ -97,16 +100,13 @@ export class Config { } } - private static langServerBinarySource( - ctx: vscode.ExtensionContext, - config: vscode.WorkspaceConfiguration - ): null | BinarySource { - const langServerPath = RA_LSP_DEBUG ?? config.get("raLspServerPath"); + langServerBinarySource(): null | BinarySource { + const langServerPath = RA_LSP_DEBUG ?? this.cfg.get("raLspServerPath"); if (langServerPath) { return { type: BinarySource.Type.ExplicitPath, - path: Config.expandPathResolving(langServerPath) + path: Config.replaceTildeWithHomeDir(langServerPath) }; } @@ -118,7 +118,7 @@ export class Config { return { type: BinarySource.Type.GithubRelease, - dir: ctx.globalStoragePath, + dir: this.ctx.globalStoragePath, file: prebuiltBinaryName, repo: { name: "rust-analyzer", @@ -127,158 +127,36 @@ export class Config { }; } + // 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 - // FIXME: revisit the logic for `if (.has(...)) config.get(...)` set default - // values only in one place (i.e. remove default values from non-readonly members declarations) - private refresh(ctx: vscode.ExtensionContext) { - const config = vscode.workspace.getConfiguration('rust-analyzer'); - - let requireReloadMessage = null; - - if (config.has('highlightingOn')) { - this.highlightingOn = config.get('highlightingOn') as boolean; - } - - if (config.has('rainbowHighlightingOn')) { - this.rainbowHighlightingOn = config.get( - 'rainbowHighlightingOn', - ) as boolean; - } - - if (config.has('enableEnhancedTyping')) { - this.enableEnhancedTyping = config.get( - 'enableEnhancedTyping', - ) as boolean; - - if (this.prevEnhancedTyping === null) { - this.prevEnhancedTyping = this.enableEnhancedTyping; - } - } else if (this.prevEnhancedTyping === null) { - this.prevEnhancedTyping = this.enableEnhancedTyping; - } - - if (this.prevEnhancedTyping !== this.enableEnhancedTyping) { - requireReloadMessage = - 'Changing enhanced typing setting requires a reload'; - this.prevEnhancedTyping = this.enableEnhancedTyping; - } - - this.langServerSource = Config.langServerBinarySource(ctx, config); - - if (config.has('cargo-watch.enable')) { - this.cargoWatchOptions.enable = config.get( - 'cargo-watch.enable', - true, - ); - } - - if (config.has('cargo-watch.arguments')) { - this.cargoWatchOptions.arguments = config.get( - 'cargo-watch.arguments', - [], - ); - } - - if (config.has('cargo-watch.command')) { - this.cargoWatchOptions.command = config.get( - 'cargo-watch.command', - '', - ); - } + // FIXME: add codegen for primitive configurations + highlightingOn() { return this.cfg.get("highlightingOn") as boolean; } + rainbowHighlightingOn() { return this.cfg.get("rainbowHighlightingOn") as boolean; } + lruCapacity() { return this.cfg.get("lruCapacity") as null | number; } + displayInlayHints() { return this.cfg.get("displayInlayHints") as boolean; } + maxInlayHintLength() { return this.cfg.get("maxInlayHintLength") as number; } + excludeGlobs() { return this.cfg.get("excludeGlobs") as string[]; } + useClientWatching() { return this.cfg.get("useClientWatching") as boolean; } + featureFlags() { return this.cfg.get("featureFlags") as Record; } - if (config.has('cargo-watch.allTargets')) { - this.cargoWatchOptions.allTargets = config.get( - 'cargo-watch.allTargets', - true, - ); - } - - if (config.has('lruCapacity')) { - this.lruCapacity = config.get('lruCapacity') as number; - } - - if (config.has('displayInlayHints')) { - this.displayInlayHints = config.get('displayInlayHints') as boolean; - } - if (config.has('maxInlayHintLength')) { - this.maxInlayHintLength = config.get( - 'maxInlayHintLength', - ) as number; - } - if (config.has('excludeGlobs')) { - this.excludeGlobs = config.get('excludeGlobs') || []; - } - if (config.has('useClientWatching')) { - this.useClientWatching = config.get('useClientWatching') || true; - } - if (config.has('featureFlags')) { - this.featureFlags = config.get('featureFlags') || {}; - } - if (config.has('withSysroot')) { - this.withSysroot = config.get('withSysroot') || false; - } - - if (config.has('cargoFeatures.noDefaultFeatures')) { - this.cargoFeatures.noDefaultFeatures = config.get( - 'cargoFeatures.noDefaultFeatures', - false, - ); - } - if (config.has('cargoFeatures.allFeatures')) { - this.cargoFeatures.allFeatures = config.get( - 'cargoFeatures.allFeatures', - true, - ); - } - if (config.has('cargoFeatures.features')) { - this.cargoFeatures.features = config.get( - 'cargoFeatures.features', - [], - ); - } - - if ( - this.prevCargoFeatures !== null && - (this.cargoFeatures.allFeatures !== - this.prevCargoFeatures.allFeatures || - this.cargoFeatures.noDefaultFeatures !== - this.prevCargoFeatures.noDefaultFeatures || - this.cargoFeatures.features.length !== - this.prevCargoFeatures.features.length || - this.cargoFeatures.features.some( - (v, i) => v !== this.prevCargoFeatures!.features[i], - )) - ) { - requireReloadMessage = 'Changing cargo features requires a reload'; - } - this.prevCargoFeatures = { ...this.cargoFeatures }; - - if (this.prevCargoWatchOptions !== null) { - const changed = - this.cargoWatchOptions.enable !== this.prevCargoWatchOptions.enable || - this.cargoWatchOptions.command !== this.prevCargoWatchOptions.command || - this.cargoWatchOptions.allTargets !== this.prevCargoWatchOptions.allTargets || - this.cargoWatchOptions.arguments.length !== this.prevCargoWatchOptions.arguments.length || - this.cargoWatchOptions.arguments.some( - (v, i) => v !== this.prevCargoWatchOptions!.arguments[i], - ); - if (changed) { - requireReloadMessage = 'Changing cargo-watch options requires a reload'; - } - } - this.prevCargoWatchOptions = { ...this.cargoWatchOptions }; + cargoWatchOptions(): CargoWatchOptions { + return { + enable: this.cfg.get("cargo-watch.enable") as boolean, + arguments: this.cfg.get("cargo-watch.arguments") as string[], + allTargets: this.cfg.get("cargo-watch.allTargets") as boolean, + command: this.cfg.get("cargo-watch.command") as string, + }; + } - if (requireReloadMessage !== null) { - const reloadAction = 'Reload now'; - vscode.window - .showInformationMessage(requireReloadMessage, reloadAction) - .then(selectedAction => { - if (selectedAction === reloadAction) { - vscode.commands.executeCommand( - 'workbench.action.reloadWindow', - ); - } - }); - } + cargoFeatures(): CargoFeatures { + return { + noDefaultFeatures: this.cfg.get("cargoFeatures.noDefaultFeatures") as boolean, + allFeatures: this.cfg.get("cargoFeatures.allFeatures") as boolean, + features: this.cfg.get("cargoFeatures.features") as string[], + }; } + + // for internal use + withSysroot() { return this.cfg.get("withSysroot", false); } } diff --git a/editors/code/src/highlighting.ts b/editors/code/src/highlighting.ts index 4fbbe3ddc..e2ae31d29 100644 --- a/editors/code/src/highlighting.ts +++ b/editors/code/src/highlighting.ts @@ -11,7 +11,7 @@ export function activateHighlighting(ctx: Ctx) { client.onNotification( 'rust-analyzer/publishDecorations', (params: PublishDecorationsParams) => { - if (!ctx.config.highlightingOn) return; + if (!ctx.config.highlightingOn()) return; const targetEditor = vscode.window.visibleTextEditors.find( editor => { @@ -39,7 +39,7 @@ export function activateHighlighting(ctx: Ctx) { vscode.window.onDidChangeActiveTextEditor( async (editor: vscode.TextEditor | undefined) => { if (!editor || editor.document.languageId !== 'rust') return; - if (!ctx.config.highlightingOn) return; + if (!ctx.config.highlightingOn()) return; const client = ctx.client; if (!client) return; @@ -122,7 +122,7 @@ class Highlighter { string, [vscode.Range[], boolean] > = new Map(); - const rainbowTime = this.ctx.config.rainbowHighlightingOn; + const rainbowTime = this.ctx.config.rainbowHighlightingOn(); for (const tag of this.decorations.keys()) { byTag.set(tag, []); diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts index 1c019a51b..3ff45a625 100644 --- a/editors/code/src/inlay_hints.ts +++ b/editors/code/src/inlay_hints.ts @@ -22,12 +22,12 @@ export function activateInlayHints(ctx: Ctx) { ); vscode.workspace.onDidChangeConfiguration( - async _ => hintsUpdater.setEnabled(ctx.config.displayInlayHints), + async _ => hintsUpdater.setEnabled(ctx.config.displayInlayHints()), null, ctx.subscriptions ); - ctx.onDidRestart(_ => hintsUpdater.setEnabled(ctx.config.displayInlayHints)); + ctx.onDidRestart(_ => hintsUpdater.setEnabled(ctx.config.displayInlayHints())); } interface InlayHintsParams { @@ -59,7 +59,7 @@ class HintsUpdater { constructor(ctx: Ctx) { this.ctx = ctx; - this.enabled = ctx.config.displayInlayHints; + this.enabled = ctx.config.displayInlayHints(); } async setEnabled(enabled: boolean) { diff --git a/editors/code/src/status_display.ts b/editors/code/src/status_display.ts index 51dbf388b..ae9a7b1b5 100644 --- a/editors/code/src/status_display.ts +++ b/editors/code/src/status_display.ts @@ -7,7 +7,7 @@ import { Ctx } from './ctx'; const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; export function activateStatusDisplay(ctx: Ctx) { - const statusDisplay = new StatusDisplay(ctx.config.cargoWatchOptions.command); + const statusDisplay = new StatusDisplay(ctx.config.cargoWatchOptions().command); ctx.pushCleanup(statusDisplay); ctx.onDidRestart(client => ctx.pushCleanup(client.onProgress( WorkDoneProgress.type, @@ -66,9 +66,9 @@ class StatusDisplay implements Disposable { refreshLabel() { if (this.packageName) { - this.statusBarItem!.text = `${spinnerFrames[this.i]} cargo ${this.command} [${this.packageName}]`; + this.statusBarItem.text = `${spinnerFrames[this.i]} cargo ${this.command} [${this.packageName}]`; } else { - this.statusBarItem!.text = `${spinnerFrames[this.i]} cargo ${this.command}`; + this.statusBarItem.text = `${spinnerFrames[this.i]} cargo ${this.command}`; } } -- cgit v1.2.3 From fd37151ade9948398e863c38418fb4f0d0acdfa7 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Thu, 13 Feb 2020 23:05:32 +0200 Subject: vscode: reordered config constructor before methods --- editors/code/src/config.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 6c4742464..349f80278 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -26,16 +26,17 @@ export class Config { private cfg!: vscode.WorkspaceConfiguration; + constructor(private readonly ctx: vscode.ExtensionContext) { + vscode.workspace.onDidChangeConfiguration(this.onConfigChange, this, ctx.subscriptions); + this.refreshConfig(); + } + + private refreshConfig() { this.cfg = vscode.workspace.getConfiguration(Config.rootSection); console.log("Using configuration:", this.cfg); } - constructor(private ctx: vscode.ExtensionContext) { - vscode.workspace.onDidChangeConfiguration(this.onConfigChange, this, ctx.subscriptions); - this.refreshConfig(); - } - async onConfigChange(event: vscode.ConfigurationChangeEvent) { this.refreshConfig(); -- cgit v1.2.3 From 4fb427743c27c63a4aa3ccd54c488b22d4308bc2 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Fri, 14 Feb 2020 23:04:50 +0200 Subject: vscode: moved to getters as per matklad --- editors/code/src/client.ts | 18 ++++++++--------- editors/code/src/config.ts | 40 ++++++++++++++++---------------------- editors/code/src/highlighting.ts | 6 +++--- editors/code/src/inlay_hints.ts | 6 +++--- editors/code/src/status_display.ts | 2 +- 5 files changed, 33 insertions(+), 39 deletions(-) diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index a6fb04536..4484b2167 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -10,7 +10,7 @@ export async function createClient(config: Config): Promise("raLspServerPath"); if (langServerPath) { @@ -111,9 +108,7 @@ export class Config { }; } - const prebuiltBinaryName = Config.prebuiltLangServerFileName( - process.platform, process.arch - ); + const prebuiltBinaryName = this.prebuiltLangServerFileName; if (!prebuiltBinaryName) return null; @@ -131,17 +126,16 @@ export class Config { // 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 - // FIXME: add codegen for primitive configurations - highlightingOn() { return this.cfg.get("highlightingOn") as boolean; } - rainbowHighlightingOn() { return this.cfg.get("rainbowHighlightingOn") as boolean; } - lruCapacity() { return this.cfg.get("lruCapacity") as null | number; } - displayInlayHints() { return this.cfg.get("displayInlayHints") as boolean; } - maxInlayHintLength() { return this.cfg.get("maxInlayHintLength") as number; } - excludeGlobs() { return this.cfg.get("excludeGlobs") as string[]; } - useClientWatching() { return this.cfg.get("useClientWatching") as boolean; } - featureFlags() { return this.cfg.get("featureFlags") as Record; } - - cargoWatchOptions(): CargoWatchOptions { + get highlightingOn() { return this.cfg.get("highlightingOn") as boolean; } + get rainbowHighlightingOn() { return this.cfg.get("rainbowHighlightingOn") as boolean; } + get lruCapacity() { return this.cfg.get("lruCapacity") as null | number; } + get displayInlayHints() { return this.cfg.get("displayInlayHints") as boolean; } + get maxInlayHintLength() { return this.cfg.get("maxInlayHintLength") as number; } + get excludeGlobs() { return this.cfg.get("excludeGlobs") as string[]; } + get useClientWatching() { return this.cfg.get("useClientWatching") as boolean; } + get featureFlags() { return this.cfg.get("featureFlags") as Record; } + + get cargoWatchOptions(): CargoWatchOptions { return { enable: this.cfg.get("cargo-watch.enable") as boolean, arguments: this.cfg.get("cargo-watch.arguments") as string[], @@ -150,7 +144,7 @@ export class Config { }; } - cargoFeatures(): CargoFeatures { + get cargoFeatures(): CargoFeatures { return { noDefaultFeatures: this.cfg.get("cargoFeatures.noDefaultFeatures") as boolean, allFeatures: this.cfg.get("cargoFeatures.allFeatures") as boolean, @@ -159,5 +153,5 @@ export class Config { } // for internal use - withSysroot() { return this.cfg.get("withSysroot", false); } + get withSysroot() { return this.cfg.get("withSysroot", false); } } diff --git a/editors/code/src/highlighting.ts b/editors/code/src/highlighting.ts index e2ae31d29..4fbbe3ddc 100644 --- a/editors/code/src/highlighting.ts +++ b/editors/code/src/highlighting.ts @@ -11,7 +11,7 @@ export function activateHighlighting(ctx: Ctx) { client.onNotification( 'rust-analyzer/publishDecorations', (params: PublishDecorationsParams) => { - if (!ctx.config.highlightingOn()) return; + if (!ctx.config.highlightingOn) return; const targetEditor = vscode.window.visibleTextEditors.find( editor => { @@ -39,7 +39,7 @@ export function activateHighlighting(ctx: Ctx) { vscode.window.onDidChangeActiveTextEditor( async (editor: vscode.TextEditor | undefined) => { if (!editor || editor.document.languageId !== 'rust') return; - if (!ctx.config.highlightingOn()) return; + if (!ctx.config.highlightingOn) return; const client = ctx.client; if (!client) return; @@ -122,7 +122,7 @@ class Highlighter { string, [vscode.Range[], boolean] > = new Map(); - const rainbowTime = this.ctx.config.rainbowHighlightingOn(); + const rainbowTime = this.ctx.config.rainbowHighlightingOn; for (const tag of this.decorations.keys()) { byTag.set(tag, []); diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts index 3ff45a625..1c019a51b 100644 --- a/editors/code/src/inlay_hints.ts +++ b/editors/code/src/inlay_hints.ts @@ -22,12 +22,12 @@ export function activateInlayHints(ctx: Ctx) { ); vscode.workspace.onDidChangeConfiguration( - async _ => hintsUpdater.setEnabled(ctx.config.displayInlayHints()), + async _ => hintsUpdater.setEnabled(ctx.config.displayInlayHints), null, ctx.subscriptions ); - ctx.onDidRestart(_ => hintsUpdater.setEnabled(ctx.config.displayInlayHints())); + ctx.onDidRestart(_ => hintsUpdater.setEnabled(ctx.config.displayInlayHints)); } interface InlayHintsParams { @@ -59,7 +59,7 @@ class HintsUpdater { constructor(ctx: Ctx) { this.ctx = ctx; - this.enabled = ctx.config.displayInlayHints(); + this.enabled = ctx.config.displayInlayHints; } async setEnabled(enabled: boolean) { diff --git a/editors/code/src/status_display.ts b/editors/code/src/status_display.ts index ae9a7b1b5..993e79d70 100644 --- a/editors/code/src/status_display.ts +++ b/editors/code/src/status_display.ts @@ -7,7 +7,7 @@ import { Ctx } from './ctx'; const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; export function activateStatusDisplay(ctx: Ctx) { - const statusDisplay = new StatusDisplay(ctx.config.cargoWatchOptions().command); + const statusDisplay = new StatusDisplay(ctx.config.cargoWatchOptions.command); ctx.pushCleanup(statusDisplay); ctx.onDidRestart(client => ctx.pushCleanup(client.onProgress( WorkDoneProgress.type, -- cgit v1.2.3 From 20fabaf1eeec32e1115627a5552eddf0c074ce37 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Fri, 14 Feb 2020 23:06:11 +0200 Subject: make onConfigChange handler private --- editors/code/src/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 3ce669330..8cd89e119 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -37,7 +37,7 @@ export class Config { console.log("Using configuration:", this.cfg); } - async onConfigChange(event: vscode.ConfigurationChangeEvent) { + private async onConfigChange(event: vscode.ConfigurationChangeEvent) { this.refreshConfig(); const requiresReloadOpt = Config.requiresReloadOpts.find( -- cgit v1.2.3