diff --git a/src/eclipse/net.vtst.ow.eclipse.less/src/net/vtst/ow/eclipse/less/Less.xtext b/src/eclipse/net.vtst.ow.eclipse.less/src/net/vtst/ow/eclipse/less/Less.xtext index 2cf1fb1..efbc1b2 100644 --- a/src/eclipse/net.vtst.ow.eclipse.less/src/net/vtst/ow/eclipse/less/Less.xtext +++ b/src/eclipse/net.vtst.ow.eclipse.less/src/net/vtst/ow/eclipse/less/Less.xtext @@ -540,7 +540,9 @@ terminal fragment STRING2: '\'' (!('\n' | '\r' /*| '\f'*/ | '\\' | '\'') | '\\' terminal STRING : STRING1 | STRING2; terminal JS_EVALUATION : '`' (!'`')* '`'; -terminal HASH_IDENT : '#' IDENT_CHAR+; +// ori: terminal HASH_IDENT : '#' IDENT_CHAR+; +// in CSS identifiers are allowed to contain colons; a colon has to be escaped as '\:' +terminal HASH_IDENT : '#' (IDENT_CHAR | '\\:')+; terminal NUMBER : (('0' .. '9')* '.')? ('0' .. '9')+; terminal ML_COMMENT : '/*' -> '*/'; terminal SL_COMMENT : '//' !('\n'|'\r')* ('\r'? '\n')?; diff --git a/src/eclipse/net.vtst.ow.eclipse.less/src/net/vtst/ow/eclipse/less/ModelUtils.java b/src/eclipse/net.vtst.ow.eclipse.less/src/net/vtst/ow/eclipse/less/ModelUtils.java new file mode 100644 index 0000000..e3cc573 --- /dev/null +++ b/src/eclipse/net.vtst.ow.eclipse.less/src/net/vtst/ow/eclipse/less/ModelUtils.java @@ -0,0 +1,26 @@ +package net.vtst.ow.eclipse.less; + +import org.eclipse.emf.ecore.EObject; + +public class ModelUtils { + + /** + * Searches the object's parent hierarchy for an object of given type. + * + * @param the type of the EObject which is searched + * @param from the starting point + * @param type the type of the EObject which is searched + * @return the parent or grand parent or... of the given object which has the specified type + */ + @SuppressWarnings("unchecked") + public static C goUpTo(EObject from, java.lang.Class type) { + EObject parent = from; + while (parent != null) { + if (type.isInstance(parent)) { + return (C) parent; + } + parent = parent.eContainer(); + } + return null; + } +} diff --git a/src/eclipse/net.vtst.ow.eclipse.less/src/net/vtst/ow/eclipse/less/scoping/LessScopeProvider.java b/src/eclipse/net.vtst.ow.eclipse.less/src/net/vtst/ow/eclipse/less/scoping/LessScopeProvider.java index d972f7d..d6f3ebb 100644 --- a/src/eclipse/net.vtst.ow.eclipse.less/src/net/vtst/ow/eclipse/less/scoping/LessScopeProvider.java +++ b/src/eclipse/net.vtst.ow.eclipse.less/src/net/vtst/ow/eclipse/less/scoping/LessScopeProvider.java @@ -6,18 +6,6 @@ import java.util.ArrayList; import java.util.List; -import net.vtst.ow.eclipse.less.less.AtVariableDef; -import net.vtst.ow.eclipse.less.less.AtVariableRefTarget; -import net.vtst.ow.eclipse.less.less.Block; -import net.vtst.ow.eclipse.less.less.ImportStatement; -import net.vtst.ow.eclipse.less.less.LessPackage; -import net.vtst.ow.eclipse.less.less.Mixin; -import net.vtst.ow.eclipse.less.less.MixinParameter; -import net.vtst.ow.eclipse.less.less.MixinUtils; -import net.vtst.ow.eclipse.less.less.StyleSheet; -import net.vtst.ow.eclipse.less.less.VariableDefinition; -import net.vtst.ow.eclipse.less.scoping.LessImportStatementResolver.ResolvedImportStatement; - import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; @@ -35,6 +23,22 @@ import com.google.inject.Inject; import com.google.inject.Provider; +import net.vtst.ow.eclipse.less.ModelUtils; +import net.vtst.ow.eclipse.less.less.AtVariableDef; +import net.vtst.ow.eclipse.less.less.AtVariableRefTarget; +import net.vtst.ow.eclipse.less.less.Block; +import net.vtst.ow.eclipse.less.less.HashOrClassRef; +import net.vtst.ow.eclipse.less.less.ImportStatement; +import net.vtst.ow.eclipse.less.less.LessPackage; +import net.vtst.ow.eclipse.less.less.Mixin; +import net.vtst.ow.eclipse.less.less.MixinParameter; +import net.vtst.ow.eclipse.less.less.MixinUtils; +import net.vtst.ow.eclipse.less.less.StyleSheet; +import net.vtst.ow.eclipse.less.less.VariableDefinition; +import net.vtst.ow.eclipse.less.linking.LessMixinLinkingService; +import net.vtst.ow.eclipse.less.linking.LessMixinLinkingService.MixinLink; +import net.vtst.ow.eclipse.less.scoping.LessImportStatementResolver.ResolvedImportStatement; + public class LessScopeProvider extends AbstractDeclarativeScopeProvider { private static final String ARGUMENTS_VARIABLE_NAME = "@arguments"; @@ -52,6 +56,9 @@ public class LessScopeProvider extends AbstractDeclarativeScopeProvider { @Inject private LessMixinScopeProvider mixinScopeProvider; + + @Inject + private LessMixinLinkingService mixinLinkingService; private Iterable getStyleSheetStatements(StyleSheet styleSheet) { return styleSheet.eContents(); @@ -156,10 +163,15 @@ private void addVariableDefinitions(Iterable statements, List // There is no cycle, and the imported stylesheet is not null. addVariableDefinitions(resolvedImportStatement.getImportedStyleSheet().getStatements(), variableDefinitions); } + // fix BEGIN + // MixinUtils.isCall((Mixin)statement) should be redundant, but we do it to be sure + } else if (statement instanceof Mixin && MixinUtils.isCall((Mixin)statement)) { + addVariablesDefinitionsOfCalledMixin((Mixin)statement, variableDefinitions); } - } + // fix END + } } - + /** Add the variables defined by a mixin. */ private void addVariableDefinitions(Mixin mixinDefinition, List variableDefinitions) { @@ -169,7 +181,43 @@ private void addVariableDefinitions(Mixin mixinDefinition, List variableDefinitions) { + MixinLink linkedMixin = mixinLinkingService.getLinkedMixin(mixinStatement); + if (linkedMixin.isSuccess() && linkedMixin.getElement().size() > 0) { + EObject object = linkedMixin.getElement().getObject(0); + if (object instanceof HashOrClassRef) { + HashOrClassRef hashOrClassRef = (HashOrClassRef) object; + Mixin referencedMixin = ModelUtils.goUpTo(hashOrClassRef, Mixin.class); + if (referencedMixin != null) { + if (referencedMixin.getBody() != null && referencedMixin.getBody().getContent() != null) { + // we don't call addVariableDefinitions() recursivley because variables of called + // mixins aren't visible recursivly in calling scope. The direct variables of + // called mixins are visible only. + for (EObject innerStatement : referencedMixin.getBody().getContent().getStatement()) { + if (innerStatement instanceof VariableDefinition) { + variableDefinitions.add(getEObjectDescriptionFor(((VariableDefinition) innerStatement).getLhs().getVariable())); + } + } + } + } + } + } + } + /** Create the object description for a variable definition ident. */ private IEObjectDescription getEObjectDescriptionFor(AtVariableRefTarget atVariable) { @@ -201,5 +249,4 @@ IScope scope_HashOrClassRefTarget(EObject context, EReference ref) { MixinScope scope = mixinScopeProvider.getScope(mixinContext.getMixin()); return scope.getScope(mixinContext.getSelectorIndex()); } - } \ No newline at end of file