Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion org.eclipse.jdt.ls.core/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<extension-point id="org.eclipse.jdt.ls.core.importers" name="JDT LS Project Importer" schema="schema/org.eclipse.jdt.ls.core.importers.exsd"/>
<extension-point id="org.eclipse.jdt.ls.core.contentProvider" name="contentProvider" schema="schema/org.eclipse.jdt.ls.core.contentProvider.exsd"/>
<extension-point id="org.eclipse.jdt.ls.core.buildSupport" name="Build Support" schema="schema/org.eclipse.jdt.ls.core.buildSupport.exsd"/>
<extension-point id="org.eclipse.jdt.ls.core.completionHandler" name="Code Completion" schema="schema/org.eclipse.jdt.ls.core.completionHandler.exsd"/>
<extension
id="id1"
point="org.eclipse.core.runtime.applications">
Expand Down Expand Up @@ -225,7 +226,6 @@
id="org.eclipse.jdt.core.javanature">
</requires-nature>
</extension>

<extension point="org.eclipse.core.contenttype.contentTypes">
<file-association
content-type="org.eclipse.jdt.core.javaDerivedSource"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Schema file written by PDE -->
<schema targetNamespace="org.eclipse.jdt.ls.core" xmlns="http://www.w3.org/2001/XMLSchema">
<annotation>
<appinfo>
<meta.schema plugin="org.eclipse.jdt.ls.core" id="org.eclipse.jdt.ls.core.codeCompletion" name="Code Completion"/>
</appinfo>
<documentation>
This extension point represents different kinds of code completion handlers for the JDT LS.
Each extension must implement &lt;code&gt;org.eclipse.jdt.ls.core.internal.handlers.ICompletionHandler&lt;/code&gt;.
</documentation>
</annotation>

<element name="extension">
<annotation>
<appinfo>
<meta.element />
</appinfo>
</annotation>
<complexType>
<sequence>
<element ref="completionHandler" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="point" type="string" use="required">
<annotation>
<documentation>
a fully qualified identifier of the target extension point
</documentation>
</annotation>
</attribute>
<attribute name="id" type="string">
<annotation>
<documentation>
an optional identifier of the extension instance
</documentation>
</annotation>
</attribute>
<attribute name="name" type="string">
<annotation>
<documentation>
an optional name of the extension instance
</documentation>
</annotation>
</attribute>
</complexType>
</element>

<element name="completionHandler">
<complexType>
<attribute name="id" type="string" use="required">
<annotation>
<documentation>
A unique identifier that can be used to reference this ICompletionHandler.
</documentation>
</annotation>
</attribute>
<attribute name="class" type="string" use="required">
<annotation>
<documentation>
The class that implements this completion handler. The class must implement ICompletionHandler.
</documentation>
<appinfo>
<meta.attribute kind="java" basedOn=":org.eclipse.jdt.ls.core.internal.handlers.ICompletionHandler"/>
</appinfo>
</annotation>
</attribute>
</complexType>
</element>


<annotation>
<appinfo>
<meta.section type="examples"/>
</appinfo>
<documentation>
The following is an example of a language server content provider extension:

&lt;pre&gt;
&lt;extension
id=&quot;completionHandler&quot;
point=&quot;org.eclipse.jdt.ls.core.completionHandler&quot;&gt;
&lt;completionHandler
id=&quot;someCompletionHandler&quot;
class=&quot;com.example.SomeCompletionHandler&quot; /&gt;
&lt;/extension&gt;
&lt;/pre&gt;
</documentation>
</annotation>




