Skip to content

Commit fb45d2a

Browse files
bors[bot]vsrs
andauthored
Merge #8624
8624: Automatically detect rust library source file map r=vsrs a=vsrs This PR adds a new possible `rust-analyzer.debug.sourceFileMap` value: ```json { "rust-analyzer.debug.sourceFileMap": "auto" } ``` I did not make it the default because it uses two shell calls (`rustc --print sysroot` and `rustc -V -v`). First one can be slow (rust-lang/rustup#783) Fixes #8619 Co-authored-by: vsrs <vit@conrlab.com>
2 parents e2b8773 + 1b4197c commit fb45d2a

File tree

5 files changed

+60
-8
lines changed

5 files changed

+60
-8
lines changed

editors/code/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,9 @@
353353
"Use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)"
354354
]
355355
},
356-
"rust-analyzer.debug.sourceFileMap": {
357-
"type": "object",
356+
"rust-analyzer.debug.sourceFileMap": {
357+
"type": ["object", "string"],
358+
"const": "auto",
358359
"description": "Optional source file mappings passed to the debug engine.",
359360
"default": {
360361
"/rustc/<id>": "${env:USERPROFILE}/.rustup/toolchains/<toolchain-id>/lib/rustlib/src/rust"

editors/code/src/config.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,12 @@ export class Config {
135135
}
136136

137137
get debug() {
138-
// "/rustc/<id>" used by suggestions only.
139-
const { ["/rustc/<id>"]: _, ...sourceFileMap } = this.get<Record<string, string>>("debug.sourceFileMap");
138+
let sourceFileMap = this.get<Record<string, string> | "auto">("debug.sourceFileMap");
139+
if (sourceFileMap !== "auto") {
140+
// "/rustc/<id>" used by suggestions only.
141+
const { ["/rustc/<id>"]: _, ...trimmed } = this.get<Record<string, string>>("debug.sourceFileMap");
142+
sourceFileMap = trimmed;
143+
}
140144

141145
return {
142146
engine: this.get<string>("debug.engine"),

editors/code/src/debug.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as vscode from 'vscode';
33
import * as path from 'path';
44
import * as ra from './lsp_ext';
55

6-
import { Cargo } from './toolchain';
6+
import { Cargo, getRustcId, getSysroot } from './toolchain';
77
import { Ctx } from "./ctx";
88
import { prepareEnv } from "./run";
99

@@ -104,7 +104,17 @@ async function getDebugConfiguration(ctx: Ctx, runnable: ra.Runnable): Promise<v
104104

105105
const executable = await getDebugExecutable(runnable);
106106
const env = prepareEnv(runnable, ctx.config.runnableEnv);
107-
const debugConfig = knownEngines[debugEngine.id](runnable, simplifyPath(executable), env, debugOptions.sourceFileMap);
107+
let sourceFileMap = debugOptions.sourceFileMap;
108+
if (sourceFileMap === "auto") {
109+
// let's try to use the default toolchain
110+
const commitHash = await getRustcId(wsFolder);
111+
const sysroot = await getSysroot(wsFolder);
112+
const rustlib = path.normalize(sysroot + "/lib/rustlib/src/rust");
113+
sourceFileMap = {};
114+
sourceFileMap[`/rustc/${commitHash}/`] = rustlib;
115+
}
116+
117+
const debugConfig = knownEngines[debugEngine.id](runnable, simplifyPath(executable), env, sourceFileMap);
108118
if (debugConfig.type in debugOptions.engineSettings) {
109119
const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type];
110120
for (var key in settingsMap) {

editors/code/src/toolchain.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as path from 'path';
44
import * as fs from 'fs';
55
import * as readline from 'readline';
66
import { OutputChannel } from 'vscode';
7-
import { log, memoize } from './util';
7+
import { execute, log, memoize } from './util';
88

99
interface CompilationArtifact {
1010
fileName: string;
@@ -121,6 +121,24 @@ export class Cargo {
121121
}
122122
}
123123

124+
/** Mirrors `project_model::sysroot::discover_sysroot_dir()` implementation*/
125+
export function getSysroot(dir: string): Promise<string> {
126+
const rustcPath = getPathForExecutable("rustc");
127+
128+
// do not memoize the result because the toolchain may change between runs
129+
return execute(`${rustcPath} --print sysroot`, { cwd: dir });
130+
}
131+
132+
export async function getRustcId(dir: string): Promise<string> {
133+
const rustcPath = getPathForExecutable("rustc");
134+
135+
// do not memoize the result because the toolchain may change between runs
136+
const data = await execute(`${rustcPath} -V -v`, { cwd: dir });
137+
const rx = /commit-hash:\s(.*)$/m.compile();
138+
139+
return rx.exec(data)![1];
140+
}
141+
124142
/** Mirrors `toolchain::cargo()` implementation */
125143
export function cargoPath(): string {
126144
return getPathForExecutable("cargo");

editors/code/src/util.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as lc from "vscode-languageclient/node";
22
import * as vscode from "vscode";
33
import { strict as nativeAssert } from "assert";
4-
import { spawnSync } from "child_process";
4+
import { exec, ExecOptions, spawnSync } from "child_process";
55
import { inspect } from "util";
66

77
export function assert(condition: boolean, explanation: string): asserts condition {
@@ -141,3 +141,22 @@ export function memoize<Ret, TThis, Param extends string>(func: (this: TThis, ar
141141
return result;
142142
};
143143
}
144+
145+
/** Awaitable wrapper around `child_process.exec` */
146+
export function execute(command: string, options: ExecOptions): Promise<string> {
147+
return new Promise((resolve, reject) => {
148+
exec(command, options, (err, stdout, stderr) => {
149+
if (err) {
150+
reject(err);
151+
return;
152+
}
153+
154+
if (stderr) {
155+
reject(new Error(stderr));
156+
return;
157+
}
158+
159+
resolve(stdout.trimEnd());
160+
});
161+
});
162+
}

0 commit comments

Comments
 (0)