diff options
Diffstat (limited to 'editors/code')
-rw-r--r-- | editors/code/package.json | 6 | ||||
-rw-r--r-- | editors/code/src/config.ts | 4 | ||||
-rw-r--r-- | editors/code/src/main.ts | 34 | ||||
-rw-r--r-- | editors/code/src/net.ts | 32 | ||||
-rw-r--r-- | editors/code/src/toolchain.ts | 21 |
5 files changed, 49 insertions, 48 deletions
diff --git a/editors/code/package.json b/editors/code/package.json index 9565c6edb..1fac700be 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -313,7 +313,7 @@ | |||
313 | }, | 313 | }, |
314 | "rust-analyzer.updates.askBeforeDownload": { | 314 | "rust-analyzer.updates.askBeforeDownload": { |
315 | "type": "boolean", | 315 | "type": "boolean", |
316 | "default": true, | 316 | "default": false, |
317 | "description": "Whether to ask for permission before downloading any files from the Internet." | 317 | "description": "Whether to ask for permission before downloading any files from the Internet." |
318 | }, | 318 | }, |
319 | "rust-analyzer.server.path": { | 319 | "rust-analyzer.server.path": { |
@@ -389,7 +389,7 @@ | |||
389 | "default": {}, | 389 | "default": {}, |
390 | "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`" | 390 | "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`" |
391 | }, | 391 | }, |
392 | "$generated-start": false, | 392 | "$generated-start": {}, |
393 | "rust-analyzer.assist.importGranularity": { | 393 | "rust-analyzer.assist.importGranularity": { |
394 | "markdownDescription": "How imports should be grouped into use statements.", | 394 | "markdownDescription": "How imports should be grouped into use statements.", |
395 | "default": "crate", | 395 | "default": "crate", |
@@ -841,7 +841,7 @@ | |||
841 | "Search for all symbols kinds" | 841 | "Search for all symbols kinds" |
842 | ] | 842 | ] |
843 | }, | 843 | }, |
844 | "$generated-end": false | 844 | "$generated-end": {} |
845 | } | 845 | } |
846 | }, | 846 | }, |
847 | "problemPatterns": [ | 847 | "problemPatterns": [ |
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 1f1fe59a4..2277eeb7e 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts | |||
@@ -31,10 +31,10 @@ export class Config { | |||
31 | enableProposedApi: boolean | undefined; | 31 | enableProposedApi: boolean | undefined; |
32 | } = vscode.extensions.getExtension(this.extensionId)!.packageJSON; | 32 | } = vscode.extensions.getExtension(this.extensionId)!.packageJSON; |
33 | 33 | ||
34 | readonly globalStoragePath: string; | 34 | readonly globalStorageUri: vscode.Uri; |
35 | 35 | ||
36 | constructor(ctx: vscode.ExtensionContext) { | 36 | constructor(ctx: vscode.ExtensionContext) { |
37 | this.globalStoragePath = ctx.globalStorageUri.fsPath; | 37 | this.globalStorageUri = ctx.globalStorageUri; |
38 | vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, ctx.subscriptions); | 38 | vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, ctx.subscriptions); |
39 | this.refreshLogging(); | 39 | this.refreshLogging(); |
40 | } | 40 | } |
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 74ee28d24..15f2151ad 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts | |||
@@ -1,7 +1,5 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as path from "path"; | ||
3 | import * as os from "os"; | 2 | import * as os from "os"; |
4 | import { promises as fs, PathLike } from "fs"; | ||
5 | 3 | ||
6 | import * as commands from './commands'; | 4 | import * as commands from './commands'; |
7 | import { activateInlayHints } from './inlay_hints'; | 5 | import { activateInlayHints } from './inlay_hints'; |
@@ -160,7 +158,7 @@ export async function deactivate() { | |||
160 | } | 158 | } |
161 | 159 | ||
162 | async function bootstrap(config: Config, state: PersistentState): Promise<string> { | 160 | async function bootstrap(config: Config, state: PersistentState): Promise<string> { |
163 | await fs.mkdir(config.globalStoragePath, { recursive: true }); | 161 | await vscode.workspace.fs.createDirectory(config.globalStorageUri).then(); |
164 | 162 | ||
165 | if (!config.currentExtensionIsNightly) { | 163 | if (!config.currentExtensionIsNightly) { |
166 | await state.updateNightlyReleaseId(undefined); | 164 | await state.updateNightlyReleaseId(undefined); |
@@ -222,7 +220,7 @@ async function bootstrapExtension(config: Config, state: PersistentState): Promi | |||
222 | const artifact = latestNightlyRelease.assets.find(artifact => artifact.name === "rust-analyzer.vsix"); | 220 | const artifact = latestNightlyRelease.assets.find(artifact => artifact.name === "rust-analyzer.vsix"); |
223 | assert(!!artifact, `Bad release: ${JSON.stringify(latestNightlyRelease)}`); | 221 | assert(!!artifact, `Bad release: ${JSON.stringify(latestNightlyRelease)}`); |
224 | 222 | ||
225 | const dest = path.join(config.globalStoragePath, "rust-analyzer.vsix"); | 223 | const dest = vscode.Uri.joinPath(config.globalStorageUri, "rust-analyzer.vsix"); |
226 | 224 | ||
227 | await downloadWithRetryDialog(state, async () => { | 225 | await downloadWithRetryDialog(state, async () => { |
228 | await download({ | 226 | await download({ |
@@ -233,8 +231,8 @@ async function bootstrapExtension(config: Config, state: PersistentState): Promi | |||
233 | }); | 231 | }); |
234 | }); | 232 | }); |
235 | 233 | ||
236 | await vscode.commands.executeCommand("workbench.extensions.installExtension", vscode.Uri.file(dest)); | 234 | await vscode.commands.executeCommand("workbench.extensions.installExtension", dest); |
237 | await fs.unlink(dest); | 235 | await vscode.workspace.fs.delete(dest); |
238 | 236 | ||
239 | await state.updateNightlyReleaseId(latestNightlyRelease.id); | 237 | await state.updateNightlyReleaseId(latestNightlyRelease.id); |
240 | await state.updateLastCheck(now); | 238 | await state.updateLastCheck(now); |
@@ -259,7 +257,7 @@ async function bootstrapServer(config: Config, state: PersistentState): Promise< | |||
259 | return path; | 257 | return path; |
260 | } | 258 | } |
261 | 259 | ||
262 | async function patchelf(dest: PathLike): Promise<void> { | 260 | async function patchelf(dest: vscode.Uri): Promise<void> { |
263 | await vscode.window.withProgress( | 261 | await vscode.window.withProgress( |
264 | { | 262 | { |
265 | location: vscode.ProgressLocation.Notification, | 263 | location: vscode.ProgressLocation.Notification, |
@@ -279,11 +277,11 @@ async function patchelf(dest: PathLike): Promise<void> { | |||
279 | ''; | 277 | ''; |
280 | } | 278 | } |
281 | `; | 279 | `; |
282 | const origFile = dest + "-orig"; | 280 | const origFile = vscode.Uri.file(dest.fsPath + "-orig"); |
283 | await fs.rename(dest, origFile); | 281 | await vscode.workspace.fs.rename(dest, origFile); |
284 | progress.report({ message: "Patching executable", increment: 20 }); | 282 | progress.report({ message: "Patching executable", increment: 20 }); |
285 | await new Promise((resolve, reject) => { | 283 | await new Promise((resolve, reject) => { |
286 | const handle = exec(`nix-build -E - --argstr srcStr '${origFile}' -o '${dest}'`, | 284 | const handle = exec(`nix-build -E - --argstr srcStr '${origFile.fsPath}' -o '${dest.fsPath}'`, |
287 | (err, stdout, stderr) => { | 285 | (err, stdout, stderr) => { |
288 | if (err != null) { | 286 | if (err != null) { |
289 | reject(Error(stderr)); | 287 | reject(Error(stderr)); |
@@ -294,7 +292,7 @@ async function patchelf(dest: PathLike): Promise<void> { | |||
294 | handle.stdin?.write(expression); | 292 | handle.stdin?.write(expression); |
295 | handle.stdin?.end(); | 293 | handle.stdin?.end(); |
296 | }); | 294 | }); |
297 | await fs.unlink(origFile); | 295 | await vscode.workspace.fs.delete(origFile); |
298 | } | 296 | } |
299 | ); | 297 | ); |
300 | } | 298 | } |
@@ -334,20 +332,20 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
334 | platform = "x86_64-unknown-linux-musl"; | 332 | platform = "x86_64-unknown-linux-musl"; |
335 | } | 333 | } |
336 | const ext = platform.indexOf("-windows-") !== -1 ? ".exe" : ""; | 334 | const ext = platform.indexOf("-windows-") !== -1 ? ".exe" : ""; |
337 | const dest = path.join(config.globalStoragePath, `rust-analyzer-${platform}${ext}`); | 335 | const dest = vscode.Uri.joinPath(config.globalStorageUri, `rust-analyzer-${platform}${ext}`); |
338 | const exists = await fs.stat(dest).then(() => true, () => false); | 336 | const exists = await vscode.workspace.fs.stat(dest).then(() => true, () => false); |
339 | if (!exists) { | 337 | if (!exists) { |
340 | await state.updateServerVersion(undefined); | 338 | await state.updateServerVersion(undefined); |
341 | } | 339 | } |
342 | 340 | ||
343 | if (state.serverVersion === config.package.version) return dest; | 341 | if (state.serverVersion === config.package.version) return dest.fsPath; |
344 | 342 | ||
345 | if (config.askBeforeDownload) { | 343 | if (config.askBeforeDownload) { |
346 | const userResponse = await vscode.window.showInformationMessage( | 344 | const userResponse = await vscode.window.showInformationMessage( |
347 | `Language server version ${config.package.version} for rust-analyzer is not installed.`, | 345 | `Language server version ${config.package.version} for rust-analyzer is not installed.`, |
348 | "Download now" | 346 | "Download now" |
349 | ); | 347 | ); |
350 | if (userResponse !== "Download now") return dest; | 348 | if (userResponse !== "Download now") return dest.fsPath; |
351 | } | 349 | } |
352 | 350 | ||
353 | const releaseTag = config.package.releaseTag; | 351 | const releaseTag = config.package.releaseTag; |
@@ -374,7 +372,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
374 | } | 372 | } |
375 | 373 | ||
376 | await state.updateServerVersion(config.package.version); | 374 | await state.updateServerVersion(config.package.version); |
377 | return dest; | 375 | return dest.fsPath; |
378 | } | 376 | } |
379 | 377 | ||
380 | function serverPath(config: Config): string | null { | 378 | function serverPath(config: Config): string | null { |
@@ -383,9 +381,9 @@ function serverPath(config: Config): string | null { | |||
383 | 381 | ||
384 | async function isNixOs(): Promise<boolean> { | 382 | async function isNixOs(): Promise<boolean> { |
385 | try { | 383 | try { |
386 | const contents = await fs.readFile("/etc/os-release"); | 384 | const contents = (await vscode.workspace.fs.readFile(vscode.Uri.file("/etc/os-release"))).toString(); |
387 | return contents.indexOf("ID=nixos") !== -1; | 385 | return contents.indexOf("ID=nixos") !== -1; |
388 | } catch (e) { | 386 | } catch { |
389 | return false; | 387 | return false; |
390 | } | 388 | } |
391 | } | 389 | } |
diff --git a/editors/code/src/net.ts b/editors/code/src/net.ts index 07ebc615c..722dab756 100644 --- a/editors/code/src/net.ts +++ b/editors/code/src/net.ts | |||
@@ -73,14 +73,14 @@ export interface GithubRelease { | |||
73 | assets: Array<{ | 73 | assets: Array<{ |
74 | name: string; | 74 | name: string; |
75 | // eslint-disable-next-line camelcase | 75 | // eslint-disable-next-line camelcase |
76 | browser_download_url: string; | 76 | browser_download_url: vscode.Uri; |
77 | }>; | 77 | }>; |
78 | } | 78 | } |
79 | 79 | ||
80 | interface DownloadOpts { | 80 | interface DownloadOpts { |
81 | progressTitle: string; | 81 | progressTitle: string; |
82 | url: string; | 82 | url: vscode.Uri; |
83 | dest: string; | 83 | dest: vscode.Uri; |
84 | mode?: number; | 84 | mode?: number; |
85 | gunzip?: boolean; | 85 | gunzip?: boolean; |
86 | httpProxy?: string; | 86 | httpProxy?: string; |
@@ -90,9 +90,9 @@ export async function download(opts: DownloadOpts) { | |||
90 | // Put artifact into a temporary file (in the same dir for simplicity) | 90 | // Put artifact into a temporary file (in the same dir for simplicity) |
91 | // to prevent partially downloaded files when user kills vscode | 91 | // to prevent partially downloaded files when user kills vscode |
92 | // This also avoids overwriting running executables | 92 | // This also avoids overwriting running executables |
93 | const dest = path.parse(opts.dest); | ||
94 | const randomHex = crypto.randomBytes(5).toString("hex"); | 93 | const randomHex = crypto.randomBytes(5).toString("hex"); |
95 | const tempFile = path.join(dest.dir, `${dest.name}${randomHex}`); | 94 | const rawDest = path.parse(opts.dest.fsPath); |
95 | const tempFilePath = vscode.Uri.joinPath(vscode.Uri.file(rawDest.dir), `${rawDest.name}${randomHex}`); | ||
96 | 96 | ||
97 | await vscode.window.withProgress( | 97 | await vscode.window.withProgress( |
98 | { | 98 | { |
@@ -102,7 +102,7 @@ export async function download(opts: DownloadOpts) { | |||
102 | }, | 102 | }, |
103 | async (progress, _cancellationToken) => { | 103 | async (progress, _cancellationToken) => { |
104 | let lastPercentage = 0; | 104 | let lastPercentage = 0; |
105 | await downloadFile(opts.url, tempFile, opts.mode, !!opts.gunzip, opts.httpProxy, (readBytes, totalBytes) => { | 105 | await downloadFile(opts.url, tempFilePath, opts.mode, !!opts.gunzip, opts.httpProxy, (readBytes, totalBytes) => { |
106 | const newPercentage = Math.round((readBytes / totalBytes) * 100); | 106 | const newPercentage = Math.round((readBytes / totalBytes) * 100); |
107 | if (newPercentage !== lastPercentage) { | 107 | if (newPercentage !== lastPercentage) { |
108 | progress.report({ | 108 | progress.report({ |
@@ -116,28 +116,30 @@ export async function download(opts: DownloadOpts) { | |||
116 | } | 116 | } |
117 | ); | 117 | ); |
118 | 118 | ||
119 | await fs.promises.rename(tempFile, opts.dest); | 119 | await vscode.workspace.fs.rename(tempFilePath, opts.dest, { overwrite: true }); |
120 | } | 120 | } |
121 | 121 | ||
122 | async function downloadFile( | 122 | async function downloadFile( |
123 | url: string, | 123 | url: vscode.Uri, |
124 | destFilePath: fs.PathLike, | 124 | destFilePath: vscode.Uri, |
125 | mode: number | undefined, | 125 | mode: number | undefined, |
126 | gunzip: boolean, | 126 | gunzip: boolean, |
127 | httpProxy: string | null | undefined, | 127 | httpProxy: string | null | undefined, |
128 | onProgress: (readBytes: number, totalBytes: number) => void | 128 | onProgress: (readBytes: number, totalBytes: number) => void |
129 | ): Promise<void> { | 129 | ): Promise<void> { |
130 | const urlString = url.toString(); | ||
131 | |||
130 | const res = await (() => { | 132 | const res = await (() => { |
131 | if (httpProxy) { | 133 | if (httpProxy) { |
132 | log.debug(`Downloading ${url} via proxy: ${httpProxy}`); | 134 | log.debug(`Downloading ${urlString} via proxy: ${httpProxy}`); |
133 | return fetch(url, { agent: new HttpsProxyAgent(httpProxy) }); | 135 | return fetch(urlString, { agent: new HttpsProxyAgent(httpProxy) }); |
134 | } | 136 | } |
135 | 137 | ||
136 | return fetch(url); | 138 | return fetch(urlString); |
137 | })(); | 139 | })(); |
138 | 140 | ||
139 | if (!res.ok) { | 141 | if (!res.ok) { |
140 | log.error("Error", res.status, "while downloading file from", url); | 142 | log.error("Error", res.status, "while downloading file from", urlString); |
141 | log.error({ body: await res.text(), headers: res.headers }); | 143 | log.error({ body: await res.text(), headers: res.headers }); |
142 | 144 | ||
143 | throw new Error(`Got response ${res.status} when trying to download a file.`); | 145 | throw new Error(`Got response ${res.status} when trying to download a file.`); |
@@ -146,7 +148,7 @@ async function downloadFile( | |||
146 | const totalBytes = Number(res.headers.get('content-length')); | 148 | const totalBytes = Number(res.headers.get('content-length')); |
147 | assert(!Number.isNaN(totalBytes), "Sanity check of content-length protocol"); | 149 | assert(!Number.isNaN(totalBytes), "Sanity check of content-length protocol"); |
148 | 150 | ||
149 | log.debug("Downloading file of", totalBytes, "bytes size from", url, "to", destFilePath); | 151 | log.debug("Downloading file of", totalBytes, "bytes size from", urlString, "to", destFilePath.fsPath); |
150 | 152 | ||
151 | let readBytes = 0; | 153 | let readBytes = 0; |
152 | res.body.on("data", (chunk: Buffer) => { | 154 | res.body.on("data", (chunk: Buffer) => { |
@@ -154,7 +156,7 @@ async function downloadFile( | |||
154 | onProgress(readBytes, totalBytes); | 156 | onProgress(readBytes, totalBytes); |
155 | }); | 157 | }); |
156 | 158 | ||
157 | const destFileStream = fs.createWriteStream(destFilePath, { mode }); | 159 | const destFileStream = fs.createWriteStream(destFilePath.fsPath, { mode }); |
158 | const srcStream = gunzip ? res.body.pipe(zlib.createGunzip()) : res.body; | 160 | const srcStream = gunzip ? res.body.pipe(zlib.createGunzip()) : res.body; |
159 | 161 | ||
160 | await pipeline(srcStream, destFileStream); | 162 | await pipeline(srcStream, destFileStream); |
diff --git a/editors/code/src/toolchain.ts b/editors/code/src/toolchain.ts index 68826c478..355dd76fe 100644 --- a/editors/code/src/toolchain.ts +++ b/editors/code/src/toolchain.ts | |||
@@ -1,9 +1,8 @@ | |||
1 | import * as cp from 'child_process'; | 1 | import * as cp from 'child_process'; |
2 | import * as os from 'os'; | 2 | import * as os from 'os'; |
3 | import * as path from 'path'; | 3 | import * as path from 'path'; |
4 | import * as fs from 'fs'; | ||
5 | import * as readline from 'readline'; | 4 | import * as readline from 'readline'; |
6 | import { OutputChannel } from 'vscode'; | 5 | import * as vscode from 'vscode'; |
7 | import { execute, log, memoize } from './util'; | 6 | import { execute, log, memoize } from './util'; |
8 | 7 | ||
9 | interface CompilationArtifact { | 8 | interface CompilationArtifact { |
@@ -19,7 +18,7 @@ export interface ArtifactSpec { | |||
19 | } | 18 | } |
20 | 19 | ||
21 | export class Cargo { | 20 | export class Cargo { |
22 | constructor(readonly rootFolder: string, readonly output: OutputChannel) { } | 21 | constructor(readonly rootFolder: string, readonly output: vscode.OutputChannel) { } |
23 | 22 | ||
24 | // Made public for testing purposes | 23 | // Made public for testing purposes |
25 | static artifactSpec(args: readonly string[]): ArtifactSpec { | 24 | static artifactSpec(args: readonly string[]): ArtifactSpec { |
@@ -158,9 +157,9 @@ export const getPathForExecutable = memoize( | |||
158 | try { | 157 | try { |
159 | // hmm, `os.homedir()` seems to be infallible | 158 | // hmm, `os.homedir()` seems to be infallible |
160 | // it is not mentioned in docs and cannot be infered by the type signature... | 159 | // it is not mentioned in docs and cannot be infered by the type signature... |
161 | const standardPath = path.join(os.homedir(), ".cargo", "bin", executableName); | 160 | const standardPath = vscode.Uri.joinPath(vscode.Uri.file(os.homedir()), ".cargo", "bin", executableName); |
162 | 161 | ||
163 | if (isFile(standardPath)) return standardPath; | 162 | if (isFileAtUri(standardPath)) return standardPath.fsPath; |
164 | } catch (err) { | 163 | } catch (err) { |
165 | log.error("Failed to read the fs info", err); | 164 | log.error("Failed to read the fs info", err); |
166 | } | 165 | } |
@@ -178,14 +177,16 @@ function lookupInPath(exec: string): boolean { | |||
178 | : [candidate]; | 177 | : [candidate]; |
179 | }); | 178 | }); |
180 | 179 | ||
181 | return candidates.some(isFile); | 180 | return candidates.some(isFileAtPath); |
182 | } | 181 | } |
183 | 182 | ||
184 | function isFile(suspectPath: string): boolean { | 183 | async function isFileAtPath(path: string): Promise<boolean> { |
185 | // It is not mentionned in docs, but `statSync()` throws an error when | 184 | return isFileAtUri(vscode.Uri.file(path)); |
186 | // the path doesn't exist | 185 | } |
186 | |||
187 | async function isFileAtUri(uri: vscode.Uri): Promise<boolean> { | ||
187 | try { | 188 | try { |
188 | return fs.statSync(suspectPath).isFile(); | 189 | return ((await vscode.workspace.fs.stat(uri)).type & vscode.FileType.File) !== 0; |
189 | } catch { | 190 | } catch { |
190 | return false; | 191 | return false; |
191 | } | 192 | } |