Skip to content
This repository has been archived by the owner on Apr 21, 2023. It is now read-only.

Commit

Permalink
Merge pull request #941 from eclipse/hs_issue677
Browse files Browse the repository at this point in the history
[#677] Eclipse Xtend favorites
  • Loading branch information
holgerschill committed Jan 16, 2019
2 parents a4b448f + 7245223 commit a7d9c90
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 23 deletions.
Expand Up @@ -347,6 +347,18 @@ public void setSelectionStart(int selectionStart) {
this.selectionStart = selectionStart;
}

/**
* @since 2.17
*/
public void shiftOffset(int deltaLength) {
this.cursorPosition = this.cursorPosition + deltaLength;
this.selectionStart = this.selectionStart + deltaLength;
if (this.contextInformation instanceof ISmartContextInformation) {
ISmartContextInformation casted = (ISmartContextInformation) contextInformation;
casted.setContextInformationPosition(casted.getContextInformationPosition() + deltaLength);
}
}

public void setSimpleLinkedMode(ITextViewer viewer, char... exitChars) {
this.linkedMode = true;
this.viewer = viewer;
Expand Down
Expand Up @@ -34,4 +34,9 @@ public interface ISmartContextInformation extends IContextInformation, IContextI
*/
boolean updatePresentation(ITextViewer viewer, int offset, TextPresentation presentation);

/**
* @since 2.17
*/
void setContextInformationPosition(int pos);

}
Expand Up @@ -29,6 +29,7 @@
import org.eclipse.text.edits.TextEdit;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.common.types.JvmDeclaredType;
import org.eclipse.xtext.common.types.JvmFeature;
import org.eclipse.xtext.common.types.xtext.ui.JdtTypesProposalProvider;
import org.eclipse.xtext.conversion.IValueConverter;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
Expand Down Expand Up @@ -108,19 +109,18 @@ public void apply(IDocument document, ConfigurableCompletionProposal proposal) t
return;
}
}

