Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@
"type": "boolean",
"description": "Synchronize dependency viewer selection with folder explorer",
"default": true
},
"java.dependency.packagePresentation": {
"type": "string",
"enum":["flat","hierarchical"],
"description": "Set the presentation model of packages",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Package presentation mode: flat or hierarchical

"default": "flat"
}
}
},
Expand Down
66 changes: 66 additions & 0 deletions src/java/packageTreeNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

import { INodeData, NodeKind } from "./nodeData";

export class PackageTreeNode {
public name: string;
public fullName: string;
public childs: PackageTreeNode[] = [];
public isPackage: boolean = false;

constructor(packageName: string, parentName: string) {
const splitPackageName = packageName.split(".");
this.name = splitPackageName[0];
this.fullName = parentName === "" ? this.name : parentName + "." + this.name;
if (splitPackageName.length > 1) {
this.childs.push(new PackageTreeNode(packageName.substring(this.name.length + 1), this.fullName));
} else {
this.isPackage = true;
}
}

public addPackage(packageName: string): void {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addPackage constructor compressTree should be better organized to clearance to detect tree structures based on a list of packages:
a.b
a.b.c.d
a.b.c.d.e

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second this. Currently, the compressTree will not work for this case.

const splitPackageName = packageName.split(".");
const firstSubName = splitPackageName[0];
const restname = packageName.substring(firstSubName.length + 1);

let contains: boolean = false;
this.childs.forEach((child) => {
if (child.name === firstSubName) {
if (restname === "") {
child.isPackage = true;
} else {
child.addPackage(restname);
}
contains = true;
}
});
if (!contains) {
this.childs.push(new PackageTreeNode(packageName, this.fullName));
}
}

public compressTree(): void {
Comment thread
Flanker32 marked this conversation as resolved.
Outdated
// Don't compress the root node
while (this.name !== "" && this.childs.length === 1 && !this.isPackage) {
const child = this.childs[0];
this.fullName = this.fullName + "." + child.name;
this.name = this.name + "." + child.name;
this.childs = child.childs;
this.isPackage = child.isPackage;
}
this.childs.forEach((child) => child.compressTree());
}

public getNodeDataFromPackageTreeNode(nodeData: INodeData): INodeData {
return {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically, this is an adapter that we can apply here.

name: this.name,
moduleName: nodeData.moduleName,
path: nodeData.path,
uri: null,
kind: NodeKind.PackageRoot,
children: null,
};
}
}
4 changes: 4 additions & 0 deletions src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,9 @@ export class Settings {
return this._depdendencyConfig.get("syncWithFolderExplorer");
}

public static isHierarchicalView(): boolean {
return this._depdendencyConfig.get("packagePresentation") === "hierarchical";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should avoid to use the configuration directly since the config may change at runtime, in your impl, change of this options will take effective on next update. see https://github.com/Microsoft/vscode-java-debug/blob/bcd69b52e4d941323cae662a154afd2a7852f43d/src/debugCodeLensProvider.ts#L38

}

private static _depdendencyConfig: WorkspaceConfiguration = workspace.getConfiguration("java.dependency");
}
4 changes: 2 additions & 2 deletions src/views/containerNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Jdtls } from "../java/jdtls";
import { INodeData, NodeKind } from "../java/nodeData";
import { DataNode } from "./dataNode";
import { ExplorerNode } from "./explorerNode";
import { PackageRootNode } from "./packageRootNode";
import { NodeFactory } from "./nodeFactory";
import { ProjectNode } from "./projectNode";

