mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-08-16 22:50:22 +03:00
Bundle autocomplete-css
This commit is contained in:
parent
05b3976fc2
commit
b7c94a875c
@ -35,7 +35,7 @@
|
||||
"atom-light-ui": "file:packages/atom-light-ui",
|
||||
"atom-select-list": "^0.8.1",
|
||||
"autocomplete-atom-api": "https://codeload.github.com/atom/autocomplete-atom-api/legacy.tar.gz/refs/tags/v0.10.7",
|
||||
"autocomplete-css": "https://codeload.github.com/atom/autocomplete-css/legacy.tar.gz/refs/tags/v0.17.5",
|
||||
"autocomplete-css": "file:packages/autocomplete-css",
|
||||
"autocomplete-html": "https://github.com/pulsar-edit/autocomplete-html.git#v0.8.9",
|
||||
"autocomplete-plus": "https://codeload.github.com/atom/autocomplete-plus/legacy.tar.gz/refs/tags/v2.42.4",
|
||||
"autocomplete-snippets": "https://codeload.github.com/atom/autocomplete-snippets/legacy.tar.gz/refs/tags/v1.12.1",
|
||||
@ -194,7 +194,7 @@
|
||||
"about": "file:./packages/about",
|
||||
"archive-view": "0.66.0",
|
||||
"autocomplete-atom-api": "0.10.7",
|
||||
"autocomplete-css": "0.17.5",
|
||||
"autocomplete-css": "file:./packages/autocomplete-css",
|
||||
"autocomplete-html": "0.8.9",
|
||||
"autocomplete-plus": "2.42.4",
|
||||
"autocomplete-snippets": "1.12.1",
|
||||
|
1
packages/autocomplete-css/.coffeelintignore
Normal file
1
packages/autocomplete-css/.coffeelintignore
Normal file
@ -0,0 +1 @@
|
||||
spec/fixtures
|
1
packages/autocomplete-css/.gitignore
vendored
Normal file
1
packages/autocomplete-css/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
node_modules
|
40
packages/autocomplete-css/ISSUE_TEMPLATE.md
Normal file
40
packages/autocomplete-css/ISSUE_TEMPLATE.md
Normal file
@ -0,0 +1,40 @@
|
||||
<!--
|
||||
|
||||
Have you read Atom's Code of Conduct? By filing an Issue, you are expected to comply with it, including treating everyone with respect: https://github.com/atom/atom/blob/master/CODE_OF_CONDUCT.md
|
||||
|
||||
Do you want to ask a question? Are you looking for support? The Atom message board is the best place for getting support: https://discuss.atom.io
|
||||
|
||||
-->
|
||||
|
||||
### Prerequisites
|
||||
|
||||
* [ ] Put an X between the brackets on this line if you have done all of the following:
|
||||
* Reproduced the problem in Safe Mode: http://flight-manual.atom.io/hacking-atom/sections/debugging/#using-safe-mode
|
||||
* Followed all applicable steps in the debugging guide: http://flight-manual.atom.io/hacking-atom/sections/debugging/
|
||||
* Checked the FAQs on the message board for common solutions: https://discuss.atom.io/c/faq
|
||||
* Checked that your issue isn't already filed: https://github.com/issues?utf8=✓&q=is%3Aissue+user%3Aatom
|
||||
* Checked that there is not already an Atom package that provides the described functionality: https://atom.io/packages
|
||||
|
||||
### Description
|
||||
|
||||
[Description of the issue]
|
||||
|
||||
### Steps to Reproduce
|
||||
|
||||
1. [First Step]
|
||||
2. [Second Step]
|
||||
3. [and so on...]
|
||||
|
||||
**Expected behavior:** [What you expect to happen]
|
||||
|
||||
**Actual behavior:** [What actually happens]
|
||||
|
||||
**Reproduces how often:** [What percentage of the time does it reproduce?]
|
||||
|
||||
### Versions
|
||||
|
||||
You can get this information from copy and pasting the output of `atom --version` and `apm --version` from the command line. Also, please include the OS and what version of the OS you're running.
|
||||
|
||||
### Additional Information
|
||||
|
||||
Any additional information, configuration or data that might be necessary to reproduce the issue.
|
20
packages/autocomplete-css/LICENSE.md
Normal file
20
packages/autocomplete-css/LICENSE.md
Normal file
@ -0,0 +1,20 @@
|
||||
Copyright (c) 2015 GitHub Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
28
packages/autocomplete-css/PULL_REQUEST_TEMPLATE.md
Normal file
28
packages/autocomplete-css/PULL_REQUEST_TEMPLATE.md
Normal file
@ -0,0 +1,28 @@
|
||||
### Requirements
|
||||
|
||||
* Filling out the template is required. Any pull request that does not include enough information to be reviewed in a timely manner may be closed at the maintainers' discretion.
|
||||
* All new code requires tests to ensure against regressions
|
||||
|
||||
### Description of the Change
|
||||
|
||||
<!--
|
||||
|
||||
We must be able to understand the design of your change from this description. If we can't get a good idea of what the code will be doing from the description here, the pull request may be closed at the maintainers' discretion. Keep in mind that the maintainer reviewing this PR may not be familiar with or have worked with the code here recently, so please walk us through the concepts.
|
||||
|
||||
-->
|
||||
|
||||
### Alternate Designs
|
||||
|
||||
<!-- Explain what other alternates were considered and why the proposed version was selected -->
|
||||
|
||||
### Benefits
|
||||
|
||||
<!-- What benefits will be realized by the code change? -->
|
||||
|
||||
### Possible Drawbacks
|
||||
|
||||
<!-- What are the possible side-effects or negative impacts of the code change? -->
|
||||
|
||||
### Applicable Issues
|
||||
|
||||
<!-- Enter any applicable Issues here -->
|
13
packages/autocomplete-css/README.md
Normal file
13
packages/autocomplete-css/README.md
Normal file
@ -0,0 +1,13 @@
|
||||
# CSS Autocomplete package
|
||||
[![OS X Build Status](https://travis-ci.org/atom/autocomplete-css.svg?branch=master)](https://travis-ci.org/atom/autocomplete-css) [![Windows Build Status](https://ci.appveyor.com/api/projects/status/k3e5uvpmpc5bkja9/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/autocomplete-css/branch/master) [![Dependency Status](https://david-dm.org/atom/autocomplete-css.svg)](https://david-dm.org/atom/autocomplete-css)
|
||||
|
||||
CSS property name and value autocompletions in Atom. Uses the
|
||||
[autocomplete-plus](https://github.com/atom-community/autocomplete-plus) package.
|
||||
|
||||
This is powered by the list of CSS property and values [here](https://github.com/adobe/brackets/blob/master/src/extensions/default/CSSCodeHints/CSSProperties.json).
|
||||
|
||||
![css-completions](https://cloud.githubusercontent.com/assets/671378/6357910/b9ecbe7c-bc1c-11e4-89b1-033e626c891f.gif)
|
||||
|
||||
You can update the prebuilt list of property names and values by running the `update.coffee` file at the root of the repository and then checking in the changed `properties.json` file.
|
||||
|
||||
`sorted-property-names.json` is updated manually - take a look at https://developer.microsoft.com/en-us/microsoft-edge/platform/usage/ and https://www.chromestatus.com/metrics/css/popularity for guidance.
|
37
packages/autocomplete-css/coffeelint.json
Normal file
37
packages/autocomplete-css/coffeelint.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"max_line_length": {
|
||||
"level": "ignore"
|
||||
},
|
||||
"no_empty_param_list": {
|
||||
"level": "error"
|
||||
},
|
||||
"arrow_spacing": {
|
||||
"level": "error"
|
||||
},
|
||||
"no_interpolation_in_single_quotes": {
|
||||
"level": "error"
|
||||
},
|
||||
"no_debugger": {
|
||||
"level": "error"
|
||||
},
|
||||
"prefer_english_operator": {
|
||||
"level": "error"
|
||||
},
|
||||
"colon_assignment_spacing": {
|
||||
"spacing": {
|
||||
"left": 0,
|
||||
"right": 1
|
||||
},
|
||||
"level": "error"
|
||||
},
|
||||
"braces_spacing": {
|
||||
"spaces": 0,
|
||||
"level": "error"
|
||||
},
|
||||
"spacing_after_comma": {
|
||||
"level": "error"
|
||||
},
|
||||
"no_stand_alone_at": {
|
||||
"level": "error"
|
||||
}
|
||||
}
|
2225
packages/autocomplete-css/completions.json
Normal file
2225
packages/autocomplete-css/completions.json
Normal file
File diff suppressed because it is too large
Load Diff
85
packages/autocomplete-css/fetch-property-docs.coffee
Normal file
85
packages/autocomplete-css/fetch-property-docs.coffee
Normal file
@ -0,0 +1,85 @@
|
||||
path = require 'path'
|
||||
fs = require 'fs'
|
||||
request = require 'request'
|
||||
|
||||
mdnCSSURL = 'https://developer.mozilla.org/en-US/docs/Web/CSS'
|
||||
mdnJSONAPI = 'https://developer.mozilla.org/en-US/search.json?topic=css&highlight=false'
|
||||
PropertiesURL = 'https://raw.githubusercontent.com/adobe/brackets/master/src/extensions/default/CSSCodeHints/CSSProperties.json'
|
||||
|
||||
fetch = ->
|
||||
propertiesPromise = new Promise (resolve) ->
|
||||
request {json: true, url: PropertiesURL}, (error, response, properties) ->
|
||||
if error?
|
||||
console.error(error.message)
|
||||
resolve(null)
|
||||
|
||||
if response.statusCode isnt 200
|
||||
console.error("Request for CSSProperties.json failed: #{response.statusCode}")
|
||||
resolve(null)
|
||||
|
||||
resolve(properties)
|
||||
|
||||
propertiesPromise.then (properties) ->
|
||||
return unless properties?
|
||||
|
||||
MAX = 10
|
||||
queue = Object.keys(properties)
|
||||
running = []
|
||||
docs = {}
|
||||
|
||||
new Promise (resolve) ->
|
||||
checkEnd = ->
|
||||
resolve(docs) if queue.length is 0 and running.length is 0
|
||||
|
||||
removeRunning = (propertyName) ->
|
||||
index = running.indexOf(propertyName)
|
||||
running.splice(index, 1) if index > -1
|
||||
|
||||
runNext = ->
|
||||
checkEnd()
|
||||
if queue.length isnt 0
|
||||
propertyName = queue.pop()
|
||||
running.push(propertyName)
|
||||
run(propertyName)
|
||||
|
||||
run = (propertyName) ->
|
||||
url = "#{mdnJSONAPI}&q=#{propertyName}"
|
||||
request {json: true, url}, (error, response, searchResults) ->
|
||||
if not error? and response.statusCode is 200
|
||||
handleRequest(propertyName, searchResults)
|
||||
else
|
||||
console.error "Req failed #{url}; #{response.statusCode}, #{error}"
|
||||
removeRunning(propertyName)
|
||||
checkEnd()
|
||||
runNext()
|
||||
|
||||
handleRequest = (propertyName, searchResults) ->
|
||||
if searchResults.documents?
|
||||
for doc in searchResults.documents
|
||||
if doc.url is "#{mdnCSSURL}/#{propertyName}"
|
||||
docs[propertyName] = filterExcerpt(propertyName, doc.excerpt)
|
||||
break
|
||||
return
|
||||
|
||||
runNext() for [0..MAX]
|
||||
return
|
||||
|
||||
filterExcerpt = (propertyName, excerpt) ->
|
||||
beginningPattern = /^the (css )?[a-z-]+ (css )?property (is )?(\w+)/i
|
||||
excerpt = excerpt.replace beginningPattern, (match) ->
|
||||
matches = beginningPattern.exec(match)
|
||||
firstWord = matches[4]
|
||||
firstWord[0].toUpperCase() + firstWord.slice(1)
|
||||
periodIndex = excerpt.indexOf('.')
|
||||
excerpt = excerpt.slice(0, periodIndex + 1) if periodIndex > -1
|
||||
excerpt
|
||||
|
||||
# Save a file if run from the command line
|
||||
if require.main is module
|
||||
fetch().then (docs) ->
|
||||
if docs?
|
||||
fs.writeFileSync(path.join(__dirname, 'property-docs.json'), "#{JSON.stringify(docs, null, ' ')}\n")
|
||||
else
|
||||
console.error 'No docs'
|
||||
|
||||
module.exports = fetch
|
114
packages/autocomplete-css/html-tags.json
Normal file
114
packages/autocomplete-css/html-tags.json
Normal file
@ -0,0 +1,114 @@
|
||||
[
|
||||
"a",
|
||||
"b",
|
||||
"blockquote",
|
||||
"body",
|
||||
"br",
|
||||
"button",
|
||||
"canvas",
|
||||
"code",
|
||||
"div",
|
||||
"em",
|
||||
"form",
|
||||
"footer",
|
||||
"h1",
|
||||
"h2",
|
||||
"h3",
|
||||
"h4",
|
||||
"h5",
|
||||
"h6",
|
||||
"head",
|
||||
"header",
|
||||
"hgroup",
|
||||
"hr",
|
||||
"html",
|
||||
"i",
|
||||
"iframe",
|
||||
"img",
|
||||
"input",
|
||||
"label",
|
||||
"li",
|
||||
"nav",
|
||||
"ol",
|
||||
"p",
|
||||
"pre",
|
||||
"select",
|
||||
"span",
|
||||
"strong",
|
||||
"sub",
|
||||
"summary",
|
||||
"table",
|
||||
"td",
|
||||
"textarea",
|
||||
"th",
|
||||
"title",
|
||||
"tr",
|
||||
"ul",
|
||||
"abbr",
|
||||
"address",
|
||||
"area",
|
||||
"article",
|
||||
"aside",
|
||||
"audio",
|
||||
"base",
|
||||
"bdi",
|
||||
"bdo",
|
||||
"big",
|
||||
"caption",
|
||||
"cite",
|
||||
"col",
|
||||
"colgroup",
|
||||
"command",
|
||||
"datalist",
|
||||
"dd",
|
||||
"del",
|
||||
"details",
|
||||
"dfn",
|
||||
"dialog",
|
||||
"dl",
|
||||
"dt",
|
||||
"embed",
|
||||
"fieldset",
|
||||
"figcaption",
|
||||
"figure",
|
||||
"ilayer",
|
||||
"ins",
|
||||
"kbd",
|
||||
"keygen",
|
||||
"legend",
|
||||
"link",
|
||||
"main",
|
||||
"map",
|
||||
"mark",
|
||||
"marquee",
|
||||
"menu",
|
||||
"meta",
|
||||
"meter",
|
||||
"noscript",
|
||||
"object",
|
||||
"optgroup",
|
||||
"option",
|
||||
"output",
|
||||
"param",
|
||||
"progress",
|
||||
"q",
|
||||
"rp",
|
||||
"rt",
|
||||
"ruby",
|
||||
"samp",
|
||||
"script",
|
||||
"section",
|
||||
"small",
|
||||
"source",
|
||||
"style",
|
||||
"sup",
|
||||
"tbody",
|
||||
"tfoot",
|
||||
"thead",
|
||||
"time",
|
||||
"track",
|
||||
"tt",
|
||||
"var",
|
||||
"video",
|
||||
"wbr"
|
||||
]
|
6
packages/autocomplete-css/lib/main.coffee
Normal file
6
packages/autocomplete-css/lib/main.coffee
Normal file
@ -0,0 +1,6 @@
|
||||
provider = require './provider'
|
||||
|
||||
module.exports =
|
||||
activate: ->
|
||||
|
||||
getProvider: -> provider
|
318
packages/autocomplete-css/lib/provider.coffee
Normal file
318
packages/autocomplete-css/lib/provider.coffee
Normal file
@ -0,0 +1,318 @@
|
||||
COMPLETIONS = require('../completions.json')
|
||||
|
||||
firstInlinePropertyNameWithColonPattern = /{\s*(\S+)\s*:/ # .example { display: }
|
||||
inlinePropertyNameWithColonPattern = /(?:;.+?)*;\s*(\S+)\s*:/ # .example { display: block; float: left; color: } (match the last one)
|
||||
propertyNameWithColonPattern = /^\s*(\S+)\s*:/ # display:
|
||||
propertyNamePrefixPattern = /[a-zA-Z]+[-a-zA-Z]*$/
|
||||
pseudoSelectorPrefixPattern = /:(:)?([a-z]+[a-z-]*)?$/
|
||||
tagSelectorPrefixPattern = /(^|\s|,)([a-z]+)?$/
|
||||
importantPrefixPattern = /(![a-z]+)$/
|
||||
cssDocsURL = "https://developer.mozilla.org/en-US/docs/Web/CSS"
|
||||
|
||||
module.exports =
|
||||
selector: '.source.css, .source.sass, .source.css.postcss'
|
||||
disableForSelector: '.source.css .comment, .source.css .string, .source.sass .comment, .source.sass .string, .source.css.postcss .comment, source.css.postcss .string'
|
||||
properties: COMPLETIONS.properties
|
||||
pseudoSelectors: COMPLETIONS.pseudoSelectors
|
||||
tags: COMPLETIONS.tags
|
||||
|
||||
# Tell autocomplete to fuzzy filter the results of getSuggestions(). We are
|
||||
# still filtering by the first character of the prefix in this provider for
|
||||
# efficiency.
|
||||
filterSuggestions: true
|
||||
|
||||
getSuggestions: (request) ->
|
||||
completions = null
|
||||
scopes = request.scopeDescriptor.getScopesArray()
|
||||
isSass = hasScope(scopes, 'source.sass', true)
|
||||
|
||||
if @isCompletingValue(request)
|
||||
completions = @getPropertyValueCompletions(request)
|
||||
else if @isCompletingPseudoSelector(request)
|
||||
completions = @getPseudoSelectorCompletions(request)
|
||||
else
|
||||
if isSass and @isCompletingNameOrTag(request)
|
||||
completions = @getPropertyNameCompletions(request)
|
||||
.concat(@getTagCompletions(request))
|
||||
else if not isSass and @isCompletingName(request)
|
||||
completions = @getPropertyNameCompletions(request)
|
||||
|
||||
if not isSass and @isCompletingTagSelector(request)
|
||||
tagCompletions = @getTagCompletions(request)
|
||||
if tagCompletions?.length
|
||||
completions ?= []
|
||||
completions = completions.concat(tagCompletions)
|
||||
|
||||
completions
|
||||
|
||||
onDidInsertSuggestion: ({editor, suggestion}) ->
|
||||
setTimeout(@triggerAutocomplete.bind(this, editor), 1) if suggestion.type is 'property'
|
||||
|
||||
triggerAutocomplete: (editor) ->
|
||||
atom.commands.dispatch(atom.views.getView(editor), 'autocomplete-plus:activate', {activatedManually: false})
|
||||
|
||||
isCompletingValue: ({scopeDescriptor, bufferPosition, prefix, editor}) ->
|
||||
scopes = scopeDescriptor.getScopesArray()
|
||||
|
||||
beforePrefixBufferPosition = [bufferPosition.row, Math.max(0, bufferPosition.column - prefix.length - 1)]
|
||||
beforePrefixScopes = editor.scopeDescriptorForBufferPosition(beforePrefixBufferPosition)
|
||||
beforePrefixScopesArray = beforePrefixScopes.getScopesArray()
|
||||
|
||||
previousBufferPosition = [bufferPosition.row, Math.max(0, bufferPosition.column - 1)]
|
||||
previousScopes = editor.scopeDescriptorForBufferPosition(previousBufferPosition)
|
||||
previousScopesArray = previousScopes.getScopesArray()
|
||||
|
||||
(hasScope(scopes, 'meta.property-list.css') and prefix.trim() is ":") or
|
||||
(hasScope(previousScopesArray, 'meta.property-value.css')) or
|
||||
(hasScope(scopes, 'meta.property-list.scss') and prefix.trim() is ":") or
|
||||
(hasScope(previousScopesArray, 'meta.property-value.scss')) or
|
||||
(hasScope(scopes, 'meta.property-list.postcss') and prefix.trim() is ":") or
|
||||
(hasScope(previousScopesArray, 'meta.property-value.postcss')) or
|
||||
(hasScope(scopes, 'source.sass', true) and (hasScope(scopes, 'meta.property-value.sass') or
|
||||
(not hasScope(beforePrefixScopesArray, 'entity.name.tag.css') and prefix.trim() is ":")
|
||||
))
|
||||
|
||||
isCompletingName: ({scopeDescriptor, bufferPosition, prefix, editor}) ->
|
||||
scopes = scopeDescriptor.getScopesArray()
|
||||
isAtTerminator = prefix.endsWith(';')
|
||||
isAtParentSymbol = prefix.endsWith('&')
|
||||
isVariable = hasScope(scopes, 'variable.css') or
|
||||
hasScope(scopes, 'variable.scss') or
|
||||
hasScope(scopes, 'variable.var.postcss')
|
||||
isInPropertyList = not isAtTerminator and
|
||||
(hasScope(scopes, 'meta.property-list.css') or
|
||||
hasScope(scopes, 'meta.property-list.scss') or
|
||||
hasScope(scopes, 'meta.property-list.postcss'))
|
||||
|
||||
return false unless isInPropertyList
|
||||
return false if isAtParentSymbol or isVariable
|
||||
|
||||
previousBufferPosition = [bufferPosition.row, Math.max(0, bufferPosition.column - prefix.length - 1)]
|
||||
previousScopes = editor.scopeDescriptorForBufferPosition(previousBufferPosition)
|
||||
previousScopesArray = previousScopes.getScopesArray()
|
||||
|
||||
return false if hasScope(previousScopesArray, 'entity.other.attribute-name.class.css') or
|
||||
hasScope(previousScopesArray, 'entity.other.attribute-name.id.css') or
|
||||
hasScope(previousScopesArray, 'entity.other.attribute-name.id') or
|
||||
hasScope(previousScopesArray, 'entity.other.attribute-name.parent-selector.css') or
|
||||
hasScope(previousScopesArray, 'entity.name.tag.reference.scss') or
|
||||
hasScope(previousScopesArray, 'entity.name.tag.scss') or
|
||||
hasScope(previousScopesArray, 'entity.name.tag.reference.postcss') or
|
||||
hasScope(previousScopesArray, 'entity.name.tag.postcss')
|
||||
|
||||
isAtBeginScopePunctuation = hasScope(scopes, 'punctuation.section.property-list.begin.bracket.curly.css') or
|
||||
hasScope(scopes, 'punctuation.section.property-list.begin.bracket.curly.scss') or
|
||||
hasScope(scopes, 'punctuation.section.property-list.begin.postcss')
|
||||
isAtEndScopePunctuation = hasScope(scopes, 'punctuation.section.property-list.end.bracket.curly.css') or
|
||||
hasScope(scopes, 'punctuation.section.property-list.end.bracket.curly.scss') or
|
||||
hasScope(scopes, 'punctuation.section.property-list.end.postcss')
|
||||
|
||||
if isAtBeginScopePunctuation
|
||||
# * Disallow here: `canvas,|{}`
|
||||
# * Allow here: `canvas,{| }`
|
||||
prefix.endsWith('{')
|
||||
else if isAtEndScopePunctuation
|
||||
# * Disallow here: `canvas,{}|`
|
||||
# * Allow here: `canvas,{ |}`
|
||||
not prefix.endsWith('}')
|
||||
else
|
||||
true
|
||||
|
||||
isCompletingNameOrTag: ({scopeDescriptor, bufferPosition, editor}) ->
|
||||
scopes = scopeDescriptor.getScopesArray()
|
||||
prefix = @getPropertyNamePrefix(bufferPosition, editor)
|
||||
return @isPropertyNamePrefix(prefix) and
|
||||
hasScope(scopes, 'meta.selector.css') and
|
||||
not hasScope(scopes, 'entity.other.attribute-name.id.css.sass') and
|
||||
not hasScope(scopes, 'entity.other.attribute-name.class.sass')
|
||||
|
||||
isCompletingTagSelector: ({editor, scopeDescriptor, bufferPosition}) ->
|
||||
scopes = scopeDescriptor.getScopesArray()
|
||||
tagSelectorPrefix = @getTagSelectorPrefix(editor, bufferPosition)
|
||||
return false unless tagSelectorPrefix?.length
|
||||
|
||||
previousBufferPosition = [bufferPosition.row, Math.max(0, bufferPosition.column - 1)]
|
||||
previousScopes = editor.scopeDescriptorForBufferPosition(previousBufferPosition)
|
||||
previousScopesArray = previousScopes.getScopesArray()
|
||||
|
||||
if hasScope(scopes, 'meta.selector.css') or hasScope(previousScopesArray, 'meta.selector.css')
|
||||
true
|
||||
else if hasScope(scopes, 'source.css.scss', true) or hasScope(scopes, 'source.css.less', true) or hasScope(scopes, 'source.css.postcss', true)
|
||||
not hasScope(previousScopesArray, 'meta.property-value.scss') and
|
||||
not hasScope(previousScopesArray, 'meta.property-value.css') and
|
||||
not hasScope(previousScopesArray, 'meta.property-value.postcss') and
|
||||
not hasScope(previousScopesArray, 'support.type.property-value.css')
|
||||
else
|
||||
false
|
||||
|
||||
isCompletingPseudoSelector: ({editor, scopeDescriptor, bufferPosition}) ->
|
||||
scopes = scopeDescriptor.getScopesArray()
|
||||
previousBufferPosition = [bufferPosition.row, Math.max(0, bufferPosition.column - 1)]
|
||||
previousScopes = editor.scopeDescriptorForBufferPosition(previousBufferPosition)
|
||||
previousScopesArray = previousScopes.getScopesArray()
|
||||
if (hasScope(scopes, 'meta.selector.css') or hasScope(previousScopesArray, 'meta.selector.css')) and not hasScope(scopes, 'source.sass', true)
|
||||
true
|
||||
else if hasScope(scopes, 'source.css.scss', true) or hasScope(scopes, 'source.css.less', true) or hasScope(scopes, 'source.sass', true) or hasScope(scopes, 'source.css.postcss', true)
|
||||
prefix = @getPseudoSelectorPrefix(editor, bufferPosition)
|
||||
if prefix
|
||||
previousBufferPosition = [bufferPosition.row, Math.max(0, bufferPosition.column - prefix.length - 1)]
|
||||
previousScopes = editor.scopeDescriptorForBufferPosition(previousBufferPosition)
|
||||
previousScopesArray = previousScopes.getScopesArray()
|
||||
not hasScope(previousScopesArray, 'meta.property-name.scss') and
|
||||
not hasScope(previousScopesArray, 'meta.property-value.scss') and
|
||||
not hasScope(previousScopesArray, 'meta.property-value.postcss') and
|
||||
not hasScope(previousScopesArray, 'support.type.property-name.css') and
|
||||
not hasScope(previousScopesArray, 'support.type.property-value.css') and
|
||||
not hasScope(previousScopesArray, 'support.type.property-name.postcss')
|
||||
else
|
||||
false
|
||||
else
|
||||
false
|
||||
|
||||
isPropertyValuePrefix: (prefix) ->
|
||||
prefix = prefix.trim()
|
||||
prefix.length > 0 and prefix isnt ':'
|
||||
|
||||
isPropertyNamePrefix: (prefix) ->
|
||||
return false unless prefix?
|
||||
prefix = prefix.trim()
|
||||
prefix.length > 0 and prefix.match(/^[a-zA-Z-]+$/)
|
||||
|
||||
getImportantPrefix: (editor, bufferPosition) ->
|
||||
line = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition])
|
||||
importantPrefixPattern.exec(line)?[1]
|
||||
|
||||
getPreviousPropertyName: (bufferPosition, editor) ->
|
||||
{row, column} = bufferPosition
|
||||
while row >= 0
|
||||
line = editor.lineTextForBufferRow(row)
|
||||
line = line.substr(0, column) if row is bufferPosition.row
|
||||
propertyName = inlinePropertyNameWithColonPattern.exec(line)?[1]
|
||||
propertyName ?= firstInlinePropertyNameWithColonPattern.exec(line)?[1]
|
||||
propertyName ?= propertyNameWithColonPattern.exec(line)?[1]
|
||||
return propertyName if propertyName
|
||||
row--
|
||||
return
|
||||
|
||||
getPropertyValueCompletions: ({bufferPosition, editor, prefix, scopeDescriptor}) ->
|
||||
property = @getPreviousPropertyName(bufferPosition, editor)
|
||||
values = @properties[property]?.values
|
||||
return null unless values?
|
||||
|
||||
scopes = scopeDescriptor.getScopesArray()
|
||||
addSemicolon = not lineEndsWithSemicolon(bufferPosition, editor) and not hasScope(scopes, 'source.sass', true)
|
||||
|
||||
completions = []
|
||||
if @isPropertyValuePrefix(prefix)
|
||||
for value in values when firstCharsEqual(value, prefix)
|
||||
completions.push(@buildPropertyValueCompletion(value, property, addSemicolon))
|
||||
else if not hasScope(scopes, 'keyword.other.unit.percentage.css') and # CSS
|
||||
not hasScope(scopes, 'keyword.other.unit.scss') and # SCSS (TODO: remove in Atom 1.19.0)
|
||||
not hasScope(scopes, 'keyword.other.unit.css') # Less, Sass (TODO: remove in Atom 1.19.0)
|
||||
# Don't complete here: `width: 100%|`
|
||||
for value in values
|
||||
completions.push(@buildPropertyValueCompletion(value, property, addSemicolon))
|
||||
|
||||
if importantPrefix = @getImportantPrefix(editor, bufferPosition)
|
||||
# attention: règle dangereux
|
||||
completions.push
|
||||
type: 'keyword'
|
||||
text: '!important'
|
||||
displayText: '!important'
|
||||
replacementPrefix: importantPrefix
|
||||
description: "Forces this property to override any other declaration of the same property. Use with caution."
|
||||
descriptionMoreURL: "#{cssDocsURL}/Specificity#The_!important_exception"
|
||||
|
||||
completions
|
||||
|
||||
buildPropertyValueCompletion: (value, propertyName, addSemicolon) ->
|
||||
text = value
|
||||
text += ';' if addSemicolon
|
||||
|
||||
{
|
||||
type: 'value'
|
||||
text: text
|
||||
displayText: value
|
||||
description: "#{value} value for the #{propertyName} property"
|
||||
descriptionMoreURL: "#{cssDocsURL}/#{propertyName}#Values"
|
||||
}
|
||||
|
||||
getPropertyNamePrefix: (bufferPosition, editor) ->
|
||||
line = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition])
|
||||
propertyNamePrefixPattern.exec(line)?[0]
|
||||
|
||||
getPropertyNameCompletions: ({bufferPosition, editor, scopeDescriptor, activatedManually}) ->
|
||||
# Don't autocomplete property names in SASS on root level
|
||||
scopes = scopeDescriptor.getScopesArray()
|
||||
line = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition])
|
||||
return [] if hasScope(scopes, 'source.sass', true) and not line.match(/^(\s|\t)/)
|
||||
|
||||
prefix = @getPropertyNamePrefix(bufferPosition, editor)
|
||||
return [] unless activatedManually or prefix
|
||||
|
||||
completions = []
|
||||
for property, options of @properties when not prefix or firstCharsEqual(property, prefix)
|
||||
completions.push(@buildPropertyNameCompletion(property, prefix, options))
|
||||
completions
|
||||
|
||||
buildPropertyNameCompletion: (propertyName, prefix, {description}) ->
|
||||
type: 'property'
|
||||
text: "#{propertyName}: "
|
||||
displayText: propertyName
|
||||
replacementPrefix: prefix
|
||||
description: description
|
||||
descriptionMoreURL: "#{cssDocsURL}/#{propertyName}"
|
||||
|
||||
getPseudoSelectorPrefix: (editor, bufferPosition) ->
|
||||
line = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition])
|
||||
line.match(pseudoSelectorPrefixPattern)?[0]
|
||||
|
||||
getPseudoSelectorCompletions: ({bufferPosition, editor}) ->
|
||||
prefix = @getPseudoSelectorPrefix(editor, bufferPosition)
|
||||
return null unless prefix
|
||||
|
||||
completions = []
|
||||
for pseudoSelector, options of @pseudoSelectors when firstCharsEqual(pseudoSelector, prefix)
|
||||
completions.push(@buildPseudoSelectorCompletion(pseudoSelector, prefix, options))
|
||||
completions
|
||||
|
||||
buildPseudoSelectorCompletion: (pseudoSelector, prefix, {argument, description}) ->
|
||||
completion =
|
||||
type: 'pseudo-selector'
|
||||
replacementPrefix: prefix
|
||||
description: description
|
||||
descriptionMoreURL: "#{cssDocsURL}/#{pseudoSelector}"
|
||||
|
||||
if argument?
|
||||
completion.snippet = "#{pseudoSelector}(${1:#{argument}})"
|
||||
else
|
||||
completion.text = pseudoSelector
|
||||
completion
|
||||
|
||||
getTagSelectorPrefix: (editor, bufferPosition) ->
|
||||
line = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition])
|
||||
tagSelectorPrefixPattern.exec(line)?[2]
|
||||
|
||||
getTagCompletions: ({bufferPosition, editor, prefix}) ->
|
||||
completions = []
|
||||
if prefix
|
||||
for tag in @tags when firstCharsEqual(tag, prefix)
|
||||
completions.push(@buildTagCompletion(tag))
|
||||
completions
|
||||
|
||||
buildTagCompletion: (tag) ->
|
||||
type: 'tag'
|
||||
text: tag
|
||||
description: "Selector for <#{tag}> elements"
|
||||
|
||||
lineEndsWithSemicolon = (bufferPosition, editor) ->
|
||||
{row} = bufferPosition
|
||||
line = editor.lineTextForBufferRow(row)
|
||||
/;\s*$/.test(line)
|
||||
|
||||
hasScope = (scopesArray, scope, checkEmbedded = false) ->
|
||||
scopesArray.indexOf(scope) isnt -1 or
|
||||
(checkEmbedded and scopesArray.indexOf("#{scope}.embedded.html") isnt -1)
|
||||
|
||||
firstCharsEqual = (str1, str2) ->
|
||||
str1[0].toLowerCase() is str2[0].toLowerCase()
|
22
packages/autocomplete-css/package.json
Normal file
22
packages/autocomplete-css/package.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "autocomplete-css",
|
||||
"version": "0.17.5",
|
||||
"description": "CSS property name and value autocompletions",
|
||||
"main": "./lib/main",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/atom/autocomplete-css",
|
||||
"engines": {
|
||||
"atom": ">=0.174.0 <2.0.0"
|
||||
},
|
||||
"providedServices": {
|
||||
"autocomplete.provider": {
|
||||
"versions": {
|
||||
"2.0.0": "getProvider"
|
||||
}
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"coffeelint": "^1.9.7",
|
||||
"request": "^2.53.0"
|
||||
}
|
||||
}
|
138
packages/autocomplete-css/pseudo-selectors.json
Normal file
138
packages/autocomplete-css/pseudo-selectors.json
Normal file
@ -0,0 +1,138 @@
|
||||
{
|
||||
"::after": {
|
||||
"description": "Matches a virtual last child of the selected element."
|
||||
},
|
||||
"::before": {
|
||||
"description": "Creates a pseudo-element that is the first child of the element matched."
|
||||
},
|
||||
"::first-letter": {
|
||||
"description": "Matches the first letter of the first line of a block, if it is not preceded by any other content."
|
||||
},
|
||||
"::first-line": {
|
||||
"description": "Applies styles only to the first line of an element."
|
||||
},
|
||||
"::selection": {
|
||||
"description": "Applies rules to the portion of a document that has been highlighted."
|
||||
},
|
||||
":active": {
|
||||
"description": "Matches when an element is being activated by the user."
|
||||
},
|
||||
":checked": {
|
||||
"description": "Matches any radio input, checkbox input or option element that is checked or toggled to an on state."
|
||||
},
|
||||
":default": {
|
||||
"description": "Matches any user interface element that is the default among a group of similar elements"
|
||||
},
|
||||
":dir": {
|
||||
"argument": "direction",
|
||||
"description": "Matches elements based on the directionality of the text contained in it."
|
||||
},
|
||||
":disabled": {
|
||||
"description": "Matches any disabled element."
|
||||
},
|
||||
":empty": {
|
||||
"description": "Matches any element that has no children at all."
|
||||
},
|
||||
":enabled": {
|
||||
"description": "Matches any enabled element."
|
||||
},
|
||||
":first": {
|
||||
"description": "Describes the styling of the first page when printing a document."
|
||||
},
|
||||
":first-child": {
|
||||
"description": "Matches any element that is the first child element of its parent."
|
||||
},
|
||||
":first-of-type": {
|
||||
"description": "Matches the first sibling of its type in the list of children of its parent element."
|
||||
},
|
||||
":focus": {
|
||||
"description": "Matches an element that has focus."
|
||||
},
|
||||
":fullscreen": {
|
||||
"description": "Applies to any element that's currently being displayed in full-screen mode."
|
||||
},
|
||||
":hover": {
|
||||
"description": "Matches when the user designates an element with a pointing device, but does not necessarily activate it."
|
||||
},
|
||||
":indeterminate": {
|
||||
"description": "Matches any checkbox input whose indeterminate DOM property is set to true by JavaScript."
|
||||
},
|
||||
":invalid": {
|
||||
"description": "Matches any <input> or <form> element whose content fails to validate according to the input's type setting."
|
||||
},
|
||||
":lang": {
|
||||
"argument": "language",
|
||||
"description": "Matches elements based on the language the element is determined to be in."
|
||||
},
|
||||
":last-child": {
|
||||
"description": "Matches any element that is the last child element of its parent."
|
||||
},
|
||||
":last-of-type": {
|
||||
"description": "Matches the last sibling with the given element name in the list of children of its parent element."
|
||||
},
|
||||
":left": {
|
||||
"description": "Matches any left page when printing a page."
|
||||
},
|
||||
":link": {
|
||||
"description": "Matches links inside elements."
|
||||
},
|
||||
":not": {
|
||||
"argument": "selector",
|
||||
"description": "Matches an element that is not represented by the argument."
|
||||
},
|
||||
":nth-child": {
|
||||
"argument": "an+b",
|
||||
"description": "Matches an element that has an+b-1 siblings before it in the document tree."
|
||||
},
|
||||
":nth-last-child": {
|
||||
"argument": "an+b",
|
||||
"description": "Matches an element that has an+b-1 siblings after it in the document tree."
|
||||
},
|
||||
":nth-last-of-type": {
|
||||
"argument": "an+b",
|
||||
"description": "Matches an element that has an+b-1 siblings with the same element name after it in the document tree."
|
||||
},
|
||||
":nth-of-type": {
|
||||
"argument": "an+b",
|
||||
"description": "Matches an element that has an+b-1 siblings with the same element name before it in the document tree"
|
||||
},
|
||||
":only-child": {
|
||||
"description": "Matches any element which is the only child of its parent."
|
||||
},
|
||||
":only-of-type": {
|
||||
"description": "Matches any element that has no siblings of the given type."
|
||||
},
|
||||
":optional": {
|
||||
"description": "Matches any <input> element that does not have the required attribute set on it."
|
||||
},
|
||||
":out-of-range": {
|
||||
"description": "Matches when an element has its value attribute outside the specified range limitations for this element."
|
||||
},
|
||||
":read-only": {
|
||||
"description": "Matches when an element is not writable by the user."
|
||||
},
|
||||
":read-write": {
|
||||
"description": "Matches when an element is editable by user like text input element."
|
||||
},
|
||||
":required": {
|
||||
"description": "Matches any <input> element that has the required attribute set on it."
|
||||
},
|
||||
":right": {
|
||||
"description": "Matches any right page when printing a page. It allows to describe the styling of right-side page."
|
||||
},
|
||||
":root": {
|
||||
"description": "Matches the root element of a tree representing the document."
|
||||
},
|
||||
":scope": {
|
||||
"description": "Matches the elements that are a reference point for selectors to match against."
|
||||
},
|
||||
":target": {
|
||||
"description": "Matches the unique element, if any, with an id matching the fragment identifier of the URI of the document."
|
||||
},
|
||||
":valid": {
|
||||
"description": "Matches any <input> or <form> element whose content validates correctly according to the input's type setting"
|
||||
},
|
||||
":visited": {
|
||||
"description": "Matches links that have been visited."
|
||||
}
|
||||
}
|
462
packages/autocomplete-css/sorted-property-names.json
Normal file
462
packages/autocomplete-css/sorted-property-names.json
Normal file
@ -0,0 +1,462 @@
|
||||
[
|
||||
"width",
|
||||
"height",
|
||||
"margin",
|
||||
"margin-left",
|
||||
"margin-right",
|
||||
"margin-top",
|
||||
"margin-bottom",
|
||||
"padding",
|
||||
"padding-left",
|
||||
"padding-right",
|
||||
"padding-top",
|
||||
"padding-bottom",
|
||||
"font",
|
||||
"font-size",
|
||||
"font-style",
|
||||
"font-weight",
|
||||
"font-family",
|
||||
"border",
|
||||
"border-radius",
|
||||
"border-top",
|
||||
"border-bottom",
|
||||
"border-left",
|
||||
"border-right",
|
||||
"border-color",
|
||||
"border-width",
|
||||
"position",
|
||||
"text-align",
|
||||
"background",
|
||||
"background-color",
|
||||
"background-position",
|
||||
"background-repeat",
|
||||
"background-image",
|
||||
"background-size",
|
||||
"background-clip",
|
||||
"right",
|
||||
"left",
|
||||
"top",
|
||||
"bottom",
|
||||
"overflow",
|
||||
"overflow-x",
|
||||
"overflow-y",
|
||||
"opacity",
|
||||
"cursor",
|
||||
"display",
|
||||
"color",
|
||||
"visibility",
|
||||
"float",
|
||||
"text-decoration",
|
||||
"line-height",
|
||||
"z-index",
|
||||
"vertical-align",
|
||||
"box-sizing",
|
||||
"clear",
|
||||
"white-space",
|
||||
"max-width",
|
||||
"outline",
|
||||
"content",
|
||||
"min-width",
|
||||
"min-height",
|
||||
"list-style",
|
||||
"box-shadow",
|
||||
"webkit-border-radius",
|
||||
"webkit-user-select",
|
||||
"webkit-box-shadow",
|
||||
"text-shadow",
|
||||
"text-indent",
|
||||
"max-height",
|
||||
"text-overflow",
|
||||
"border-style",
|
||||
"border-spacing",
|
||||
"border-collapse",
|
||||
"border-left-color",
|
||||
"border-left-style",
|
||||
"border-left-width",
|
||||
"border-right-color",
|
||||
"border-right-style",
|
||||
"border-right-width",
|
||||
"border-top-color",
|
||||
"border-top-style",
|
||||
"border-top-width",
|
||||
"border-bottom-color",
|
||||
"border-bottom-style",
|
||||
"border-bottom-width",
|
||||
"border-top-left-radius",
|
||||
"border-top-right-radius",
|
||||
"border-bottom-left-radius",
|
||||
"border-bottom-right-radius",
|
||||
"user-select",
|
||||
"text-transform",
|
||||
"webkit-transition",
|
||||
"zoom",
|
||||
"list-style-type",
|
||||
"word-wrap",
|
||||
"webkit-transform",
|
||||
"transition",
|
||||
"webkit-appearance",
|
||||
"letter-spacing",
|
||||
"transform",
|
||||
"pointer-events",
|
||||
"webkit-font-smoothing",
|
||||
"webkit-animation",
|
||||
"direction",
|
||||
"clip",
|
||||
"table-layout",
|
||||
"src",
|
||||
"webkit-tap-highlight-color",
|
||||
"resize",
|
||||
"webkit-transform-origin",
|
||||
"word-break",
|
||||
"webkit-background-clip",
|
||||
"webkit-background-size",
|
||||
"filter",
|
||||
"transform-origin",
|
||||
"font-variant",
|
||||
"webkit-filter",
|
||||
"quotes",
|
||||
"unicode-bidi",
|
||||
"word-spacing",
|
||||
"text-rendering",
|
||||
"fill",
|
||||
"webkit-backface-visibility",
|
||||
"webkit-transition-duration",
|
||||
"outline-color",
|
||||
"list-style-position",
|
||||
"webkit-box-orient",
|
||||
"webkit-animation-timing-function",
|
||||
"outline-offset",
|
||||
"webkit-transition-property",
|
||||
"webkit-animation-duration",
|
||||
"webkit-animation-name",
|
||||
"orphans",
|
||||
"outline-style",
|
||||
"outline-width",
|
||||
"flex",
|
||||
"flex-grow",
|
||||
"flex-direction",
|
||||
"flex-flow",
|
||||
"flex-wrap",
|
||||
"flex-shrink",
|
||||
"flex-basis",
|
||||
"list-style-image",
|
||||
"unicode-range",
|
||||
"align-items",
|
||||
"transition-delay",
|
||||
"webkit-animation-fill-mode",
|
||||
"transition-duration",
|
||||
"justify-content",
|
||||
"transition-property",
|
||||
"webkit-animation-iteration-count",
|
||||
"webkit-line-clamp",
|
||||
"webkit-transition-timing-function",
|
||||
"order",
|
||||
"transition-timing-function",
|
||||
"background-attachment",
|
||||
"background-position-y",
|
||||
"background-origin",
|
||||
"background-position-x",
|
||||
"backface-visibility",
|
||||
"page-break-inside",
|
||||
"page-break-after",
|
||||
"speak",
|
||||
"stroke",
|
||||
"webkit-box-flex",
|
||||
"webkit-transition-delay",
|
||||
"widows",
|
||||
"webkit-perspective",
|
||||
"stroke-width",
|
||||
"webkit-animation-direction",
|
||||
"fill-opacity",
|
||||
"webkit-box-pack",
|
||||
"webkit-user-drag",
|
||||
"overflow-wrap",
|
||||
"webkit-box-align",
|
||||
"webkit-animation-play-state",
|
||||
"counter-increment",
|
||||
"counter-reset",
|
||||
"webkit-animation-delay",
|
||||
"image-rendering",
|
||||
"perspective-origin",
|
||||
"webkit-perspective-origin",
|
||||
"perspective",
|
||||
"webkit-margin-start",
|
||||
"webkit-transform-style",
|
||||
"empty-cells",
|
||||
"stroke-opacity",
|
||||
"caption-side",
|
||||
"webkit-mask-image",
|
||||
"webkit-margin-end",
|
||||
"transform-style",
|
||||
"border-image",
|
||||
"touch-action",
|
||||
"webkit-box-ordinal-group",
|
||||
"webkit-column-count",
|
||||
"font-stretch",
|
||||
"webkit-print-color-adjust",
|
||||
"webkit-mask-size",
|
||||
"webkit-column-gap",
|
||||
"webkit-margin-top-collapse",
|
||||
"webkit-border-image",
|
||||
"will-change",
|
||||
"webkit-padding-start",
|
||||
"webkit-mask-repeat",
|
||||
"webkit-text-fill-color",
|
||||
"webkit-margin-before",
|
||||
"webkit-mask-box-image",
|
||||
"webkit-border-horizontal-spacing",
|
||||
"animation",
|
||||
"webkit-column-break-inside",
|
||||
"page-break-before",
|
||||
"webkit-margin-after",
|
||||
"webkit-user-modify",
|
||||
"webkit-font-feature-settings",
|
||||
"webkit-line-break",
|
||||
"webkit-mask-position",
|
||||
"align-self",
|
||||
"webkit-box-direction",
|
||||
"size",
|
||||
"align-content",
|
||||
"webkit-text-stroke",
|
||||
"webkit-padding-end",
|
||||
"webkit-text-stroke-width",
|
||||
"border-image-slice",
|
||||
"border-image-width",
|
||||
"webkit-column-width",
|
||||
"border-image-outset",
|
||||
"webkit-columns",
|
||||
"border-image-repeat",
|
||||
"tab-size",
|
||||
"stop-color",
|
||||
"object-fit",
|
||||
"fill-rule",
|
||||
"writing-mode",
|
||||
"clip-rule",
|
||||
"shape-rendering",
|
||||
"stroke-dasharray",
|
||||
"webkit-text-stroke-color",
|
||||
"font-kerning",
|
||||
"webkit-background-origin",
|
||||
"stroke-linecap",
|
||||
"webkit-box-reflect",
|
||||
"animation-name",
|
||||
"text-anchor",
|
||||
"animation-duration",
|
||||
"stop-opacity",
|
||||
"webkit-border-vertical-spacing",
|
||||
"webkit-perspective-origin-y",
|
||||
"border-image-source",
|
||||
"stroke-linejoin",
|
||||
"webkit-perspective-origin-x",
|
||||
"animation-fill-mode",
|
||||
"webkit-padding-before",
|
||||
"webkit-column-rule-color",
|
||||
"webkit-column-span",
|
||||
"webkit-column-rule",
|
||||
"animation-timing-function",
|
||||
"mask",
|
||||
"webkit-mask",
|
||||
"stroke-miterlimit",
|
||||
"webkit-text-security",
|
||||
"webkit-box-lines",
|
||||
"webkit-padding-after",
|
||||
"webkit-border-end",
|
||||
"webkit-text-emphasis-color",
|
||||
"webkit-border-start-color",
|
||||
"webkit-border-start-width",
|
||||
"animation-iteration-count",
|
||||
"stroke-dashoffset",
|
||||
"animation-delay",
|
||||
"webkit-rtl-ordering",
|
||||
"page",
|
||||
"webkit-margin-collapse",
|
||||
"webkit-border-start",
|
||||
"webkit-transform-origin-y",
|
||||
"webkit-writing-mode",
|
||||
"alignment-baseline",
|
||||
"dominant-baseline",
|
||||
"webkit-column-rule-style",
|
||||
"webkit-column-rule-width",
|
||||
"baseline-shift",
|
||||
"webkit-highlight",
|
||||
"font-variant-ligatures",
|
||||
"webkit-transform-origin-x",
|
||||
"webkit-app-region",
|
||||
"webkit-clip-path",
|
||||
"background-blend-mode",
|
||||
"clip-path",
|
||||
"object-position",
|
||||
"webkit-box-decoration-break",
|
||||
"x",
|
||||
"webkit-border-end-color",
|
||||
"enable-background",
|
||||
"webkit-hyphenate-character",
|
||||
"mask-type",
|
||||
"webkit-column-break-before",
|
||||
"webkit-column-break-after",
|
||||
"mix-blend-mode",
|
||||
"webkit-text-decorations-in-effect",
|
||||
"webkit-box-flex-group",
|
||||
"webkit-line-box-contain",
|
||||
"webkit-mask-composite",
|
||||
"vector-effect",
|
||||
"marker-start",
|
||||
"marker-end",
|
||||
"webkit-border-end-width",
|
||||
"webkit-mask-clip",
|
||||
"flood-color",
|
||||
"flood-opacity",
|
||||
"webkit-background-composite",
|
||||
"marker-mid",
|
||||
"webkit-mask-origin",
|
||||
"webkit-text-emphasis-style",
|
||||
"color-rendering",
|
||||
"color-interpolation-filters",
|
||||
"webkit-margin-before-collapse",
|
||||
"color-interpolation",
|
||||
"webkit-border-after-color",
|
||||
"webkit-border-before-color",
|
||||
"webkit-text-orientation",
|
||||
"webkit-border-after-width",
|
||||
"background-repeat-y",
|
||||
"webkit-border-before-width",
|
||||
"glyph-orientation-vertical",
|
||||
"lighting-color",
|
||||
"glyph-orientation-horizontal",
|
||||
"webkit-mask-box-image-source",
|
||||
"webkit-mask-box-image-repeat",
|
||||
"shape-outside",
|
||||
"webkit-mask-box-image-slice",
|
||||
"paint-order",
|
||||
"webkit-text-combine",
|
||||
"webkit-text-emphasis-position",
|
||||
"shape-margin",
|
||||
"webkit-mask-box-image-width",
|
||||
"webkit-mask-box-image-outset",
|
||||
"webkit-margin-after-collapse",
|
||||
"isolation",
|
||||
"buffered-rendering",
|
||||
"shape-image-threshold",
|
||||
"background-repeat-x",
|
||||
"animation-direction",
|
||||
"animation-play-state",
|
||||
"webkit-locale",
|
||||
"webkit-border-end-style",
|
||||
"webkit-margin-bottom-collapse",
|
||||
"all",
|
||||
"marker",
|
||||
"webkit-border-after",
|
||||
"y",
|
||||
"rx",
|
||||
"ry",
|
||||
"cx",
|
||||
"cy",
|
||||
"r",
|
||||
"webkit-border-start-style",
|
||||
"webkit-mask-position-x",
|
||||
"webkit-border-fit",
|
||||
"webkit-transform-origin-z",
|
||||
"text-justify",
|
||||
"column-fill",
|
||||
"text-align-last",
|
||||
"webkit-min-logical-height",
|
||||
"text-decoration-color",
|
||||
"webkit-min-logical-width",
|
||||
"webkit-logical-height",
|
||||
"text-decoration-style",
|
||||
"text-decoration-line",
|
||||
"webkit-mask-position-y",
|
||||
"min-zoom",
|
||||
"max-zoom",
|
||||
"webkit-max-logical-height",
|
||||
"webkit-border-before",
|
||||
"webkit-text-emphasis",
|
||||
"webkit-max-logical-width",
|
||||
"webkit-logical-width",
|
||||
"user-zoom",
|
||||
"webkit-border-after-style",
|
||||
"font-size-adjust",
|
||||
"text-underline-style",
|
||||
"orientation",
|
||||
"webkit-font-size-delta",
|
||||
"text-underline-position",
|
||||
"webkit-border-before-style",
|
||||
"text-underline-color",
|
||||
"touch-action-delay",
|
||||
"webkit-ruby-position",
|
||||
"webkit-mask-repeat-x",
|
||||
"webkit-mask-repeat-y",
|
||||
"scroll-behavior",
|
||||
"justify-self",
|
||||
"text-overline-width",
|
||||
"grid-column",
|
||||
"grid-row",
|
||||
"grid-template",
|
||||
"text-line-through-width",
|
||||
"caret-color",
|
||||
"justify-items",
|
||||
"grid-template-columns",
|
||||
"grid-auto-columns",
|
||||
"grid-auto-flow",
|
||||
"mask-source-type",
|
||||
"grid-auto-rows",
|
||||
"grid-column-start",
|
||||
"grid-template-rows",
|
||||
"scroll-blocks-on",
|
||||
"grid-row-end",
|
||||
"grid-column-end",
|
||||
"grid-row-start",
|
||||
"text-line-through-style",
|
||||
"text-line-through-mode",
|
||||
"webkit-wrap-flow",
|
||||
"webkit-wrap-through",
|
||||
"text-line-through-color",
|
||||
"text-overline-color",
|
||||
"webkit-aspect-ratio",
|
||||
"text-underline-width",
|
||||
"text-underline-mode",
|
||||
"box-decoration-break",
|
||||
"break-after",
|
||||
"break-before",
|
||||
"break-inside",
|
||||
"columns",
|
||||
"column-count",
|
||||
"column-gap",
|
||||
"column-rule",
|
||||
"column-rule-color",
|
||||
"column-rule-style",
|
||||
"column-rule-width",
|
||||
"column-span",
|
||||
"column-width",
|
||||
"flow-into",
|
||||
"flow-from",
|
||||
"font-feature-settings",
|
||||
"font-language-override",
|
||||
"font-synthesis",
|
||||
"font-variant-alternates",
|
||||
"font-variant-caps",
|
||||
"font-variant-east-asian",
|
||||
"font-variant-numeric",
|
||||
"font-variant-position",
|
||||
"hyphens",
|
||||
"image-orientation",
|
||||
"image-resolution",
|
||||
"region-break-after",
|
||||
"region-break-before",
|
||||
"region-break-inside",
|
||||
"region-fragment",
|
||||
"shape-inside",
|
||||
"text-decoration-skip",
|
||||
"text-emphasis",
|
||||
"text-emphasis-color",
|
||||
"text-emphasis-position",
|
||||
"text-emphasis-style",
|
||||
"font-display",
|
||||
"grid",
|
||||
"grid-area",
|
||||
"grid-column-gap",
|
||||
"grid-gap",
|
||||
"grid-row-gap",
|
||||
"grid-template-areas",
|
||||
"hanging-punctuation"
|
||||
]
|
907
packages/autocomplete-css/spec/provider-spec.coffee
Normal file
907
packages/autocomplete-css/spec/provider-spec.coffee
Normal file
@ -0,0 +1,907 @@
|
||||
packagesToTest =
|
||||
CSS:
|
||||
name: 'language-css'
|
||||
file: 'test.css'
|
||||
SCSS:
|
||||
name: 'language-sass'
|
||||
file: 'test.scss'
|
||||
Less:
|
||||
name: 'language-less'
|
||||
file: 'test.less'
|
||||
PostCSS:
|
||||
name: 'language-postcss'
|
||||
file: 'test.postcss'
|
||||
|
||||
Object.keys(packagesToTest).forEach (packageLabel) ->
|
||||
unless atom.packages.getAvailablePackageNames().includes(packagesToTest[packageLabel].name)
|
||||
console.warn "Skipping tests for #{packageLabel} because it is not installed"
|
||||
delete packagesToTest[packageLabel]
|
||||
|
||||
describe "CSS property name and value autocompletions", ->
|
||||
[editor, provider] = []
|
||||
|
||||
getCompletions = (options={}) ->
|
||||
cursor = editor.getLastCursor()
|
||||
start = cursor.getBeginningOfCurrentWordBufferPosition()
|
||||
end = cursor.getBufferPosition()
|
||||
prefix = editor.getTextInRange([start, end])
|
||||
request =
|
||||
editor: editor
|
||||
bufferPosition: end
|
||||
scopeDescriptor: cursor.getScopeDescriptor()
|
||||
prefix: prefix
|
||||
activatedManually: options.activatedManually ? true
|
||||
provider.getSuggestions(request)
|
||||
|
||||
beforeEach ->
|
||||
waitsForPromise -> atom.packages.activatePackage('autocomplete-css')
|
||||
waitsForPromise -> atom.packages.activatePackage('language-css') # Used in all CSS languages
|
||||
|
||||
runs ->
|
||||
provider = atom.packages.getActivePackage('autocomplete-css').mainModule.getProvider()
|
||||
|
||||
waitsFor -> Object.keys(provider.properties).length > 0
|
||||
|
||||
Object.keys(packagesToTest).forEach (packageLabel) ->
|
||||
describe "#{packageLabel} files", ->
|
||||
beforeEach ->
|
||||
waitsForPromise -> atom.packages.activatePackage(packagesToTest[packageLabel].name)
|
||||
waitsForPromise -> atom.workspace.open(packagesToTest[packageLabel].file)
|
||||
runs -> editor = atom.workspace.getActiveTextEditor()
|
||||
|
||||
it "returns tag completions when not in a property list", ->
|
||||
editor.setText('')
|
||||
expect(getCompletions()).toBe null
|
||||
|
||||
editor.setText('d')
|
||||
editor.setCursorBufferPosition([0, 0])
|
||||
expect(getCompletions()).toBe null
|
||||
|
||||
editor.setCursorBufferPosition([0, 1])
|
||||
completions = getCompletions()
|
||||
expect(completions).toHaveLength 9
|
||||
for completion in completions
|
||||
expect(completion.text.length).toBeGreaterThan 0
|
||||
expect(completion.type).toBe 'tag'
|
||||
|
||||
it "autocompletes property names without a prefix when activated manually", ->
|
||||
editor.setText """
|
||||
body {
|
||||
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 0])
|
||||
completions = getCompletions(activatedManually: true)
|
||||
expect(completions.length).toBe 237
|
||||
for completion in completions
|
||||
expect(completion.text.length).toBeGreaterThan 0
|
||||
expect(completion.type).toBe 'property'
|
||||
expect(completion.descriptionMoreURL.length).toBeGreaterThan 0
|
||||
|
||||
it "does not autocomplete property names without a prefix when not activated manually", ->
|
||||
editor.setText """
|
||||
body {
|
||||
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 0])
|
||||
completions = getCompletions(activatedManually: false)
|
||||
expect(completions).toEqual []
|
||||
|
||||
it "autocompletes property names with a prefix", ->
|
||||
editor.setText """
|
||||
body {
|
||||
d
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 3])
|
||||
completions = getCompletions()
|
||||
expect(completions[0].text).toBe 'display: '
|
||||
expect(completions[0].displayText).toBe 'display'
|
||||
expect(completions[0].type).toBe 'property'
|
||||
expect(completions[0].replacementPrefix).toBe 'd'
|
||||
expect(completions[0].description.length).toBeGreaterThan 0
|
||||
expect(completions[0].descriptionMoreURL.length).toBeGreaterThan 0
|
||||
expect(completions[1].text).toBe 'direction: '
|
||||
expect(completions[1].displayText).toBe 'direction'
|
||||
expect(completions[1].type).toBe 'property'
|
||||
expect(completions[1].replacementPrefix).toBe 'd'
|
||||
|
||||
editor.setText """
|
||||
body {
|
||||
D
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 3])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 2
|
||||
expect(completions[0].text).toBe 'display: '
|
||||
expect(completions[1].text).toBe 'direction: '
|
||||
expect(completions[1].replacementPrefix).toBe 'D'
|
||||
|
||||
editor.setText """
|
||||
body {
|
||||
d:
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 3])
|
||||
completions = getCompletions()
|
||||
expect(completions[0].text).toBe 'display: '
|
||||
expect(completions[1].text).toBe 'direction: '
|
||||
|
||||
editor.setText """
|
||||
body {
|
||||
bord
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 6])
|
||||
completions = getCompletions()
|
||||
expect(completions[0].text).toBe 'border: '
|
||||
expect(completions[0].displayText).toBe 'border'
|
||||
expect(completions[0].replacementPrefix).toBe 'bord'
|
||||
|
||||
it "does not autocomplete when at a terminator", ->
|
||||
editor.setText """
|
||||
body {
|
||||
.somemixin();
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 15])
|
||||
completions = getCompletions()
|
||||
expect(completions).toBe null
|
||||
|
||||
it "does not autocomplete property names when preceding a {", ->
|
||||
editor.setText """
|
||||
body,{
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 5])
|
||||
completions = getCompletions()
|
||||
expect(completions).toBe null
|
||||
|
||||
editor.setText """
|
||||
body,{}
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 5])
|
||||
completions = getCompletions()
|
||||
expect(completions).toBe null
|
||||
|
||||
editor.setText """
|
||||
body
|
||||
{
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 0])
|
||||
completions = getCompletions()
|
||||
expect(completions).toBe null
|
||||
|
||||
it "does not autocomplete property names when immediately after a }", ->
|
||||
editor.setText """
|
||||
body{}
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 6])
|
||||
completions = getCompletions()
|
||||
expect(completions).toBe null
|
||||
|
||||
editor.setText """
|
||||
body{
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 1])
|
||||
completions = getCompletions()
|
||||
expect(completions).toBe null
|
||||
|
||||
it "autocompletes property names when the cursor is up against the punctuation inside the property list", ->
|
||||
editor.setText """
|
||||
body {
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 6])
|
||||
completions = getCompletions()
|
||||
expect(completions[0].displayText).toBe 'width'
|
||||
|
||||
editor.setText """
|
||||
body {
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 0])
|
||||
completions = getCompletions()
|
||||
expect(completions[0].displayText).toBe 'width'
|
||||
|
||||
editor.setText """
|
||||
body { }
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 6])
|
||||
completions = getCompletions()
|
||||
expect(completions[0].displayText).toBe 'width'
|
||||
|
||||
editor.setText """
|
||||
body { }
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 7])
|
||||
completions = getCompletions()
|
||||
expect(completions[0].displayText).toBe 'width'
|
||||
|
||||
it "triggers autocomplete when an property name has been inserted", ->
|
||||
spyOn(atom.commands, 'dispatch')
|
||||
suggestion = {type: 'property', text: 'whatever'}
|
||||
provider.onDidInsertSuggestion({editor, suggestion})
|
||||
|
||||
advanceClock 1
|
||||
expect(atom.commands.dispatch).toHaveBeenCalled()
|
||||
|
||||
args = atom.commands.dispatch.mostRecentCall.args
|
||||
expect(args[0].tagName.toLowerCase()).toBe 'atom-text-editor'
|
||||
expect(args[1]).toBe 'autocomplete-plus:activate'
|
||||
|
||||
it "autocompletes property values without a prefix", ->
|
||||
editor.setText """
|
||||
body {
|
||||
display:
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 10])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 24
|
||||
for completion in completions
|
||||
expect(completion.text.length).toBeGreaterThan 0
|
||||
expect(completion.description.length).toBeGreaterThan 0
|
||||
expect(completion.descriptionMoreURL.length).toBeGreaterThan 0
|
||||
|
||||
editor.setText """
|
||||
body {
|
||||
display:
|
||||
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([2, 0])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 24
|
||||
for completion in completions
|
||||
expect(completion.text.length).toBeGreaterThan 0
|
||||
|
||||
it "autocompletes property values with a prefix", ->
|
||||
editor.setText """
|
||||
body {
|
||||
display: i
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 12])
|
||||
completions = getCompletions()
|
||||
expect(completions[0].text).toBe 'inline;'
|
||||
expect(completions[0].description.length).toBeGreaterThan 0
|
||||
expect(completions[0].descriptionMoreURL.length).toBeGreaterThan 0
|
||||
expect(completions[1].text).toBe 'inline-block;'
|
||||
expect(completions[2].text).toBe 'inline-flex;'
|
||||
expect(completions[3].text).toBe 'inline-grid;'
|
||||
expect(completions[4].text).toBe 'inline-table;'
|
||||
expect(completions[5].text).toBe 'inherit;'
|
||||
|
||||
editor.setText """
|
||||
body {
|
||||
display: I
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 12])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 6
|
||||
expect(completions[0].text).toBe 'inline;'
|
||||
expect(completions[1].text).toBe 'inline-block;'
|
||||
expect(completions[2].text).toBe 'inline-flex;'
|
||||
expect(completions[3].text).toBe 'inline-grid;'
|
||||
expect(completions[4].text).toBe 'inline-table;'
|
||||
expect(completions[5].text).toBe 'inherit;'
|
||||
|
||||
editor.setText """
|
||||
body {
|
||||
display:
|
||||
i
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([2, 5])
|
||||
completions = getCompletions()
|
||||
expect(completions[0].text).toBe 'inline;'
|
||||
expect(completions[1].text).toBe 'inline-block;'
|
||||
expect(completions[2].text).toBe 'inline-flex;'
|
||||
expect(completions[3].text).toBe 'inline-grid;'
|
||||
expect(completions[4].text).toBe 'inline-table;'
|
||||
expect(completions[5].text).toBe 'inherit;'
|
||||
|
||||
editor.setText """
|
||||
body {
|
||||
text-align:
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 13])
|
||||
completions = getCompletions()
|
||||
expect(completions).toHaveLength 5
|
||||
expect(completions[0].text).toBe 'center;'
|
||||
expect(completions[1].text).toBe 'left;'
|
||||
expect(completions[2].text).toBe 'justify;'
|
||||
expect(completions[3].text).toBe 'right;'
|
||||
expect(completions[4].text).toBe 'inherit;'
|
||||
|
||||
editor.setText """
|
||||
body {
|
||||
text-align: c
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 15])
|
||||
completions = getCompletions()
|
||||
expect(completions).toHaveLength 1
|
||||
expect(completions[0].text).toBe 'center;'
|
||||
|
||||
it "does not complete property values after percentage signs", ->
|
||||
editor.setText """
|
||||
body {
|
||||
width: 100%
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 13])
|
||||
completions = getCompletions()
|
||||
expect(completions).toHaveLength 0
|
||||
|
||||
it "it doesn't add semicolon after a property if one is already present", ->
|
||||
editor.setText """
|
||||
body {
|
||||
display: i;
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 12])
|
||||
completions = getCompletions()
|
||||
completions.forEach (completion) ->
|
||||
expect(completion.text).not.toMatch(/;\s*$/)
|
||||
|
||||
it "autocompletes inline property values", ->
|
||||
editor.setText "body { display: }"
|
||||
editor.setCursorBufferPosition([0, 16])
|
||||
completions = getCompletions()
|
||||
expect(completions).toHaveLength 24
|
||||
expect(completions[0].text).toBe 'block;'
|
||||
|
||||
editor.setText """
|
||||
body {
|
||||
display: block; float:
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 24])
|
||||
completions = getCompletions()
|
||||
expect(completions).toHaveLength 4
|
||||
expect(completions[0].text).toBe 'left;'
|
||||
|
||||
it "autocompletes more than one inline property value", ->
|
||||
editor.setText "body { display: block; float: }"
|
||||
editor.setCursorBufferPosition([0, 30])
|
||||
completions = getCompletions()
|
||||
expect(completions).toHaveLength 4
|
||||
expect(completions[0].text).toBe 'left;'
|
||||
|
||||
editor.setText "body { display: block; float: left; cursor: alias; text-decoration: }"
|
||||
editor.setCursorBufferPosition([0, 68])
|
||||
completions = getCompletions()
|
||||
expect(completions).toHaveLength 5
|
||||
expect(completions[0].text).toBe 'line-through;'
|
||||
|
||||
it "autocompletes inline property values with a prefix", ->
|
||||
editor.setText "body { display: i }"
|
||||
editor.setCursorBufferPosition([0, 17])
|
||||
completions = getCompletions()
|
||||
expect(completions).toHaveLength 6
|
||||
expect(completions[0].text).toBe 'inline;'
|
||||
expect(completions[1].text).toBe 'inline-block;'
|
||||
expect(completions[2].text).toBe 'inline-flex;'
|
||||
expect(completions[3].text).toBe 'inline-grid;'
|
||||
expect(completions[4].text).toBe 'inline-table;'
|
||||
expect(completions[5].text).toBe 'inherit;'
|
||||
|
||||
editor.setText "body { display: i}"
|
||||
editor.setCursorBufferPosition([0, 17])
|
||||
completions = getCompletions()
|
||||
expect(completions).toHaveLength 6
|
||||
expect(completions[0].text).toBe 'inline;'
|
||||
expect(completions[1].text).toBe 'inline-block;'
|
||||
expect(completions[2].text).toBe 'inline-flex;'
|
||||
expect(completions[3].text).toBe 'inline-grid;'
|
||||
expect(completions[4].text).toBe 'inline-table;'
|
||||
expect(completions[5].text).toBe 'inherit;'
|
||||
|
||||
it "autocompletes inline property values that aren't at the end of the line", ->
|
||||
editor.setText "body { float: display: inline; font-weight: bold; }"
|
||||
editor.setCursorBufferPosition([0, 14]) # right before display
|
||||
completions = getCompletions()
|
||||
expect(completions).toHaveLength 4
|
||||
expect(completions[0].text).toBe 'left;'
|
||||
expect(completions[1].text).toBe 'right;'
|
||||
expect(completions[2].text).toBe 'none;'
|
||||
expect(completions[3].text).toBe 'inherit;'
|
||||
|
||||
it "autocompletes !important in property-value scope", ->
|
||||
editor.setText """
|
||||
body {
|
||||
display: inherit !im
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 22])
|
||||
completions = getCompletions()
|
||||
|
||||
important = null
|
||||
for c in completions
|
||||
important = c if c.displayText is '!important'
|
||||
|
||||
expect(important.displayText).toBe '!important'
|
||||
|
||||
it "does not autocomplete !important in property-name scope", ->
|
||||
editor.setText """
|
||||
body {
|
||||
!im
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 5])
|
||||
completions = getCompletions()
|
||||
|
||||
important = null
|
||||
for c in completions
|
||||
important = c if c.displayText is '!important'
|
||||
|
||||
expect(important).toBe null
|
||||
|
||||
describe "tags", ->
|
||||
it "autocompletes with a prefix", ->
|
||||
editor.setText """
|
||||
ca {
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 2])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 7
|
||||
expect(completions[0].text).toBe 'canvas'
|
||||
expect(completions[0].type).toBe 'tag'
|
||||
expect(completions[0].description).toBe 'Selector for <canvas> elements'
|
||||
expect(completions[1].text).toBe 'code'
|
||||
|
||||
editor.setText """
|
||||
canvas,ca {
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 9])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 7
|
||||
expect(completions[0].text).toBe 'canvas'
|
||||
|
||||
editor.setText """
|
||||
canvas ca {
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 9])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 7
|
||||
expect(completions[0].text).toBe 'canvas'
|
||||
|
||||
editor.setText """
|
||||
canvas, ca {
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 10])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 7
|
||||
expect(completions[0].text).toBe 'canvas'
|
||||
|
||||
it "does not autocompletes when prefix is preceded by class or id char", ->
|
||||
editor.setText """
|
||||
.ca {
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 3])
|
||||
completions = getCompletions()
|
||||
expect(completions).toBe null
|
||||
|
||||
editor.setText """
|
||||
#ca {
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 3])
|
||||
completions = getCompletions()
|
||||
expect(completions).toBe null
|
||||
|
||||
describe "pseudo selectors", ->
|
||||
it "autocompletes without a prefix", ->
|
||||
editor.setText """
|
||||
div: {
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 4])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 43
|
||||
for completion in completions
|
||||
text = (completion.text or completion.snippet)
|
||||
expect(text.length).toBeGreaterThan 0
|
||||
expect(completion.type).toBe 'pseudo-selector'
|
||||
|
||||
# TODO: Enable these tests when we can enable autocomplete and test the
|
||||
# entire path.
|
||||
xit "autocompletes with a prefix", ->
|
||||
editor.setText """
|
||||
div:f {
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 5])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 5
|
||||
expect(completions[0].text).toBe ':first'
|
||||
expect(completions[0].type).toBe 'pseudo-selector'
|
||||
expect(completions[0].description.length).toBeGreaterThan 0
|
||||
expect(completions[0].descriptionMoreURL.length).toBeGreaterThan 0
|
||||
|
||||
xit "autocompletes with arguments", ->
|
||||
editor.setText """
|
||||
div:nth {
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 7])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 4
|
||||
expect(completions[0].snippet).toBe ':nth-child(${1:an+b})'
|
||||
expect(completions[0].type).toBe 'pseudo-selector'
|
||||
expect(completions[0].description.length).toBeGreaterThan 0
|
||||
expect(completions[0].descriptionMoreURL.length).toBeGreaterThan 0
|
||||
|
||||
xit "autocompletes when nothing precedes the colon", ->
|
||||
editor.setText """
|
||||
:f {
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 2])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 5
|
||||
expect(completions[0].text).toBe ':first'
|
||||
|
||||
Object.keys(packagesToTest).forEach (packageLabel) ->
|
||||
unless packagesToTest[packageLabel].name is 'language-css'
|
||||
describe "#{packageLabel} files", ->
|
||||
beforeEach ->
|
||||
waitsForPromise -> atom.packages.activatePackage(packagesToTest[packageLabel].name)
|
||||
waitsForPromise -> atom.workspace.open(packagesToTest[packageLabel].file)
|
||||
runs -> editor = atom.workspace.getActiveTextEditor()
|
||||
|
||||
it "autocompletes tags and properties when nesting inside the property list", ->
|
||||
editor.setText """
|
||||
.ca {
|
||||
di
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 4])
|
||||
completions = getCompletions()
|
||||
expect(completions[0].text).toBe 'display: '
|
||||
expect(completions[1].text).toBe 'direction: '
|
||||
expect(completions[2].text).toBe 'div'
|
||||
|
||||
# FIXME: This is an issue with the grammar. It thinks nested
|
||||
# pseudo-selectors are meta.property-value.scss/less
|
||||
xit "autocompletes pseudo selectors when nested in LESS and SCSS files", ->
|
||||
editor.setText """
|
||||
.some-class {
|
||||
.a:f
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 6])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 5
|
||||
expect(completions[0].text).toBe ':first'
|
||||
|
||||
it "does not show property names when in a class selector", ->
|
||||
editor.setText """
|
||||
body {
|
||||
.a
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 4])
|
||||
completions = getCompletions()
|
||||
expect(completions).toBe null
|
||||
|
||||
it "does not show property names when in an id selector", ->
|
||||
editor.setText """
|
||||
body {
|
||||
#a
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 4])
|
||||
completions = getCompletions()
|
||||
expect(completions).toBe null
|
||||
|
||||
it "does not show property names when in a parent selector", ->
|
||||
editor.setText """
|
||||
body {
|
||||
&
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 4])
|
||||
completions = getCompletions()
|
||||
expect(completions).toBe null
|
||||
|
||||
it "does not show property names when in a parent selector with a prefix", ->
|
||||
editor.setText """
|
||||
body {
|
||||
&a
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 4])
|
||||
completions = getCompletions()
|
||||
expect(completions).toBe null
|
||||
|
||||
describe "SASS files", ->
|
||||
beforeEach ->
|
||||
waitsForPromise -> atom.packages.activatePackage('language-sass')
|
||||
waitsForPromise -> atom.workspace.open('test.sass')
|
||||
runs -> editor = atom.workspace.getActiveTextEditor()
|
||||
|
||||
it "autocompletes property names with a prefix", ->
|
||||
editor.setText """
|
||||
body
|
||||
d
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 3])
|
||||
completions = getCompletions()
|
||||
expect(completions[0].text).toBe 'display: '
|
||||
expect(completions[0].displayText).toBe 'display'
|
||||
expect(completions[0].type).toBe 'property'
|
||||
expect(completions[0].replacementPrefix).toBe 'd'
|
||||
expect(completions[0].description.length).toBeGreaterThan 0
|
||||
expect(completions[0].descriptionMoreURL.length).toBeGreaterThan 0
|
||||
expect(completions[1].text).toBe 'direction: '
|
||||
expect(completions[1].displayText).toBe 'direction'
|
||||
expect(completions[1].type).toBe 'property'
|
||||
expect(completions[1].replacementPrefix).toBe 'd'
|
||||
|
||||
editor.setText """
|
||||
body
|
||||
D
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 3])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 11
|
||||
expect(completions[0].text).toBe 'display: '
|
||||
expect(completions[1].text).toBe 'direction: '
|
||||
expect(completions[1].replacementPrefix).toBe 'D'
|
||||
|
||||
editor.setText """
|
||||
body
|
||||
d:
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 3])
|
||||
completions = getCompletions()
|
||||
expect(completions[0].text).toBe 'display: '
|
||||
expect(completions[1].text).toBe 'direction: '
|
||||
|
||||
editor.setText """
|
||||
body
|
||||
bord
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 6])
|
||||
completions = getCompletions()
|
||||
expect(completions[0].text).toBe 'border: '
|
||||
expect(completions[0].displayText).toBe 'border'
|
||||
expect(completions[0].replacementPrefix).toBe 'bord'
|
||||
|
||||
it "triggers autocomplete when an property name has been inserted", ->
|
||||
spyOn(atom.commands, 'dispatch')
|
||||
suggestion = {type: 'property', text: 'whatever'}
|
||||
provider.onDidInsertSuggestion({editor, suggestion})
|
||||
|
||||
advanceClock 1
|
||||
expect(atom.commands.dispatch).toHaveBeenCalled()
|
||||
|
||||
args = atom.commands.dispatch.mostRecentCall.args
|
||||
expect(args[0].tagName.toLowerCase()).toBe 'atom-text-editor'
|
||||
expect(args[1]).toBe 'autocomplete-plus:activate'
|
||||
|
||||
it "autocompletes property values without a prefix", ->
|
||||
editor.setText """
|
||||
body
|
||||
display:
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 10])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 24
|
||||
for completion in completions
|
||||
expect(completion.text.length).toBeGreaterThan 0
|
||||
expect(completion.description.length).toBeGreaterThan 0
|
||||
expect(completion.descriptionMoreURL.length).toBeGreaterThan 0
|
||||
|
||||
editor.setText """
|
||||
body
|
||||
display:
|
||||
"""
|
||||
editor.setCursorBufferPosition([2, 0])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 24
|
||||
for completion in completions
|
||||
expect(completion.text.length).toBeGreaterThan 0
|
||||
|
||||
it "autocompletes property values with a prefix", ->
|
||||
editor.setText """
|
||||
body
|
||||
display: i
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 12])
|
||||
completions = getCompletions()
|
||||
expect(completions[0].text).toBe 'inline'
|
||||
expect(completions[0].description.length).toBeGreaterThan 0
|
||||
expect(completions[0].descriptionMoreURL.length).toBeGreaterThan 0
|
||||
expect(completions[1].text).toBe 'inline-block'
|
||||
expect(completions[2].text).toBe 'inline-flex'
|
||||
expect(completions[3].text).toBe 'inline-grid'
|
||||
expect(completions[4].text).toBe 'inline-table'
|
||||
expect(completions[5].text).toBe 'inherit'
|
||||
|
||||
editor.setText """
|
||||
body
|
||||
display: I
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 12])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 6
|
||||
expect(completions[0].text).toBe 'inline'
|
||||
expect(completions[1].text).toBe 'inline-block'
|
||||
expect(completions[2].text).toBe 'inline-flex'
|
||||
expect(completions[3].text).toBe 'inline-grid'
|
||||
expect(completions[4].text).toBe 'inline-table'
|
||||
expect(completions[5].text).toBe 'inherit'
|
||||
|
||||
it "autocompletes !important in property-value scope", ->
|
||||
editor.setText """
|
||||
body
|
||||
display: inherit !im
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 22])
|
||||
completions = getCompletions()
|
||||
|
||||
important = null
|
||||
for c in completions
|
||||
important = c if c.displayText is '!important'
|
||||
|
||||
expect(important.displayText).toBe '!important'
|
||||
|
||||
it "does not autocomplete when indented and prefix is not a char", ->
|
||||
editor.setText """
|
||||
body
|
||||
.
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 3])
|
||||
completions = getCompletions(activatedManually: false)
|
||||
expect(completions).toBe null
|
||||
|
||||
editor.setText """
|
||||
body
|
||||
#
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 3])
|
||||
completions = getCompletions(activatedManually: false)
|
||||
expect(completions).toBe null
|
||||
|
||||
editor.setText """
|
||||
body
|
||||
.foo,
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 7])
|
||||
completions = getCompletions(activatedManually: false)
|
||||
expect(completions).toBe null
|
||||
|
||||
editor.setText """
|
||||
body
|
||||
foo -
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 8])
|
||||
completions = getCompletions(activatedManually: false)
|
||||
expect(completions).toBe null
|
||||
|
||||
# As spaces at end of line will be removed, we'll test with a char
|
||||
# after the space and with the cursor before that char.
|
||||
editor.setCursorBufferPosition([1, 7])
|
||||
completions = getCompletions(activatedManually: false)
|
||||
expect(completions).toBe null
|
||||
|
||||
it 'does not autocomplete when inside a nth-child selector', ->
|
||||
editor.setText """
|
||||
body
|
||||
&:nth-child(4
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 15])
|
||||
completions = getCompletions(activatedManually: false)
|
||||
expect(completions).toBe null
|
||||
|
||||
it 'autocompletes a property name with a dash', ->
|
||||
editor.setText """
|
||||
body
|
||||
border-
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 9])
|
||||
completions = getCompletions(activatedManually: false)
|
||||
expect(completions).not.toBe null
|
||||
|
||||
expect(completions[0].text).toBe 'border: '
|
||||
expect(completions[0].displayText).toBe 'border'
|
||||
expect(completions[0].replacementPrefix).toBe 'border-'
|
||||
|
||||
expect(completions[1].text).toBe 'border-radius: '
|
||||
expect(completions[1].displayText).toBe 'border-radius'
|
||||
expect(completions[1].replacementPrefix).toBe 'border-'
|
||||
|
||||
it "does not autocomplete !important in property-name scope", ->
|
||||
editor.setText """
|
||||
body {
|
||||
!im
|
||||
}
|
||||
"""
|
||||
editor.setCursorBufferPosition([1, 5])
|
||||
completions = getCompletions()
|
||||
|
||||
important = null
|
||||
for c in completions
|
||||
important = c if c.displayText is '!important'
|
||||
|
||||
expect(important).toBe null
|
||||
|
||||
describe "tags", ->
|
||||
it "autocompletes with a prefix", ->
|
||||
editor.setText """
|
||||
ca
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 2])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 7
|
||||
expect(completions[0].text).toBe 'canvas'
|
||||
expect(completions[0].type).toBe 'tag'
|
||||
expect(completions[0].description).toBe 'Selector for <canvas> elements'
|
||||
expect(completions[1].text).toBe 'code'
|
||||
|
||||
editor.setText """
|
||||
canvas,ca
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 9])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 7
|
||||
expect(completions[0].text).toBe 'canvas'
|
||||
|
||||
editor.setText """
|
||||
canvas ca
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 9])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 7
|
||||
expect(completions[0].text).toBe 'canvas'
|
||||
|
||||
editor.setText """
|
||||
canvas, ca
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 10])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 7
|
||||
expect(completions[0].text).toBe 'canvas'
|
||||
|
||||
it "does not autocomplete when prefix is preceded by class or id char", ->
|
||||
editor.setText """
|
||||
.ca
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 3])
|
||||
completions = getCompletions()
|
||||
expect(completions).toBe null
|
||||
|
||||
editor.setText """
|
||||
#ca
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 3])
|
||||
completions = getCompletions()
|
||||
expect(completions).toBe null
|
||||
|
||||
describe "pseudo selectors", ->
|
||||
it "autocompletes without a prefix", ->
|
||||
editor.setText """
|
||||
div:
|
||||
"""
|
||||
editor.setCursorBufferPosition([0, 4])
|
||||
completions = getCompletions()
|
||||
expect(completions.length).toBe 43
|
||||
for completion in completions
|
||||
text = (completion.text or completion.snippet)
|
||||
expect(text.length).toBeGreaterThan 0
|
||||
expect(completion.type).toBe 'pseudo-selector'
|
41
packages/autocomplete-css/update.coffee
Normal file
41
packages/autocomplete-css/update.coffee
Normal file
@ -0,0 +1,41 @@
|
||||
# Run this to update the static list of completions stored in the completions.json
|
||||
# file at the root of this repository.
|
||||
|
||||
path = require 'path'
|
||||
fs = require 'fs'
|
||||
request = require 'request'
|
||||
fetchPropertyDescriptions = require './fetch-property-docs'
|
||||
|
||||
PropertiesURL = 'https://raw.githubusercontent.com/adobe/brackets/master/src/extensions/default/CSSCodeHints/CSSProperties.json'
|
||||
|
||||
propertiesPromise = new Promise (resolve) ->
|
||||
request {json: true, url: PropertiesURL}, (error, response, properties) ->
|
||||
if error?
|
||||
console.error(error.message)
|
||||
resolve(null)
|
||||
if response.statusCode isnt 200
|
||||
console.error("Request for CSSProperties.json failed: #{response.statusCode}")
|
||||
resolve(null)
|
||||
resolve(properties)
|
||||
|
||||
propertyDescriptionsPromise = fetchPropertyDescriptions()
|
||||
|
||||
Promise.all([propertiesPromise, propertyDescriptionsPromise]).then (values) ->
|
||||
properties = {}
|
||||
propertiesRaw = values[0]
|
||||
propertyDescriptions = values[1]
|
||||
sortedPropertyNames = JSON.parse(fs.readFileSync(path.join(__dirname, 'sorted-property-names.json')))
|
||||
for propertyName in sortedPropertyNames
|
||||
continue unless metadata = propertiesRaw[propertyName]
|
||||
metadata.description = propertyDescriptions[propertyName]
|
||||
properties[propertyName] = metadata
|
||||
console.warn "No description for property #{propertyName}" unless propertyDescriptions[propertyName]?
|
||||
|
||||
for propertyName of propertiesRaw
|
||||
console.warn "Ignoring #{propertyName}; not in sorted-property-names.json" if sortedPropertyNames.indexOf(propertyName) < 0
|
||||
|
||||
tags = JSON.parse(fs.readFileSync(path.join(__dirname, 'html-tags.json')))
|
||||
pseudoSelectors = JSON.parse(fs.readFileSync(path.join(__dirname, 'pseudo-selectors.json')))
|
||||
|
||||
completions = {tags, properties, pseudoSelectors}
|
||||
fs.writeFileSync(path.join(__dirname, 'completions.json'), "#{JSON.stringify(completions, null, ' ')}\n")
|
@ -2270,9 +2270,8 @@ atom-slick@^2, atom-slick@^2.0.0:
|
||||
version "0.10.7"
|
||||
resolved "https://codeload.github.com/atom/autocomplete-atom-api/legacy.tar.gz/refs/tags/v0.10.7#c9d51fa721d543ccfc1b2189101155e81db6b97d"
|
||||
|
||||
"autocomplete-css@https://codeload.github.com/atom/autocomplete-css/legacy.tar.gz/refs/tags/v0.17.5":
|
||||
"autocomplete-css@file:packages/autocomplete-css":
|
||||
version "0.17.5"
|
||||
resolved "https://codeload.github.com/atom/autocomplete-css/legacy.tar.gz/refs/tags/v0.17.5#a6b38bca90bdba18a2f40c366266cda93bf582c3"
|
||||
|
||||
"autocomplete-html@https://github.com/pulsar-edit/autocomplete-html.git#v0.8.9":
|
||||
version "0.8.9"
|
||||
|
Loading…
Reference in New Issue
Block a user