aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src/config.ts
diff options
context:
space:
mode:
Diffstat (limited to 'editors/code/src/config.ts')
-rw-r--r--editors/code/src/config.ts117
1 files changed, 97 insertions, 20 deletions
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 6db073bec..f63e1d20e 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -1,7 +1,7 @@
1import * as os from "os"; 1import * as os from "os";
2import * as vscode from 'vscode'; 2import * as vscode from 'vscode';
3import { ArtifactSource } from "./installation/interfaces"; 3import { ArtifactSource } from "./installation/interfaces";
4import { log } from "./util"; 4import { log, vscodeReloadWindow } from "./util";
5 5
6const RA_LSP_DEBUG = process.env.__RA_LSP_SERVER_DEBUG; 6const RA_LSP_DEBUG = process.env.__RA_LSP_SERVER_DEBUG;
7 7
@@ -23,25 +23,40 @@ export interface CargoFeatures {
23 allFeatures: boolean; 23 allFeatures: boolean;
24 features: string[]; 24 features: string[];
25} 25}
26
27export const enum UpdatesChannel {
28 Stable = "stable",
29 Nightly = "nightly"
30}
31
32export const NIGHTLY_TAG = "nightly";
26export class Config { 33export class Config {
27 private static readonly rootSection = "rust-analyzer"; 34 readonly extensionId = "matklad.rust-analyzer";
28 private static readonly requiresReloadOpts = [ 35
36 private readonly rootSection = "rust-analyzer";
37 private readonly requiresReloadOpts = [
38 "serverPath",
29 "cargoFeatures", 39 "cargoFeatures",
30 "cargo-watch", 40 "cargo-watch",
31 "highlighting.semanticTokens", 41 "highlighting.semanticTokens",
32 "inlayHints", 42 "inlayHints",
33 ] 43 ]
34 .map(opt => `${Config.rootSection}.${opt}`); 44 .map(opt => `${this.rootSection}.${opt}`);
35 45
36 private static readonly extensionVersion: string = (() => { 46 readonly packageJsonVersion = vscode
37 const packageJsonVersion = vscode 47 .extensions
38 .extensions 48 .getExtension(this.extensionId)!
39 .getExtension("matklad.rust-analyzer")! 49 .packageJSON
40 .packageJSON 50 .version as string; // n.n.YYYYMMDD[-nightly]
41 .version as string; // n.n.YYYYMMDD 51
52 /**
53 * Either `nightly` or `YYYY-MM-DD` (i.e. `stable` release)
54 */
55 readonly extensionReleaseTag: string = (() => {
56 if (this.packageJsonVersion.endsWith(NIGHTLY_TAG)) return NIGHTLY_TAG;
42 57
43 const realVersionRegexp = /^\d+\.\d+\.(\d{4})(\d{2})(\d{2})/; 58 const realVersionRegexp = /^\d+\.\d+\.(\d{4})(\d{2})(\d{2})/;
44 const [, yyyy, mm, dd] = packageJsonVersion.match(realVersionRegexp)!; 59 const [, yyyy, mm, dd] = this.packageJsonVersion.match(realVersionRegexp)!;
45 60
46 return `${yyyy}-${mm}-${dd}`; 61 return `${yyyy}-${mm}-${dd}`;
47 })(); 62 })();
@@ -54,16 +69,19 @@ export class Config {
54 } 69 }
55 70
56 private refreshConfig() { 71 private refreshConfig() {
57 this.cfg = vscode.workspace.getConfiguration(Config.rootSection); 72 this.cfg = vscode.workspace.getConfiguration(this.rootSection);
58 const enableLogging = this.cfg.get("trace.extension") as boolean; 73 const enableLogging = this.cfg.get("trace.extension") as boolean;
59 log.setEnabled(enableLogging); 74 log.setEnabled(enableLogging);
60 log.debug("Using configuration:", this.cfg); 75 log.debug(
76 "Extension version:", this.packageJsonVersion,
77 "using configuration:", this.cfg
78 );
61 } 79 }
62 80
63 private async onConfigChange(event: vscode.ConfigurationChangeEvent) { 81 private async onConfigChange(event: vscode.ConfigurationChangeEvent) {
64 this.refreshConfig(); 82 this.refreshConfig();
65 83
66 const requiresReloadOpt = Config.requiresReloadOpts.find( 84 const requiresReloadOpt = this.requiresReloadOpts.find(
67 opt => event.affectsConfiguration(opt) 85 opt => event.affectsConfiguration(opt)
68 ); 86 );
69 87
@@ -75,7 +93,7 @@ export class Config {
75 ); 93 );
76 94
77 if (userResponse === "Reload now") { 95 if (userResponse === "Reload now") {
78 vscode.commands.executeCommand("workbench.action.reloadWindow"); 96 await vscodeReloadWindow();
79 } 97 }
80 } 98 }
81 99
@@ -121,8 +139,14 @@ export class Config {
121 } 139 }
122 } 140 }
123 141
142 get installedExtensionUpdateChannel(): UpdatesChannel {
143 return this.extensionReleaseTag === NIGHTLY_TAG
144 ? UpdatesChannel.Nightly
145 : UpdatesChannel.Stable;
146 }
147
124 get serverSource(): null | ArtifactSource { 148 get serverSource(): null | ArtifactSource {
125 const serverPath = RA_LSP_DEBUG ?? this.cfg.get<null | string>("serverPath"); 149 const serverPath = RA_LSP_DEBUG ?? this.serverPath;
126 150
127 if (serverPath) { 151 if (serverPath) {
128 return { 152 return {
@@ -135,13 +159,18 @@ export class Config {
135 159
136 if (!prebuiltBinaryName) return null; 160 if (!prebuiltBinaryName) return null;
137 161
162 return this.createGithubReleaseSource(
163 prebuiltBinaryName,
164 this.extensionReleaseTag
165 );
166 }
167
168 private createGithubReleaseSource(file: string, tag: string): ArtifactSource.GithubRelease {
138 return { 169 return {
139 type: ArtifactSource.Type.GithubRelease, 170 type: ArtifactSource.Type.GithubRelease,
171 file,
172 tag,
140 dir: this.ctx.globalStoragePath, 173 dir: this.ctx.globalStoragePath,
141 file: prebuiltBinaryName,
142 storage: this.ctx.globalState,
143 tag: Config.extensionVersion,
144 askBeforeDownload: this.cfg.get("updates.askBeforeDownload") as boolean,
145 repo: { 174 repo: {
146 name: "rust-analyzer", 175 name: "rust-analyzer",
147 owner: "rust-analyzer", 176 owner: "rust-analyzer",
@@ -149,9 +178,23 @@ export class Config {
149 }; 178 };
150 } 179 }
151 180
181 get nightlyVsixSource(): ArtifactSource.GithubRelease {
182 return this.createGithubReleaseSource("rust-analyzer.vsix", NIGHTLY_TAG);
183 }
184
185 readonly installedNightlyExtensionReleaseDate = new DateStorage(
186 "installed-nightly-extension-release-date",
187 this.ctx.globalState
188 );
189 readonly serverReleaseDate = new DateStorage("server-release-date", this.ctx.globalState);
190 readonly serverReleaseTag = new Storage<null | string>("server-release-tag", this.ctx.globalState, null);
191
152 // We don't do runtime config validation here for simplicity. More on stackoverflow: 192 // We don't do runtime config validation here for simplicity. More on stackoverflow:
153 // https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension 193 // https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension
154 194
195 private get serverPath() { return this.cfg.get("serverPath") as null | string; }
196 get updatesChannel() { return this.cfg.get("updates.channel") as UpdatesChannel; }
197 get askBeforeDownload() { return this.cfg.get("updates.askBeforeDownload") as boolean; }
155 get highlightingSemanticTokens() { return this.cfg.get("highlighting.semanticTokens") as boolean; } 198 get highlightingSemanticTokens() { return this.cfg.get("highlighting.semanticTokens") as boolean; }
156 get highlightingOn() { return this.cfg.get("highlightingOn") as boolean; } 199 get highlightingOn() { return this.cfg.get("highlightingOn") as boolean; }
157 get rainbowHighlightingOn() { return this.cfg.get("rainbowHighlightingOn") as boolean; } 200 get rainbowHighlightingOn() { return this.cfg.get("rainbowHighlightingOn") as boolean; }
@@ -189,3 +232,37 @@ export class Config {
189 // for internal use 232 // for internal use
190 get withSysroot() { return this.cfg.get("withSysroot", true) as boolean; } 233 get withSysroot() { return this.cfg.get("withSysroot", true) as boolean; }
191} 234}
235
236export class Storage<T> {
237 constructor(
238 private readonly key: string,
239 private readonly storage: vscode.Memento,
240 private readonly defaultVal: T
241 ) { }
242
243 get(): T {
244 const val = this.storage.get(this.key, this.defaultVal);
245 log.debug(this.key, "==", val);
246 return val;
247 }
248 async set(val: T) {
249 log.debug(this.key, "=", val);
250 await this.storage.update(this.key, val);
251 }
252}
253export class DateStorage {
254 inner: Storage<null | string>;
255
256 constructor(key: string, storage: vscode.Memento) {
257 this.inner = new Storage(key, storage, null);
258 }
259
260 get(): null | Date {
261 const dateStr = this.inner.get();
262 return dateStr ? new Date(dateStr) : null;
263 }
264
265 async set(date: null | Date) {
266 await this.inner.set(date ? date.toString() : null);
267 }
268}