aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src
diff options
context:
space:
mode:
Diffstat (limited to 'editors/code/src')
-rw-r--r--editors/code/src/client.ts7
-rw-r--r--editors/code/src/config.ts6
-rw-r--r--editors/code/src/ctx.ts43
-rw-r--r--editors/code/src/debug.ts16
-rw-r--r--editors/code/src/lsp_ext.ts3
-rw-r--r--editors/code/src/run.ts35
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
6export const NIGHTLY_TAG = "nightly"; 6export const NIGHTLY_TAG = "nightly";
7 7
8export type RunnableEnvCfg = undefined | Record<string, string> | { mask?: string; env: Record<string, string> }[];
9
8export class Config { 10export 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 @@
1import * as vscode from 'vscode'; 1import * as vscode from 'vscode';
2import * as lc from 'vscode-languageclient'; 2import * as lc from 'vscode-languageclient';
3import * as ra from './lsp_ext';
3 4
4import { Config } from './config'; 5import { Config } from './config';
5import { createClient } from './client'; 6import { createClient } from './client';
6import { isRustEditor, RustEditor } from './util'; 7import { isRustEditor, RustEditor } from './util';
8import { Status } from './lsp_ext';
7 9
8export class Ctx { 10export 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
6import { Cargo } from './toolchain'; 6import { Cargo } from './toolchain';
7import { Ctx } from "./ctx"; 7import { Ctx } from "./ctx";
8import { prepareEnv } from "./run";
8 9
9const debugOutput = vscode.window.createOutputChannel("Debug"); 10const debugOutput = vscode.window.createOutputChannel("Debug");
10type DebugConfigProvider = (config: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>) => vscode.DebugConfiguration; 11type DebugConfigProvider = (config: ra.Runnable, executable: string, env: Record<string, string>, sourceFileMap?: Record<string, string>) => vscode.DebugConfiguration;
11 12
12export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise<void> { 13export 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
124function getLldbDebugConfig(runnable: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration { 126function 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
137function getCppvsDebugConfig(runnable: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration { 140function 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
7export const analyzerStatus = new lc.RequestType<null, string, void>("rust-analyzer/analyzerStatus"); 7export const analyzerStatus = new lc.RequestType<null, string, void>("rust-analyzer/analyzerStatus");
8 8
9export type Status = "loading" | "ready" | "invalid" | "needsReload";
10export const status = new lc.NotificationType<Status>("rust-analyzer/status");
11
9export const reloadWorkspace = new lc.RequestType<null, null, void>("rust-analyzer/reloadWorkspace"); 12export const reloadWorkspace = new lc.RequestType<null, null, void>("rust-analyzer/reloadWorkspace");
10 13
11export interface SyntaxTreeParams { 14export 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
6import { Ctx } from './ctx'; 6import { Ctx } from './ctx';
7import { makeDebugConfig } from './debug'; 7import { makeDebugConfig } from './debug';
8import { Config } from './config'; 8import { Config, RunnableEnvCfg } from './config';
9 9
10const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }]; 10const 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
99export 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
99export async function createTask(runnable: ra.Runnable, config: Config): Promise<vscode.Task> { 123export 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()