</schema>
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
import org.eclipse.jdt.ls.core.internal.commands.VmCommand;
import org.eclipse.jdt.ls.core.internal.framework.protobuf.ProtobufSupport;
import org.eclipse.jdt.ls.core.internal.handlers.BundleUtils;
import org.eclipse.jdt.ls.core.internal.handlers.CompletionHandler;
import org.eclipse.jdt.ls.core.internal.handlers.CompletionHandlers;
import org.eclipse.jdt.ls.core.internal.handlers.CreateModuleInfoHandler;
import org.eclipse.jdt.ls.core.internal.handlers.FormatterHandler;
import org.eclipse.jdt.ls.core.internal.handlers.PasteEventHandler;
Expand Down Expand Up @@ -191,10 +191,10 @@ public Object executeCommand(String commandId, List<Object> arguments, IProgress
return false;
}
case "java.completion.onDidSelect":
CompletionHandler completionHandler = new CompletionHandler(JavaLanguageServerPlugin.getPreferencesManager());
CompletionHandlers completionHandlers = JavaLanguageServerPlugin.getInstance().getCompletionHandlers();
String requestId = (String) arguments.get(0);
String proposalId = (String) arguments.get(1);
completionHandler.onDidCompletionItemSelect(requestId, proposalId);
completionHandlers.onDidCompletionItemSelect(requestId, proposalId);
return new Object();
case "java.decompile":
String uri = (String) arguments.get(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import org.eclipse.jdt.ls.core.internal.corext.template.java.JavaLanguageServerTemplateStore;
import org.eclipse.jdt.ls.core.internal.handlers.BundleUtils;
import org.eclipse.jdt.ls.core.internal.handlers.CompletionContributionService;
import org.eclipse.jdt.ls.core.internal.handlers.CompletionHandlers;
import org.eclipse.jdt.ls.core.internal.handlers.JDTLanguageServer;
import org.eclipse.jdt.ls.core.internal.handlers.LogHandler;
import org.eclipse.jdt.ls.core.internal.managers.ContentProviderManager;
Expand Down Expand Up @@ -137,6 +138,8 @@ public class JavaLanguageServerPlugin extends Plugin {
private CompletionContributionService completionContributionService;
private LogHandler logHandler;

private CompletionHandlers completionHandlers;

public static LanguageServerApplication getLanguageServer() {
return pluginInstance == null ? null : pluginInstance.languageServer;
}
Expand Down Expand Up @@ -167,6 +170,7 @@ public void start(BundleContext bundleContext) throws Exception {
preferenceManager = new StandardPreferenceManager();
projectsManager = new StandardProjectsManager(preferenceManager);
}
completionHandlers = new CompletionHandlers(preferenceManager);
digestStore = new DigestStore(getStateLocation().toFile());
try {
ResourcesPlugin.getWorkspace().addSaveParticipant(IConstants.PLUGIN_ID, projectsManager);
Expand Down Expand Up @@ -427,6 +431,10 @@ public WorkingCopyOwner getWorkingCopyOwner() {
return this.protocol.getWorkingCopyOwner();
}

public CompletionHandlers getCompletionHandlers() {
return completionHandlers;
}

public static JavaLanguageServerPlugin getInstance() {
return pluginInstance;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,13 @@
package org.eclipse.jdt.ls.core.internal.handlers;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.ProgressMonitorWrapper;
Expand All @@ -37,9 +34,6 @@
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.manipulation.SharedASTProviderCore;
import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner;
import org.eclipse.jdt.ls.core.contentassist.CompletionRanking;
import org.eclipse.jdt.ls.core.contentassist.ICompletionRankingProvider;
import org.eclipse.jdt.ls.core.internal.ExceptionFactory;
import org.eclipse.jdt.ls.core.internal.JDTEnvironmentUtils;
import org.eclipse.jdt.ls.core.internal.JDTUtils;
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
Expand All @@ -51,7 +45,6 @@
import org.eclipse.jdt.ls.core.internal.contentassist.SortTextHelper;
import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager;
import org.eclipse.jdt.ls.core.internal.syntaxserver.ModelBasedCompletionEngine;
import org.eclipse.lsp4j.Command;
import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.CompletionItemKind;
import org.eclipse.lsp4j.CompletionItemOptions;
Expand All @@ -60,10 +53,9 @@
import org.eclipse.lsp4j.CompletionParams;
import org.eclipse.lsp4j.CompletionTriggerKind;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.jsonrpc.messages.Either;


public class CompletionHandler{
public class CompletionHandler implements ICompletionHandler {

public final static CompletionOptions getDefaultCompletionOptions(PreferenceManager preferenceManager) {
CompletionOptions completionOptions = new CompletionOptions(Boolean.TRUE, List.of(".", "@", "#", "*", " "));
Expand Down Expand Up @@ -101,19 +93,15 @@ public int compare(CompletionItem o1, CompletionItem o2) {

};

// TODO: we can consider to cache more detailed context so that the information can also
// be used by features like inlay hint.
public static CompletionProposal selectedProposal;

private PreferenceManager manager;

public CompletionHandler(PreferenceManager manager) {
this.manager = manager;
}

public Either<List<CompletionItem>, CompletionList> completion(CompletionParams params,
@Override
public CompletionList completion(CompletionParams params,
IProgressMonitor monitor) {
long startTime = System.currentTimeMillis();
CompletionList $ = null;
try {
ICompilationUnit unit = JDTUtils.resolveCompilationUnit(params.getTextDocument().getUri());
Expand All @@ -137,96 +125,7 @@ public Either<List<CompletionItem>, CompletionList> completion(CompletionParams
} else {
JavaLanguageServerPlugin.logInfo("Completion request completed");
}
long executionTime = System.currentTimeMillis() - startTime;
String lastRequestId = null;
for (CompletionItem item : $.getItems()) {
String requestId = "";
String proposalId = "";
@SuppressWarnings("unchecked")
Map<String, String> data = (Map<String, String>) item.getData();
if (data != null) {
requestId = data.getOrDefault(CompletionResolveHandler.DATA_FIELD_REQUEST_ID, "");
proposalId = data.getOrDefault(CompletionResolveHandler.DATA_FIELD_PROPOSAL_ID, "");
}
if (requestId.isEmpty() || proposalId.isEmpty()) {
continue;
}
item.setCommand(new Command("", "java.completion.onDidSelect", Arrays.asList(
requestId,
proposalId
)));

if (Objects.equals(requestId, lastRequestId)) {
continue;
}
lastRequestId = requestId;
int pId = Integer.parseInt(proposalId);
long rId = Long.parseLong(requestId);
CompletionResponse completionResponse = CompletionResponses.get(rId);
if (completionResponse == null || completionResponse.getProposals().size() <= pId) {
JavaLanguageServerPlugin.logError("Failed to save common data for completion items.");
continue;
}
completionResponse.setCommonData(CompletionRanking.COMPLETION_EXECUTION_TIME, String.valueOf(executionTime));
}
return Either.forRight($);
}

@SuppressWarnings("unchecked")
public void onDidCompletionItemSelect(String requestId, String proposalId) throws CoreException {
triggerSignatureHelp();
if (proposalId.isEmpty() || requestId.isEmpty()) {
return;
}
int pId = Integer.parseInt(proposalId);
long rId = Long.parseLong(requestId);
CompletionResponse completionResponse = CompletionResponses.get(rId);
if (completionResponse == null || completionResponse.getItems().size() <= pId
|| completionResponse.getProposals().size() <= pId) {
throw ExceptionFactory.newException("Cannot get completion responses.");
}

CompletionProposal proposal = completionResponse.getProposals().get(pId);

// clear the cache if failed to get the selected proposal.
if (proposal == null) {
selectedProposal = null;
} else if (proposal.getKind() == CompletionProposal.METHOD_REF
|| proposal.getKind() == CompletionProposal.CONSTRUCTOR_INVOCATION
|| proposal.getKind() == CompletionProposal.METHOD_REF_WITH_CASTED_RECEIVER) {
selectedProposal = proposal;
}
CompletionItem item = completionResponse.getItems().get(pId);
if (item == null) {
throw ExceptionFactory.newException("Cannot get the completion item.");
}

// get the cached completion execution time and set it to the selected item in case that providers need it.
String executionTime = completionResponse.getCommonData(CompletionRanking.COMPLETION_EXECUTION_TIME);
if (executionTime != null) {
((Map<String, String>)item.getData()).put(CompletionRanking.COMPLETION_EXECUTION_TIME, executionTime);
}

Map<String, String> contributedData = completionResponse.getCompletionItemData(pId);
if (contributedData != null) {
((Map<String, String>)item.getData()).putAll(contributedData);
}

List<ICompletionRankingProvider> providers =
((CompletionContributionService) JavaLanguageServerPlugin.getCompletionContributionService()).getRankingProviders();
for (ICompletionRankingProvider provider : providers) {
provider.onDidCompletionItemSelect(item);
}
}

private void triggerSignatureHelp() {
if (manager.getPreferences().isSignatureHelpEnabled()) {
String onSelectedCommand = manager.getClientPreferences().getCompletionItemCommand();
if (!onSelectedCommand.isEmpty() && manager.getClientPreferences().isExecuteClientCommandSupport()) {
JavaLanguageServerPlugin.getInstance().getClientConnection()
.executeClientCommand(onSelectedCommand);
}
}
return $;
}

private CompletionList computeContentAssist(ICompilationUnit unit, CompletionParams params, IProgressMonitor monitor) throws JavaModelException {
Expand Down
Loading