Use ScopeSelector class from first-mate

Begin migrating TextMate helpers out of src/ and into the first-mate
package.
This commit is contained in:
Kevin Sawicki
2013-08-12 16:22:18 -07:00
parent 0a53e2f7bb
commit 063d48c4ab
8 changed files with 7 additions and 298 deletions

View File

@@ -1,79 +0,0 @@
TextMateScopeSelector = require 'text-mate-scope-selector'
describe "TextMateScopeSelector", ->
describe ".matches(scopes)", ->
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.b').matches(['a.b.c'])).toBeTruthy()
expect(new TextMateScopeSelector('a').matches(['abc'])).toBeFalsy()
expect(new TextMateScopeSelector('a.b-c').matches(['a.b-c.d'])).toBeTruthy()
expect(new TextMateScopeSelector('a.b').matches(['a.b-d'])).toBeFalsy()
expect(new TextMateScopeSelector('c++').matches(['c++'])).toBeTruthy()
expect(new TextMateScopeSelector('c++').matches(['c'])).toBeFalsy()
expect(new TextMateScopeSelector('a_b_c').matches(['a_b_c'])).toBeTruthy()
expect(new TextMateScopeSelector('a_b_c').matches(['a_b'])).toBeFalsy()
it "matches filters", ->
expect(new TextMateScopeSelector('R:g').matches(['g'])).toBeTruthy()
it "matches disjunction", ->
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 - c').matches(['a'])).toBeTruthy()
expect(new TextMateScopeSelector('-c').matches(['b'])).toBeTruthy()
expect(new TextMateScopeSelector('-c').matches(['c', 'b'])).toBeFalsy()
expect(new TextMateScopeSelector('a-b').matches(['a', 'b'])).toBeFalsy()
expect(new TextMateScopeSelector('a -b').matches(['a', 'b'])).toBeFalsy()
expect(new TextMateScopeSelector('a -c').matches(['a', 'b'])).toBeTruthy()
expect(new TextMateScopeSelector('a-c').matches(['a', 'b'])).toBeFalsy()
it "matches conjunction", ->
expect(new TextMateScopeSelector('a & b').matches(['b', 'a'])).toBeTruthy()
expect(new TextMateScopeSelector('a&b&c').matches(['c'])).toBeFalsy()
expect(new TextMateScopeSelector('a&b&c').matches(['a', 'b', 'd'])).toBeFalsy()
expect(new TextMateScopeSelector('a & -b').matches(['a', 'b', 'd'])).toBeFalsy()
expect(new TextMateScopeSelector('a & -b').matches(['a', 'd'])).toBeTruthy()
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()
expect(new TextMateScopeSelector('a,').matches(['a', 'c'])).toBeTruthy()
expect(new TextMateScopeSelector('a,').matches(['b', 'c'])).toBeFalsy()
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()
it "matches paths", ->
expect(new TextMateScopeSelector('a b').matches(['a', 'b'])).toBeTruthy()
expect(new TextMateScopeSelector('a b').matches(['b', 'a'])).toBeFalsy()
expect(new TextMateScopeSelector('a c').matches(['a', 'b', 'c', 'd', 'e'])).toBeTruthy()
expect(new TextMateScopeSelector('a b e').matches(['a', 'b', 'c', 'd', 'e'])).toBeTruthy()
describe ".toCssSelector()", ->
it "converts the TextMate scope selector to a CSS selector", ->
expect(new TextMateScopeSelector('a b c').toCssSelector()).toBe '.a .b .c'
expect(new TextMateScopeSelector('a.b.c').toCssSelector()).toBe '.a.b.c'
expect(new TextMateScopeSelector('*').toCssSelector()).toBe '*'
expect(new TextMateScopeSelector('a - b').toCssSelector()).toBe '.a:not(.b)'
expect(new TextMateScopeSelector('a & b').toCssSelector()).toBe '.a .b'
expect(new TextMateScopeSelector('a & -b').toCssSelector()).toBe '.a:not(.b)'
expect(new TextMateScopeSelector('a | b').toCssSelector()).toBe '.a, .b'
expect(new TextMateScopeSelector('a - (b.c d)').toCssSelector()).toBe '.a:not(.b.c .d)'
expect(new TextMateScopeSelector('a, b').toCssSelector()).toBe '.a, .b'

View File

@@ -11,7 +11,7 @@ Selection = require 'selection'
EventEmitter = require 'event-emitter'
Subscriber = require 'subscriber'
Range = require 'range'
TextMateScopeSelector = require 'text-mate-scope-selector'
TextMateScopeSelector = require('first-mate').ScopeSelector
# An `EditSession` manages the states between {Editor}s, {Buffer}s, and the project as a whole.
module.exports =

View File

@@ -5,7 +5,7 @@ Specificity = require 'specificity'
fsUtils = require 'fs-utils'
EventEmitter = require 'event-emitter'
NullGrammar = require 'null-grammar'
TextMateScopeSelector = require 'text-mate-scope-selector'
TextMateScopeSelector = require('first-mate').ScopeSelector
### Internal ###

View File

