]> git.lizzy.rs Git - rust.git/blob - editors/code/src/config.ts
better configuration enum items
[rust.git] / editors / code / src / config.ts
1 import * as vscode from 'vscode';
2 import { log } from "./util";
3
4 export type UpdatesChannel = "stable" | "nightly";
5
6 export const NIGHTLY_TAG = "nightly";
7
8 export class Config {
9     readonly extensionId = "matklad.rust-analyzer";
10
11     private readonly rootSection = "rust-analyzer";
12     private readonly requiresReloadOpts = [
13         "serverPath",
14         "cargo",
15         "procMacro",
16         "files",
17         "highlighting",
18         "updates.channel",
19     ]
20         .map(opt => `${this.rootSection}.${opt}`);
21
22     readonly package: {
23         version: string;
24         releaseTag: string | null;
25         enableProposedApi: boolean | undefined;
26     } = vscode.extensions.getExtension(this.extensionId)!.packageJSON;
27
28     readonly globalStoragePath: string;
29
30     constructor(ctx: vscode.ExtensionContext) {
31         this.globalStoragePath = ctx.globalStoragePath;
32         vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, ctx.subscriptions);
33         this.refreshLogging();
34     }
35
36     private refreshLogging() {
37         log.setEnabled(this.traceExtension);
38         log.debug(
39             "Extension version:", this.package.version,
40             "using configuration:", this.cfg
41         );
42     }
43
44     private async onDidChangeConfiguration(event: vscode.ConfigurationChangeEvent) {
45         this.refreshLogging();
46
47         const requiresReloadOpt = this.requiresReloadOpts.find(
48             opt => event.affectsConfiguration(opt)
49         );
50
51         if (!requiresReloadOpt) return;
52
53         const userResponse = await vscode.window.showInformationMessage(
54             `Changing "${requiresReloadOpt}" requires a reload`,
55             "Reload now"
56         );
57
58         if (userResponse === "Reload now") {
59             await vscode.commands.executeCommand("workbench.action.reloadWindow");
60         }
61     }
62
63     // We don't do runtime config validation here for simplicity. More on stackoverflow:
64     // https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension
65
66     private get cfg(): vscode.WorkspaceConfiguration {
67         return vscode.workspace.getConfiguration(this.rootSection);
68     }
69
70     /**
71      * Beware that postfix `!` operator erases both `null` and `undefined`.
72      * This is why the following doesn't work as expected:
73      *
74      * ```ts
75      * const nullableNum = vscode
76      *  .workspace
77      *  .getConfiguration
78      *  .getConfiguration("rust-analyer")
79      *  .get<number | null>(path)!;
80      *
81      * // What happens is that type of `nullableNum` is `number` but not `null | number`:
82      * const fullFledgedNum: number = nullableNum;
83      * ```
84      * So this getter handles this quirk by not requiring the caller to use postfix `!`
85      */
86     private get<T>(path: string): T {
87         return this.cfg.get<T>(path)!;
88     }
89
90     get serverPath() { return this.get<null | string>("serverPath"); }
91     get channel() { return this.get<UpdatesChannel>("updates.channel"); }
92     get askBeforeDownload() { return this.get<boolean>("updates.askBeforeDownload"); }
93     get traceExtension() { return this.get<boolean>("trace.extension"); }
94
95     get inlayHints() {
96         return {
97             typeHints: this.get<boolean>("inlayHints.typeHints"),
98             parameterHints: this.get<boolean>("inlayHints.parameterHints"),
99             chainingHints: this.get<boolean>("inlayHints.chainingHints"),
100             maxLength: this.get<null | number>("inlayHints.maxLength"),
101         };
102     }
103
104     get checkOnSave() {
105         return {
106             command: this.get<string>("checkOnSave.command"),
107         };
108     }
109
110     get debug() {
111         return {
112             engine: this.get<string>("debug.engine"),
113             sourceFileMap: this.get<Record<string, string>>("debug.sourceFileMap"),
114         };
115     }
116
117 }