mirror of
https://github.com/atom/atom.git
synced 2026-01-24 14:28:14 -05:00
Store grammars on the syntax global
This commit is contained in:
@@ -1,4 +1,22 @@
|
||||
describe "the `syntax` global", ->
|
||||
describe ".grammarForFilePath(filePath)", ->
|
||||
it "uses the filePath's extension to load the correct grammar", ->
|
||||
expect(syntax.grammarForFilePath("file.js").name).toBe "JavaScript"
|
||||
|
||||
it "uses the filePath's base name if there is no extension", ->
|
||||
expect(syntax.grammarForFilePath("Rakefile").name).toBe "Ruby"
|
||||
|
||||
it "uses the filePath's shebang line if the grammar cannot be determined by the extension or basename", ->
|
||||
filePath = require.resolve("fixtures/shebang")
|
||||
expect(syntax.grammarForFilePath(filePath).name).toBe "Ruby"
|
||||
|
||||
it "uses the grammar's fileType as a suffix of the full filePath if the grammar cannot be determined by shebang line", ->
|
||||
expect(syntax.grammarForFilePath("/tmp/.git/config").name).toBe "Git Config"
|
||||
|
||||
it "uses plain text if no grammar can be found", ->
|
||||
filePath = require.resolve("this-is-not-a-real-file")
|
||||
expect(syntax.grammarForFilePath(filePath).name).toBe "Plain Text"
|
||||
|
||||
describe ".getProperty(scopeDescriptor)", ->
|
||||
it "returns the property with the most specific scope selector", ->
|
||||
syntax.addProperties(".source.coffee .string.quoted.double.coffee", foo: bar: baz: 42)
|
||||
|
||||
@@ -2,14 +2,6 @@ fs = require('fs')
|
||||
TextMateBundle = require 'text-mate-bundle'
|
||||
|
||||
describe "TextMateBundle", ->
|
||||
describe ".getPreferencesByScopeSelector()", ->
|
||||
it "logs warning, but does not raise errors if a preference can't be parsed", ->
|
||||
bundlePath = fs.join(require.resolve('fixtures'), "test.tmbundle")
|
||||
spyOn(console, 'warn')
|
||||
bundle = new TextMateBundle(bundlePath)
|
||||
expect(-> bundle.getPreferencesByScopeSelector()).not.toThrow()
|
||||
expect(console.warn).toHaveBeenCalled()
|
||||
|
||||
describe ".constructor(bundlePath)", ->
|
||||
it "logs warning, but does not raise errors if a grammar can't be parsed", ->
|
||||
bundlePath = fs.join(require.resolve('fixtures'), "test.tmbundle")
|
||||
@@ -17,20 +9,3 @@ describe "TextMateBundle", ->
|
||||
expect(-> new TextMateBundle(bundlePath)).not.toThrow()
|
||||
expect(console.warn).toHaveBeenCalled()
|
||||
|
||||
describe ".grammarForFilePath(filePath)", ->
|
||||
it "uses the filePath's extension to load the correct grammar", ->
|
||||
expect(TextMateBundle.grammarForFilePath("file.js").name).toBe "JavaScript"
|
||||
|
||||
it "uses the filePath's base name if there is no extension", ->
|
||||
expect(TextMateBundle.grammarForFilePath("Rakefile").name).toBe "Ruby"
|
||||
|
||||
it "uses the filePath's shebang line if the grammar cannot be determined by the extension or basename", ->
|
||||
filePath = require.resolve("fixtures/shebang")
|
||||
expect(TextMateBundle.grammarForFilePath(filePath).name).toBe "Ruby"
|
||||
|
||||
it "uses the grammar's fileType as a suffix of the full filePath if the grammar cannot be determined by shebang line", ->
|
||||
expect(TextMateBundle.grammarForFilePath("/tmp/.git/config").name).toBe "Git Config"
|
||||
|
||||
it "uses plain text if no grammar can be found", ->
|
||||
filePath = require.resolve("this-is-not-a-real-file")
|
||||
expect(TextMateBundle.grammarForFilePath(filePath).name).toBe "Plain Text"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
TextMateGrammar = require 'text-mate-grammar'
|
||||
TextMateBundle = require 'text-mate-bundle'
|
||||
plist = require 'plist'
|
||||
fs = require 'fs'
|
||||
_ = require 'underscore'
|
||||
@@ -8,7 +7,7 @@ describe "TextMateGrammar", ->
|
||||
grammar = null
|
||||
|
||||
beforeEach ->
|
||||
grammar = TextMateBundle.grammarForFilePath("hello.coffee")
|
||||
grammar = syntax.grammarForFilePath("hello.coffee")
|
||||
|
||||
describe ".tokenizeLine(line, ruleStack)", ->
|
||||
describe "when the entire line matches a single pattern with no capture groups", ->
|
||||
@@ -31,7 +30,7 @@ describe "TextMateGrammar", ->
|
||||
|
||||
describe "when the line doesn't match any patterns", ->
|
||||
it "returns the entire line as a single simple token with the grammar's scope", ->
|
||||
textGrammar = TextMateBundle.grammarForFilePath('foo.txt')
|
||||
textGrammar = syntax.grammarForFilePath('foo.txt')
|
||||
{tokens} = textGrammar.tokenizeLine("abc def")
|
||||
expect(tokens.length).toBe 1
|
||||
|
||||
@@ -108,20 +107,20 @@ describe "TextMateGrammar", ->
|
||||
|
||||
describe "when the line matches no patterns", ->
|
||||
it "does not infinitely loop", ->
|
||||
grammar = TextMateBundle.grammarForFilePath("sample.txt")
|
||||
grammar = syntax.grammarForFilePath("sample.txt")
|
||||
{tokens} = grammar.tokenizeLine('hoo')
|
||||
expect(tokens.length).toBe 1
|
||||
expect(tokens[0]).toEqual value: 'hoo', scopes: ["text.plain", "meta.paragraph.text"]
|
||||
|
||||
describe "when the line matches a pattern with a 'contentName'", ->
|
||||
it "creates tokens using the content of contentName as the token name", ->
|
||||
grammar = TextMateBundle.grammarForFilePath("sample.txt")
|
||||
grammar = syntax.grammarForFilePath("sample.txt")
|
||||
{tokens} = grammar.tokenizeLine('ok, cool')
|
||||
expect(tokens[0]).toEqual value: 'ok, cool', scopes: ["text.plain", "meta.paragraph.text"]
|
||||
|
||||
describe "when the line matches a pattern with no `name` or `contentName`", ->
|
||||
it "creates tokens without adding a new scope", ->
|
||||
grammar = TextMateBundle.grammarsByFileType["rb"]
|
||||
grammar = syntax.grammarsByFileType["rb"]
|
||||
{tokens} = grammar.tokenizeLine('%w|oh \\look|')
|
||||
expect(tokens.length).toBe 5
|
||||
expect(tokens[0]).toEqual value: '%w|', scopes: ["source.ruby", "string.quoted.other.literal.lower.ruby", "punctuation.definition.string.begin.ruby"]
|
||||
@@ -166,7 +165,7 @@ describe "TextMateGrammar", ->
|
||||
|
||||
describe "when the end pattern contains a back reference", ->
|
||||
it "constructs the end rule based on its back-references to captures in the begin rule", ->
|
||||
grammar = TextMateBundle.grammarsByFileType["rb"]
|
||||
grammar = syntax.grammarsByFileType["rb"]
|
||||
{tokens} = grammar.tokenizeLine('%w|oh|,')
|
||||
expect(tokens.length).toBe 4
|
||||
expect(tokens[0]).toEqual value: '%w|', scopes: ["source.ruby", "string.quoted.other.literal.lower.ruby", "punctuation.definition.string.begin.ruby"]
|
||||
@@ -175,7 +174,7 @@ describe "TextMateGrammar", ->
|
||||
expect(tokens[3]).toEqual value: ',', scopes: ["source.ruby", "punctuation.separator.object.ruby"]
|
||||
|
||||
it "allows the rule containing that end pattern to be pushed to the stack multiple times", ->
|
||||
grammar = TextMateBundle.grammarsByFileType["rb"]
|
||||
grammar = syntax.grammarsByFileType["rb"]
|
||||
{tokens} = grammar.tokenizeLine('%Q+matz had some #{%Q-crazy ideas-} for ruby syntax+ # damn.')
|
||||
expect(tokens[0]).toEqual value: '%Q+', scopes: ["source.ruby","string.quoted.other.literal.upper.ruby","punctuation.definition.string.begin.ruby"]
|
||||
expect(tokens[1]).toEqual value: 'matz had some ', scopes: ["source.ruby","string.quoted.other.literal.upper.ruby"]
|
||||
@@ -192,7 +191,7 @@ describe "TextMateGrammar", ->
|
||||
|
||||
describe "when the pattern includes rules from another grammar", ->
|
||||
it "parses tokens inside the begin/end patterns based on the included grammar's rules", ->
|
||||
grammar = TextMateBundle.grammarsByFileType["html.erb"]
|
||||
grammar = syntax.grammarsByFileType["html.erb"]
|
||||
{tokens} = grammar.tokenizeLine("<div class='name'><%= User.find(2).full_name %></div>")
|
||||
|
||||
expect(tokens[0]).toEqual value: '<', scopes: ["text.html.ruby","meta.tag.block.any.html","punctuation.definition.tag.begin.html"]
|
||||
@@ -243,18 +242,18 @@ describe "TextMateGrammar", ->
|
||||
expect(tokens[1].value).toBe " a singleLineComment"
|
||||
|
||||
it "does not loop infinitely (regression)", ->
|
||||
grammar = TextMateBundle.grammarForFilePath("hello.js")
|
||||
grammar = syntax.grammarForFilePath("hello.js")
|
||||
{tokens, ruleStack} = grammar.tokenizeLine("// line comment")
|
||||
{tokens, ruleStack} = grammar.tokenizeLine(" // second line comment with a single leading space", ruleStack)
|
||||
|
||||
describe "when inside a C block", ->
|
||||
it "correctly parses a method. (regression)", ->
|
||||
grammar = TextMateBundle.grammarForFilePath("hello.c")
|
||||
grammar = syntax.grammarForFilePath("hello.c")
|
||||
{tokens, ruleStack} = grammar.tokenizeLine("if(1){m()}")
|
||||
expect(tokens[5]).toEqual value: "m", scopes: ["source.c", "meta.block.c", "meta.function-call.c", "support.function.any-method.c"]
|
||||
|
||||
it "correctly parses nested blocks. (regression)", ->
|
||||
grammar = TextMateBundle.grammarForFilePath("hello.c")
|
||||
grammar = syntax.grammarForFilePath("hello.c")
|
||||
{tokens, ruleStack} = grammar.tokenizeLine("if(1){if(1){m()}}")
|
||||
expect(tokens[5]).toEqual value: "if", scopes: ["source.c", "meta.block.c", "keyword.control.c"]
|
||||
expect(tokens[10]).toEqual value: "m", scopes: ["source.c", "meta.block.c", "meta.block.c", "meta.function-call.c", "support.function.any-method.c"]
|
||||
|
||||
@@ -17,7 +17,7 @@ class LanguageMode
|
||||
|
||||
constructor: (@editSession) ->
|
||||
@buffer = @editSession.buffer
|
||||
@grammar = TextMateBundle.grammarForFilePath(@buffer.getPath())
|
||||
@grammar = syntax.grammarForFilePath(@buffer.getPath())
|
||||
@bracketAnchorRanges = []
|
||||
|
||||
_.adviseBefore @editSession, 'insertText', (text) =>
|
||||
|
||||
@@ -2,14 +2,50 @@ _ = require 'underscore'
|
||||
jQuery = require 'jquery'
|
||||
Specificity = require 'specificity'
|
||||
{$$} = require 'space-pen'
|
||||
fs = require 'fs'
|
||||
|
||||
module.exports =
|
||||
class Syntax
|
||||
constructor: ->
|
||||
@grammars = []
|
||||
@grammarsByFileType = {}
|
||||
@grammarsByScopeName = {}
|
||||
@globalProperties = {}
|
||||
@scopedPropertiesIndex = 0
|
||||
@scopedProperties = []
|
||||
@propertiesBySelector = {}
|
||||
|
||||
addGrammar: (grammar) ->
|
||||
@grammars.push(grammar)
|
||||
for fileType in grammar.fileTypes
|
||||
@grammarsByFileType[fileType] = grammar
|
||||
@grammarsByScopeName[grammar.scopeName] = grammar
|
||||
|
||||
grammarForFilePath: (filePath) ->
|
||||
return @grammarsByFileType["txt"] unless filePath
|
||||
|
||||
extension = fs.extension(filePath)?[1..]
|
||||
if filePath and extension.length == 0
|
||||
extension = fs.base(filePath)
|
||||
|
||||
@grammarsByFileType[extension] or
|
||||
@grammarByShebang(filePath) or
|
||||
@grammarByFileTypeSuffix(filePath) or
|
||||
@grammarsByFileType["txt"]
|
||||
|
||||
grammarByFileTypeSuffix: (filePath) ->
|
||||
for fileType, grammar of @grammarsByFileType
|
||||
return grammar if _.endsWith(filePath, fileType)
|
||||
|
||||
grammarByShebang: (filePath) ->
|
||||
try
|
||||
fileContents = fs.read(filePath)
|
||||
catch e
|
||||
null
|
||||
|
||||
_.find @grammars, (grammar) -> grammar.firstLineRegex?.test(fileContents)
|
||||
|
||||
grammarForScopeName: (scopeName) ->
|
||||
@grammarsByScopeName[scopeName]
|
||||
|
||||
addProperties: (args...) ->
|
||||
selector = args.shift() if args.length > 1
|
||||
|
||||
@@ -9,50 +9,13 @@ module.exports =
|
||||
class TextMateBundle
|
||||
@grammarsByFileType: {}
|
||||
@grammarsByScopeName: {}
|
||||
@preferencesByScopeSelector: {}
|
||||
@grammars: []
|
||||
|
||||
@load: (name)->
|
||||
@load: (name) ->
|
||||
bundle = new TextMateBundle(require.resolve(name))
|
||||
|
||||
for scopeSelector, preferences of bundle.getPreferencesByScopeSelector()
|
||||
if @preferencesByScopeSelector[scopeSelector]?
|
||||
_.extend(@preferencesByScopeSelector[scopeSelector], preferences)
|
||||
else
|
||||
@preferencesByScopeSelector[scopeSelector] = preferences
|
||||
|
||||
for grammar in bundle.grammars
|
||||
@grammars.push(grammar)
|
||||
for fileType in grammar.fileTypes
|
||||
@grammarsByFileType[fileType] = grammar
|
||||
@grammarsByScopeName[grammar.scopeName] = grammar
|
||||
|
||||
syntax.addGrammar(grammar) for grammar in bundle.grammars
|
||||
bundle
|
||||
|
||||
@grammarForFilePath: (filePath) ->
|
||||
return @grammarsByFileType["txt"] unless filePath
|
||||
|
||||
extension = fs.extension(filePath)?[1...]
|
||||
if filePath and extension.length == 0
|
||||
extension = fs.base(filePath)
|
||||
|
||||
@grammarsByFileType[extension] or @grammarByShebang(filePath) or @grammarByFileTypeSuffix(filePath) or @grammarsByFileType["txt"]
|
||||
|
||||
@grammarByFileTypeSuffix: (filePath) ->
|
||||
for fileType, grammar of @grammarsByFileType
|
||||
return grammar if _.endsWith(filePath, fileType)
|
||||
|
||||
@grammarByShebang: (filePath) ->
|
||||
try
|
||||
fileContents = fs.read(filePath)
|
||||
catch e
|
||||
null
|
||||
|
||||
_.find @grammars, (grammar) -> grammar.firstLineRegex?.test(fileContents)
|
||||
|
||||
@grammarForScopeName: (scopeName) ->
|
||||
@grammarsByScopeName[scopeName]
|
||||
|
||||
grammars: null
|
||||
|
||||
constructor: (@path) ->
|
||||
@@ -64,25 +27,5 @@ class TextMateBundle
|
||||
catch e
|
||||
console.warn "Failed to load grammar at path '#{syntaxPath}'", e
|
||||
|
||||
getPreferencesByScopeSelector: ->
|
||||
return {} unless fs.exists(@getPreferencesPath())
|
||||
preferencesByScopeSelector = {}
|
||||
for preferencePath in fs.list(@getPreferencesPath())
|
||||
plist.parseString fs.read(preferencePath), (e, data) ->
|
||||
if e
|
||||
console.warn "Failed to parse preference at path '#{preferencePath}'", e
|
||||
else
|
||||
{ scope, settings } = data[0]
|
||||
return unless scope
|
||||
for scope in scope.split(',')
|
||||
scope = $.trim(scope)
|
||||
continue unless scope
|
||||
preferencesByScopeSelector[scope] = _.extend(preferencesByScopeSelector[scope] ? {}, settings)
|
||||
|
||||
preferencesByScopeSelector
|
||||
|
||||
getSyntaxesPath: ->
|
||||
fs.join(@path, "Syntaxes")
|
||||
|
||||
getPreferencesPath: ->
|
||||
fs.join(@path, "Preferences")
|
||||
|
||||
@@ -72,8 +72,7 @@ class TextMateGrammar
|
||||
else if name == "$self" or name == "$base"
|
||||
@initialRule
|
||||
else
|
||||
TextMateBundle = require 'text-mate-bundle'
|
||||
TextMateBundle.grammarForScopeName(name)?.initialRule
|
||||
syntax.grammarForScopeName(name)?.initialRule
|
||||
|
||||
class Rule
|
||||
grammar: null
|
||||
|
||||
@@ -71,4 +71,4 @@ class TextMatePackage extends Package
|
||||
{ editor: editorProperties } if _.size(editorProperties) > 0
|
||||
|
||||
cssSelectorFromScopeSelector: (scopeSelector) ->
|
||||
@constructor.cssSelectorFromScopeSelector(scopeSelector)
|
||||
@constructor.cssSelectorFromScopeSelector(scopeSelector)
|
||||
|
||||
Reference in New Issue
Block a user