initial implementation towards a compilation-unit-based content-assist for types and packages
This commit is contained in:
@@ -68,6 +68,8 @@ import org.springframework.ide.vscode.commons.protocol.HighlightParams;
|
||||
import org.springframework.ide.vscode.commons.protocol.ProgressParams;
|
||||
import org.springframework.ide.vscode.commons.protocol.STS4LanguageClient;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.ClasspathListenerParams;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaCodeCompleteData;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaCodeCompleteParams;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaDataParams;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaSearchParams;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaTypeHierarchyParams;
|
||||
@@ -75,6 +77,7 @@ import org.springframework.ide.vscode.commons.protocol.java.TypeData;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.TypeDescriptorData;
|
||||
import org.springframework.tooling.jdt.ls.commons.Logger;
|
||||
import org.springframework.tooling.jdt.ls.commons.classpath.ReusableClasspathListenerHandler;
|
||||
import org.springframework.tooling.jdt.ls.commons.java.JavaCodeCompletion;
|
||||
import org.springframework.tooling.jdt.ls.commons.java.JavaData;
|
||||
import org.springframework.tooling.jdt.ls.commons.java.JavaFluxSearch;
|
||||
import org.springframework.tooling.jdt.ls.commons.java.TypeHierarchy;
|
||||
@@ -125,11 +128,10 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
|
||||
}
|
||||
}
|
||||
|
||||
final private JavaData javaData = new JavaData(STS4LanguageClientImpl::label , Logger.forEclipsePlugin(LanguageServerCommonsActivator::getInstance));
|
||||
|
||||
final private JavaFluxSearch javaFluxSearch = new JavaFluxSearch(Logger.forEclipsePlugin(LanguageServerCommonsActivator::getInstance), javaData);
|
||||
|
||||
final private TypeHierarchy typeHierarchy = new TypeHierarchy(Logger.forEclipsePlugin(LanguageServerCommonsActivator::getInstance), javaData);
|
||||
private final JavaData javaData = new JavaData(STS4LanguageClientImpl::label , Logger.forEclipsePlugin(LanguageServerCommonsActivator::getInstance));
|
||||
private final JavaFluxSearch javaFluxSearch = new JavaFluxSearch(Logger.forEclipsePlugin(LanguageServerCommonsActivator::getInstance), javaData);
|
||||
private final TypeHierarchy typeHierarchy = new TypeHierarchy(Logger.forEclipsePlugin(LanguageServerCommonsActivator::getInstance), javaData);
|
||||
private final JavaCodeCompletion codeComplete = new JavaCodeCompletion();
|
||||
|
||||
private static final String ANNOTION_TYPE_ID = "org.springframework.tooling.bootinfo";
|
||||
|
||||
@@ -482,4 +484,17 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<JavaCodeCompleteData>> javaCodeComplete(JavaCodeCompleteParams params) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
return codeComplete.codeComplete(params.getProjectUri(), params.getPrefix(), params.isIncludeTypes(), params.isIncludePackages());
|
||||
} catch (Exception e) {
|
||||
LanguageServerCommonsActivator.logError(e, "Failed to do code complete with prefix '" + params.getPrefix()
|
||||
+ "' in project " + params.getProjectUri());
|
||||
return Collections.emptyList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ import org.eclipse.lsp4j.jsonrpc.services.JsonNotification;
|
||||
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest;
|
||||
import org.eclipse.lsp4j.services.LanguageClient;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.ClasspathListenerParams;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaCodeCompleteData;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaCodeCompleteParams;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaDataParams;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaSearchParams;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaTypeHierarchyParams;
|
||||
@@ -71,4 +73,7 @@ public interface STS4LanguageClient extends LanguageClient {
|
||||
@JsonRequest("sts/javaSuperTypes")
|
||||
CompletableFuture<List<TypeDescriptorData>> javaSuperTypes(JavaTypeHierarchyParams params);
|
||||
|
||||
@JsonRequest("sts/javaCodeComplete")
|
||||
CompletableFuture<List<JavaCodeCompleteData>> javaCodeComplete(JavaCodeCompleteParams params);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.protocol.java;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class JavaCodeCompleteData {
|
||||
|
||||
public static final String PACKAGE_PROPOSAL = "package";
|
||||
public static final String CLASS_PROPOSAL = "class";
|
||||
public static final String INTERFACE_PROPOSAL = "interface";
|
||||
public static final String ENUM_PROPOSAL = "enum";
|
||||
|
||||
private String kind;
|
||||
private String fullyQualifiedName;
|
||||
private int relevance;
|
||||
|
||||
public String getFullyQualifiedName() {
|
||||
return this.fullyQualifiedName;
|
||||
}
|
||||
|
||||
public void setFullyQualifiedName(String fullyQualifiedName) {
|
||||
this.fullyQualifiedName = fullyQualifiedName;
|
||||
}
|
||||
|
||||
public String getKind() {
|
||||
return this.kind;
|
||||
}
|
||||
|
||||
public void setKind(String kind) {
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
public int getRelevance() {
|
||||
return this.relevance;
|
||||
}
|
||||
|
||||
public void setRelevance(int relevance) {
|
||||
this.relevance = relevance;
|
||||
}
|
||||
|
||||
public boolean isInterfaceProposal() {
|
||||
return INTERFACE_PROPOSAL.equals(kind);
|
||||
}
|
||||
|
||||
public boolean isEnumProposal() {
|
||||
return ENUM_PROPOSAL.equals(kind);
|
||||
}
|
||||
|
||||
public boolean isPackageProposal() {
|
||||
return PACKAGE_PROPOSAL.equals(kind);
|
||||
}
|
||||
|
||||
public boolean isClassProposal() {
|
||||
return CLASS_PROPOSAL.equals(kind);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.protocol.java;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class JavaCodeCompleteParams {
|
||||
|
||||
private String projectUri;
|
||||
private String prefix;
|
||||
private boolean includeTypes;
|
||||
private boolean includePackages;
|
||||
|
||||
public JavaCodeCompleteParams(String projectUri, String prefix, boolean includeTypes, boolean includePackages) {
|
||||
super();
|
||||
this.projectUri = projectUri;
|
||||
this.prefix = prefix;
|
||||
this.includeTypes = includeTypes;
|
||||
this.includePackages = includePackages;
|
||||
}
|
||||
|
||||
public String getProjectUri() {
|
||||
return projectUri;
|
||||
}
|
||||
|
||||
public void setProjectUri(String projectUri) {
|
||||
this.projectUri = projectUri;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public void setPrefix(String prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public boolean isIncludeTypes() {
|
||||
return includeTypes;
|
||||
}
|
||||
|
||||
public void setIncludeTypes(boolean includeTypes) {
|
||||
this.includeTypes = includeTypes;
|
||||
}
|
||||
|
||||
public boolean isIncludePackages() {
|
||||
return includePackages;
|
||||
}
|
||||
|
||||
public void setIncludePackages(boolean includePackages) {
|
||||
this.includePackages = includePackages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (includePackages ? 1231 : 1237);
|
||||
result = prime * result + (includeTypes ? 1231 : 1237);
|
||||
result = prime * result + ((prefix == null) ? 0 : prefix.hashCode());
|
||||
result = prime * result + ((projectUri == null) ? 0 : projectUri.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
JavaCodeCompleteParams other = (JavaCodeCompleteParams) obj;
|
||||
if (includePackages != other.includePackages)
|
||||
return false;
|
||||
if (includeTypes != other.includeTypes)
|
||||
return false;
|
||||
if (prefix == null) {
|
||||
if (other.prefix != null)
|
||||
return false;
|
||||
} else if (!prefix.equals(other.prefix))
|
||||
return false;
|
||||
if (projectUri == null) {
|
||||
if (other.projectUri != null)
|
||||
return false;
|
||||
} else if (!projectUri.equals(other.projectUri))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -113,6 +113,8 @@ import org.springframework.ide.vscode.commons.protocol.HighlightParams;
|
||||
import org.springframework.ide.vscode.commons.protocol.ProgressParams;
|
||||
import org.springframework.ide.vscode.commons.protocol.STS4LanguageClient;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.ClasspathListenerParams;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaCodeCompleteData;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaCodeCompleteParams;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaDataParams;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaSearchParams;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaTypeHierarchyParams;
|
||||
@@ -387,6 +389,11 @@ public class LanguageServerHarness {
|
||||
return CompletableFuture.completedFuture(Collections.emptyList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<JavaCodeCompleteData>> javaCodeComplete(JavaCodeCompleteParams params) {
|
||||
return CompletableFuture.completedFuture(Collections.emptyList());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.tooling.jdt.ls.commons.java;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaCodeCompleteData;
|
||||
import org.springframework.tooling.jdt.ls.commons.resources.ResourceUtils;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class JavaCodeCompletion {
|
||||
|
||||
public List<JavaCodeCompleteData> codeComplete(String project, String prefix, boolean includeTypes, boolean includePackages) throws Exception {
|
||||
URI projectUri = project == null ? null : URI.create(project);
|
||||
IJavaProject javaProject = projectUri == null ? null : ResourceUtils.getJavaProject(projectUri);
|
||||
|
||||
JavaCodeCompletionProposalCollector collector = new JavaCodeCompletionProposalCollector(includeTypes, includePackages);
|
||||
JavaCodeCompletionUtils.codeComplete(javaProject, prefix, collector);
|
||||
|
||||
return collector.getProposals();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.tooling.jdt.ls.commons.java;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.CompletionProposal;
|
||||
import org.eclipse.jdt.core.CompletionRequestor;
|
||||
import org.eclipse.jdt.core.Flags;
|
||||
import org.eclipse.jdt.core.Signature;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaCodeCompleteData;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class JavaCodeCompletionProposalCollector extends CompletionRequestor {
|
||||
|
||||
private final boolean includeTypes;
|
||||
private final boolean includePackages;
|
||||
private final List<JavaCodeCompleteData> proposals;
|
||||
|
||||
public JavaCodeCompletionProposalCollector(boolean includeTypes, boolean includePackages) {
|
||||
this.includeTypes = includeTypes;
|
||||
this.includePackages = includePackages;
|
||||
this.proposals = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(CompletionProposal proposal) {
|
||||
if (includeTypes && proposal.getKind() == CompletionProposal.TYPE_REF) {
|
||||
if (!JavaCodeCompletionUtils.CLASS_NAME.equals(String.valueOf(proposal.getCompletion()))) {
|
||||
addTypeProposal(proposal);
|
||||
}
|
||||
}
|
||||
else if (includePackages && proposal.getKind() == CompletionProposal.PACKAGE_REF) {
|
||||
addPackageProposal(proposal);
|
||||
}
|
||||
}
|
||||
|
||||
public List<JavaCodeCompleteData> getProposals() {
|
||||
return proposals;
|
||||
}
|
||||
|
||||
private void addPackageProposal(CompletionProposal proposal) {
|
||||
JavaCodeCompleteData proposalData = new JavaCodeCompleteData();
|
||||
|
||||
proposalData.setKind(JavaCodeCompleteData.PACKAGE_PROPOSAL);
|
||||
proposalData.setRelevance(proposal.getRelevance());
|
||||
proposalData.setFullyQualifiedName(String.valueOf(proposal.getDeclarationSignature()));
|
||||
|
||||
this.proposals.add(proposalData);
|
||||
}
|
||||
|
||||
private void addTypeProposal(CompletionProposal proposal) {
|
||||
JavaCodeCompleteData proposalData = new JavaCodeCompleteData();
|
||||
|
||||
if (Flags.isInterface(proposal.getFlags())) {
|
||||
proposalData.setKind(JavaCodeCompleteData.INTERFACE_PROPOSAL);
|
||||
}
|
||||
else if (Flags.isEnum(proposal.getFlags())) {
|
||||
proposalData.setKind(JavaCodeCompleteData.ENUM_PROPOSAL);
|
||||
}
|
||||
else {
|
||||
proposalData.setKind(JavaCodeCompleteData.CLASS_PROPOSAL);
|
||||
}
|
||||
proposalData.setRelevance(proposal.getRelevance());
|
||||
|
||||
String fullyQualifiedName = String.valueOf(Signature.toCharArray(proposal.getSignature()));
|
||||
proposalData.setFullyQualifiedName(fullyQualifiedName);
|
||||
|
||||
this.proposals.add(proposalData);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.tooling.jdt.ls.commons.java;
|
||||
|
||||
import org.eclipse.jdt.core.IBuffer;
|
||||
import org.eclipse.jdt.core.ICompilationUnit;
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
import org.eclipse.jdt.core.IPackageFragment;
|
||||
import org.eclipse.jdt.core.IPackageFragmentRoot;
|
||||
import org.eclipse.jdt.core.JavaModelException;
|
||||
import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
@SuppressWarnings("restriction")
|
||||
public class JavaCodeCompletionUtils {
|
||||
|
||||
public static final String CLASS_NAME = "_xxx";
|
||||
|
||||
private static final String CLASS_SOURCE_START = "public class " + CLASS_NAME + " {\n"
|
||||
+ " public void main(String[] args) {\n" + " ";
|
||||
|
||||
private static final String CLASS_SOURCE_END = "\n" + " }\n" + "}";
|
||||
|
||||
|
||||
public static void codeComplete(IJavaProject project, String prefix, JavaCodeCompletionProposalCollector proposalCollector) {
|
||||
if (prefix == null || prefix.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ICompilationUnit unit = createCompilationUnit(project, prefix);
|
||||
|
||||
prefix = prefix.replace('$', '.');
|
||||
|
||||
String sourceStart = CLASS_SOURCE_START + prefix;
|
||||
String packageName = null;
|
||||
|
||||
int dot = prefix.lastIndexOf('.');
|
||||
if (dot > -1) {
|
||||
packageName = prefix.substring(0, dot);
|
||||
sourceStart = "package " + packageName + ";\n" + sourceStart;
|
||||
}
|
||||
|
||||
String source = sourceStart + CLASS_SOURCE_END;
|
||||
setContents(unit, source);
|
||||
|
||||
unit.codeComplete(sourceStart.length(), proposalCollector, DefaultWorkingCopyOwner.PRIMARY);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
private static ICompilationUnit createCompilationUnit(IJavaProject project, String prefix) throws JavaModelException {
|
||||
IPackageFragment root = getPackageFragment(project, prefix);
|
||||
ICompilationUnit unit = root.getCompilationUnit("_xxx.java").getWorkingCopy(null);
|
||||
return unit;
|
||||
}
|
||||
|
||||
private static IPackageFragment getPackageFragment(IJavaProject project, String prefix) throws JavaModelException {
|
||||
int dot = prefix.lastIndexOf('.');
|
||||
if (dot > -1) {
|
||||
String packageName = prefix.substring(0, dot);
|
||||
for (IPackageFragmentRoot root : project.getPackageFragmentRoots()) {
|
||||
IPackageFragment p = root.getPackageFragment(packageName);
|
||||
if (p != null && p.exists()) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
IPackageFragment[] packages = project.getPackageFragments();
|
||||
for (IPackageFragment p : packages) {
|
||||
if (p.getElementName().equals(packageName))
|
||||
return p;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (IPackageFragmentRoot p : project.getAllPackageFragmentRoots()) {
|
||||
if (p.getKind() == IPackageFragmentRoot.K_SOURCE) {
|
||||
return p.getPackageFragment("");
|
||||
}
|
||||
}
|
||||
}
|
||||
return project.getPackageFragments()[0];
|
||||
}
|
||||
|
||||
private static void setContents(ICompilationUnit cu, String source) {
|
||||
if (cu == null)
|
||||
return;
|
||||
|
||||
synchronized (cu) {
|
||||
IBuffer buffer;
|
||||
try {
|
||||
|
||||
buffer = cu.getBuffer();
|
||||
}
|
||||
catch (JavaModelException e) {
|
||||
e.printStackTrace();
|
||||
buffer = null;
|
||||
}
|
||||
|
||||
if (buffer != null)
|
||||
buffer.setContents(source);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -41,6 +41,7 @@ public class JavaFluxSearch {
|
||||
public List<String> fuzzySearchPackages(JavaSearchParams params) throws Exception {
|
||||
URI projectUri = params.getProjectUri() == null ? null : URI.create(params.getProjectUri());
|
||||
IJavaProject javaProject = projectUri == null ? null : ResourceUtils.getJavaProject(projectUri);
|
||||
|
||||
PackageFluxSearch fluxPackageSearch = packageSearchCache.get(
|
||||
Tuples.of(params.isIncludeBinaries(), params.isIncludeSystemLibs()), () -> new PackageFluxSearch(logger, params.isIncludeBinaries(), params.isIncludeSystemLibs())
|
||||
);
|
||||
@@ -50,6 +51,7 @@ public class JavaFluxSearch {
|
||||
public List<TypeDescriptorData> fuzzySearchTypes(JavaSearchParams params) throws Exception {
|
||||
URI projectUri = params.getProjectUri() == null ? null : URI.create(params.getProjectUri());
|
||||
IJavaProject javaProject = projectUri == null ? null : ResourceUtils.getJavaProject(projectUri);
|
||||
|
||||
TypeFluxSearch fluxTypeSearch = typeSearchCache.get(
|
||||
Tuples.of(params.isIncludeBinaries(), params.isIncludeSystemLibs()), () -> new TypeFluxSearch(logger, javaData, params.isIncludeBinaries(), params.isIncludeSystemLibs())
|
||||
);
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.springframework.ide.vscode.boot.xml.completions.TypeCompletionProposa
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
/**
|
||||
@@ -51,12 +51,12 @@ public class SpringXMLCompletionEngine implements ICompletionEngine {
|
||||
private final BootJavaConfig config;
|
||||
|
||||
public SpringXMLCompletionEngine(SpringXMLLanguageServerComponents springXMLLanguageServerComponents,
|
||||
JavaProjectFinder projectFinder, SpringSymbolIndex symbolIndex, SimpleTextDocumentService simpleTextDocumentService, BootJavaConfig config) {
|
||||
SimpleLanguageServer server, JavaProjectFinder projectFinder, SpringSymbolIndex symbolIndex, BootJavaConfig config) {
|
||||
|
||||
this.config = config;
|
||||
|
||||
|
||||
this.completionProviders = new HashMap<>();
|
||||
this.completionProviders.put(new XMLCompletionProviderKey(BEANS_NAMESPACE, null, BEAN_ELEMENT, CLASS_ATTRIBUTE), new TypeCompletionProposalProvider(projectFinder, simpleTextDocumentService, true));
|
||||
this.completionProviders.put(new XMLCompletionProviderKey(BEANS_NAMESPACE, null, BEAN_ELEMENT, CLASS_ATTRIBUTE), new TypeCompletionProposalProvider(server, projectFinder, true, true, false, false));
|
||||
this.completionProviders.put(new XMLCompletionProviderKey(BEANS_NAMESPACE, BEAN_ELEMENT, PROPERTY_ELEMENT, NAME_ATTRIBUTE), new PropertyNameCompletionProposalProvider(projectFinder));
|
||||
this.completionProviders.put(new XMLCompletionProviderKey(BEANS_NAMESPACE, BEAN_ELEMENT, PROPERTY_ELEMENT, REF_ATTRIBUTE), new BeanRefCompletionProposalProvider(projectFinder, symbolIndex));
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public class SpringXMLLanguageServerComponents implements LanguageServerComponen
|
||||
server.doOnInitialized(this::initialized);
|
||||
server.onShutdown(this::shutdown);
|
||||
|
||||
this.completionEngine = new SpringXMLCompletionEngine(this, projectFinder, symbolIndex, server.getTextDocumentService(), config);
|
||||
this.completionEngine = new SpringXMLCompletionEngine(this, server, projectFinder, symbolIndex, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -12,9 +12,10 @@ package org.springframework.ide.vscode.boot.xml.completions;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.lsp4j.CompletionItemKind;
|
||||
import org.eclipse.lsp4xml.dom.DOMAttr;
|
||||
@@ -22,33 +23,35 @@ import org.eclipse.lsp4xml.dom.DOMNode;
|
||||
import org.eclipse.lsp4xml.dom.parser.Scanner;
|
||||
import org.springframework.ide.vscode.boot.xml.XMLCompletionProvider;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.IType;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaCodeCompleteData;
|
||||
import org.springframework.ide.vscode.commons.protocol.java.JavaCodeCompleteParams;
|
||||
import org.springframework.ide.vscode.commons.util.Renderable;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class TypeCompletionProposalProvider implements XMLCompletionProvider {
|
||||
|
||||
private final JavaProjectFinder projectFinder;
|
||||
private final boolean classesOnly;
|
||||
private final Set<String> typeSearchAlreadyInitializedProjects = Collections.synchronizedSet(new HashSet<>());
|
||||
private final SimpleLanguageServer server;
|
||||
private final boolean packagesAllowed;
|
||||
private final boolean classesAllowed;
|
||||
private final boolean interfacesAllowed;
|
||||
private final boolean enumsAllowed;
|
||||
|
||||
public TypeCompletionProposalProvider(JavaProjectFinder projectFinder, SimpleTextDocumentService simpleTextDocumentService, boolean classesOnly) {
|
||||
public TypeCompletionProposalProvider(SimpleLanguageServer server, JavaProjectFinder projectFinder,
|
||||
boolean packagesAllowed, boolean classesAllowed, boolean interfacesAllowed, boolean enumsAllowed) {
|
||||
this.server = server;
|
||||
this.projectFinder = projectFinder;
|
||||
this.classesOnly = classesOnly;
|
||||
|
||||
simpleTextDocumentService.onDidOpen(doc -> {
|
||||
initializeTypeSearch(doc);
|
||||
});
|
||||
this.packagesAllowed = packagesAllowed;
|
||||
this.classesAllowed = classesAllowed;
|
||||
this.interfacesAllowed = interfacesAllowed;
|
||||
this.enumsAllowed = enumsAllowed;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,68 +72,81 @@ public class TypeCompletionProposalProvider implements XMLCompletionProvider {
|
||||
}
|
||||
|
||||
// Flux<Tuple2<IType, Double>> types = project.getIndex().fuzzySearchTypes(prefix, true, true);
|
||||
Flux<Tuple2<IType, Double>> types = project.getIndex().camelcaseSearchTypes(prefix, true, true);
|
||||
// Flux<Tuple2<IType, Double>> types = project.getIndex().camelcaseSearchTypes(prefix, true, true);
|
||||
|
||||
JavaCodeCompleteParams params = new JavaCodeCompleteParams(project.getLocationUri().toString(), prefix, true, true);
|
||||
CompletableFuture<List<JavaCodeCompleteData>> completions = server.getClient().javaCodeComplete(params);
|
||||
|
||||
final String prefixStr = prefix;
|
||||
|
||||
return types
|
||||
.filter(result -> result.getT1() != null && result.getT1().getElementName() != null && result.getT1().getElementName().length() > 0)
|
||||
.filter(result -> classesOnly ? result.getT1().isClass() : true)
|
||||
.map(t -> createProposal(t, doc, offset, prefixStr))
|
||||
.collectList().block();
|
||||
final String finalPrefix = prefix;
|
||||
|
||||
try {
|
||||
return completions.get().stream()
|
||||
.filter(proposal -> {
|
||||
if (proposal.isClassProposal()) return classesAllowed;
|
||||
if (proposal.isInterfaceProposal()) return interfacesAllowed;
|
||||
if (proposal.isEnumProposal()) return enumsAllowed;
|
||||
if (proposal.isPackageProposal()) return packagesAllowed;
|
||||
return false;
|
||||
})
|
||||
.map(proposal -> createProposal(proposal, doc, finalPrefix, offset))
|
||||
.filter(proposal -> proposal != null)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
catch (Exception e) {
|
||||
// TODO: logging
|
||||
}
|
||||
};
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private ICompletionProposal createProposal(Tuple2<IType, Double> t, TextDocument doc, int offset, String prefix) {
|
||||
IType type = t.getT1();
|
||||
private ICompletionProposal createProposal(JavaCodeCompleteData proposal, TextDocument doc, String prefix, int offset) {
|
||||
if (proposal.isPackageProposal()) {
|
||||
return createPackageProposal(proposal, doc, prefix, offset);
|
||||
}
|
||||
else if (proposal.isClassProposal() || proposal.isInterfaceProposal() || proposal.isEnumProposal()) {
|
||||
return createTypeProposal(proposal, doc, prefix, offset);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private TypeCompletionProposal createPackageProposal(JavaCodeCompleteData proposal, TextDocument doc, String prefix, int offset) {
|
||||
String label = proposal.getFullyQualifiedName();
|
||||
CompletionItemKind kind = CompletionItemKind.Module;
|
||||
|
||||
DocumentEdits edits = new DocumentEdits(doc, false);
|
||||
edits.replace(offset - prefix.length(), offset, proposal.getFullyQualifiedName());
|
||||
|
||||
Renderable renderable = null;
|
||||
|
||||
return new TypeCompletionProposal(label, kind, edits, proposal.getFullyQualifiedName(), renderable, proposal.getRelevance());
|
||||
}
|
||||
|
||||
private TypeCompletionProposal createTypeProposal(JavaCodeCompleteData proposal, TextDocument doc, String prefix, int offset) {
|
||||
String label = proposal.getFullyQualifiedName();
|
||||
|
||||
String label = type.getFullyQualifiedName();
|
||||
int splitIndex = Math.max(label.lastIndexOf("."), label.lastIndexOf("$"));
|
||||
|
||||
if (splitIndex > 0) {
|
||||
label = label.substring(splitIndex + 1) + " - " + label.substring(0, splitIndex);
|
||||
}
|
||||
|
||||
CompletionItemKind kind;
|
||||
if (type.isClass()) {
|
||||
kind = CompletionItemKind.Class;
|
||||
}
|
||||
else if (type.isInterface()) {
|
||||
CompletionItemKind kind = CompletionItemKind.Class;
|
||||
if (proposal.isInterfaceProposal()) {
|
||||
kind = CompletionItemKind.Interface;
|
||||
}
|
||||
else if (type.isEnum()) {
|
||||
else if (proposal.isEnumProposal()) {
|
||||
kind = CompletionItemKind.Enum;
|
||||
}
|
||||
else {
|
||||
kind = CompletionItemKind.Property;
|
||||
}
|
||||
|
||||
DocumentEdits edits = new DocumentEdits(doc, false);
|
||||
edits.replace(offset - prefix.length(), offset, type.getFullyQualifiedName());
|
||||
edits.replace(offset - prefix.length(), offset, proposal.getFullyQualifiedName());
|
||||
|
||||
Renderable renderable = null;
|
||||
|
||||
return new TypeCompletionProposal(label, kind, edits, type.getFullyQualifiedName(), renderable, t.getT2());
|
||||
return new TypeCompletionProposal(label, kind, edits, proposal.getFullyQualifiedName(), renderable, proposal.getRelevance());
|
||||
}
|
||||
|
||||
/**
|
||||
* trigger initial type search as soon as the doc opens to avoid search timeouts when doing type proposals for the first time
|
||||
*/
|
||||
private void initializeTypeSearch(TextDocument doc) {
|
||||
Optional<IJavaProject> foundProject = this.projectFinder.find(doc.getId());
|
||||
if (foundProject.isPresent()) {
|
||||
IJavaProject project = foundProject.get();
|
||||
String projectName = project.getElementName();
|
||||
|
||||
if (!this.typeSearchAlreadyInitializedProjects.contains(projectName)) {
|
||||
|
||||
this.typeSearchAlreadyInitializedProjects.add(projectName);
|
||||
Flux<Tuple2<IType, Double>> types = project.getIndex().camelcaseSearchTypes("", true, true);
|
||||
types.count();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user