Support grammars with an injectionSelector

These grammars can now contribute rules to other grammars when
their selector matches the current scope stack.
This commit is contained in:
Kevin Sawicki 2013-04-22 12:56:17 -07:00
parent 927e9c3de8
commit f0cf337857
2 changed files with 35 additions and 14 deletions

View File

@ -433,3 +433,14 @@ describe "TextMateGrammar", ->
grammar = syntax.grammarForScopeName("text.hyperlink")
{tokens} = grammar.tokenizeLine("https://github.com")
expect(tokens[0].scopes).toEqual ["text.hyperlink", "markup.underline.link.https.hyperlink"]
describe "when the grammar has an injection selector", ->
it "includes the grammar's patterns when the selector matches the current scope in other grammars", ->
grammar = syntax.selectGrammar("text.js")
{tokens} = grammar.tokenizeLine("var i; // http://github.com")
expect(tokens[0].value).toBe "var";
expect(tokens[0].scopes).toEqual ["source.js", "storage.modifier.js"]
expect(tokens[6].value).toBe "http://github.com"
expect(tokens[6].scopes).toEqual ["source.js", "comment.line.double-slash.js", "markup.underline.link.http.hyperlink"]

View File

@ -27,6 +27,8 @@ class TextMateGrammar
@loadSync: (path) ->
new TextMateGrammar(fsUtils.readObject(path))
@injectionGrammars: []
name: null
rawPatterns: null
rawRepository: null
@ -38,10 +40,15 @@ class TextMateGrammar
includedGrammarScopes: null
maxTokensPerLine: 100
constructor: ({ @name, @fileTypes, @scopeName, injections, patterns, repository, @foldingStopMarker, firstLineMatch}) ->
constructor: ({ @name, @fileTypes, @scopeName, injections, injectionSelector, patterns, repository, @foldingStopMarker, firstLineMatch}) ->
@rawPatterns = patterns
@rawRepository = repository
@injections = new Injections(this, injections)
if injectionSelector?
@injectionSelector = new TextMateScopeSelector(injectionSelector)
TextMateGrammar.injectionGrammars.push(this)
@firstLineRegex = new OnigRegExp(firstLineMatch) if firstLineMatch
@fileTypes ?= []
@includedGrammarScopes = []
@ -261,23 +268,26 @@ class Rule
findNextMatch: (ruleStack, line, position, firstLine) ->
lineWithNewline = "#{line}\n"
baseGrammar = ruleStack[0].grammar
results = []
scanner = @getScanner(baseGrammar, position, firstLine)
result = scanner.findNextMatch(lineWithNewline, position)
@normalizeCaptureIndices(line, result.captureIndices) if result?
if result = scanner.findNextMatch(lineWithNewline, position)
results.push(result)
injectionResult = @scanInjections(ruleStack, lineWithNewline, position, firstLine)
@normalizeCaptureIndices(line, injectionResult.captureIndices) if injectionResult?
if result = @scanInjections(ruleStack, lineWithNewline, position, firstLine)
results.push(result)
if result? and injectionResult?
resultStartPosition = result.captureIndices[1]
injectionResultStartPosition = injectionResult.captureIndices[1]
if injectionResultStartPosition < resultStartPosition
injectionResult
else
result
else
result ? injectionResult
scopes = scopesFromStack(ruleStack)
for injectionGrammar in _.without(TextMateGrammar.injectionGrammars, @grammar, baseGrammar)
if injectionGrammar.injectionSelector.matches(scopes)
scanner = injectionGrammar.getInitialRule().getScanner(injectionGrammar, position, firstLine)
if result = scanner.findNextMatch(lineWithNewline, position)
results.push(result)
if results.length > 0
_.min results, (result) =>
@normalizeCaptureIndices(line, result.captureIndices)
result.captureIndices[1]
getNextTokens: (ruleStack, line, position, firstLine) ->
result = @findNextMatch(ruleStack, line, position, firstLine)