This repository has been archived by the owner on Mar 3, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 17.4k
/
grammar-registry.coffee
130 lines (112 loc) · 4.44 KB
/
grammar-registry.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
_ = require 'underscore-plus'
FirstMate = require 'first-mate'
Token = require './token'
fs = require 'fs-plus'
Grim = require 'grim'
PathSplitRegex = new RegExp("[/.]")
# Extended: Syntax class holding the grammars used for tokenizing.
#
# An instance of this class is always available as the `atom.grammars` global.
#
# The Syntax class also contains properties for things such as the
# language-specific comment regexes. See {::getProperty} for more details.
module.exports =
class GrammarRegistry extends FirstMate.GrammarRegistry
constructor: ({@config}={}) ->
super(maxTokensPerLine: 100, maxLineLength: 1000)
createToken: (value, scopes) -> new Token({value, scopes})
# Extended: Select a grammar for the given file path and file contents.
#
# This picks the best match by checking the file path and contents against
# each grammar.
#
# * `filePath` A {String} file path.
# * `fileContents` A {String} of text for the file path.
#
# Returns a {Grammar}, never null.
selectGrammar: (filePath, fileContents) ->
@selectGrammarWithScore(filePath, fileContents).grammar
selectGrammarWithScore: (filePath, fileContents) ->
bestMatch = null
highestScore = -Infinity
for grammar in @grammars
score = @getGrammarScore(grammar, filePath, fileContents)
if score > highestScore or not bestMatch?
bestMatch = grammar
highestScore = score
{grammar: bestMatch, score: highestScore}
# Extended: Returns a {Number} representing how well the grammar matches the
# `filePath` and `contents`.
getGrammarScore: (grammar, filePath, contents) ->
contents = fs.readFileSync(filePath, 'utf8') if not contents? and fs.isFileSync(filePath)
score = @getGrammarPathScore(grammar, filePath)
if score > 0 and not grammar.bundledPackage
score += 0.25
if @grammarMatchesContents(grammar, contents)
score += 0.125
score
getGrammarPathScore: (grammar, filePath) ->
return -1 unless filePath
filePath = filePath.replace(/\\/g, '/') if process.platform is 'win32'
pathComponents = filePath.toLowerCase().split(PathSplitRegex)
pathScore = -1
fileTypes = grammar.fileTypes
if customFileTypes = @config.get('core.customFileTypes')?[grammar.scopeName]
fileTypes = fileTypes.concat(customFileTypes)
for fileType, i in fileTypes
fileTypeComponents = fileType.toLowerCase().split(PathSplitRegex)
pathSuffix = pathComponents[-fileTypeComponents.length..-1]
if _.isEqual(pathSuffix, fileTypeComponents)
pathScore = Math.max(pathScore, fileType.length)
if i >= grammar.fileTypes.length
pathScore += 0.5
pathScore
grammarMatchesContents: (grammar, contents) ->
return false unless contents? and grammar.firstLineRegex?
escaped = false
numberOfNewlinesInRegex = 0
for character in grammar.firstLineRegex.source
switch character
when '\\'
escaped = not escaped
when 'n'
numberOfNewlinesInRegex++ if escaped
escaped = false
else
escaped = false
lines = contents.split('\n')
grammar.firstLineRegex.testSync(lines[0..numberOfNewlinesInRegex].join('\n'))
# Deprecated: Get the grammar override for the given file path.
#
# * `filePath` A {String} file path.
#
# Returns a {String} such as `"source.js"`.
grammarOverrideForPath: (filePath) ->
Grim.deprecate 'Use atom.textEditors.getGrammarOverride(editor) instead'
if editor = getEditorForPath(filePath)
atom.textEditors.getGrammarOverride(editor)
# Deprecated: Set the grammar override for the given file path.
#
# * `filePath` A non-empty {String} file path.
# * `scopeName` A {String} such as `"source.js"`.
#
# Returns undefined
setGrammarOverrideForPath: (filePath, scopeName) ->
Grim.deprecate 'Use atom.textEditors.setGrammarOverride(editor, scopeName) instead'
if editor = getEditorForPath(filePath)
atom.textEditors.setGrammarOverride(editor, scopeName)
return
# Deprecated: Remove the grammar override for the given file path.
#
# * `filePath` A {String} file path.
#
# Returns undefined.
clearGrammarOverrideForPath: (filePath) ->
Grim.deprecate 'Use atom.textEditors.clearGrammarOverride(editor) instead'
if editor = getEditorForPath(filePath)
atom.textEditors.clearGrammarOverride(editor)
return
getEditorForPath = (filePath) ->
if filePath?
atom.workspace.getTextEditors().find (editor) ->
editor.getPath() is filePath