initial implementation towards a compilation-unit-based content-assist for types and packages

This commit is contained in:
Martin Lippert
2019-05-02 09:15:10 +02:00
parent 652f5dcbcd
commit 5abc6f9df0
12 changed files with 512 additions and 66 deletions

View File

@@ -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();
}
});
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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());
}
});
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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())
);

View File

@@ -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));
}

View File

@@ -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

View File

@@ -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();
}
}
}
}