Add initial TextMate scope selector parser

This commit is contained in:
Kevin Sawicki
2013-04-17 16:31:21 -07:00
parent ed9f46b39f
commit 3e5448b698
3 changed files with 132 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
TextMateScopeSelector = require 'text-mate-scope-selector'
describe "TextMateScopeSelector", ->
it "matches the asterix", ->
expect(new TextMateScopeSelector('*').matches(['a'])).toBeTruthy()
expect(new TextMateScopeSelector('*').matches(['b', 'c'])).toBeTruthy()
expect(new TextMateScopeSelector('a.*.c').matches(['a.b.c'])).toBeTruthy()
expect(new TextMateScopeSelector('a.*.c').matches(['a.b.c.d'])).toBeTruthy()
expect(new TextMateScopeSelector('a.*.c').matches(['a.b.d.c'])).toBeFalsy()
it "matches prefixes", ->
expect(new TextMateScopeSelector('a').matches(['a'])).toBeTruthy()
expect(new TextMateScopeSelector('a').matches(['a.b'])).toBeTruthy()
expect(new TextMateScopeSelector('a').matches(['abc'])).toBeFalsy()
it "matches alternation", ->
expect(new TextMateScopeSelector('a | b').matches(['b'])).toBeTruthy()
expect(new TextMateScopeSelector('a|b|c').matches(['c'])).toBeTruthy()
expect(new TextMateScopeSelector('a|b|c').matches(['d'])).toBeFalsy()
it "matches negation", ->
expect(new TextMateScopeSelector('a - c').matches(['a', 'b'])).toBeTruthy()
expect(new TextMateScopeSelector('a-b').matches(['a', 'b'])).toBeFalsy()
it "matches composites", ->
expect(new TextMateScopeSelector('a,b,c').matches(['b', 'c'])).toBeTruthy()
expect(new TextMateScopeSelector('a, b, c').matches(['d', 'e'])).toBeFalsy()
expect(new TextMateScopeSelector('a, b, c').matches(['d', 'c.e'])).toBeTruthy()
it "matches groups", ->
expect(new TextMateScopeSelector('(a,b) | (c, d)').matches(['a'])).toBeTruthy()
expect(new TextMateScopeSelector('(a,b) | (c, d)').matches(['b'])).toBeTruthy()
expect(new TextMateScopeSelector('(a,b) | (c, d)').matches(['c'])).toBeTruthy()
expect(new TextMateScopeSelector('(a,b) | (c, d)').matches(['d'])).toBeTruthy()
expect(new TextMateScopeSelector('(a,b) | (c, d)').matches(['e'])).toBeFalsy()

View File

@@ -0,0 +1,79 @@
start = _ match:(selector) _ {
return match;
}
segment
= _ segment:[a-zA-Z0-9]+ _ {
var segment = segment.join("");
return function(scope) {
return scope === segment;
};
}
/ _ scopeName:[\*] _ {
return function() {
return true;
};
}
scope
= first:segment others:("." segment)* {
return function(scopes) {
var segments = [first];
for (var i = 0; i < others.length; i++)
segments.push(others[i][1]);
for (var i = 0; i < scopes.length; i++) {
var scopeSegments = scopes[i].split(".");
if (scopeSegments.length < segments.length)
continue;
var allSegmentsMatch = true;
for (var j = 0; j < segments.length; j++)
if (!segments[j](scopeSegments[j])) {
allSegmentsMatch = false;
break;
}
if (allSegmentsMatch)
return true;
}
return false;
}
}
expression
= scope
/ "(" _ selector:selector _ ")" {
return selector;
}
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);
};
}
}
/ expression
selector
= left:composite _ "," _ right:selector {
return function(scopes) {
return left(scopes) || right(scopes);
};
}
/ composite
_
= [ \t]*

View File

@@ -0,0 +1,18 @@
PEG = require 'pegjs'
fsUtils = require 'fs-utils'
module.exports =
class TextMateScopeSelector
@parser: null
@createParser: ->
unless TextMateScopeSelector.parser?
patternPath = require.resolve('text-mate-scope-selector-pattern.pegjs')
TextMateScopeSelector.parser = PEG.buildParser(fsUtils.read(patternPath))
TextMateScopeSelector.parser
constructor: (@selector) ->
@matcher = TextMateScopeSelector.createParser().parse(@selector)
matches: (scopes) ->
@matcher(scopes)