String typeNameInScope = typeName;
// ReplacementString might have brackets if it's a JVMExecutable
int indexOfBracket = typeName.lastIndexOf("(");
if(indexOfBracket > -1) {
typeNameInScope = typeName.substring(0, indexOfBracket);
}
QualifiedName qualifiedNameInScope = qualifiedNameConverter.toQualifiedName(typeNameInScope);
// we could create an import statement if there is no conflict
QualifiedName qualifiedName = qualifiedNameConverter.toQualifiedName(typeName);
if (qualifiedName.getSegmentCount() == 1) {
// type resides in default package - no need to hassle with imports
proposal.setCursorPosition(proposalReplacementString.length());
document.replace(proposal.getReplacementOffset(), proposal.getReplacementLength(),
proposalReplacementString);
return;
}
IEObjectDescription description = scope.getSingleElement(qualifiedName.skipFirst(qualifiedName
IEObjectDescription description = scope.getSingleElement(qualifiedNameInScope.skipFirst(qualifiedNameInScope
.getSegmentCount() - 1));
IEObjectDescription typeToImport = scope.getSingleElement(qualifiedName);
IEObjectDescription typeToImport = scope.getSingleElement(qualifiedNameInScope);
if (description != null) {
if (typeToImport != null && !description.getEObjectURI().equals(typeToImport.getEObjectURI())) {
// there exists a conflict - insert fully qualified name
Expand Down Expand Up @@ -151,9 +151,20 @@ public void apply(IDocument document, ConfigurableCompletionProposal proposal) t
return;
}
EObject resolved = EcoreUtil.resolve(typeToImport.getEObjectOrProxy(), context);
Assert.isTrue(!resolved.eIsProxy() && resolved instanceof JvmDeclaredType);
importSection.addImport((JvmDeclaredType) resolved);

// In case we want to import a static JvmFeature - https://github.com/eclipse/xtext-xtend/issues/677
if(resolved instanceof JvmFeature) {
JvmFeature operation = (JvmFeature) resolved;
if(operation.isStatic()) {
EObject container = operation.eContainer();
if(container instanceof JvmDeclaredType) {
JvmDeclaredType type = (JvmDeclaredType) container;
importSection.addStaticImport(type.getQualifiedName(), operation.getSimpleName());
}
}
} else {
Assert.isTrue(!resolved.eIsProxy() && resolved instanceof JvmDeclaredType);
importSection.addImport((JvmDeclaredType) resolved);
}
DocumentRewriteSession rewriteSession = null;
try {
if (document instanceof IDocumentExtension4) {
Expand All @@ -162,10 +173,18 @@ public void apply(IDocument document, ConfigurableCompletionProposal proposal) t
}
// apply short proposal
String escapedShortname = shortName;
if (valueConverter != null) {
escapedShortname = valueConverter.toString(shortName);

if(indexOfBracket > -1) {
if (valueConverter != null) {
escapedShortname = valueConverter.toString(typeNameInScope) + shortName.substring(indexOfBracket);
}
proposal.setCursorPosition(escapedShortname.length()-1);
} else {
if (valueConverter != null) {
escapedShortname = valueConverter.toString(shortName);
}
proposal.setCursorPosition(escapedShortname.length());
}
proposal.setCursorPosition(escapedShortname.length());
int initialCursorLine = document.getLineOfOffset(proposal.getReplacementOffset());
ReplaceEdit replaceEdit = new ReplaceEdit(proposal.getReplacementOffset(), proposal.getReplacementLength(), escapedShortname);

Expand All @@ -181,10 +200,11 @@ public void apply(IDocument document, ConfigurableCompletionProposal proposal) t
textEdit = replaceEdit;
}
textEdit.apply(document);

int cursorPosition = proposal.getCursorPosition() + replaceConverter.getReplaceLengthDelta(importChanges, proposal.getReplacementOffset());
proposal.setCursorPosition(cursorPosition);
int newCursorLine = document.getLineOfOffset(cursorPosition);
// delta caused by the newly introduced imports
int deltaLength = replaceConverter.getReplaceLengthDelta(importChanges, proposal.getSelectionStart());
// shift offset by deltaLength
proposal.shiftOffset(deltaLength);
int newCursorLine = document.getLineOfOffset(proposal.getCursorPosition());

// set the pixel coordinates
if (widget != null) {
Expand Down
Expand Up @@ -42,13 +42,13 @@ public class ParameterContextInformation implements ISmartContextInformation {
private final String contextDisplayString;
private int parameterListOffset;
private int currentParameter = -1;
private int initialCarretOffset;
private int initialCaretOffset;

public ParameterContextInformation(ParameterData data, String contextDisplayString, int parameterListOffset, int initialCarretOffset) {
this.data = data;
this.contextDisplayString = contextDisplayString;
this.parameterListOffset = parameterListOffset;
this.initialCarretOffset = initialCarretOffset;
this.initialCaretOffset = initialCarretOffset;
}

@Override
Expand Down Expand Up @@ -91,7 +91,12 @@ public String getContextDisplayString() {

@Override
public int getContextInformationPosition() {
return initialCarretOffset;
return initialCaretOffset;
}

@Override
public void setContextInformationPosition(int pos) {
this.initialCaretOffset = pos;
}

@Override
Expand Down
Expand Up @@ -12,6 +12,7 @@
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.ui.PreferenceConstants;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
Expand All @@ -24,12 +25,16 @@
import org.eclipse.xtext.Group;
import org.eclipse.xtext.Keyword;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.common.types.JvmConstructor;
import org.eclipse.xtext.common.types.JvmDeclaredType;
import org.eclipse.xtext.common.types.JvmExecutable;
import org.eclipse.xtext.common.types.JvmFeature;
import org.eclipse.xtext.common.types.JvmFormalParameter;
import org.eclipse.xtext.common.types.JvmIdentifiableElement;
import org.eclipse.xtext.common.types.JvmType;
import org.eclipse.xtext.common.types.JvmTypeReference;
import org.eclipse.xtext.common.types.TypesPackage;
import org.eclipse.xtext.common.types.util.TypeReferences;
import org.eclipse.xtext.common.types.xtext.ui.ITypesProposalProvider;
import org.eclipse.xtext.common.types.xtext.ui.TypeMatchFilters;
import org.eclipse.xtext.conversion.IValueConverter;
Expand All @@ -42,8 +47,11 @@
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.impl.SimpleScope;
import org.eclipse.xtext.ui.editor.contentassist.ConfigurableCompletionProposal;
import org.eclipse.xtext.ui.editor.contentassist.ConfigurableCompletionProposal.IReplacementTextApplier;
import org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext;
import org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor;
import org.eclipse.xtext.ui.editor.contentassist.PrefixMatcher;
Expand All @@ -59,18 +67,23 @@
import org.eclipse.xtext.xbase.XMemberFeatureCall;
import org.eclipse.xtext.xbase.XbasePackage;
import org.eclipse.xtext.xbase.conversion.XbaseQualifiedNameValueConverter;
import org.eclipse.xtext.xbase.imports.RewritableImportSection;
import org.eclipse.xtext.xbase.scoping.SyntaxFilteredScopes;
import org.eclipse.xtext.xbase.scoping.batch.IIdentifiableElementDescription;
import org.eclipse.xtext.xbase.scoping.batch.StaticFeatureDescription;
import org.eclipse.xtext.xbase.scoping.featurecalls.OperatorMapping;
import org.eclipse.xtext.xbase.typesystem.IBatchTypeResolver;
import org.eclipse.xtext.xbase.typesystem.IExpressionScope;
import org.eclipse.xtext.xbase.typesystem.IResolvedTypes;
import org.eclipse.xtext.xbase.typesystem.references.LightweightTypeReference;
import org.eclipse.xtext.xbase.typesystem.references.LightweightTypeReferenceFactory;
import org.eclipse.xtext.xbase.ui.contentassist.ImportingTypesProposalProvider.FQNImporter;
import org.eclipse.xtext.xbase.ui.imports.ReplaceConverter;
import org.eclipse.xtext.xtype.XtypePackage;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.inject.Inject;

Expand Down Expand Up @@ -128,6 +141,12 @@ public boolean apply(IEObjectDescription input) {
@Inject
private SyntaxFilteredScopes syntaxFilteredScopes;

@Inject
private TypeReferences typeReferences;

@Inject
private IQualifiedNameConverter qualifiedNameConverter;

protected class XbaseProposalCreator extends DefaultProposalCreator {

private ContentAssistContext contentAssistContext;
Expand Down Expand Up @@ -766,12 +785,86 @@ protected void createLocalVariableAndImplicitProposals(
// TODO use the type name information
proposeDeclaringTypeForStaticInvocation(context, null /* ignore */, contentAssistContext, acceptor);
// System.out.printf("XbaseProposalProvider.proposeDeclaringTypeForStaticInvocation = %d\n", System.currentTimeMillis() - time);
createFavoriteStaticFeature(context, contentAssistContext, acceptor, proposalFactory);
}

/**
* @since 2.17
*/
protected void createFavoriteStaticFeature(
EObject context,ContentAssistContext contentAssistContext,
ICompletionProposalAcceptor acceptor,
Function<IEObjectDescription, ICompletionProposal> proposalFactory) {
// Favorite proposals coming from JDT - https://github.com/eclipse/xtext-xtend/issues/677
String pref= PreferenceConstants.getPreference(PreferenceConstants.CODEASSIST_FAVORITE_STATIC_MEMBERS, null);
String[] favourites= pref.split(";"); //$NON-NLS-1$
for(String fav : favourites) {
String typeName = fav.substring(0, fav.lastIndexOf("."));
JvmType type = typeReferences.findDeclaredType(typeName, context);
if(type != null) {
if(type instanceof JvmDeclaredType) {
JvmDeclaredType genericType = (JvmDeclaredType) type;
// All features but no Constructor
Iterable<JvmFeature> featuresToImport = Iterables.filter(Iterables.filter(genericType.getMembers(), JvmFeature.class), new Predicate<JvmFeature>() {
@Override
public boolean apply(JvmFeature input) {
return !(input instanceof JvmConstructor);
}
});
if(context != null) {
// Make sure that already imported static features are not proposed
RewritableImportSection importSection = importSectionFactory.parse((XtextResource) context.eResource());
featuresToImport = Iterables.filter(featuresToImport, new Predicate<JvmFeature>() {
@Override
public boolean apply(JvmFeature input) {
return !importSection.hasStaticImport(input.getSimpleName(), false);
}
});
}
// Create StaticFeatureDescription instead of SimpleIdentifiableElementDescription since we want the Proposal to show parameters
Iterable<IEObjectDescription> scopedFeatures = Iterables.transform(featuresToImport, new Function<JvmFeature,IEObjectDescription>() {
@Override
public IEObjectDescription apply(JvmFeature feature) {
return new StaticFeatureDescription(QualifiedName.create(feature.getSimpleName()), feature, 0, true);
}
});
// Scope for all static features
IScope staticMemberScope = new SimpleScope(IScope.NULLSCOPE, scopedFeatures);
IReplacementTextApplier textApplier = new FQNImporter(contentAssistContext.getResource(), contentAssistContext.getViewer(), staticMemberScope, qualifiedNameConverter,
qualifiedNameValueConverter, importSectionFactory, replaceConverter);
Function<IEObjectDescription, ICompletionProposal> importAddingProposalFactory = new Function<IEObjectDescription, ICompletionProposal>() {
@Override
public ICompletionProposal apply(IEObjectDescription input) {
ICompletionProposal proposal = proposalFactory.apply(input);
if(proposal instanceof ConfigurableCompletionProposal) {
ConfigurableCompletionProposal castedProposal = (ConfigurableCompletionProposal) proposal;
// Add textApplier to introduce imports if necessary
((ConfigurableCompletionProposal) proposal).setTextApplier(textApplier);
return castedProposal;
}
return proposal;
}
};
getCrossReferenceProposalCreator().lookupCrossReference(staticMemberScope, context, XbasePackage.Literals.XABSTRACT_FEATURE_CALL__FEATURE, acceptor,getFeatureDescriptionPredicate(contentAssistContext),importAddingProposalFactory);
}
}
}
}

@Inject
private RewritableImportSection.Factory importSectionFactory;

@Inject
private ReplaceConverter replaceConverter;

protected String getFeatureCallRuleName() {
return "IdOrSuper";
}

protected String getQualifiedNameRuleName() {
return "QualifiedName";
}

/**
* Create proposal for {@link XAbstractFeatureCall#getFeature() simple feature calls} that use an <code>IdOrSuper</code>
* as concrete syntax.
Expand Down

0 comments on commit a7d9c90

Please sign in to comment.