Skip to content

Commit e86bac9

Browse files
committed
Auto merge of rust-lang#14019 - Veykril:ts-bin-og, r=Veykril
Substitute VSCode variables more generally
2 parents cd4ac0d + ec94760 commit e86bac9

File tree

5 files changed

+87
-85
lines changed

5 files changed

+87
-85
lines changed

editors/code/src/bootstrap.ts

Lines changed: 47 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as vscode from "vscode";
22
import * as os from "os";
3-
import { Config, substituteVSCodeVariables } from "./config";
3+
import { Config } from "./config";
44
import { log, isValidExecutable } from "./util";
55
import { PersistentState } from "./persistent_state";
66
import { exec } from "child_process";
@@ -31,58 +31,12 @@ export async function bootstrap(
3131

3232
return path;
3333
}
34-
35-
async function patchelf(dest: vscode.Uri): Promise<void> {
36-
await vscode.window.withProgress(
37-
{
38-
location: vscode.ProgressLocation.Notification,
39-
title: "Patching rust-analyzer for NixOS",
40-
},
41-
async (progress, _) => {
42-
const expression = `
43-
{srcStr, pkgs ? import <nixpkgs> {}}:
44-
pkgs.stdenv.mkDerivation {
45-
name = "rust-analyzer";
46-
src = /. + srcStr;
47-
phases = [ "installPhase" "fixupPhase" ];
48-
installPhase = "cp $src $out";
49-
fixupPhase = ''
50-
chmod 755 $out
51-
patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out
52-
'';
53-
}
54-
`;
55-
const origFile = vscode.Uri.file(dest.fsPath + "-orig");
56-
await vscode.workspace.fs.rename(dest, origFile, { overwrite: true });
57-
try {
58-
progress.report({ message: "Patching executable", increment: 20 });
59-
await new Promise((resolve, reject) => {
60-
const handle = exec(
61-
`nix-build -E - --argstr srcStr '${origFile.fsPath}' -o '${dest.fsPath}'`,
62-
(err, stdout, stderr) => {
63-
if (err != null) {
64-
reject(Error(stderr));
65-
} else {
66-
resolve(stdout);
67-
}
68-
}
69-
);
70-
handle.stdin?.write(expression);
71-
handle.stdin?.end();
72-
});
73-
} finally {
74-
await vscode.workspace.fs.delete(origFile);
75-
}
76-
}
77-
);
78-
}
79-
8034
async function getServer(
8135
context: vscode.ExtensionContext,
8236
config: Config,
8337
state: PersistentState
8438
): Promise<string | undefined> {
85-
const explicitPath = serverPath(config);
39+
const explicitPath = process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath;
8640
if (explicitPath) {
8741
if (explicitPath.startsWith("~/")) {
8842
return os.homedir() + explicitPath.slice("~".length);
@@ -131,9 +85,6 @@ async function getServer(
13185
);
13286
return undefined;
13387
}
134-
function serverPath(config: Config): string | null {
135-
return process.env.__RA_LSP_SERVER_DEBUG ?? substituteVSCodeVariables(config.serverPath);
136-
}
13788

13889
async function isNixOs(): Promise<boolean> {
13990
try {
@@ -146,3 +97,48 @@ async function isNixOs(): Promise<boolean> {
14697
return false;
14798
}
14899
}
100+
101+
async function patchelf(dest: vscode.Uri): Promise<void> {
102+
await vscode.window.withProgress(
103+
{
104+
location: vscode.ProgressLocation.Notification,
105+
title: "Patching rust-analyzer for NixOS",
106+
},
107+
async (progress, _) => {
108+
const expression = `
109+
{srcStr, pkgs ? import <nixpkgs> {}}:
110+
pkgs.stdenv.mkDerivation {
111+
name = "rust-analyzer";
112+
src = /. + srcStr;
113+
phases = [ "installPhase" "fixupPhase" ];
114+
installPhase = "cp $src $out";
115+
fixupPhase = ''
116+
chmod 755 $out
117+
patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out
118+
'';
119+
}
120+
`;
121+
const origFile = vscode.Uri.file(dest.fsPath + "-orig");
122+
await vscode.workspace.fs.rename(dest, origFile, { overwrite: true });
123+
try {
124+
progress.report({ message: "Patching executable", increment: 20 });
125+
await new Promise((resolve, reject) => {
126+
const handle = exec(
127+
`nix-build -E - --argstr srcStr '${origFile.fsPath}' -o '${dest.fsPath}'`,
128+
(err, stdout, stderr) => {
129+
if (err != null) {
130+
reject(Error(stderr));
131+
} else {
132+
resolve(stdout);
133+
}
134+
}
135+
);
136+
handle.stdin?.write(expression);
137+
handle.stdin?.end();
138+
});
139+
} finally {
140+
await vscode.workspace.fs.delete(origFile);
141+
}
142+
}
143+
);
144+
}

editors/code/src/config.ts

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import * as path from "path";
1+
import * as Is from "vscode-languageclient/lib/common/utils/is";
22
import * as os from "os";
3+
import * as path from "path";
34
import * as vscode from "vscode";
45
import { Env } from "./client";
56
import { log } from "./util";
@@ -47,7 +48,7 @@ export class Config {
4748
}
4849

4950
private refreshLogging() {
50-
log.setEnabled(this.traceExtension);
51+
log.setEnabled(this.traceExtension ?? false);
5152
log.info("Extension version:", this.package.version);
5253

5354
const cfg = Object.entries(this.cfg).filter(([_, val]) => !(val instanceof Function));
@@ -163,18 +164,24 @@ export class Config {
163164
* ```
164165
* So this getter handles this quirk by not requiring the caller to use postfix `!`
165166
*/
166-
private get<T>(path: string): T {
167-
return this.cfg.get<T>(path)!;
167+
private get<T>(path: string): T | undefined {
168+
return substituteVSCodeVariables(this.cfg.get<T>(path));
168169
}
169170

170171
get serverPath() {
171172
return this.get<null | string>("server.path") ?? this.get<null | string>("serverPath");
172173
}
174+
173175
get serverExtraEnv(): Env {
174176
const extraEnv =
175177
this.get<{ [key: string]: string | number } | null>("server.extraEnv") ?? {};
176-
return Object.fromEntries(
177-
Object.entries(extraEnv).map(([k, v]) => [k, typeof v !== "string" ? v.toString() : v])
178+
return substituteVariablesInEnv(
179+
Object.fromEntries(
180+
Object.entries(extraEnv).map(([k, v]) => [
181+
k,
182+
typeof v !== "string" ? v.toString() : v,
183+
])
184+
)
178185
);
179186
}
180187
get traceExtension() {
@@ -216,13 +223,13 @@ export class Config {
216223
if (sourceFileMap !== "auto") {
217224
// "/rustc/<id>" used by suggestions only.
218225
const { ["/rustc/<id>"]: _, ...trimmed } =
219-
this.get<Record<string, string>>("debug.sourceFileMap");
226+
this.get<Record<string, string>>("debug.sourceFileMap") ?? {};
220227
sourceFileMap = trimmed;
221228
}
222229

223230
return {
224231
engine: this.get<string>("debug.engine"),
225-
engineSettings: this.get<object>("debug.engineSettings"),
232+
engineSettings: this.get<object>("debug.engineSettings") ?? {},
226233
openDebugPane: this.get<boolean>("debug.openDebugPane"),
227234
sourceFileMap: sourceFileMap,
228235
};
@@ -247,37 +254,27 @@ export class Config {
247254
}
248255
}
249256

250-
const VarRegex = new RegExp(/\$\{(.+?)\}/g);
251-
252-
export function substituteVSCodeVariableInString(val: string): string {
253-
return val.replace(VarRegex, (substring: string, varName) => {
254-
if (typeof varName === "string") {
255-
return computeVscodeVar(varName) || substring;
256-
} else {
257-
return substring;
258-
}
259-
});
260-
}
261-
262-
export function substituteVSCodeVariables(resp: any): any {
263-
if (typeof resp === "string") {
264-
return substituteVSCodeVariableInString(resp);
265-
} else if (resp && Array.isArray(resp)) {
257+
export function substituteVSCodeVariables<T>(resp: T): T {
258+
if (Is.string(resp)) {
259+
return substituteVSCodeVariableInString(resp) as T;
260+
} else if (resp && Is.array<any>(resp)) {
266261
return resp.map((val) => {
267262
return substituteVSCodeVariables(val);
268-
});
263+
}) as T;
269264
} else if (resp && typeof resp === "object") {
270265
const res: { [key: string]: any } = {};
271266
for (const key in resp) {
272267
const val = resp[key];
273268
res[key] = substituteVSCodeVariables(val);
274269
}
275-
return res;
276-
} else if (typeof resp === "function") {
277-
return null;
270+
return res as T;
271+
} else if (Is.func(resp)) {
272+
throw new Error("Unexpected function type in substitution");
278273
}
279274
return resp;
280275
}
276+
277+
// FIXME: Merge this with `substituteVSCodeVariables` above
281278
export function substituteVariablesInEnv(env: Env): Env {
282279
const missingDeps = new Set<string>();
283280
// vscode uses `env:ENV_NAME` for env vars resolution, and it's easier
@@ -355,6 +352,17 @@ export function substituteVariablesInEnv(env: Env): Env {
355352
return resolvedEnv;
356353
}
357354

355+
const VarRegex = new RegExp(/\$\{(.+?)\}/g);
356+
function substituteVSCodeVariableInString(val: string): string {
357+
return val.replace(VarRegex, (substring: string, varName) => {
358+
if (Is.string(varName)) {
359+
return computeVscodeVar(varName) || substring;
360+
} else {
361+
return substring;
362+
}
363+
});
364+
}
365+
358366
function computeVscodeVar(varName: string): string | null {
359367
const workspaceFolder = () => {
360368
const folders = vscode.workspace.workspaceFolders ?? [];

editors/code/src/ctx.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as vscode from "vscode";
22
import * as lc from "vscode-languageclient/node";
33
import * as ra from "./lsp_ext";
44

5-
import { Config, substituteVariablesInEnv, substituteVSCodeVariables } from "./config";
5+
import { Config, substituteVSCodeVariables } from "./config";
66
import { createClient } from "./client";
77
import { isRustDocument, isRustEditor, log, RustEditor } from "./util";
88
import { ServerStatusParams } from "./lsp_ext";
@@ -152,9 +152,7 @@ export class Ctx {
152152
throw new Error(message);
153153
}
154154
);
155-
const newEnv = substituteVariablesInEnv(
156-
Object.assign({}, process.env, this.config.serverExtraEnv)
157-
);
155+
const newEnv = Object.assign({}, process.env, this.config.serverExtraEnv);
158156
const run: lc.Executable = {
159157
command: this._serverPath,
160158
options: { env: newEnv },

editors/code/src/debug.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ async function getDebugConfiguration(
8484
debugEngine = vscode.extensions.getExtension(engineId);
8585
if (debugEngine) break;
8686
}
87-
} else {
87+
} else if (debugOptions.engine) {
8888
debugEngine = vscode.extensions.getExtension(debugOptions.engine);
8989
}
9090

editors/code/src/util.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export function isValidExecutable(path: string): boolean {
117117

118118
const res = spawnSync(path, ["--version"], { encoding: "utf8" });
119119

120-
const printOutput = res.error && (res.error as any).code !== "ENOENT" ? log.warn : log.debug;
120+
const printOutput = res.error ? log.warn : log.info;
121121
printOutput(path, "--version:", res);
122122

123123
return res.status === 0;

0 commit comments

Comments
 (0)