Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixes for issues #264 and #265 #266

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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')?;
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <C> 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 extends EObject> C goUpTo(EObject from, java.lang.Class<C> type) {
EObject parent = from;
while (parent != null) {
if (type.isInstance(parent)) {
return (C) parent;
}
parent = parent.eContainer();
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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";
Expand All @@ -52,6 +56,9 @@ public class LessScopeProvider extends AbstractDeclarativeScopeProvider {

@Inject
private LessMixinScopeProvider mixinScopeProvider;

@Inject
private LessMixinLinkingService mixinLinkingService;

private Iterable<EObject> getStyleSheetStatements(StyleSheet styleSheet) {
return styleSheet.eContents();
Expand Down Expand Up @@ -156,10 +163,15 @@ private void addVariableDefinitions(Iterable<? extends EObject> 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<IEObjectDescription> variableDefinitions) {
Expand All @@ -169,7 +181,43 @@ private void addVariableDefinitions(Mixin mixinDefinition, List<IEObjectDescript
}
variableDefinitions.add(EObjectDescription.create(QualifiedName.create(ARGUMENTS_VARIABLE_NAME), mixinDefinition));
}


/**
* In newer LESS versrions (since 1.4) it's possible to use a mixin as a
* function call (see
* http://lesscss.org/features/#mixins-as-functions-feature): the variables
* defined inside the mixin body are accessible in a calling mixin. So we
* add these variables for a Mixin call.
*
* @param mixinStatement
* the statement which calls a Mixin
* @param variableDefinitions
* the list of variable definitions which should be used to add
* the direct variables of called Mixin
*/
private void addVariablesDefinitionsOfCalledMixin(Mixin mixinStatement, List<IEObjectDescription> 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) {
Expand Down Expand Up @@ -201,5 +249,4 @@ IScope scope_HashOrClassRefTarget(EObject context, EReference ref) {
MixinScope scope = mixinScopeProvider.getScope(mixinContext.getMixin());
return scope.getScope(mixinContext.getSelectorIndex());
}

}