Skip to content

Commit 7cab083

Browse files
authored
refactor: Use visitor pattern to get the explorer nodes (#729)
--------- Signed-off-by: Sheng Chen <[email protected]>
1 parent dbd8d84 commit 7cab083

File tree

6 files changed

+428
-194
lines changed

6 files changed

+428
-194
lines changed

jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/PackageCommand.java

Lines changed: 122 additions & 182 deletions
Large diffs are not rendered by default.

jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/PackageNode.java

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2018 Microsoft Corporation and others.
2+
* Copyright (c) 2018-2023 Microsoft Corporation and others.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -25,15 +25,18 @@
2525
import org.eclipse.core.resources.IResource;
2626
import org.eclipse.core.runtime.CoreException;
2727
import org.eclipse.core.runtime.IPath;
28+
import org.eclipse.jdt.core.IClasspathAttribute;
2829
import org.eclipse.jdt.core.IClasspathContainer;
2930
import org.eclipse.jdt.core.IClasspathEntry;
3031
import org.eclipse.jdt.core.IJavaElement;
3132
import org.eclipse.jdt.core.IJavaProject;
33+
import org.eclipse.jdt.core.IModuleDescription;
3234
import org.eclipse.jdt.core.IPackageFragment;
3335
import org.eclipse.jdt.core.IPackageFragmentRoot;
3436
import org.eclipse.jdt.core.IType;
3537
import org.eclipse.jdt.core.JavaCore;
3638
import org.eclipse.jdt.core.JavaModelException;
39+
import org.eclipse.jdt.internal.core.JrtPackageFragmentRoot;
3740
import org.eclipse.jdt.ls.core.internal.JDTUtils;
3841
import org.eclipse.jdt.ls.core.internal.ProjectUtils;
3942

@@ -176,24 +179,35 @@ public static PackageNode createNodeForProject(IJavaElement javaElement) {
176179
return projectNode;
177180
}
178181

182+
public static PackageNode createNodeForFile(IFile file) {
183+
PackageNode entry = new PackageNode(file.getName(), file.getFullPath().toPortableString(), NodeKind.FILE);
184+
entry.setUri(JDTUtils.getFileURI(file));
185+
return entry;
186+
}
187+
188+
public static PackageNode createNodeForFolder(IFolder folder) {
189+
PackageNode entry = new PackageNode(folder.getName(), folder.getFullPath().toPortableString(), NodeKind.FOLDER);
190+
entry.setUri(JDTUtils.getFileURI(folder));
191+
return entry;
192+
}
193+
179194
public static PackageNode createNodeForResource(IResource resource) {
180195
if (resource instanceof IFile) {
181-
IFile file = (IFile) resource;
182-
PackageNode entry = new PackageNode(file.getName(), file.getFullPath().toPortableString(), NodeKind.FILE);
183-
entry.setUri(JDTUtils.getFileURI(file));
184-
return entry;
196+
return createNodeForFile((IFile) resource);
185197
} else if (resource instanceof IFolder) {
186-
IFolder folder = (IFolder) resource;
187-
PackageNode entry = new PackageNode(folder.getName(), folder.getFullPath().toPortableString(), NodeKind.FOLDER);
188-
entry.setUri(JDTUtils.getFileURI(folder));
189-
return entry;
198+
return createNodeForFolder((IFolder) resource);
190199
}
191200
return null;
192201
}
193202

194203
public static PackageNode createNodeForPackageFragment(IPackageFragment packageFragment) {
195204
PackageNode fragmentNode = new PackageNode(packageFragment.getElementName(), packageFragment.getPath().toPortableString(), NodeKind.PACKAGE);
196205
fragmentNode.setHandlerIdentifier(packageFragment.getHandleIdentifier());
206+
if (packageFragment.getResource() != null) {
207+
fragmentNode.setUri(packageFragment.getResource().getLocationURI().toString());
208+
} else {
209+
fragmentNode.setUri(packageFragment.getPath().toFile().toURI().toString());
210+
}
197211
return fragmentNode;
198212
}
199213

@@ -211,15 +225,16 @@ public static PackageNode createNodeForVirtualContainer(IPackageFragmentRoot pkg
211225
}
212226

213227
public static PackageRootNode createNodeForPackageFragmentRoot(IPackageFragmentRoot pkgRoot) throws JavaModelException {
228+
PackageRootNode node;
214229
String displayName = pkgRoot.getElementName();
215230
boolean isSourcePath = pkgRoot.getKind() == IPackageFragmentRoot.K_SOURCE;
216231
if (!isSourcePath) {
217232
IClasspathEntry entry = pkgRoot.getRawClasspathEntry();
218233
// Process Referenced Variable
219234
if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) {
220-
return createNodeForClasspathVariable(entry);
235+
node = createNodeForClasspathVariable(entry);
221236
} else {
222-
return new PackageRootNode(pkgRoot, displayName, NodeKind.PACKAGEROOT);
237+
node = new PackageRootNode(pkgRoot, displayName, NodeKind.PACKAGEROOT);
223238
}
224239
} else {
225240
IJavaProject javaProject = pkgRoot.getJavaProject();
@@ -231,8 +246,25 @@ public static PackageRootNode createNodeForPackageFragmentRoot(IPackageFragmentR
231246
relativePath = relativePath.removeFirstSegments(1); // Remove the '_' prefix
232247
}
233248
displayName = relativePath.toPortableString();
234-
return new PackageRootNode(pkgRoot, displayName, NodeKind.PACKAGEROOT);
249+
node = new PackageRootNode(pkgRoot, displayName, NodeKind.PACKAGEROOT);
235250
}
251+
252+
node.setHandlerIdentifier(pkgRoot.getHandleIdentifier());
253+
if (pkgRoot instanceof JrtPackageFragmentRoot) {
254+
IModuleDescription moduleDescription = pkgRoot.getModuleDescription();
255+
if (moduleDescription != null) {
256+
node.setModuleName(moduleDescription.getElementName());
257+
}
258+
}
259+
260+
IClasspathEntry resolvedClasspathEntry = pkgRoot.getResolvedClasspathEntry();
261+
if (resolvedClasspathEntry != null) {
262+
for (IClasspathAttribute attribute : resolvedClasspathEntry.getExtraAttributes()) {
263+
node.setMetaDataValue(attribute.getName(), attribute.getValue());
264+
}
265+
}
266+
267+
return node;
236268
}
237269

