diff options
Diffstat (limited to 'editors/code/src/config.ts')
-rw-r--r-- | editors/code/src/config.ts | 117 |
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 @@ | |||
1 | import * as os from "os"; | 1 | import * as os from "os"; |
2 | import * as vscode from 'vscode'; | 2 | import * as vscode from 'vscode'; |
3 | import { ArtifactSource } from "./installation/interfaces"; | 3 | import { ArtifactSource } from "./installation/interfaces"; |
4 | import { log } from "./util"; | 4 | import { log, vscodeReloadWindow } from "./util"; |
5 | 5 | ||
6 | const RA_LSP_DEBUG = process.env.__RA_LSP_SERVER_DEBUG; | 6 | const 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 | |||
27 | export const enum UpdatesChannel { | ||
28 | Stable = "stable", | ||
29 | Nightly = "nightly" | ||
30 | } | ||
31 | |||
32 | export const NIGHTLY_TAG = "nightly"; | ||
26 | export class Config { | 33 | export 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 | |||
236 | export 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 | } | ||
253 | export 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 | } | ||