aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormclay2008-11-09 09:41:58 (EST)
committersefftinge2008-11-09 09:41:58 (EST)
commit0dcacba2b3c50df06b552d01fdc6314c698c72c6 (patch)
tree5e4b1598978af0d96153730691c6c6d185bfdce0
parent6dc60517828857262bffb2d93186ff85844dfdd2 (diff)
downloadorg.eclipse.xtext-0dcacba2b3c50df06b552d01fdc6314c698c72c6.zip
org.eclipse.xtext-0dcacba2b3c50df06b552d01fdc6314c698c72c6.tar.gz
org.eclipse.xtext-0dcacba2b3c50df06b552d01fdc6314c698c72c6.tar.bz2
add: 'right-to-left' (backtrack?) capability and differentiate CA for crossref depending on if its linked or not linked
-rw-r--r--devtools/org.eclipse.xtext.reference.ui/src-gen/org/eclipse/xtext/reference/ReferenceGrammarGenProposalProvider.java16
-rw-r--r--plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/AbstractProposalProvider.java247
-rw-r--r--plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/DefaultContentAssistProcessor.java244
-rw-r--r--plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/IProposalProvider.java4
-rw-r--r--plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/ProposalCandidateResolverSwitch.java8
-rw-r--r--plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/ProposalProviderInvokerSwitch.java271
-rw-r--r--plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/XtextCompletionProposal.java58
7 files changed, 532 insertions, 316 deletions
diff --git a/devtools/org.eclipse.xtext.reference.ui/src-gen/org/eclipse/xtext/reference/ReferenceGrammarGenProposalProvider.java b/devtools/org.eclipse.xtext.reference.ui/src-gen/org/eclipse/xtext/reference/ReferenceGrammarGenProposalProvider.java
index 571d996..bc840df 100644
--- a/devtools/org.eclipse.xtext.reference.ui/src-gen/org/eclipse/xtext/reference/ReferenceGrammarGenProposalProvider.java
+++ b/devtools/org.eclipse.xtext.reference.ui/src-gen/org/eclipse/xtext/reference/ReferenceGrammarGenProposalProvider.java
@@ -52,7 +52,7 @@ public class ReferenceGrammarGenProposalProvider extends AbstractProposalProvid
+ assignment.getTerminal() + "' cardinality '" + assignment.getCardinality() + "' and prefix '"
+ prefix.trim() + "'");
}
- return Collections.singletonList(createCompletionProposal("1", offset));
+ return Collections.singletonList(createCompletionProposal(assignment,model,"1", offset));
}
public List<? extends ICompletionProposal> completeSpielplatzBeschreibung(Assignment assignment, EObject model, String prefix, IDocument doc,int offset) {
@@ -61,7 +61,7 @@ public class ReferenceGrammarGenProposalProvider extends AbstractProposalProvid
+ assignment.getTerminal() + "' cardinality '" + assignment.getCardinality() + "' and prefix '"
+ prefix.trim() + "'");
}
- return Collections.singletonList(createCompletionProposal("\"SpielplatzBeschreibung\"", offset));
+ return Collections.singletonList(createCompletionProposal(assignment,model,"\"SpielplatzBeschreibung\"", offset));
}
public List<? extends ICompletionProposal> completeSpielplatzKinder(Assignment assignment, EObject model, String prefix, IDocument doc,int offset) {
@@ -115,7 +115,7 @@ public class ReferenceGrammarGenProposalProvider extends AbstractProposalProvid
+ assignment.getTerminal() + "' cardinality '" + assignment.getCardinality() + "' and prefix '"
+ prefix.trim() + "'");
}
- return Collections.singletonList(createCompletionProposal("KindName", offset));
+ return Collections.singletonList(createCompletionProposal(assignment,model,"KindName", offset));
}
public List<? extends ICompletionProposal> completeKindAge(Assignment assignment, EObject model, String prefix, IDocument doc,int offset) {
@@ -124,7 +124,7 @@ public class ReferenceGrammarGenProposalProvider extends AbstractProposalProvid
+ assignment.getTerminal() + "' cardinality '" + assignment.getCardinality() + "' and prefix '"
+ prefix.trim() + "'");
}
- return Collections.singletonList(createCompletionProposal("1", offset));
+ return Collections.singletonList(createCompletionProposal(assignment,model,"1", offset));
}
public List<? extends ICompletionProposal> completeErwachsenerName(Assignment assignment, EObject model, String prefix, IDocument doc,int offset) {
@@ -133,7 +133,7 @@ public class ReferenceGrammarGenProposalProvider extends AbstractProposalProvid
+ assignment.getTerminal() + "' cardinality '" + assignment.getCardinality() + "' and prefix '"
+ prefix.trim() + "'");
}
- return Collections.singletonList(createCompletionProposal("ErwachsenerName", offset));
+ return Collections.singletonList(createCompletionProposal(assignment,model,"ErwachsenerName", offset));
}
public List<? extends ICompletionProposal> completeErwachsenerAge(Assignment assignment, EObject model, String prefix, IDocument doc,int offset) {
@@ -142,7 +142,7 @@ public class ReferenceGrammarGenProposalProvider extends AbstractProposalProvid
+ assignment.getTerminal() + "' cardinality '" + assignment.getCardinality() + "' and prefix '"
+ prefix.trim() + "'");
}
- return Collections.singletonList(createCompletionProposal("1", offset));
+ return Collections.singletonList(createCompletionProposal(assignment,model,"1", offset));
}
public List<? extends ICompletionProposal> completeSpielzeugName(Assignment assignment, EObject model, String prefix, IDocument doc,int offset) {
@@ -151,7 +151,7 @@ public class ReferenceGrammarGenProposalProvider extends AbstractProposalProvid
+ assignment.getTerminal() + "' cardinality '" + assignment.getCardinality() + "' and prefix '"
+ prefix.trim() + "'");
}
- return Collections.singletonList(createCompletionProposal("SpielzeugName", offset));
+ return Collections.singletonList(createCompletionProposal(assignment,model,"SpielzeugName", offset));
}
public List<? extends ICompletionProposal> completeSpielzeugFarbe(Assignment assignment, EObject model, String prefix, IDocument doc,int offset) {
@@ -215,7 +215,7 @@ public class ReferenceGrammarGenProposalProvider extends AbstractProposalProvid
+ assignment.getTerminal() + "' cardinality '" + assignment.getCardinality() + "' and prefix '"
+ prefix.trim() + "'");
}
- return Collections.singletonList(createCompletionProposal("CustomTypeParserRuleName", offset));
+ return Collections.singletonList(createCompletionProposal(assignment,model,"CustomTypeParserRuleName", offset));
}
diff --git a/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/AbstractProposalProvider.java b/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/AbstractProposalProvider.java
index 0eda0d4..ec42692 100644
--- a/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/AbstractProposalProvider.java
+++ b/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/AbstractProposalProvider.java
@@ -13,6 +13,7 @@ import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.viewers.StyledString;
+import org.eclipse.xtext.AbstractElement;
import org.eclipse.xtext.AbstractRule;
import org.eclipse.xtext.Assignment;
import org.eclipse.xtext.CrossReference;
@@ -58,9 +59,9 @@ public abstract class AbstractProposalProvider implements IProposalProvider {
+ prefix.trim() + "'");
}
String text = keyword.getValue().length() == 1 ? keyword.getValue() : keyword.getValue() + " ";
- return Collections.singletonList(createCompletionProposal(text, offset));
+ return Collections.singletonList(createCompletionProposal(keyword, model, text, offset));
}
-
+
/*
* (non-Javadoc)
* @see org.eclipse.xtext.ui.common.editor.codecompletion.IProposalProvider#completeRuleCall(org.eclipse.xtext.RuleCall, org.eclipse.emf.ecore.EObject, java.lang.String, org.eclipse.jface.text.IDocument, int)
@@ -71,119 +72,78 @@ public abstract class AbstractProposalProvider implements IProposalProvider {
logger.debug("completeRuleCall '" + ruleCall.getName() + "' cardinality '" + ruleCall.getCardinality()
+ "' for model '" + model + "' and prefix '" + prefix.trim() + "'");
}
-
+
AbstractRule calledRule = GrammarUtil.calledRule(ruleCall);
-
+
if (calledRule instanceof LexerRule) {
- return doCompleteLexerRuleRuleCall((LexerRule) calledRule, ruleCall, offset);
- }
-
+ return doCompleteLexerRuleRuleCall((LexerRule) calledRule, ruleCall, model, offset);
+ }
+
return Collections.emptyList();
}
-
+
/*
* (non-Javadoc)
- * @see org.eclipse.xtext.ui.common.editor.codecompletion.IProposalProvider#sortAndFilter(java.util.List, org.eclipse.emf.ecore.EObject, java.lang.String)
+ * @see org.eclipse.xtext.ui.common.editor.codecompletion.IProposalProvider#sortAndFilter(java.util.List, org.eclipse.emf.ecore.EObject, java.lang.String, org.eclipse.jface.text.IDocument, int)
*/
public List<? extends ICompletionProposal> sortAndFilter(
- List<? extends ICompletionProposal> completionProposalList, EObject model, String prefix) {
- return doSortAndFilter(completionProposalList,model,prefix);
+ List<? extends ICompletionProposal> completionProposalList, EObject model, String prefix,
+ IDocument document, int offset) {
+ return doSortAndFilter(completionProposalList, model, prefix, document, offset);
}
-
- /**
- * Concrete subclasses can override this for custom sort and filter
- * behavior. Gets called after all completion proposals have been collected.
- *
- * The default behavior of this implementation is to sort duplicates and to trim
- * matching <code>ICompletionProposal#displayString</code> with matching prefix values.
- *
- * @param completionProposalList matching {@link ICompletionProposal} to sort and filter
- * @param model - the most specific model element under the cursor.
- * @param prefix - the prefix under the cursor or null if there is no prefix
- * @return the sorted and filtered <code>ICompletionProposal</code> list.
- *
- */
- protected List<? extends ICompletionProposal> doSortAndFilter(
- List<? extends ICompletionProposal> completionProposalList,EObject model,String prefix) {
-
- if (model instanceof LeafNode) {
-
- LeafNode leafNode = (LeafNode) model;
-
- Map<String,ICompletionProposal> displayString2ICompletionProposalMap = new HashMap<String,ICompletionProposal>();
-
- for (Iterator<? extends ICompletionProposal> iterator = completionProposalList.iterator(); iterator.hasNext();) {
- ICompletionProposal completionProposal = iterator.next();
-
- // filter duplicate displayString
- if (!displayString2ICompletionProposalMap.containsKey(completionProposal.getDisplayString())) {
-
- displayString2ICompletionProposalMap.put(completionProposal.getDisplayString(), completionProposal);
-
- // trim displayString
- if (leafNode.isHidden() && !"".equals(leafNode.getText().trim()) ) {
-
- if (completionProposal.getDisplayString().startsWith(leafNode.getText()) &&
- completionProposal instanceof XtextCompletionProposal) {
-
- XtextCompletionProposal xtextCompletionProposal = (XtextCompletionProposal) completionProposal;
-
- xtextCompletionProposal.setText(xtextCompletionProposal.getText().replaceFirst(leafNode.getText(), ""));
- } else {
- iterator.remove();
- }
- }
- } else {
- iterator.remove();
- }
- }
- }
-
- return completionProposalList;
- }
-
/**
- * Concrete subclasses can override this to provide a more meaningful and sophisticated behaviour
- * whenever a list of ICompletionProposal's should be computed for simple <code>LexerRule</code> call's.
+ * Concrete subclasses can override this to provide a more meaningful and
+ * sophisticated behaviour whenever a list of ICompletionProposal's should
+ * be computed for simple <code>LexerRule</code> call's.
*
- * This implementation returns one <code>ICompletionProposal</code> with a displayString composed
- * of the name of the containing rule plus the featurename of an optional assignment and at the end the name
- * of the given LexerRule (e.i. ParserRuleName+AssignmentFeatureName+LexerRuleName) or {@link #getDefaultIntegerValue()}
- * if its <i>INT</i> based LexerRule.
+ * This implementation returns one <code>ICompletionProposal</code> with a
+ * displayString composed of the name of the containing rule plus the
+ * featurename of an optional assignment and at the end the name of the
+ * given LexerRule (e.i. ParserRuleName+AssignmentFeatureName+LexerRuleName)
+ * or {@link #getDefaultIntegerValue()} if its <i>INT</i> based LexerRule.
*
- * @param lexerRule the 'called' LexerRule instance
- * @param ruleCall the ruleCall for the provided lexerRule
- * @param offset an offset within the document for which completions should be computed
- * @return a computed list of <code>ICompletionProposal</code> for the given <code>LexerRule</code>
+ * @param lexerRule
+ * the 'called' LexerRule instance
+ * @param ruleCall
+ * the ruleCall for the provided lexerRule
+ * @param offset
+ * an offset within the document for which completions should be
+ * computed
+ * @return a computed list of <code>ICompletionProposal</code> for the given
+ * <code>LexerRule</code>
*/
- protected List<? extends ICompletionProposal> doCompleteLexerRuleRuleCall(LexerRule lexerRule,RuleCall ruleCall, int offset) {
+ protected List<? extends ICompletionProposal> doCompleteLexerRuleRuleCall(LexerRule lexerRule, RuleCall ruleCall,
+ EObject model, int offset) {
ParserRule containingParserRule = GrammarUtil.containingParserRule(ruleCall);
Assignment containingAssignment = GrammarUtil.containingAssignment(ruleCall);
-
- String defaultDisplayString = containingParserRule.getName() +
- (null != containingAssignment ? firstLetterCapitalized(containingAssignment.getFeature()) : "") + lexerRule.getName();
-
+
+ String defaultDisplayString = containingParserRule.getName()
+ + (null != containingAssignment ? firstLetterCapitalized(containingAssignment.getFeature()) : "")
+ + lexerRule.getName();
+
if (LEXER_RULE_INT.equalsIgnoreCase(lexerRule.getName())) {
- defaultDisplayString=String.valueOf(getDefaultIntegerValue());
- } else if (LEXER_RULE_STRING.equalsIgnoreCase(lexerRule.getName())) {
- defaultDisplayString="\""+defaultDisplayString+"\"";
- }
-
- return Collections.singletonList(createCompletionProposal(defaultDisplayString, offset));
+ defaultDisplayString = String.valueOf(getDefaultIntegerValue());
+ }
+ else if (LEXER_RULE_STRING.equalsIgnoreCase(lexerRule.getName())) {
+ defaultDisplayString = "\"" + defaultDisplayString + "\"";
+ }
+
+ return Collections.singletonList(createCompletionProposal(containingAssignment, model, defaultDisplayString,
+ offset));
}
-
+
/**
* @return the default integer value for ecore::EInt <code>RuleCall<>
*/
protected int getDefaultIntegerValue() {
return 0;
}
-
+
/**
*
- * @return the id of the plug-in containing the image files;
- * <code>null</code> is returned if the plug-in does not exist
+ * @return the id of the plug-in containing the image files; <code>null
+ * </code> is returned if the plug-in does not exist
*/
protected abstract String getPluginId();
@@ -209,14 +169,17 @@ public abstract class AbstractProposalProvider implements IProposalProvider {
*/
protected List<? extends ICompletionProposal> lookupCrossReference(CrossReference crossReference, EObject model,
String prefix, int offset) {
-
+
List<ICompletionProposal> completionProposalList = new ArrayList<ICompletionProposal>();
if (linkingService != null) {
- EObject semanticModel = model instanceof AbstractNode?NodeUtil.getNearestSemanticObject((AbstractNode) model):model;
- List<Pair<String, URI>> candidates = linkingService.getLinkCandidates(semanticModel, crossReference, prefix);
+ EObject semanticModel = model instanceof AbstractNode ? NodeUtil
+ .getNearestSemanticObject((AbstractNode) model) : model;
+ List<Pair<String, URI>> candidates = linkingService
+ .getLinkCandidates(semanticModel, crossReference, prefix);
for (Pair<String, URI> candidate : candidates) {
- completionProposalList.add(createCompletionProposal(candidate.getFirstElement(), offset));
+ completionProposalList.add(createCompletionProposal(crossReference, model, candidate.getFirstElement(),
+ offset));
}
}
@@ -227,13 +190,103 @@ public abstract class AbstractProposalProvider implements IProposalProvider {
* @return a new <code>XtextCompletionProposal</code> for the given text and
* offset.
*/
- protected final XtextCompletionProposal createCompletionProposal(String text, int offset) {
- return new XtextCompletionProposal(text, new StyledString(text), text, getDefaultImageFilePath(),
- getPluginId(), offset);
+ protected final XtextCompletionProposal createCompletionProposal(AbstractElement abstractElement, EObject model,
+ String text, int offset) {
+ return new XtextCompletionProposal(abstractElement, model, text, new StyledString(text), text,
+ getDefaultImageFilePath(), getPluginId(), offset);
+ }
+
+ /**
+ * Concrete subclasses can override this for custom sort and filter
+ * behavior. Gets called after all completion proposals have been collected.
+ *
+ * The default behavior of this implementation is to sort duplicates and to
+ * trim matching <code>ICompletionProposal#displayString</code> with
+ * matching prefix values.
+ *
+ * @param completionProposalList
+ * matching {@link ICompletionProposal} to sort and filter
+ * @param model
+ * - the most specific model element under the cursor.
+ * @param prefix
+ * - the prefix under the cursor or null if there is no prefix
+ * @param offset
+ * @param document
+ * @return the sorted and filtered <code>ICompletionProposal</code> list.
+ *
+ */
+ protected List<? extends ICompletionProposal> doSortAndFilter(
+ List<? extends ICompletionProposal> completionProposalList, EObject model, String prefix,
+ IDocument document, int offset) {
+
+ if (model instanceof LeafNode) {
+
+ LeafNode leafNode = (LeafNode) model;
+
+ Map<String, ICompletionProposal> displayString2ICompletionProposalMap = new HashMap<String, ICompletionProposal>();
+
+ for (Iterator<? extends ICompletionProposal> iterator = completionProposalList.iterator(); iterator
+ .hasNext();) {
+
+ ICompletionProposal completionProposal = iterator.next();
+
+ // filter duplicate displayString
+ if (!displayString2ICompletionProposalMap.containsKey(completionProposal.getDisplayString())) {
+
+ displayString2ICompletionProposalMap.put(completionProposal.getDisplayString(), completionProposal);
+
+ boolean cursorIsAtTheEndOfTheLastElement = offset == (leafNode.getOffset() + leafNode.getLength());
+ /**
+ * 1. filter and trim proposal's matching the prefix of the
+ * current leafNode (e.g. leafNode 'kin' for keyword 'kind'
+ * will be trimmed to 'd' , displayString stays the same)
+ * <p/>
+ * 2. special case for crossref: if the cursor is at the end
+ * of the previous element kind>|< we want to apply the
+ * filter only to instances of the previous grammarElement
+ * in order to always show all matches for 'right-to-left'
+ * backtracking use-cases
+ */
+ if ((leafNode.isHidden() || cursorIsAtTheEndOfTheLastElement)
+ && !"".equals(leafNode.getText().trim())
+ && completionProposal instanceof XtextCompletionProposal) {
+
+ XtextCompletionProposal xtextCompletionProposal = (XtextCompletionProposal) completionProposal;
+
+ AbstractElement abstractElement = xtextCompletionProposal.getAbstractElement();
+
+ EObject grammarElement = leafNode.getGrammarElement();
+ // at the end of the last element we want to filter only
+ // the CompletionProposal for the same grammar element
+ if (completionProposal.getDisplayString().startsWith(leafNode.getText())) {
+ xtextCompletionProposal.setText(xtextCompletionProposal.getText().substring(
+ leafNode.getText().length()));
+ }
+ else if ((cursorIsAtTheEndOfTheLastElement && abstractElement.equals(grammarElement))
+ || !cursorIsAtTheEndOfTheLastElement) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("filter completionProposal '" + completionProposal + "'");
+ }
+ iterator.remove();
+ }
+ }
+ }
+ else {
+ if (logger.isDebugEnabled()) {
+ logger.debug("filter duplicate completionProposal '" + completionProposal + "'");
+ }
+
+ iterator.remove();
+ }
+ }
+ }
+
+ return completionProposalList;
}
/**
- * @param text to apply
+ * @param text
+ * to apply
* @return the provided string with the first letter capitalized
*/
protected final String firstLetterCapitalized(String text) {
diff --git a/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/DefaultContentAssistProcessor.java b/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/DefaultContentAssistProcessor.java
index 7b3c99e..3a31dc3 100644
--- a/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/DefaultContentAssistProcessor.java
+++ b/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/DefaultContentAssistProcessor.java
@@ -1,13 +1,8 @@
package org.eclipse.xtext.ui.common.editor.codecompletion;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
@@ -25,15 +20,9 @@ import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
import org.eclipse.xtext.AbstractElement;
-import org.eclipse.xtext.AbstractRule;
-import org.eclipse.xtext.Assignment;
import org.eclipse.xtext.CrossReference;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.GrammarUtil;
-import org.eclipse.xtext.Keyword;
-import org.eclipse.xtext.ParserRule;
-import org.eclipse.xtext.RuleCall;
-import org.eclipse.xtext.TypeRef;
import org.eclipse.xtext.parser.IParseResult;
import org.eclipse.xtext.parsetree.AbstractNode;
import org.eclipse.xtext.parsetree.CompositeNode;
@@ -58,7 +47,6 @@ public class DefaultContentAssistProcessor implements IContentAssistProcessor {
@Inject
private IProposalProvider proposalProvider;
- private final Map<String, Method> methodLookupMap = new HashMap<String, Method>();
/**
* computes the possible grammar elements following the one at the given
@@ -93,25 +81,37 @@ public class DefaultContentAssistProcessor implements IContentAssistProcessor {
LeafNode currentLeafNode = ParseTreeUtil.getCurrentNodeByOffset(rootNode, offset);
String prefix = null==currentLeafNode ? "" : currentLeafNode.getText();
-
- Set<AbstractElement> nextValidElementSet = ParseTreeUtil.getElementSetValidFromOffset(rootNode,lastCompleteNode, offset);
+
+ Set<AbstractElement> nextValidElementSet = new LinkedHashSet<AbstractElement>();
+ /**
+ * in the case of a non linked crossreference we delegate to proposalProvider (again)
+ */
+ if (lastCompleteNode.getGrammarElement() instanceof CrossReference && !isLinked(lastCompleteNode)) {
+
+ nextValidElementSet.add((AbstractElement) lastCompleteNode.getGrammarElement());
+ }
/**
- * in the case of a non linked crossreference we delegate to proposalProvider (again)
+ * in the case we are at the end of the completed previous element add for 'right-to-left' backtracking cases
*/
- if (lastCompleteNode.getGrammarElement() instanceof CrossReference && !isLinked(lastCompleteNode) ) {
- nextValidElementSet.add((AbstractElement) lastCompleteNode.getGrammarElement().eContainer());
+ else if (currentLeafNode==lastCompleteNode) {
+ nextValidElementSet.add((AbstractElement) lastCompleteNode.getGrammarElement());
}
+ nextValidElementSet.addAll(ParseTreeUtil.getElementSetValidFromOffset(rootNode,lastCompleteNode, offset));
+
+ ProposalProviderInvokerSwitch proposalProviderInvokerSwitch = new ProposalProviderInvokerSwitch(
+ lastCompleteNode, document, offset, prefix, proposalProvider);
+
for (List<EObject> resolvedElementOrRuleList : new ProposalCandidateResolverSwitch(nextValidElementSet)) {
- List<ICompletionProposal> collectedCompletionProposalList = collectCompletionProposalList(resolvedElementOrRuleList, xtextDocument,
- lastCompleteNode, prefix, offset);
+ List<ICompletionProposal> collectedCompletionProposalList =
+ proposalProviderInvokerSwitch.collectCompletionProposalList(resolvedElementOrRuleList);
completionProposalList.addAll(collectedCompletionProposalList);
}
if (completionProposalList != null) {
- List<? extends ICompletionProposal> sortAndFilter = proposalProvider.sortAndFilter(completionProposalList,currentLeafNode,prefix);
+ List<? extends ICompletionProposal> sortAndFilter = proposalProvider.sortAndFilter(completionProposalList,currentLeafNode,prefix,document,offset);
completionProposals = sortAndFilter.toArray(new ICompletionProposal[] {});
}
}
@@ -140,210 +140,42 @@ public class DefaultContentAssistProcessor implements IContentAssistProcessor {
return new ContextInformationValidator(this);
}
- private List<ICompletionProposal> collectCompletionProposalList(List<EObject> resolvedElementOrRuleList, IDocument document, AbstractNode currentLeafNode,
- String prefix, final int offset) {
-
- List<ICompletionProposal> completionProposalList = new ArrayList<ICompletionProposal>();
-
- for (Iterator<EObject> elementOrRuleIterator = resolvedElementOrRuleList.iterator(); elementOrRuleIterator
- .hasNext();) {
- EObject abstractElement = elementOrRuleIterator.next();
-
- if (abstractElement instanceof Keyword) {
- completionProposalList.addAll(proposalProvider.completeKeyword((Keyword) abstractElement,
- currentLeafNode, prefix, document, offset));
- }
- else if (abstractElement instanceof Assignment) {
-
- Assignment assignment = (Assignment) abstractElement;
-
- ParserRule parserRule = GrammarUtil.containingParserRule(assignment);
-
- EObject model = null == ((CompositeNode) currentLeafNode.eContainer()).getElement() ? currentLeafNode
- .eContainer() : ((CompositeNode) currentLeafNode.eContainer()).getElement();
-
- Method method = findMethod(proposalProvider.getClass(), "complete"
- + firstLetterCapitalized(parserRule.getName())
- + firstLetterCapitalized(assignment.getFeature()), Assignment.class, model.getClass(),
- String.class, document.getClass(), int.class);
-
- Collection<? extends ICompletionProposal> assignmentProposalList = null == method ? null
- : invokeMethod(method, proposalProvider, assignment, model, prefix, document, offset);
-
- if (null != assignmentProposalList) {
- completionProposalList.addAll(assignmentProposalList);
- }
-
- }
- else if (abstractElement instanceof RuleCall) {
-
- EObject model = null == ((CompositeNode) currentLeafNode.eContainer()).getElement() ? currentLeafNode
- .eContainer() : ((CompositeNode) currentLeafNode.eContainer()).getElement();
-
- List<? extends ICompletionProposal> ruleCallProposalList = this.proposalProvider.completeRuleCall(
- (RuleCall) abstractElement, model, prefix, document, offset);
-
- if (null != ruleCallProposalList) {
- completionProposalList.addAll(ruleCallProposalList);
- }
-
- AbstractRule calledRule = GrammarUtil.calledRule((RuleCall) abstractElement);
-
- if (calledRule.getType() != null) {
-
- TypeRef typeRef = calledRule.getType();
-
- Method method = findMethod(proposalProvider.getClass(), "complete"
- + firstLetterCapitalized(typeRef.getAlias()) + firstLetterCapitalized(typeRef.getName()),
- RuleCall.class, model.getClass(), String.class, document.getClass(), int.class);
-
- Collection<? extends ICompletionProposal> proposalList = null == method ? null : invokeMethod(
- method, proposalProvider, abstractElement, model, prefix, document, offset);
-
- if (null != proposalList) {
- completionProposalList.addAll(proposalList);
- }
-
- }
- }
- }
-
- return completionProposalList;
- }
-
- private final Method findMethod(Class<?> clazz, String name, Class<?>... paramTypes) {
- Assert.isNotNull(clazz, "Class must not be null");
- Assert.isNotNull(name, "Method name must not be null");
- Method result = methodLookupMap.get(name);
- Class<?> searchType = clazz;
- while (!Object.class.equals(searchType) && searchType != null && null == result) {
- Method[] methods = (searchType.isInterface() ? searchType.getMethods() : searchType.getDeclaredMethods());
- for (int i = 0; i < methods.length; i++) {
- Method method = methods[i];
- if (name.equals(method.getName())
- && (paramTypes == null || equalOrAssignableTypes(method.getParameterTypes(), paramTypes))) {
- if (result == null
- || equalOrAssignableTypes(result.getParameterTypes(), method.getParameterTypes())) {
- result = method;
- methodLookupMap.put(name, method);
- }
- }
- }
- searchType = searchType.getSuperclass();
- }
- return result;
- }
@SuppressWarnings("unchecked")
- private final Collection<ICompletionProposal> invokeMethod(Method method, Object target, Object... args) {
-
- try {
- return (Collection<ICompletionProposal>) method.invoke(target, args);
- }
- catch (Exception ex) {
- handleReflectionException(ex);
- }
- throw new IllegalStateException("huh?");
- }
-
- private void handleReflectionException(Exception ex) {
- if (ex instanceof NoSuchMethodException) {
- throw new IllegalStateException("Method not found: " + ex.getMessage());
- }
- if (ex instanceof IllegalAccessException) {
- throw new IllegalStateException("Could not access method: " + ex.getMessage());
- }
- if (ex instanceof InvocationTargetException) {
- rethrowRuntimeException(((InvocationTargetException) ex).getTargetException());
- }
- if (ex instanceof RuntimeException) {
- throw (RuntimeException) ex;
- }
- handleUnexpectedException(ex);
- }
-
- private void handleUnexpectedException(Throwable ex) {
- IllegalStateException isex = new IllegalStateException("Unexpected exception thrown");
- isex.initCause(ex);
- throw isex;
- }
-
- private final void rethrowRuntimeException(Throwable ex) {
- if (ex instanceof RuntimeException) {
- throw (RuntimeException) ex;
- }
- if (ex instanceof Error) {
- throw (Error) ex;
- }
- handleUnexpectedException(ex);
- }
-
- private boolean equalOrAssignableTypes(Class<?>[] a, Class<?>[] a2) {
- if (a == a2) {
- return true;
- }
-
- if (a == null || a2 == null) {
- return false;
- }
+ private boolean isLinked(AbstractNode lastCompleteNode) {
- int length = a.length;
+ EObject semanticModel = NodeUtil.getNearestSemanticObject(lastCompleteNode);
- if (a2.length != length) {
- return false;
- }
+ EReference eReference = getReference((CrossReference) lastCompleteNode.getGrammarElement(), semanticModel
+ .eClass());
- for (int i = 0; i < length; i++) {
- Class<?> o1 = a[i];
- Class<?> o2 = a2[i];
+ if (eReference.getUpperBound() == 1) {
- if (!(o1 == null ? o2 == null : o1.equals(o2) || o1.isAssignableFrom(o2))) {
- return false;
- }
- }
- return true;
- }
-
- private final String firstLetterCapitalized(String name) {
- return name.substring(0, 1).toUpperCase() + name.substring(1);
- }
-
- @SuppressWarnings("unchecked")
- private boolean isLinked(AbstractNode lastCompleteNode) {
-
- EObject semanticModel = NodeUtil.getNearestSemanticObject(lastCompleteNode);
-
- EReference eReference = getReference((CrossReference) lastCompleteNode.getGrammarElement(), semanticModel.eClass());
-
- if (eReference.getUpperBound() == 1 ) {
-
- if (null!=semanticModel.eGet(eReference)) {
+ if (null != semanticModel.eGet(eReference)) {
return true;
}
}
- else {
-
+ else {
+
EcoreEList<EObject> ecoreEList = (EcoreEList<EObject>) semanticModel.eGet(eReference);
-
- for (Iterator<EObject> iterator = ecoreEList.iterator(); iterator.hasNext();) {
-
- EObject object = iterator.next();
-
- if (EcoreUtil2.getURIFragment(object).equalsIgnoreCase(((LeafNode)lastCompleteNode).getText())) {
+
+ for (EObject object : ecoreEList) {
+
+ if (EcoreUtil2.getURIFragment(object).equalsIgnoreCase(((LeafNode) lastCompleteNode).getText())) {
return true;
}
}
}
-
+
return false;
}
-
+
private EReference getReference(CrossReference ref, EClass class1) {
-
+
EList<EReference> references = class1.getEAllReferences();
-
+
String feature = GrammarUtil.containingAssignment(ref).getFeature();
-
+
for (EReference reference : references) {
if (!reference.isContainment() && reference.getName().equals(feature))
return reference;
diff --git a/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/IProposalProvider.java b/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/IProposalProvider.java
index 394988f..88db9a5 100644
--- a/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/IProposalProvider.java
+++ b/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/IProposalProvider.java
@@ -71,8 +71,8 @@ public interface IProposalProvider {
* This method is invoked by the framework after all possible completions have been collected.
* @param completionProposalList matching {@link ICompletionProposal} to sort and filter
* @param model - the most specific model element under the cursor.
- * @param prefix - the prefix under the cursor or null if there is no prefix
* @return the sorted and filtered <code>ICompletionProposal</code> list.
+ *
*/
- public List<? extends ICompletionProposal> sortAndFilter(List<? extends ICompletionProposal> completionProposalList,EObject model,String prefix);
+ public List<? extends ICompletionProposal> sortAndFilter(List<? extends ICompletionProposal> completionProposalList,EObject model, String prefix, IDocument document,int offset);
}
diff --git a/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/ProposalCandidateResolverSwitch.java b/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/ProposalCandidateResolverSwitch.java
index 4028f49..b3e31ea 100644
--- a/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/ProposalCandidateResolverSwitch.java
+++ b/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/ProposalCandidateResolverSwitch.java
@@ -19,6 +19,7 @@ import org.eclipse.xtext.AbstractElement;
import org.eclipse.xtext.AbstractRule;
import org.eclipse.xtext.Alternatives;
import org.eclipse.xtext.Assignment;
+import org.eclipse.xtext.CrossReference;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.Group;
import org.eclipse.xtext.ParserRule;
@@ -26,7 +27,7 @@ import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.util.XtextSwitch;
/**
- * Represents <b>Switch</b> for the model's inheritance hierarchy to resolve
+ * Represents a <b>Switch</b> for the Xtext model's inheritance hierarchy to resolve
* potential completion proposal candidate's.
*
* It supports the call {@link #doSwitch(EObject) doSwitch(object)} instead of
@@ -115,6 +116,11 @@ public class ProposalCandidateResolverSwitch extends XtextSwitch<List<EObject>>
}
return elementList;
}
+
+ @Override
+ public List<EObject> caseCrossReference(CrossReference crossReference) {
+ return Collections.singletonList(crossReference.eContainer());
+ }
@Override
public List<EObject> defaultCase(EObject object) {
diff --git a/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/ProposalProviderInvokerSwitch.java b/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/ProposalProviderInvokerSwitch.java
new file mode 100644
index 0000000..b12e918
--- /dev/null
+++ b/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/ProposalProviderInvokerSwitch.java
@@ -0,0 +1,271 @@
+/*******************************************************************************
+ * Copyright (c) 2008 itemis AG (http://www.itemis.eu) and others.
+ * 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ *******************************************************************************/
+package org.eclipse.xtext.ui.common.editor.codecompletion;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.xtext.AbstractRule;
+import org.eclipse.xtext.Assignment;
+import org.eclipse.xtext.GrammarUtil;
+import org.eclipse.xtext.Keyword;
+import org.eclipse.xtext.ParserRule;
+import org.eclipse.xtext.RuleCall;
+import org.eclipse.xtext.TypeRef;
+import org.eclipse.xtext.parsetree.AbstractNode;
+import org.eclipse.xtext.parsetree.CompositeNode;
+import org.eclipse.xtext.util.XtextSwitch;
+
+/**
+ * Represents a <b>Switch</b> for the Xtext model's inheritance hierarchy to
+ * callback and invoke the completion methods of <code>IProposalProvider</code>
+ * implementations to gather and collect <code>ICompletionProposal</code> to be
+ * displayed for Content Assist.
+ *
+ * It supports the call {@link #doSwitch(EObject) doSwitch(object)} instead of
+ * typical <code>if (x instanceof y)</code> code blocks.
+ *
+ * @author Michael Clay - Initial contribution and API
+ * @see IProposalProvider
+ * @see org.eclipse.xtext.util.XtextSwitch
+ */
+public class ProposalProviderInvokerSwitch extends XtextSwitch<List<ICompletionProposal>> {
+
+ private List<ICompletionProposal> completionProposalList = new ArrayList<ICompletionProposal>();
+
+ private final IProposalProvider proposalProvider;
+
+ private final IDocument document;
+
+ private final AbstractNode currentLeafNode;
+
+ private final String prefix;
+
+ private int offset;
+
+ private static final Map<String, Method> methodLookupMap = new HashMap<String, Method>();
+
+ /**
+ *
+ * @param currentLeafNode
+ * the last node in the document
+ * @param document
+ * the document itself
+ * @param offset
+ * the position in the offset from which CA was triggered
+ * @param prefix
+ * the prefix normally consisting of the text content of the
+ * currentLeafNode
+ * @param proposalProvider
+ * the proposalProvider to callback and invoke
+ */
+ public ProposalProviderInvokerSwitch(AbstractNode currentLeafNode, IDocument document, int offset, String prefix,
+ IProposalProvider proposalProvider) {
+ super();
+ this.currentLeafNode = currentLeafNode;
+ this.document = document;
+ this.offset = offset;
+ this.prefix = prefix;
+ this.proposalProvider = proposalProvider;
+ }
+
+ /**
+ * Collect a list of <code>ICompletionProposal</code> for the given
+ * elementList through callback and reflective invocations to
+ * <code>IProposalProvider</code>
+ *
+ * @param elementList
+ * the list of <code>EObject</code> to collect
+ * <code>ICompletionProposal</code> for
+ * @return a list of matching <code>ICompletionProposal</code>
+ */
+ public List<ICompletionProposal> collectCompletionProposalList(List<EObject> elementList) {
+
+ completionProposalList = new ArrayList<ICompletionProposal>();
+
+ for (Iterator<EObject> elementOrRuleIterator = elementList.iterator(); elementOrRuleIterator.hasNext();) {
+ EObject abstractElement = elementOrRuleIterator.next();
+ doSwitch(abstractElement);
+ }
+
+ return completionProposalList;
+
+ }
+
+ @Override
+ public List<ICompletionProposal> caseAssignment(Assignment assignment) {
+ ParserRule parserRule = GrammarUtil.containingParserRule(assignment);
+
+ EObject model = null == ((CompositeNode) currentLeafNode.eContainer()).getElement() ? currentLeafNode
+ .eContainer() : ((CompositeNode) currentLeafNode.eContainer()).getElement();
+
+ Method method = findMethod(proposalProvider.getClass(), "complete"
+ + firstLetterCapitalized(parserRule.getName()) + firstLetterCapitalized(assignment.getFeature()),
+ Assignment.class, model.getClass(), String.class, document.getClass(), int.class);
+
+ Collection<? extends ICompletionProposal> assignmentProposalList = null == method ? null : invokeMethod(method,
+ proposalProvider, assignment, model, prefix, document, offset);
+
+ if (null != assignmentProposalList) {
+ completionProposalList.addAll(assignmentProposalList);
+ }
+
+ return null;
+ }
+
+ @Override
+ public List<ICompletionProposal> caseKeyword(Keyword keyword) {
+ completionProposalList.addAll(proposalProvider.completeKeyword(keyword, currentLeafNode, prefix, document,
+ offset));
+ return null;
+ }
+
+ @Override
+ public List<ICompletionProposal> caseRuleCall(RuleCall ruleCall) {
+
+ EObject model = null == ((CompositeNode) currentLeafNode.eContainer()).getElement() ? currentLeafNode
+ .eContainer() : ((CompositeNode) currentLeafNode.eContainer()).getElement();
+
+
+ List<? extends ICompletionProposal> ruleCallProposalList = this.proposalProvider.completeRuleCall(ruleCall,
+ model, prefix, document, offset);
+
+ if (null != ruleCallProposalList) {
+ completionProposalList.addAll(ruleCallProposalList);
+ }
+
+ AbstractRule calledRule = GrammarUtil.calledRule(ruleCall);
+
+ if (calledRule.getType() != null) {
+
+ TypeRef typeRef = calledRule.getType();
+
+ Method method = findMethod(proposalProvider.getClass(), "complete"
+ + firstLetterCapitalized(typeRef.getAlias()) + firstLetterCapitalized(typeRef.getName()),
+ RuleCall.class, model.getClass(), String.class, document.getClass(), int.class);
+
+ Collection<? extends ICompletionProposal> proposalList = null == method ? null : invokeMethod(method,
+ proposalProvider, ruleCall, model, prefix, document, offset);
+
+ if (null != proposalList) {
+ completionProposalList.addAll(proposalList);
+ }
+
+ }
+ return null;
+ }
+
+ private final Method findMethod(Class<?> clazz, String name, Class<?>... paramTypes) {
+ Assert.isNotNull(clazz, "Class must not be null");
+ Assert.isNotNull(name, "Method name must not be null");
+ Method result = methodLookupMap.get(name);
+ Class<?> searchType = clazz;
+ while (!Object.class.equals(searchType) && searchType != null && null == result) {
+ Method[] methods = (searchType.isInterface() ? searchType.getMethods() : searchType.getDeclaredMethods());
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ if (name.equals(method.getName())
+ && (paramTypes == null || equalOrAssignableTypes(method.getParameterTypes(), paramTypes))) {
+ if (result == null
+ || equalOrAssignableTypes(result.getParameterTypes(), method.getParameterTypes())) {
+ result = method;
+ methodLookupMap.put(name, method);
+ }
+ }
+ }
+ searchType = searchType.getSuperclass();
+ }
+ return result;
+ }
+
+ @SuppressWarnings("unchecked")
+ private final Collection<ICompletionProposal> invokeMethod(Method method, Object target, Object... args) {
+
+ try {
+ return (Collection<ICompletionProposal>) method.invoke(target, args);
+ }
+ catch (Exception ex) {
+ handleReflectionException(ex);
+ }
+ throw new IllegalStateException("huh?");
+ }
+
+ private void handleReflectionException(Exception ex) {
+ if (ex instanceof NoSuchMethodException) {
+ throw new IllegalStateException("Method not found: " + ex.getMessage());
+ }
+ if (ex instanceof IllegalAccessException) {
+ throw new IllegalStateException("Could not access method: " + ex.getMessage());
+ }
+ if (ex instanceof InvocationTargetException) {
+ rethrowRuntimeException(((InvocationTargetException) ex).getTargetException());
+ }
+ if (ex instanceof RuntimeException) {
+ throw (RuntimeException) ex;
+ }
+ handleUnexpectedException(ex);
+ }
+
+ private void handleUnexpectedException(Throwable ex) {
+ IllegalStateException isex = new IllegalStateException("Unexpected exception thrown");
+ isex.initCause(ex);
+ throw isex;
+ }
+
+ private final void rethrowRuntimeException(Throwable ex) {
+ if (ex instanceof RuntimeException) {
+ throw (RuntimeException) ex;
+ }
+ if (ex instanceof Error) {
+ throw (Error) ex;
+ }
+ handleUnexpectedException(ex);
+ }
+
+ private boolean equalOrAssignableTypes(Class<?>[] a, Class<?>[] a2) {
+ if (a == a2) {
+ return true;
+ }
+
+ if (a == null || a2 == null) {
+ return false;
+ }
+
+ int length = a.length;
+
+ if (a2.length != length) {
+ return false;
+ }
+
+ for (int i = 0; i < length; i++) {
+ Class<?> o1 = a[i];
+ Class<?> o2 = a2[i];
+
+ if (!(o1 == null ? o2 == null : o1.equals(o2) || o1.isAssignableFrom(o2))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private final String firstLetterCapitalized(String name) {
+ return name.substring(0, 1).toUpperCase() + name.substring(1);
+ }
+
+}
diff --git a/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/XtextCompletionProposal.java b/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/XtextCompletionProposal.java
index 9428dbd..ffeef6d 100644
--- a/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/XtextCompletionProposal.java
+++ b/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/XtextCompletionProposal.java
@@ -2,6 +2,7 @@ package org.eclipse.xtext.ui.common.editor.codecompletion;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.Assert;
+import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentEvent;
@@ -15,6 +16,7 @@ import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
+import org.eclipse.xtext.AbstractElement;
/**
* Default Xtext implementation of interface <code>ICompletionProposal</code>.
@@ -28,8 +30,11 @@ import org.eclipse.swt.graphics.Point;
public class XtextCompletionProposal implements ICompletionProposal,
ICompletionProposalExtension2, ICompletionProposalExtension6 {
- private Logger logger = Logger.getLogger(XtextCompletionProposal.class);
+ protected final Logger logger = Logger.getLogger(XtextCompletionProposal.class);
+
+ private EObject model;
+ private AbstractElement abstractElement;
private String text;
private String description;
private Image image;
@@ -38,6 +43,9 @@ public class XtextCompletionProposal implements ICompletionProposal,
private String pluginIdentifier;
/**
+ * @param element
+ * the element for which this CompletionProposal is created for
+ * @param model the last semtantically complete object
* @param text
* the text value to be replaced/inserted
* @param label
@@ -52,12 +60,14 @@ public class XtextCompletionProposal implements ICompletionProposal,
* @param offset
* the offset of the text
*/
- public XtextCompletionProposal(String text, StyledString label,
+ public XtextCompletionProposal(AbstractElement element,EObject model,String text, StyledString label,
String description, String imageFilePath, String pluginIdentifier,
int offset) {
Assert.isNotNull(text, "parameter 'text' must not be null");
Assert.isNotNull(pluginIdentifier,
"pluginIdentifier 'text' must not be null");
+ this.abstractElement = element;
+ this.model = model;
this.text = text;
this.description = description;
this.offset = offset;
@@ -74,6 +84,45 @@ public class XtextCompletionProposal implements ICompletionProposal,
}
/**
+ *
+ * Getter for model property.
+ *
+ * @return the associated model object
+ */
+ public EObject getModel() {
+ return model;
+ }
+
+ /**
+ * Setter for model property.
+ *
+ * @param model to set
+ */
+ public void setModel(EObject model) {
+ this.model = model;
+ }
+
+
+ /**
+ * Getter for abstractElement property.
+ *
+ * @return the associated element
+ */
+ public AbstractElement getAbstractElement() {
+ return abstractElement;
+ }
+
+
+ /**
+ * Setter for abstractElement property.
+ * @param abstractElement to set
+ */
+ public void setAbstractElement(AbstractElement abstractElement) {
+ this.abstractElement = abstractElement;
+ }
+
+
+ /**
* Setter for the text to insert
*
* @param text
@@ -227,6 +276,11 @@ public class XtextCompletionProposal implements ICompletionProposal,
public Point getSelection(IDocument document) {
return new Point(offset + this.text.length(), 0);
}
+
+ @Override
+ public String toString() {
+ return "XtextCompletionPoposal[text='"+getText()+"']";
+ }
private void initializeImage(String imageName) {
Image newImage = JFaceResources.getImage(imageName);