mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-16 08:48:55 +00:00
[regionAccess] implemented regionsForFeatures()
Signed-off-by: Moritz Eysholdt <moritz.eysholdt@itemis.de>
This commit is contained in:
parent
303287508f
commit
fe2d242e2e
3 changed files with 139 additions and 18 deletions
|
@ -67,6 +67,8 @@ import org.eclipse.xtext.resource.XtextResource;
|
|||
*/
|
||||
public interface ITextRegionAccess {
|
||||
|
||||
List<ILineRegion> expandToLines(ITextSegment segment, int leadingLinesToAdd, int trailingLinesToAdd);
|
||||
|
||||
/**
|
||||
* @return the {@link RuleCall} or the assigned {@link Action} that led to the construction of this EObject. For the
|
||||
* model's root element, the {@link ParserRule} is returned.
|
||||
|
@ -78,6 +80,8 @@ public interface ITextRegionAccess {
|
|||
*/
|
||||
XtextResource getResource();
|
||||
|
||||
ITextRegionRewriter getRewriter();
|
||||
|
||||
/**
|
||||
* @return true, if one or more parse error occurred when parsing the document.
|
||||
*/
|
||||
|
@ -135,6 +139,10 @@ public interface ITextRegionAccess {
|
|||
*/
|
||||
IHiddenRegion leadingHiddenRegion(EObject owner);
|
||||
|
||||
ILineRegion lineForOffset(int offset);
|
||||
|
||||
ITextSegment regionForDocument();
|
||||
|
||||
/**
|
||||
* @return a text region that reaches from the beginning of its first semantic region to the end of its last
|
||||
* semantic region.
|
||||
|
@ -147,18 +155,29 @@ public interface ITextRegionAccess {
|
|||
*/
|
||||
ISemanticRegion regionForFeature(EObject owner, EStructuralFeature feature);
|
||||
|
||||
/**
|
||||
* no containment; returned order same as syntactic oder
|
||||
*/
|
||||
List<ISemanticRegion> regionsForFeatures(EObject owner, EStructuralFeature... features);
|
||||
|
||||
/**
|
||||
* @return the first {@link ISemanticRegion} that represent 'keyword' and directly belongs to the provided
|
||||
* 'EObject'. Keywords of child-EObjects are not considered. May be null.
|
||||
*/
|
||||
ISemanticRegion regionForKeyword(EObject owner, String keyword);
|
||||
|
||||
ITextSegment regionForOffset(int offset, int length);
|
||||
|
||||
IEObjectRegion regionForRootEObject();
|
||||
|
||||
/**
|
||||
* @return the first {@link ISemanticRegion} that represent a RuleCall to the provided AbstractRule and directly
|
||||
* belongs to the provided 'EObject'. RuleCalls of child-EObjects are not considered. May be null.
|
||||
*/
|
||||
ISemanticRegion regionForRuleCallTo(EObject owner, AbstractRule rule);
|
||||
|
||||
List<IEObjectRegion> regionsForAllEObjects();
|
||||
|
||||
/**
|
||||
* @return All {@link ISemanticRegion semantic regions} that represent one of the provided 'keyword's and directly
|
||||
* belong to the provided 'EObject'. Keywords of child-EObjects are not considered.
|
||||
|
@ -172,26 +191,12 @@ public interface ITextRegionAccess {
|
|||
*/
|
||||
List<ISemanticRegion> regionsForRuleCallsTo(EObject owner, AbstractRule... rule);
|
||||
|
||||
String textForOffset(int offset, int length);
|
||||
|
||||
/**
|
||||
* @return the {@link IHiddenRegion} that follows after the EObject's last {@link ISemanticRegion}.
|
||||
*
|
||||
* @see #leadingHiddenRegion(EObject)
|
||||
*/
|
||||
IHiddenRegion trailingHiddenRegion(EObject owner); // rename to nextHiddenRegion; do same with leading()
|
||||
|
||||
ITextRegionRewriter getRewriter();
|
||||
|
||||
IEObjectRegion regionForRootEObject();
|
||||
|
||||
ITextSegment regionForDocument();
|
||||
|
||||
ITextSegment regionForOffset(int offset, int length);
|
||||
|
||||
ILineRegion lineForOffset(int offset);
|
||||
|
||||
String textForOffset(int offset, int length);
|
||||
|
||||
List<ILineRegion> expandToLines(ITextSegment segment, int leadingLinesToAdd, int trailingLinesToAdd);
|
||||
|
||||
List<IEObjectRegion> regionsForAllEObjects();
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.util.Collections;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.emf.ecore.EAttribute;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
|
@ -31,6 +32,7 @@ import org.eclipse.xtext.formatting2.regionaccess.ISequentialRegion;
|
|||
import org.eclipse.xtext.formatting2.regionaccess.ITextRegionAccess;
|
||||
import org.eclipse.xtext.formatting2.regionaccess.ITextSegment;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
|
@ -154,8 +156,7 @@ public abstract class AbstractRegionAccess implements ITextRegionAccess {
|
|||
|
||||
@Override
|
||||
public ISemanticRegion regionForFeature(EObject owner, EStructuralFeature feat) {
|
||||
if (!(feat instanceof EAttribute) && !(feat instanceof EReference && !((EReference) feat).isContainment()))
|
||||
throw new IllegalStateException("Only EAttributes and CrossReferences allowed.");
|
||||
assertNoContainment(feat);
|
||||
AbstractEObjectRegion tokens = regionForEObject(owner);
|
||||
if (tokens == null)
|
||||
return null;
|
||||
|
@ -167,6 +168,31 @@ public abstract class AbstractRegionAccess implements ITextRegionAccess {
|
|||
return null;
|
||||
}
|
||||
|
||||
protected void assertNoContainment(EStructuralFeature feat) {
|
||||
if (!(feat instanceof EAttribute) && !(feat instanceof EReference && !((EReference) feat).isContainment()))
|
||||
throw new IllegalStateException("Only EAttributes and CrossReferences allowed.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ISemanticRegion> regionsForFeatures(EObject owner, EStructuralFeature... features) {
|
||||
Set<String> names = Sets.newHashSet();
|
||||
for (int i = 0; i < features.length; i++) {
|
||||
EStructuralFeature feat = features[i];
|
||||
assertNoContainment(feat);
|
||||
names.add(feat.getName());
|
||||
}
|
||||
AbstractEObjectRegion tokens = regionForEObject(owner);
|
||||
if (tokens == null)
|
||||
return null;
|
||||
List<ISemanticRegion> result = Lists.newArrayList();
|
||||
for (ISemanticRegion region : tokens.getSemanticLeafRegions()) {
|
||||
Assignment assignment = GrammarUtil.containingAssignment(region.getGrammarElement());
|
||||
if (assignment != null && names.contains(assignment.getFeature()))
|
||||
result.add(region);
|
||||
}
|
||||
return ImmutableList.copyOf(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ISemanticRegion regionForKeyword(EObject owner, String keyword) {
|
||||
AbstractEObjectRegion tokens = regionForEObject(owner);
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015 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.formatting2.regionaccess.internal
|
||||
|
||||
import com.google.inject.Inject
|
||||
import com.google.inject.Provider
|
||||
import org.eclipse.emf.ecore.EObject
|
||||
import org.eclipse.xtext.formatting2.regionaccess.ITextRegionAccess
|
||||
import org.eclipse.xtext.formatting2.regionaccess.TextRegionAccessBuilder
|
||||
import org.eclipse.xtext.formatting2.regionaccess.internal.regionaccesstestlanguage.Mixed
|
||||
import org.eclipse.xtext.formatting2.regionaccess.internal.regionaccesstestlanguage.Root
|
||||
import org.eclipse.xtext.junit4.InjectWith
|
||||
import org.eclipse.xtext.junit4.XtextRunner
|
||||
import org.eclipse.xtext.junit4.util.ParseHelper
|
||||
import org.eclipse.xtext.junit4.validation.ValidationTestHelper
|
||||
import org.eclipse.xtext.resource.XtextResource
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import static org.eclipse.xtext.formatting2.regionaccess.internal.regionaccesstestlanguage.RegionaccesstestlanguagePackage.Literals.*
|
||||
import static org.junit.Assert.*
|
||||
import org.eclipse.xtext.formatting2.regionaccess.internal.regionaccesstestlanguage.AssignedAction
|
||||
|
||||
/**
|
||||
* @author Moritz Eysholdt - Initial contribution and API
|
||||
*/
|
||||
@RunWith(XtextRunner)
|
||||
@InjectWith(RegionAccessTestLanguageInjectorProvider)
|
||||
class RegionAccessAccessTest {
|
||||
@Inject extension ParseHelper<Root> parseHelper
|
||||
@Inject Provider<TextRegionAccessBuilder> textRegionAccessBuilder
|
||||
@Inject extension ValidationTestHelper validationTestHelper
|
||||
|
||||
@Test def void regionForFeatureAttribute() {
|
||||
val mixed = '''6 (foo)'''.parseAs(Mixed)
|
||||
val access = mixed.toAccess
|
||||
val actual = access.regionForFeature(mixed, MIXED__NAME)
|
||||
assertEquals("foo", actual.text)
|
||||
}
|
||||
|
||||
@Test def void regionForFeatureCrossReference() {
|
||||
val mixed = '''6 (ref foo) action (foo) end'''.parseAs(AssignedAction)
|
||||
val access = mixed.toAccess
|
||||
val actual = access.regionForFeature(mixed.child, MIXED__REF)
|
||||
assertEquals("foo", actual.text)
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException) def void regionForFeatureContainmentReference() {
|
||||
val mixed = '''6 (foo) action'''.parseAs(AssignedAction)
|
||||
val access = mixed.toAccess
|
||||
val actual = access.regionForFeature(mixed, ASSIGNED_ACTION__CHILD)
|
||||
assertEquals("foo", actual.text)
|
||||
}
|
||||
|
||||
@Test def void regionsForFeaturesAttribute() {
|
||||
val mixed = '''6 (foo)'''.parseAs(Mixed)
|
||||
val access = mixed.toAccess
|
||||
val actual = access.regionsForFeatures(mixed, MIXED__NAME)
|
||||
assertEquals("foo", actual.map[text].join)
|
||||
}
|
||||
|
||||
@Test def void regionsForFeaturesCrossReference() {
|
||||
val mixed = '''6 (ref foo) action (foo) end'''.parseAs(AssignedAction)
|
||||
val access = mixed.toAccess
|
||||
val actual = access.regionsForFeatures(mixed.child, MIXED__REF)
|
||||
assertEquals("foo", actual.map[text].join)
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException) def void regionsForFeaturesContainmentReference() {
|
||||
val mixed = '''6 (foo) action'''.parseAs(AssignedAction)
|
||||
val access = mixed.toAccess
|
||||
val actual = access.regionsForFeatures(mixed, ASSIGNED_ACTION__CHILD)
|
||||
assertEquals("foo", actual.map[text].join)
|
||||
}
|
||||
|
||||
def private <T extends EObject> parseAs(CharSequence seq, Class<T> cls) {
|
||||
val result = seq.parse
|
||||
result.assertNoErrors
|
||||
return cls.cast(result)
|
||||
}
|
||||
|
||||
def private ITextRegionAccess toAccess(EObject obj) {
|
||||
return textRegionAccessBuilder.get.forNodeModel(obj.eResource as XtextResource).create
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue