mirror of
https://github.com/atom/atom.git
synced 2026-04-06 03:02:13 -04:00
Add initial TextMate scope selector parser
This commit is contained in:
35
spec/app/text-mate-scope-selector-spec.coffee
Normal file
35
spec/app/text-mate-scope-selector-spec.coffee
Normal 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()
|
||||
79
src/app/text-mate-scope-selector-pattern.pegjs
Normal file
79
src/app/text-mate-scope-selector-pattern.pegjs
Normal 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]*
|
||||
18
src/app/text-mate-scope-selector.coffee
Normal file
18
src/app/text-mate-scope-selector.coffee
Normal 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)
|
||||
Reference in New Issue
Block a user