aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormclay2008-11-09 16:18:16 (EST)
committersefftinge2008-11-09 16:18:16 (EST)
commit5e99a1ca7f3c64102c0c83ac25df7914b375302f (patch)
tree4cf9ab218f142ceb90a6062b88f7d601f61a0dca
parent0dcacba2b3c50df06b552d01fdc6314c698c72c6 (diff)
downloadorg.eclipse.xtext-5e99a1ca7f3c64102c0c83ac25df7914b375302f.zip
org.eclipse.xtext-5e99a1ca7f3c64102c0c83ac25df7914b375302f.tar.gz
org.eclipse.xtext-5e99a1ca7f3c64102c0c83ac25df7914b375302f.tar.bz2
fix: some NPE's
-rw-r--r--plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/AbstractProposalProvider.java100
-rw-r--r--plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/DefaultContentAssistProcessor.java41
-rw-r--r--plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/IProposalProvider.java3
-rw-r--r--plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/ProposalCandidateResolverSwitch.java5
-rw-r--r--plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/ProposalProviderInvokerSwitch.java25
-rw-r--r--plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/XtextCompletionProposal.java46
6 files changed, 122 insertions, 98 deletions
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 ec42692..609579e 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
@@ -24,8 +24,10 @@ import org.eclipse.xtext.ParserRule;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.crossref.ILinkingService;
import org.eclipse.xtext.parsetree.AbstractNode;
+import org.eclipse.xtext.parsetree.CompositeNode;
import org.eclipse.xtext.parsetree.LeafNode;
import org.eclipse.xtext.parsetree.NodeUtil;
+import org.eclipse.xtext.parsetree.ParseTreeUtil;
import org.eclipse.xtext.service.Inject;
import org.eclipse.xtext.util.Pair;
@@ -82,9 +84,10 @@ public abstract class AbstractProposalProvider implements IProposalProvider {
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, org.eclipse.jface.text.IDocument, int)
+ * @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, org.eclipse.xtext.parsetree.AbstractNode, org.eclipse.xtext.parsetree.LeafNode)
*/
public List<? extends ICompletionProposal> sortAndFilter(
List<? extends ICompletionProposal> completionProposalList, EObject model, String prefix,
@@ -173,10 +176,8 @@ public abstract class AbstractProposalProvider implements IProposalProvider {
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);
+ .getLinkCandidates(model, crossReference, prefix);
for (Pair<String, URI> candidate : candidates) {
completionProposalList.add(createCompletionProposal(crossReference, model, candidate.getFirstElement(),
offset));
@@ -201,85 +202,60 @@ public abstract class AbstractProposalProvider implements IProposalProvider {
* 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.
+ * trim matching <code>ICompletionProposal#displayString</code> with matching prefix values.
*
+ * @see #sortAndFilter(List, EObject, String, IDocument, int, AbstractNode, LeafNode)
*/
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;
+ List<? extends ICompletionProposal> completionProposalList, EObject model, String prefix,IDocument document, int offset) {
- Map<String, ICompletionProposal> displayString2ICompletionProposalMap = new HashMap<String, ICompletionProposal>();
+ Map<String, ICompletionProposal> displayString2ICompletionProposalMap = new HashMap<String, ICompletionProposal>();
+
+ for (Iterator<? extends ICompletionProposal> iterator = completionProposalList.iterator(); iterator.hasNext();) {
- for (Iterator<? extends ICompletionProposal> iterator = completionProposalList.iterator(); iterator
- .hasNext();) {
+ ICompletionProposal completionProposal = iterator.next();
+
+ // filter duplicate displayString
+ if (!displayString2ICompletionProposalMap.containsKey(completionProposal.getDisplayString())) {
- ICompletionProposal completionProposal = iterator.next();
+ displayString2ICompletionProposalMap.put(completionProposal.getDisplayString(), completionProposal);
+
+ if (model != null) {
+
+ CompositeNode parserNode = NodeUtil.getRootNode(model);
+
+ LeafNode currentLeafNode=ParseTreeUtil.getCurrentNodeByOffset(parserNode, offset);
- // 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) {
+ boolean isCursorAtTheEndOfTheLastElement = offset == (currentLeafNode.getOffset() + currentLeafNode.getLength());
+
+ if (isCursorAtTheEndOfTheLastElement && 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) {
+ EObject grammarElement = currentLeafNode.getGrammarElement();
+ // at the end of the last element we want to filter only the CompletionProposal for the same grammar element
+ if (((isCursorAtTheEndOfTheLastElement && abstractElement.equals(grammarElement))
+ || !isCursorAtTheEndOfTheLastElement) && !completionProposal.getDisplayString().startsWith(currentLeafNode.getText())) {
if (logger.isDebugEnabled()) {
logger.debug("filter completionProposal '" + completionProposal + "'");
}
iterator.remove();
}
- }
+ }
}
- else {
- if (logger.isDebugEnabled()) {
- logger.debug("filter duplicate completionProposal '" + completionProposal + "'");
- }
-
- iterator.remove();
+
+ }
+ else {
+ if (logger.isDebugEnabled()) {
+ logger.debug("filter duplicate completionProposal '" + completionProposal + "'");
}
+
+ iterator.remove();
}
}
+
return completionProposalList;
}
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 3a31dc3..5f7ba5e 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
@@ -82,37 +82,48 @@ public class DefaultContentAssistProcessor implements IContentAssistProcessor {
String prefix = null==currentLeafNode ? "" : currentLeafNode.getText();
+ EObject model = lastCompleteNode instanceof AbstractNode ? NodeUtil
+ .getNearestSemanticObject((AbstractNode) lastCompleteNode) : lastCompleteNode;
+
Set<AbstractElement> nextValidElementSet = new LinkedHashSet<AbstractElement>();
/**
- * in the case of a non linked crossreference we delegate to proposalProvider (again)
+ * in case of a crossreference which isnt linked already we evaluate it again and delegate to proposalProvider (again)
*/
if (lastCompleteNode.getGrammarElement() instanceof CrossReference && !isLinked(lastCompleteNode)) {
-
nextValidElementSet.add((AbstractElement) lastCompleteNode.getGrammarElement());
+ nextValidElementSet.addAll(ParseTreeUtil.getElementSetValidFromOffset(rootNode,lastCompleteNode, offset));
}
/**
- * in the case we are at the end of the completed previous element add for 'right-to-left' backtracking cases
+ * in case of 'at-the-end' of the previous,completed element we evaluate it again for 'right-to-left-backtracking' cases (e.g. for keyword 'kind' kind>|< |=cursorpos)
*/
else if (currentLeafNode==lastCompleteNode) {
+ nextValidElementSet = ParseTreeUtil.getElementSetValidFromOffset(rootNode,lastCompleteNode, offset);
nextValidElementSet.add((AbstractElement) lastCompleteNode.getGrammarElement());
+ } else {
+ nextValidElementSet = ParseTreeUtil.getElementSetValidFromOffset(rootNode,lastCompleteNode, offset);
}
- nextValidElementSet.addAll(ParseTreeUtil.getElementSetValidFromOffset(rootNode,lastCompleteNode, offset));
-
ProposalProviderInvokerSwitch proposalProviderInvokerSwitch = new ProposalProviderInvokerSwitch(
- lastCompleteNode, document, offset, prefix, proposalProvider);
+ model, document, offset, prefix, proposalProvider);
- for (List<EObject> resolvedElementOrRuleList : new ProposalCandidateResolverSwitch(nextValidElementSet)) {
+
+ try {
+ for (List<EObject> resolvedElementOrRuleList : new ProposalCandidateResolverSwitch(
+ nextValidElementSet)) {
- List<ICompletionProposal> collectedCompletionProposalList =
- proposalProviderInvokerSwitch.collectCompletionProposalList(resolvedElementOrRuleList);
-
- completionProposalList.addAll(collectedCompletionProposalList);
- }
+ List<ICompletionProposal> collectedCompletionProposalList = proposalProviderInvokerSwitch
+ .collectCompletionProposalList(resolvedElementOrRuleList);
- if (completionProposalList != null) {
- List<? extends ICompletionProposal> sortAndFilter = proposalProvider.sortAndFilter(completionProposalList,currentLeafNode,prefix,document,offset);
- completionProposals = sortAndFilter.toArray(new ICompletionProposal[] {});
+ completionProposalList.addAll(collectedCompletionProposalList);
+ }
+ if (completionProposalList != null) {
+ List<? extends ICompletionProposal> processedCompletionProposalList = proposalProvider
+ .sortAndFilter(completionProposalList, model, prefix, document, offset);
+ completionProposals = processedCompletionProposalList.toArray(new ICompletionProposal[] {});
+ }
+ }
+ catch (Exception e) {
+ e.printStackTrace();
}
}
}
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 88db9a5..c4d35f9 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,6 +71,9 @@ 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
+ * @param document - the IDocument instance used by the editor
+ * @param offset - an offset within the document for which completions should be computed
* @return the sorted and filtered <code>ICompletionProposal</code> list.
*
*/
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 b3e31ea..d309adf 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
@@ -27,8 +27,9 @@ import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.util.XtextSwitch;
/**
- * Represents a <b>Switch</b> for the Xtext model's inheritance hierarchy to resolve
- * potential completion proposal candidate's.
+ * Represents a <b>Switch</b> for the Xtext model's inheritance hierarchy to
+ * resolve (or flatten) 'container' level elements like <code>Group</code> or
+ * <code>Alternatives</code> to gather potential completion proposal candidates.
*
* It supports the call {@link #doSwitch(EObject) doSwitch(object)} instead of
* typical <code>if (x instanceof y)</code> code blocks.
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
index b12e918..ad32773 100644
--- 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
@@ -28,8 +28,6 @@ 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;
/**
@@ -53,7 +51,7 @@ public class ProposalProviderInvokerSwitch extends XtextSwitch<List<ICompletionP
private final IDocument document;
- private final AbstractNode currentLeafNode;
+ private final EObject model;
private final String prefix;
@@ -63,8 +61,7 @@ public class ProposalProviderInvokerSwitch extends XtextSwitch<List<ICompletionP
/**
*
- * @param currentLeafNode
- * the last node in the document
+ * @param model the most specific model element under the cursor.
* @param document
* the document itself
* @param offset
@@ -75,10 +72,10 @@ public class ProposalProviderInvokerSwitch extends XtextSwitch<List<ICompletionP
* @param proposalProvider
* the proposalProvider to callback and invoke
*/
- public ProposalProviderInvokerSwitch(AbstractNode currentLeafNode, IDocument document, int offset, String prefix,
+ public ProposalProviderInvokerSwitch(EObject model, IDocument document, int offset, String prefix,
IProposalProvider proposalProvider) {
super();
- this.currentLeafNode = currentLeafNode;
+ this.model = model;
this.document = document;
this.offset = offset;
this.prefix = prefix;
@@ -112,12 +109,9 @@ public class ProposalProviderInvokerSwitch extends XtextSwitch<List<ICompletionP
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);
+ Assignment.class, model==null? EObject.class : model.getClass(), String.class, document.getClass(), int.class);
Collection<? extends ICompletionProposal> assignmentProposalList = null == method ? null : invokeMethod(method,
proposalProvider, assignment, model, prefix, document, offset);
@@ -131,18 +125,13 @@ public class ProposalProviderInvokerSwitch extends XtextSwitch<List<ICompletionP
@Override
public List<ICompletionProposal> caseKeyword(Keyword keyword) {
- completionProposalList.addAll(proposalProvider.completeKeyword(keyword, currentLeafNode, prefix, document,
- offset));
+ completionProposalList.addAll(proposalProvider.completeKeyword(keyword, model, 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);
@@ -158,7 +147,7 @@ public class ProposalProviderInvokerSwitch extends XtextSwitch<List<ICompletionP
Method method = findMethod(proposalProvider.getClass(), "complete"
+ firstLetterCapitalized(typeRef.getAlias()) + firstLetterCapitalized(typeRef.getName()),
- RuleCall.class, model.getClass(), String.class, document.getClass(), int.class);
+ RuleCall.class, model==null? EObject.class : model.getClass(), String.class, document.getClass(), int.class);
Collection<? extends ICompletionProposal> proposalList = null == method ? null : invokeMethod(method,
proposalProvider, ruleCall, model, prefix, document, offset);
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 ffeef6d..5567aaa 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
@@ -17,6 +17,14 @@ import org.eclipse.jface.viewers.StyledString;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.xtext.AbstractElement;
+import org.eclipse.xtext.Assignment;
+import org.eclipse.xtext.CrossReference;
+import org.eclipse.xtext.GrammarUtil;
+import org.eclipse.xtext.RuleCall;
+import org.eclipse.xtext.parsetree.CompositeNode;
+import org.eclipse.xtext.parsetree.LeafNode;
+import org.eclipse.xtext.parsetree.NodeUtil;
+import org.eclipse.xtext.parsetree.ParseTreeUtil;
/**
* Default Xtext implementation of interface <code>ICompletionProposal</code>.
@@ -206,10 +214,46 @@ public class XtextCompletionProposal implements ICompletionProposal,
int offset) {
try {
+
IDocument document = viewer.getDocument();
+
+ if (model != null) {
+ CompositeNode parserNode = NodeUtil.getRootNode(model);
+
+ LeafNode currentLeafNode=ParseTreeUtil.getCurrentNodeByOffset(parserNode, offset);
+
+ boolean isCursorAtTheEndOfTheLastElement = offset == (currentLeafNode.getOffset() + currentLeafNode
+ .getLength());
+
+ if ((currentLeafNode.isHidden() && !"".equals(currentLeafNode.getText().trim()))
+ || isCursorAtTheEndOfTheLastElement) {
+ if (getDisplayString().startsWith(currentLeafNode.getText())) {
+ setText(getText().substring(currentLeafNode.getText().length()));
+ }
+ }
+
+ if (!currentLeafNode.isHidden() &&
+ isCursorAtTheEndOfTheLastElement &&
+ getDisplayString().equalsIgnoreCase(getText())) {
+ if (currentLeafNode.getGrammarElement() instanceof CrossReference
+ && abstractElement instanceof CrossReference) {
+ setText(" " + getText());
+ }
+ else if (currentLeafNode.getGrammarElement() instanceof RuleCall
+ && currentLeafNode.getGrammarElement().eContainer() instanceof Assignment
+ && abstractElement instanceof Assignment) {
+ setText(" " + getText());
+ }
+ else if (!GrammarUtil.containingParserRule(abstractElement).equals(GrammarUtil.containingParserRule(currentLeafNode.getGrammarElement()))) {
+ setText(" " + getText());
+ }
+
+ }
+ }
+
document.replace(this.offset, offset != this.offset ? offset
- - this.offset : 0, this.text);
+ - this.offset : 0, getText());
} catch (BadLocationException e) {
logger.error(e);