diff options
Diffstat (limited to 'editors')
-rw-r--r-- | editors/code/package.json | 29 | ||||
-rw-r--r-- | editors/code/src/client.ts | 11 | ||||
-rw-r--r-- | editors/code/src/commands.ts | 55 | ||||
-rw-r--r-- | editors/code/src/config.ts | 7 | ||||
-rw-r--r-- | editors/code/src/ctx.ts | 2 | ||||
-rw-r--r-- | editors/code/src/lsp_ext.ts | 1 | ||||
-rw-r--r-- | editors/code/src/main.ts | 27 |
7 files changed, 115 insertions, 17 deletions
diff --git a/editors/code/package.json b/editors/code/package.json index 13749a084..3e6ebd7ed 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -104,6 +104,11 @@ | |||
104 | "category": "Rust Analyzer" | 104 | "category": "Rust Analyzer" |
105 | }, | 105 | }, |
106 | { | 106 | { |
107 | "command": "rust-analyzer.viewHir", | ||
108 | "title": "View Hir", | ||
109 | "category": "Rust Analyzer" | ||
110 | }, | ||
111 | { | ||
107 | "command": "rust-analyzer.expandMacro", | 112 | "command": "rust-analyzer.expandMacro", |
108 | "title": "Expand macro recursively", | 113 | "title": "Expand macro recursively", |
109 | "category": "Rust Analyzer" | 114 | "category": "Rust Analyzer" |
@@ -275,7 +280,7 @@ | |||
275 | "default": true, | 280 | "default": true, |
276 | "description": "Whether to ask for permission before downloading any files from the Internet." | 281 | "description": "Whether to ask for permission before downloading any files from the Internet." |
277 | }, | 282 | }, |
278 | "rust-analyzer.serverPath": { | 283 | "rust-analyzer.server.path": { |
279 | "type": [ | 284 | "type": [ |
280 | "null", | 285 | "null", |
281 | "string" | 286 | "string" |
@@ -283,6 +288,14 @@ | |||
283 | "default": null, | 288 | "default": null, |
284 | "markdownDescription": "Path to rust-analyzer executable (points to bundled binary by default). If this is set, then `#rust-analyzer.updates.channel#` setting is not used" | 289 | "markdownDescription": "Path to rust-analyzer executable (points to bundled binary by default). If this is set, then `#rust-analyzer.updates.channel#` setting is not used" |
285 | }, | 290 | }, |
291 | "rust-analyzer.server.extraEnv": { | ||
292 | "type": [ | ||
293 | "null", | ||
294 | "object" | ||
295 | ], | ||
296 | "default": null, | ||
297 | "markdownDescription": "Extra environment variables that will be passed to the rust-analyzer executable. Useful for passing e.g. `RA_LOG` for debugging." | ||
298 | }, | ||
286 | "rust-analyzer.trace.server": { | 299 | "rust-analyzer.trace.server": { |
287 | "type": "string", | 300 | "type": "string", |
288 | "scope": "window", | 301 | "scope": "window", |
@@ -336,7 +349,7 @@ | |||
336 | "default": {}, | 349 | "default": {}, |
337 | "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`" | 350 | "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`" |
338 | }, | 351 | }, |
339 | "rust-analyzer.assist.importMergeBehaviour": { | 352 | "rust-analyzer.assist.importMergeBehavior": { |
340 | "markdownDescription": "The strategy to use when inserting new imports or merging imports.", | 353 | "markdownDescription": "The strategy to use when inserting new imports or merging imports.", |
341 | "default": "full", | 354 | "default": "full", |
342 | "type": "string", | 355 | "type": "string", |
@@ -650,6 +663,14 @@ | |||
650 | "default": false, | 663 | "default": false, |
651 | "type": "boolean" | 664 | "type": "boolean" |
652 | }, | 665 | }, |
666 | "rust-analyzer.procMacro.server": { | ||
667 | "markdownDescription": "Internal config, path to proc-macro server executable (typically, this is rust-analyzer itself, but we override this in tests).", | ||
668 | "default": null, | ||
669 | "type": [ | ||
670 | "null", | ||
671 | "string" | ||
672 | ] | ||
673 | }, | ||
653 | "rust-analyzer.runnables.overrideCargo": { | 674 | "rust-analyzer.runnables.overrideCargo": { |
654 | "markdownDescription": "Command to be executed instead of 'cargo' for runnables.", | 675 | "markdownDescription": "Command to be executed instead of 'cargo' for runnables.", |
655 | "default": null, | 676 | "default": null, |
@@ -999,6 +1020,10 @@ | |||
999 | "when": "inRustProject" | 1020 | "when": "inRustProject" |
1000 | }, | 1021 | }, |
1001 | { | 1022 | { |
1023 | "command": "rust-analyzer.viewHir", | ||
1024 | "when": "inRustProject" | ||
1025 | }, | ||
1026 | { | ||
1002 | "command": "rust-analyzer.expandMacro", | 1027 | "command": "rust-analyzer.expandMacro", |
1003 | "when": "inRustProject" | 1028 | "when": "inRustProject" |
1004 | }, | 1029 | }, |
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 63ab82dde..539e487ec 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts | |||
@@ -6,6 +6,10 @@ import { DocumentSemanticsTokensSignature, DocumentSemanticsTokensEditsSignature | |||
6 | import { assert } from './util'; | 6 | import { assert } from './util'; |
7 | import { WorkspaceEdit } from 'vscode'; | 7 | import { WorkspaceEdit } from 'vscode'; |
8 | 8 | ||
9 | export interface Env { | ||
10 | [name: string]: string; | ||
11 | } | ||
12 | |||
9 | function renderCommand(cmd: ra.CommandLink) { | 13 | function renderCommand(cmd: ra.CommandLink) { |
10 | return `[${cmd.title}](command:${cmd.command}?${encodeURIComponent(JSON.stringify(cmd.arguments))} '${cmd.tooltip!}')`; | 14 | return `[${cmd.title}](command:${cmd.command}?${encodeURIComponent(JSON.stringify(cmd.arguments))} '${cmd.tooltip!}')`; |
11 | } | 15 | } |
@@ -27,14 +31,17 @@ async function semanticHighlightingWorkaround<R, F extends (...args: any[]) => v | |||
27 | return res; | 31 | return res; |
28 | } | 32 | } |
29 | 33 | ||
30 | export function createClient(serverPath: string, cwd: string): lc.LanguageClient { | 34 | export function createClient(serverPath: string, cwd: string, extraEnv: Env): lc.LanguageClient { |
31 | // '.' Is the fallback if no folder is open | 35 | // '.' Is the fallback if no folder is open |
32 | // TODO?: Workspace folders support Uri's (eg: file://test.txt). | 36 | // TODO?: Workspace folders support Uri's (eg: file://test.txt). |
33 | // It might be a good idea to test if the uri points to a file. | 37 | // It might be a good idea to test if the uri points to a file. |
34 | 38 | ||
39 | const newEnv = Object.assign({}, process.env); | ||
40 | Object.assign(newEnv, extraEnv); | ||
41 | |||
35 | const run: lc.Executable = { | 42 | const run: lc.Executable = { |
36 | command: serverPath, | 43 | command: serverPath, |
37 | options: { cwd }, | 44 | options: { cwd, env: newEnv }, |
38 | }; | 45 | }; |
39 | const serverOptions: lc.ServerOptions = { | 46 | const serverOptions: lc.ServerOptions = { |
40 | run, | 47 | run, |
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index b12e134ca..c1c9f9754 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts | |||
@@ -340,6 +340,61 @@ export function syntaxTree(ctx: Ctx): Cmd { | |||
340 | }; | 340 | }; |
341 | } | 341 | } |
342 | 342 | ||
343 | // Opens the virtual file that will show the HIR of the function containing the cursor position | ||
344 | // | ||
345 | // The contents of the file come from the `TextDocumentContentProvider` | ||
346 | export function viewHir(ctx: Ctx): Cmd { | ||
347 | const tdcp = new class implements vscode.TextDocumentContentProvider { | ||
348 | readonly uri = vscode.Uri.parse('rust-analyzer://viewHir/hir.txt'); | ||
349 | readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>(); | ||
350 | constructor() { | ||
351 | vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions); | ||
352 | vscode.window.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, ctx.subscriptions); | ||
353 | } | ||
354 | |||
355 | private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { | ||
356 | if (isRustDocument(event.document)) { | ||
357 | // We need to order this after language server updates, but there's no API for that. | ||
358 | // Hence, good old sleep(). | ||
359 | void sleep(10).then(() => this.eventEmitter.fire(this.uri)); | ||
360 | } | ||
361 | } | ||
362 | private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) { | ||
363 | if (editor && isRustEditor(editor)) { | ||
364 | this.eventEmitter.fire(this.uri); | ||
365 | } | ||
366 | } | ||
367 | |||
368 | provideTextDocumentContent(_uri: vscode.Uri, ct: vscode.CancellationToken): vscode.ProviderResult<string> { | ||
369 | const rustEditor = ctx.activeRustEditor; | ||
370 | const client = ctx.client; | ||
371 | if (!rustEditor || !client) return ''; | ||
372 | |||
373 | const params = { | ||
374 | textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(rustEditor.document), | ||
375 | position: client.code2ProtocolConverter.asPosition( | ||
376 | rustEditor.selection.active, | ||
377 | ), | ||
378 | }; | ||
379 | return client.sendRequest(ra.viewHir, params, ct); | ||
380 | } | ||
381 | |||
382 | get onDidChange(): vscode.Event<vscode.Uri> { | ||
383 | return this.eventEmitter.event; | ||
384 | } | ||
385 | }; | ||
386 | |||
387 | ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp)); | ||
388 | |||
389 | return async () => { | ||
390 | const document = await vscode.workspace.openTextDocument(tdcp.uri); | ||
391 | tdcp.eventEmitter.fire(tdcp.uri); | ||
392 | void await vscode.window.showTextDocument(document, { | ||
393 | viewColumn: vscode.ViewColumn.Two, | ||
394 | preserveFocus: true | ||
395 | }); | ||
396 | }; | ||
397 | } | ||
343 | 398 | ||
344 | // Opens the virtual file that will show the syntax tree | 399 | // Opens the virtual file that will show the syntax tree |
345 | // | 400 | // |
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 848e92af9..ebe4de1ea 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import { Env } from './client'; | ||
2 | import { log } from "./util"; | 3 | import { log } from "./util"; |
3 | 4 | ||
4 | export type UpdatesChannel = "stable" | "nightly"; | 5 | export type UpdatesChannel = "stable" | "nightly"; |
@@ -13,6 +14,7 @@ export class Config { | |||
13 | readonly rootSection = "rust-analyzer"; | 14 | readonly rootSection = "rust-analyzer"; |
14 | private readonly requiresReloadOpts = [ | 15 | private readonly requiresReloadOpts = [ |
15 | "serverPath", | 16 | "serverPath", |
17 | "server", | ||
16 | "cargo", | 18 | "cargo", |
17 | "procMacro", | 19 | "procMacro", |
18 | "files", | 20 | "files", |
@@ -91,7 +93,10 @@ export class Config { | |||
91 | return this.cfg.get<T>(path)!; | 93 | return this.cfg.get<T>(path)!; |
92 | } | 94 | } |
93 | 95 | ||
94 | get serverPath() { return this.get<null | string>("serverPath"); } | 96 | get serverPath() { |
97 | return this.get<null | string>("server.path") ?? this.get<null | string>("serverPath"); | ||
98 | } | ||
99 | get serverExtraEnv() { return this.get<Env | null>("server.extraEnv") ?? {}; } | ||
95 | get channel() { return this.get<UpdatesChannel>("updates.channel"); } | 100 | get channel() { return this.get<UpdatesChannel>("updates.channel"); } |
96 | get askBeforeDownload() { return this.get<boolean>("updates.askBeforeDownload"); } | 101 | get askBeforeDownload() { return this.get<boolean>("updates.askBeforeDownload"); } |
97 | get traceExtension() { return this.get<boolean>("trace.extension"); } | 102 | get traceExtension() { return this.get<boolean>("trace.extension"); } |
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index d39864d33..e7585184b 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts | |||
@@ -24,7 +24,7 @@ export class Ctx { | |||
24 | serverPath: string, | 24 | serverPath: string, |
25 | cwd: string, | 25 | cwd: string, |
26 | ): Promise<Ctx> { | 26 | ): Promise<Ctx> { |
27 | const client = createClient(serverPath, cwd); | 27 | const client = createClient(serverPath, cwd, config.serverExtraEnv); |
28 | 28 | ||
29 | const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); | 29 | const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); |
30 | extCtx.subscriptions.push(statusBar); | 30 | extCtx.subscriptions.push(statusBar); |
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index 5e877ce65..d21a3db86 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts | |||
@@ -24,6 +24,7 @@ export interface SyntaxTreeParams { | |||
24 | } | 24 | } |
25 | export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>("rust-analyzer/syntaxTree"); | 25 | export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>("rust-analyzer/syntaxTree"); |
26 | 26 | ||
27 | export const viewHir = new lc.RequestType<lc.TextDocumentPositionParams, string, void>("rust-analyzer/viewHir"); | ||
27 | 28 | ||
28 | export interface ExpandMacroParams { | 29 | export interface ExpandMacroParams { |
29 | textDocument: lc.TextDocumentIdentifier; | 30 | textDocument: lc.TextDocumentIdentifier; |
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 282240d84..694da9409 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts | |||
@@ -105,6 +105,7 @@ async function tryActivate(context: vscode.ExtensionContext) { | |||
105 | ctx.registerCommand('joinLines', commands.joinLines); | 105 | ctx.registerCommand('joinLines', commands.joinLines); |
106 | ctx.registerCommand('parentModule', commands.parentModule); | 106 | ctx.registerCommand('parentModule', commands.parentModule); |
107 | ctx.registerCommand('syntaxTree', commands.syntaxTree); | 107 | ctx.registerCommand('syntaxTree', commands.syntaxTree); |
108 | ctx.registerCommand('viewHir', commands.viewHir); | ||
108 | ctx.registerCommand('expandMacro', commands.expandMacro); | 109 | ctx.registerCommand('expandMacro', commands.expandMacro); |
109 | ctx.registerCommand('run', commands.run); | 110 | ctx.registerCommand('run', commands.run); |
110 | ctx.registerCommand('debug', commands.debug); | 111 | ctx.registerCommand('debug', commands.debug); |
@@ -166,6 +167,7 @@ async function bootstrapExtension(config: Config, state: PersistentState): Promi | |||
166 | } | 167 | } |
167 | return; | 168 | return; |
168 | }; | 169 | }; |
170 | if (serverPath(config) !== null) return; | ||
169 | 171 | ||
170 | const now = Date.now(); | 172 | const now = Date.now(); |
171 | if (config.package.releaseTag === NIGHTLY_TAG) { | 173 | if (config.package.releaseTag === NIGHTLY_TAG) { |
@@ -277,7 +279,7 @@ async function patchelf(dest: PathLike): Promise<void> { | |||
277 | } | 279 | } |
278 | 280 | ||
279 | async function getServer(config: Config, state: PersistentState): Promise<string | undefined> { | 281 | async function getServer(config: Config, state: PersistentState): Promise<string | undefined> { |
280 | const explicitPath = process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath; | 282 | const explicitPath = serverPath(config); |
281 | if (explicitPath) { | 283 | if (explicitPath) { |
282 | if (explicitPath.startsWith("~/")) { | 284 | if (explicitPath.startsWith("~/")) { |
283 | return os.homedir() + explicitPath.slice("~".length); | 285 | return os.homedir() + explicitPath.slice("~".length); |
@@ -286,16 +288,15 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
286 | }; | 288 | }; |
287 | if (config.package.releaseTag === null) return "rust-analyzer"; | 289 | if (config.package.releaseTag === null) return "rust-analyzer"; |
288 | 290 | ||
289 | let platform: string | undefined; | 291 | const platforms: { [key: string]: string } = { |
290 | if ((process.arch === "x64" || process.arch === "ia32") && process.platform === "win32") { | 292 | "ia32 win32": "x86_64-pc-windows-msvc", |
291 | platform = "x86_64-pc-windows-msvc"; | 293 | "x64 win32": "x86_64-pc-windows-msvc", |
292 | } else if (process.arch === "x64" && process.platform === "linux") { | 294 | "x64 linux": "x86_64-unknown-linux-gnu", |
293 | platform = "x86_64-unknown-linux-gnu"; | 295 | "x64 darwin": "x86_64-apple-darwin", |
294 | } else if (process.arch === "x64" && process.platform === "darwin") { | 296 | "arm64 win32": "aarch64-pc-windows-msvc", |
295 | platform = "x86_64-apple-darwin"; | 297 | "arm64 darwin": "aarch64-apple-darwin", |
296 | } else if (process.arch === "arm64" && process.platform === "darwin") { | 298 | }; |
297 | platform = "aarch64-apple-darwin"; | 299 | const platform = platforms[`${process.arch} ${process.platform}`]; |
298 | } | ||
299 | if (platform === undefined) { | 300 | if (platform === undefined) { |
300 | vscode.window.showErrorMessage( | 301 | vscode.window.showErrorMessage( |
301 | "Unfortunately we don't ship binaries for your platform yet. " + | 302 | "Unfortunately we don't ship binaries for your platform yet. " + |
@@ -351,6 +352,10 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
351 | return dest; | 352 | return dest; |
352 | } | 353 | } |
353 | 354 | ||
355 | function serverPath(config: Config): string | null { | ||
356 | return process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath; | ||
357 | } | ||
358 | |||
354 | async function isNixOs(): Promise<boolean> { | 359 | async function isNixOs(): Promise<boolean> { |
355 | try { | 360 | try { |
356 | const contents = await fs.readFile("/etc/os-release"); | 361 | const contents = await fs.readFile("/etc/os-release"); |