diff --git a/src/app/text-mate-scope-selector-matchers.coffee b/src/app/text-mate-scope-selector-matchers.coffee new file mode 100644 index 000000000..66b51a8d4 --- /dev/null +++ b/src/app/text-mate-scope-selector-matchers.coffee @@ -0,0 +1,78 @@ +class SegmentMatcher + constructor: (segment) -> + @segment = segment.join('') + + matches: (scope) -> + scope is @segment + +class AsterixMatcher + constructor: -> + + matches: -> + true + +class ScopeMatcher + constructor: (first, others) -> + @segments = [first] + @segments.push(segment[1]) for segment in others + + matches: (scope) -> + scopeSegments = scope.split('.') + if scopeSegments.length < @segments.length + return false + + for segment, index in @segments + unless segment.matches(scopeSegments[index]) + return false + true + +class PathMatcher + constructor: (first, others) -> + @matchers = [first] + @matchers.push(matcher[1]) for matcher in others + + matches: (scopes) -> + matcher = @matchers.shift() + for scope in scopes + matcher = @matchers.shift() if matcher.matches(scope) + return true unless matcher? + false + +class OrMatcher + constructor: (@left, @right) -> + + matches: (scopes) -> + @left.matches(scopes) or @right.matches(scopes) + +class AndMatcher + constructor: (@left, @right) -> + + matches: (scopes) -> + @left.matches(scopes) and @right.matches(scopes) + +class NegateMatcher + constructor: (@left, @right) -> + + matches: (scopes) -> + @left.matches(scopes) and not @right.matches(scopes) + +class CompositeMatcher + constructor: (left, operator, right) -> + switch operator + when '|' then @matcher = new OrMatcher(left, right) + when '&' then @matcher = new AndMatcher(left, right) + when '-' then @matcher = new NegateMatcher(left, right) + + matches: (scopes) -> + @matcher.matches(scopes) + +module.exports = { + AndMatcher + AsterixMatcher + CompositeMatcher + NegateMatcher + OrMatcher + PathMatcher + ScopeMatcher + SegmentMatcher +} diff --git a/src/app/text-mate-scope-selector-pattern.pegjs b/src/app/text-mate-scope-selector-pattern.pegjs index e538cfda0..724e7842f 100644 --- a/src/app/text-mate-scope-selector-pattern.pegjs +++ b/src/app/text-mate-scope-selector-pattern.pegjs @@ -1,55 +1,28 @@ -start = _ match:(selector) _ { - return match; +{ + var matchers = require('text-mate-scope-selector-matchers'); +} + +start = _ selector:(selector) _ { + return selector; } segment = _ segment:[a-zA-Z0-9]+ _ { - var segment = segment.join(""); - return function(scope) { - return scope === segment; - }; + return new matchers.SegmentMatcher(segment); } / _ scopeName:[\*] _ { - return function() { - return true; - }; + return new matchers.AsterixMatcher(); } scope = first:segment others:("." segment)* { - return function(scope) { - var segments = [first]; - for (var i = 0; i < others.length; i++) - segments.push(others[i][1]); - - var scopeSegments = scope.split("."); - if (scopeSegments.length < segments.length) - return false; - - for (var i = 0; i < segments.length; i++) - if (!segments[i](scopeSegments[i])) - return false; - return true; - } + return new matchers.ScopeMatcher(first, others); } path = first:scope others:(_ scope)* { - return function(scopes) { - var scopeMatchers = [first]; - for (var i = 0; i < others.length; i++) - scopeMatchers.push(others[i][1]); - - var matcher = scopeMatchers.shift(); - for (var i = 0; i < scopes.length; i++) { - if (matcher(scopes[i])) - matcher = scopeMatchers.shift(); - if (!matcher) - return true; - } - return false; - } + return new matchers.PathMatcher(first, others); } expression @@ -61,30 +34,15 @@ expression composite = left:expression _ operator:[|&-] _ right:composite { - switch(operator) { - case "|": - return function(scopes) { - return left(scopes) || right(scopes); - }; - case "&": - return function(scopes) { - return left(scopes) && right(scopes); - }; - case "-": - return function(scopes) { - return left(scopes) && !right(scopes); - }; - } - } + return new matchers.CompositeMatcher(left, operator, right); + } / expression selector = left:composite _ "," _ right:selector { - return function(scopes) { - return left(scopes) || right(scopes); - }; - } + return new matchers.OrMatcher(left, right); + } / composite diff --git a/src/app/text-mate-scope-selector.coffee b/src/app/text-mate-scope-selector.coffee index 30ae1ac96..5b5ca7899 100644 --- a/src/app/text-mate-scope-selector.coffee +++ b/src/app/text-mate-scope-selector.coffee @@ -15,4 +15,4 @@ class TextMateScopeSelector @matcher = TextMateScopeSelector.createParser().parse(@selector) matches: (scopes) -> - @matcher(scopes) + @matcher.matches(scopes)