This repository was archived by the owner on Sep 8, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 49
/
Copy pathprovider.coffee
127 lines (100 loc) · 5.29 KB
/
provider.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
# ref https://github.com/atom/autocomplete-html/blob/master/lib/provider.coffee
COMPLETIONS = require '../completions.json'
attributePattern = /\s+([a-zA-Z][-a-zA-Z]*)\s*=\s*$/
module.exports =
selector: '.source.js, .text.html'
disableForSelector: '.source.js .comment, .text.html .comment'
filterSuggestions: true
completions: COMPLETIONS
getSuggestions: (request) ->
if @isJavaScript(request) and not @isIgnoreInJavaScript(request)
@getJavascriptCompletions(request)
else if @isHtml(request)
if @isAttributeStart(request)
@getAttributeNameCompletions(request)
else if @isTagStart(request)
@getTagNameCompletions(request)
else
[]
isJavaScript: ({ scopeDescriptor }) ->
for scope in scopeDescriptor.getScopesArray()
return true if scope.startsWith('source') and scope.endsWith('.js')
return false
isIgnoreInJavaScript: ({ scopeDescriptor, prefix }) ->
scopes = scopeDescriptor.getScopesArray()
return true if scopes.indexOf('punctuation.terminator.statement.js') isnt -1 or
scopes.indexOf('keyword.operator.assignment.js') isnt -1 or
scopes.indexOf('meta.delimiter.object.comma.js') isnt -1 or
scopes.indexOf('keyword.operator.comparison.js') isnt -1 or
scopes.indexOf('keyword.operator.ternary.js') isnt -1 or
scopes.indexOf('keyword.operator.js') isnt -1 or
scopes.indexOf('string.quoted.template.js') isnt -1 or
prefix.trim() is ''
return false
isHtml: ({ scopeDescriptor }) ->
for scope in scopeDescriptor.getScopesArray()
return true if scope.endsWith('.html')
return false
isAttributeStart: ({prefix, scopeDescriptor, bufferPosition, editor}) ->
scopes = scopeDescriptor.getScopesArray()
return @hasTagScope(scopes) if not @getPreviousAttribute(editor, bufferPosition) and prefix and not prefix.trim()
previousBufferPosition = [bufferPosition.row, Math.max(0, bufferPosition.column - 1)]
previousScopes = editor.scopeDescriptorForBufferPosition(previousBufferPosition)
previousScopesArray = previousScopes.getScopesArray()
return true if previousScopesArray.indexOf('entity.other.attribute-name.html') isnt -1
return false unless @hasTagScope(scopes)
# autocomplete here: <tag |>
# not here: <tag >|
scopes.indexOf('punctuation.definition.tag.end.html') isnt -1 and
previousScopesArray.indexOf('punctuation.definition.tag.end.html') is -1
isTagStart: ({ prefix, scopeDescriptor, bufferPosition, editor }) ->
return @hasTagScope(scopeDescriptor.getScopesArray()) if prefix.trim() and prefix.indexOf('<') is -1
# autocomplete-plus's default prefix setting does not capture <. Manually check for it.
prefix = editor.getTextInRange([[bufferPosition.row, bufferPosition.column - 1], bufferPosition])
scopes = scopeDescriptor.getScopesArray()
# Don't autocomplete in embedded languages
prefix is '<' and scopes[0] is 'text.html.basic' and scopes.length is 1
hasTagScope: (scopes) ->
for scope in scopes
return true if scope.startsWith('meta.tag.') and scope.endsWith('.html')
return false
hasStringScope: (scopes) ->
scopes.indexOf('string.quoted.double.html') isnt -1 or
scopes.indexOf('string.quoted.single.html') isnt -1
getAttributeNameCompletions: ({prefix, editor, bufferPosition}) ->
completions = []
cantidates = @completions.directives.concat @completions.attributes
for idx, attribute of cantidates when not prefix.trim() or firstCharsEqual(attribute, prefix)
completions.push({ text: attribute, type: 'attribute' })
completions
getTagNameCompletions: ({ prefix, editor, bufferPosition }) ->
# autocomplete-plus's default prefix setting does not capture <. Manually check for it.
ignorePrefix = editor.getTextInRange([[bufferPosition.row, bufferPosition.column - 1], bufferPosition]) is '<'
completions = []
for idx, tag of @completions.directives when ignorePrefix or firstCharsEqual(tag, prefix)
completions.push({ text: tag, type: 'tag' })
completions
getJavascriptCompletions: ({ prefix, editor, bufferPosition }) ->
completions = []
prefix = @getPrefix(editor, bufferPosition)
for idx, tag of @completions.javascript
completions.push({ text: tag, type: 'angularjs', replacementPrefix: prefix })
completions
getPreviousAttribute: (editor, bufferPosition) ->
# Remove everything until the opening quote (if we're in a string)
quoteIndex = bufferPosition.column - 1 # Don't start at the end of the line
while quoteIndex
scopes = editor.scopeDescriptorForBufferPosition([bufferPosition.row, quoteIndex])
scopesArray = scopes.getScopesArray()
break if not @hasStringScope(scopesArray) or scopesArray.indexOf('punctuation.definition.string.begin.html') isnt -1
quoteIndex--
attributePattern.exec(editor.getTextInRange([[bufferPosition.row, 0], [bufferPosition.row, quoteIndex]]))?[1]
getPrefix: (editor, bufferPosition) ->
# Whatever your prefix regex might be
regex = /\$?[\w0-9_-]+$/
# Get the text for the line up to the triggered buffer position
line = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition])
# Match the regex to the line, and return the match
line.match(regex)?[0] or ''
firstCharsEqual = (str1, str2) ->
str1[0].toLowerCase() is str2[0].toLowerCase()