diff --git a/jdtls.ext/com.microsoft.jdtls.ext.core/.settings/org.eclipse.jdt.core.prefs b/jdtls.ext/com.microsoft.jdtls.ext.core/.settings/org.eclipse.jdt.core.prefs index 5b3d27d8..a7e5d63e 100644 --- a/jdtls.ext/com.microsoft.jdtls.ext.core/.settings/org.eclipse.jdt.core.prefs +++ b/jdtls.ext/com.microsoft.jdtls.ext.core/.settings/org.eclipse.jdt.core.prefs @@ -104,8 +104,11 @@ org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning org.eclipse.jdt.core.compiler.source=1.8 +org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false +org.eclipse.jdt.core.formatter.align_with_spaces=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 @@ -115,6 +118,7 @@ org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_e org.eclipse.jdt.core.formatter.alignment_for_assignment=0 org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 +org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 @@ -158,6 +162,8 @@ org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=false +org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=true @@ -382,6 +388,9 @@ org.eclipse.jdt.core.formatter.join_wrapped_lines=true org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false org.eclipse.jdt.core.formatter.lineSplit=160 org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false @@ -399,10 +408,10 @@ org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true -org.eclipse.jdt.core.formatter.tabulation.char=tab +org.eclipse.jdt.core.formatter.tabulation.char=space org.eclipse.jdt.core.formatter.tabulation.size=4 org.eclipse.jdt.core.formatter.use_on_off_tags=false -org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true diff --git a/jdtls.ext/com.microsoft.jdtls.ext.core/.settings/org.eclipse.jdt.ui.prefs b/jdtls.ext/com.microsoft.jdtls.ext.core/.settings/org.eclipse.jdt.ui.prefs index 9c075644..9cfef937 100644 --- a/jdtls.ext/com.microsoft.jdtls.ext.core/.settings/org.eclipse.jdt.ui.prefs +++ b/jdtls.ext/com.microsoft.jdtls.ext.core/.settings/org.eclipse.jdt.ui.prefs @@ -58,8 +58,8 @@ cleanup_profile=org.eclipse.jdt.ui.default.eclipse_clean_up_profile cleanup_settings_version=2 eclipse.preferences.version=1 editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true -formatter_profile=_JDTLS.EXT -formatter_settings_version=13 +formatter_profile=_Java Dependency +formatter_settings_version=14 org.eclipse.jdt.ui.javadoc=true org.eclipse.jdt.ui.text.custom_code_templates= sp_cleanup.add_default_serial_version_id=true diff --git a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/JarFileContentProvider.java b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/JarFileContentProvider.java index 3970b017..5be1940c 100644 --- a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/JarFileContentProvider.java +++ b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/JarFileContentProvider.java @@ -15,13 +15,16 @@ import java.io.InputStream; import java.net.URI; import java.nio.charset.StandardCharsets; +import java.util.Arrays; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.IJarEntryResource; +import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.internal.core.JarEntryDirectory; @@ -64,6 +67,24 @@ private String getContent(String rootId, String path, IProgressMonitor pm) { } } } + // if the file exists in the java packages + String[] segments = StringUtils.split(path, "/"); + String packageName = StringUtils.join(Arrays.asList(segments).subList(0, segments.length - 1), '.'); + IPackageFragment packageFragment = packageRoot.getPackageFragment(packageName); + if (packageFragment != null && packageFragment.exists()) { + + Object[] objs = packageFragment.getNonJavaResources(); + for (Object obj : objs) { + if (obj instanceof IJarEntryResource) { + IJarEntryResource child = (IJarEntryResource) obj; + if (child instanceof JarEntryFile && child.getFullPath().toPortableString().equals(path)) { + return readFileContent((JarEntryFile) child); + } + } + + } + } + } } catch (CoreException e) { JavaLanguageServerPlugin.logException("Problem get JarEntryFile content ", e); diff --git a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/PackageCommand.java b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/PackageCommand.java index bfca48eb..e45bd645 100644 --- a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/PackageCommand.java +++ b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/PackageCommand.java @@ -10,6 +10,7 @@ *******************************************************************************/ package com.microsoft.jdtls.ext.core; +import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -19,11 +20,15 @@ import java.util.function.BiFunction; import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; @@ -38,6 +43,7 @@ import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; +import org.eclipse.jdt.core.ITypeRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.core.JarEntryDirectory; @@ -72,7 +78,7 @@ public class PackageCommand { commands.put(NodeKind.CONTAINER, PackageCommand::getPackageFragmentRoots); commands.put(NodeKind.PACKAGEROOT, PackageCommand::getPackages); commands.put(NodeKind.PACKAGE, PackageCommand::getRootTypes); - commands.put(NodeKind.Folder, PackageCommand::getFolderChildren); + commands.put(NodeKind.FOLDER, PackageCommand::getFolderChildren); } /** @@ -118,26 +124,45 @@ public static List resolvePath(List arguments, IProgressMon List result = new ArrayList<>(); - ICompilationUnit cu = JDTUtils.resolveCompilationUnit(typeRootUri); - if (cu != null) { + URI uri = JDTUtils.toURI(typeRootUri); + ITypeRoot typeRoot = null; + if ("jdt".equals(uri.getScheme())) { + typeRoot = JDTUtils.resolveClassFile(uri); + } else { + typeRoot = JDTUtils.resolveCompilationUnit(uri); + } + if (typeRoot != null) { // Add project node: - IProject proj = cu.getJavaProject().getProject(); + IProject proj = typeRoot.getJavaProject().getProject(); PackageNode projectNode = new PackageNode(proj.getName(), proj.getFullPath().toPortableString(), NodeKind.PROJECT); projectNode.setUri(proj.getLocationURI().toString()); result.add(projectNode); - IPackageFragment packageFragment = (IPackageFragment) cu.getParent(); + IPackageFragment packageFragment = (IPackageFragment) typeRoot.getParent(); String packageName = packageFragment.isDefaultPackage() ? DEFAULT_PACKAGE_DISPLAYNAME : packageFragment.getElementName(); PackageNode packageNode = new PackageNode(packageName, packageFragment.getPath().toPortableString(), NodeKind.PACKAGE); IPackageFragmentRoot pkgRoot = (IPackageFragmentRoot) packageFragment.getParent(); - PackageNode rootNode = new PackageRootNode( - ExtUtils.removeProjectSegment(cu.getJavaProject().getElementName(), pkgRoot.getPath()).toPortableString(), - pkgRoot.getPath().toPortableString(), NodeKind.PACKAGEROOT, pkgRoot.getKind()); + PackageNode rootNode = null; + if (typeRoot instanceof IClassFile) { + rootNode = new PackageRootNode(pkgRoot.getElementName(), pkgRoot.getPath().toPortableString(), NodeKind.PACKAGEROOT, pkgRoot.getKind()); + } else { + rootNode = new PackageRootNode(ExtUtils.removeProjectSegment(typeRoot.getJavaProject().getElementName(), pkgRoot.getPath()).toPortableString(), + pkgRoot.getPath().toPortableString(), NodeKind.PACKAGEROOT, pkgRoot.getKind()); + } + // TODO: Let the client handle the display instead. Server side should always + // provide the container node. + if (typeRoot instanceof IClassFile) { + IClasspathEntry entry = pkgRoot.getRawClasspathEntry(); + IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), typeRoot.getJavaProject()); + PackageNode containerNode = new ContainerNode(container.getDescription(), container.getPath().toPortableString(), NodeKind.CONTAINER, + entry.getEntryKind()); + result.add(containerNode); + } result.add(rootNode); result.add(packageNode); - PackageNode item = new TypeRootNode(cu.getElementName(), cu.getPath().toPortableString(), NodeKind.TYPEROOT, TypeRootNode.K_SOURCE); - item.setUri(JDTUtils.toURI(cu)); + PackageNode item = new TypeRootNode(typeRoot.getElementName(), typeRoot.getPath().toPortableString(), NodeKind.TYPEROOT, TypeRootNode.K_SOURCE); + item.setUri(JDTUtils.toUri(typeRoot)); result.add(item); } @@ -228,7 +253,7 @@ private static List getPackages(PackageParams query, IProgressMonit new Status(IStatus.ERROR, JdtlsExtActivator.PLUGIN_ID, String.format("No package root found for %s", query.getPath()))); } Object[] result = getPackageFragmentRootContent(packageRoot, pm); - return convertToPackageNode(result); + return convertToPackageNode(result, packageRoot); } catch (CoreException e) { JdtlsExtActivator.logException("Problem load project package ", e); } @@ -248,7 +273,8 @@ private static List getRootTypes(PackageParams query, IProgressMoni IPackageFragment packageFragment = packageRoot.getPackageFragment(DEFAULT_PACKAGE_DISPLAYNAME.equals(query.getPath()) ? "" : query.getPath()); if (packageFragment != null) { IJavaElement[] types = packageFragment.getChildren(); - return Arrays.stream(types).filter(typeRoot -> !typeRoot.getElementName().contains("$")).map(typeRoot -> { + Object[] nonJavaResources = packageFragment.getNonJavaResources(); + List rootTypeNodes = Arrays.stream(types).filter(typeRoot -> !typeRoot.getElementName().contains("$")).map(typeRoot -> { PackageNode item = new TypeRootNode(typeRoot.getElementName(), typeRoot.getPath().toPortableString(), NodeKind.TYPEROOT, typeRoot instanceof IClassFile ? TypeRootNode.K_BINARY : TypeRootNode.K_SOURCE); if (typeRoot instanceof ICompilationUnit) { @@ -258,7 +284,26 @@ private static List getRootTypes(PackageParams query, IProgressMoni } return item; }).collect(Collectors.toList()); - + if (nonJavaResources.length == 0) { + return rootTypeNodes; + } + // when .java files and other .properties files are mixed up + rootTypeNodes.addAll( + Arrays.stream(nonJavaResources).filter(resource -> resource instanceof IFile || resource instanceof JarEntryFile).map(resource -> { + if (resource instanceof IFile) { + IFile file = (IFile) resource; + PackageNode item = new PackageNode(file.getName(), file.getFullPath().toPortableString(), NodeKind.FILE); + item.setUri(JDTUtils.getFileURI(file)); + return item; + } else { + JarEntryFile file = (JarEntryFile) resource; + PackageNode entry = new PackageNode(file.getName(), file.getFullPath().toPortableString(), NodeKind.FILE); + entry.setUri(ExtUtils.toUri((JarEntryFile) resource)); + return entry; + } + + }).collect(Collectors.toList())); + return rootTypeNodes; } } catch (CoreException e) { JdtlsExtActivator.logException("Problem load project classfile list ", e); @@ -276,17 +321,27 @@ private static List getFolderChildren(PackageParams query, IProgres throw new CoreException( new Status(IStatus.ERROR, JdtlsExtActivator.PLUGIN_ID, String.format("No package root found for %s", query.getPath()))); } - // jar file and folders - Object[] resources = packageRoot.getNonJavaResources(); - for (Object resource : resources) { - if (pm.isCanceled()) { - throw new OperationCanceledException(); + if (packageRoot.getKind() == IPackageFragmentRoot.K_BINARY) { + Object[] resources = packageRoot.getNonJavaResources(); + for (Object resource : resources) { + if (pm.isCanceled()) { + throw new OperationCanceledException(); + } + if (resource instanceof JarEntryDirectory) { + JarEntryDirectory directory = (JarEntryDirectory) resource; + Object[] children = findJarDirectoryChildren(directory, query.getPath()); + if (children != null) { + return convertToPackageNode(children, null); + } + } } - if (resource instanceof JarEntryDirectory) { - JarEntryDirectory directory = (JarEntryDirectory) resource; - Object[] children = findJarDirectoryChildren(directory, query.getPath()); + } else { + IFolder folder = javaProject.getProject().getFolder(new Path(query.getPath()).makeRelativeTo(javaProject.getProject().getFullPath())); + if (folder != null && folder.exists()) { + Object[] children = JavaCore.create(folder) != null ? Arrays.stream(folder.members()).filter(t -> t instanceof IFile).toArray() + : folder.members(); if (children != null) { - return convertToPackageNode(children); + return convertToPackageNode(children, null); } } } @@ -304,6 +359,8 @@ private static Object[] getPackageFragmentRootContent(IPackageFragmentRoot root, IPackageFragment fragment = (IPackageFragment) child; if (fragment.hasChildren()) { result.add(child); + } else if (fragment.getNonJavaResources().length > 0) { // some package has non-java files + result.add(fragment); } } Object[] nonJavaResources = root.getNonJavaResources(); @@ -311,7 +368,7 @@ private static Object[] getPackageFragmentRootContent(IPackageFragmentRoot root, return result.toArray(); } - private static List convertToPackageNode(Object[] rootContent) throws JavaModelException { + private static List convertToPackageNode(Object[] rootContent, IPackageFragmentRoot packageRoot) throws JavaModelException { List result = new ArrayList<>(); for (Object root : rootContent) { if (root instanceof IPackageFragment) { @@ -329,6 +386,24 @@ private static List convertToPackageNode(Object[] rootContent) thro if (jarNode != null) { result.add(jarNode); } + } else if (root instanceof IFile) { + IFile file = (IFile) root; + PackageNode entry = new PackageNode(file.getName(), file.getFullPath().toPortableString(), NodeKind.FILE); + entry.setUri(JDTUtils.getFileURI(file)); + result.add(entry); + } else if (root instanceof IFolder) { + IFolder folder = (IFolder) root; + String displayName = folder.getName(); + if (packageRoot != null) { + // together with package list, we need to provide full folder name relative to + // package root + IPath path = folder.getFullPath().makeRelativeTo(packageRoot.getPath()); + displayName = StringUtils.replace(path.toPortableString(), "/", "."); + } + + PackageNode entry = new PackageNode(displayName, folder.getFullPath().toPortableString(), NodeKind.FOLDER); + entry.setUri(JDTUtils.getFileURI(folder)); + result.add(entry); } } @@ -337,7 +412,7 @@ private static List convertToPackageNode(Object[] rootContent) thro private static PackageNode getJarEntryResource(JarEntryResource resource) { if (resource instanceof JarEntryDirectory) { - return new PackageNode(resource.getName(), resource.getFullPath().toPortableString(), NodeKind.Folder); + return new PackageNode(resource.getName(), resource.getFullPath().toPortableString(), NodeKind.FOLDER); } else if (resource instanceof JarEntryFile) { PackageNode entry = new PackageNode(resource.getName(), resource.getFullPath().toPortableString(), NodeKind.FILE); entry.setUri(ExtUtils.toUri((JarEntryFile) resource)); diff --git a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/NodeKind.java b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/NodeKind.java index 5ac371de..a57b58e7 100644 --- a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/NodeKind.java +++ b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/NodeKind.java @@ -24,7 +24,7 @@ public enum NodeKind { TYPEROOT(6), - Folder(7), + FOLDER(7), FILE(8); diff --git a/src/views/dependencyExplorer.ts b/src/views/dependencyExplorer.ts index a3e87599..4c80ee89 100644 --- a/src/views/dependencyExplorer.ts +++ b/src/views/dependencyExplorer.ts @@ -23,7 +23,7 @@ export class DependencyExplorer { this._dependencyViewer = window.createTreeView("javaDependencyExplorer", { treeDataProvider: this._dataProvider }); window.onDidChangeActiveTextEditor((textEditor: TextEditor) => { - if (textEditor && textEditor.document && textEditor.document.languageId === "java" && Settings.syncWithFolderExplorer()) { + if (textEditor && textEditor.document && Settings.syncWithFolderExplorer()) { this.reveal(textEditor.document.uri); } }); @@ -63,7 +63,7 @@ export class DependencyExplorer { private visitChildren(children: DataNode[], paths: INodeData[]): void { if (children && paths) { for (const c of children) { - if (c.path === paths[0].path) { + if (paths[0] && c.path === paths[0].path && c.nodeData.name === paths[0].name) { if (paths.length === 1) { if (this._dependencyViewer.visible) { this._dependencyViewer.reveal(c); diff --git a/src/views/packageNode.ts b/src/views/packageNode.ts index 0cf6de8f..a453f84b 100644 --- a/src/views/packageNode.ts +++ b/src/views/packageNode.ts @@ -5,6 +5,7 @@ import { Jdtls } from "../java/jdtls"; import { INodeData, NodeKind } from "../java/nodeData"; import { DataNode } from "./dataNode"; import { ExplorerNode } from "./explorerNode"; +import { FileNode } from "./fileNode"; import { TypeRootNode } from "./typeRootNode"; export class PackageNode extends DataNode { @@ -26,7 +27,11 @@ export class PackageNode extends DataNode { if (this.nodeData.children && this.nodeData.children.length) { this.sort(); this.nodeData.children.forEach((nodeData) => { - result.push(new TypeRootNode(nodeData, this)); + if (nodeData.kind === NodeKind.File) { + result.push(new FileNode(nodeData, this)); + } else { + result.push(new TypeRootNode(nodeData, this)); + } }); } return result;