Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--editors/code/src/bootstrap.ts17
-rw-r--r--editors/code/tests/unit/bootstrap.test.ts71
2 files changed, 85 insertions, 3 deletions
diff --git a/editors/code/src/bootstrap.ts b/editors/code/src/bootstrap.ts
index ca5b7e3ec7..440f21cbe3 100644
--- a/editors/code/src/bootstrap.ts
+++ b/editors/code/src/bootstrap.ts
@@ -176,14 +176,24 @@ async function fileExists(uri: vscode.Uri) {
);
}
+// Captures the elements of a `components` array. They are matched with `[^\]]` rather than `.`
+// so that the array may be spread over several lines, which is just as valid TOML as keeping it
+// on one, while still stopping at the end of the array.
+const COMPONENTS_RE = /components\s*=\s*\[(?<components>[^\]]*)\]/;
+// TOML strings come in both quote flavours.
+const RA_COMPONENT_RE = /["']rust-analyzer["']/;
+
+function declaresRaComponent(toolchainFileContents: string): boolean {
+ const components = toolchainFileContents.match(COMPONENTS_RE)?.groups?.["components"];
+ return components !== undefined && RA_COMPONENT_RE.test(components);
+}
+
async function hasToolchainFileWithRaDeclared(uri: vscode.Uri): Promise<boolean> {
try {
const toolchainFileContents = new TextDecoder().decode(
await vscode.workspace.fs.readFile(uri),
);
- return (
- toolchainFileContents.match(/components\s*=\s*\[.*"rust-analyzer".*\]/g)?.length === 1
- );
+ return declaresRaComponent(toolchainFileContents);
} catch (_) {
return false;
}
@@ -296,6 +306,7 @@ async function patchelf(dest: vscode.Uri): Promise<void> {
}
export const _private = {
+ declaresRaComponent,
earliestToolchainPath,
orderFromPath,
};
diff --git a/editors/code/tests/unit/bootstrap.test.ts b/editors/code/tests/unit/bootstrap.test.ts
index baabf4f897..259428da41 100644
--- a/editors/code/tests/unit/bootstrap.test.ts
+++ b/editors/code/tests/unit/bootstrap.test.ts
@@ -93,4 +93,75 @@ export async function getTests(ctx: Context) {
);
});
});
+
+ await ctx.suite("Bootstrap/Detect RA component in toolchain file", (suite) => {
+ suite.addTest("Single line components array", async () => {
+ assert.ok(
+ _private.declaresRaComponent(
+ `[toolchain]
+channel = "1.88"
+components = ["cargo", "rust-analyzer", "rustfmt"]
+`,
+ ),
+ );
+ });
+
+ suite.addTest("Multi line components array", async () => {
+ assert.ok(
+ _private.declaresRaComponent(
+ `[toolchain]
+channel = "1.88"
+components = [
+ "cargo",
+ "rust-analyzer",
+ "rustfmt",
+]
+profile = "default"
+`,
+ ),
+ );
+ });
+
+ suite.addTest("Components array with literal strings", async () => {
+ assert.ok(_private.declaresRaComponent(`components = ['cargo', 'rust-analyzer']`));
+ });
+
+ suite.addTest("Components array without RA", async () => {
+ assert.ok(
+ !_private.declaresRaComponent(
+ `[toolchain]
+channel = "1.88"
+components = [
+ "cargo",
+ "rustfmt",
+]
+`,
+ ),
+ );
+ });
+
+ suite.addTest("No components array", async () => {
+ assert.ok(
+ !_private.declaresRaComponent(
+ `[toolchain]
+channel = "1.88"
+`,
+ ),
+ );
+ });
+
+ suite.addTest("RA mentioned outside the components array", async () => {
+ assert.ok(
+ !_private.declaresRaComponent(
+ `[toolchain]
+channel = "1.88"
+components = [
+ "cargo",
+]
+# add "rust-analyzer" here to use the matching server
+`,
+ ),
+ );
+ });
+ });
}