Unnamed repository; edit this file 'description' to name the repository.
improving code to work with multi-workspaces
Bruno Ortiz 2023-05-02
parent 1b8288f · commit 8e687f7
-rw-r--r--crates/ide/src/fetch_crates.rs6
-rw-r--r--crates/ide/src/lib.rs4
-rw-r--r--editors/code/src/commands.ts70
-rw-r--r--editors/code/src/ctx.ts8
-rw-r--r--editors/code/src/dependencies_provider.ts6
-rw-r--r--editors/code/src/util.ts18
6 files changed, 89 insertions, 23 deletions
diff --git a/crates/ide/src/fetch_crates.rs b/crates/ide/src/fetch_crates.rs
index 416082ae73..5750d6b426 100644
--- a/crates/ide/src/fetch_crates.rs
+++ b/crates/ide/src/fetch_crates.rs
@@ -1,9 +1,9 @@
use ide_db::{
base_db::{CrateOrigin, SourceDatabase, SourceDatabaseExt},
- RootDatabase,
+ FxIndexSet, RootDatabase,
};
-#[derive(Debug)]
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CrateInfo {
pub name: String,
pub version: String,
@@ -16,7 +16,7 @@ pub struct CrateInfo {
//
// |===
// image::https://user-images.githubusercontent.com/5748995/229394139-2625beab-f4c9-484b-84ed-ad5dee0b1e1a.png[]
-pub(crate) fn fetch_crates(db: &RootDatabase) -> Vec<CrateInfo> {
+pub(crate) fn fetch_crates(db: &RootDatabase) -> FxIndexSet<CrateInfo> {
let crate_graph = db.crate_graph();
crate_graph
.iter()
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 96adb11dcd..24e2aed65a 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -70,7 +70,7 @@ use ide_db::{
salsa::{self, ParallelDatabase},
CrateOrigin, Env, FileLoader, FileSet, SourceDatabase, VfsPath,
},
- symbol_index, FxHashMap, LineIndexDatabase,
+ symbol_index, FxHashMap, FxIndexSet, LineIndexDatabase,
};
use syntax::SourceFile;
@@ -333,7 +333,7 @@ impl Analysis {
self.with_db(|db| view_crate_graph::view_crate_graph(db, full))
}
- pub fn fetch_crates(&self) -> Cancellable<Vec<CrateInfo>> {
+ pub fn fetch_crates(&self) -> Cancellable<FxIndexSet<CrateInfo>> {
self.with_db(|db| fetch_crates::fetch_crates(db))
}
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index 7fe32754c9..4393d5fccb 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -8,7 +8,15 @@ import { applySnippetWorkspaceEdit, applySnippetTextEdits } from "./snippets";
import { spawnSync } from "child_process";
import { RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run";
import { AstInspector } from "./ast_inspector";
-import { isRustDocument, isCargoTomlDocument, sleep, isRustEditor, RustEditor } from "./util";
+import {
+ isRustDocument,
+ isCargoTomlDocument,
+ sleep,
+ isRustEditor,
+ RustEditor,
+ RustDocument,
+ closeDocument,
+} from "./util";
import { startDebugSession, makeDebugConfig } from "./debug";
import { LanguageClient } from "vscode-languageclient/node";
import { LINKED_COMMANDS } from "./client";
@@ -269,27 +277,63 @@ export function openCargoToml(ctx: CtxInit): Cmd {
export function revealDependency(ctx: CtxInit): Cmd {
return async (editor: RustEditor) => {
- const rootPath = vscode.workspace.workspaceFolders![0].uri.fsPath;
const documentPath = editor.document.uri.fsPath;
- if (documentPath.startsWith(rootPath)) return;
const dep = ctx.dependencies?.getDependency(documentPath);
if (dep) {
await ctx.treeView?.reveal(dep, { select: true, expand: true });
} else {
- let documentPath = editor.document.uri.fsPath;
- const parentChain: DependencyId[] = [{ id: documentPath.toLowerCase() }];
- do {
- documentPath = path.dirname(documentPath);
- parentChain.push({ id: documentPath.toLowerCase() });
- } while (!ctx.dependencies?.contains(documentPath));
- parentChain.reverse();
- for (const idx in parentChain) {
- await ctx.treeView?.reveal(parentChain[idx], { select: true, expand: true });
- }
+ await revealParentChain(editor.document, ctx);
}
};
}
+/**
+ * This function calculates the parent chain of a given file until it reaches it crate root contained in ctx.dependencies.
+ * This is need because the TreeView is Lazy, so at first it only has the root dependencies: For example if we have the following crates:
+ * - core
+ * - alloc
+ * - std
+ *
+ * if I want to reveal alloc/src/str.rs, I have to:
+
+ * 1. reveal every children of alloc
+ * - core
+ * - alloc\
+ * &emsp;|-beches\
+ * &emsp;|-src\
+ * &emsp;|- ...
+ * - std
+ * 2. reveal every children of src:
+ * core
+ * alloc\
+ * &emsp;|-beches\
+ * &emsp;|-src\
+ * &emsp;&emsp;|- lib.rs\
+ * &emsp;&emsp;|- str.rs <------- FOUND IT!\
+ * &emsp;&emsp;|- ...\
+ * &emsp;|- ...\
+ * std
+ */
+async function revealParentChain(document: RustDocument, ctx: CtxInit) {
+ let documentPath = document.uri.fsPath;
+ const maxDepth = documentPath.split(path.sep).length - 1;
+ const parentChain: DependencyId[] = [{ id: documentPath.toLowerCase() }];
+ do {
+ documentPath = path.dirname(documentPath);
+ parentChain.push({ id: documentPath.toLowerCase() });
+ if (parentChain.length >= maxDepth) {
+ // this is an odd case that can happen when we change a crate version but we'd still have
+ // a open file referencing the old version
+ await closeDocument(document);
+ return;
+ }
+ } while (!ctx.dependencies?.contains(documentPath));
+ parentChain.reverse();
+ for (const idx in parentChain) {
+ await ctx.treeView?.reveal(parentChain[idx], { select: true, expand: true });
+ }
+}
+
export async function execRevealDependency(e: RustEditor): Promise<void> {
await vscode.commands.executeCommand("rust-analyzer.revealDependency", e);
}
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts
index 69347522b8..dd2373d584 100644
--- a/editors/code/src/ctx.ts
+++ b/editors/code/src/ctx.ts
@@ -7,6 +7,7 @@ import { Config, prepareVSCodeConfig } from "./config";
import { createClient } from "./client";
import {
executeDiscoverProject,
+ isDocumentInWorkspace,
isRustDocument,
isRustEditor,
LazyOutputChannel,
@@ -277,15 +278,16 @@ export class Ctx {
...this,
client: client,
};
- const rootPath = vscode.workspace.workspaceFolders![0].uri.fsPath;
- this._dependencies = new RustDependenciesProvider(rootPath, ctxInit);
+ this._dependencies = new RustDependenciesProvider(ctxInit);
this._treeView = vscode.window.createTreeView("rustDependencies", {
treeDataProvider: this._dependencies,
showCollapseAll: true,
});
+ this.pushExtCleanup(this._treeView);
vscode.window.onDidChangeActiveTextEditor((e) => {
- if (e && isRustEditor(e)) {
+ // we should skip documents that belong to the current workspace
+ if (e && isRustEditor(e) && !isDocumentInWorkspace(e.document)) {
execRevealDependency(e).catch((reason) => {
void vscode.window.showErrorMessage(`Dependency error: ${reason}`);
});
diff --git a/editors/code/src/dependencies_provider.ts b/editors/code/src/dependencies_provider.ts
index 2e5ea04922..3edbb31681 100644
--- a/editors/code/src/dependencies_provider.ts
+++ b/editors/code/src/dependencies_provider.ts
@@ -15,7 +15,7 @@ export class RustDependenciesProvider
dependenciesMap: { [id: string]: Dependency | DependencyFile };
ctx: CtxInit;
- constructor(private readonly workspaceRoot: string,ctx: CtxInit) {
+ constructor(ctx: CtxInit) {
this.dependenciesMap = {};
this.ctx = ctx;
}
@@ -37,6 +37,7 @@ export class RustDependenciesProvider
}
refresh(): void {
+ this.dependenciesMap = {};
this._onDidChangeTreeData.fire();
}
@@ -56,7 +57,7 @@ export class RustDependenciesProvider
element?: Dependency | DependencyFile
): vscode.ProviderResult<Dependency[] | DependencyFile[]> {
return new Promise((resolve, _reject) => {
- if (!this.workspaceRoot) {
+ if (!vscode.workspace.workspaceFolders) {
void vscode.window.showInformationMessage("No dependency in empty workspace");
return Promise.resolve([]);
}
@@ -108,6 +109,7 @@ export class Dependency extends vscode.TreeItem {
public readonly collapsibleState: vscode.TreeItemCollapsibleState
) {
super(label, collapsibleState);
+ this.id = this.dependencyPath.toLowerCase();
this.tooltip = `${this.label}-${this.version}`;
this.description = this.version;
this.resourceUri = vscode.Uri.file(dependencyPath);
diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts
index 922fbcbcf3..0196b37b8b 100644
--- a/editors/code/src/util.ts
+++ b/editors/code/src/util.ts
@@ -112,6 +112,24 @@ export function isRustEditor(editor: vscode.TextEditor): editor is RustEditor {
return isRustDocument(editor.document);
}
+export function isDocumentInWorkspace(document: RustDocument): boolean {
+ const workspaceFolders = vscode.workspace.workspaceFolders;
+ if (!workspaceFolders) {
+ return false;
+ }
+ for (const folder of workspaceFolders) {
+ if (document.uri.fsPath.startsWith(folder.uri.fsPath)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+export async function closeDocument(document: RustDocument) {
+ await vscode.window.showTextDocument(document, { preview: true, preserveFocus: false });
+ await vscode.commands.executeCommand("workbench.action.closeActiveEditor");
+}
+
export function isValidExecutable(path: string): boolean {
log.debug("Checking availability of a binary at", path);