improving code to work with multi-workspaces
This commit is contained in:
parent
1b8288ff96
commit
8e687f7afb
@ -1,9 +1,9 @@
|
|||||||
use ide_db::{
|
use ide_db::{
|
||||||
base_db::{CrateOrigin, SourceDatabase, SourceDatabaseExt},
|
base_db::{CrateOrigin, SourceDatabase, SourceDatabaseExt},
|
||||||
RootDatabase,
|
FxIndexSet, RootDatabase,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct CrateInfo {
|
pub struct CrateInfo {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub version: 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[]
|
// 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();
|
let crate_graph = db.crate_graph();
|
||||||
crate_graph
|
crate_graph
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -70,7 +70,7 @@ use ide_db::{
|
|||||||
salsa::{self, ParallelDatabase},
|
salsa::{self, ParallelDatabase},
|
||||||
CrateOrigin, Env, FileLoader, FileSet, SourceDatabase, VfsPath,
|
CrateOrigin, Env, FileLoader, FileSet, SourceDatabase, VfsPath,
|
||||||
},
|
},
|
||||||
symbol_index, FxHashMap, LineIndexDatabase,
|
symbol_index, FxHashMap, FxIndexSet, LineIndexDatabase,
|
||||||
};
|
};
|
||||||
use syntax::SourceFile;
|
use syntax::SourceFile;
|
||||||
|
|
||||||
@ -333,7 +333,7 @@ impl Analysis {
|
|||||||
self.with_db(|db| view_crate_graph::view_crate_graph(db, full))
|
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))
|
self.with_db(|db| fetch_crates::fetch_crates(db))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,15 @@ import { applySnippetWorkspaceEdit, applySnippetTextEdits } from "./snippets";
|
|||||||
import { spawnSync } from "child_process";
|
import { spawnSync } from "child_process";
|
||||||
import { RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run";
|
import { RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run";
|
||||||
import { AstInspector } from "./ast_inspector";
|
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 { startDebugSession, makeDebugConfig } from "./debug";
|
||||||
import { LanguageClient } from "vscode-languageclient/node";
|
import { LanguageClient } from "vscode-languageclient/node";
|
||||||
import { LINKED_COMMANDS } from "./client";
|
import { LINKED_COMMANDS } from "./client";
|
||||||
@ -269,27 +277,63 @@ export function openCargoToml(ctx: CtxInit): Cmd {
|
|||||||
|
|
||||||
export function revealDependency(ctx: CtxInit): Cmd {
|
export function revealDependency(ctx: CtxInit): Cmd {
|
||||||
return async (editor: RustEditor) => {
|
return async (editor: RustEditor) => {
|
||||||
const rootPath = vscode.workspace.workspaceFolders![0].uri.fsPath;
|
|
||||||
const documentPath = editor.document.uri.fsPath;
|
const documentPath = editor.document.uri.fsPath;
|
||||||
if (documentPath.startsWith(rootPath)) return;
|
|
||||||
const dep = ctx.dependencies?.getDependency(documentPath);
|
const dep = ctx.dependencies?.getDependency(documentPath);
|
||||||
if (dep) {
|
if (dep) {
|
||||||
await ctx.treeView?.reveal(dep, { select: true, expand: true });
|
await ctx.treeView?.reveal(dep, { select: true, expand: true });
|
||||||
} else {
|
} else {
|
||||||
let documentPath = editor.document.uri.fsPath;
|
await revealParentChain(editor.document, ctx);
|
||||||
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 });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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\
|
||||||
|
*  |-beches\
|
||||||
|
*  |-src\
|
||||||
|
*  |- ...
|
||||||
|
* - std
|
||||||
|
* 2. reveal every children of src:
|
||||||
|
* core
|
||||||
|
* alloc\
|
||||||
|
*  |-beches\
|
||||||
|
*  |-src\
|
||||||
|
*   |- lib.rs\
|
||||||
|
*   |- str.rs <------- FOUND IT!\
|
||||||
|
*   |- ...\
|
||||||
|
*  |- ...\
|
||||||
|
* 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> {
|
export async function execRevealDependency(e: RustEditor): Promise<void> {
|
||||||
await vscode.commands.executeCommand("rust-analyzer.revealDependency", e);
|
await vscode.commands.executeCommand("rust-analyzer.revealDependency", e);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import { Config, prepareVSCodeConfig } from "./config";
|
|||||||
import { createClient } from "./client";
|
import { createClient } from "./client";
|
||||||
import {
|
import {
|
||||||
executeDiscoverProject,
|
executeDiscoverProject,
|
||||||
|
isDocumentInWorkspace,
|
||||||
isRustDocument,
|
isRustDocument,
|
||||||
isRustEditor,
|
isRustEditor,
|
||||||
LazyOutputChannel,
|
LazyOutputChannel,
|
||||||
@ -277,15 +278,16 @@ export class Ctx {
|
|||||||
...this,
|
...this,
|
||||||
client: client,
|
client: client,
|
||||||
};
|
};
|
||||||
const rootPath = vscode.workspace.workspaceFolders![0].uri.fsPath;
|
this._dependencies = new RustDependenciesProvider(ctxInit);
|
||||||
this._dependencies = new RustDependenciesProvider(rootPath, ctxInit);
|
|
||||||
this._treeView = vscode.window.createTreeView("rustDependencies", {
|
this._treeView = vscode.window.createTreeView("rustDependencies", {
|
||||||
treeDataProvider: this._dependencies,
|
treeDataProvider: this._dependencies,
|
||||||
showCollapseAll: true,
|
showCollapseAll: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.pushExtCleanup(this._treeView);
|
||||||
vscode.window.onDidChangeActiveTextEditor((e) => {
|
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) => {
|
execRevealDependency(e).catch((reason) => {
|
||||||
void vscode.window.showErrorMessage(`Dependency error: ${reason}`);
|
void vscode.window.showErrorMessage(`Dependency error: ${reason}`);
|
||||||
});
|
});
|
||||||
|
@ -15,7 +15,7 @@ export class RustDependenciesProvider
|
|||||||
dependenciesMap: { [id: string]: Dependency | DependencyFile };
|
dependenciesMap: { [id: string]: Dependency | DependencyFile };
|
||||||
ctx: CtxInit;
|
ctx: CtxInit;
|
||||||
|
|
||||||
constructor(private readonly workspaceRoot: string,ctx: CtxInit) {
|
constructor(ctx: CtxInit) {
|
||||||
this.dependenciesMap = {};
|
this.dependenciesMap = {};
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
}
|
}
|
||||||
@ -37,6 +37,7 @@ export class RustDependenciesProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
refresh(): void {
|
refresh(): void {
|
||||||
|
this.dependenciesMap = {};
|
||||||
this._onDidChangeTreeData.fire();
|
this._onDidChangeTreeData.fire();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +57,7 @@ export class RustDependenciesProvider
|
|||||||
element?: Dependency | DependencyFile
|
element?: Dependency | DependencyFile
|
||||||
): vscode.ProviderResult<Dependency[] | DependencyFile[]> {
|
): vscode.ProviderResult<Dependency[] | DependencyFile[]> {
|
||||||
return new Promise((resolve, _reject) => {
|
return new Promise((resolve, _reject) => {
|
||||||
if (!this.workspaceRoot) {
|
if (!vscode.workspace.workspaceFolders) {
|
||||||
void vscode.window.showInformationMessage("No dependency in empty workspace");
|
void vscode.window.showInformationMessage("No dependency in empty workspace");
|
||||||
return Promise.resolve([]);
|
return Promise.resolve([]);
|
||||||
}
|
}
|
||||||
@ -108,6 +109,7 @@ export class Dependency extends vscode.TreeItem {
|
|||||||
public readonly collapsibleState: vscode.TreeItemCollapsibleState
|
public readonly collapsibleState: vscode.TreeItemCollapsibleState
|
||||||
) {
|
) {
|
||||||
super(label, collapsibleState);
|
super(label, collapsibleState);
|
||||||
|
this.id = this.dependencyPath.toLowerCase();
|
||||||
this.tooltip = `${this.label}-${this.version}`;
|
this.tooltip = `${this.label}-${this.version}`;
|
||||||
this.description = this.version;
|
this.description = this.version;
|
||||||
this.resourceUri = vscode.Uri.file(dependencyPath);
|
this.resourceUri = vscode.Uri.file(dependencyPath);
|
||||||
|
@ -112,6 +112,24 @@ export function isRustEditor(editor: vscode.TextEditor): editor is RustEditor {
|
|||||||
return isRustDocument(editor.document);
|
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 {
|
export function isValidExecutable(path: string): boolean {
|
||||||
log.debug("Checking availability of a binary at", path);
|
log.debug("Checking availability of a binary at", path);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user