export class ContainerNode extends DataNode {
Expand All @@ -21,7 +21,7 @@ export class ContainerNode extends DataNode {
if (this.nodeData.children && this.nodeData.children.length) {
this.sort();
this.nodeData.children.forEach((classpathNode) => {
result.push(new PackageRootNode(classpathNode, this, this._project));
result.push(NodeFactory.createPackageRootNode(classpathNode, this, this._project));
});
}
return result;
Expand Down
7 changes: 2 additions & 5 deletions src/views/dependencyExplorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
// Licensed under the MIT license.

import { ExtensionContext, ProviderResult, TextEditor, TreeView, TreeViewVisibilityChangeEvent, Uri, window } from "vscode";
import { Jdtls } from "../java/jdtls";
import { INodeData } from "../java/nodeData";
import { Settings } from "../settings";
import { Utility } from "../utility";
import { DataNode } from "./dataNode";
import { DependencyDataProvider } from "./dependencyDataProvider";
import { ExplorerNode } from "./explorerNode";
import { PathProcesser } from "./pathProcesser";

export class DependencyExplorer {

Expand Down Expand Up @@ -40,16 +40,13 @@ export class DependencyExplorer {
}

public reveal(uri: Uri): void {
Jdtls.resolvePath(uri.toString()).then((paths: INodeData[]) => {
this.revealPath(this._dataProvider, paths);
});
PathProcesser.resolvePath(uri).then((paths: INodeData[]) => this.revealPath(this._dataProvider, paths));
}

private revealPath(current: { getChildren: (element?: ExplorerNode) => ProviderResult<ExplorerNode[]> }, paths: INodeData[]) {
if (!current) {
return;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid the empty diff if possible. You can always provide another PR for format/coding convention to avoid distraction.

const res = current.getChildren();
if (Utility.isThenable(res)) {
res.then((children: DataNode[]) => {
Expand Down
97 changes: 97 additions & 0 deletions src/views/hierachicalPackageRootNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

import { INodeData, NodeKind } from "../java/nodeData";
import { PackageTreeNode } from "../java/packageTreeNode";
import { Settings } from "../settings";
import { DataNode } from "./dataNode";
import { ExplorerNode } from "./explorerNode";
import { FileNode } from "./fileNode";
import { FolderNode } from "./folderNode";
import { HierachicalPackageRootSubNode } from "./hierachicalPackageRootSubNode";
import { PackageRootNode } from "./packageRootNode";
import { ProjectNode } from "./projectNode";
import { TypeRootNode } from "./typeRootNode";

export class HierachicalPackageRootNode extends PackageRootNode {

public static async convertPaths(paths: INodeData[]): Promise<INodeData[]> {
const index = paths.findIndex((nodeData) => nodeData.kind === NodeKind.PackageRoot);
const projectNodeData = paths.find((nodeData) => nodeData.kind === NodeKind.Project);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these operations are model oriented. You can compute the tree without creating a view.

For example, you can make the packagetree as a the model and build the hierarchy model outof the the view.

const packageRootNodeData = paths[index];
const packageNodeData = paths[index + 1];
const packageRootNode = new HierachicalPackageRootNode(packageRootNodeData, null, new ProjectNode(projectNodeData, null));

const correspondDataNodes: INodeData[] = [];
let correspondNode = await packageRootNode.revealPath(packageNodeData);
while (correspondNode instanceof HierachicalPackageRootSubNode) {
correspondDataNodes.push({
name: correspondNode.nodeData.name,
moduleName: null,
path: correspondNode.nodeData.path,
uri: null,
kind: NodeKind.PackageRoot,
children: null,
});
correspondNode = correspondNode.getParent();
}
const result = paths.slice(null, index + 1).concat(correspondDataNodes.reverse(), paths.slice(index + 2));
return result;
}

constructor(nodeData: INodeData, parent: DataNode, _project: ProjectNode) {
super(nodeData, parent, _project);
}

public async revealPath(packageNodeData: INodeData): Promise<ExplorerNode> {
await this.getChildren();
let packageTreeNode: PackageTreeNode = this.getPackageTree();
let result: DataNode = null;
while (packageTreeNode && packageTreeNode.fullName !== packageNodeData.name) {
packageTreeNode = packageTreeNode.childs.find((child) => packageNodeData.name.startsWith(child.fullName));
result = packageTreeNode ? new HierachicalPackageRootSubNode(packageTreeNode.getNodeDataFromPackageTreeNode(this.nodeData),
result, this._project, packageTreeNode) : null;
}
return result;
}

protected createChildNodeList(): ExplorerNode[] {
const result = [];
if (this.nodeData.children && this.nodeData.children.length) {
this.sort();
this.nodeData.children.forEach((data) => {
if (data.kind === NodeKind.File) {
result.push(new FileNode(data, this));
} else if (data.kind === NodeKind.Folder) {
result.push(new FolderNode(data, this, this._project, this));
} else if (data.kind === NodeKind.TypeRoot) {
result.push(new TypeRootNode(data, this));
}
});
}
const packageNodeList = this.getHierarchicalPackageNodes();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't introduce local var here

return packageNodeList.concat(result);
}

protected getHierarchicalPackageNodes(): ExplorerNode[] {
const result = [];
const packageTree = this.getPackageTree();
packageTree.childs.forEach((childNode) => {
result.push(new HierachicalPackageRootSubNode(childNode.getNodeDataFromPackageTreeNode(this.nodeData), this, this._project, childNode));
});
return result;
}

private getPackageTree(): PackageTreeNode {
const result: PackageTreeNode = new PackageTreeNode("", "");
if (this.nodeData.children && this.nodeData.children.length) {
this.nodeData.children.forEach((child) => {
if (child.kind === NodeKind.Package) {
result.addPackage(child.name);
}
});
}
result.compressTree();
return result;
}
}
58 changes: 58 additions & 0 deletions src/views/hierachicalPackageRootSubNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

import { Jdtls } from "../java/jdtls";
import { INodeData, NodeKind } from "../java/nodeData";
import { PackageTreeNode } from "../java/packageTreeNode";
import { DataNode } from "./dataNode";
import { ExplorerNode } from "./explorerNode";
import { FileNode } from "./fileNode";
import { FolderNode } from "./folderNode";
import { ProjectNode } from "./projectNode";
import { TypeRootNode } from "./typeRootNode";

export class HierachicalPackageRootSubNode extends DataNode {

public packageTree: PackageTreeNode;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class code is duplicate with the HierarchicalPackageRootNode, could we model these two types in one class?


constructor(nodeData: INodeData, parent: DataNode, private _project: ProjectNode, packageTree: PackageTreeNode = null) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= null should be removed

super(nodeData, parent);
this.packageTree = packageTree;
}

protected loadData(): Thenable<any[]> {
return Jdtls.getPackageData({
kind: NodeKind.Package, projectUri: this._project.nodeData.uri, path: this.packageTree.fullName, rootPath: this.nodeData.path,
});
}

protected get iconPath(): { light: string; dark: string } {
return ExplorerNode.resolveIconPath("package");
}

protected createChildNodeList(): ExplorerNode[] {
const result = [];
if (this.nodeData.children && this.nodeData.children.length) {
this.sort();
this.nodeData.children.forEach((data) => {
if (data.kind === NodeKind.File) {
result.push(new FileNode(data, this));
} else if (data.kind === NodeKind.Folder) {
result.push(new FolderNode(data, this, this._project, this));
} else if (data.kind === NodeKind.TypeRoot) {
result.push(new TypeRootNode(data, this));
}
});
}
const packageNodeList = this.getHierarchicalPackageNodes();
return packageNodeList.concat(result);
}

protected getHierarchicalPackageNodes(): ExplorerNode[] {
const result = [];
this.packageTree.childs.forEach((childNode) => {
Comment thread
Flanker32 marked this conversation as resolved.
Outdated
result.push(new HierachicalPackageRootSubNode(childNode.getNodeDataFromPackageTreeNode(this.nodeData), this, this._project, childNode));
});
return result;
}
}
Loading