about summary refs log tree commit diff
path: root/editors/code/src/ctx.ts
diff options
context:
space:
mode:
authorDavid Barsky <me@davidbarsky.com>2023-03-09 15:06:26 -0500
committerDavid Barsky <me@davidbarsky.com>2023-03-13 13:30:18 -0400
commit8af3d6367ecead0abf80e697176f697d97c25215 (patch)
tree54a28c70aadc17ddc93991fb4344a516ae6cba29 /editors/code/src/ctx.ts
parent95497533524537b1cc7a2870ce94b0b14503be8b (diff)
downloadrust-8af3d6367ecead0abf80e697176f697d97c25215.tar.gz
rust-8af3d6367ecead0abf80e697176f697d97c25215.zip
This commit add Cargo-style project discovery for Buck and Bazel users.
This feature requires the user to add a command that generates a
`rust-project.json` from a set of files. Project discovery can be invoked
in two ways:

1. At extension activation time, which includes the generated
   `rust-project.json` as part of the linkedProjects argument in
    InitializeParams
2. Through a new command titled "Add current file to workspace", which
   makes use of a new, rust-analyzer specific LSP request that adds
   the workspace without erasing any existing workspaces.

I think that the command-running functionality _could_ merit being
placed into its own extension (and expose it via extension contribution
points), if only provide build-system idiomatic progress reporting and
status handling, but I haven't (yet) made an extension that does this.
Diffstat (limited to 'editors/code/src/ctx.ts')
-rw-r--r--editors/code/src/ctx.ts42
1 files changed, 31 insertions, 11 deletions
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts
index 1708d47cee7..ba2d4e97af1 100644
--- a/editors/code/src/ctx.ts
+++ b/editors/code/src/ctx.ts
@@ -4,10 +4,11 @@ import * as ra from "./lsp_ext";
 
 import { Config, substituteVSCodeVariables } from "./config";
 import { createClient } from "./client";
-import { isRustDocument, isRustEditor, LazyOutputChannel, log, RustEditor } from "./util";
+import { executeDiscoverProject, isRustDocument, isRustEditor, LazyOutputChannel, log, RustEditor } from "./util";
 import { ServerStatusParams } from "./lsp_ext";
 import { PersistentState } from "./persistent_state";
 import { bootstrap } from "./bootstrap";
+import { ExecOptions } from "child_process";
 
 // We only support local folders, not eg. Live Share (`vlsl:` scheme), so don't activate if
 // only those are in use. We use "Empty" to represent these scenarios
@@ -16,12 +17,12 @@ import { bootstrap } from "./bootstrap";
 export type Workspace =
     | { kind: "Empty" }
     | {
-          kind: "Workspace Folder";
-      }
+        kind: "Workspace Folder";
+    }
     | {
-          kind: "Detached Files";
-          files: vscode.TextDocument[];
-      };
+        kind: "Detached Files";
+        files: vscode.TextDocument[];
+    };
 
 export function fetchWorkspace(): Workspace {
     const folders = (vscode.workspace.workspaceFolders || []).filter(
@@ -35,12 +36,19 @@ export function fetchWorkspace(): Workspace {
         ? rustDocuments.length === 0
             ? { kind: "Empty" }
             : {
-                  kind: "Detached Files",
-                  files: rustDocuments,
-              }
+                kind: "Detached Files",
+                files: rustDocuments,
+            }
         : { kind: "Workspace Folder" };
 }
 
+export async function discoverWorkspace(files: readonly vscode.TextDocument[], command: string[], options: ExecOptions): Promise<JsonProject> {
+    const paths = files.map((f) => f.uri.fsPath).join(" ");
+    const joinedCommand = command.join(" ");
+    const data = await executeDiscoverProject(`${joinedCommand} -- ${paths}`, options);
+    return JSON.parse(data) as JsonProject;
+}
+
 export type CommandFactory = {
     enabled: (ctx: CtxInit) => Cmd;
     disabled?: (ctx: Ctx) => Cmd;
@@ -63,6 +71,7 @@ export class Ctx {
     private state: PersistentState;
     private commandFactories: Record<string, CommandFactory>;
     private commandDisposables: Disposable[];
+    private discoveredWorkspaces: JsonProject[] | undefined;
 
     get client() {
         return this._client;
@@ -71,7 +80,7 @@ export class Ctx {
     constructor(
         readonly extCtx: vscode.ExtensionContext,
         commandFactories: Record<string, CommandFactory>,
-        workspace: Workspace
+        workspace: Workspace,
     ) {
         extCtx.subscriptions.push(this);
         this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
@@ -169,7 +178,18 @@ export class Ctx {
                 };
             }
 
-            const initializationOptions = substituteVSCodeVariables(rawInitializationOptions);
+            const discoverProjectCommand = this.config.discoverProjectCommand;
+            if (discoverProjectCommand) {
+                let workspaces: JsonProject[] = await Promise.all(vscode.workspace.workspaceFolders!.map(async (folder): Promise<JsonProject> => {
+                    return discoverWorkspace(vscode.workspace.textDocuments, discoverProjectCommand, { cwd: folder.uri.fsPath });
+                }));
+
+                this.discoveredWorkspaces = workspaces;
+            }
+
+            let initializationOptions = substituteVSCodeVariables(rawInitializationOptions);
+            // this appears to be load-bearing, for better or worse.
+            await initializationOptions.update('linkedProjects', this.discoveredWorkspaces)
 
             this._client = await createClient(
                 this.traceOutputChannel,