diff options
Diffstat (limited to 'editors/code/src')
-rw-r--r-- | editors/code/src/client.ts | 7 | ||||
-rw-r--r-- | editors/code/src/config.ts | 6 | ||||
-rw-r--r-- | editors/code/src/ctx.ts | 43 | ||||
-rw-r--r-- | editors/code/src/debug.ts | 16 | ||||
-rw-r--r-- | editors/code/src/lsp_ext.ts | 3 | ||||
-rw-r--r-- | editors/code/src/run.ts | 35 |
6 files changed, 94 insertions, 16 deletions
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 65ad573d8..41ffac7b3 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts | |||
@@ -66,7 +66,7 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient | |||
66 | return Promise.resolve(null); | 66 | return Promise.resolve(null); |
67 | }); | 67 | }); |
68 | }, | 68 | }, |
69 | // Using custom handling of CodeActions where each code action is resloved lazily | 69 | // Using custom handling of CodeActions where each code action is resolved lazily |
70 | // That's why we are not waiting for any command or edits | 70 | // That's why we are not waiting for any command or edits |
71 | async provideCodeActions(document: vscode.TextDocument, range: vscode.Range, context: vscode.CodeActionContext, token: vscode.CancellationToken, _next: lc.ProvideCodeActionsSignature) { | 71 | async provideCodeActions(document: vscode.TextDocument, range: vscode.Range, context: vscode.CodeActionContext, token: vscode.CancellationToken, _next: lc.ProvideCodeActionsSignature) { |
72 | const params: lc.CodeActionParams = { | 72 | const params: lc.CodeActionParams = { |
@@ -87,7 +87,8 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient | |||
87 | continue; | 87 | continue; |
88 | } | 88 | } |
89 | assert(isCodeActionWithoutEditsAndCommands(item), "We don't expect edits or commands here"); | 89 | assert(isCodeActionWithoutEditsAndCommands(item), "We don't expect edits or commands here"); |
90 | const action = new vscode.CodeAction(item.title); | 90 | const kind = client.protocol2CodeConverter.asCodeActionKind((item as any).kind); |
91 | const action = new vscode.CodeAction(item.title, kind); | ||
91 | const group = (item as any).group; | 92 | const group = (item as any).group; |
92 | const id = (item as any).id; | 93 | const id = (item as any).id; |
93 | const resolveParams: ra.ResolveCodeActionParams = { | 94 | const resolveParams: ra.ResolveCodeActionParams = { |
@@ -116,6 +117,7 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient | |||
116 | result[index] = items[0]; | 117 | result[index] = items[0]; |
117 | } else { | 118 | } else { |
118 | const action = new vscode.CodeAction(group); | 119 | const action = new vscode.CodeAction(group); |
120 | action.kind = items[0].kind; | ||
119 | action.command = { | 121 | action.command = { |
120 | command: "rust-analyzer.applyActionGroup", | 122 | command: "rust-analyzer.applyActionGroup", |
121 | title: "", | 123 | title: "", |
@@ -161,6 +163,7 @@ class ExperimentalFeatures implements lc.StaticFeature { | |||
161 | caps.codeActionGroup = true; | 163 | caps.codeActionGroup = true; |
162 | caps.resolveCodeAction = true; | 164 | caps.resolveCodeAction = true; |
163 | caps.hoverActions = true; | 165 | caps.hoverActions = true; |
166 | caps.statusNotification = true; | ||
164 | capabilities.experimental = caps; | 167 | capabilities.experimental = caps; |
165 | } | 168 | } |
166 | initialize(_capabilities: lc.ServerCapabilities<any>, _documentSelector: lc.DocumentSelector | undefined): void { | 169 | initialize(_capabilities: lc.ServerCapabilities<any>, _documentSelector: lc.DocumentSelector | undefined): void { |
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index fc95a7de6..23975c726 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts | |||
@@ -5,6 +5,8 @@ export type UpdatesChannel = "stable" | "nightly"; | |||
5 | 5 | ||
6 | export const NIGHTLY_TAG = "nightly"; | 6 | export const NIGHTLY_TAG = "nightly"; |
7 | 7 | ||
8 | export type RunnableEnvCfg = undefined | Record<string, string> | { mask?: string; env: Record<string, string> }[]; | ||
9 | |||
8 | export class Config { | 10 | export class Config { |
9 | readonly extensionId = "matklad.rust-analyzer"; | 11 | readonly extensionId = "matklad.rust-analyzer"; |
10 | 12 | ||
@@ -114,6 +116,10 @@ export class Config { | |||
114 | return this.get<string | undefined>("cargoRunner"); | 116 | return this.get<string | undefined>("cargoRunner"); |
115 | } | 117 | } |
116 | 118 | ||
119 | get runnableEnv() { | ||
120 | return this.get<RunnableEnvCfg>("runnableEnv"); | ||
121 | } | ||
122 | |||
117 | get debug() { | 123 | get debug() { |
118 | // "/rustc/<id>" used by suggestions only. | 124 | // "/rustc/<id>" used by suggestions only. |
119 | const { ["/rustc/<id>"]: _, ...sourceFileMap } = this.get<Record<string, string>>("debug.sourceFileMap"); | 125 | const { ["/rustc/<id>"]: _, ...sourceFileMap } = this.get<Record<string, string>>("debug.sourceFileMap"); |
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index 41df11991..6e767babf 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts | |||
@@ -1,9 +1,11 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as lc from 'vscode-languageclient'; | 2 | import * as lc from 'vscode-languageclient'; |
3 | import * as ra from './lsp_ext'; | ||
3 | 4 | ||
4 | import { Config } from './config'; | 5 | import { Config } from './config'; |
5 | import { createClient } from './client'; | 6 | import { createClient } from './client'; |
6 | import { isRustEditor, RustEditor } from './util'; | 7 | import { isRustEditor, RustEditor } from './util'; |
8 | import { Status } from './lsp_ext'; | ||
7 | 9 | ||
8 | export class Ctx { | 10 | export class Ctx { |
9 | private constructor( | 11 | private constructor( |
@@ -11,6 +13,7 @@ export class Ctx { | |||
11 | private readonly extCtx: vscode.ExtensionContext, | 13 | private readonly extCtx: vscode.ExtensionContext, |
12 | readonly client: lc.LanguageClient, | 14 | readonly client: lc.LanguageClient, |
13 | readonly serverPath: string, | 15 | readonly serverPath: string, |
16 | readonly statusBar: vscode.StatusBarItem, | ||
14 | ) { | 17 | ) { |
15 | 18 | ||
16 | } | 19 | } |
@@ -22,9 +25,18 @@ export class Ctx { | |||
22 | cwd: string, | 25 | cwd: string, |
23 | ): Promise<Ctx> { | 26 | ): Promise<Ctx> { |
24 | const client = createClient(serverPath, cwd); | 27 | const client = createClient(serverPath, cwd); |
25 | const res = new Ctx(config, extCtx, client, serverPath); | 28 | |
29 | const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); | ||
30 | extCtx.subscriptions.push(statusBar); | ||
31 | statusBar.text = "rust-analyzer"; | ||
32 | statusBar.tooltip = "ready"; | ||
33 | statusBar.show(); | ||
34 | |||
35 | const res = new Ctx(config, extCtx, client, serverPath, statusBar); | ||
36 | |||
26 | res.pushCleanup(client.start()); | 37 | res.pushCleanup(client.start()); |
27 | await client.onReady(); | 38 | await client.onReady(); |
39 | client.onNotification(ra.status, (status) => res.setStatus(status)); | ||
28 | return res; | 40 | return res; |
29 | } | 41 | } |
30 | 42 | ||
@@ -54,6 +66,35 @@ export class Ctx { | |||
54 | return this.extCtx.subscriptions; | 66 | return this.extCtx.subscriptions; |
55 | } | 67 | } |
56 | 68 | ||
69 | setStatus(status: Status) { | ||
70 | switch (status) { | ||
71 | case "loading": | ||
72 | this.statusBar.text = "$(sync~spin) rust-analyzer"; | ||
73 | this.statusBar.tooltip = "Loading the project"; | ||
74 | this.statusBar.command = undefined; | ||
75 | this.statusBar.color = undefined; | ||
76 | break; | ||
77 | case "ready": | ||
78 | this.statusBar.text = "rust-analyzer"; | ||
79 | this.statusBar.tooltip = "Ready"; | ||
80 | this.statusBar.command = undefined; | ||
81 | this.statusBar.color = undefined; | ||
82 | break; | ||
83 | case "invalid": | ||
84 | this.statusBar.text = "$(error) rust-analyzer"; | ||
85 | this.statusBar.tooltip = "Failed to load the project"; | ||
86 | this.statusBar.command = undefined; | ||
87 | this.statusBar.color = new vscode.ThemeColor("notificationsErrorIcon.foreground"); | ||
88 | break; | ||
89 | case "needsReload": | ||
90 | this.statusBar.text = "$(warning) rust-analyzer"; | ||
91 | this.statusBar.tooltip = "Click to reload"; | ||
92 | this.statusBar.command = "rust-analyzer.reloadWorkspace"; | ||
93 | this.statusBar.color = new vscode.ThemeColor("notificationsWarningIcon.foreground"); | ||
94 | break; | ||
95 | } | ||
96 | } | ||
97 | |||
57 | pushCleanup(d: Disposable) { | 98 | pushCleanup(d: Disposable) { |
58 | this.extCtx.subscriptions.push(d); | 99 | this.extCtx.subscriptions.push(d); |
59 | } | 100 | } |
diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts index 61c12dbe0..bd92c5b6d 100644 --- a/editors/code/src/debug.ts +++ b/editors/code/src/debug.ts | |||
@@ -5,9 +5,10 @@ import * as ra from './lsp_ext'; | |||
5 | 5 | ||
6 | import { Cargo } from './toolchain'; | 6 | import { Cargo } from './toolchain'; |
7 | import { Ctx } from "./ctx"; | 7 | import { Ctx } from "./ctx"; |
8 | import { prepareEnv } from "./run"; | ||
8 | 9 | ||
9 | const debugOutput = vscode.window.createOutputChannel("Debug"); | 10 | const debugOutput = vscode.window.createOutputChannel("Debug"); |
10 | type DebugConfigProvider = (config: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>) => vscode.DebugConfiguration; | 11 | type DebugConfigProvider = (config: ra.Runnable, executable: string, env: Record<string, string>, sourceFileMap?: Record<string, string>) => vscode.DebugConfiguration; |
11 | 12 | ||
12 | export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise<void> { | 13 | export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise<void> { |
13 | const scope = ctx.activeRustEditor?.document.uri; | 14 | const scope = ctx.activeRustEditor?.document.uri; |
@@ -92,7 +93,8 @@ async function getDebugConfiguration(ctx: Ctx, runnable: ra.Runnable): Promise<v | |||
92 | } | 93 | } |
93 | 94 | ||
94 | const executable = await getDebugExecutable(runnable); | 95 | const executable = await getDebugExecutable(runnable); |
95 | const debugConfig = knownEngines[debugEngine.id](runnable, simplifyPath(executable), debugOptions.sourceFileMap); | 96 | const env = prepareEnv(runnable, ctx.config.runnableEnv); |
97 | const debugConfig = knownEngines[debugEngine.id](runnable, simplifyPath(executable), env, debugOptions.sourceFileMap); | ||
96 | if (debugConfig.type in debugOptions.engineSettings) { | 98 | if (debugConfig.type in debugOptions.engineSettings) { |
97 | const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type]; | 99 | const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type]; |
98 | for (var key in settingsMap) { | 100 | for (var key in settingsMap) { |
@@ -121,7 +123,7 @@ async function getDebugExecutable(runnable: ra.Runnable): Promise<string> { | |||
121 | return executable; | 123 | return executable; |
122 | } | 124 | } |
123 | 125 | ||
124 | function getLldbDebugConfig(runnable: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration { | 126 | function getLldbDebugConfig(runnable: ra.Runnable, executable: string, env: Record<string, string>, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration { |
125 | return { | 127 | return { |
126 | type: "lldb", | 128 | type: "lldb", |
127 | request: "launch", | 129 | request: "launch", |
@@ -130,11 +132,12 @@ function getLldbDebugConfig(runnable: ra.Runnable, executable: string, sourceFil | |||
130 | args: runnable.args.executableArgs, | 132 | args: runnable.args.executableArgs, |
131 | cwd: runnable.args.workspaceRoot, | 133 | cwd: runnable.args.workspaceRoot, |
132 | sourceMap: sourceFileMap, | 134 | sourceMap: sourceFileMap, |
133 | sourceLanguages: ["rust"] | 135 | sourceLanguages: ["rust"], |
136 | env | ||
134 | }; | 137 | }; |
135 | } | 138 | } |
136 | 139 | ||
137 | function getCppvsDebugConfig(runnable: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration { | 140 | function getCppvsDebugConfig(runnable: ra.Runnable, executable: string, env: Record<string, string>, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration { |
138 | return { | 141 | return { |
139 | type: (os.platform() === "win32") ? "cppvsdbg" : "cppdbg", | 142 | type: (os.platform() === "win32") ? "cppvsdbg" : "cppdbg", |
140 | request: "launch", | 143 | request: "launch", |
@@ -142,6 +145,7 @@ function getCppvsDebugConfig(runnable: ra.Runnable, executable: string, sourceFi | |||
142 | program: executable, | 145 | program: executable, |
143 | args: runnable.args.executableArgs, | 146 | args: runnable.args.executableArgs, |
144 | cwd: runnable.args.workspaceRoot, | 147 | cwd: runnable.args.workspaceRoot, |
145 | sourceFileMap: sourceFileMap, | 148 | sourceFileMap, |
149 | env, | ||
146 | }; | 150 | }; |
147 | } | 151 | } |
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index 981b6f40e..bf4703239 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts | |||
@@ -6,6 +6,9 @@ import * as lc from "vscode-languageclient"; | |||
6 | 6 | ||
7 | export const analyzerStatus = new lc.RequestType<null, string, void>("rust-analyzer/analyzerStatus"); | 7 | export const analyzerStatus = new lc.RequestType<null, string, void>("rust-analyzer/analyzerStatus"); |
8 | 8 | ||
9 | export type Status = "loading" | "ready" | "invalid" | "needsReload"; | ||
10 | export const status = new lc.NotificationType<Status>("rust-analyzer/status"); | ||
11 | |||
9 | export const reloadWorkspace = new lc.RequestType<null, null, void>("rust-analyzer/reloadWorkspace"); | 12 | export const reloadWorkspace = new lc.RequestType<null, null, void>("rust-analyzer/reloadWorkspace"); |
10 | 13 | ||
11 | export interface SyntaxTreeParams { | 14 | export interface SyntaxTreeParams { |
diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts index e1430e31f..de68f27ae 100644 --- a/editors/code/src/run.ts +++ b/editors/code/src/run.ts | |||
@@ -5,7 +5,7 @@ import * as tasks from './tasks'; | |||
5 | 5 | ||
6 | import { Ctx } from './ctx'; | 6 | import { Ctx } from './ctx'; |
7 | import { makeDebugConfig } from './debug'; | 7 | import { makeDebugConfig } from './debug'; |
8 | import { Config } from './config'; | 8 | import { Config, RunnableEnvCfg } from './config'; |
9 | 9 | ||
10 | const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }]; | 10 | const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }]; |
11 | 11 | ||
@@ -96,6 +96,30 @@ export class RunnableQuickPick implements vscode.QuickPickItem { | |||
96 | } | 96 | } |
97 | } | 97 | } |
98 | 98 | ||
99 | export function prepareEnv(runnable: ra.Runnable, runnableEnvCfg: RunnableEnvCfg): Record<string, string> { | ||
100 | const env: Record<string, string> = { "RUST_BACKTRACE": "short" }; | ||
101 | |||
102 | if (runnable.args.expectTest) { | ||
103 | env["UPDATE_EXPECT"] = "1"; | ||
104 | } | ||
105 | |||
106 | Object.assign(env, process.env as { [key: string]: string }); | ||
107 | |||
108 | if (runnableEnvCfg) { | ||
109 | if (Array.isArray(runnableEnvCfg)) { | ||
110 | for (const it of runnableEnvCfg) { | ||
111 | if (!it.mask || new RegExp(it.mask).test(runnable.label)) { | ||
112 | Object.assign(env, it.env); | ||
113 | } | ||
114 | } | ||
115 | } else { | ||
116 | Object.assign(env, runnableEnvCfg); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | return env; | ||
121 | } | ||
122 | |||
99 | export async function createTask(runnable: ra.Runnable, config: Config): Promise<vscode.Task> { | 123 | export async function createTask(runnable: ra.Runnable, config: Config): Promise<vscode.Task> { |
100 | if (runnable.kind !== "cargo") { | 124 | if (runnable.kind !== "cargo") { |
101 | // rust-analyzer supports only one kind, "cargo" | 125 | // rust-analyzer supports only one kind, "cargo" |
@@ -108,16 +132,13 @@ export async function createTask(runnable: ra.Runnable, config: Config): Promise | |||
108 | if (runnable.args.executableArgs.length > 0) { | 132 | if (runnable.args.executableArgs.length > 0) { |
109 | args.push('--', ...runnable.args.executableArgs); | 133 | args.push('--', ...runnable.args.executableArgs); |
110 | } | 134 | } |
111 | const env: { [key: string]: string } = { "RUST_BACKTRACE": "short" }; | 135 | |
112 | if (runnable.args.expectTest) { | ||
113 | env["UPDATE_EXPECT"] = "1"; | ||
114 | } | ||
115 | const definition: tasks.CargoTaskDefinition = { | 136 | const definition: tasks.CargoTaskDefinition = { |
116 | type: tasks.TASK_TYPE, | 137 | type: tasks.TASK_TYPE, |
117 | command: args[0], // run, test, etc... | 138 | command: args[0], // run, test, etc... |
118 | args: args.slice(1), | 139 | args: args.slice(1), |
119 | cwd: runnable.args.workspaceRoot, | 140 | cwd: runnable.args.workspaceRoot || ".", |
120 | env: Object.assign({}, process.env as { [key: string]: string }, env), | 141 | env: prepareEnv(runnable, config.runnableEnv), |
121 | }; | 142 | }; |
122 | 143 | ||
123 | const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate() | 144 | const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate() |