Skip to content

Commit 40cbeb5

Browse files
committed
Auto merge of rust-lang#13423 - Veykril:vscode-vars, r=Veykril
Substitute some VSCode variables in the VSCode client cc rust-lang/rust-analyzer#13405
2 parents a2e4f78 + d5f467a commit 40cbeb5

File tree

2 files changed

+79
-32
lines changed

2 files changed

+79
-32
lines changed

editors/code/src/client.ts

+22-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import * as Is from "vscode-languageclient/lib/common/utils/is";
55
import { assert } from "./util";
66
import { WorkspaceEdit } from "vscode";
77
import { Workspace } from "./ctx";
8-
import { substituteVariablesInEnv } from "./config";
8+
import { substituteVariablesInEnv, substituteVSCodeVariables } from "./config";
99
import { outputChannel, traceOutputChannel } from "./main";
1010
import { randomUUID } from "crypto";
1111

@@ -83,22 +83,40 @@ export async function createClient(
8383
debug: run,
8484
};
8585

86-
let initializationOptions = vscode.workspace.getConfiguration("rust-analyzer");
86+
let rawInitializationOptions = vscode.workspace.getConfiguration("rust-analyzer");
8787

8888
if (workspace.kind === "Detached Files") {
89-
initializationOptions = {
89+
rawInitializationOptions = {
9090
detachedFiles: workspace.files.map((file) => file.uri.fsPath),
91-
...initializationOptions,
91+
...rawInitializationOptions,
9292
};
9393
}
9494

95+
const initializationOptions = substituteVSCodeVariables(rawInitializationOptions);
96+
9597
const clientOptions: lc.LanguageClientOptions = {
9698
documentSelector: [{ scheme: "file", language: "rust" }],
9799
initializationOptions,
98100
diagnosticCollectionName: "rustc",
99101
traceOutputChannel: traceOutputChannel(),
100102
outputChannel: outputChannel(),
101103
middleware: {
104+
workspace: {
105+
async configuration(
106+
params: lc.ConfigurationParams,
107+
token: vscode.CancellationToken,
108+
next: lc.ConfigurationRequest.HandlerSignature
109+
) {
110+
const resp = await next(params, token);
111+
if (resp && Array.isArray(resp)) {
112+
return resp.map((val) => {
113+
return substituteVSCodeVariables(val);
114+
});
115+
} else {
116+
return resp;
117+
}
118+
},
119+
},
102120
async provideHover(
103121
document: vscode.TextDocument,
104122
position: vscode.Position,

editors/code/src/config.ts

+57-28
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import path = require("path");
1+
import * as path from "path";
2+
import * as os from "os";
23
import * as vscode from "vscode";
34
import { Env } from "./client";
45
import { log } from "./util";
@@ -187,6 +188,37 @@ export class Config {
187188
}
188189
}
189190

191+
const VarRegex = new RegExp(/\$\{(.+?)\}/g);
192+
193+
export function substituteVSCodeVariableInString(val: string): string {
194+
return val.replaceAll(VarRegex, (substring: string, varName) => {
195+
if (typeof varName === "string") {
196+
return computeVscodeVar(varName) || substring;
197+
} else {
198+
return substring;
199+
}
200+
});
201+
}
202+
203+
export function substituteVSCodeVariables(resp: any): any {
204+
if (typeof resp === "string") {
205+
return substituteVSCodeVariableInString(resp);
206+
} else if (resp && Array.isArray(resp)) {
207+
return resp.map((val) => {
208+
return substituteVSCodeVariables(val);
209+
});
210+
} else if (resp && typeof resp === "object") {
211+
const res: { [key: string]: any } = {};
212+
for (const key in resp) {
213+
const val = resp[key];
214+
res[key] = substituteVSCodeVariables(val);
215+
}
216+
return res;
217+
} else if (typeof resp === "function") {
218+
return null;
219+
}
220+
return resp;
221+
}
190222
export function substituteVariablesInEnv(env: Env): Env {
191223
const missingDeps = new Set<string>();
192224
// vscode uses `env:ENV_NAME` for env vars resolution, and it's easier
@@ -233,7 +265,7 @@ export function substituteVariablesInEnv(env: Env): Env {
233265
}
234266
} else {
235267
envWithDeps[dep] = {
236-
value: computeVscodeVar(dep),
268+
value: computeVscodeVar(dep) || "${" + dep + "}",
237269
deps: [],
238270
};
239271
}
@@ -264,37 +296,34 @@ export function substituteVariablesInEnv(env: Env): Env {
264296
return resolvedEnv;
265297
}
266298

267-
function computeVscodeVar(varName: string): string {
299+
function computeVscodeVar(varName: string): string | null {
300+
const workspaceFolder = () => {
301+
const folders = vscode.workspace.workspaceFolders ?? [];
302+
if (folders.length === 1) {
303+
// TODO: support for remote workspaces?
304+
return folders[0].uri.fsPath;
305+
} else if (folders.length > 1) {
306+
// could use currently opened document to detect the correct
307+
// workspace. However, that would be determined by the document
308+
// user has opened on Editor startup. Could lead to
309+
// unpredictable workspace selection in practice.
310+
// It's better to pick the first one
311+
return folders[0].uri.fsPath;
312+
} else {
313+
// no workspace opened
314+
return "";
315+
}
316+
};
268317
// https://code.visualstudio.com/docs/editor/variables-reference
269318
const supportedVariables: { [k: string]: () => string } = {
270-
workspaceFolder: () => {
271-
const folders = vscode.workspace.workspaceFolders ?? [];
272-
if (folders.length === 1) {
273-
// TODO: support for remote workspaces?
274-
return folders[0].uri.fsPath;
275-
} else if (folders.length > 1) {
276-
// could use currently opened document to detect the correct
277-
// workspace. However, that would be determined by the document
278-
// user has opened on Editor startup. Could lead to
279-
// unpredictable workspace selection in practice.
280-
// It's better to pick the first one
281-
return folders[0].uri.fsPath;
282-
} else {
283-
// no workspace opened
284-
return "";
285-
}
286-
},
319+
workspaceFolder,
287320

288321
workspaceFolderBasename: () => {
289-
const workspaceFolder = computeVscodeVar("workspaceFolder");
290-
if (workspaceFolder) {
291-
return path.basename(workspaceFolder);
292-
} else {
293-
return "";
294-
}
322+
return path.basename(workspaceFolder());
295323
},
296324

297325
cwd: () => process.cwd(),
326+
userHome: () => os.homedir(),
298327

299328
// see
300329
// https://github.com/microsoft/vscode/blob/08ac1bb67ca2459496b272d8f4a908757f24f56f/src/vs/workbench/api/common/extHostVariableResolverService.ts#L81
@@ -308,7 +337,7 @@ function computeVscodeVar(varName: string): string {
308337
if (varName in supportedVariables) {
309338
return supportedVariables[varName]();
310339
} else {
311-
// can't resolve, keep the expression as is
312-
return "${" + varName + "}";
340+
// return "${" + varName + "}";
341+
return null;
313342
}
314343
}

0 commit comments

Comments
 (0)