2022-07-17 10:38:56 -05:00
|
|
|
import * as vscode from "vscode";
|
|
|
|
import * as fspath from "path";
|
|
|
|
import * as fs from "fs";
|
2023-04-26 20:02:38 -05:00
|
|
|
import { CtxInit } from "./ctx";
|
2022-07-17 11:05:55 -05:00
|
|
|
import * as ra from "./lsp_ext";
|
2023-04-26 20:02:38 -05:00
|
|
|
import { FetchDependencyListResult } from "./lsp_ext";
|
2023-06-27 14:03:53 -05:00
|
|
|
import { unwrapUndefinable } from "./undefinable";
|
2022-02-25 19:37:09 -06:00
|
|
|
|
2022-07-17 10:38:56 -05:00
|
|
|
export class RustDependenciesProvider
|
2023-04-26 20:02:38 -05:00
|
|
|
implements vscode.TreeDataProvider<Dependency | DependencyFile>
|
|
|
|
{
|
2023-04-02 20:37:07 -05:00
|
|
|
dependenciesMap: { [id: string]: Dependency | DependencyFile };
|
|
|
|
ctx: CtxInit;
|
2022-02-25 19:37:09 -06:00
|
|
|
|
2023-04-05 12:57:01 -05:00
|
|
|
constructor(ctx: CtxInit) {
|
2022-07-17 11:05:55 -05:00
|
|
|
this.dependenciesMap = {};
|
2022-07-17 11:05:55 -05:00
|
|
|
this.ctx = ctx;
|
2022-02-25 19:37:09 -06:00
|
|
|
}
|
|
|
|
|
2022-07-17 10:38:56 -05:00
|
|
|
private _onDidChangeTreeData: vscode.EventEmitter<
|
|
|
|
Dependency | DependencyFile | undefined | null | void
|
|
|
|
> = new vscode.EventEmitter<Dependency | undefined | null | void>();
|
2022-02-25 19:37:09 -06:00
|
|
|
|
2022-07-17 10:38:56 -05:00
|
|
|
readonly onDidChangeTreeData: vscode.Event<
|
|
|
|
Dependency | DependencyFile | undefined | null | void
|
|
|
|
> = this._onDidChangeTreeData.event;
|
2022-02-25 19:37:09 -06:00
|
|
|
|
|
|
|
getDependency(filePath: string): Dependency | DependencyFile | undefined {
|
|
|
|
return this.dependenciesMap[filePath.toLowerCase()];
|
|
|
|
}
|
|
|
|
|
|
|
|
contains(filePath: string): boolean {
|
|
|
|
return filePath.toLowerCase() in this.dependenciesMap;
|
|
|
|
}
|
|
|
|
|
2023-04-27 14:13:05 -05:00
|
|
|
isInitialized(): boolean {
|
|
|
|
return Object.keys(this.dependenciesMap).length !== 0;
|
|
|
|
}
|
|
|
|
|
2022-02-25 19:37:09 -06:00
|
|
|
refresh(): void {
|
2023-04-05 12:57:01 -05:00
|
|
|
this.dependenciesMap = {};
|
2022-02-25 19:37:09 -06:00
|
|
|
this._onDidChangeTreeData.fire();
|
|
|
|
}
|
|
|
|
|
2022-07-17 10:38:56 -05:00
|
|
|
getParent?(
|
|
|
|
element: Dependency | DependencyFile
|
|
|
|
): vscode.ProviderResult<Dependency | DependencyFile> {
|
2022-02-25 19:37:09 -06:00
|
|
|
if (element instanceof Dependency) return undefined;
|
|
|
|
return element.parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
getTreeItem(element: Dependency | DependencyFile): vscode.TreeItem | Thenable<vscode.TreeItem> {
|
2023-06-27 14:03:53 -05:00
|
|
|
const dependenciesMap = this.dependenciesMap;
|
|
|
|
const elementId = element.id!;
|
|
|
|
if (elementId in dependenciesMap) {
|
|
|
|
const dependency = unwrapUndefinable(dependenciesMap[elementId]);
|
|
|
|
return dependency;
|
|
|
|
}
|
2022-02-25 19:37:09 -06:00
|
|
|
return element;
|
|
|
|
}
|
|
|
|
|
2022-07-17 10:38:56 -05:00
|
|
|
getChildren(
|
|
|
|
element?: Dependency | DependencyFile
|
|
|
|
): vscode.ProviderResult<Dependency[] | DependencyFile[]> {
|
2022-02-25 19:37:09 -06:00
|
|
|
return new Promise((resolve, _reject) => {
|
2023-04-05 12:57:01 -05:00
|
|
|
if (!vscode.workspace.workspaceFolders) {
|
2022-07-17 10:38:56 -05:00
|
|
|
void vscode.window.showInformationMessage("No dependency in empty workspace");
|
2022-02-25 19:37:09 -06:00
|
|
|
return Promise.resolve([]);
|
|
|
|
}
|
|
|
|
if (element) {
|
2022-07-17 10:38:56 -05:00
|
|
|
const files = fs.readdirSync(element.dependencyPath).map((fileName) => {
|
2022-02-25 19:37:09 -06:00
|
|
|
const filePath = fspath.join(element.dependencyPath, fileName);
|
2022-07-17 10:38:56 -05:00
|
|
|
const collapsibleState = fs.lstatSync(filePath).isDirectory()
|
|
|
|
? vscode.TreeItemCollapsibleState.Collapsed
|
2022-07-17 10:38:56 -05:00
|
|
|
: vscode.TreeItemCollapsibleState.None;
|
|
|
|
const dep = new DependencyFile(fileName, filePath, element, collapsibleState);
|
2022-02-25 19:37:09 -06:00
|
|
|
this.dependenciesMap[dep.dependencyPath.toLowerCase()] = dep;
|
|
|
|
return dep;
|
|
|
|
});
|
2022-07-17 10:38:56 -05:00
|
|
|
return resolve(files);
|
2022-02-25 19:37:09 -06:00
|
|
|
} else {
|
|
|
|
return resolve(this.getRootDependencies());
|
|
|
|
}
|
2022-02-25 18:37:55 -06:00
|
|
|
});
|
2022-02-25 19:37:09 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
private async getRootDependencies(): Promise<Dependency[]> {
|
2023-04-04 11:47:01 -05:00
|
|
|
const dependenciesResult: FetchDependencyListResult = await this.ctx.client.sendRequest(
|
|
|
|
ra.fetchDependencyList,
|
2023-04-02 20:37:07 -05:00
|
|
|
{}
|
|
|
|
);
|
2023-04-02 19:58:20 -05:00
|
|
|
const crates = dependenciesResult.crates;
|
2023-04-26 19:54:31 -05:00
|
|
|
|
2023-05-05 07:49:42 -05:00
|
|
|
return crates
|
|
|
|
.map((crate) => {
|
|
|
|
const dep = this.toDep(crate.name || "unknown", crate.version || "", crate.path);
|
|
|
|
this.dependenciesMap[dep.dependencyPath.toLowerCase()] = dep;
|
|
|
|
return dep;
|
|
|
|
})
|
|
|
|
.sort((a, b) => {
|
|
|
|
return a.label.localeCompare(b.label);
|
|
|
|
});
|
2022-02-25 19:37:09 -06:00
|
|
|
}
|
2023-04-02 19:58:20 -05:00
|
|
|
|
2023-04-02 20:37:07 -05:00
|
|
|
private toDep(moduleName: string, version: string, path: string): Dependency {
|
2023-04-27 14:13:05 -05:00
|
|
|
return new Dependency(
|
|
|
|
moduleName,
|
|
|
|
version,
|
|
|
|
vscode.Uri.parse(path).fsPath,
|
|
|
|
vscode.TreeItemCollapsibleState.Collapsed
|
|
|
|
);
|
2023-04-02 20:37:07 -05:00
|
|
|
}
|
2022-02-25 18:37:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
export class Dependency extends vscode.TreeItem {
|
2022-02-25 19:37:09 -06:00
|
|
|
constructor(
|
2023-06-27 13:12:42 -05:00
|
|
|
public override readonly label: string,
|
2022-02-25 19:37:09 -06:00
|
|
|
private version: string,
|
|
|
|
readonly dependencyPath: string,
|
2023-06-27 13:12:42 -05:00
|
|
|
public override readonly collapsibleState: vscode.TreeItemCollapsibleState
|
2022-02-25 19:37:09 -06:00
|
|
|
) {
|
|
|
|
super(label, collapsibleState);
|
|
|
|
this.resourceUri = vscode.Uri.file(dependencyPath);
|
2023-04-27 14:13:05 -05:00
|
|
|
this.id = this.resourceUri.fsPath.toLowerCase();
|
|
|
|
this.description = this.version;
|
2023-04-08 11:07:25 -05:00
|
|
|
if (this.version) {
|
|
|
|
this.tooltip = `${this.label}-${this.version}`;
|
|
|
|
} else {
|
|
|
|
this.tooltip = this.label;
|
|
|
|
}
|
2022-02-25 19:37:09 -06:00
|
|
|
}
|
2022-02-25 18:37:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
export class DependencyFile extends vscode.TreeItem {
|
2022-02-25 19:37:09 -06:00
|
|
|
constructor(
|
2023-06-27 13:12:42 -05:00
|
|
|
override readonly label: string,
|
2022-02-25 19:37:09 -06:00
|
|
|
readonly dependencyPath: string,
|
|
|
|
readonly parent: Dependency | DependencyFile,
|
2023-06-27 13:12:42 -05:00
|
|
|
public override readonly collapsibleState: vscode.TreeItemCollapsibleState
|
2022-02-25 19:37:09 -06:00
|
|
|
) {
|
|
|
|
super(vscode.Uri.file(dependencyPath), collapsibleState);
|
2023-04-27 14:13:05 -05:00
|
|
|
this.id = this.resourceUri!.fsPath.toLowerCase();
|
|
|
|
const isDir = fs.lstatSync(this.resourceUri!.fsPath).isDirectory();
|
2022-02-25 19:37:09 -06:00
|
|
|
if (!isDir) {
|
2023-04-26 19:54:31 -05:00
|
|
|
this.command = {
|
|
|
|
command: "vscode.open",
|
2022-07-17 10:38:56 -05:00
|
|
|
title: "Open File",
|
2023-04-27 14:13:05 -05:00
|
|
|
arguments: [this.resourceUri],
|
2023-04-26 19:54:31 -05:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
2022-02-25 18:37:55 -06:00
|
|
|
}
|
|
|
|
|
2023-04-26 20:02:38 -05:00
|
|
|
export type DependencyId = { id: string };
|