mirror of
https://github.com/atom/atom.git
synced 2026-04-28 03:01:47 -04:00
Change syntax.selectGrammar to choose the highest-scoring grammar
This sets us up to switch to a grammar when it is loaded if it is a better match for the current file.
This commit is contained in:
@@ -5,5 +5,7 @@ class NullGrammar
|
||||
name: 'Null Grammar'
|
||||
scopeName: 'text.plain.null-grammar'
|
||||
|
||||
getScore: -> 0
|
||||
|
||||
tokenizeLine: (line) ->
|
||||
{ tokens: [new Token(value: line, scopes: ['null-grammar.text.plain'])] }
|
||||
|
||||
@@ -5,8 +5,6 @@ Specificity = require 'specificity'
|
||||
fsUtils = require 'fs-utils'
|
||||
EventEmitter = require 'event-emitter'
|
||||
NullGrammar = require 'null-grammar'
|
||||
nodePath = require 'path'
|
||||
pathSplitRegex = new RegExp("[#{nodePath.sep}.]")
|
||||
|
||||
module.exports =
|
||||
class Syntax
|
||||
@@ -18,13 +16,13 @@ class Syntax
|
||||
syntax
|
||||
|
||||
constructor: ->
|
||||
@grammars = []
|
||||
@nullGrammar = new NullGrammar
|
||||
@grammars = [@nullGrammar]
|
||||
@grammarsByFileType = {}
|
||||
@grammarsByScopeName = {}
|
||||
@grammarOverridesByPath = {}
|
||||
@scopedPropertiesIndex = 0
|
||||
@scopedProperties = []
|
||||
@nullGrammar = new NullGrammar
|
||||
|
||||
serialize: ->
|
||||
{ deserializer: @constructor.name, @grammarOverridesByPath }
|
||||
@@ -50,51 +48,10 @@ class Syntax
|
||||
@grammarOverridesByPath = {}
|
||||
|
||||
selectGrammar: (filePath, fileContents) ->
|
||||
|
||||
return @grammarsByFileType["txt"] ? @nullGrammar unless filePath
|
||||
|
||||
@grammarOverrideForPath(filePath) ?
|
||||
@grammarByFirstLineRegex(filePath, fileContents) ?
|
||||
@grammarByPath(filePath) ?
|
||||
@grammarsByFileType["txt"] ?
|
||||
@nullGrammar
|
||||
_.max @grammars, (grammar) -> grammar.getScore(filePath, fileContents)
|
||||
|
||||
grammarOverrideForPath: (path) ->
|
||||
@grammarsByScopeName[@grammarOverridesByPath[path]]
|
||||
|
||||
grammarByPath: (path) ->
|
||||
pathComponents = path.split(pathSplitRegex)
|
||||
for fileType, grammar of @grammarsByFileType
|
||||
fileTypeComponents = fileType.split(pathSplitRegex)
|
||||
pathSuffix = pathComponents[-fileTypeComponents.length..-1]
|
||||
return grammar if _.isEqual(pathSuffix, fileTypeComponents)
|
||||
|
||||
grammarByFirstLineRegex: (filePath, fileContents) ->
|
||||
try
|
||||
fileContents ?= fsUtils.read(filePath)
|
||||
catch e
|
||||
return
|
||||
|
||||
return unless fileContents
|
||||
|
||||
lines = fileContents.split('\n')
|
||||
_.find @grammars, (grammar) ->
|
||||
regex = grammar.firstLineRegex
|
||||
return unless regex?
|
||||
|
||||
escaped = false
|
||||
numberOfNewlinesInRegex = 0
|
||||
for character in regex.source
|
||||
switch character
|
||||
when '\\'
|
||||
escaped = !escaped
|
||||
when 'n'
|
||||
numberOfNewlinesInRegex++ if escaped
|
||||
escaped = false
|
||||
else
|
||||
escaped = false
|
||||
|
||||
regex.test(lines[0..numberOfNewlinesInRegex].join('\n'))
|
||||
@grammarOverridesByPath[path]
|
||||
|
||||
grammarForScopeName: (scopeName) ->
|
||||
@grammarsByScopeName[scopeName]
|
||||
|
||||
@@ -2,8 +2,9 @@ _ = require 'underscore'
|
||||
fsUtils = require 'fs-utils'
|
||||
plist = require 'plist'
|
||||
Token = require 'token'
|
||||
CSON = require 'cson'
|
||||
{OnigRegExp, OnigScanner} = require 'oniguruma'
|
||||
nodePath = require 'path'
|
||||
pathSplitRegex = new RegExp("[#{nodePath.sep}.]")
|
||||
|
||||
module.exports =
|
||||
class TextMateGrammar
|
||||
@@ -38,6 +39,48 @@ class TextMateGrammar
|
||||
data = {patterns: [data], tempName: name} if data.begin? or data.match?
|
||||
@repository[name] = new Rule(this, data)
|
||||
|
||||
getScore: (path, contents) ->
|
||||
contents = fsUtils.read(path) if not contents? and fsUtils.isFile(path)
|
||||
|
||||
if syntax.grammarOverrideForPath(path) is @scopeName
|
||||
Infinity
|
||||
else if @matchesContents(contents)
|
||||
3
|
||||
else if @matchesPath(path)
|
||||
2
|
||||
else if @isTextGrammar()
|
||||
1
|
||||
else
|
||||
-1
|
||||
|
||||
matchesContents: (contents) ->
|
||||
return false unless contents? and @firstLineRegex?
|
||||
|
||||
escaped = false
|
||||
numberOfNewlinesInRegex = 0
|
||||
for character in @firstLineRegex.source
|
||||
switch character
|
||||
when '\\'
|
||||
escaped = !escaped
|
||||
when 'n'
|
||||
numberOfNewlinesInRegex++ if escaped
|
||||
escaped = false
|
||||
else
|
||||
escaped = false
|
||||
lines = contents.split('\n')
|
||||
@firstLineRegex.test(lines[0..numberOfNewlinesInRegex].join('\n'))
|
||||
|
||||
matchesPath: (path) ->
|
||||
return false unless path?
|
||||
pathComponents = path.split(pathSplitRegex)
|
||||
_.find @fileTypes, (fileType) ->
|
||||
fileTypeComponents = fileType.split(pathSplitRegex)
|
||||
pathSuffix = pathComponents[-fileTypeComponents.length..-1]
|
||||
_.isEqual(pathSuffix, fileTypeComponents)
|
||||
|
||||
isTextGrammar: ->
|
||||
@scopeName is 'text.plain'
|
||||
|
||||
tokenizeLine: (line, ruleStack=[@initialRule], firstLine=false) ->
|
||||
originalRuleStack = ruleStack
|
||||
ruleStack = new Array(ruleStack...) # clone ruleStack
|
||||
|
||||
Reference in New Issue
Block a user