blob: ccc8f91330af34d49fc546d66a28169ee40cd775 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2017 IBM Corporation and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
*******************************************************************************/
package org.eclipse.dltk.ui.text.completion;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.dltk.compiler.CharOperation;
import org.eclipse.dltk.compiler.problem.IProblem;
import org.eclipse.dltk.core.CompletionContext;
import org.eclipse.dltk.core.CompletionProposal;
import org.eclipse.dltk.core.CompletionRequestor;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.ICompletionRequestorExtension;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.IType;
import org.eclipse.dltk.internal.ui.text.completion.ScriptCompletionProposalFactoryRegistry;
import org.eclipse.dltk.ui.DLTKUIPlugin;
import org.eclipse.dltk.ui.viewsupport.ImageDescriptorRegistry;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.swt.graphics.Image;
/**
* Script UI implementation of <code>CompletionRequestor</code>. Produces
* {@link IScriptCompletionProposal}s from the proposal descriptors received via
* the <code>CompletionRequestor</code> interface.
* <p>
* The lifecycle of a <code>CompletionProposalCollector</code> instance is very
* simple:
*
* <pre>
* ISourceModule unit= ...
* int offset= ...
*
* CompletionProposalCollector collector= new CompletionProposalCollector(cu);
* unit.codeComplete(offset, collector);
* IScriptCompletionProposal[] proposals= collector.getScriptCompletionProposals();
* String errorMessage= collector.getErrorMessage();
*
* / / display / process proposals
* </pre>
*
* Note that after a code completion operation, the collector will store any
* received proposals, which may require a considerable amount of memory, so the
* collector should not be kept as a reference after a completion operation.
* </p>
* <p>
* Clients may instantiate or subclass.
* </p>
*
*
*/
public abstract class ScriptCompletionProposalCollector extends CompletionRequestor
implements ICompletionRequestorExtension {
/**
* Intermediate attribute of {@link CompletionProposal} used to limit the number
* of displayed method parameters.
*
* @since 5.0
*/
public static final String ATTR_PARAM_LIMIT = DLTKUIPlugin.PLUGIN_ID + "CompletionProposal#ParameterLimit";
/** Tells whether this class is in debug mode. */
private static final boolean DEBUG = "true".equalsIgnoreCase(Platform //$NON-NLS-1$
.getDebugOption("org.eclipse.dltk.ui/debug/ResultCollector")); //$NON-NLS-1$
/** Triggers for method proposals without parameters. Do not modify. */
/** Triggers for variables. Do not modify. */
private CompletionProposalLabelProvider fLabelProvider;
private final ImageDescriptorRegistry fRegistry = DLTKUIPlugin.getImageDescriptorRegistry();
private final List<IScriptCompletionProposal> fScriptProposals = new ArrayList<>();
private final List<CompletionProposal> fUnprocessedCompletionProposals = new ArrayList<>();
private final List<IScriptCompletionProposal> fKeywords = new ArrayList<>();
private final Set<String> fSuggestedMethodNames = new HashSet<>();
private final ISourceModule fSourceModule;
private final IScriptProject fScriptProject;
private int fUserReplacementLength;
private CompletionContext fContext;
private IProblem fLastProblem;
private boolean fAsyncCompletion = false;
/* performance measurement */
private long fStartTime;
/**
* The UI invocation context or <code>null</code>.
*
*
*/
private ScriptContentAssistInvocationContext fInvocationContext;
/**
* Creates a new instance ready to collect proposals. If the passed
* <code>ISourceModule</code> is not contained in an {@link IScriptProject}, no
* javadoc will be available as
* {@link org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo()
* additional info} on the created proposals.
*
* @param cu the compilation unit that the result collector will operate on
*/
public ScriptCompletionProposalCollector(ISourceModule cu) {
this(cu.getScriptProject(), cu);
}
/**
* Creates a new instance ready to collect proposals. Note that proposals for
* anonymous types and method declarations are not created when using this
* constructor, as those need to know the compilation unit that they are created
* on. Use
* {@link ScriptCompletionProposalCollector#CompletionProposalCollector(ISourceModule)}
* instead to get all proposals.
* <p>
* If the passed Script project is <code>null</code>, no javadoc will be
* available as
* {@link org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo()
* additional info} on the created (e.g. method and type) proposals.
* </p>
*
* @param project the project that the result collector will operate on, or
* <code>null</code>
*/
public ScriptCompletionProposalCollector(IScriptProject project) {
this(project, null);
}
protected ScriptCompletionProposalCollector(IScriptProject project, ISourceModule cu) {
fScriptProject = project;
fSourceModule = cu;
fUserReplacementLength = -1;
}
/**
* Enable async mode
*/
public void setAsyncCompletion(boolean async) {
fAsyncCompletion = async;
}
/**
* Sets the invocation context.
* <p>
* Subclasses may extend.
* </p>
*
* @param context the invocation context
* @see #getInvocationContext()
*
*/
public void setInvocationContext(ScriptContentAssistInvocationContext context) {
fInvocationContext = context;
context.setCollector(this);
}
/**
* Returns the invocation context. If none has been set via
* {@link #setInvocationContext(JavaContentAssistInvocationContext)}, a new one
* is created.
*
* @return invocationContext the invocation context
*
*/
public final ScriptContentAssistInvocationContext getInvocationContext() {
if (fInvocationContext == null) {
setInvocationContext(createScriptContentAssistInvocationContext(getSourceModule()));
}
return fInvocationContext;
}
protected ScriptContentAssistInvocationContext createScriptContentAssistInvocationContext(
ISourceModule sourceModule) {
return new ScriptContentAssistInvocationContext(sourceModule, getNatureId());
}
/**
* {@inheritDoc}
* <p>
* Subclasses may replace, but usually should not need to. Consider replacing
* {@linkplain #createScriptCompletionProposal(CompletionProposal)
* createScriptCompletionProposal} instead.
* </p>
*/
@Override
public void accept(CompletionProposal proposal) {
if (isFiltered(proposal))
return;
doAccept(proposal);
}
protected void doAccept(CompletionProposal proposal) {
synchronized (fUnprocessedCompletionProposals) {
fUnprocessedCompletionProposals.add(proposal);
}
}
/**
* {@inheritDoc}
* <p>
* Subclasses may extend, but usually should not need to.
* </p>
*
* @see #getContext()
*/
@Override
public void acceptContext(CompletionContext context) {
fContext = context;
getLabelProvider().setContext(context);
}
// Label provider
protected final CompletionProposalLabelProvider createLabelProvider() {
return CompletionProposalLabelProviderRegistry.create(getNatureId());
}
public CompletionProposalLabelProvider getLabelProvider() {
if (fLabelProvider == null) {
fLabelProvider = createLabelProvider();
}
return fLabelProvider;
}
/**
* {@inheritDoc}
*
* Subclasses may extend, but must call the super implementation.
*/
@Override
public void completionFailure(IProblem problem) {
fLastProblem = problem;
}
/**
* Returns an error message about any error that may have occurred during code
* completion, or the empty string if none.
* <p>
* Subclasses may replace or extend.
* </p>
*
* @return an error message or the empty string
*/
public String getErrorMessage() {
if (fLastProblem != null)
return fLastProblem.getMessage();
return ""; //$NON-NLS-1$
}
/**
* Returns the unsorted list of received proposals.
*
* @return the unsorted list of received proposals
*/
public final IScriptCompletionProposal[] getScriptCompletionProposals() {
processUnprocessedProposals();
return fScriptProposals.toArray(new IScriptCompletionProposal[fScriptProposals.size()]);
}
private void processUnprocessedProposals() {
final long start = DEBUG ? System.currentTimeMillis() : 0;
final CompletionProposal[] copy;
synchronized (fUnprocessedCompletionProposals) {
final int size = fUnprocessedCompletionProposals.size();
if (size == 0)
return;
copy = fUnprocessedCompletionProposals.toArray(new CompletionProposal[size]);
fUnprocessedCompletionProposals.clear();
}
for (CompletionProposal proposal : copy) {
try {
processUnprocessedProposal(proposal);
} catch (IllegalArgumentException e) {
// all signature processing method may throw IAEs
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=84657
// don't abort, but log and show all the valid proposals
DLTKUIPlugin.log(new Status(IStatus.ERROR, DLTKUIPlugin.getPluginId(), IStatus.OK,
"Exception when processing proposal for: " //$NON-NLS-1$
+ String.valueOf(proposal.getCompletion()),
e));
}
}
if (DEBUG) {
final long UITime = System.currentTimeMillis() - start;
System.err.println("Core Collector (ui):\t" + UITime); //$NON-NLS-1$
}
}
protected void processUnprocessedProposal(CompletionProposal proposal) {
if (proposal.getKind() == CompletionProposal.POTENTIAL_METHOD_DECLARATION) {
acceptPotentialMethodDeclaration(proposal);
} else {
if (proposal.getKind() == CompletionProposal.METHOD_REF && !isContextInformationMode()) {
final String[] params = proposal.findParameterNames(null);
final Integer requiredParamCount = (Integer) proposal
.getAttribute(CompletionProposal.ATTR_REQUIRED_PARAM_COUNT);
if (params != null && requiredParamCount != null && params.length > requiredParamCount.intValue()) {
for (int i = requiredParamCount.intValue(); i <= params.length; ++i) {
final CompletionProposal copy = proposal.clone();
copy.setAttribute(ATTR_PARAM_LIMIT, i);
final IScriptCompletionProposal scriptProposal = createScriptCompletionProposal(copy);
if (scriptProposal != null) {
addProposal(scriptProposal, copy);
}
}
return;
}
}
final IScriptCompletionProposal scriptProposal = createScriptCompletionProposal(proposal);
if (scriptProposal != null) {
addProposal(scriptProposal, proposal);
}
}
}
protected void addProposal(IScriptCompletionProposal scriptProposal, CompletionProposal proposal) {
fScriptProposals.add(scriptProposal);
if (proposal.getKind() == CompletionProposal.KEYWORD)
fKeywords.add(scriptProposal);
}
/**
* Returns the unsorted list of received keyword proposals.
*
* @return the unsorted list of received keyword proposals
*/
public final IScriptCompletionProposal[] getKeywordCompletionProposals() {
processUnprocessedProposals();
return fKeywords.toArray(new IScriptCompletionProposal[fKeywords.size()]);
}
/**
* If the replacement length is set, it overrides the length returned from the
* content assist infrastructure. Use this setting if code assist is called with
* a none empty selection.
*
* @param length the new replacement length, relative to the code assist offset.
* Must be equal to or greater than zero.
*/
public final void setReplacementLength(int length) {
fUserReplacementLength = length;
}
/**
* Computes the relevance for a given <code>CompletionProposal</code>.
* <p>
* Subclasses may replace, but usually should not need to.
* </p>
*
* @param proposal the proposal to compute the relevance for
* @return the relevance for <code>proposal</code>
*/
public int computeRelevance(CompletionProposal proposal) {
final int baseRelevance = proposal.getRelevance() * 16;
switch (proposal.getKind()) {
case CompletionProposal.LABEL_REF:
return baseRelevance + 0;
case CompletionProposal.KEYWORD:
return baseRelevance + 1;
case CompletionProposal.PACKAGE_REF:
return baseRelevance + 2;
case CompletionProposal.TYPE_REF:
return baseRelevance + 2;
case CompletionProposal.METHOD_REF:
case CompletionProposal.METHOD_NAME_REFERENCE:
case CompletionProposal.METHOD_DECLARATION:
return baseRelevance + 3;
case CompletionProposal.POTENTIAL_METHOD_DECLARATION:
return baseRelevance + 3 /* + 99 */;
case CompletionProposal.FIELD_REF:
return baseRelevance + 4;
case CompletionProposal.LOCAL_VARIABLE_REF:
case CompletionProposal.VARIABLE_DECLARATION:
return baseRelevance + 5;
default:
return baseRelevance;
}
}
/**
* Creates a new script completion proposal from a core proposal. This may
* involve computing the display label and setting up some context.
* <p>
* This method is called for every proposal that will be displayed to the user,
* which may be hundreds. Implementations should therefore defer as much work as
* possible: Labels should be computed lazily to leverage virtual table usage,
* and any information only needed when <em>applying</em> a proposal should not
* be computed yet.
* </p>
* <p>
* Implementations may return <code>null</code> if a proposal should not be
* included in the list presented to the user.
* </p>
* <p>
* Subclasses may extend or replace this method.
* </p>
*
* @param proposal the core completion proposal to create a UI proposal for
* @return the created script completion proposal, or <code>null</code> if no
* proposal should be displayed
*/
protected IScriptCompletionProposal createScriptCompletionProposal(CompletionProposal proposal) {
final IScriptCompletionProposalFactory[] factories = ScriptCompletionProposalFactoryRegistry
.getFactories(getNatureId());
if (factories != null) {
for (IScriptCompletionProposalFactory factory : factories) {
final IScriptCompletionProposal scriptProposal = factory.create(this, proposal);
if (scriptProposal != null) {
return scriptProposal;
}
}
}
switch (proposal.getKind()) {
case CompletionProposal.KEYWORD:
return createKeywordProposal(proposal);
case CompletionProposal.PACKAGE_REF:
return createPackageProposal(proposal);
case CompletionProposal.TYPE_REF:
return createTypeProposal(proposal);
// case CompletionProposal.JAVADOC_TYPE_REF:
// return createJavadocLinkTypeProposal(proposal);
case CompletionProposal.FIELD_REF:
// case CompletionProposal.JAVADOC_FIELD_REF:
// case CompletionProposal.JAVADOC_VALUE_REF:
return createFieldProposal(proposal);
case CompletionProposal.METHOD_REF:
case CompletionProposal.METHOD_NAME_REFERENCE:
// case CompletionProposal.JAVADOC_METHOD_REF:
return createMethodReferenceProposal0(proposal);
case CompletionProposal.METHOD_DECLARATION:
return createMethodDeclarationProposal(proposal);
case CompletionProposal.LABEL_REF:
return createLabelProposal(proposal);
case CompletionProposal.LOCAL_VARIABLE_REF:
case CompletionProposal.VARIABLE_DECLARATION:
return createLocalVariableProposal(proposal);
// case CompletionProposal.ANNOTATION_ATTRIBUTE_REF:
// return createAnnotationAttributeReferenceProposal(proposal);
// case CompletionProposal.JAVADOC_BLOCK_TAG:
// case CompletionProposal.JAVADOC_PARAM_REF:
// return createJavadocSimpleProposal(proposal);
// case CompletionProposal.JAVADOC_INLINE_TAG:
// return createJavadocInlineTagProposal(proposal);
case CompletionProposal.POTENTIAL_METHOD_DECLARATION:
default:
return new ScriptCompletionProposal(proposal.getCompletion(), proposal.getReplaceStart(),
proposal.getReplaceEnd() - proposal.getReplaceStart(), null, proposal.getName(),
proposal.getRelevance());
}
}
/**
* Creates the context information for a given method reference proposal. The
* passed proposal must be of kind {@link CompletionProposal#METHOD_REF} .
*
* @param methodProposal the method proposal for which to create context
* information
* @return the context information for <code>methodProposal</code>
*/
protected final IContextInformation createMethodContextInformation(CompletionProposal methodProposal) {
Assert.isTrue(methodProposal.getKind() == CompletionProposal.METHOD_REF);
return new ProposalContextInformation(methodProposal);
}
/**
* Returns the compilation unit that the receiver operates on, or
* <code>null</code> if the <code>IScriptProject</code> constructor was used to
* create the receiver.
*
* @return the compilation unit that the receiver operates on, or
* <code>null</code>
*/
public final ISourceModule getSourceModule() {
return fSourceModule;
}
/**
* Returns the <code>CompletionContext</code> for this completion operation.
*
* @return the <code>CompletionContext</code> for this completion operation
* @see CompletionRequestor#acceptContext(CompletionContext)
*/
protected final CompletionContext getContext() {
return fContext;
}
/**
* Returns a cached image for the given descriptor.
*
* @param descriptor the image descriptor to get an image for, may be
* <code>null</code>
* @return the image corresponding to <code>descriptor</code>
*/
public final Image getImage(ImageDescriptor descriptor) {
return (descriptor == null) ? null : fRegistry.get(descriptor);
}
/**
* Returns the replacement length of a given completion proposal. The
* replacement length is usually the difference between the return values of
* <code>proposal.getReplaceEnd</code> and
* <code>proposal.getReplaceStart</code>, but this behavior may be overridden by
* calling {@link #setReplacementLength(int)}.
*
* @param proposal the completion proposal to get the replacement length for
* @return the replacement length for <code>proposal</code>
*/
protected final int getLength(CompletionProposal proposal) {
int start = proposal.getReplaceStart();
int end = proposal.getReplaceEnd();
int length;
if (fUserReplacementLength == -1) {
length = end - start;
} else {
length = fUserReplacementLength;
// extend length to begin at start
int behindCompletion = proposal.getCompletionLocation();
if (start < behindCompletion) {
length += behindCompletion - start;
}
}
return length;
}
/**
* Returns <code>true</code> if <code>proposal</code> is filtered, e.g. should
* not be proposed to the user, <code>false</code> if it is valid.
* <p>
* Subclasses may extends this method. The default implementation filters
* proposals set to be ignored via
* {@linkplain CompletionRequestor#setIgnored(int, boolean) setIgnored} and
* types set to be ignored in the preferences.
* </p>
*
* @param proposal the proposal to filter
* @return <code>true</code> to filter <code>proposal</code>, <code>false</code>
* to let it pass
*/
protected boolean isFiltered(CompletionProposal proposal) {
if (isIgnored(proposal.getKind())) {
return true;
}
int value = evaluateFilters(proposal);
if (value == CompletionProposalFilter.IGNORE) {
return true;
} else if (value == CompletionProposalFilter.DISCOURAGED) {
// TODO (alex) implement proper support
return true;
} else if (value != CompletionProposalFilter.DEFAULT) {
proposal.setRelevance(proposal.getRelevance() + value);
}
return false;
}
private void acceptPotentialMethodDeclaration(CompletionProposal proposal) {
if (fSourceModule == null)
return;
// String prefix = String.valueOf(proposal.getName());
// int completionStart = proposal.getReplaceStart();
// int completionEnd = proposal.getReplaceEnd();
// int relevance = computeRelevance(proposal);
try {
IModelElement element = fSourceModule.getElementAt(proposal.getCompletionLocation());
if (element != null) {
IType type = (IType) element.getAncestor(IModelElement.TYPE);
if (type != null) {
// GetterSetterCompletionProposal.evaluateProposals(type,
// prefix, completionStart, completionEnd
// - completionStart, relevance + 1,
// fSuggestedMethodNames, fJavaProposals);
// MethodCompletionProposal.evaluateProposals(type, prefix,
// completionStart, completionEnd - completionStart,
// relevance, fSuggestedMethodNames, fJavaProposals);
if (DLTKCore.DEBUG) {
System.out.println("TODO: Add method completion proposal support here..."); //$NON-NLS-1$
}
}
}
} catch (CoreException e) {
DLTKUIPlugin.log(e);
}
}
// private IScriptCompletionProposal
// createAnnotationAttributeReferenceProposal(
// CompletionProposal proposal) {
// String displayString = getLabelProvider()
// .createLabelWithTypeAndDeclaration(proposal);
// ImageDescriptor descriptor = getLabelProvider()
// .createMethodImageDescriptor(proposal);
// String completion = String.valueOf(proposal.getCompletion());
// return createScriptCompletionProposal(completion, proposal
// .getReplaceStart(), getLength(proposal), getImage(descriptor),
// displayString, computeRelevance(proposal));
// }
protected abstract String getNatureId();
/**
* It is recommended to override only the next method.
*/
@Deprecated
protected ScriptCompletionProposal createScriptCompletionProposal(String completion, int replaceStart, int length,
Image image, String displayString, int relevance) {
return createScriptCompletionProposal(completion, replaceStart, length, image, displayString, relevance, false);
}
@Deprecated
protected ScriptCompletionProposal createScriptCompletionProposal(String completion, int replaceStart, int length,
Image image, String displayString, int relevance, boolean isInDoc) {
return new ScriptCompletionProposal(completion, replaceStart, length, image, displayString, relevance, isInDoc);
}
/**
* @since 5.2
*/
protected ScriptCompletionProposal createScriptCompletionProposal(String completion, int replaceStart, int length,
Image image, StyledString displayString, int relevance, boolean isInDoc) {
return new ScriptCompletionProposal(completion, replaceStart, length, image, displayString, relevance, isInDoc);
}
/**
* Used when {@link #setAsyncCompletion(true)} is called
*
* @since 5.9
*/
protected ScriptCompletionProposal createScriptCompletionProposal(String completion, int replaceStart, int length,
Supplier<Image> image, StyledString displayString, int relevance, boolean isInDoc) {
return new ScriptCompletionProposal(completion, replaceStart, length, image, displayString, relevance, isInDoc);
}
@Deprecated
protected ScriptCompletionProposal createOverrideCompletionProposal(IScriptProject scriptProject,
ISourceModule compilationUnit, String name, String[] paramTypes, int start, int length, String label,
String string) {
// default implementation return null, as this functionality is optional
return null;
}
/**
* @since 5.5
*/
protected ScriptCompletionProposal createOverrideCompletionProposal(IScriptProject scriptProject,
ISourceModule compilationUnit, String name, String[] paramTypes, int start, int length, StyledString label,
String string) {
return null;
}
protected IScriptCompletionProposal createFieldProposal(CompletionProposal proposal) {
String completion = String.valueOf(proposal.getCompletion());
int start = proposal.getReplaceStart();
int length = getLength(proposal);
int relevance = computeRelevance(proposal);
ScriptCompletionProposal scriptProposal;
CompletionProposalLabelProvider labelProvider = getLabelProvider();
Supplier<Image> image = getImageFactory(getLabelProvider().createFieldImageDescriptor(proposal));
if (labelProvider instanceof ICompletionProposalLabelProviderExtension) {
StyledString label = ((ICompletionProposalLabelProviderExtension) getLabelProvider())
.createStyledFieldProposalLabel(proposal);
if (fAsyncCompletion) {
scriptProposal = createScriptCompletionProposal(completion, start, length, image, label, relevance,
false);
} else {
scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label,
relevance, false);
}
} else {
String label = getLabelProvider().createFieldProposalLabel(proposal);
scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label, relevance,
false);
}
if (fScriptProject != null)
scriptProposal.setProposalInfo(new FieldProposalInfo(fScriptProject, proposal));
scriptProposal.setTriggerCharacters(getVarTrigger());
return scriptProposal;
}
protected Supplier<Image> getImageFactory(ImageDescriptor imageDescriptor) {
return () -> getImage(imageDescriptor);
}
protected IScriptCompletionProposal createKeywordProposal(CompletionProposal proposal) {
String completion = String.valueOf(proposal.getCompletion());
int start = proposal.getReplaceStart();
int length = getLength(proposal);
int relevance = computeRelevance(proposal);
ScriptCompletionProposal scriptProposal;
CompletionProposalLabelProvider labelProvider = getLabelProvider();
Supplier<Image> image = getImageFactory(getLabelProvider().createImageDescriptor(proposal));
if (labelProvider instanceof ICompletionProposalLabelProviderExtension) {
StyledString label = ((ICompletionProposalLabelProviderExtension) getLabelProvider())
.createStyledKeywordLabel(proposal);
if (fAsyncCompletion) {
scriptProposal = createScriptCompletionProposal(completion, start, length, image, label, relevance,
false);
} else {
scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label,
relevance, false);
}
} else {
String label = getLabelProvider().createKeywordLabel(proposal);
scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label, relevance,
false);
}
if (fScriptProject != null) {
scriptProposal.setProposalInfo(new ProposalInfo(fScriptProject, proposal.getName()));
}
return scriptProposal;
}
protected IScriptCompletionProposal createPackageProposal(CompletionProposal proposal) {
String completion = String.valueOf(proposal.getCompletion());
int start = proposal.getReplaceStart();
int length = getLength(proposal);
int relevance = computeRelevance(proposal);
ScriptCompletionProposal scriptProposal;
CompletionProposalLabelProvider labelProvider = getLabelProvider();
Supplier<Image> image = getImageFactory(getLabelProvider().createImageDescriptor(proposal));
if (labelProvider instanceof ICompletionProposalLabelProviderExtension) {
StyledString label = ((ICompletionProposalLabelProviderExtension) getLabelProvider())
.createStyledSimpleLabel(proposal);
if (fAsyncCompletion) {
scriptProposal = createScriptCompletionProposal(completion, start, length, image, label, relevance,
false);
} else {
scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label,
relevance, false);
}
} else {
String label = getLabelProvider().createSimpleLabel(proposal);
scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label, relevance,
false);
}
return scriptProposal;
}
private IScriptCompletionProposal createLabelProposal(CompletionProposal proposal) {
String completion = String.valueOf(proposal.getCompletion());
int start = proposal.getReplaceStart();
int length = getLength(proposal);
int relevance = computeRelevance(proposal);
ScriptCompletionProposal scriptProposal;
CompletionProposalLabelProvider labelProvider = getLabelProvider();
Image image = null;
Supplier<Image> factory = null;
if (labelProvider instanceof ICompletionProposalLabelProviderExtension) {
StyledString label = ((ICompletionProposalLabelProviderExtension) getLabelProvider())
.createStyledSimpleLabel(proposal);
if (fAsyncCompletion) {
scriptProposal = createScriptCompletionProposal(completion, start, length, factory, label, relevance,
false);
} else {
scriptProposal = createScriptCompletionProposal(completion, start, length, image, label, relevance,
false);
}
} else {
String label = getLabelProvider().createSimpleLabel(proposal);
scriptProposal = createScriptCompletionProposal(completion, start, length, image, label, relevance, false);
}
return scriptProposal;
}
private IScriptCompletionProposal createLocalVariableProposal(CompletionProposal proposal) {
String completion = String.valueOf(proposal.getCompletion());
int start = proposal.getReplaceStart();
int length = getLength(proposal);
int relevance = computeRelevance(proposal);
ScriptCompletionProposal scriptProposal;
CompletionProposalLabelProvider labelProvider = getLabelProvider();
Supplier<Image> image = getImageFactory(getLabelProvider().createLocalImageDescriptor(proposal));
if (labelProvider instanceof ICompletionProposalLabelProviderExtension) {
StyledString label = ((ICompletionProposalLabelProviderExtension) getLabelProvider())
.createStyledSimpleLabelWithType(proposal);
if (fAsyncCompletion) {
scriptProposal = createScriptCompletionProposal(completion, start, length, image, label, relevance,
false);
} else {
scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label,
relevance, false);
}
} else {
String label = getLabelProvider().createSimpleLabelWithType(proposal);
scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label, relevance,
false);
}
scriptProposal.setTriggerCharacters(getVarTrigger());
return scriptProposal;
}
/**
* @since 3.0
*/
protected static final char[] VAR_TRIGGER = new char[] { '\t', ' ', '=', ';', '.' };
protected char[] getVarTrigger() {
return VAR_TRIGGER;
}
private IScriptCompletionProposal createMethodDeclarationProposal(CompletionProposal proposal) {
if (fSourceModule == null || fScriptProject == null) {
return null;
}
String name = proposal.getName();
String[] paramTypes = CharOperation.NO_STRINGS;
int start = proposal.getReplaceStart();
int length = getLength(proposal);
CompletionProposalLabelProvider labelProvider = getLabelProvider();
ScriptCompletionProposal scriptProposal;
if (labelProvider instanceof ICompletionProposalLabelProviderExtension2) {
StyledString label = ((ICompletionProposalLabelProviderExtension2) labelProvider)
.createStyledOverrideMethodProposalLabel(proposal);
scriptProposal = createOverrideCompletionProposal(fScriptProject, fSourceModule, name, paramTypes, start,
length, label, String.valueOf(proposal.getCompletion()));
} else {
String label = labelProvider.createOverrideMethodProposalLabel(proposal);
scriptProposal = createOverrideCompletionProposal(fScriptProject, fSourceModule, name, paramTypes, start,
length, label, String.valueOf(proposal.getCompletion()));
}
if (scriptProposal == null)
return null;
scriptProposal.setImage(getImage(getLabelProvider().createMethodImageDescriptor(proposal)));
ProposalInfo info = new MethodProposalInfo(fScriptProject, proposal);
scriptProposal.setProposalInfo(info);
scriptProposal.setRelevance(computeRelevance(proposal));
fSuggestedMethodNames.add(name);
return scriptProposal;
}
private IScriptCompletionProposal createMethodReferenceProposal0(CompletionProposal methodProposal) {
IScriptCompletionProposal proposal = createMethodReferenceProposal(methodProposal);
if (proposal instanceof AbstractScriptCompletionProposal) {
adaptLength((AbstractScriptCompletionProposal) proposal, methodProposal);
}
return proposal;
}
protected IScriptCompletionProposal createMethodReferenceProposal(CompletionProposal methodProposal) {
return new ScriptMethodCompletionProposal(methodProposal, getInvocationContext());
}
private void adaptLength(AbstractScriptCompletionProposal proposal, CompletionProposal coreProposal) {
if (fUserReplacementLength != -1) {
proposal.setReplacementLength(getLength(coreProposal));
}
}
protected IScriptCompletionProposal createTypeProposal(CompletionProposal proposal) {
String completion = proposal.getCompletion();
int start = proposal.getReplaceStart();
int length = proposal.getReplaceEnd() - proposal.getReplaceStart();
int relevance = computeRelevance(proposal);
ScriptCompletionProposal scriptProposal;
CompletionProposalLabelProvider labelProvider = getLabelProvider();
Supplier<Image> image = getImageFactory(getLabelProvider().createTypeImageDescriptor(proposal));
if (labelProvider instanceof ICompletionProposalLabelProviderExtension) {
StyledString label = ((ICompletionProposalLabelProviderExtension) getLabelProvider())
.createStyledTypeProposalLabel(proposal);
if (fAsyncCompletion) {
scriptProposal = createScriptCompletionProposal(completion, start, length, image, label, relevance,
false);
} else {
scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label,
relevance, false);
}
} else {
String label = getLabelProvider().createTypeProposalLabel(proposal);
scriptProposal = createScriptCompletionProposal(completion, start, length, image.get(), label, relevance,
false);
}
scriptProposal.setProposalInfo(new TypeProposalInfo(fScriptProject, proposal));
return scriptProposal;
}
@Override
public boolean isContextInformationMode() {
return fInvocationContext != null && fInvocationContext.isContextInformationMode();
}
@Override
public void reset() {
synchronized (fUnprocessedCompletionProposals) {
fUnprocessedCompletionProposals.clear();
}
fScriptProposals.clear();
fKeywords.clear();
fSuggestedMethodNames.clear();
}
public IScriptProject getScriptProject() {
return fScriptProject;
}
private Map<Object, Object> attributes = null;
public Object getAttribute(Object key) {
if (attributes != null) {
return attributes.get(key);
}
return null;
}
public void setAttribute(Object key, Object value) {
if (value == null) {
if (attributes != null) {
attributes.remove(value);
}
} else {
if (attributes == null) {
attributes = new HashMap<>();
}
attributes.put(key, value);
}
}
void startCompletion() {
if (DEBUG) {
fStartTime = System.currentTimeMillis();
}
}
void endCompletion() {
if (DEBUG) {
long total = System.currentTimeMillis() - fStartTime;
System.err.println("Core Collector (core):\t" + total); //$NON-NLS-1$
}
}
}