| author | szarnekow | 2009-03-26 10:03:38 (EDT) |
|---|---|---|
| committer | sefftinge | 2009-03-26 10:03:38 (EDT) |
| commit | 79db19ed047eb23a0acdc1095d809f6f3b75fdb0 (patch) (side-by-side diff) | |
| tree | 9f3f96aff521ecefadb8b1aefcb6ec4c89ac6284 | |
| parent | 4001dad8f9be884228242c6edcda2c03526604a3 (diff) | |
| download | org.eclipse.xtext-79db19ed047eb23a0acdc1095d809f6f3b75fdb0.zip org.eclipse.xtext-79db19ed047eb23a0acdc1095d809f6f3b75fdb0.tar.gz org.eclipse.xtext-79db19ed047eb23a0acdc1095d809f6f3b75fdb0.tar.bz2 | |
improvements to DefaultLocationInFileProvider, introduce XtextLocationInFileProvider
| -rw-r--r-- | plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/DefaultLocationInFileProvider.java | 134 |
1 files changed, 104 insertions, 30 deletions
diff --git a/plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/DefaultLocationInFileProvider.java b/plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/DefaultLocationInFileProvider.java index 1fbf245..086a14f 100644 --- a/plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/DefaultLocationInFileProvider.java +++ b/plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/DefaultLocationInFileProvider.java @@ -9,18 +9,22 @@ package org.eclipse.xtext.ui.core; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.jface.text.Region; import org.eclipse.xtext.Keyword; import org.eclipse.xtext.RuleCall; import org.eclipse.xtext.parsetree.AbstractNode; import org.eclipse.xtext.parsetree.CompositeNode; +import org.eclipse.xtext.parsetree.LeafNode; import org.eclipse.xtext.parsetree.NodeAdapter; import org.eclipse.xtext.parsetree.NodeUtil; - +import org.eclipse.xtext.parsetree.util.ParsetreeSwitch; /** * @author Peter Friese - Implementation @@ -29,50 +33,120 @@ import org.eclipse.xtext.parsetree.NodeUtil; public class DefaultLocationInFileProvider implements ILocationInFileProvider { public Region getLocation(EObject obj) { - NodeAdapter adapter = NodeUtil.getNodeAdapter(obj); - if (adapter == null) - return new Region(0,0); - - CompositeNode startNode = adapter.getParserNode(); - EList<AbstractNode> leafNodes = startNode.getChildren(); + final NodeAdapter adapter = NodeUtil.getNodeAdapter(obj); + if (adapter == null) { + if (obj.eContainer() == null) + return new Region(0, 0); + return getLocation(obj.eContainer()); + } + + List<AbstractNode> nodes = getLocationNodes(obj); + if (nodes == null || nodes.isEmpty()) + nodes = Collections.<AbstractNode> singletonList(adapter.getParserNode()); + + return createRegion(nodes); + } + + protected List<AbstractNode> getLocationNodes(EObject obj) { + final EStructuralFeature nameFeature = getIdentifierFeature(obj); + if (nameFeature != null) + return NodeUtil.findNodesForFeature(obj, nameFeature); + + List<AbstractNode> resultNodes = new ArrayList<AbstractNode>(); + final NodeAdapter adapter = NodeUtil.getNodeAdapter(obj); + final CompositeNode startNode = adapter.getParserNode(); AbstractNode keywordNode = null; - List<AbstractNode> idNodes = null; - for (AbstractNode leafNode : leafNodes) { - EObject grammarElement = leafNode.getGrammarElement(); + // use LeafNodes instead of children? + EList<AbstractNode> children = startNode.getChildren(); + for (AbstractNode child : children) { + EObject grammarElement = child.getGrammarElement(); if (grammarElement instanceof RuleCall) { RuleCall ruleCall = (RuleCall) grammarElement; String ruleName = ruleCall.getRule().getName(); - - // TODO usually we use the name feature if the instead of the id call - // LeafNode.getFeature() if (ruleName.equals("ID")) { - if (idNodes == null) { - idNodes = new ArrayList<AbstractNode>(); - } - idNodes.add(leafNode); + resultNodes.add(child); } } else if (grammarElement instanceof Keyword) { - if (keywordNode == null) { - keywordNode = leafNode; + // TODO use only keywords, that aren't symbols like '=' ? + if (keywordNode == null && useKeyword((Keyword) grammarElement, obj)) { + keywordNode = child; } } } + if (resultNodes.isEmpty() && keywordNode != null) + resultNodes.add(keywordNode); + return resultNodes; + } + + protected boolean useKeyword(Keyword keyword, EObject context) { + return true; + } + + protected EStructuralFeature getIdentifierFeature(EObject obj) { + final EClass eClass = obj.eClass(); + final EStructuralFeature result = eClass.getEStructuralFeature("name"); + return result != null ? result : eClass.getEStructuralFeature("id"); + } - if (idNodes != null) { - // if we've got more than one ID elements, we want to select - // them all - AbstractNode firstIdNode = idNodes.get(0); - AbstractNode lastIdNode = idNodes.get(idNodes.size() - 1); - int length = (lastIdNode.getOffset() - firstIdNode.getOffset()) + lastIdNode.getLength(); - return new Region(firstIdNode.getOffset(), length); + protected static class OffsetCalculator extends ParsetreeSwitch<LeafNode> { + + private boolean forward = true; + + @Override + public LeafNode caseCompositeNode(CompositeNode object) { + return handleImpl(object.getChildren()); } - else if (keywordNode != null) { - return new Region(keywordNode.getOffset(), keywordNode.getLength()); + + public AbstractNode handle(List<AbstractNode> nodes, boolean forward) { + this.forward = forward; + AbstractNode result = handleImpl(nodes); + if (result == null) { + if (forward) + result = nodes.get(0); + else + result = nodes.get(nodes.size()-1); + } + return result; + } + + public LeafNode handleImpl(List<AbstractNode> nodes) { + if(forward) { + for (AbstractNode node: nodes) { + LeafNode result = doSwitch(node); + if (result != null) + return result; + } + } else { + for(int i = nodes.size() - 1; i >= 0; i--) { + AbstractNode node = nodes.get(i); + LeafNode result = doSwitch(node); + if (result != null) + return result; + } + } + return null; } - else { - return new Region(startNode.getOffset(), startNode.getLength()); + + @Override + public LeafNode caseLeafNode(LeafNode object) { + if (!object.isHidden()) + return object; + return null; } } + protected Region createRegion(final List<AbstractNode> nodes) { + // if we've got more than one ID elements, we want to select them all + OffsetCalculator calculator = createCalculator(); + AbstractNode firstNode = calculator.handle(nodes, true); + AbstractNode lastNode = calculator.handle(nodes, false); + int length = (lastNode.getOffset() - firstNode.getOffset()) + lastNode.getLength(); + return new Region(firstNode.getOffset(), length); + } + + protected OffsetCalculator createCalculator() { + return new OffsetCalculator(); + } + } |

