Skip to content

Commit b87c7b5

Browse files
Vigilanstestforstephen
authored andcommitted
Support right click context for viewer nodes (#208)
* Support URI for nodes created from classpath entry * Support URI for PackageRootNode * Support URI for PackageFragment * Support Right Click Context in Client Side * Change description for `revealFileInOS` * Hide right-click-context commands from command palette * Add context value for testing uri * Extract detecting container uri as util method * Fix getContainerURI NPE
1 parent 26c5920 commit b87c7b5

File tree

9 files changed

+125
-21
lines changed

9 files changed

+125
-21
lines changed

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

+15
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@
2020
import org.eclipse.core.runtime.IPath;
2121
import org.eclipse.core.runtime.IStatus;
2222
import org.eclipse.core.runtime.Status;
23+
import org.eclipse.jdt.core.IClasspathContainer;
2324
import org.eclipse.jdt.core.IJarEntryResource;
25+
import org.eclipse.jdt.core.IJavaProject;
2426
import org.eclipse.jdt.core.IPackageFragment;
2527
import org.eclipse.jdt.core.IPackageFragmentRoot;
2628
import org.eclipse.jdt.core.JavaCore;
2729
import org.eclipse.jdt.core.JavaModelException;
2830
import org.eclipse.jdt.internal.core.JarEntryDirectory;
2931
import org.eclipse.jdt.internal.core.JarEntryFile;
32+
import org.eclipse.jdt.launching.JavaRuntime;
3033
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
3134

3235
public final class ExtUtils {
@@ -104,6 +107,18 @@ public static IPath removeProjectSegment(String projectElementName, IPath path)
104107
return path;
105108
}
106109

110+
public static URI getContainerURI(IJavaProject javaProject, IClasspathContainer container) throws CoreException {
111+
switch (container.getKind()) {
112+
case IClasspathContainer.K_DEFAULT_SYSTEM: // JRE Container
113+
case IClasspathContainer.K_SYSTEM:
114+
return JavaRuntime.getVMInstall(javaProject).getInstallLocation().toURI();
115+
case IClasspathContainer.K_APPLICATION: // Plugin Container, Maven Container, etc
116+
return null; // TODO: find out a good way to detect these containers' uri
117+
default: // Persistent container (e.g. /src/main/java)
118+
return container.getPath().toFile().toURI();
119+
}
120+
}
121+
107122
private static JarEntryFile findFileInJar(JarEntryDirectory directory, String path) {
108123
for (IJarEntryResource child : directory.getChildren()) {
109124
if (child instanceof JarEntryFile && child.getFullPath().toPortableString().equals(path)) {

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

+13-7
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,9 @@ public static List<PackageNode> resolvePath(List<Object> arguments, IProgressMon
175175
IPackageFragmentRoot pkgRoot = (IPackageFragmentRoot) packageFragment.getParent();
176176
PackageNode rootNode = null;
177177

178-
rootNode = new PackageRootNode(
178+
rootNode = new PackageRootNode(pkgRoot,
179179
ExtUtils.removeProjectSegment(packageFragment.getJavaProject().getElementName(), pkgRoot.getPath()).toPortableString(),
180-
pkgRoot.getPath().toPortableString(), NodeKind.PACKAGEROOT, pkgRoot.getKind());
180+
NodeKind.PACKAGEROOT);
181181

182182
result.add(PackageNode.createNodeForProject(packageFragment));
183183
result.add(rootNode);
@@ -209,8 +209,8 @@ private static List<PackageNode> getParentAncestorNodes(IResource element) throw
209209
IJavaElement javaElement = JavaCore.create(element);
210210
if (javaElement instanceof IPackageFragmentRoot) {
211211
IPackageFragmentRoot pkgRoot = (IPackageFragmentRoot) javaElement;
212-
nodeList.add(0, new PackageRootNode(element.getProjectRelativePath().toPortableString(), pkgRoot.getPath().toPortableString(),
213-
NodeKind.PACKAGEROOT, pkgRoot.getKind()));
212+
nodeList.add(0, new PackageRootNode(pkgRoot,
213+
element.getProjectRelativePath().toPortableString(), NodeKind.PACKAGEROOT));
214214
nodeList.add(0, PackageNode.createNodeForProject(javaElement));
215215
return nodeList;
216216
} else if (javaElement instanceof IPackageFragment) {
@@ -280,8 +280,7 @@ private static List<PackageNode> getPackageFragmentRoots(PackageParams query, IP
280280
if (fragmentRoot.getKind() == IPackageFragmentRoot.K_SOURCE) {
281281
displayName = ExtUtils.removeProjectSegment(javaProject.getElementName(), fragmentRoot.getPath()).toPortableString();
282282
}
283-
PackageRootNode node = new PackageRootNode(displayName, fragmentRoot.getPath().toPortableString(), NodeKind.PACKAGEROOT,
284-
fragmentRoot.getKind());
283+
PackageRootNode node = new PackageRootNode(fragmentRoot, displayName, NodeKind.PACKAGEROOT);
285284
children.add(node);
286285
if (fragmentRoot instanceof JrtPackageFragmentRoot) {
287286
node.setModuleName(fragmentRoot.getModuleDescription().getElementName());
@@ -440,7 +439,14 @@ private static List<PackageNode> convertToPackageNode(Object[] rootContent, IPac
440439
List<PackageNode> result = new ArrayList<>();
441440
for (Object root : rootContent) {
442441
if (root instanceof IPackageFragment) {
443-
result.add(PackageNode.createNodeForPackageFragment((IPackageFragment) root));
442+
IPackageFragment fragment = (IPackageFragment) root;
443+
PackageNode entry = PackageNode.createNodeForPackageFragment(fragment);
444+
if (fragment.getResource() != null) {
445+
entry.setUri(fragment.getResource().getLocationURI().toString());
446+
} else {
447+
entry.setUri(fragment.getPath().toFile().toURI().toString());
448+
}
449+
result.add(entry);
444450
} else if (root instanceof IClassFile) {
445451
IClassFile classFile = (IClassFile) root;
446452
PackageNode entry = new PackageNode(classFile.getElementName(), null, NodeKind.TYPEROOT);

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

+18-12
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
package com.microsoft.jdtls.ext.core.model;
1313

14+
import java.net.URI;
1415
import java.util.List;
1516

1617
import org.eclipse.core.resources.IFile;
@@ -133,11 +134,11 @@ public static PackageNode createNodeForPackageFragmentRoot(IPackageFragmentRoot
133134
if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) {
134135
return createNodeForClasspathVariable(entry);
135136
} else {
136-
return new PackageRootNode(pkgRoot.getElementName(), pkgRoot.getPath().toPortableString(), NodeKind.PACKAGEROOT, pkgRoot.getKind());
137+
return new PackageRootNode(pkgRoot, pkgRoot.getElementName(), NodeKind.PACKAGEROOT);
137138
}
138139
} else {
139-
return new PackageRootNode(ExtUtils.removeProjectSegment(pkgRoot.getJavaProject().getElementName(), pkgRoot.getPath()).toPortableString(),
140-
pkgRoot.getPath().toPortableString(), NodeKind.PACKAGEROOT, pkgRoot.getKind());
140+
return new PackageRootNode(pkgRoot,
141+
ExtUtils.removeProjectSegment(pkgRoot.getJavaProject().getElementName(), pkgRoot.getPath()).toPortableString(), NodeKind.PACKAGEROOT);
141142
}
142143
}
143144

@@ -161,17 +162,21 @@ public static PackageNode createNodeForClasspathEntry(IClasspathEntry classpathE
161162
container = JavaCore.getClasspathContainer(entry.getPath(), javaProject);
162163
}
163164
if (container != null) {
164-
switch (nodeKind) {
165-
case CONTAINER:
166-
return new ContainerNode(container.getDescription(), container.getPath().toPortableString(), nodeKind, entry.getEntryKind());
167-
case PACKAGEROOT:
165+
PackageNode node = null;
166+
if (nodeKind == NodeKind.CONTAINER) {
167+
node = new ContainerNode(container.getDescription(), container.getPath().toPortableString(), nodeKind, entry.getEntryKind());
168+
final URI containerURI = ExtUtils.getContainerURI(javaProject, container);
169+
node.setUri(containerURI != null ? containerURI.toString() : null);
170+
} else if (nodeKind == NodeKind.PACKAGEROOT) { // ClasspathEntry for referenced jar files
168171
// Use package name as package root name
169172
String[] pathSegments = container.getPath().segments();
170-
return new PackageRootNode(pathSegments[pathSegments.length - 1], container.getPath().toPortableString(), nodeKind,
171-
IPackageFragmentRoot.K_BINARY);
172-
default:
173-
return null;
173+
node = new PackageRootNode(
174+
pathSegments[pathSegments.length - 1],
175+
container.getPath().toPortableString(),
176+
container.getPath().toFile().toURI().toString(),
177+
nodeKind, IPackageFragmentRoot.K_BINARY);
174178
}
179+
return node;
175180
}
176181
} catch (CoreException e) {
177182
JdtlsExtActivator.logException("Problems when convert classpath entry to package node ", e);
@@ -201,7 +206,8 @@ public static PackageNode createNodeForClasspathVariable(IClasspathEntry classpa
201206
IClasspathEntry entry = JavaCore.getResolvedClasspathEntry(classpathEntry);
202207
String name = classpathEntry.getPath().toPortableString();
203208
String path = entry.getPath().toPortableString();
204-
return new PackageRootNode(name, path, NodeKind.PACKAGEROOT, IPackageFragmentRoot.K_BINARY);
209+
String uri = entry.getPath().toFile().toURI().toString();
210+
return new PackageRootNode(name, path, uri, NodeKind.PACKAGEROOT, IPackageFragmentRoot.K_BINARY);
205211
}
206212

207213
public String getName() {

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

+14-1
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,30 @@
1313

1414
import java.util.Map;
1515

16+
import org.eclipse.jdt.core.IPackageFragmentRoot;
17+
import org.eclipse.jdt.core.JavaModelException;
18+
1619
public class PackageRootNode extends PackageNode {
1720

1821
private int entryKind;
1922

2023
private Map<String, String> attributes;
2124

22-
public PackageRootNode(String name, String path, NodeKind kind, int entryKind) {
25+
public PackageRootNode(String name, String path, String uri, NodeKind kind, int entryKind) {
2326
super(name, path, kind);
27+
this.setUri(uri);
2428
this.entryKind = entryKind;
2529
}
2630

31+
public PackageRootNode(IPackageFragmentRoot pkgRoot, String name, NodeKind kind) throws JavaModelException {
32+
this(name, pkgRoot.getPath().toPortableString(), null, kind, pkgRoot.getKind());
33+
if (pkgRoot.getResource() != null) {
34+
this.setUri(pkgRoot.getResource().getLocationURI().toString());
35+
} else {
36+
this.setUri(pkgRoot.getPath().toFile().toURI().toString());
37+
}
38+
}
39+
2740
public int getEntryType() {
2841
return this.entryKind;
2942
}

package.json

+47-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"explorer"
1313
],
1414
"engines": {
15-
"vscode": "^1.30.0"
15+
"vscode": "^1.31.0"
1616
},
1717
"repository": {
1818
"type": "git",
@@ -83,6 +83,21 @@
8383
"dark": "images/dark/icon-link.svg",
8484
"light": "images/light/icon-link.svg"
8585
}
86+
},
87+
{
88+
"command": "java.view.package.revealFileInOS",
89+
"title": "%contributes.commands.java.view.package.revealFileInOS%",
90+
"category": "Java"
91+
},
92+
{
93+
"command": "java.view.package.copyFilePath",
94+
"title": "%contributes.commands.java.view.package.copyFilePath%",
95+
"category": "Java"
96+
},
97+
{
98+
"command": "java.view.package.copyRelativeFilePath",
99+
"title": "%contributes.commands.java.view.package.copyRelativeFilePath%",
100+
"category": "Java"
86101
}
87102
],
88103
"configuration": {
@@ -121,6 +136,20 @@
121136
}
122137
},
123138
"menus": {
139+
"commandPalette": [
140+
{
141+
"command": "java.view.package.revealFileInOS",
142+
"when": "never"
143+
},
144+
{
145+
"command": "java.view.package.copyFilePath",
146+
"when": "never"
147+
},
148+
{
149+
"command": "java.view.package.copyRelativeFilePath",
150+
"when": "never"
151+
}
152+
],
124153
"view/title": [
125154
{
126155
"command": "java.view.package.refresh",
@@ -147,6 +176,23 @@
147176
"when": "view == javaDependencyExplorer && config.java.dependency.syncWithFolderExplorer == true",
148177
"group": "navigation@0"
149178
}
179+
],
180+
"view/item/context": [
181+
{
182+
"command": "java.view.package.revealFileInOS",
183+
"when": "view == javaDependencyExplorer && viewItem =~ /java:.*?\\+uri/",
184+
"group": "@1"
185+
},
186+
{
187+
"command": "java.view.package.copyFilePath",
188+
"when": "view == javaDependencyExplorer && viewItem =~ /java:.*?\\+uri/",
189+
"group": "@2"
190+
},
191+
{
192+
"command": "java.view.package.copyRelativeFilePath",
193+
"when": "view == javaDependencyExplorer && viewItem =~ /java:.*?\\+uri/",
194+
"group": "@2"
195+
}
150196
]
151197
},
152198
"views": {

package.nls.json

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
"contributes.commands.java.view.package.changeToHierarchicalPackageView":"Change to hierarchical package representation",
88
"contributes.commands.java.view.package.linkWithFolderExplorer":"Synchronize dependency viewer selection with folder explorer",
99
"contributes.commands.java.view.package.unlinkWithFolderExplorer":"Desynchronize dependency viewer selection with folder explorer",
10+
"contributes.commands.java.view.package.revealFileInOS": "Reveal In Explorer",
11+
"contributes.commands.java.view.package.copyFilePath": "Copy Path",
12+
"contributes.commands.java.view.package.copyRelativeFilePath": "Copy Relative Path",
1013
"configuration.java.dependency.title": "Java Dependency Configuration",
1114
"configuration.java.dependency.showOutline": "Enable show outline in the Java Dependency explorer",
1215
"configuration.java.dependency.syncWithFolderExplorer": "Synchronize dependency viewer selection with folder explorer",

package.nls.zh.json

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
"contributes.commands.java.view.package.changeToHierarchicalPackageView":"将 Java 包显示方式切换为分层显示",
88
"contributes.commands.java.view.package.linkWithFolderExplorer":"开启 Java 依赖项资源管理器与当前浏览文件的关联",
99
"contributes.commands.java.view.package.unlinkWithFolderExplorer":"关闭 Java 依赖项资源管理器与当前浏览文件的关联",
10+
"contributes.commands.java.view.package.revealFileInOS": "打开所在的文件夹",
11+
"contributes.commands.java.view.package.copyFilePath": "复制路径",
12+
"contributes.commands.java.view.package.copyRelativeFilePath": "复制相对路径",
1013
"configuration.java.dependency.title": "Java 依赖管理配置",
1114
"configuration.java.dependency.showOutline": "在 Java 依赖项资源管理器中显示类成员大纲",
1215
"configuration.java.dependency.syncWithFolderExplorer": "在 Java 依赖项资源管理器中同步关联当前打开的文件",

src/commands.ts

+6
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ export namespace Commands {
2424

2525
export const VIEW_PACKAGE_OUTLINE = "java.view.package.outline";
2626

27+
export const VIEW_PACKAGE_REVEAL_FILE_OS = "java.view.package.revealFileInOS";
28+
29+
export const VIEW_PACKAGE_COPY_FILE_PATH = "java.view.package.copyFilePath";
30+
31+
export const VIEW_PACKAGE_COPY_RELATIVE_FILE_PATH = "java.view.package.copyRelativeFilePath";
32+
2733
export const JAVA_PROJECT_CREATE = "java.project.create";
2834

2935
export const JAVA_PROJECT_LIST = "java.project.list";

src/views/dependencyDataProvider.ts

+6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ export class DependencyDataProvider implements TreeDataProvider<ExplorerNode> {
2828

2929
constructor(public readonly context: ExtensionContext) {
3030
context.subscriptions.push(commands.registerCommand(Commands.VIEW_PACKAGE_REFRESH, (debounce?: boolean) => this.refreshWithLog(debounce)));
31+
context.subscriptions.push(commands.registerCommand(Commands.VIEW_PACKAGE_REVEAL_FILE_OS,
32+
(node: INodeData) => commands.executeCommand("revealFileInOS", Uri.parse(node.uri))));
33+
context.subscriptions.push(commands.registerCommand(Commands.VIEW_PACKAGE_COPY_FILE_PATH,
34+
(node: INodeData) => commands.executeCommand("copyFilePath", Uri.parse(node.uri))));
35+
context.subscriptions.push(commands.registerCommand(Commands.VIEW_PACKAGE_COPY_RELATIVE_FILE_PATH,
36+
(node: INodeData) => commands.executeCommand("copyRelativeFilePath", Uri.parse(node.uri))));
3137
context.subscriptions.push(commands.registerCommand(Commands.VIEW_PACKAGE_OPEN_FILE,
3238
instrumentOperation(Commands.VIEW_PACKAGE_OPEN_FILE, (_operationId, uri) => this.openFile(uri))));
3339
context.subscriptions.push(commands.registerCommand(Commands.VIEW_PACKAGE_OUTLINE,

0 commit comments

Comments
 (0)