Skip to content

Commit 1c9052f

Browse files
committed
feat: Display non-java resources in the Project explorer
Signed-off-by: Sheng Chen <[email protected]>
1 parent 1574851 commit 1c9052f

File tree

8 files changed

+179
-105
lines changed

8 files changed

+179
-105
lines changed

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

+48-28
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,10 @@ public class PackageCommand {
7878

7979
static {
8080
commands = new HashMap<>();
81-
commands.put(NodeKind.PROJECT, PackageCommand::getContainers);
82-
commands.put(NodeKind.CONTAINER, PackageCommand::getPackageFragmentRoots);
83-
commands.put(NodeKind.PACKAGEROOT, PackageCommand::getPackages);
84-
commands.put(NodeKind.PACKAGE, PackageCommand::getRootTypes);
81+
commands.put(NodeKind.PROJECT, PackageCommand::getProjectChildren);
82+
commands.put(NodeKind.CONTAINER, PackageCommand::getContainerChildren);
83+
commands.put(NodeKind.PACKAGEROOT, PackageCommand::getPackageRootChildren);
84+
commands.put(NodeKind.PACKAGE, PackageCommand::getPackageChildren);
8585
commands.put(NodeKind.FOLDER, PackageCommand::getFolderChildren);
8686
}
8787

@@ -225,10 +225,17 @@ public static List<PackageNode> resolvePath(List<Object> arguments, IProgressMon
225225
* @throws JavaModelException when fails to get path or resource
226226
*/
227227
private static List<PackageNode> getParentAncestorNodes(IResource element) throws JavaModelException {
228-
List<PackageNode> nodeList = new ArrayList<>();
229-
while (element != null) {
228+
List<PackageNode> nodeList = new LinkedList<>();
229+
while (element != null && !(element instanceof IWorkspaceRoot)) {
230230
IJavaElement javaElement = JavaCore.create(element);
231-
if (javaElement instanceof IPackageFragmentRoot) {
231+
if (javaElement == null) {
232+
PackageNode entry = PackageNode.createNodeForResource(element);
233+
if (entry != null) {
234+
nodeList.add(0, entry);
235+
}
236+
} else if (javaElement instanceof IJavaProject) {
237+
nodeList.add(0, PackageNode.createNodeForProject(javaElement));
238+
} else if (javaElement instanceof IPackageFragmentRoot) {
232239
IPackageFragmentRoot pkgRoot = (IPackageFragmentRoot) javaElement;
233240
nodeList.add(0, new PackageRootNode(pkgRoot,
234241
element.getProjectRelativePath().toPortableString(), NodeKind.PACKAGEROOT));
@@ -239,12 +246,6 @@ private static List<PackageNode> getParentAncestorNodes(IResource element) throw
239246
if (packageFragment.containsJavaResources() || packageFragment.getNonJavaResources().length > 0) {
240247
nodeList.add(0, PackageNode.createNodeForPackageFragment(packageFragment));
241248
}
242-
243-
} else if (javaElement == null) {
244-
PackageNode entry = PackageNode.createNodeForResource(element);
245-
if (entry != null) {
246-
nodeList.add(0, entry);
247-
}
248249
}
249250
element = element.getParent();
250251
}
@@ -255,20 +256,28 @@ private static List<PackageNode> getParentAncestorNodes(IResource element) throw
255256
/**
256257
* Get the class path container list.
257258
*/
258-
private static List<PackageNode> getContainers(PackageParams query, IProgressMonitor pm) {
259+
private static List<PackageNode> getProjectChildren(PackageParams query, IProgressMonitor pm) {
259260
IJavaProject javaProject = getJavaProject(query.getProjectUri());
260261
if (javaProject != null) {
262+
refreshLocal(javaProject.getProject(), pm);
261263
List<Object> children = new LinkedList<>();
262264
boolean hasReferencedLibraries = false;
263265
try {
264266
IClasspathEntry[] references = javaProject.getRawClasspath();
265267
for (IClasspathEntry entry : references) {
266-
if (entry.getEntryKind() != IClasspathEntry.CPE_LIBRARY && entry.getEntryKind() != IClasspathEntry.CPE_VARIABLE) {
268+
int entryKind = entry.getEntryKind();
269+
if (entryKind == IClasspathEntry.CPE_SOURCE) {
270+
IPackageFragmentRoot[] packageFragmentRoots = javaProject.findPackageFragmentRoots(entry);
271+
children.addAll(Arrays.asList(packageFragmentRoots));
272+
} else if (entryKind == IClasspathEntry.CPE_CONTAINER) {
267273
children.add(entry);
268-
} else {
274+
} else if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY || entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) {
269275
hasReferencedLibraries = true;
276+
} else {
277+
// TODO: handle IClasspathEntry.CPE_PROJECT
270278
}
271279
}
280+
Collections.addAll(children, javaProject.getNonJavaResources());
272281
} catch (CoreException e) {
273282
JdtlsExtActivator.logException("Problem load project library ", e);
274283
}
@@ -278,7 +287,7 @@ private static List<PackageNode> getContainers(PackageParams query, IProgressMon
278287
resourceSet.accept(visitor);
279288
List<PackageNode> result = visitor.getNodes();
280289

281-
// Invisble project will always have the referenced libraries entry
290+
// Invisible project will always have the referenced libraries entry
282291
if (!ProjectUtils.isVisibleProject(javaProject.getProject())) {
283292
result.add(PackageNode.REFERENCED_LIBRARIES_CONTAINER);
284293
} else if (hasReferencedLibraries) {
@@ -289,7 +298,7 @@ private static List<PackageNode> getContainers(PackageParams query, IProgressMon
289298
return Collections.emptyList();
290299
}
291300

292-
private static List<PackageNode> getPackageFragmentRoots(PackageParams query, IProgressMonitor pm) {
301+
private static List<PackageNode> getContainerChildren(PackageParams query, IProgressMonitor pm) {
293302
IJavaProject javaProject = getJavaProject(query.getProjectUri());
294303
if (javaProject == null) {
295304
return Collections.emptyList();
@@ -311,6 +320,7 @@ private static List<PackageNode> getPackageFragmentRoots(PackageParams query, IP
311320

312321
for (IPackageFragmentRoot fragmentRoot : packageFragmentRoots) {
313322
children.add(fragmentRoot);
323+
children.addAll(Arrays.asList(fragmentRoot.getNonJavaResources()));
314324
}
315325
}
316326
} catch (CoreException e) {
@@ -343,15 +353,15 @@ private static IPackageFragmentRoot[] findPackageFragmentRoots(IJavaProject java
343353
return null;
344354
}
345355

346-
private static List<PackageNode> getPackages(PackageParams query, IProgressMonitor pm) {
356+
private static List<PackageNode> getPackageRootChildren(PackageParams query, IProgressMonitor pm) {
347357
try {
348358
IPackageFragmentRoot packageRoot = getPackageFragmentRootFromQuery(query);
349359
if (packageRoot == null) {
350360
throw new CoreException(
351361
new Status(IStatus.ERROR, JdtlsExtActivator.PLUGIN_ID, String.format("No package root found for %s", query.getPath())));
352362
}
353363
List<Object> result = getPackageFragmentRootContent(packageRoot, query.isHierarchicalView(), pm);
354-
ResourceSet resourceSet = new ResourceSet(result);
364+
ResourceSet resourceSet = new ResourceSet(result, query.isHierarchicalView());
355365
ResourceVisitor visitor = new JavaResourceVisitor(packageRoot.getJavaProject());
356366
resourceSet.accept(visitor);
357367
return visitor.getNodes();
@@ -375,28 +385,28 @@ private static IPackageFragmentRoot getPackageFragmentRootFromQuery(PackageParam
375385
return javaProject.findPackageFragmentRoot(Path.fromPortableString(query.getRootPath()));
376386
} catch (JavaModelException e) {
377387
JdtlsExtActivator.log(e);
378-
return null;
379388
}
380389
}
381390
}
382391

383392
return null;
384393
}
385394

386-
private static List<PackageNode> getRootTypes(PackageParams query, IProgressMonitor pm) {
395+
private static List<PackageNode> getPackageChildren(PackageParams query, IProgressMonitor pm) {
387396
IPackageFragment packageFragment = (IPackageFragment) JavaCore.create(query.getHandlerIdentifier());
388-
List<Object> children = getChildrenForPackage(packageFragment);
397+
List<Object> children = getChildrenForPackage(packageFragment, pm);
389398
ResourceSet resourceSet = new ResourceSet(children);
390399
ResourceVisitor visitor = new JavaResourceVisitor(packageFragment.getJavaProject());
391400
resourceSet.accept(visitor);
392401
return visitor.getNodes();
393402
}
394403

395-
public static List<Object> getChildrenForPackage(IPackageFragment packageFragment) {
404+
public static List<Object> getChildrenForPackage(IPackageFragment packageFragment, IProgressMonitor pm) {
396405
if (packageFragment == null) {
397406
return Collections.emptyList();
398407
}
399408

409+
refreshLocal(packageFragment.getResource(), pm);
400410
List<Object> children = new LinkedList<>();
401411
try {
402412
for (IJavaElement element : packageFragment.getChildren()) {
@@ -412,10 +422,7 @@ public static List<Object> getChildrenForPackage(IPackageFragment packageFragmen
412422
}
413423
}
414424

415-
Object[] nonJavaResources = packageFragment.getNonJavaResources();
416-
for (Object resource : nonJavaResources) {
417-
children.add(resource);
418-
}
425+
Collections.addAll(children, packageFragment.getNonJavaResources());
419426
} catch (JavaModelException e) {
420427
JdtlsExtActivator.log(e);
421428
}
@@ -458,6 +465,7 @@ private static List<PackageNode> getFolderChildren(PackageParams query, IProgres
458465
// general resource folder.
459466
IFolder folder = ResourcesPlugin.getWorkspace().getRoot().getFolder(Path.fromPortableString(query.getPath()));
460467
if (folder.exists()) {
468+
refreshLocal(folder, pm);
461469
children.addAll(Arrays.asList(folder.members()));
462470
javaProject = JavaCore.create(folder.getProject());
463471
}
@@ -488,6 +496,7 @@ private static List<PackageNode> getFolderChildren(PackageParams query, IProgres
488496
*/
489497
public static List<Object> getPackageFragmentRootContent(IPackageFragmentRoot root, boolean isHierarchicalView, IProgressMonitor pm) throws CoreException {
490498
ArrayList<Object> result = new ArrayList<>();
499+
refreshLocal(root.getResource(), pm);
491500
if (isHierarchicalView) {
492501
Map<String, IJavaElement> map = new HashMap<>();
493502
for (IJavaElement child : root.getChildren()) {
@@ -583,4 +592,15 @@ public static IJavaProject getJavaProject(String projectUri) {
583592
}
584593
return null;
585594
}
595+
596+
private static void refreshLocal(IResource resource, IProgressMonitor monitor) {
597+
if (resource == null || !resource.exists()) {
598+
return;
599+
}
600+
try {
601+
resource.refreshLocal(IResource.DEPTH_ONE, monitor);
602+
} catch (CoreException e) {
603+
JdtlsExtActivator.log(e);
604+
}
605+
}
586606
}

jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/parser/ResourceSet.java

+56-6
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,13 @@
1515
import java.util.ListIterator;
1616
import java.util.Objects;
1717

18+
import org.eclipse.core.internal.utils.FileUtil;
1819
import org.eclipse.core.resources.IFile;
1920
import org.eclipse.core.resources.IFolder;
21+
import org.eclipse.core.resources.IProject;
22+
import org.eclipse.core.resources.IResource;
2023
import org.eclipse.core.runtime.CoreException;
24+
import org.eclipse.core.runtime.IPath;
2125
import org.eclipse.core.runtime.NullProgressMonitor;
2226
import org.eclipse.jdt.core.IClassFile;
2327
import org.eclipse.jdt.core.IClasspathEntry;
@@ -26,6 +30,7 @@
2630
import org.eclipse.jdt.core.IPackageFragment;
2731
import org.eclipse.jdt.core.IPackageFragmentRoot;
2832
import org.eclipse.jdt.core.IType;
33+
import org.eclipse.jdt.core.JavaCore;
2934
import org.eclipse.jdt.ls.core.internal.ProjectUtils;
3035

3136
import com.microsoft.jdtls.ext.core.JdtlsExtActivator;
@@ -35,9 +40,15 @@
3540
public class ResourceSet {
3641

3742
private List<Object> resources;
43+
private boolean isHierarchicalView;
3844

3945
public ResourceSet(List<Object> resources) {
46+
this(resources, false);
47+
}
48+
49+
public ResourceSet(List<Object> resources, boolean isHierarchicalView) {
4050
this.resources = resources;
51+
this.isHierarchicalView = isHierarchicalView;
4152
}
4253

4354
public void accept(ResourceVisitor visitor) {
@@ -58,11 +69,11 @@ public void accept(ResourceVisitor visitor) {
5869
}
5970

6071
// skip invisible project's linked folder and add its children to the iterator.
61-
if (!ProjectUtils.isVisibleProject(javaProject.getProject()) &&
72+
if (ProjectUtils.isUnmanagedFolder(javaProject.getProject()) &&
6273
Objects.equals(ProjectUtils.WORKSPACE_LINK, pkgRoot.getElementName())) {
6374
try {
6475
List<Object> nextObjs = PackageCommand.getPackageFragmentRootContent(
65-
pkgRoot, false, new NullProgressMonitor());
76+
pkgRoot, isHierarchicalView, new NullProgressMonitor());
6677
for (Object nextObj : nextObjs) {
6778
iterator.add(nextObj);
6879
iterator.previous();
@@ -76,9 +87,9 @@ public void accept(ResourceVisitor visitor) {
7687
}
7788
} else if (resource instanceof IPackageFragment) {
7889
IPackageFragment fragment = (IPackageFragment) resource;
79-
// skil default package and add its children to the iterator.
90+
// skip default package and add its children to the iterator.
8091
if (fragment.isDefaultPackage()) {
81-
List<Object> nextObjs = PackageCommand.getChildrenForPackage(fragment);
92+
List<Object> nextObjs = PackageCommand.getChildrenForPackage(fragment, new NullProgressMonitor());
8293
for (Object nextObj : nextObjs) {
8394
iterator.add(nextObj);
8495
iterator.previous();
@@ -91,12 +102,51 @@ public void accept(ResourceVisitor visitor) {
91102
} else if (resource instanceof IClassFile) {
92103
visitor.visit((IClassFile) resource);
93104
} else if (resource instanceof IFile) {
94-
visitor.visit((IFile) resource);
105+
if (shouldVisit((IFile) resource)) {
106+
visitor.visit((IFile) resource);
107+
}
95108
} else if (resource instanceof IFolder) {
96-
visitor.visit((IFolder) resource);
109+
if (shouldVisit((IFolder) resource)) {
110+
visitor.visit((IFolder) resource);
111+
}
97112
} else if (resource instanceof IJarEntryResource) {
98113
visitor.visit((IJarEntryResource) resource);
99114
}
100115
}
101116
}
117+
118+
/**
119+
* Check if the IFolder or IFile should be visited. The following conditions will skip visit:
120+
* <ul>
121+
* <li>the resource is null.</li>
122+
* <li>the resource does not belong to any project.</li>
123+
* <li>the resource is not in the project's real location.</li>
124+
* <li>the resource is a java element.</li>
125+
* </ul>
126+
*/
127+
private boolean shouldVisit(IResource resource) {
128+
if (resource == null) {
129+
return false;
130+
}
131+
132+
IProject project = resource.getProject();
133+
if (project == null) {
134+
return false;
135+
}
136+
137+
IPath projectRealFolder = ProjectUtils.getProjectRealFolder(project.getProject());
138+
IPath resourcePath = FileUtil.toPath(resource.getLocationURI());
139+
// check if the resource stores in the project's real location.
140+
if (!projectRealFolder.isPrefixOf(resourcePath)) {
141+
return false;
142+
}
143+
144+
// skip linked folder.
145+
if (Objects.equals(projectRealFolder, resourcePath) &&
146+
Objects.equals(ProjectUtils.WORKSPACE_LINK, resource.getName())) {
147+
return false;
148+
}
149+
150+
return JavaCore.create(resource) == null;
151+
}
102152
}

src/explorerCommands/rename.ts

+3
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ function getValueSelection(uri: string): [number, number] | undefined {
7171
}
7272

7373
function CheckQualifiedInputName(value: string, nodeKind: NodeKind): string {
74+
if (nodeKind === NodeKind.Folder || nodeKind === NodeKind.File) {
75+
return "";
76+
}
7477
const javaValidateMessage = checkJavaQualifiedName(value);
7578

7679
if (javaValidateMessage) {

0 commit comments

Comments
 (0)