@@ -5,7 +5,7 @@ Token = require 'token'
{OnigRegExp, OnigScanner} = require 'oniguruma'
path = require 'path'
EventEmitter = require 'event-emitter'
TextMateScopeSelector = require 'text-mate-scope-selector'
{ScopeSelector} = require 'first-mate'
pathSplitRegex = new RegExp("[#{path.sep}.]")
@@ -40,7 +40,7 @@ class TextMateGrammar
@injections = new Injections(this, injections)
if injectionSelector?
@injectionSelector = new TextMateScopeSelector(injectionSelector)
@injectionSelector = new ScopeSelector(injectionSelector)
@firstLineRegex = new OnigRegExp(firstLineMatch) if firstLineMatch
@fileTypes ?= []
@@ -197,7 +197,7 @@ class Injections
patterns.push(pattern.getIncludedPatterns(grammar, patterns)...)
@injections.push
anchored: anchored
selector: new TextMateScopeSelector(selector)
selector: new ScopeSelector(selector)
patterns: patterns
getScanner: (injection, firstLine, position, anchorPosition) ->

View File

@@ -1,101 +0,0 @@
_ = require 'underscore'
### Internal ###
class SegmentMatcher
constructor: (segment) ->
@segment = _.flatten(segment).join('')
matches: (scope) -> scope is @segment
toCssSelector: ->
@segment.split('.').map((dotFragment) ->
'.' + dotFragment.replace(/\+/g, '\\+')
).join('')
class TrueMatcher
constructor: ->
matches: -> true
toCssSelector: -> '*'
class ScopeMatcher
constructor: (first, others) ->
@segments = [first]
@segments.push(segment[1]) for segment in others
matches: (scope) ->
scopeSegments = scope.split('.')
return false if scopeSegments.length < @segments.length
for segment, index in @segments
return false unless segment.matches(scopeSegments[index])
true
toCssSelector: ->
@segments.map((matcher) -> matcher.toCssSelector()).join('')
class PathMatcher
constructor: (first, others) ->
@matchers = [first]
@matchers.push(matcher[1]) for matcher in others
matches: (scopes) ->
index = 0
matcher = @matchers[index]
for scope in scopes
matcher = @matchers[++index] if matcher.matches(scope)
return true unless matcher?
false
toCssSelector: ->
@matchers.map((matcher) -> matcher.toCssSelector()).join(' ')
class OrMatcher
constructor: (@left, @right) ->
matches: (scopes) -> @left.matches(scopes) or @right.matches(scopes)
toCssSelector: -> "#{@left.toCssSelector()}, #{@right.toCssSelector()}"
class AndMatcher
constructor: (@left, @right) ->
matches: (scopes) -> @left.matches(scopes) and @right.matches(scopes)
toCssSelector: ->
if @right instanceof NegateMatcher
"#{@left.toCssSelector()}#{@right.toCssSelector()}"
else
"#{@left.toCssSelector()} #{@right.toCssSelector()}"
class NegateMatcher
constructor: (@matcher) ->
matches: (scopes) -> not @matcher.matches(scopes)
toCssSelector: -> ":not(#{@matcher.toCssSelector()})"
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 AndMatcher(left, new NegateMatcher(right))
matches: (scopes) -> @matcher.matches(scopes)
toCssSelector: -> @matcher.toCssSelector()
module.exports = {
AndMatcher
CompositeMatcher
NegateMatcher
OrMatcher
PathMatcher
ScopeMatcher
SegmentMatcher
TrueMatcher
}

View File

@@ -1,79 +0,0 @@
{
var matchers = require('text-mate-scope-selector-matchers');
}
start = _ selector:(selector) _ {
return selector;
}
segment
= _ segment:([a-zA-Z0-9+_]+[a-zA-Z0-9-+_]*) _ {
return new matchers.SegmentMatcher(segment);
}
/ _ scopeName:[\*] _ {
return new matchers.TrueMatcher();
}
scope
= first:segment others:("." segment)* {
return new matchers.ScopeMatcher(first, others);
}
path
= first:scope others:(_ scope)* {
return new matchers.PathMatcher(first, others);
}
group
= "(" _ selector:selector _ ")" {
return selector;
}
filter
= prefix:([LRB]":") _ group:group {
return group;
}
/ prefix:([LRB]":") _ path:path {
return path;
}
expression
= "-" _ filter:filter _ {
return new matchers.NegateMatcher(filter);
}
/ "-" _ group:group _ {
return new matchers.NegateMatcher(group);
}
/ "-" _ path:path _ {
return new matchers.NegateMatcher(path);
}
/ filter
/ group
/ path
composite
= left:expression _ operator:[|&-] _ right:composite {
return new matchers.CompositeMatcher(left, operator, right);
}
/ expression
selector
= left:composite _ "," _ right:selector? {
if (right)
return new matchers.OrMatcher(left, right);
else
return left;
}
/ composite
_
= [ \t]*

View File

@@ -1,32 +0,0 @@
PEG = require 'pegjs'
fsUtils = require 'fs-utils'
# Internal: Test a stack of scopes to see if they match a scope selector.
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
source: null
matcher: null
# Create a new scope selector.
#
# source - A {String} to parse as a scope selector.
constructor: (@source) ->
@matcher = TextMateScopeSelector.createParser().parse(@source)
# Check if this scope selector matches the scopes.
#
# scopes - An {Array} of {String}s.
#
# Return a {Boolean}.
matches: (scopes) ->
@matcher.matches(scopes)
toCssSelector: -> @matcher.toCssSelector()

View File

@@ -8,8 +8,8 @@ module.exports =
return unless token?
unless @selector?
TextMateScopeSelector = require 'text-mate-scope-selector'
@selector = new TextMateScopeSelector('markup.underline.link')
{ScopeSelector} = require 'first-mate'
@selector = new ScopeSelector('markup.underline.link')
if @selector.matches(token.scopes)
require('shell').openExternal token.value