238270
/**
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2023 Microsoft Corporation and others.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Microsoft Corporation - initial API and implementation
10+
*******************************************************************************/
11+
12+
package com.microsoft.jdtls.ext.core.parser;
13+
14+
import java.util.LinkedList;
15+
import java.util.List;
16+
17+
import org.eclipse.core.resources.IFile;
18+
import org.eclipse.core.resources.IFolder;
19+
import org.eclipse.jdt.core.IClassFile;
20+
import org.eclipse.jdt.core.IClasspathEntry;
21+
import org.eclipse.jdt.core.IJarEntryResource;
22+
import org.eclipse.jdt.core.IJavaProject;
23+
import org.eclipse.jdt.core.IPackageFragment;
24+
import org.eclipse.jdt.core.IPackageFragmentRoot;
25+
import org.eclipse.jdt.core.IType;
26+
import org.eclipse.jdt.core.JavaModelException;
27+
import org.eclipse.jdt.ls.core.internal.JDTUtils;
28+
29+
import com.microsoft.jdtls.ext.core.ExtUtils;
30+
import com.microsoft.jdtls.ext.core.JdtlsExtActivator;
31+
import com.microsoft.jdtls.ext.core.model.NodeKind;
32+
import com.microsoft.jdtls.ext.core.model.PackageNode;
33+
34+
public class JavaResourceVisitor implements ResourceVisitor {
35+
36+
private IJavaProject project;
37+
private List<PackageNode> nodes;
38+
39+
public JavaResourceVisitor(IJavaProject project) {
40+
this.project = project;
41+
this.nodes = new LinkedList<>();
42+
}
43+
44+
@Override
45+
public void visit(IPackageFragment fragment) {
46+
this.nodes.add(PackageNode.createNodeForPackageFragment(fragment));
47+
}
48+
49+
@Override
50+
public void visit(IType type) {
51+
this.nodes.add(PackageNode.createNodeForPrimaryType(type));
52+
}
53+
54+
@Override
55+
public void visit(IClassFile classFile) {
56+
PackageNode node = new PackageNode(classFile.getElementName(), null, NodeKind.FILE);
57+
node.setUri(JDTUtils.toUri(classFile));
58+
this.nodes.add(node);
59+
}
60+
61+
@Override
62+
public void visit(IFile file) {
63+
this.nodes.add(PackageNode.createNodeForFile(file));
64+
}
65+
66+
@Override
67+
public void visit(IFolder folder) {
68+
this.nodes.add(PackageNode.createNodeForFolder(folder));
69+
}
70+
71+
@Override
72+
public void visit(IJarEntryResource jarEntryResource) {
73+
NodeKind kind = jarEntryResource.isFile() ? NodeKind.FILE : NodeKind.FOLDER;
74+
PackageNode node = new PackageNode(jarEntryResource.getName(),
75+
jarEntryResource.getFullPath().toPortableString(), kind);
76+
node.setUri(ExtUtils.toUri(jarEntryResource));
77+
this.nodes.add(node);
78+
}
79+
80+
@Override
81+
public void visit(IClasspathEntry entry) {
82+
PackageNode node = null;
83+
if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) {
84+
node = PackageNode.createNodeForClasspathVariable(entry);
85+
} else if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
86+
node = PackageNode.createNodeForClasspathEntry(entry, this.project, NodeKind.PACKAGEROOT);
87+
} else {
88+
node = PackageNode.createNodeForClasspathEntry(entry, this.project, NodeKind.CONTAINER);
89+
}
90+
91+
if (node != null) {
92+
this.nodes.add(node);
93+
}
94+
}
95+
96+
@Override
97+
public void visit(IPackageFragmentRoot packageFragmentRoot) {
98+
try {
99+
this.nodes.add(PackageNode.createNodeForPackageFragmentRoot(packageFragmentRoot));
100+
} catch (JavaModelException e) {
101+
JdtlsExtActivator.log(e);
102+
}
103+
}
104+
105+
@Override
106+
public List<PackageNode> getNodes() {
107+
return nodes;
108+
}
109+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2023 Microsoft Corporation and others.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Microsoft Corporation - initial API and implementation
10+
*******************************************************************************/
11+
12+
package com.microsoft.jdtls.ext.core.parser;
13+
14+
import java.util.List;
15+
import java.util.ListIterator;
16+
import java.util.Objects;
17+
18+
import org.eclipse.core.resources.IFile;
19+
import org.eclipse.core.resources.IFolder;
20+
import org.eclipse.core.runtime.CoreException;
21+
import org.eclipse.core.runtime.NullProgressMonitor;
22+
import org.eclipse.jdt.core.IClassFile;
23+
import org.eclipse.jdt.core.IClasspathEntry;
24+
import org.eclipse.jdt.core.IJarEntryResource;
25+
import org.eclipse.jdt.core.IJavaProject;
26+
import org.eclipse.jdt.core.IPackageFragment;
27+
import org.eclipse.jdt.core.IPackageFragmentRoot;
28+
import org.eclipse.jdt.core.IType;
29+
import org.eclipse.jdt.ls.core.internal.ProjectUtils;
30+
31+
import com.microsoft.jdtls.ext.core.JdtlsExtActivator;
32+
import com.microsoft.jdtls.ext.core.PackageCommand;
33+
34+
// TODO: progress monitor
35+
public class ResourceSet {
36+
37+
private List<Object> resources;
38+
39+
public ResourceSet(List<Object> resources) {
40+
this.resources = resources;
41+
}
42+
43+
public void accept(ResourceVisitor visitor) {
44+
ListIterator<Object> iterator = resources.listIterator();
45+
while (iterator.hasNext()) {
46+
Object resource = iterator.next();
47+
if (resource == null) {
48+
continue;
49+
}
50+
51+
if (resource instanceof IClasspathEntry) {
52+
visitor.visit((IClasspathEntry) resource);
53+
} else if (resource instanceof IPackageFragmentRoot) {
54+
IPackageFragmentRoot pkgRoot = (IPackageFragmentRoot) resource;
55+
IJavaProject javaProject = pkgRoot.getJavaProject();
56+
if (javaProject == null) {
57+
continue;
58+
}
59+
60+
// skip invisible project's linked folder and add its children to the iterator.
61+
if (!ProjectUtils.isVisibleProject(javaProject.getProject()) &&
62+
Objects.equals(ProjectUtils.WORKSPACE_LINK, pkgRoot.getElementName())) {
63+
try {
64+
List<Object> nextObjs = PackageCommand.getPackageFragmentRootContent(
65+
pkgRoot, false, new NullProgressMonitor());
66+
for (Object nextObj : nextObjs) {
67+
iterator.add(nextObj);
68+
iterator.previous();
69+
}
70+
} catch (CoreException e) {
71+
JdtlsExtActivator.logException("Failed to get package fragment root content", e);
72+
continue;
73+
}
74+
} else {
75+
visitor.visit(pkgRoot);
76+
}
77+
} else if (resource instanceof IPackageFragment) {
78+
IPackageFragment fragment = (IPackageFragment) resource;
79+
// skil default package and add its children to the iterator.
80+
if (fragment.isDefaultPackage()) {
81+
List<Object> nextObjs = PackageCommand.getChildrenForPackage(fragment);
82+
for (Object nextObj : nextObjs) {
83+
iterator.add(nextObj);
84+
iterator.previous();
85+
}
86+
} else {
87+
visitor.visit(fragment);
88+
}
89+
} else if (resource instanceof IType) {
90+
visitor.visit((IType) resource);
91+
} else if (resource instanceof IClassFile) {
92+
visitor.visit((IClassFile) resource);
93+
} else if (resource instanceof IFile) {
94+
visitor.visit((IFile) resource);
95+
} else if (resource instanceof IFolder) {
96+
visitor.visit((IFolder) resource);
97+
} else if (resource instanceof IJarEntryResource) {
98+
visitor.visit((IJarEntryResource) resource);
99+
}
100+
}
101+
}
102+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2023 Microsoft Corporation and others.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Microsoft Corporation - initial API and implementation
10+
*******************************************************************************/
11+
12+
package com.microsoft.jdtls.ext.core.parser;
13+
14+
import java.util.List;
15+
16+
import org.eclipse.core.resources.IFile;
17+
import org.eclipse.core.resources.IFolder;
18+
import org.eclipse.jdt.core.IClassFile;
19+
import org.eclipse.jdt.core.IClasspathEntry;
20+
import org.eclipse.jdt.core.IJarEntryResource;
21+
import org.eclipse.jdt.core.IPackageFragment;
22+
import org.eclipse.jdt.core.IPackageFragmentRoot;
23+
import org.eclipse.jdt.core.IType;
24+
25+
import com.microsoft.jdtls.ext.core.model.PackageNode;
26+
27+
/**
28+
* A visitor to iterate through resources in a project and parse them to
29+
* nodes in the UI.
30+
*/
31+
public interface ResourceVisitor {
32+
33+
void visit(IClasspathEntry entry);
34+
35+
void visit(IPackageFragmentRoot packageFragmentRoot);
36+
37+
void visit(IPackageFragment fragment);
38+
39+
void visit(IType type);
40+
41+
void visit(IClassFile classFile);
42+
43+
void visit(IFile file);
44+
45+
void visit(IFolder folder);
46+
47+
void visit(IJarEntryResource jarEntryResource);
48+
49+
List<PackageNode> getNodes();
50+
}

src/views/folderNode.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export class FolderNode extends DataNode {
2020
kind: NodeKind.Folder,
2121
projectUri: this._project.uri,
2222
path: this.path,
23+
rootPath: this._rootNode.path,
2324
handlerIdentifier: this._rootNode.handlerIdentifier,
2425
});
2526
}

0 commit comments

Comments
 (0)