Comparar commits
267 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 82527c24f2 | |||
| ccfe787e4f | |||
| 4a5b43553b | |||
| da1ceb0e51 | |||
| 97e0ddf15d | |||
| fb3cc5554c | |||
| 184aecb4a4 | |||
| 181cecaf2f | |||
| ced66d920d | |||
| 6fe7eb086f | |||
| 462af79d21 | |||
| 771a60b1bc | |||
| 3e34e426bf | |||
| f77f48102c | |||
| 7dd67caf57 | |||
| 8081595523 | |||
| 47cd2359c8 | |||
| 571d146ec0 | |||
| 8f4555b970 | |||
| e0bc7948ae | |||
| a606fc516b | |||
| 2c1f8ce733 | |||
| 62adc98b17 | |||
| 94e12ee886 | |||
| 4c74b07b22 | |||
| 8eb53696a6 | |||
| f9e28af59b | |||
| 3b5bb1501c | |||
| 8c4c15c17a | |||
| ae61ecf602 | |||
| 9a7582fd0b | |||
| f7f2f4497b | |||
| d4c4ab58b1 | |||
| a01e6e543e | |||
| d931b3ed5c | |||
| b95a7f47a8 | |||
| 06cbbe4b67 | |||
| 7d44026a92 | |||
| 11b0a80d3d | |||
| 92a8701c70 | |||
| 08e1d550c8 | |||
| c9eb84f2a4 | |||
| 74afcc58ac | |||
| 180725799a | |||
| 03468e405a | |||
| 1fd4e945ee | |||
| 0b48150b71 | |||
| bed8abea22 | |||
| 893bdda47d | |||
| 0b98093370 | |||
| 6abe05b1ab | |||
| 0f45937adf | |||
| c8726c991f | |||
| 60205aaabe | |||
| 6a16c8a59c | |||
| a055f09a6c | |||
| c19b42a49c | |||
| 2632e9aa10 | |||
| a9753d430e | |||
| 796eefd012 | |||
| 0f9eea34a5 | |||
| a84e19c9bd | |||
| 6d276d39d3 | |||
| ab203e5f81 | |||
| 61512b9e19 | |||
| c29c4652b0 | |||
| a9c0553e31 | |||
| 6d6e5baa9a | |||
| 1de76c7d73 | |||
| f6b7450dea | |||
| 71e1928f74 | |||
| 1a709065f8 | |||
| dca99cb34e | |||
| 3e79f54860 | |||
| a8b5960bc0 | |||
| 70e3484a16 | |||
| 5ac3f58cdb | |||
| 692f6947f2 | |||
| 08fad809d2 | |||
| ba63239928 | |||
| d90c8c0fb7 | |||
| 35e782f05d | |||
| 00af9a93d7 | |||
| 018e22ad8d | |||
| f73d3df233 | |||
| 25b44ceb1a | |||
| c28ecf1a7d | |||
| 478e80e585 | |||
| 08be377004 | |||
| 4db3e47377 | |||
| 76857b4486 | |||
| e743d93d6d | |||
| f443c375d4 | |||
| b9b488bee2 | |||
| e192922f0e | |||
| d1c41fbf68 | |||
| aa8b97a039 | |||
| 5276cb716a | |||
| 03f8a32f86 | |||
| eabb498af7 | |||
| a1e4c0bb05 | |||
| 6a285b695f | |||
| 7f66a2fca4 | |||
| 6565f6d608 | |||
| 493035fe4e | |||
| 6e30998ef5 | |||
| 825c4f6098 | |||
| b4756aa9b7 | |||
| 651fa1aa42 | |||
| db17fe2daa | |||
| 1e0c839257 | |||
| 18481789b0 | |||
| 304f63532e | |||
| 6e7364c7c6 | |||
| 339f331776 | |||
| 32275b27a3 | |||
| 5c730415b7 | |||
| 637b2b0aba | |||
| b4246a2f07 | |||
| 31170dcfae | |||
| f784b51f12 | |||
| 3c6dab22d8 | |||
| e80f5acd50 | |||
| 90aca1c6ad | |||
| c7771ffde9 | |||
| bdfc862dac | |||
| 2c7aa170e9 | |||
| 6c8d624e73 | |||
| 57a876e677 | |||
| 20adc96e4c | |||
| d508d1eedf | |||
| 2949ebfe86 | |||
| dbaef8e593 | |||
| 3edd2f9590 | |||
| f2652bcb40 | |||
| d6c8ec83d4 | |||
| b4b492a321 | |||
| ba6a976013 | |||
| d0486cc923 | |||
| fb09f28c4c | |||
| 883c48b490 | |||
| ceefc15b15 | |||
| a0cc63273c | |||
| c328092463 | |||
| b1a3d89af3 | |||
| bd92acba7e | |||
| d90daf07f8 | |||
| 388428b074 | |||
| f439d0d996 | |||
| 4142845632 | |||
| 60c5293b5e | |||
| a1b4820c04 | |||
| 1cf8479831 | |||
| a14d57ceac | |||
| c1d5d96aca | |||
| b5632b6988 | |||
| fe02442b23 | |||
| 04ceaf36bf | |||
| 08d183dff1 | |||
| 134daa1fe2 | |||
| 360fbe2a3f | |||
| 8148446a86 | |||
| 16f56a068b | |||
| 11112cb374 | |||
| 5c7177746c | |||
| ab947ba87a | |||
| 8a4db34cb8 | |||
| 669088612c | |||
| 0a14d232d2 | |||
| 651fe5d71c | |||
| 7d49d50b34 | |||
| aab51d15ab | |||
| 1926156eee | |||
| b12a6abc90 | |||
| 46762c293f | |||
| 6b8ef25c8e | |||
| 03a769b516 | |||
| 229e7e03b2 | |||
| 45ee6df36e | |||
| 9422a8047a | |||
| 85456ad920 | |||
| 2f3d54db8a | |||
| bae903a772 | |||
| aabf4dfbab | |||
| 44327724a8 | |||
| 3c3e72e36d | |||
| e0741d2073 | |||
| d973ce9832 | |||
| 25cb56a936 | |||
| 9640678c29 | |||
| 2ce1677aa5 | |||
| d5c8956d38 | |||
| d532f506fe | |||
| 32b414328a | |||
| b1697399dc | |||
| 27eccfaf81 | |||
| ebbd8101ba | |||
| 20504fc7a8 | |||
| 0db1971825 | |||
| 80c828d001 | |||
| e688df57f2 | |||
| 0790d33e9d | |||
| 05820a3044 | |||
| c4ac602644 | |||
| 12d4fae91c | |||
| 2f334979d5 | |||
| d9e414af27 | |||
| 335c1e215a | |||
| b9b7646d4b | |||
| d885fb2d13 | |||
| f5ae96820a | |||
| 435fee1433 | |||
| c96f976162 | |||
| 5115540f8e | |||
| d642553351 | |||
| fa090345a8 | |||
| 55d291ffde | |||
| a0038b6f56 | |||
| 48f63926ab | |||
| b0501c9cb2 | |||
| 355ab1eb2f | |||
| 28ac51d140 | |||
| d6210b24d9 | |||
| b0731afd4c | |||
| 1c81aa90c0 | |||
| bbf6930061 | |||
| 3d149eb9d1 | |||
| 5a8b96b180 | |||
| 5add777291 | |||
| f866e69704 | |||
| b27b4387fc | |||
| 1f850f0af1 | |||
| 9f1bbc54de | |||
| e7d34d4b83 | |||
| c5a15fb50e | |||
| 7a251f5432 | |||
| dc2a453986 | |||
| fdd55dfd27 | |||
| 5147fb6a8b | |||
| 9bbbb58084 | |||
| 9ad080cd31 | |||
| 509976fa18 | |||
| aad5700418 | |||
| 09a0773043 | |||
| 2ea92cf0e5 | |||
| 9a2cc36c6b | |||
| 965a6243e1 | |||
| 503fa30c28 | |||
| b8f239cd39 | |||
| 231da60e13 | |||
| a47719eb53 | |||
| 9f851e55d1 | |||
| ab89776f01 | |||
| 2cea51b50e | |||
| 4e4794f3fd | |||
| ac6fbf100d | |||
| 8c8e866a97 | |||
| f859ad5fc5 | |||
| d30cf35a16 | |||
| c35fb90653 | |||
| 73df017d83 | |||
| 0e1ef201c1 | |||
| be4d23aa13 | |||
| c58606907a | |||
| c489a4662b | |||
| aff1aa5112 | |||
| 3b6d55dbbb |
@@ -87,6 +87,7 @@ For more information on how to work with Atom's official packages, see
|
||||
* :white_check_mark: `:white_check_mark:` when adding tests
|
||||
* :lock: `:lock:` when dealing with security
|
||||
* :arrow_up: `:arrow_up:` when upgrading dependencies
|
||||
* :arrow_down: `:arrow_down:` when downgrading dependencies
|
||||
|
||||
## CoffeeScript Styleguide
|
||||
|
||||
|
||||
+1
-1
@@ -6,6 +6,6 @@
|
||||
"url": "https://github.com/atom/atom.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"atom-package-manager": "0.116.0"
|
||||
"atom-package-manager": "0.117.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"fs-plus": "2.x",
|
||||
"github-releases": "~0.2.0",
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-atom-shell-installer": "^0.13.0",
|
||||
"grunt-atom-shell-installer": "^0.16.0",
|
||||
"grunt-cli": "~0.1.9",
|
||||
"grunt-coffeelint": "git+https://github.com/atom/grunt-coffeelint.git#cfb99aa99811d52687969532bd5a98011ed95bfe",
|
||||
"grunt-contrib-coffee": "~0.9.0",
|
||||
|
||||
@@ -25,6 +25,7 @@ module.exports = (grunt) ->
|
||||
cp 'atom.sh', path.join(appDir, 'atom.sh')
|
||||
|
||||
cp 'package.json', path.join(appDir, 'package.json')
|
||||
cp path.join('resources', 'atom.png'), path.join(appDir, 'atom.png')
|
||||
|
||||
packageDirectories = []
|
||||
nonPackageDirectories = [
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
|
||||
@@ -101,7 +101,7 @@ getAssets = ->
|
||||
logError = (message, error, details) ->
|
||||
grunt.log.error(message)
|
||||
grunt.log.error(error.message ? error) if error?
|
||||
grunt.log.error(details) if details
|
||||
grunt.log.error(require('util').inspect(details)) if details
|
||||
|
||||
zipAssets = (buildDir, assets, callback) ->
|
||||
zip = (directory, sourcePath, assetName, callback) ->
|
||||
@@ -142,7 +142,30 @@ getAtomDraftRelease = (callback) ->
|
||||
firstDraft.assets = assets
|
||||
callback(null, firstDraft)
|
||||
else
|
||||
callback(new Error('No draft release in atom/atom repo'))
|
||||
createAtomDraftRelease(callback)
|
||||
|
||||
createAtomDraftRelease = (callback) ->
|
||||
{version} = require('../../package.json')
|
||||
options =
|
||||
uri: 'https://api.github.com/repos/atom/atom/releases'
|
||||
method: 'POST'
|
||||
headers: defaultHeaders
|
||||
json:
|
||||
tag_name: "v#{version}"
|
||||
name: version
|
||||
draft: true
|
||||
body: """
|
||||
### Notable Changes
|
||||
|
||||
*
|
||||
"""
|
||||
|
||||
request options, (error, response, body='') ->
|
||||
if error? or response.statusCode isnt 201
|
||||
logError("Creating atom/atom draft release failed", error, body)
|
||||
callback(error ? new Error(response.statusCode))
|
||||
else
|
||||
callback(null, body)
|
||||
|
||||
deleteRelease = (release) ->
|
||||
options =
|
||||
|
||||
@@ -12,11 +12,18 @@ module.exports = (grunt) ->
|
||||
packageSpecQueue = null
|
||||
|
||||
logDeprecations = (label, {stderr}={}) ->
|
||||
if process.env.JANKY_SHA1 and stderr?.indexOf('Calls to deprecated functions') isnt -1
|
||||
grunt.log.error(label)
|
||||
stderr = stderr.replace(/^\[.*\] "/g, '')
|
||||
stderr = stderr.replace(/source: .*$/g, '')
|
||||
grunt.log.error(stderr)
|
||||
return unless process.env.JANKY_SHA1
|
||||
stderr ?= ''
|
||||
deprecatedStart = stderr.indexOf('Calls to deprecated functions')
|
||||
return if deprecatedStart.length is -1
|
||||
|
||||
grunt.log.error(label)
|
||||
stderr = stderr.substring(deprecatedStart)
|
||||
stderr = stderr.replace(/^\s*\[[^\]]+\]\s+/gm, '')
|
||||
stderr = stderr.replace(/source: .*$/gm, '')
|
||||
stderr = stderr.replace(/^"/gm, '')
|
||||
stderr = stderr.replace(/",\s*$/gm, '')
|
||||
grunt.log.error(stderr)
|
||||
|
||||
getAppPath = ->
|
||||
contentsDir = grunt.config.get('atom.contentsDir')
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
path = require 'path'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
grunt.registerTask 'update-octicons', 'Update octicon font and LESS variables', ->
|
||||
pathToOcticons = path.resolve('..', 'octicons')
|
||||
if grunt.file.isDir(pathToOcticons)
|
||||
# Copy font-file
|
||||
fontSrc = path.join(pathToOcticons, 'octicons', 'octicons.woff')
|
||||
fontDest = path.resolve('static', 'octicons.woff')
|
||||
grunt.file.copy(fontSrc, fontDest)
|
||||
|
||||
# Update Octicon UTF codes
|
||||
glyphsSrc = path.join(pathToOcticons, 'data', 'glyphs.yml')
|
||||
output = []
|
||||
for {css, code} in grunt.file.readYAML(glyphsSrc)
|
||||
output.push "@#{css}: \"\\#{code}\";"
|
||||
|
||||
octiconUtfDest = path.resolve('static', 'variables', 'octicon-utf-codes.less')
|
||||
grunt.file.write(octiconUtfDest, "#{output.join('\n')}\n")
|
||||
else
|
||||
grunt.log.error("octicons repo must be cloned to #{pathToOcticons}")
|
||||
false
|
||||
@@ -30,8 +30,8 @@ All requests that take parameters require `application/json`.
|
||||
Parameters:
|
||||
|
||||
- **page** (optional)
|
||||
- **sort** (optional, values: `created_at`, `updated_at`, `downloads`)
|
||||
- **direction** (optional, values: `asc`, `desc`)
|
||||
- **sort** (optional) - One of `downloads`, `created_at`, `updated_at`, `stars`. Defaults to `downloads`
|
||||
- **direction** (optional) - `asc` or `desc`. Defaults to `desc`. `stars` can only be ordered `desc`
|
||||
|
||||
Returns a list of all packages in the following format:
|
||||
```json
|
||||
@@ -61,17 +61,18 @@ Link: <https://www.atom.io/api/packages?page=1>; rel="self",
|
||||
|
||||
By default, results are sorted by download count, descending.
|
||||
|
||||
### Searching packages
|
||||
|
||||
#### GET /api/packages/search
|
||||
|
||||
Parameters:
|
||||
|
||||
- **q** String query to search
|
||||
- **sort** (optional, values: `created_at`, `updated_at`, `downloads`)
|
||||
- **direction** (optional, values: `asc`, `desc`)
|
||||
- **q** (required) - Search query
|
||||
- **page** (optional)
|
||||
- **sort** (optional) - One of `downloads`, `created_at`, `updated_at`, `stars`. Defaults to the relevance of the search query.
|
||||
- **direction** (optional) - `asc` or `desc`. Defaults to `desc`.
|
||||
|
||||
Returns a list of all packages in the same format as `/api/packages`.
|
||||
|
||||
By default, results sorted by relevance to search query.
|
||||
Returns results in the same format as [listing packages](#listing-packages).
|
||||
|
||||
### Showing package details
|
||||
|
||||
|
||||
@@ -26,13 +26,17 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
|
||||
|
||||
### Arch
|
||||
|
||||
* `sudo pacman -S base-devel git nodejs libgnome-keyring python2`
|
||||
* `sudo pacman -S gconf base-devel git nodejs libgnome-keyring python2`
|
||||
* `export PYTHON=/usr/bin/python2` before building Atom.
|
||||
|
||||
### Slackware
|
||||
|
||||
* `sbopkg -k -i node -i atom`
|
||||
|
||||
### openSUSE
|
||||
|
||||
* `sudo zypper install nodejs make gcc gcc-c++ glibc-devel git-core libgnome-keyring-devel rpmdevtools`
|
||||
|
||||
## Instructions
|
||||
|
||||
If you have problems with permissions don't forget to prefix with `sudo`
|
||||
|
||||
@@ -59,6 +59,8 @@ window in dev mode. To open a Dev Mode Atom window run `atom --dev .` in the
|
||||
terminal, use `cmd-shift-o` or use the _View > Developer > Open in Dev Mode_
|
||||
menu. When you edit your theme, changes will instantly be reflected!
|
||||
|
||||
> Note: It's advised to _not_ specify a `font-family` in your syntax theme because it will override the Font Family field in Atom's settings. If you still like to recommend a font that goes well with your theme, we recommend you do so in your README.
|
||||
|
||||
## Creating an Interface Theme
|
||||
|
||||
Interface themes **must** provide a `ui-variables.less` file which contains all
|
||||
|
||||
@@ -105,6 +105,7 @@ You can open this file in an editor from the _Atom > Open Your Config_ menu.
|
||||
- `core`
|
||||
- `disabledPackages`: An array of package names to disable
|
||||
- `excludeVcsIgnoredPaths`: Don't search within files specified by _.gitignore_
|
||||
- `followSymlinks`: Follow symlinks when searching and scanning root directory
|
||||
- `ignoredNames`: File names to ignore across all of Atom
|
||||
- `projectHome`: The directory where projects are assumed to be located
|
||||
- `themes`: An array of theme names to load, in cascading order
|
||||
|
||||
+12
-1
@@ -3,7 +3,8 @@
|
||||
Atom provides several tools to help you understand unexpected behavior and debug problems. This guide describes some of those tools and a few approaches to help you debug and provide more helpful information when [submitting issues]:
|
||||
|
||||
* [Update to the latest version](#update-to-the-latest-version)
|
||||
* [Check Atom and package settings](#check-atom-and-package-settings)
|
||||
* [Check for linked packages](#check-for-linked-packages)
|
||||
* [Check Atom and package settings](#check-atom-and-package-settings)
|
||||
* [Check the keybindings](#check-the-keybindings)
|
||||
* [Check if the problem shows up in safe mode](#check-if-the-problem-shows-up-in-safe-mode)
|
||||
* [Check your config files](#check-your-config-files)
|
||||
@@ -24,6 +25,16 @@ $ atom --version
|
||||
|
||||
Head on over to the [list of releases][atom releases] and see if there's a more recent release. You can update to the most recent release by downloading Atom from the releases page, or with the in-app auto-updater. The in-app auto-updater checks for and downloads a new version after you restart Atom, or if you use the Atom > Check for Update menu option.
|
||||
|
||||
## Check for linked packages
|
||||
|
||||
If you develop or contribute to Atom packages, there may be left-over packages linked to your `~/.atom/packages` or `~/.atom/dev/packages` directories. You can use:
|
||||
|
||||
```shell
|
||||
$ apm links
|
||||
```
|
||||
|
||||
to list all linked development packages. You can remove the links using the `apm unlink` command. See `apm unlink --help` for details.
|
||||
|
||||
## Check Atom and package settings
|
||||
|
||||
In some cases, unexpected behavior might be caused by misconfigured or unconfigured settings in Atom or in one of the packages.
|
||||
|
||||
+16
-16
@@ -40,11 +40,11 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
Object.defineProperty module.exports, '$', get: ->
|
||||
deprecate """
|
||||
Requiring `$` from `atom` is no longer supported.
|
||||
If you are using `space-pen`, please require `$` from `space-pen`. Otherwise require `jquery` instead:
|
||||
`{$} = require 'space-pen'`
|
||||
If you are using `space-pen`, please require `$` from `atom-space-pen-views`. Otherwise require `jquery` instead:
|
||||
`{$} = require 'atom-space-pen-views'`
|
||||
or
|
||||
`$ = require 'jquery'`
|
||||
Add `"space-pen": "^4"` to your package dependencies.
|
||||
Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies.
|
||||
Or add `"jquery": "^2"` to your package dependencies.
|
||||
"""
|
||||
$
|
||||
@@ -52,27 +52,27 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
Object.defineProperty module.exports, '$$', get: ->
|
||||
deprecate """
|
||||
Requiring `$$` from `atom` is no longer supported.
|
||||
Please require `space-pen` instead:
|
||||
`{$$} = require 'space-pen'`
|
||||
Add `"space-pen": "^4"` to your package dependencies.
|
||||
Please require `atom-space-pen-views` instead:
|
||||
`{$$} = require 'atom-space-pen-views'`
|
||||
Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies.
|
||||
"""
|
||||
$$
|
||||
|
||||
Object.defineProperty module.exports, '$$$', get: ->
|
||||
deprecate """
|
||||
Requiring `$$$` from `atom` is no longer supported.
|
||||
Please require `space-pen` instead:
|
||||
`{$$$} = require 'space-pen'`
|
||||
Add `"space-pen": "^4"` to your package dependencies.
|
||||
Please require `atom-space-pen-views` instead:
|
||||
`{$$$} = require 'atom-space-pen-views'`
|
||||
Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies.
|
||||
"""
|
||||
$$$
|
||||
|
||||
Object.defineProperty module.exports, 'View', get: ->
|
||||
deprecate """
|
||||
Requiring `View` from `atom` is no longer supported.
|
||||
Please require `space-pen` instead:
|
||||
`{View} = require 'space-pen'`
|
||||
Add `"space-pen": "^4"` to your package dependencies.
|
||||
Please require `atom-space-pen-views` instead:
|
||||
`{View} = require 'atom-space-pen-views'`
|
||||
Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies.
|
||||
"""
|
||||
View
|
||||
|
||||
@@ -81,7 +81,7 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
Requiring `EditorView` from `atom` is no longer supported.
|
||||
Please require `TextEditorView` from `atom-space-pen-view` instead:
|
||||
`{TextEditorView} = require 'atom-space-pen-views'`
|
||||
Add `"atom-space-pen-views": "^0"` to your package dependencies.
|
||||
Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies.
|
||||
"""
|
||||
require '../src/text-editor-view'
|
||||
|
||||
@@ -90,7 +90,7 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
Requiring `TextEditorView` from `atom` is no longer supported.
|
||||
Please require `TextEditorView` from `atom-space-pen-view` instead:
|
||||
`{TextEditorView} = require 'atom-space-pen-views'`
|
||||
Add `"atom-space-pen-views": "^0"` to your package dependencies.
|
||||
Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies.
|
||||
"""
|
||||
require '../src/text-editor-view'
|
||||
|
||||
@@ -100,7 +100,7 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
Please require `ScrollView` from `atom-space-pen-view` instead:
|
||||
`{ScrollView} = require 'atom-space-pen-views'`
|
||||
Note that the API has changed slightly! Please read the docs at https://github.com/atom/atom-space-pen-views
|
||||
Add `"atom-space-pen-views": "^0"` to your package dependencies.
|
||||
Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies.
|
||||
"""
|
||||
require '../src/scroll-view'
|
||||
|
||||
@@ -110,7 +110,7 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
Please require `SelectListView` from `atom-space-pen-view` instead:
|
||||
`{SelectListView} = require 'atom-space-pen-views'`
|
||||
Note that the API has changed slightly! Please read the docs at https://github.com/atom/atom-space-pen-views
|
||||
Add `"atom-space-pen-views": "^0"` to your package dependencies.
|
||||
Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies.
|
||||
"""
|
||||
require '../src/select-list-view'
|
||||
|
||||
|
||||
+1
-1
@@ -202,7 +202,7 @@
|
||||
]
|
||||
|
||||
'context-menu':
|
||||
'.overlayer': [
|
||||
'atom-text-editor, .overlayer': [
|
||||
{label: 'Undo', command: 'core:undo'}
|
||||
{label: 'Redo', command: 'core:redo'}
|
||||
{type: 'separator'}
|
||||
|
||||
+1
-1
@@ -160,7 +160,7 @@
|
||||
]
|
||||
|
||||
'context-menu':
|
||||
'.overlayer': [
|
||||
'atom-text-editor, .overlayer': [
|
||||
{label: 'Undo', command: 'core:undo'}
|
||||
{label: 'Redo', command: 'core:redo'}
|
||||
{type: 'separator'}
|
||||
|
||||
+1
-1
@@ -181,7 +181,7 @@
|
||||
]
|
||||
|
||||
'context-menu':
|
||||
'.overlayer': [
|
||||
'atom-text-editor, .overlayer': [
|
||||
{label: 'Undo', command: 'core:undo'}
|
||||
{label: 'Redo', command: 'core:redo'}
|
||||
{type: 'separator'}
|
||||
|
||||
+71
-71
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "atom",
|
||||
"productName": "Atom",
|
||||
"version": "0.160.0",
|
||||
"version": "0.167.0",
|
||||
"description": "A hackable text editor for the 21st Century.",
|
||||
"main": "./src/browser/main.js",
|
||||
"repository": {
|
||||
@@ -17,23 +17,23 @@
|
||||
"url": "http://github.com/atom/atom/raw/master/LICENSE.md"
|
||||
}
|
||||
],
|
||||
"atomShellVersion": "0.19.4",
|
||||
"atomShellVersion": "0.20.4",
|
||||
"dependencies": {
|
||||
"async": "0.2.6",
|
||||
"atom-keymap": "^2.3.0",
|
||||
"atom-keymap": "^2.3.3",
|
||||
"bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
|
||||
"clear-cut": "0.4.0",
|
||||
"coffee-script": "1.7.0",
|
||||
"coffeestack": "0.7.0",
|
||||
"delegato": "^1",
|
||||
"emissary": "^1.3.1",
|
||||
"event-kit": "0.8.1",
|
||||
"first-mate": "^2.2.0",
|
||||
"event-kit": "^1.0.1",
|
||||
"first-mate": "^2.2.3",
|
||||
"fs-plus": "^2.3.2",
|
||||
"fstream": "0.1.24",
|
||||
"fuzzaldrin": "^2.1",
|
||||
"git-utils": "^2.2",
|
||||
"grim": "0.12.0",
|
||||
"grim": "1.0.0",
|
||||
"guid": "0.0.10",
|
||||
"jasmine-json": "~0.0",
|
||||
"jasmine-tagged": "^1.1.2",
|
||||
@@ -45,7 +45,7 @@
|
||||
"nslog": "^1.0.1",
|
||||
"oniguruma": "^3.0.4",
|
||||
"optimist": "0.4.0",
|
||||
"pathwatcher": "^2.3.5",
|
||||
"pathwatcher": "^2.3.7",
|
||||
"property-accessors": "^1",
|
||||
"q": "^1.0.1",
|
||||
"random-words": "0.0.1",
|
||||
@@ -53,7 +53,7 @@
|
||||
"reactionary-atom-fork": "^1.0.0",
|
||||
"runas": "1.0.1",
|
||||
"scandal": "1.0.3",
|
||||
"scoped-property-store": "^0.15.2",
|
||||
"scoped-property-store": "^0.16.2",
|
||||
"scrollbar-style": "^1.0.2",
|
||||
"season": "^1.0.2",
|
||||
"semver": "2.2.1",
|
||||
@@ -61,91 +61,91 @@
|
||||
"service-hub": "^0.1.0",
|
||||
"space-pen": "3.8.2",
|
||||
"temp": "0.7.0",
|
||||
"text-buffer": "^3.8.2",
|
||||
"text-buffer": "^3.8.4",
|
||||
"theorist": "^1.0.2",
|
||||
"underscore-plus": "^1.6.3",
|
||||
"underscore-plus": "^1.6.6",
|
||||
"vm-compatibility-layer": "0.1.0"
|
||||
},
|
||||
"packageDependencies": {
|
||||
"atom-dark-syntax": "0.23.0",
|
||||
"atom-dark-ui": "0.42.0",
|
||||
"atom-light-syntax": "0.22.0",
|
||||
"atom-light-syntax": "0.24.0",
|
||||
"atom-light-ui": "0.36.0",
|
||||
"base16-tomorrow-dark-theme": "0.22.0",
|
||||
"base16-tomorrow-dark-theme": "0.23.0",
|
||||
"base16-tomorrow-light-theme": "0.5.0",
|
||||
"solarized-dark-syntax": "0.27.0",
|
||||
"solarized-light-syntax": "0.13.0",
|
||||
"archive-view": "0.40.0",
|
||||
"autocomplete": "0.34.0",
|
||||
"solarized-dark-syntax": "0.30.0",
|
||||
"solarized-light-syntax": "0.17.0",
|
||||
"archive-view": "0.43.0",
|
||||
"autocomplete": "0.40.0",
|
||||
"autoflow": "0.20.0",
|
||||
"autosave": "0.19.0",
|
||||
"background-tips": "0.18.0",
|
||||
"bookmarks": "0.31.0",
|
||||
"bracket-matcher": "0.64.0",
|
||||
"command-palette": "0.30.0",
|
||||
"deprecation-cop": "0.20.0",
|
||||
"background-tips": "0.20.0",
|
||||
"bookmarks": "0.33.0",
|
||||
"bracket-matcher": "0.67.0",
|
||||
"command-palette": "0.32.0",
|
||||
"deprecation-cop": "0.22.0",
|
||||
"dev-live-reload": "0.36.0",
|
||||
"encoding-selector": "0.12.0",
|
||||
"encoding-selector": "0.14.0",
|
||||
"exception-reporting": "0.21.0",
|
||||
"find-and-replace": "0.152.0",
|
||||
"fuzzy-finder": "0.62.0",
|
||||
"git-diff": "0.45.0",
|
||||
"go-to-line": "0.27.0",
|
||||
"grammar-selector": "0.38.0",
|
||||
"image-view": "0.44.0",
|
||||
"incompatible-packages": "0.16.0",
|
||||
"keybinding-resolver": "0.24.0",
|
||||
"find-and-replace": "0.155.0",
|
||||
"fuzzy-finder": "0.64.0",
|
||||
"git-diff": "0.47.0",
|
||||
"go-to-line": "0.30.0",
|
||||
"grammar-selector": "0.42.0",
|
||||
"image-view": "0.46.0",
|
||||
"incompatible-packages": "0.19.0",
|
||||
"keybinding-resolver": "0.25.0",
|
||||
"link": "0.28.0",
|
||||
"markdown-preview": "0.112.0",
|
||||
"markdown-preview": "0.116.0",
|
||||
"metrics": "0.40.0",
|
||||
"notifications": "0.18.0",
|
||||
"notifications": "0.23.0",
|
||||
"open-on-github": "0.31.0",
|
||||
"package-generator": "0.33.0",
|
||||
"release-notes": "0.39.0",
|
||||
"settings-view": "0.161.0",
|
||||
"snippets": "0.59.0",
|
||||
"spell-check": "0.45.0",
|
||||
"status-bar": "0.53.0",
|
||||
"styleguide": "0.36.0",
|
||||
"symbols-view": "0.70.0",
|
||||
"tabs": "0.58.0",
|
||||
"timecop": "0.24.0",
|
||||
"tree-view": "0.138.0",
|
||||
"package-generator": "0.36.0",
|
||||
"release-notes": "0.45.0",
|
||||
"settings-view": "0.164.0",
|
||||
"snippets": "0.66.0",
|
||||
"spell-check": "0.49.0",
|
||||
"status-bar": "0.56.0",
|
||||
"styleguide": "0.39.0",
|
||||
"symbols-view": "0.77.0",
|
||||
"tabs": "0.61.0",
|
||||
"timecop": "0.26.0",
|
||||
"tree-view": "0.147.0",
|
||||
"update-package-dependencies": "0.7.0",
|
||||
"welcome": "0.21.0",
|
||||
"whitespace": "0.27.0",
|
||||
"wrap-guide": "0.26.0",
|
||||
"language-c": "0.33.0",
|
||||
"language-clojure": "0.9.0",
|
||||
"language-coffee-script": "0.38.1",
|
||||
"language-css": "0.24.0",
|
||||
"language-gfm": "0.55.0",
|
||||
"language-git": "0.9.0",
|
||||
"language-go": "0.19.1",
|
||||
"language-html": "0.26.1",
|
||||
"whitespace": "0.28.0",
|
||||
"wrap-guide": "0.29.0",
|
||||
"language-c": "0.37.0",
|
||||
"language-clojure": "0.10.0",
|
||||
"language-coffee-script": "0.39.0",
|
||||
"language-css": "0.26.0",
|
||||
"language-gfm": "0.58.0",
|
||||
"language-git": "0.10.0",
|
||||
"language-go": "0.20.0",
|
||||
"language-html": "0.28.0",
|
||||
"language-hyperlink": "0.12.2",
|
||||
"language-java": "0.13.0",
|
||||
"language-javascript": "0.51.0",
|
||||
"language-json": "0.10.0",
|
||||
"language-less": "0.21.0",
|
||||
"language-make": "0.12.0",
|
||||
"language-java": "0.14.0",
|
||||
"language-javascript": "0.53.0",
|
||||
"language-json": "0.11.0",
|
||||
"language-less": "0.24.0",
|
||||
"language-make": "0.13.0",
|
||||
"language-mustache": "0.11.0",
|
||||
"language-objective-c": "0.12.0",
|
||||
"language-perl": "0.9.0",
|
||||
"language-php": "0.18.0",
|
||||
"language-property-list": "0.7.0",
|
||||
"language-python": "0.26.0",
|
||||
"language-ruby": "0.44.0",
|
||||
"language-objective-c": "0.15.0",
|
||||
"language-perl": "0.10.0",
|
||||
"language-php": "0.20.0",
|
||||
"language-property-list": "0.8.0",
|
||||
"language-python": "0.29.0",
|
||||
"language-ruby": "0.47.0",
|
||||
"language-ruby-on-rails": "0.18.0",
|
||||
"language-sass": "0.28.0",
|
||||
"language-shellscript": "0.10.1",
|
||||
"language-source": "0.8.0",
|
||||
"language-sql": "0.11.0",
|
||||
"language-sass": "0.30.0",
|
||||
"language-shellscript": "0.12.0",
|
||||
"language-source": "0.9.0",
|
||||
"language-sql": "0.13.0",
|
||||
"language-text": "0.6.0",
|
||||
"language-todo": "0.15.0",
|
||||
"language-toml": "0.14.1",
|
||||
"language-xml": "0.25.0",
|
||||
"language-yaml": "0.21.0"
|
||||
"language-toml": "0.15.0",
|
||||
"language-xml": "0.26.0",
|
||||
"language-yaml": "0.22.0"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Package: <%= name %>
|
||||
Version: <%= version %>
|
||||
Depends: gconf2, gconf-service, libgtk2.0-0, libudev0 | libudev1, libgcrypt11, libnotify4, libxtst6, libnss3, python, gvfs-bin, xdg-utils
|
||||
Depends: git, gconf2, gconf-service, libgtk2.0-0, libudev0 | libudev1, libgcrypt11, libnotify4, libxtst6, libnss3, python, gvfs-bin, xdg-utils
|
||||
Suggests: libgnome-keyring0, gir1.2-gnomekeyring-1.0
|
||||
Section: <%= section %>
|
||||
Priority: optional
|
||||
|
||||
@@ -9,3 +9,4 @@ docker run \
|
||||
--env JANKY_BRANCH="$JANKY_BRANCH" \
|
||||
--env ATOM_ACCESS_TOKEN="$BUILD_ATOM_RPM_ACCESS_TOKEN" \
|
||||
atom-rpm /atom/script/rpmbuild
|
||||
docker rmi atom-rpm
|
||||
|
||||
@@ -117,7 +117,7 @@ class AtomReporter extends View
|
||||
@div class: 'result-message fail deprecation-message', =>
|
||||
@raw marked(deprecation.message)
|
||||
|
||||
for stack in deprecation.stacks
|
||||
for stack in deprecation.getStacks()
|
||||
fullStack = stack.map ({functionName, location}) ->
|
||||
if functionName is '<unknown>'
|
||||
" at #{location}"
|
||||
|
||||
@@ -54,6 +54,7 @@ describe "the `atom` global", ->
|
||||
describe "loading default config", ->
|
||||
it 'loads the default core config', ->
|
||||
expect(atom.config.get('core.excludeVcsIgnoredPaths')).toBe true
|
||||
expect(atom.config.get('core.followSymlinks')).toBe false
|
||||
expect(atom.config.get('editor.showInvisibles')).toBe false
|
||||
|
||||
describe "window onerror handler", ->
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
ChildProcess = require 'child_process'
|
||||
path = require 'path'
|
||||
BufferedProcess = require '../src/buffered-process'
|
||||
|
||||
describe "BufferedProcess", ->
|
||||
@@ -40,3 +42,34 @@ describe "BufferedProcess", ->
|
||||
expect(window.onerror).toHaveBeenCalled()
|
||||
expect(window.onerror.mostRecentCall.args[0]).toContain 'Failed to spawn command `bad-command-nope`'
|
||||
expect(window.onerror.mostRecentCall.args[4].name).toBe 'BufferedProcessError'
|
||||
|
||||
describe "on Windows", ->
|
||||
originalPlatform = null
|
||||
|
||||
beforeEach ->
|
||||
# Prevent any commands from actually running and affecting the host
|
||||
originalSpawn = ChildProcess.spawn
|
||||
spyOn(ChildProcess, 'spawn').andCallFake ->
|
||||
# Just spawn something that won't actually modify the host
|
||||
if originalPlatform is 'win32'
|
||||
originalSpawn('dir')
|
||||
else
|
||||
originalSpawn('ls')
|
||||
|
||||
originalPlatform = process.platform
|
||||
Object.defineProperty process, 'platform', value: 'win32'
|
||||
|
||||
afterEach ->
|
||||
Object.defineProperty process, 'platform', value: originalPlatform
|
||||
|
||||
describe "when the explorer command is spawned on Windows", ->
|
||||
it "doesn't quote arguments of the form /root,C...", ->
|
||||
new BufferedProcess({command: 'explorer.exe', args: ['/root,C:\\foo']})
|
||||
expect(ChildProcess.spawn.argsForCall[0][1][2]).toBe '"explorer.exe /root,C:\\foo"'
|
||||
|
||||
it "spawns the command using a cmd.exe wrapper", ->
|
||||
new BufferedProcess({command: 'dir'})
|
||||
expect(path.basename(ChildProcess.spawn.argsForCall[0][0])).toBe 'cmd.exe'
|
||||
expect(ChildProcess.spawn.argsForCall[0][1][0]).toBe '/s'
|
||||
expect(ChildProcess.spawn.argsForCall[0][1][1]).toBe '/c'
|
||||
expect(ChildProcess.spawn.argsForCall[0][1][2]).toBe '"dir"'
|
||||
|
||||
+1090
-836
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "package-with-empty-keymap",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "package-with-empty-menu",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
@@ -381,6 +381,23 @@ describe "LanguageMode", ->
|
||||
expect(languageMode.isFoldableAtBufferRow(3)).toBe false
|
||||
expect(languageMode.isFoldableAtBufferRow(4)).toBe true
|
||||
|
||||
describe ".foldAllAtIndentLevel(indentLevel)", ->
|
||||
it "folds blocks of text at the given indentation level", ->
|
||||
languageMode.foldAllAtIndentLevel(0)
|
||||
expect(editor.lineTextForScreenRow(0)).toBe "var quicksort = function () {"
|
||||
expect(editor.getLastScreenRow()).toBe 0
|
||||
|
||||
languageMode.foldAllAtIndentLevel(1)
|
||||
expect(editor.lineTextForScreenRow(0)).toBe "var quicksort = function () {"
|
||||
expect(editor.lineTextForScreenRow(1)).toBe " var sort = function(items) {"
|
||||
expect(editor.getLastScreenRow()).toBe 4
|
||||
|
||||
languageMode.foldAllAtIndentLevel(2)
|
||||
expect(editor.lineTextForScreenRow(0)).toBe "var quicksort = function () {"
|
||||
expect(editor.lineTextForScreenRow(1)).toBe " var sort = function(items) {"
|
||||
expect(editor.lineTextForScreenRow(2)).toBe " if (items.length <= 1) return items;"
|
||||
expect(editor.getLastScreenRow()).toBe 9
|
||||
|
||||
describe "folding with comments", ->
|
||||
beforeEach ->
|
||||
waitsForPromise ->
|
||||
|
||||
@@ -3,19 +3,36 @@ Package = require '../src/package'
|
||||
|
||||
describe "PackageManager", ->
|
||||
workspaceElement = null
|
||||
|
||||
beforeEach ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
|
||||
describe "::loadPackage(name)", ->
|
||||
it "continues if the package has an invalid package.json", ->
|
||||
spyOn(console, 'warn')
|
||||
beforeEach ->
|
||||
atom.config.set("core.disabledPackages", [])
|
||||
expect(-> atom.packages.loadPackage("package-with-broken-package-json")).not.toThrow()
|
||||
|
||||
it "continues if the package has an invalid keymap", ->
|
||||
it "returns the package", ->
|
||||
pack = atom.packages.loadPackage("package-with-index")
|
||||
expect(pack instanceof Package).toBe true
|
||||
expect(pack.metadata.name).toBe "package-with-index"
|
||||
|
||||
it "returns the package if it has an invalid keymap", ->
|
||||
spyOn(console, 'warn')
|
||||
atom.config.set("core.disabledPackages", [])
|
||||
expect(-> atom.packages.loadPackage("package-with-broken-keymap")).not.toThrow()
|
||||
pack = atom.packages.loadPackage("package-with-broken-keymap")
|
||||
expect(pack instanceof Package).toBe true
|
||||
expect(pack.metadata.name).toBe "package-with-broken-keymap"
|
||||
|
||||
it "returns null if the package has an invalid package.json", ->
|
||||
spyOn(console, 'warn')
|
||||
expect(atom.packages.loadPackage("package-with-broken-package-json")).toBeNull()
|
||||
expect(console.warn.callCount).toBe(1)
|
||||
expect(console.warn.argsForCall[0][0]).toContain("Failed to load package.json")
|
||||
|
||||
it "returns null if the package is not found in any package directory", ->
|
||||
spyOn(console, 'warn')
|
||||
expect(atom.packages.loadPackage("this-package-cannot-be-found")).toBeNull()
|
||||
expect(console.warn.callCount).toBe(1)
|
||||
expect(console.warn.argsForCall[0][0]).toContain("Could not resolve")
|
||||
|
||||
describe "::unloadPackage(name)", ->
|
||||
describe "when the package is active", ->
|
||||
@@ -197,11 +214,30 @@ describe "PackageManager", ->
|
||||
runs ->
|
||||
expect(pack.mainModule.activate).toHaveBeenCalledWith({someNumber: 77})
|
||||
|
||||
it "logs warning instead of throwing an exception if the package fails to load", ->
|
||||
atom.config.set("core.disabledPackages", [])
|
||||
spyOn(console, "warn")
|
||||
expect(-> atom.packages.activatePackage("package-that-throws-an-exception")).not.toThrow()
|
||||
expect(console.warn).toHaveBeenCalled()
|
||||
describe "when the package throws an error while loading", ->
|
||||
it "logs a warning instead of throwing an exception", ->
|
||||
atom.config.set("core.disabledPackages", [])
|
||||
spyOn(console, "warn")
|
||||
expect(-> atom.packages.activatePackage("package-that-throws-an-exception")).not.toThrow()
|
||||
expect(console.warn).toHaveBeenCalled()
|
||||
|
||||
describe "when the package is not found", ->
|
||||
it "rejects the promise", ->
|
||||
atom.config.set("core.disabledPackages", [])
|
||||
|
||||
onSuccess = jasmine.createSpy('onSuccess')
|
||||
onFailure = jasmine.createSpy('onFailure')
|
||||
spyOn(console, 'warn')
|
||||
|
||||
atom.packages.activatePackage("this-doesnt-exist").then(onSuccess, onFailure)
|
||||
|
||||
waitsFor "promise to be rejected", ->
|
||||
onFailure.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(console.warn.callCount).toBe 1
|
||||
expect(onFailure.mostRecentCall.args[0] instanceof Error).toBe true
|
||||
expect(onFailure.mostRecentCall.args[0].message).toContain "Failed to load package 'this-doesnt-exist'"
|
||||
|
||||
describe "keymap loading", ->
|
||||
describe "when the metadata does not contain a 'keymaps' manifest", ->
|
||||
@@ -237,6 +273,14 @@ describe "PackageManager", ->
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-n', target:element1[0])[0].command).toBe 'keymap-2'
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-y', target:element3[0])).toHaveLength 0
|
||||
|
||||
describe "when the keymap file is empty", ->
|
||||
it "does not throw an error on activation", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-empty-keymap")
|
||||
|
||||
runs ->
|
||||
expect(atom.packages.isPackageActive("package-with-empty-keymap")).toBe true
|
||||
|
||||
describe "menu loading", ->
|
||||
beforeEach ->
|
||||
atom.contextMenu.definitions = []
|
||||
@@ -275,6 +319,14 @@ describe "PackageManager", ->
|
||||
expect(atom.contextMenu.templateForElement(element)[1].label).toBe "Menu item 1"
|
||||
expect(atom.contextMenu.templateForElement(element)[2]).toBeUndefined()
|
||||
|
||||
describe "when the menu file is empty", ->
|
||||
it "does not throw an error on activation", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-empty-menu")
|
||||
|
||||
runs ->
|
||||
expect(atom.packages.isPackageActive("package-with-empty-menu")).toBe true
|
||||
|
||||
describe "stylesheet loading", ->
|
||||
describe "when the metadata contains a 'stylesheets' manifest", ->
|
||||
it "loads stylesheets from the stylesheets directory as specified by the manifest", ->
|
||||
@@ -364,10 +416,10 @@ describe "PackageManager", ->
|
||||
describe "scoped-property loading", ->
|
||||
it "loads the scoped properties", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-scoped-properties")
|
||||
atom.packages.activatePackage("package-with-settings")
|
||||
|
||||
runs ->
|
||||
expect(atom.config.get ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
|
||||
expect(atom.config.get 'editor.increaseIndentPattern', scope: ['.source.omg']).toBe '^a'
|
||||
|
||||
describe "converted textmate packages", ->
|
||||
it "loads the package's grammars", ->
|
||||
@@ -380,13 +432,13 @@ describe "PackageManager", ->
|
||||
expect(atom.grammars.selectGrammar("file.rb").name).toBe "Ruby"
|
||||
|
||||
it "loads the translated scoped properties", ->
|
||||
expect(atom.config.get(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
expect(atom.config.get('editor.commentStart', scope: ['.source.ruby'])).toBeUndefined()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
runs ->
|
||||
expect(atom.config.get(['.source.ruby'], 'editor.commentStart')).toBe '# '
|
||||
expect(atom.config.get('editor.commentStart', scope: ['.source.ruby'])).toBe '# '
|
||||
|
||||
describe "::deactivatePackage(id)", ->
|
||||
afterEach ->
|
||||
@@ -490,12 +542,12 @@ describe "PackageManager", ->
|
||||
|
||||
it "removes the package's scoped-properties", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-scoped-properties")
|
||||
atom.packages.activatePackage("package-with-settings")
|
||||
|
||||
runs ->
|
||||
expect(atom.config.get ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
|
||||
atom.packages.deactivatePackage("package-with-scoped-properties")
|
||||
expect(atom.config.get ['.source.omg'], 'editor.increaseIndentPattern').toBeUndefined()
|
||||
expect(atom.config.get 'editor.increaseIndentPattern', scope: ['.source.omg']).toBe '^a'
|
||||
atom.packages.deactivatePackage("package-with-settings")
|
||||
expect(atom.config.get 'editor.increaseIndentPattern', scope: ['.source.omg']).toBeUndefined()
|
||||
|
||||
describe "textmate packages", ->
|
||||
it "removes the package's grammars", ->
|
||||
@@ -515,7 +567,7 @@ describe "PackageManager", ->
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackage('language-ruby')
|
||||
expect(atom.config.get(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
expect(atom.config.get('editor.commentStart', scope: ['.source.ruby'])).toBeUndefined()
|
||||
|
||||
describe "::activate()", ->
|
||||
packageActivator = null
|
||||
@@ -552,9 +604,9 @@ describe "PackageManager", ->
|
||||
themes = themeActivator.mostRecentCall.args[0]
|
||||
expect(['theme']).toContain(theme.getType()) for theme in themes
|
||||
|
||||
describe "::enablePackage() and ::disablePackage()", ->
|
||||
describe "::enablePackage(id) and ::disablePackage(id)", ->
|
||||
describe "with packages", ->
|
||||
it ".enablePackage() enables a disabled package", ->
|
||||
it "enables a disabled package", ->
|
||||
packageName = 'package-with-main'
|
||||
atom.config.pushAtKeyPath('core.disabledPackages', packageName)
|
||||
atom.packages.observeDisabledPackages()
|
||||
@@ -572,7 +624,7 @@ describe "PackageManager", ->
|
||||
expect(activatedPackages).toContain(pack)
|
||||
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
|
||||
|
||||
it ".disablePackage() disables an enabled package", ->
|
||||
it "disables an enabled package", ->
|
||||
packageName = 'package-with-main'
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage(packageName)
|
||||
@@ -587,6 +639,11 @@ describe "PackageManager", ->
|
||||
expect(activatedPackages).not.toContain(pack)
|
||||
expect(atom.config.get('core.disabledPackages')).toContain packageName
|
||||
|
||||
it "returns null if the package cannot be loaded", ->
|
||||
spyOn(console, 'warn')
|
||||
expect(atom.packages.enablePackage("this-doesnt-exist")).toBeNull()
|
||||
expect(console.warn.callCount).toBe 1
|
||||
|
||||
describe "with themes", ->
|
||||
reloadedHandler = null
|
||||
|
||||
@@ -597,7 +654,7 @@ describe "PackageManager", ->
|
||||
afterEach ->
|
||||
atom.themes.deactivateThemes()
|
||||
|
||||
it ".enablePackage() and .disablePackage() enables and disables a theme", ->
|
||||
it "enables and disables a theme", ->
|
||||
packageName = 'theme-with-package-file'
|
||||
|
||||
expect(atom.config.get('core.themes')).not.toContain packageName
|
||||
|
||||
@@ -4,7 +4,6 @@ Project = require '../src/project'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
platform = require './spec-helper-platform'
|
||||
BufferedProcess = require '../src/buffered-process'
|
||||
|
||||
describe "Project", ->
|
||||
@@ -195,290 +194,6 @@ describe "Project", ->
|
||||
expect(atom.project.getPaths()[0]).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
|
||||
expect(atom.project.getDirectories()[0].path).toEqual path.dirname(require.resolve('./fixtures/dir/a'))
|
||||
|
||||
describe ".replace()", ->
|
||||
[filePath, commentFilePath, sampleContent, sampleCommentContent] = []
|
||||
|
||||
beforeEach ->
|
||||
atom.project.setPaths([atom.project.resolve('../')])
|
||||
|
||||
filePath = atom.project.resolve('sample.js')
|
||||
commentFilePath = atom.project.resolve('sample-with-comments.js')
|
||||
sampleContent = fs.readFileSync(filePath).toString()
|
||||
sampleCommentContent = fs.readFileSync(commentFilePath).toString()
|
||||
|
||||
afterEach ->
|
||||
fs.writeFileSync(filePath, sampleContent)
|
||||
fs.writeFileSync(commentFilePath, sampleCommentContent)
|
||||
|
||||
describe "when a file doesn't exist", ->
|
||||
it "calls back with an error", ->
|
||||
errors = []
|
||||
missingPath = path.resolve('/not-a-file.js')
|
||||
expect(fs.existsSync(missingPath)).toBeFalsy()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.replace /items/gi, 'items', [missingPath], (result, error) ->
|
||||
errors.push(error)
|
||||
|
||||
runs ->
|
||||
expect(errors).toHaveLength 1
|
||||
expect(errors[0].path).toBe missingPath
|
||||
|
||||
describe "when called with unopened files", ->
|
||||
it "replaces properly", ->
|
||||
results = []
|
||||
waitsForPromise ->
|
||||
atom.project.replace /items/gi, 'items', [filePath], (result) ->
|
||||
results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 1
|
||||
expect(results[0].filePath).toBe filePath
|
||||
expect(results[0].replacements).toBe 6
|
||||
|
||||
describe "when a buffer is already open", ->
|
||||
it "replaces properly and saves when not modified", ->
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.isModified()).toBeFalsy()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.replace /items/gi, 'items', [filePath], (result) ->
|
||||
results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 1
|
||||
expect(results[0].filePath).toBe filePath
|
||||
expect(results[0].replacements).toBe 6
|
||||
|
||||
expect(editor.isModified()).toBeFalsy()
|
||||
|
||||
it "does not replace when the path is not specified", ->
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample-with-comments.js').then (o) -> editor = o
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.replace /items/gi, 'items', [commentFilePath], (result) ->
|
||||
results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 1
|
||||
expect(results[0].filePath).toBe commentFilePath
|
||||
|
||||
it "does NOT save when modified", ->
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
editor.buffer.setTextInRange([[0,0],[0,0]], 'omg')
|
||||
expect(editor.isModified()).toBeTruthy()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.replace /items/gi, 'okthen', [filePath], (result) ->
|
||||
results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 1
|
||||
expect(results[0].filePath).toBe filePath
|
||||
expect(results[0].replacements).toBe 6
|
||||
|
||||
expect(editor.isModified()).toBeTruthy()
|
||||
|
||||
describe ".scan(options, callback)", ->
|
||||
describe "when called with a regex", ->
|
||||
it "calls the callback with all regex results in all files in the project", ->
|
||||
results = []
|
||||
waitsForPromise ->
|
||||
atom.project.scan /(a)+/, (result) ->
|
||||
results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength(3)
|
||||
expect(results[0].filePath).toBe atom.project.resolve('a')
|
||||
expect(results[0].matches).toHaveLength(3)
|
||||
expect(results[0].matches[0]).toEqual
|
||||
matchText: 'aaa'
|
||||
lineText: 'aaa bbb'
|
||||
lineTextOffset: 0
|
||||
range: [[0, 0], [0, 3]]
|
||||
|
||||
it "works with with escaped literals (like $ and ^)", ->
|
||||
results = []
|
||||
waitsForPromise ->
|
||||
atom.project.scan /\$\w+/, (result) -> results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results.length).toBe 1
|
||||
|
||||
{filePath, matches} = results[0]
|
||||
expect(filePath).toBe atom.project.resolve('a')
|
||||
expect(matches).toHaveLength 1
|
||||
expect(matches[0]).toEqual
|
||||
matchText: '$bill'
|
||||
lineText: 'dollar$bill'
|
||||
lineTextOffset: 0
|
||||
range: [[2, 6], [2, 11]]
|
||||
|
||||
it "works on evil filenames", ->
|
||||
platform.generateEvilFiles()
|
||||
atom.project.setPaths([path.join(__dirname, 'fixtures', 'evil-files')])
|
||||
paths = []
|
||||
matches = []
|
||||
waitsForPromise ->
|
||||
atom.project.scan /evil/, (result) ->
|
||||
paths.push(result.filePath)
|
||||
matches = matches.concat(result.matches)
|
||||
|
||||
runs ->
|
||||
_.each(matches, (m) -> expect(m.matchText).toEqual 'evil')
|
||||
|
||||
if platform.isWindows()
|
||||
expect(paths.length).toBe 3
|
||||
expect(paths[0]).toMatch /a_file_with_utf8.txt$/
|
||||
expect(paths[1]).toMatch /file with spaces.txt$/
|
||||
expect(path.basename(paths[2])).toBe "utfa\u0306.md"
|
||||
else
|
||||
expect(paths.length).toBe 5
|
||||
expect(paths[0]).toMatch /a_file_with_utf8.txt$/
|
||||
expect(paths[1]).toMatch /file with spaces.txt$/
|
||||
expect(paths[2]).toMatch /goddam\nnewlines$/m
|
||||
expect(paths[3]).toMatch /quote".txt$/m
|
||||
expect(path.basename(paths[4])).toBe "utfa\u0306.md"
|
||||
|
||||
it "ignores case if the regex includes the `i` flag", ->
|
||||
results = []
|
||||
waitsForPromise ->
|
||||
atom.project.scan /DOLLAR/i, (result) -> results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 1
|
||||
|
||||
describe "when the core.excludeVcsIgnoredPaths config is truthy", ->
|
||||
[projectPath, ignoredPath] = []
|
||||
|
||||
beforeEach ->
|
||||
sourceProjectPath = path.join(__dirname, 'fixtures', 'git', 'working-dir')
|
||||
projectPath = path.join(temp.mkdirSync("atom"))
|
||||
|
||||
writerStream = fstream.Writer(projectPath)
|
||||
fstream.Reader(sourceProjectPath).pipe(writerStream)
|
||||
|
||||
waitsFor (done) ->
|
||||
writerStream.on 'close', done
|
||||
writerStream.on 'error', done
|
||||
|
||||
runs ->
|
||||
fs.rename(path.join(projectPath, 'git.git'), path.join(projectPath, '.git'))
|
||||
ignoredPath = path.join(projectPath, 'ignored.txt')
|
||||
fs.writeFileSync(ignoredPath, 'this match should not be included')
|
||||
|
||||
afterEach ->
|
||||
fs.removeSync(projectPath) if fs.existsSync(projectPath)
|
||||
|
||||
it "excludes ignored files", ->
|
||||
atom.project.setPaths([projectPath])
|
||||
atom.config.set('core.excludeVcsIgnoredPaths', true)
|
||||
resultHandler = jasmine.createSpy("result found")
|
||||
waitsForPromise ->
|
||||
atom.project.scan /match/, (results) ->
|
||||
resultHandler()
|
||||
|
||||
runs ->
|
||||
expect(resultHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "includes only files when a directory filter is specified", ->
|
||||
projectPath = path.join(path.join(__dirname, 'fixtures', 'dir'))
|
||||
atom.project.setPaths([projectPath])
|
||||
|
||||
filePath = path.join(projectPath, 'a-dir', 'oh-git')
|
||||
|
||||
paths = []
|
||||
matches = []
|
||||
waitsForPromise ->
|
||||
atom.project.scan /aaa/, paths: ["a-dir#{path.sep}"], (result) ->
|
||||
paths.push(result.filePath)
|
||||
matches = matches.concat(result.matches)
|
||||
|
||||
runs ->
|
||||
expect(paths.length).toBe 1
|
||||
expect(paths[0]).toBe filePath
|
||||
expect(matches.length).toBe 1
|
||||
|
||||
it "includes files and folders that begin with a '.'", ->
|
||||
projectPath = temp.mkdirSync()
|
||||
filePath = path.join(projectPath, '.text')
|
||||
fs.writeFileSync(filePath, 'match this')
|
||||
atom.project.setPaths([projectPath])
|
||||
paths = []
|
||||
matches = []
|
||||
waitsForPromise ->
|
||||
atom.project.scan /match this/, (result) ->
|
||||
paths.push(result.filePath)
|
||||
matches = matches.concat(result.matches)
|
||||
|
||||
runs ->
|
||||
expect(paths.length).toBe 1
|
||||
expect(paths[0]).toBe filePath
|
||||
expect(matches.length).toBe 1
|
||||
|
||||
it "excludes values in core.ignoredNames", ->
|
||||
projectPath = path.join(__dirname, 'fixtures', 'git', 'working-dir')
|
||||
ignoredNames = atom.config.get("core.ignoredNames")
|
||||
ignoredNames.push("a")
|
||||
atom.config.set("core.ignoredNames", ignoredNames)
|
||||
|
||||
resultHandler = jasmine.createSpy("result found")
|
||||
waitsForPromise ->
|
||||
atom.project.scan /dollar/, (results) ->
|
||||
resultHandler()
|
||||
|
||||
runs ->
|
||||
expect(resultHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "scans buffer contents if the buffer is modified", ->
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('a').then (o) ->
|
||||
editor = o
|
||||
editor.setText("Elephant")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.scan /a|Elephant/, (result) -> results.push result
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 3
|
||||
resultForA = _.find results, ({filePath}) -> path.basename(filePath) == 'a'
|
||||
expect(resultForA.matches).toHaveLength 1
|
||||
expect(resultForA.matches[0].matchText).toBe 'Elephant'
|
||||
|
||||
it "ignores buffers outside the project", ->
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open(temp.openSync().path).then (o) ->
|
||||
editor = o
|
||||
editor.setText("Elephant")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.scan /Elephant/, (result) -> results.push result
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 0
|
||||
|
||||
describe ".eachBuffer(callback)", ->
|
||||
beforeEach ->
|
||||
atom.project.bufferForPathSync('a')
|
||||
|
||||
@@ -84,6 +84,10 @@ beforeEach ->
|
||||
atom.workspaceViewParentSelector = '#jasmine-content'
|
||||
|
||||
window.resetTimeouts()
|
||||
spyOn(_._, "now").andCallFake -> window.now
|
||||
spyOn(window, "setTimeout").andCallFake window.fakeSetTimeout
|
||||
spyOn(window, "clearTimeout").andCallFake window.fakeClearTimeout
|
||||
|
||||
atom.packages.packageStates = {}
|
||||
|
||||
serializedWindowState = null
|
||||
@@ -102,9 +106,9 @@ beforeEach ->
|
||||
spyOn(atom.menu, 'sendToBrowserProcess')
|
||||
|
||||
# reset config before each spec; don't load or save from/to `config.json`
|
||||
spyOn(Config::, 'load')
|
||||
spyOn(Config::, 'save')
|
||||
config = new Config({resourcePath, configDirPath: atom.getConfigDirPath()})
|
||||
spyOn(config, 'load')
|
||||
spyOn(config, 'save')
|
||||
atom.config = config
|
||||
atom.loadConfig()
|
||||
config.set "core.destroyEmptyPanes", false
|
||||
@@ -114,6 +118,7 @@ beforeEach ->
|
||||
config.set "core.disabledPackages", ["package-that-throws-an-exception",
|
||||
"package-with-broken-package-json", "package-with-broken-keymap"]
|
||||
config.set "editor.useShadowDOM", true
|
||||
advanceClock(1000)
|
||||
config.load.reset()
|
||||
config.save.reset()
|
||||
|
||||
@@ -121,8 +126,6 @@ beforeEach ->
|
||||
TextEditorElement::setUpdatedSynchronously(true)
|
||||
|
||||
spyOn(atom, "setRepresentedFilename")
|
||||
spyOn(window, "setTimeout").andCallFake window.fakeSetTimeout
|
||||
spyOn(window, "clearTimeout").andCallFake window.fakeClearTimeout
|
||||
spyOn(pathwatcher.File.prototype, "detectResurrectionAfterDelay").andCallFake -> @detectResurrection()
|
||||
spyOn(TextEditor.prototype, "shouldPromptToSave").andReturn false
|
||||
|
||||
@@ -204,10 +207,10 @@ jasmine.attachToDOM = (element) ->
|
||||
|
||||
deprecationsSnapshot = null
|
||||
jasmine.snapshotDeprecations = ->
|
||||
deprecationsSnapshot = Grim.getDeprecations() # suppress deprecations!!
|
||||
deprecationsSnapshot = _.clone(Grim.deprecations)
|
||||
|
||||
jasmine.restoreDeprecationsSnapshot = ->
|
||||
Grim.grimDeprecations = deprecationsSnapshot
|
||||
Grim.deprecations = deprecationsSnapshot
|
||||
|
||||
addCustomMatchers = (spec) ->
|
||||
spec.addMatchers
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
ChildProcess = require 'child_process'
|
||||
{EventEmitter} = require 'events'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
SquirrelUpdate = require '../src/browser/squirrel-update'
|
||||
|
||||
describe "Windows squirrel updates", ->
|
||||
tempHomeDirectory = null
|
||||
|
||||
beforeEach ->
|
||||
# Prevent the actually home directory from being manipulated
|
||||
tempHomeDirectory = temp.mkdirSync('atom-temp-home-')
|
||||
spyOn(fs, 'getHomeDirectory').andReturn(tempHomeDirectory)
|
||||
|
||||
# Prevent any commands from actually running and affecting the host
|
||||
originalSpawn = ChildProcess.spawn
|
||||
spyOn(ChildProcess, 'spawn').andCallFake (command, args) ->
|
||||
if path.basename(command) is 'Update.exe' and args?[0] is '--createShortcut'
|
||||
fs.writeFileSync(path.join(tempHomeDirectory, 'Desktop', 'Atom.lnk'), '')
|
||||
|
||||
# Just spawn something that won't actually modify the host
|
||||
if process.platform is 'win32'
|
||||
originalSpawn('dir')
|
||||
else
|
||||
originalSpawn('ls')
|
||||
|
||||
it "ignores errors spawning Squirrel", ->
|
||||
jasmine.unspy(ChildProcess, 'spawn')
|
||||
spyOn(ChildProcess, 'spawn').andCallFake -> throw new Error("EBUSY")
|
||||
|
||||
app = quit: jasmine.createSpy('quit')
|
||||
expect(SquirrelUpdate.handleStartupEvent(app, '--squirrel-install')).toBe true
|
||||
|
||||
waitsFor ->
|
||||
app.quit.callCount is 1
|
||||
|
||||
it "quits the app on all squirrel events", ->
|
||||
app = quit: jasmine.createSpy('quit')
|
||||
|
||||
expect(SquirrelUpdate.handleStartupEvent(app, '--squirrel-install')).toBe true
|
||||
|
||||
waitsFor ->
|
||||
app.quit.callCount is 1
|
||||
|
||||
runs ->
|
||||
app.quit.reset()
|
||||
expect(SquirrelUpdate.handleStartupEvent(app, '--squirrel-updated')).toBe true
|
||||
|
||||
waitsFor ->
|
||||
app.quit.callCount is 1
|
||||
|
||||
runs ->
|
||||
app.quit.reset()
|
||||
expect(SquirrelUpdate.handleStartupEvent(app, '--squirrel-uninstall')).toBe true
|
||||
|
||||
waitsFor ->
|
||||
app.quit.callCount is 1
|
||||
|
||||
runs ->
|
||||
app.quit.reset()
|
||||
expect(SquirrelUpdate.handleStartupEvent(app, '--squirrel-obsolete')).toBe true
|
||||
|
||||
waitsFor ->
|
||||
app.quit.callCount is 1
|
||||
|
||||
runs ->
|
||||
expect(SquirrelUpdate.handleStartupEvent(app, '--not-squirrel')).toBe false
|
||||
|
||||
it "keeps the desktop shortcut deleted on updates if it was previously deleted after install", ->
|
||||
desktopShortcutPath = path.join(tempHomeDirectory, 'Desktop', 'Atom.lnk')
|
||||
expect(fs.existsSync(desktopShortcutPath)).toBe false
|
||||
|
||||
app = quit: jasmine.createSpy('quit')
|
||||
expect(SquirrelUpdate.handleStartupEvent(app, '--squirrel-install')).toBe true
|
||||
|
||||
waitsFor ->
|
||||
app.quit.callCount is 1
|
||||
|
||||
runs ->
|
||||
app.quit.reset()
|
||||
expect(fs.existsSync(desktopShortcutPath)).toBe true
|
||||
fs.removeSync(desktopShortcutPath)
|
||||
expect(fs.existsSync(desktopShortcutPath)).toBe false
|
||||
expect(SquirrelUpdate.handleStartupEvent(app, '--squirrel-updated')).toBe true
|
||||
|
||||
waitsFor ->
|
||||
app.quit.callCount is 1
|
||||
|
||||
runs ->
|
||||
expect(fs.existsSync(desktopShortcutPath)).toBe false
|
||||
|
||||
describe ".restartAtom", ->
|
||||
it "quits the app and spawns a new one", ->
|
||||
app = new EventEmitter()
|
||||
app.quit = jasmine.createSpy('quit')
|
||||
|
||||
SquirrelUpdate.restartAtom(app)
|
||||
expect(app.quit.callCount).toBe 1
|
||||
|
||||
expect(ChildProcess.spawn.callCount).toBe 0
|
||||
app.emit('will-quit')
|
||||
expect(ChildProcess.spawn.callCount).toBe 1
|
||||
expect(path.basename(ChildProcess.spawn.argsForCall[0][0])).toBe 'atom.cmd'
|
||||
@@ -53,14 +53,16 @@ describe "StyleManager", ->
|
||||
expect(addEvents[0].getAttribute('source-path')).toBe '/foo/bar'
|
||||
expect(addEvents[0].textContent).toBe "a {color: yellow;}"
|
||||
|
||||
describe "when a group parameter is specified", ->
|
||||
it "inserts the stylesheet at the end of any existing stylesheets for the same group", ->
|
||||
manager.addStyleSheet("a {color: red}", group: 'a')
|
||||
manager.addStyleSheet("a {color: blue}", group: 'b')
|
||||
manager.addStyleSheet("a {color: green}", group: 'a')
|
||||
describe "when a priority parameter is specified", ->
|
||||
it "inserts the style sheet based on the priority", ->
|
||||
manager.addStyleSheet("a {color: red}", priority: 1)
|
||||
manager.addStyleSheet("a {color: blue}", priority: 0)
|
||||
manager.addStyleSheet("a {color: green}", priority: 2)
|
||||
manager.addStyleSheet("a {color: yellow}", priority: 1)
|
||||
|
||||
expect(manager.getStyleElements().map (elt) -> elt.textContent).toEqual [
|
||||
"a {color: red}"
|
||||
"a {color: green}"
|
||||
"a {color: blue}"
|
||||
"a {color: red}"
|
||||
"a {color: yellow}"
|
||||
"a {color: green}"
|
||||
]
|
||||
|
||||
@@ -32,16 +32,18 @@ describe "StylesElement", ->
|
||||
expect(element.children[initialChildCount].textContent).toBe "a {color: blue;}"
|
||||
expect(removedStyleElements).toEqual [addedStyleElements[0]]
|
||||
|
||||
it "orders style elements by group", ->
|
||||
it "orders style elements by priority", ->
|
||||
initialChildCount = element.children.length
|
||||
|
||||
atom.styles.addStyleSheet("a {color: red}", group: 'a')
|
||||
atom.styles.addStyleSheet("a {color: blue}", group: 'b')
|
||||
atom.styles.addStyleSheet("a {color: green}", group: 'a')
|
||||
atom.styles.addStyleSheet("a {color: red}", priority: 1)
|
||||
atom.styles.addStyleSheet("a {color: blue}", priority: 0)
|
||||
atom.styles.addStyleSheet("a {color: green}", priority: 2)
|
||||
atom.styles.addStyleSheet("a {color: yellow}", priority: 1)
|
||||
|
||||
expect(element.children[initialChildCount].textContent).toBe "a {color: red}"
|
||||
expect(element.children[initialChildCount + 1].textContent).toBe "a {color: green}"
|
||||
expect(element.children[initialChildCount + 2].textContent).toBe "a {color: blue}"
|
||||
expect(element.children[initialChildCount].textContent).toBe "a {color: blue}"
|
||||
expect(element.children[initialChildCount + 1].textContent).toBe "a {color: red}"
|
||||
expect(element.children[initialChildCount + 2].textContent).toBe "a {color: yellow}"
|
||||
expect(element.children[initialChildCount + 3].textContent).toBe "a {color: green}"
|
||||
|
||||
it "updates existing style nodes when style elements are updated", ->
|
||||
initialChildCount = element.children.length
|
||||
|
||||
@@ -755,7 +755,6 @@ describe "TextEditorComponent", ->
|
||||
expect(cursorNode.offsetWidth).toBe charWidth
|
||||
|
||||
it "blinks cursors when they aren't moving", ->
|
||||
spyOn(_._, 'now').andCallFake -> window.now # Ensure _.debounce is based on our fake spec timeline
|
||||
cursorsNode = componentNode.querySelector('.cursors')
|
||||
|
||||
expect(cursorsNode.classList.contains('blink-off')).toBe false
|
||||
@@ -1612,6 +1611,22 @@ describe "TextEditorComponent", ->
|
||||
expect(nextAnimationFrame).toBe noAnimationFrame
|
||||
expect(editor.getSelectedScreenRange()).toEqual [[2, 4], [6, 8]]
|
||||
|
||||
describe "when the editor is destroyed while dragging", ->
|
||||
it "cleans up the handlers for window.mouseup and window.mousemove", ->
|
||||
linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([2, 4]), which: 1))
|
||||
linesNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenPosition([6, 8]), which: 1))
|
||||
nextAnimationFrame()
|
||||
|
||||
spyOn(window, 'removeEventListener').andCallThrough()
|
||||
|
||||
linesNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenPosition([6, 10]), which: 1))
|
||||
editor.destroy()
|
||||
nextAnimationFrame()
|
||||
|
||||
call.args.pop() for call in window.removeEventListener.calls
|
||||
expect(window.removeEventListener).toHaveBeenCalledWith('mouseup')
|
||||
expect(window.removeEventListener).toHaveBeenCalledWith('mousemove')
|
||||
|
||||
describe "when a line is folded", ->
|
||||
beforeEach ->
|
||||
editor.foldBufferRow 4
|
||||
@@ -2032,8 +2047,6 @@ describe "TextEditorComponent", ->
|
||||
expect(component.mouseWheelScreenRow).toBe null
|
||||
|
||||
it "clears the mouseWheelScreenRow after a delay even if the event does not cause scrolling", ->
|
||||
spyOn(_._, 'now').andCallFake -> window.now # Ensure _.debounce is based on our fake spec timeline
|
||||
|
||||
expect(editor.getScrollTop()).toBe 0
|
||||
|
||||
lineNode = componentNode.querySelector('.line')
|
||||
@@ -2577,9 +2590,9 @@ describe "TextEditorComponent", ->
|
||||
|
||||
describe 'soft wrap settings', ->
|
||||
beforeEach ->
|
||||
atom.config.set '.source.coffee', 'editor.softWrap', true
|
||||
atom.config.set '.source.coffee', 'editor.preferredLineLength', 17
|
||||
atom.config.set '.source.coffee', 'editor.softWrapAtPreferredLineLength', true
|
||||
atom.config.set 'editor.softWrap', true, scopeSelector: '.source.coffee'
|
||||
atom.config.set 'editor.preferredLineLength', 17, scopeSelector: '.source.coffee'
|
||||
atom.config.set 'editor.softWrapAtPreferredLineLength', true, scopeSelector: '.source.coffee'
|
||||
|
||||
editor.setEditorWidthInChars(20)
|
||||
coffeeEditor.setEditorWidthInChars(20)
|
||||
@@ -2589,18 +2602,18 @@ describe "TextEditorComponent", ->
|
||||
expect(coffeeEditor.lineTextForScreenRow(3)).toEqual ' return items '
|
||||
|
||||
it 'updates the wrapped lines when editor.preferredLineLength changes', ->
|
||||
atom.config.set '.source.coffee', 'editor.preferredLineLength', 20
|
||||
atom.config.set 'editor.preferredLineLength', 20, scopeSelector: '.source.coffee'
|
||||
expect(coffeeEditor.lineTextForScreenRow(2)).toEqual ' return items if '
|
||||
|
||||
it 'updates the wrapped lines when editor.softWrapAtPreferredLineLength changes', ->
|
||||
atom.config.set '.source.coffee', 'editor.softWrapAtPreferredLineLength', false
|
||||
atom.config.set 'editor.softWrapAtPreferredLineLength', false, scopeSelector: '.source.coffee'
|
||||
expect(coffeeEditor.lineTextForScreenRow(2)).toEqual ' return items if '
|
||||
|
||||
it 'updates the wrapped lines when editor.softWrap changes', ->
|
||||
atom.config.set '.source.coffee', 'editor.softWrap', false
|
||||
atom.config.set 'editor.softWrap', false, scopeSelector: '.source.coffee'
|
||||
expect(coffeeEditor.lineTextForScreenRow(2)).toEqual ' return items if items.length <= 1'
|
||||
|
||||
atom.config.set '.source.coffee', 'editor.softWrap', true
|
||||
atom.config.set 'editor.softWrap', true, scopeSelector: '.source.coffee'
|
||||
expect(coffeeEditor.lineTextForScreenRow(3)).toEqual ' return items '
|
||||
|
||||
it 'updates the wrapped lines when the grammar changes', ->
|
||||
@@ -2628,11 +2641,11 @@ describe "TextEditorComponent", ->
|
||||
tab: 'F'
|
||||
cr: 'E'
|
||||
|
||||
atom.config.set '.source.js', 'editor.showInvisibles', true
|
||||
atom.config.set '.source.js', 'editor.invisibles', jsInvisibles
|
||||
atom.config.set 'editor.showInvisibles', true, scopeSelector: '.source.js'
|
||||
atom.config.set 'editor.invisibles', jsInvisibles, scopeSelector: '.source.js'
|
||||
|
||||
atom.config.set '.source.coffee', 'editor.showInvisibles', false
|
||||
atom.config.set '.source.coffee', 'editor.invisibles', coffeeInvisibles
|
||||
atom.config.set 'editor.showInvisibles', false, scopeSelector: '.source.coffee'
|
||||
atom.config.set 'editor.invisibles', coffeeInvisibles, scopeSelector: '.source.coffee'
|
||||
|
||||
editor.setText " a line with tabs\tand spaces \n"
|
||||
nextAnimationFrame()
|
||||
@@ -2648,7 +2661,7 @@ describe "TextEditorComponent", ->
|
||||
it "re-renders the invisibles when the invisible settings change", ->
|
||||
jsGrammar = editor.getGrammar()
|
||||
editor.setGrammar(coffeeEditor.getGrammar())
|
||||
atom.config.set '.source.coffee', 'editor.showInvisibles', true
|
||||
atom.config.set 'editor.showInvisibles', true, scopeSelector: '.source.coffee'
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{coffeeInvisibles.space}a line with tabs#{coffeeInvisibles.tab}and spaces#{coffeeInvisibles.space}#{coffeeInvisibles.eol}"
|
||||
|
||||
@@ -2657,7 +2670,7 @@ describe "TextEditorComponent", ->
|
||||
space: 'E'
|
||||
tab: 'W'
|
||||
cr: 'I'
|
||||
atom.config.set '.source.coffee', 'editor.invisibles', newInvisibles
|
||||
atom.config.set 'editor.invisibles', newInvisibles, scopeSelector: '.source.coffee'
|
||||
nextAnimationFrame()
|
||||
expect(component.lineNodeForScreenRow(0).textContent).toBe "#{newInvisibles.space}a line with tabs#{newInvisibles.tab}and spaces#{newInvisibles.space}#{newInvisibles.eol}"
|
||||
|
||||
@@ -2667,8 +2680,8 @@ describe "TextEditorComponent", ->
|
||||
|
||||
describe 'editor.showIndentGuide', ->
|
||||
beforeEach ->
|
||||
atom.config.set '.source.js', 'editor.showIndentGuide', true
|
||||
atom.config.set '.source.coffee', 'editor.showIndentGuide', false
|
||||
atom.config.set 'editor.showIndentGuide', true, scopeSelector: '.source.js'
|
||||
atom.config.set 'editor.showIndentGuide', false, scopeSelector: '.source.coffee'
|
||||
|
||||
it "has an 'indent-guide' class when scoped editor.showIndentGuide is true, but not when scoped editor.showIndentGuide is false", ->
|
||||
line1LeafNodes = getLeafNodes(component.lineNodeForScreenRow(1))
|
||||
@@ -2689,7 +2702,7 @@ describe "TextEditorComponent", ->
|
||||
expect(line1LeafNodes[0].classList.contains('indent-guide')).toBe true
|
||||
expect(line1LeafNodes[1].classList.contains('indent-guide')).toBe false
|
||||
|
||||
atom.config.set '.source.js', 'editor.showIndentGuide', false
|
||||
atom.config.set 'editor.showIndentGuide', false, scopeSelector: '.source.js'
|
||||
|
||||
line1LeafNodes = getLeafNodes(component.lineNodeForScreenRow(1))
|
||||
expect(line1LeafNodes[0].textContent).toBe ' '
|
||||
@@ -2697,26 +2710,35 @@ describe "TextEditorComponent", ->
|
||||
expect(line1LeafNodes[1].classList.contains('indent-guide')).toBe false
|
||||
|
||||
describe "middle mouse paste on Linux", ->
|
||||
it "pastes the previously selected text", ->
|
||||
originalPlatform = null
|
||||
|
||||
beforeEach ->
|
||||
originalPlatform = process.platform
|
||||
Object.defineProperty process, 'platform', value: 'linux'
|
||||
|
||||
afterEach ->
|
||||
Object.defineProperty process, 'platform', value: originalPlatform
|
||||
|
||||
it "pastes the previously selected text at the clicked location", ->
|
||||
jasmine.unspy(window, 'setTimeout')
|
||||
clipboardWrittenTo = false
|
||||
spyOn(require('ipc'), 'send').andCallFake (eventName, selectedText) ->
|
||||
if eventName is 'write-text-to-selection-clipboard'
|
||||
require('clipboard').writeText(selectedText, 'selection')
|
||||
clipboardWrittenTo = true
|
||||
|
||||
atom.clipboard.write('')
|
||||
component.listenForMiddleMousePaste()
|
||||
|
||||
editor.setCursorBufferPosition([10, 0])
|
||||
componentNode.querySelector('.scroll-view').dispatchEvent(buildMouseEvent('mouseup', which: 2))
|
||||
|
||||
expect(atom.clipboard.read()).toBe ''
|
||||
expect(editor.lineTextForBufferRow(10)).toBe ''
|
||||
|
||||
component.trackSelectionClipboard()
|
||||
editor.setSelectedBufferRange([[1, 6], [1, 10]])
|
||||
editor.setCursorBufferPosition([10, 0])
|
||||
componentNode.querySelector('.scroll-view').dispatchEvent(buildMouseEvent('mouseup', which: 2))
|
||||
|
||||
expect(atom.clipboard.read()).toBe 'sort'
|
||||
expect(editor.lineTextForBufferRow(10)).toBe 'sort'
|
||||
waitsFor ->
|
||||
clipboardWrittenTo
|
||||
|
||||
runs ->
|
||||
componentNode.querySelector('.scroll-view').dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([10, 0]), button: 1))
|
||||
componentNode.querySelector('.scroll-view').dispatchEvent(buildMouseEvent('mouseup', clientCoordinatesForScreenPosition([10, 0]), which: 2))
|
||||
expect(atom.clipboard.read()).toBe 'sort'
|
||||
expect(editor.lineTextForBufferRow(10)).toBe 'sort'
|
||||
|
||||
buildMouseEvent = (type, properties...) ->
|
||||
properties = extend({bubbles: true, cancelable: true}, properties...)
|
||||
|
||||
@@ -42,9 +42,12 @@ describe "TextEditorElement", ->
|
||||
|
||||
component = element.component
|
||||
expect(component.isMounted()).toBe true
|
||||
element.getModel().destroy()
|
||||
element.remove()
|
||||
expect(component.isMounted()).toBe false
|
||||
|
||||
jasmine.attachToDOM(element)
|
||||
expect(element.component.isMounted()).toBe true
|
||||
|
||||
describe "when the editor.useShadowDOM config option is false", ->
|
||||
it "mounts the react component and unmounts when removed from the dom", ->
|
||||
atom.config.set('editor.useShadowDOM', false)
|
||||
|
||||
@@ -62,7 +62,6 @@ describe "TextEditor", ->
|
||||
atom.workspace.open('sample.less', initialLine: 5).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
buffer = editor.buffer
|
||||
expect(editor.getLastCursor().getBufferPosition().row).toEqual 5
|
||||
expect(editor.getLastCursor().getBufferPosition().column).toEqual 0
|
||||
|
||||
@@ -74,10 +73,37 @@ describe "TextEditor", ->
|
||||
atom.workspace.open('sample.less', initialColumn: 8).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
buffer = editor.buffer
|
||||
expect(editor.getLastCursor().getBufferPosition().row).toEqual 0
|
||||
expect(editor.getLastCursor().getBufferPosition().column).toEqual 8
|
||||
|
||||
describe "when the editor is reopened with an initialLine option", ->
|
||||
it "positions the cursor on the specified line", ->
|
||||
editor = null
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.less', initialLine: 5).then (o) -> editor = o
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.less', initialLine: 4).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.getLastCursor().getBufferPosition().row).toEqual 4
|
||||
expect(editor.getLastCursor().getBufferPosition().column).toEqual 0
|
||||
|
||||
describe "when the editor is reopened with an initialColumn option", ->
|
||||
it "positions the cursor on the specified column", ->
|
||||
editor = null
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.less', initialColumn: 8).then (o) -> editor = o
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('sample.less', initialColumn: 7).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.getLastCursor().getBufferPosition().row).toEqual 0
|
||||
expect(editor.getLastCursor().getBufferPosition().column).toEqual 7
|
||||
|
||||
describe ".copy()", ->
|
||||
it "returns a different edit session with the same initial state", ->
|
||||
editor.setSelectedBufferRange([[1, 2], [3, 4]])
|
||||
@@ -1327,7 +1353,7 @@ describe "TextEditor", ->
|
||||
coffeeEditor.selectWordsContainingCursors()
|
||||
expect(coffeeEditor.getSelectedBufferRange()).toEqual [[0, 6], [0, 15]]
|
||||
|
||||
atom.config.set '.source.coffee', 'editor.nonWordCharacters', 'qusort'
|
||||
atom.config.set 'editor.nonWordCharacters', 'qusort', scopeSelector: '.source.coffee'
|
||||
|
||||
coffeeEditor.setCursorBufferPosition [0, 9]
|
||||
coffeeEditor.selectWordsContainingCursors()
|
||||
@@ -3276,7 +3302,7 @@ describe "TextEditor", ->
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
it 'returns correct values based on the scope of the set grammars', ->
|
||||
atom.config.set '.source.coffee', 'editor.tabLength', 6
|
||||
atom.config.set 'editor.tabLength', 6, scopeSelector: '.source.coffee'
|
||||
|
||||
expect(editor.getTabLength()).toBe 2
|
||||
expect(coffeeEditor.getTabLength()).toBe 6
|
||||
@@ -3298,12 +3324,12 @@ describe "TextEditor", ->
|
||||
expect(editor.getTabLength()).toBe 2
|
||||
expect(editor.tokenizedLineForScreenRow(5).tokens[0].firstNonWhitespaceIndex).toBe 2
|
||||
|
||||
atom.config.set '.source.js', 'editor.tabLength', 6
|
||||
atom.config.set 'editor.tabLength', 6, scopeSelector: '.source.js'
|
||||
expect(editor.getTabLength()).toBe 6
|
||||
expect(editor.tokenizedLineForScreenRow(5).tokens[0].firstNonWhitespaceIndex).toBe 6
|
||||
|
||||
it 'updates the tab length when the grammar changes', ->
|
||||
atom.config.set '.source.coffee', 'editor.tabLength', 6
|
||||
atom.config.set 'editor.tabLength', 6, scopeSelector: '.source.coffee'
|
||||
|
||||
expect(editor.getTabLength()).toBe 2
|
||||
expect(editor.tokenizedLineForScreenRow(5).tokens[0].firstNonWhitespaceIndex).toBe 2
|
||||
@@ -3473,8 +3499,8 @@ describe "TextEditor", ->
|
||||
atom.project.open('coffee.coffee', autoIndent: false).then (o) -> coffeeEditor = o
|
||||
|
||||
runs ->
|
||||
atom.config.set('.source.js', 'editor.autoIndent', true)
|
||||
atom.config.set('.source.coffee', 'editor.autoIndent', false)
|
||||
atom.config.set('editor.autoIndent', true, scopeSelector: '.source.js')
|
||||
atom.config.set('editor.autoIndent', false, scopeSelector: '.source.coffee')
|
||||
|
||||
afterEach: ->
|
||||
atom.packages.deactivatePackages()
|
||||
@@ -3766,8 +3792,12 @@ describe "TextEditor", ->
|
||||
it "updates the grammar based on grammar overrides", ->
|
||||
expect(editor.getGrammar().name).toBe 'JavaScript'
|
||||
atom.grammars.setGrammarOverrideForPath(editor.getPath(), 'source.coffee')
|
||||
callback = jasmine.createSpy('callback')
|
||||
editor.onDidChangeGrammar(callback)
|
||||
editor.reloadGrammar()
|
||||
expect(editor.getGrammar().name).toBe 'CoffeeScript'
|
||||
expect(callback.callCount).toBe 1
|
||||
expect(callback.argsForCall[0][0]).toBe atom.grammars.grammarForScopeName('source.coffee')
|
||||
|
||||
describe "when the editor's grammar has an injection selector", ->
|
||||
beforeEach ->
|
||||
|
||||
@@ -96,8 +96,8 @@ describe "ThemeManager", ->
|
||||
|
||||
runs ->
|
||||
reloadHandler.reset()
|
||||
expect($('style[group=theme]')).toHaveLength 2
|
||||
expect($('style[group=theme]:eq(0)').attr('source-path')).toMatch /atom-dark-ui/
|
||||
expect($('style[priority=1]')).toHaveLength 2
|
||||
expect($('style[priority=1]:eq(0)').attr('source-path')).toMatch /atom-dark-ui/
|
||||
atom.config.set('core.themes', ['atom-light-ui', 'atom-dark-ui'])
|
||||
|
||||
waitsFor ->
|
||||
@@ -105,9 +105,9 @@ describe "ThemeManager", ->
|
||||
|
||||
runs ->
|
||||
reloadHandler.reset()
|
||||
expect($('style[group=theme]')).toHaveLength 2
|
||||
expect($('style[group=theme]:eq(0)').attr('source-path')).toMatch /atom-dark-ui/
|
||||
expect($('style[group=theme]:eq(1)').attr('source-path')).toMatch /atom-light-ui/
|
||||
expect($('style[priority=1]')).toHaveLength 2
|
||||
expect($('style[priority=1]:eq(0)').attr('source-path')).toMatch /atom-dark-ui/
|
||||
expect($('style[priority=1]:eq(1)').attr('source-path')).toMatch /atom-light-ui/
|
||||
atom.config.set('core.themes', [])
|
||||
|
||||
waitsFor ->
|
||||
@@ -115,7 +115,7 @@ describe "ThemeManager", ->
|
||||
|
||||
runs ->
|
||||
reloadHandler.reset()
|
||||
expect($('style[group=theme]')).toHaveLength 2
|
||||
expect($('style[priority=1]')).toHaveLength 2
|
||||
# atom-dark-ui has an directory path, the syntax one doesn't
|
||||
atom.config.set('core.themes', ['theme-with-index-less', 'atom-dark-ui'])
|
||||
|
||||
@@ -123,15 +123,40 @@ describe "ThemeManager", ->
|
||||
reloadHandler.callCount == 1
|
||||
|
||||
runs ->
|
||||
expect($('style[group=theme]')).toHaveLength 2
|
||||
expect($('style[priority=1]')).toHaveLength 2
|
||||
importPaths = themeManager.getImportPaths()
|
||||
expect(importPaths.length).toBe 1
|
||||
expect(importPaths[0]).toContain 'atom-dark-ui'
|
||||
|
||||
it 'adds theme-* classes to the workspace for each active theme', ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
themeManager.onDidReloadAll reloadHandler = jasmine.createSpy()
|
||||
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
|
||||
runs ->
|
||||
expect(workspaceElement).toHaveClass 'theme-atom-dark-ui'
|
||||
|
||||
themeManager.onDidReloadAll reloadHandler = jasmine.createSpy()
|
||||
atom.config.set('core.themes', ['theme-with-ui-variables', 'theme-with-syntax-variables'])
|
||||
|
||||
waitsFor ->
|
||||
reloadHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
# `theme-` twice as it prefixes the name with `theme-`
|
||||
expect(workspaceElement).toHaveClass 'theme-theme-with-ui-variables'
|
||||
expect(workspaceElement).toHaveClass 'theme-theme-with-syntax-variables'
|
||||
expect(workspaceElement).not.toHaveClass 'theme-atom-dark-ui'
|
||||
expect(workspaceElement).not.toHaveClass 'theme-atom-dark-syntax'
|
||||
|
||||
describe "when a theme fails to load", ->
|
||||
it "logs a warning", ->
|
||||
spyOn(console, 'warn')
|
||||
expect(-> atom.packages.activatePackage('a-theme-that-will-not-be-found')).toThrow()
|
||||
atom.packages.activatePackage('a-theme-that-will-not-be-found')
|
||||
expect(console.warn.callCount).toBe 1
|
||||
expect(console.warn.argsForCall[0][0]).toContain "Could not resolve 'a-theme-that-will-not-be-found'"
|
||||
|
||||
describe "::requireStylesheet(path)", ->
|
||||
beforeEach ->
|
||||
@@ -223,11 +248,9 @@ describe "ThemeManager", ->
|
||||
|
||||
expect(stylesheetsChangedHandler).toHaveBeenCalled()
|
||||
|
||||
describe "base stylesheet loading", ->
|
||||
describe "base style sheet loading", ->
|
||||
workspaceElement = null
|
||||
beforeEach ->
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
workspaceElement.appendChild document.createElement('atom-text-editor')
|
||||
@@ -235,9 +258,6 @@ describe "ThemeManager", ->
|
||||
waitsForPromise ->
|
||||
themeManager.activateThemes()
|
||||
|
||||
beforeEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "loads the correct values from the theme's ui-variables file", ->
|
||||
themeManager.onDidReloadAll reloadHandler = jasmine.createSpy()
|
||||
atom.config.set('core.themes', ['theme-with-ui-variables', 'theme-with-syntax-variables'])
|
||||
@@ -269,22 +289,6 @@ describe "ThemeManager", ->
|
||||
# from within the theme itself
|
||||
expect($("atom-text-editor").css("background-color")).toBe "rgb(0, 152, 255)"
|
||||
|
||||
describe "theme classes on the workspace", ->
|
||||
it 'adds theme-* classes to the workspace for each active theme', ->
|
||||
expect(workspaceElement).toHaveClass 'theme-atom-dark-ui'
|
||||
|
||||
themeManager.onDidReloadAll reloadHandler = jasmine.createSpy()
|
||||
atom.config.set('core.themes', ['theme-with-ui-variables', 'theme-with-syntax-variables'])
|
||||
|
||||
waitsFor ->
|
||||
reloadHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
# `theme-` twice as it prefixes the name with `theme-`
|
||||
expect(workspaceElement).toHaveClass 'theme-theme-with-ui-variables'
|
||||
expect(workspaceElement).toHaveClass 'theme-theme-with-syntax-variables'
|
||||
expect(workspaceElement).not.toHaveClass 'theme-atom-dark-ui'
|
||||
expect(workspaceElement).not.toHaveClass 'theme-atom-dark-syntax'
|
||||
|
||||
describe "when the user stylesheet changes", ->
|
||||
beforeEach ->
|
||||
|
||||
@@ -14,14 +14,14 @@ describe "ViewRegistry", ->
|
||||
expect(registry.getView(node)).toBe node
|
||||
|
||||
describe "when passed a SpacePen view", ->
|
||||
it "returns the root node of the view with a __spacePenView property pointing at the SpacePen view", ->
|
||||
it "returns the root node of the view with a .spacePenView property pointing at the SpacePen view", ->
|
||||
class TestView extends View
|
||||
@content: -> @div "Hello"
|
||||
|
||||
view = new TestView
|
||||
node = registry.getView(view)
|
||||
expect(node.textContent).toBe "Hello"
|
||||
expect(node.__spacePenView).toBe view
|
||||
expect(node.spacePenView).toBe view
|
||||
|
||||
describe "when passed a model object", ->
|
||||
describe "when a view provider is registered matching the object's constructor", ->
|
||||
@@ -62,7 +62,7 @@ describe "ViewRegistry", ->
|
||||
node = registry.getView(model)
|
||||
|
||||
expect(node.textContent).toBe "hello"
|
||||
view = node.__spacePenView
|
||||
view = node.spacePenView
|
||||
expect(view instanceof TestView).toBe true
|
||||
expect(view.model).toBe model
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@ path = require 'path'
|
||||
temp = require 'temp'
|
||||
Workspace = require '../src/workspace'
|
||||
{View} = require '../src/space-pen-extensions'
|
||||
platform = require './spec-helper-platform'
|
||||
_ = require 'underscore-plus'
|
||||
fstream = require 'fstream'
|
||||
fs = require 'fs-plus'
|
||||
|
||||
describe "Workspace", ->
|
||||
workspace = null
|
||||
@@ -553,3 +557,287 @@ describe "Workspace", ->
|
||||
|
||||
expect(atom.workspace.panelForItem(item)).toBe panel
|
||||
expect(atom.workspace.panelForItem(itemWithNoPanel)).toBe null
|
||||
|
||||
describe "::scan(regex, options, callback)", ->
|
||||
describe "when called with a regex", ->
|
||||
it "calls the callback with all regex results in all files in the project", ->
|
||||
results = []
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /(a)+/, (result) ->
|
||||
results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength(3)
|
||||
expect(results[0].filePath).toBe atom.project.resolve('a')
|
||||
expect(results[0].matches).toHaveLength(3)
|
||||
expect(results[0].matches[0]).toEqual
|
||||
matchText: 'aaa'
|
||||
lineText: 'aaa bbb'
|
||||
lineTextOffset: 0
|
||||
range: [[0, 0], [0, 3]]
|
||||
|
||||
it "works with with escaped literals (like $ and ^)", ->
|
||||
results = []
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /\$\w+/, (result) -> results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results.length).toBe 1
|
||||
|
||||
{filePath, matches} = results[0]
|
||||
expect(filePath).toBe atom.project.resolve('a')
|
||||
expect(matches).toHaveLength 1
|
||||
expect(matches[0]).toEqual
|
||||
matchText: '$bill'
|
||||
lineText: 'dollar$bill'
|
||||
lineTextOffset: 0
|
||||
range: [[2, 6], [2, 11]]
|
||||
|
||||
it "works on evil filenames", ->
|
||||
platform.generateEvilFiles()
|
||||
atom.project.setPaths([path.join(__dirname, 'fixtures', 'evil-files')])
|
||||
paths = []
|
||||
matches = []
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /evil/, (result) ->
|
||||
paths.push(result.filePath)
|
||||
matches = matches.concat(result.matches)
|
||||
|
||||
runs ->
|
||||
_.each(matches, (m) -> expect(m.matchText).toEqual 'evil')
|
||||
|
||||
if platform.isWindows()
|
||||
expect(paths.length).toBe 3
|
||||
expect(paths[0]).toMatch /a_file_with_utf8.txt$/
|
||||
expect(paths[1]).toMatch /file with spaces.txt$/
|
||||
expect(path.basename(paths[2])).toBe "utfa\u0306.md"
|
||||
else
|
||||
expect(paths.length).toBe 5
|
||||
expect(paths[0]).toMatch /a_file_with_utf8.txt$/
|
||||
expect(paths[1]).toMatch /file with spaces.txt$/
|
||||
expect(paths[2]).toMatch /goddam\nnewlines$/m
|
||||
expect(paths[3]).toMatch /quote".txt$/m
|
||||
expect(path.basename(paths[4])).toBe "utfa\u0306.md"
|
||||
|
||||
it "ignores case if the regex includes the `i` flag", ->
|
||||
results = []
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /DOLLAR/i, (result) -> results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 1
|
||||
|
||||
describe "when the core.excludeVcsIgnoredPaths config is truthy", ->
|
||||
[projectPath, ignoredPath] = []
|
||||
|
||||
beforeEach ->
|
||||
sourceProjectPath = path.join(__dirname, 'fixtures', 'git', 'working-dir')
|
||||
projectPath = path.join(temp.mkdirSync("atom"))
|
||||
|
||||
writerStream = fstream.Writer(projectPath)
|
||||
fstream.Reader(sourceProjectPath).pipe(writerStream)
|
||||
|
||||
waitsFor (done) ->
|
||||
writerStream.on 'close', done
|
||||
writerStream.on 'error', done
|
||||
|
||||
runs ->
|
||||
fs.rename(path.join(projectPath, 'git.git'), path.join(projectPath, '.git'))
|
||||
ignoredPath = path.join(projectPath, 'ignored.txt')
|
||||
fs.writeFileSync(ignoredPath, 'this match should not be included')
|
||||
|
||||
afterEach ->
|
||||
fs.removeSync(projectPath) if fs.existsSync(projectPath)
|
||||
|
||||
it "excludes ignored files", ->
|
||||
atom.project.setPaths([projectPath])
|
||||
atom.config.set('core.excludeVcsIgnoredPaths', true)
|
||||
resultHandler = jasmine.createSpy("result found")
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /match/, (results) ->
|
||||
resultHandler()
|
||||
|
||||
runs ->
|
||||
expect(resultHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "includes only files when a directory filter is specified", ->
|
||||
projectPath = path.join(path.join(__dirname, 'fixtures', 'dir'))
|
||||
atom.project.setPaths([projectPath])
|
||||
|
||||
filePath = path.join(projectPath, 'a-dir', 'oh-git')
|
||||
|
||||
paths = []
|
||||
matches = []
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /aaa/, paths: ["a-dir#{path.sep}"], (result) ->
|
||||
paths.push(result.filePath)
|
||||
matches = matches.concat(result.matches)
|
||||
|
||||
runs ->
|
||||
expect(paths.length).toBe 1
|
||||
expect(paths[0]).toBe filePath
|
||||
expect(matches.length).toBe 1
|
||||
|
||||
it "includes files and folders that begin with a '.'", ->
|
||||
projectPath = temp.mkdirSync()
|
||||
filePath = path.join(projectPath, '.text')
|
||||
fs.writeFileSync(filePath, 'match this')
|
||||
atom.project.setPaths([projectPath])
|
||||
paths = []
|
||||
matches = []
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /match this/, (result) ->
|
||||
paths.push(result.filePath)
|
||||
matches = matches.concat(result.matches)
|
||||
|
||||
runs ->
|
||||
expect(paths.length).toBe 1
|
||||
expect(paths[0]).toBe filePath
|
||||
expect(matches.length).toBe 1
|
||||
|
||||
it "excludes values in core.ignoredNames", ->
|
||||
projectPath = path.join(__dirname, 'fixtures', 'git', 'working-dir')
|
||||
ignoredNames = atom.config.get("core.ignoredNames")
|
||||
ignoredNames.push("a")
|
||||
atom.config.set("core.ignoredNames", ignoredNames)
|
||||
|
||||
resultHandler = jasmine.createSpy("result found")
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /dollar/, (results) ->
|
||||
resultHandler()
|
||||
|
||||
runs ->
|
||||
expect(resultHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "scans buffer contents if the buffer is modified", ->
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('a').then (o) ->
|
||||
editor = o
|
||||
editor.setText("Elephant")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /a|Elephant/, (result) -> results.push result
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 3
|
||||
resultForA = _.find results, ({filePath}) -> path.basename(filePath) == 'a'
|
||||
expect(resultForA.matches).toHaveLength 1
|
||||
expect(resultForA.matches[0].matchText).toBe 'Elephant'
|
||||
|
||||
it "ignores buffers outside the project", ->
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open(temp.openSync().path).then (o) ->
|
||||
editor = o
|
||||
editor.setText("Elephant")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /Elephant/, (result) -> results.push result
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 0
|
||||
|
||||
describe "::replace(regex, replacementText, paths, iterator)", ->
|
||||
[filePath, commentFilePath, sampleContent, sampleCommentContent] = []
|
||||
|
||||
beforeEach ->
|
||||
atom.project.setPaths([atom.project.resolve('../')])
|
||||
|
||||
filePath = atom.project.resolve('sample.js')
|
||||
commentFilePath = atom.project.resolve('sample-with-comments.js')
|
||||
sampleContent = fs.readFileSync(filePath).toString()
|
||||
sampleCommentContent = fs.readFileSync(commentFilePath).toString()
|
||||
|
||||
afterEach ->
|
||||
fs.writeFileSync(filePath, sampleContent)
|
||||
fs.writeFileSync(commentFilePath, sampleCommentContent)
|
||||
|
||||
describe "when a file doesn't exist", ->
|
||||
it "calls back with an error", ->
|
||||
errors = []
|
||||
missingPath = path.resolve('/not-a-file.js')
|
||||
expect(fs.existsSync(missingPath)).toBeFalsy()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.replace /items/gi, 'items', [missingPath], (result, error) ->
|
||||
errors.push(error)
|
||||
|
||||
runs ->
|
||||
expect(errors).toHaveLength 1
|
||||
expect(errors[0].path).toBe missingPath
|
||||
|
||||
describe "when called with unopened files", ->
|
||||
it "replaces properly", ->
|
||||
results = []
|
||||
waitsForPromise ->
|
||||
atom.workspace.replace /items/gi, 'items', [filePath], (result) ->
|
||||
results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 1
|
||||
expect(results[0].filePath).toBe filePath
|
||||
expect(results[0].replacements).toBe 6
|
||||
|
||||
describe "when a buffer is already open", ->
|
||||
it "replaces properly and saves when not modified", ->
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(editor.isModified()).toBeFalsy()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.replace /items/gi, 'items', [filePath], (result) ->
|
||||
results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 1
|
||||
expect(results[0].filePath).toBe filePath
|
||||
expect(results[0].replacements).toBe 6
|
||||
|
||||
expect(editor.isModified()).toBeFalsy()
|
||||
|
||||
it "does not replace when the path is not specified", ->
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample-with-comments.js').then (o) -> editor = o
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.replace /items/gi, 'items', [commentFilePath], (result) ->
|
||||
results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 1
|
||||
expect(results[0].filePath).toBe commentFilePath
|
||||
|
||||
it "does NOT save when modified", ->
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('sample.js').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
editor.buffer.setTextInRange([[0,0],[0,0]], 'omg')
|
||||
expect(editor.isModified()).toBeTruthy()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.replace /items/gi, 'okthen', [filePath], (result) ->
|
||||
results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 1
|
||||
expect(results[0].filePath).toBe filePath
|
||||
expect(results[0].replacements).toBe 6
|
||||
|
||||
expect(editor.isModified()).toBeTruthy()
|
||||
|
||||
@@ -341,6 +341,10 @@ class Atom extends Model
|
||||
inDevMode: ->
|
||||
@getLoadSettings().devMode
|
||||
|
||||
# Public: Is the current window in safe mode?
|
||||
inSafeMode: ->
|
||||
@getLoadSettings().safeMode
|
||||
|
||||
# Public: Is the current window running specs?
|
||||
inSpecMode: ->
|
||||
@getLoadSettings().isSpec
|
||||
|
||||
@@ -140,14 +140,18 @@ class AtomApplication
|
||||
|
||||
# Registers basic application commands, non-idempotent.
|
||||
handleEvents: ->
|
||||
getLoadSettings = =>
|
||||
devMode: @focusedWindow()?.devMode
|
||||
safeMode: @focusedWindow()?.safeMode
|
||||
|
||||
@on 'application:run-all-specs', -> @runSpecs(exitWhenDone: false, resourcePath: global.devResourcePath, safeMode: @focusedWindow()?.safeMode)
|
||||
@on 'application:run-benchmarks', -> @runBenchmarks()
|
||||
@on 'application:quit', -> app.quit()
|
||||
@on 'application:new-window', -> @openPath(windowDimensions: @focusedWindow()?.getDimensions())
|
||||
@on 'application:new-window', -> @openPath(_.extend(windowDimensions: @focusedWindow()?.getDimensions(), getLoadSettings()))
|
||||
@on 'application:new-file', -> (@focusedWindow() ? this).openPath()
|
||||
@on 'application:open', -> @promptForPath(type: 'all')
|
||||
@on 'application:open-file', -> @promptForPath(type: 'file')
|
||||
@on 'application:open-folder', -> @promptForPath(type: 'folder')
|
||||
@on 'application:open', -> @promptForPath(_.extend(type: 'all', getLoadSettings()))
|
||||
@on 'application:open-file', -> @promptForPath(_.extend(type: 'file', getLoadSettings()))
|
||||
@on 'application:open-folder', -> @promptForPath(_.extend(type: 'folder', getLoadSettings()))
|
||||
@on 'application:open-dev', -> @promptForPath(devMode: true)
|
||||
@on 'application:open-safe', -> @promptForPath(safeMode: true)
|
||||
@on 'application:inspect', ({x,y, atomWindow}) ->
|
||||
@@ -355,7 +359,7 @@ class AtomApplication
|
||||
|
||||
if existingWindow?
|
||||
openedWindow = existingWindow
|
||||
openedWindow.openPath(pathToOpen, initialLine)
|
||||
openedWindow.openPath(pathToOpen, initialLine, initialColumn)
|
||||
if openedWindow.isMinimized()
|
||||
openedWindow.restore()
|
||||
else
|
||||
|
||||
@@ -18,7 +18,7 @@ class AtomWindow
|
||||
isSpec: null
|
||||
|
||||
constructor: (settings={}) ->
|
||||
{@resourcePath, pathToOpen, initialLine, initialColumn, @isSpec, @exitWhenDone, @safeMode} = settings
|
||||
{@resourcePath, pathToOpen, initialLine, initialColumn, @isSpec, @exitWhenDone, @safeMode, @devMode} = settings
|
||||
|
||||
# Normalize to make sure drive letter case is consistent on Windows
|
||||
@resourcePath = path.normalize(@resourcePath) if @resourcePath
|
||||
@@ -38,6 +38,8 @@ class AtomWindow
|
||||
loadSettings.windowState ?= '{}'
|
||||
loadSettings.appVersion = app.getVersion()
|
||||
loadSettings.resourcePath = @resourcePath
|
||||
loadSettings.devMode ?= false
|
||||
loadSettings.safeMode ?= false
|
||||
|
||||
# Only send to the first non-spec window created
|
||||
if @constructor.includeShellLoadTime and not @isSpec
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
autoUpdater = null
|
||||
_ = require 'underscore-plus'
|
||||
{EventEmitter} = require 'events'
|
||||
path = require 'path'
|
||||
|
||||
IdleState = 'idle'
|
||||
CheckingState = 'checking'
|
||||
@@ -51,8 +52,7 @@ class AutoUpdateManager
|
||||
@emitUpdateAvailableEvent(@getWindows()...)
|
||||
|
||||
# Only released versions should check for updates.
|
||||
unless /\w{7}/.test(@version)
|
||||
@check(hidePopups: true)
|
||||
@check(hidePopups: true) unless /\w{7}/.test(@version)
|
||||
|
||||
switch process.platform
|
||||
when 'win32'
|
||||
@@ -86,12 +86,24 @@ class AutoUpdateManager
|
||||
onUpdateNotAvailable: =>
|
||||
autoUpdater.removeListener 'error', @onUpdateError
|
||||
dialog = require 'dialog'
|
||||
dialog.showMessageBox type: 'info', buttons: ['OK'], message: 'No update available.', detail: "Version #{@version} is the latest version."
|
||||
dialog.showMessageBox
|
||||
type: 'info'
|
||||
buttons: ['OK']
|
||||
icon: path.join(process.resourcesPath, 'app', 'atom.png')
|
||||
message: 'No update available.'
|
||||
title: 'No Update Available'
|
||||
detail: "Version #{@version} is the latest version."
|
||||
|
||||
onUpdateError: (event, message) =>
|
||||
autoUpdater.removeListener 'update-not-available', @onUpdateNotAvailable
|
||||
dialog = require 'dialog'
|
||||
dialog.showMessageBox type: 'warning', buttons: ['OK'], message: 'There was an error checking for updates.', detail: message
|
||||
dialog.showMessageBox
|
||||
type: 'warning'
|
||||
buttons: ['OK']
|
||||
icon: path.join(process.resourcesPath, 'app', 'atom.png')
|
||||
message: 'There was an error checking for updates.'
|
||||
title: 'Update Error'
|
||||
detail: message
|
||||
|
||||
getWindows: ->
|
||||
global.atomApplication.windows
|
||||
|
||||
@@ -9,7 +9,7 @@ class AutoUpdater
|
||||
|
||||
quitAndInstall: ->
|
||||
if SquirrelUpdate.existsSync()
|
||||
SquirrelUpdate.restartAtom()
|
||||
SquirrelUpdate.restartAtom(require('app'))
|
||||
else
|
||||
require('auto-updater').quitAndInstall()
|
||||
|
||||
|
||||
@@ -26,7 +26,8 @@ fs.lstatSyncNoException = (pathToStat) ->
|
||||
start = ->
|
||||
if process.platform is 'win32'
|
||||
SquirrelUpdate = require './squirrel-update'
|
||||
return if SquirrelUpdate.handleStartupEvent()
|
||||
squirrelCommand = process.argv[1]
|
||||
return if SquirrelUpdate.handleStartupEvent(app, squirrelCommand)
|
||||
|
||||
args = parseCommandLine()
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
app = require 'app'
|
||||
ChildProcess = require 'child_process'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
@@ -26,9 +25,15 @@ environmentKeyPath = 'HKCU\\Environment'
|
||||
# Spawn a command and invoke the callback when it completes with an error
|
||||
# and the output from standard out.
|
||||
spawn = (command, args, callback) ->
|
||||
spawnedProcess = ChildProcess.spawn(command, args)
|
||||
|
||||
stdout = ''
|
||||
|
||||
try
|
||||
spawnedProcess = ChildProcess.spawn(command, args)
|
||||
catch error
|
||||
# Spawn can throw an error
|
||||
process.nextTick -> callback?(error, stdout)
|
||||
return
|
||||
|
||||
spawnedProcess.stdout.on 'data', (data) -> stdout += data
|
||||
|
||||
error = null
|
||||
@@ -166,12 +171,29 @@ removeCommandsFromPath = (callback) ->
|
||||
|
||||
# Create a desktop and start menu shortcut by using the command line API
|
||||
# provided by Squirrel's Update.exe
|
||||
createShortcut = (callback) ->
|
||||
createShortcuts = (callback) ->
|
||||
spawnUpdate(['--createShortcut', exeName], callback)
|
||||
|
||||
# Update the desktop and start menu shortcuts by using the command line API
|
||||
# provided by Squirrel's Update.exe
|
||||
updateShortcuts = (callback) ->
|
||||
if homeDirectory = fs.getHomeDirectory()
|
||||
desktopShortcutPath = path.join(homeDirectory, 'Desktop', 'Atom.lnk')
|
||||
# Check if the desktop shortcut has been previously deleted and
|
||||
# and keep it deleted if it was
|
||||
fs.exists desktopShortcutPath, (desktopShortcutExists) ->
|
||||
createShortcuts ->
|
||||
if desktopShortcutExists
|
||||
callback()
|
||||
else
|
||||
# Remove the unwanted desktop shortcut that was recreated
|
||||
fs.unlink(desktopShortcutPath, callback)
|
||||
else
|
||||
createShortcuts(callback)
|
||||
|
||||
# Remove the desktop and start menu shortcuts by using the command line API
|
||||
# provided by Squirrel's Update.exe
|
||||
removeShortcut = (callback) ->
|
||||
removeShortcuts = (callback) ->
|
||||
spawnUpdate(['--removeShortcut', exeName], callback)
|
||||
|
||||
exports.spawn = spawnUpdate
|
||||
@@ -181,21 +203,29 @@ exports.existsSync = ->
|
||||
fs.existsSync(updateDotExe)
|
||||
|
||||
# Restart Atom using the version pointed to by the atom.cmd shim
|
||||
exports.restartAtom = ->
|
||||
app.once 'will-quit', -> spawn(path.join(binFolder, 'atom.cmd'))
|
||||
exports.restartAtom = (app) ->
|
||||
if projectPath = global.atomApplication?.lastFocusedWindow?.projectPath
|
||||
args = [projectPath]
|
||||
app.once 'will-quit', -> spawn(path.join(binFolder, 'atom.cmd'), args)
|
||||
app.quit()
|
||||
|
||||
# Handle squirrel events denoted by --squirrel-* command line arguments.
|
||||
exports.handleStartupEvent = ->
|
||||
switch process.argv[1]
|
||||
when '--squirrel-install', '--squirrel-updated'
|
||||
createShortcut ->
|
||||
exports.handleStartupEvent = (app, squirrelCommand) ->
|
||||
switch squirrelCommand
|
||||
when '--squirrel-install'
|
||||
createShortcuts ->
|
||||
installContextMenu ->
|
||||
addCommandsToPath ->
|
||||
app.quit()
|
||||
true
|
||||
when '--squirrel-updated'
|
||||
updateShortcuts ->
|
||||
installContextMenu ->
|
||||
addCommandsToPath ->
|
||||
app.quit()
|
||||
true
|
||||
when '--squirrel-uninstall'
|
||||
removeShortcut ->
|
||||
removeShortcuts ->
|
||||
uninstallContextMenu ->
|
||||
removeCommandsFromPath ->
|
||||
app.quit()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
_ = require 'underscore-plus'
|
||||
ChildProcess = require 'child_process'
|
||||
{Emitter} = require 'event-kit'
|
||||
path = require 'path'
|
||||
|
||||
# Extended: A wrapper which provides standard error/output line buffering for
|
||||
# Node's ChildProcess.
|
||||
@@ -47,12 +48,12 @@ class BufferedProcess
|
||||
@emitter = new Emitter
|
||||
options ?= {}
|
||||
# Related to joyent/node#2318
|
||||
if process.platform is "win32"
|
||||
if process.platform is 'win32'
|
||||
# Quote all arguments and escapes inner quotes
|
||||
if args?
|
||||
cmdArgs = args.filter (arg) -> arg?
|
||||
cmdArgs = cmdArgs.map (arg) ->
|
||||
if command in ['explorer.exe', 'explorer'] and /^\/[a-zA-Z]+,.*$/.test(arg)
|
||||
cmdArgs = cmdArgs.map (arg) =>
|
||||
if @isExplorerCommand(command) and /^\/[a-zA-Z]+,.*$/.test(arg)
|
||||
# Don't wrap /root,C:\folder style arguments to explorer calls in
|
||||
# quotes since they will not be interpreted correctly if they are
|
||||
arg
|
||||
@@ -67,7 +68,7 @@ class BufferedProcess
|
||||
cmdArgs = ['/s', '/c', "\"#{cmdArgs.join(' ')}\""]
|
||||
cmdOptions = _.clone(options)
|
||||
cmdOptions.windowsVerbatimArguments = true
|
||||
@process = ChildProcess.spawn(process.env.comspec or 'cmd.exe', cmdArgs, cmdOptions)
|
||||
@process = ChildProcess.spawn(@getCmdPath(), cmdArgs, cmdOptions)
|
||||
else
|
||||
@process = ChildProcess.spawn(command, args, options)
|
||||
@killed = false
|
||||
@@ -191,6 +192,22 @@ class BufferedProcess
|
||||
@process?.kill()
|
||||
@process = null
|
||||
|
||||
isExplorerCommand: (command) ->
|
||||
if command is 'explorer.exe' or command is 'explorer'
|
||||
true
|
||||
else if process.env.SystemRoot
|
||||
command is path.join(process.env.SystemRoot, 'explorer.exe') or command is path.join(process.env.SystemRoot, 'explorer')
|
||||
else
|
||||
false
|
||||
|
||||
getCmdPath: ->
|
||||
if process.env.comspec
|
||||
process.env.comspec
|
||||
else if process.env.SystemRoot
|
||||
path.join(process.env.SystemRoot, 'System32', 'cmd.exe')
|
||||
else
|
||||
'cmd.exe'
|
||||
|
||||
# Public: Terminate the process.
|
||||
kill: ->
|
||||
return if @killed
|
||||
|
||||
@@ -16,6 +16,11 @@ module.exports =
|
||||
type: 'boolean'
|
||||
default: true
|
||||
title: 'Exclude VCS Ignored Paths'
|
||||
followSymlinks:
|
||||
type: 'boolean'
|
||||
default: false
|
||||
title: 'Follow symlinks'
|
||||
description: 'Used when searching and when opening files with the fuzzy finder.'
|
||||
disabledPackages:
|
||||
type: 'array'
|
||||
default: []
|
||||
@@ -93,6 +98,11 @@ module.exports =
|
||||
type: ['string', 'null']
|
||||
|
||||
# These can be used as globals or scoped, thus defaults.
|
||||
completions:
|
||||
type: "array"
|
||||
items:
|
||||
type: "string"
|
||||
default: []
|
||||
fontFamily:
|
||||
type: 'string'
|
||||
default: ''
|
||||
@@ -158,9 +168,9 @@ module.exports =
|
||||
description: 'Disabling will improve editor font rendering but reduce scrolling performance.'
|
||||
useShadowDOM:
|
||||
type: 'boolean'
|
||||
default: false
|
||||
default: true
|
||||
title: 'Use Shadow DOM'
|
||||
description: 'Enable to test out themes and packages with the new shadow DOM before it ships by default.'
|
||||
description: 'Disable if you experience styling issues with packages or themes. Be sure to open an issue on the relevant package or theme, because this option is going away eventually.'
|
||||
confirmCheckoutHeadRevision:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
|
||||
+272
-186
@@ -313,11 +313,13 @@ class Config
|
||||
@defaultSettings = {}
|
||||
@settings = {}
|
||||
@scopedSettingsStore = new ScopedPropertyStore
|
||||
@usersScopedSettings = new CompositeDisposable
|
||||
@usersScopedSettingPriority = {priority: 1000}
|
||||
@configFileHasErrors = false
|
||||
@configFilePath = fs.resolve(@configDirPath, 'config', ['json', 'cson'])
|
||||
@configFilePath ?= path.join(@configDirPath, 'config.cson')
|
||||
@transactDepth = 0
|
||||
|
||||
@debouncedSave = _.debounce(@save, 100)
|
||||
@debouncedLoad = _.debounce(@loadUserConfig, 100)
|
||||
|
||||
###
|
||||
Section: Config Subscription
|
||||
@@ -337,32 +339,36 @@ class Config
|
||||
# # do stuff with value
|
||||
# ```
|
||||
#
|
||||
# * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from
|
||||
# the root of the syntax tree to a token. Get one by calling
|
||||
# {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples.
|
||||
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
|
||||
# for more information.
|
||||
# * `keyPath` {String} name of the key to observe
|
||||
# * `options` {Object}
|
||||
# * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from
|
||||
# the root of the syntax tree to a token. Get one by calling
|
||||
# {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples.
|
||||
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
|
||||
# for more information.
|
||||
# * `callback` {Function} to call when the value of the key changes.
|
||||
# * `value` the new value of the key
|
||||
#
|
||||
# Returns a {Disposable} with the following keys on which you can call
|
||||
# `.dispose()` to unsubscribe.
|
||||
observe: (scopeDescriptor, keyPath, options, callback) ->
|
||||
args = Array::slice.call(arguments)
|
||||
if args.length is 2
|
||||
# observe(keyPath, callback)
|
||||
[keyPath, callback, scopeDescriptor, options] = args
|
||||
else if args.length is 3 and (Array.isArray(scopeDescriptor) or scopeDescriptor instanceof ScopeDescriptor)
|
||||
# observe(scopeDescriptor, keyPath, callback)
|
||||
[scopeDescriptor, keyPath, callback, options] = args
|
||||
else if args.length is 3 and _.isString(scopeDescriptor) and _.isObject(keyPath)
|
||||
# observe(keyPath, options, callback) # Deprecated!
|
||||
[keyPath, options, callback, scopeDescriptor] = args
|
||||
|
||||
message = ""
|
||||
message = "`callNow` was set to false. Use ::onDidChange instead. Note that ::onDidChange calls back with different arguments." if options.callNow == false
|
||||
Grim.deprecate "Config::observe no longer supports options; see https://atom.io/docs/api/latest/Config. #{message}"
|
||||
observe: ->
|
||||
if arguments.length is 2
|
||||
[keyPath, callback] = arguments
|
||||
else if arguments.length is 3 and (_.isArray(arguments[0]) or arguments[0] instanceof ScopeDescriptor)
|
||||
Grim.deprecate """
|
||||
Passing a scope descriptor as the first argument to Config::observe is deprecated.
|
||||
Pass a `scope` in an options hash as the third argument instead.
|
||||
"""
|
||||
[scopeDescriptor, keyPath, callback] = arguments
|
||||
else if arguments.length is 3 and (_.isString(arguments[0]) and _.isObject(arguments[1]))
|
||||
[keyPath, options, callback] = arguments
|
||||
scopeDescriptor = options.scope
|
||||
if options.callNow?
|
||||
Grim.deprecate """
|
||||
Config::observe no longer takes a `callNow` option. Use ::onDidChange instead.
|
||||
Note that ::onDidChange passes its callback different arguments.
|
||||
See https://atom.io/docs/api/latest/Config
|
||||
"""
|
||||
else
|
||||
console.error 'An unsupported form of Config::observe is being used. See https://atom.io/docs/api/latest/Config for details'
|
||||
return
|
||||
@@ -375,13 +381,14 @@ class Config
|
||||
# Essential: Add a listener for changes to a given key path. If `keyPath` is
|
||||
# not specified, your callback will be called on changes to any key.
|
||||
#
|
||||
# * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from
|
||||
# the root of the syntax tree to a token. Get one by calling
|
||||
# {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples.
|
||||
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
|
||||
# for more information.
|
||||
# * `keyPath` (optional) {String} name of the key to observe. Must be
|
||||
# specified if `scopeDescriptor` is specified.
|
||||
# * `optional` (optional) {Object}
|
||||
# * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from
|
||||
# the root of the syntax tree to a token. Get one by calling
|
||||
# {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples.
|
||||
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
|
||||
# for more information.
|
||||
# * `callback` {Function} to call when the value of the key changes.
|
||||
# * `event` {Object}
|
||||
# * `newValue` the new value of the key
|
||||
@@ -390,12 +397,20 @@ class Config
|
||||
#
|
||||
# Returns a {Disposable} with the following keys on which you can call
|
||||
# `.dispose()` to unsubscribe.
|
||||
onDidChange: (scopeDescriptor, keyPath, callback) ->
|
||||
args = Array::slice.call(arguments)
|
||||
onDidChange: ->
|
||||
if arguments.length is 1
|
||||
[callback, scopeDescriptor, keyPath] = args
|
||||
[callback] = arguments
|
||||
else if arguments.length is 2
|
||||
[keyPath, callback, scopeDescriptor] = args
|
||||
[keyPath, callback] = arguments
|
||||
else if _.isArray(arguments[0]) or arguments[0] instanceof ScopeDescriptor
|
||||
Grim.deprecate """
|
||||
Passing a scope descriptor as the first argument to Config::onDidChange is deprecated.
|
||||
Pass a `scope` in an options hash as the third argument instead.
|
||||
"""
|
||||
[scopeDescriptor, keyPath, callback] = arguments
|
||||
else
|
||||
[keyPath, options, callback] = arguments
|
||||
scopeDescriptor = options.scope
|
||||
|
||||
if scopeDescriptor?
|
||||
@onDidChangeScopedKeyPath(scopeDescriptor, keyPath, callback)
|
||||
@@ -421,14 +436,14 @@ class Config
|
||||
# files.
|
||||
#
|
||||
# ```coffee
|
||||
# atom.config.get(['source.ruby'], 'editor.tabLength') # => 2
|
||||
# atom.config.get('editor.tabLength', scope: ['source.ruby']) # => 2
|
||||
# ```
|
||||
#
|
||||
# This setting in ruby files might be different than the global tabLength setting
|
||||
#
|
||||
# ```coffee
|
||||
# atom.config.get('editor.tabLength') # => 4
|
||||
# atom.config.get(['source.ruby'], 'editor.tabLength') # => 2
|
||||
# atom.config.get('editor.tabLength', scope: ['source.ruby']) # => 2
|
||||
# ```
|
||||
#
|
||||
# You can get the language scope descriptor via
|
||||
@@ -436,34 +451,72 @@ class Config
|
||||
# for the editor's language.
|
||||
#
|
||||
# ```coffee
|
||||
# atom.config.get(@editor.getRootScopeDescriptor(), 'editor.tabLength') # => 2
|
||||
# atom.config.get('editor.tabLength', scope: @editor.getRootScopeDescriptor()) # => 2
|
||||
# ```
|
||||
#
|
||||
# Additionally, you can get the setting at the specific cursor position.
|
||||
#
|
||||
# ```coffee
|
||||
# scopeDescriptor = @editor.getLastCursor().getScopeDescriptor()
|
||||
# atom.config.get(scopeDescriptor, 'editor.tabLength') # => 2
|
||||
# atom.config.get('editor.tabLength', scope: scopeDescriptor) # => 2
|
||||
# ```
|
||||
#
|
||||
# * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from
|
||||
# the root of the syntax tree to a token. Get one by calling
|
||||
# {editor.getLastCursor().getScopeDescriptor()}
|
||||
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
|
||||
# for more information.
|
||||
# * `keyPath` The {String} name of the key to retrieve.
|
||||
# * `options` (optional) {Object}
|
||||
# * `sources` (optional) {Array} of {String} source names. If provided, only
|
||||
# values that were associated with these sources during {::set} will be used.
|
||||
# * `excludeSources` (optional) {Array} of {String} source names. If provided,
|
||||
# values that were associated with these sources during {::set} will not
|
||||
# be used.
|
||||
# * `scope` (optional) {ScopeDescriptor} describing a path from
|
||||
# the root of the syntax tree to a token. Get one by calling
|
||||
# {editor.getLastCursor().getScopeDescriptor()}
|
||||
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
|
||||
# for more information.
|
||||
#
|
||||
# Returns the value from Atom's default settings, the user's configuration
|
||||
# file in the type specified by the configuration schema.
|
||||
get: (scopeDescriptor, keyPath) ->
|
||||
if arguments.length == 1
|
||||
# cannot assign to keyPath for the sake of v8 optimization
|
||||
globalKeyPath = scopeDescriptor
|
||||
@getRawValue(globalKeyPath)
|
||||
get: ->
|
||||
if arguments.length > 1
|
||||
if typeof arguments[0] is 'string' or not arguments[0]?
|
||||
[keyPath, options] = arguments
|
||||
{scope} = options
|
||||
else
|
||||
Grim.deprecate """
|
||||
Passing a scope descriptor as the first argument to Config::get is deprecated.
|
||||
Pass a `scope` in an options hash as the final argument instead.
|
||||
"""
|
||||
[scope, keyPath] = arguments
|
||||
else
|
||||
value = @getRawScopedValue(scopeDescriptor, keyPath)
|
||||
value ?= @getRawValue(keyPath)
|
||||
value
|
||||
[keyPath] = arguments
|
||||
|
||||
if scope?
|
||||
value = @getRawScopedValue(scope, keyPath, options)
|
||||
value ? @getRawValue(keyPath, options)
|
||||
else
|
||||
@getRawValue(keyPath, options)
|
||||
|
||||
# Extended: Get all of the values for the given key-path, along with their
|
||||
# associated scope selector.
|
||||
#
|
||||
# * `keyPath` The {String} name of the key to retrieve
|
||||
# * `options` (optional) {Object} see the `options` argument to {::get}
|
||||
#
|
||||
# Returns an {Array} of {Object}s with the following keys:
|
||||
# * `scopeSelector` The scope-selector {String} with which the value is associated
|
||||
# * `value` The value for the key-path
|
||||
getAll: (keyPath, options) ->
|
||||
{scope, sources} = options if options?
|
||||
result = []
|
||||
|
||||
if scope?
|
||||
scopeDescriptor = ScopeDescriptor.fromObject(scope)
|
||||
result = result.concat @scopedSettingsStore.getAll(scopeDescriptor.getScopeChain(), keyPath, options)
|
||||
|
||||
if globalValue = @getRawValue(keyPath, options)
|
||||
result.push(scopeSelector: '*', value: globalValue)
|
||||
|
||||
result
|
||||
|
||||
# Essential: Sets the value for a configuration setting.
|
||||
#
|
||||
@@ -482,75 +535,113 @@ class Config
|
||||
#
|
||||
# ```coffee
|
||||
# atom.config.get('editor.tabLength') # => 4
|
||||
# atom.config.get(['source.ruby'], 'editor.tabLength') # => 4
|
||||
# atom.config.get(['source.js'], 'editor.tabLength') # => 4
|
||||
# atom.config.get('editor.tabLength', scope: ['source.ruby']) # => 4
|
||||
# atom.config.get('editor.tabLength', scope: ['source.js']) # => 4
|
||||
#
|
||||
# # Set ruby to 2
|
||||
# atom.config.set('source.ruby', 'editor.tabLength', 2) # => true
|
||||
# atom.config.set('editor.tabLength', 2, scopeSelector: 'source.ruby') # => true
|
||||
#
|
||||
# # Notice it's only set to 2 in the case of ruby
|
||||
# atom.config.get('editor.tabLength') # => 4
|
||||
# atom.config.get(['source.ruby'], 'editor.tabLength') # => 2
|
||||
# atom.config.get(['source.js'], 'editor.tabLength') # => 4
|
||||
# atom.config.get('editor.tabLength', scope: ['source.ruby']) # => 2
|
||||
# atom.config.get('editor.tabLength', scope: ['source.js']) # => 4
|
||||
# ```
|
||||
#
|
||||
# * `scopeSelector` (optional) {String}. eg. '.source.ruby'
|
||||
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
|
||||
# for more information.
|
||||
# * `keyPath` The {String} name of the key.
|
||||
# * `value` The value of the setting. Passing `undefined` will revert the
|
||||
# setting to the default value.
|
||||
# * `options` (optional) {Object}
|
||||
# * `scopeSelector` (optional) {String}. eg. '.source.ruby'
|
||||
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
|
||||
# for more information.
|
||||
# * `source` (optional) {String} The name of a file with which the setting
|
||||
# is associated. Defaults to the user's config file.
|
||||
#
|
||||
# Returns a {Boolean}
|
||||
# * `true` if the value was set.
|
||||
# * `false` if the value was not able to be coerced to the type specified in the setting's schema.
|
||||
set: (scopeSelector, keyPath, value) ->
|
||||
if arguments.length < 3
|
||||
value = keyPath
|
||||
keyPath = scopeSelector
|
||||
scopeSelector = undefined
|
||||
set: ->
|
||||
if arguments[0]?[0] is '.'
|
||||
Grim.deprecate """
|
||||
Passing a scope selector as the first argument to Config::set is deprecated.
|
||||
Pass a `scopeSelector` in an options hash as the final argument instead.
|
||||
"""
|
||||
[scopeSelector, keyPath, value] = arguments
|
||||
else
|
||||
[keyPath, value, options] = arguments
|
||||
scopeSelector = options?.scopeSelector
|
||||
source = options?.source
|
||||
shouldSave = options?.save ? true
|
||||
|
||||
unless value == undefined
|
||||
if source and not scopeSelector
|
||||
throw new Error("::set with a 'source' and no 'sourceSelector' is not yet implemented!")
|
||||
|
||||
source ?= @getUserConfigPath()
|
||||
|
||||
unless value is undefined
|
||||
try
|
||||
value = @makeValueConformToSchema(keyPath, value)
|
||||
catch e
|
||||
return false
|
||||
|
||||
if scopeSelector?
|
||||
@setRawScopedValue(scopeSelector, keyPath, value)
|
||||
@setRawScopedValue(source, scopeSelector, keyPath, value)
|
||||
else
|
||||
@setRawValue(keyPath, value)
|
||||
|
||||
@save() unless @configFileHasErrors
|
||||
@debouncedSave() if source is @getUserConfigPath() and shouldSave and not @configFileHasErrors
|
||||
true
|
||||
|
||||
# Extended: Restore the global setting at `keyPath` to its default value.
|
||||
# Essential: Restore the setting at `keyPath` to its default value.
|
||||
#
|
||||
# * `scopeSelector` (optional) {String}. eg. '.source.ruby'
|
||||
# See [the scopes docs](https://atom.io/docs/latest/advanced/scopes-and-scope-descriptors)
|
||||
# for more information.
|
||||
# * `keyPath` The {String} name of the key.
|
||||
# * `options` (optional) {Object}
|
||||
# * `scopeSelector` (optional) {String}. See {::set}
|
||||
# * `source` (optional) {String}. See {::set}
|
||||
unset: (keyPath, options) ->
|
||||
if typeof options is 'string'
|
||||
Grim.deprecate """
|
||||
Passing a scope selector as the first argument to Config::unset is deprecated.
|
||||
Pass a `scopeSelector` in an options hash as the second argument instead.
|
||||
"""
|
||||
scopeSelector = keyPath
|
||||
keyPath = options
|
||||
else
|
||||
{scopeSelector, source} = options ? {}
|
||||
|
||||
source ?= @getUserConfigPath()
|
||||
|
||||
if scopeSelector?
|
||||
if keyPath?
|
||||
settings = @scopedSettingsStore.propertiesForSourceAndSelector(source, scopeSelector)
|
||||
if _.valueForKeyPath(settings, keyPath)?
|
||||
@scopedSettingsStore.removePropertiesForSourceAndSelector(source, scopeSelector)
|
||||
_.setValueForKeyPath(settings, keyPath, undefined)
|
||||
settings = withoutEmptyObjects(settings)
|
||||
@set(null, settings, {scopeSelector, source, priority: @priorityForSource(source)}) if settings?
|
||||
@debouncedSave()
|
||||
else
|
||||
@scopedSettingsStore.removePropertiesForSourceAndSelector(source, scopeSelector)
|
||||
@emitChangeEvent()
|
||||
else
|
||||
@scopedSettingsStore.removePropertiesForSource(source)
|
||||
if keyPath?
|
||||
@set(keyPath, _.valueForKeyPath(@defaultSettings, keyPath))
|
||||
|
||||
# Extended: Get an {Array} of all of the `source` {String}s with which
|
||||
# settings have been added via {::set}.
|
||||
getSources: ->
|
||||
_.uniq(_.pluck(@scopedSettingsStore.propertySets, 'source')).sort()
|
||||
|
||||
# Deprecated: Restore the global setting at `keyPath` to its default value.
|
||||
#
|
||||
# Returns the new value.
|
||||
restoreDefault: (scopeSelector, keyPath) ->
|
||||
if arguments.length == 1
|
||||
keyPath = scopeSelector
|
||||
scopeSelector = null
|
||||
Grim.deprecate("Use ::unset instead.")
|
||||
@unset(scopeSelector, keyPath)
|
||||
@get(keyPath)
|
||||
|
||||
if scopeSelector?
|
||||
settings = @scopedSettingsStore.propertiesForSourceAndSelector('user-config', scopeSelector)
|
||||
if _.valueForKeyPath(settings, keyPath)?
|
||||
@scopedSettingsStore.removePropertiesForSourceAndSelector('user-config', scopeSelector)
|
||||
_.setValueForKeyPath(settings, keyPath, undefined)
|
||||
settings = withoutEmptyObjects(settings)
|
||||
@addScopedSettings('user-config', scopeSelector, settings, @usersScopedSettingPriority) if settings?
|
||||
@save() unless @configFileHasErrors
|
||||
@getDefault(scopeSelector, keyPath)
|
||||
else
|
||||
@set(keyPath, _.valueForKeyPath(@defaultSettings, keyPath))
|
||||
@get(keyPath)
|
||||
|
||||
# Extended: Get the global default value of the key path. _Please note_ that in most
|
||||
# Deprecated: Get the global default value of the key path. _Please note_ that in most
|
||||
# cases calling this is not necessary! {::get} returns the default value when
|
||||
# a custom value is not specified.
|
||||
#
|
||||
@@ -558,35 +649,30 @@ class Config
|
||||
# * `keyPath` The {String} name of the key.
|
||||
#
|
||||
# Returns the default value.
|
||||
getDefault: (scopeSelector, keyPath) ->
|
||||
if arguments.length == 1
|
||||
keyPath = scopeSelector
|
||||
scopeSelector = null
|
||||
|
||||
if scopeSelector?
|
||||
defaultValue = @scopedSettingsStore.getPropertyValue(scopeSelector, keyPath, excludeSources: ['user-config'])
|
||||
defaultValue ?= _.valueForKeyPath(@defaultSettings, keyPath)
|
||||
getDefault: ->
|
||||
Grim.deprecate("Use `::get(keyPath, {scope, excludeSources: [atom.config.getUserConfigPath()]})` instead")
|
||||
if arguments.length is 1
|
||||
[keyPath] = arguments
|
||||
else
|
||||
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
|
||||
_.deepClone(defaultValue)
|
||||
[scopeSelector, keyPath] = arguments
|
||||
scope = [scopeSelector]
|
||||
@get(keyPath, {scope, excludeSources: [@getUserConfigPath()]})
|
||||
|
||||
# Extended: Is the value at `keyPath` its default value?
|
||||
# Deprecated: Is the value at `keyPath` its default value?
|
||||
#
|
||||
# * `scopeSelector` (optional) {String}. eg. '.source.ruby'
|
||||
# * `keyPath` The {String} name of the key.
|
||||
#
|
||||
# Returns a {Boolean}, `true` if the current value is the default, `false`
|
||||
# otherwise.
|
||||
isDefault: (scopeSelector, keyPath) ->
|
||||
if arguments.length == 1
|
||||
keyPath = scopeSelector
|
||||
scopeSelector = null
|
||||
|
||||
if scopeSelector?
|
||||
settings = @scopedSettingsStore.propertiesForSourceAndSelector('user-config', scopeSelector)
|
||||
not _.valueForKeyPath(settings, keyPath)?
|
||||
isDefault: ->
|
||||
Grim.deprecate("Use `not ::get(keyPath, {scope, sources: [atom.config.getUserConfigPath()]})?` instead")
|
||||
if arguments.length is 1
|
||||
[keyPath] = arguments
|
||||
else
|
||||
not _.valueForKeyPath(@settings, keyPath)?
|
||||
[scopeSelector, keyPath] = arguments
|
||||
scope = [scopeSelector]
|
||||
not @get(keyPath, {scope, sources: [@getUserConfigPath()]})?
|
||||
|
||||
# Extended: Retrieve the schema for a specific key path. The schema will tell
|
||||
# you what type the keyPath expects, and other metadata about the config
|
||||
@@ -614,6 +700,19 @@ class Config
|
||||
getUserConfigPath: ->
|
||||
@configFilePath
|
||||
|
||||
# Extended: Suppress calls to handler functions registered with {::onDidChange}
|
||||
# and {::observe} for the duration of `callback`. After `callback` executes,
|
||||
# handlers will be called once if the value for their key-path has changed.
|
||||
#
|
||||
# * `callback` {Function} to execute while suppressing calls to handlers.
|
||||
transact: (callback) ->
|
||||
@transactDepth++
|
||||
try
|
||||
callback()
|
||||
finally
|
||||
@transactDepth--
|
||||
@emitChangeEvent()
|
||||
|
||||
###
|
||||
Section: Deprecated
|
||||
###
|
||||
@@ -722,7 +821,7 @@ class Config
|
||||
observeUserConfig: ->
|
||||
try
|
||||
@watchSubscription ?= pathWatcher.watch @configFilePath, (eventType) =>
|
||||
@loadUserConfig() if eventType is 'change' and @watchSubscription?
|
||||
@debouncedLoad() if eventType is 'change' and @watchSubscription?
|
||||
catch error
|
||||
@notifyFailure('Failed to watch user config', error)
|
||||
|
||||
@@ -738,8 +837,8 @@ class Config
|
||||
console.error detail
|
||||
|
||||
save: ->
|
||||
allSettings = global: @settings
|
||||
allSettings = _.extend allSettings, @scopedSettingsStore.propertiesForSource('user-config')
|
||||
allSettings = {'*': @settings}
|
||||
allSettings = _.extend allSettings, @scopedSettingsStore.propertiesForSource(@getUserConfigPath())
|
||||
CSON.writeFileSync(@configFilePath, allSettings)
|
||||
|
||||
###
|
||||
@@ -749,44 +848,28 @@ class Config
|
||||
resetUserSettings: (newSettings) ->
|
||||
unless isPlainObject(newSettings)
|
||||
@settings = {}
|
||||
@emitter.emit 'did-change'
|
||||
@emitChangeEvent()
|
||||
return
|
||||
|
||||
if newSettings.global?
|
||||
newSettings['*'] = newSettings.global
|
||||
delete newSettings.global
|
||||
|
||||
if newSettings['*']?
|
||||
scopedSettings = newSettings
|
||||
newSettings = newSettings.global
|
||||
delete scopedSettings.global
|
||||
newSettings = newSettings['*']
|
||||
delete scopedSettings['*']
|
||||
@resetUserScopedSettings(scopedSettings)
|
||||
|
||||
unsetUnspecifiedValues = (keyPath, value) =>
|
||||
if isPlainObject(value)
|
||||
keys = splitKeyPath(keyPath)
|
||||
for key, childValue of value
|
||||
continue unless value.hasOwnProperty(key)
|
||||
unsetUnspecifiedValues(keys.concat([key]).join('.'), childValue)
|
||||
else
|
||||
@setRawValue(keyPath, undefined) unless _.valueForKeyPath(newSettings, keyPath)?
|
||||
return
|
||||
@transact =>
|
||||
@settings = {}
|
||||
@set(key, value, save: false) for key, value of newSettings
|
||||
|
||||
@setRecursive(null, newSettings)
|
||||
unsetUnspecifiedValues(null, @settings)
|
||||
|
||||
setRecursive: (keyPath, value) ->
|
||||
if isPlainObject(value)
|
||||
keys = splitKeyPath(keyPath)
|
||||
for key, childValue of value
|
||||
continue unless value.hasOwnProperty(key)
|
||||
@setRecursive(keys.concat([key]).join('.'), childValue)
|
||||
else
|
||||
try
|
||||
value = @makeValueConformToSchema(keyPath, value)
|
||||
@setRawValue(keyPath, value)
|
||||
catch e
|
||||
console.warn("'#{keyPath}' could not be set. Attempted value: #{JSON.stringify(value)}; Schema: #{JSON.stringify(@getSchema(keyPath))}")
|
||||
|
||||
getRawValue: (keyPath) ->
|
||||
value = _.valueForKeyPath(@settings, keyPath)
|
||||
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
|
||||
getRawValue: (keyPath, options) ->
|
||||
unless options?.excludeSources?.indexOf(@getUserConfigPath()) >= 0
|
||||
value = _.valueForKeyPath(@settings, keyPath)
|
||||
unless options?.sources?.length > 0
|
||||
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
|
||||
|
||||
if value?
|
||||
value = _.deepClone(value)
|
||||
@@ -800,19 +883,24 @@ class Config
|
||||
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
|
||||
value = undefined if _.isEqual(defaultValue, value)
|
||||
|
||||
oldValue = _.clone(@get(keyPath))
|
||||
_.setValueForKeyPath(@settings, keyPath, value)
|
||||
newValue = @get(keyPath)
|
||||
@emitter.emit 'did-change', {oldValue, newValue, keyPath} unless _.isEqual(newValue, oldValue)
|
||||
if keyPath?
|
||||
_.setValueForKeyPath(@settings, keyPath, value)
|
||||
else
|
||||
@settings = value
|
||||
@emitChangeEvent()
|
||||
|
||||
observeKeyPath: (keyPath, options, callback) ->
|
||||
callback(_.clone(@get(keyPath))) unless options.callNow == false
|
||||
@emitter.on 'did-change', (event) =>
|
||||
callback(event.newValue) if keyPath? and @isSubKeyPath(keyPath, event?.keyPath)
|
||||
callback(@get(keyPath))
|
||||
@onDidChangeKeyPath keyPath, (event) -> callback(event.newValue)
|
||||
|
||||
onDidChangeKeyPath: (keyPath, callback) ->
|
||||
@emitter.on 'did-change', (event) =>
|
||||
callback(event) if not keyPath? or (keyPath? and @isSubKeyPath(keyPath, event?.keyPath))
|
||||
oldValue = @get(keyPath)
|
||||
@emitter.on 'did-change', =>
|
||||
newValue = @get(keyPath)
|
||||
unless _.isEqual(oldValue, newValue)
|
||||
event = {oldValue, newValue}
|
||||
oldValue = newValue
|
||||
callback(event)
|
||||
|
||||
isSubKeyPath: (keyPath, subKeyPath) ->
|
||||
return false unless keyPath? and subKeyPath?
|
||||
@@ -821,10 +909,8 @@ class Config
|
||||
_.isEqual(pathTokens, pathSubTokens)
|
||||
|
||||
setRawDefault: (keyPath, value) ->
|
||||
oldValue = _.clone(@get(keyPath))
|
||||
_.setValueForKeyPath(@defaultSettings, keyPath, value)
|
||||
newValue = @get(keyPath)
|
||||
@emitter.emit 'did-change', {oldValue, newValue, keyPath} unless _.isEqual(newValue, oldValue)
|
||||
@emitChangeEvent()
|
||||
|
||||
setDefaults: (keyPath, defaults) ->
|
||||
if defaults? and isPlainObject(defaults)
|
||||
@@ -882,22 +968,32 @@ class Config
|
||||
Section: Private Scoped Settings
|
||||
###
|
||||
|
||||
priorityForSource: (source) ->
|
||||
if source is @getUserConfigPath()
|
||||
1000
|
||||
else
|
||||
0
|
||||
|
||||
emitChangeEvent: ->
|
||||
@emitter.emit 'did-change' unless @transactDepth > 0
|
||||
|
||||
resetUserScopedSettings: (newScopedSettings) ->
|
||||
@usersScopedSettings?.dispose()
|
||||
@usersScopedSettings = new CompositeDisposable
|
||||
@usersScopedSettings.add @scopedSettingsStore.addProperties('user-config', newScopedSettings, @usersScopedSettingPriority)
|
||||
@emitter.emit 'did-change'
|
||||
source = @getUserConfigPath()
|
||||
@scopedSettingsStore.removePropertiesForSource(source)
|
||||
@scopedSettingsStore.addProperties(source, newScopedSettings, priority: @priorityForSource(source))
|
||||
@emitChangeEvent()
|
||||
|
||||
addScopedSettings: (source, selector, value, options) ->
|
||||
Grim.deprecate("Use ::set instead")
|
||||
settingsBySelector = {}
|
||||
settingsBySelector[selector] = value
|
||||
disposable = @scopedSettingsStore.addProperties(source, settingsBySelector, options)
|
||||
@emitter.emit 'did-change'
|
||||
@emitChangeEvent()
|
||||
new Disposable =>
|
||||
disposable.dispose()
|
||||
@emitter.emit 'did-change'
|
||||
@emitChangeEvent()
|
||||
|
||||
setRawScopedValue: (selector, keyPath, value) ->
|
||||
setRawScopedValue: (source, selector, keyPath, value) ->
|
||||
if keyPath?
|
||||
newValue = {}
|
||||
_.setValueForKeyPath(newValue, keyPath, value)
|
||||
@@ -905,40 +1001,30 @@ class Config
|
||||
|
||||
settingsBySelector = {}
|
||||
settingsBySelector[selector] = value
|
||||
@usersScopedSettings.add @scopedSettingsStore.addProperties('user-config', settingsBySelector, @usersScopedSettingPriority)
|
||||
@emitter.emit 'did-change'
|
||||
@scopedSettingsStore.addProperties(source, settingsBySelector, priority: @priorityForSource(source))
|
||||
@emitChangeEvent()
|
||||
|
||||
getRawScopedValue: (scopeDescriptor, keyPath) ->
|
||||
getRawScopedValue: (scopeDescriptor, keyPath, options) ->
|
||||
scopeDescriptor = ScopeDescriptor.fromObject(scopeDescriptor)
|
||||
@scopedSettingsStore.getPropertyValue(scopeDescriptor.getScopeChain(), keyPath)
|
||||
@scopedSettingsStore.getPropertyValue(scopeDescriptor.getScopeChain(), keyPath, options)
|
||||
|
||||
observeScopedKeyPath: (scopeDescriptor, keyPath, callback) ->
|
||||
oldValue = @get(scopeDescriptor, keyPath)
|
||||
observeScopedKeyPath: (scope, keyPath, callback) ->
|
||||
callback(@get(keyPath, {scope}))
|
||||
@onDidChangeScopedKeyPath scope, keyPath, (event) -> callback(event.newValue)
|
||||
|
||||
callback(oldValue)
|
||||
onDidChangeScopedKeyPath: (scope, keyPath, callback) ->
|
||||
oldValue = @get(keyPath, {scope})
|
||||
@emitter.on 'did-change', =>
|
||||
newValue = @get(keyPath, {scope})
|
||||
unless _.isEqual(oldValue, newValue)
|
||||
event = {oldValue, newValue}
|
||||
oldValue = newValue
|
||||
callback(event)
|
||||
|
||||
didChange = =>
|
||||
newValue = @get(scopeDescriptor, keyPath)
|
||||
callback(newValue) unless _.isEqual(oldValue, newValue)
|
||||
oldValue = newValue
|
||||
|
||||
@emitter.on 'did-change', didChange
|
||||
|
||||
onDidChangeScopedKeyPath: (scopeDescriptor, keyPath, callback) ->
|
||||
oldValue = @get(scopeDescriptor, keyPath)
|
||||
didChange = =>
|
||||
newValue = @get(scopeDescriptor, keyPath)
|
||||
callback({oldValue, newValue, keyPath}) unless _.isEqual(oldValue, newValue)
|
||||
oldValue = newValue
|
||||
|
||||
@emitter.on 'did-change', didChange
|
||||
|
||||
# TODO: figure out how to change / remove this. The return value is awkward.
|
||||
# * language mode uses it for one thing.
|
||||
# * autocomplete uses it for editor.completions
|
||||
settingsForScopeDescriptor: (scopeDescriptor, keyPath) ->
|
||||
scopeDescriptor = ScopeDescriptor.fromObject(scopeDescriptor)
|
||||
@scopedSettingsStore.getProperties(scopeDescriptor.getScopeChain(), keyPath)
|
||||
Grim.deprecate("Use Config::getAll instead")
|
||||
entries = @getAll(null, scope: scopeDescriptor)
|
||||
value for {value} in entries when _.valueForKeyPath(value, keyPath)?
|
||||
|
||||
# Base schema enforcers. These will coerce raw input into the specified type,
|
||||
# and will throw an error when the value cannot be coerced. Throwing the error
|
||||
|
||||
@@ -16,6 +16,31 @@ SpecificityCache = {}
|
||||
#
|
||||
# An instance of this class is always available as the `atom.contextMenu`
|
||||
# global.
|
||||
#
|
||||
# ## Context Menu CSON Format
|
||||
#
|
||||
# # ```coffee
|
||||
# 'atom-workspace': [{label: 'Help', command: 'application:open-documentation'}]
|
||||
# 'atom-text-editor': [{
|
||||
# label: 'History',
|
||||
# submenu: [
|
||||
# {label: 'Undo', command:'core:undo'}
|
||||
# {label: 'Redo', command:'core:redo'}
|
||||
# ]
|
||||
# }]
|
||||
# ```
|
||||
#
|
||||
# In your package's menu `.cson` file you need to specify it under a
|
||||
# `context-menu` key:
|
||||
#
|
||||
# ```coffee
|
||||
# 'context-menu':
|
||||
# 'atom-workspace': [{label: 'Help', command: 'application:open-documentation'}]
|
||||
# ...
|
||||
# ```
|
||||
#
|
||||
# The format for use in {::add} is the same minus the `context-menu` key. See
|
||||
# {::add} for more information.
|
||||
module.exports =
|
||||
class ContextMenuManager
|
||||
constructor: ({@resourcePath, @devMode}) ->
|
||||
@@ -46,8 +71,8 @@ class ContextMenuManager
|
||||
# 'atom-text-editor': [{
|
||||
# label: 'History',
|
||||
# submenu: [
|
||||
# {label: 'Undo': command:'core:undo'}
|
||||
# {label: 'Redo': command:'core:redo'}
|
||||
# {label: 'Undo', command:'core:undo'}
|
||||
# {label: 'Redo', command:'core:redo'}
|
||||
# ]
|
||||
# }]
|
||||
# }
|
||||
@@ -77,14 +102,22 @@ class ContextMenuManager
|
||||
add: (itemsBySelector) ->
|
||||
# Detect deprecated file path as first argument
|
||||
if itemsBySelector? and typeof itemsBySelector isnt 'object'
|
||||
Grim.deprecate("ContextMenuManager::add has changed to take a single object as its argument. Please consult the documentation.")
|
||||
Grim.deprecate """
|
||||
ContextMenuManager::add has changed to take a single object as its
|
||||
argument. Please see
|
||||
https://atom.io/docs/api/latest/ContextMenuManager for more info.
|
||||
"""
|
||||
itemsBySelector = arguments[1]
|
||||
devMode = arguments[2]?.devMode
|
||||
|
||||
# Detect deprecated format for items object
|
||||
for key, value of itemsBySelector
|
||||
unless _.isArray(value)
|
||||
Grim.deprecate("The format for declaring context menu items has changed. Please consult the documentation.")
|
||||
Grim.deprecate """
|
||||
ContextMenuManager::add has changed to take a single object as its
|
||||
argument. Please see
|
||||
https://atom.io/docs/api/latest/ContextMenuManager for more info.
|
||||
"""
|
||||
itemsBySelector = @convertLegacyItemsBySelector(itemsBySelector, devMode)
|
||||
|
||||
addedItemSets = []
|
||||
|
||||
+11
-5
@@ -202,14 +202,20 @@ class Cursor extends Model
|
||||
[before, after] = @editor.getTextInBufferRange(range)
|
||||
return false if /\s/.test(before) or /\s/.test(after)
|
||||
|
||||
nonWordCharacters = atom.config.get(@getScopeDescriptor(), 'editor.nonWordCharacters').split('')
|
||||
nonWordCharacters = atom.config.get('editor.nonWordCharacters', scope: @getScopeDescriptor()).split('')
|
||||
_.contains(nonWordCharacters, before) isnt _.contains(nonWordCharacters, after)
|
||||
|
||||
# Public: Returns whether this cursor is between a word's start and end.
|
||||
isInsideWord: ->
|
||||
#
|
||||
# * `options` (optional) {Object}
|
||||
# * `wordRegex` A {RegExp} indicating what constitutes a "word"
|
||||
# (default: {::wordRegExp}).
|
||||
#
|
||||
# Returns a {Boolean}
|
||||
isInsideWord: (options) ->
|
||||
{row, column} = @getBufferPosition()
|
||||
range = [[row, column], [row, Infinity]]
|
||||
@editor.getTextInBufferRange(range).search(@wordRegExp()) == 0
|
||||
@editor.getTextInBufferRange(range).search(options?.wordRegex ? @wordRegExp()) == 0
|
||||
|
||||
# Public: Returns the indentation level of the current line.
|
||||
getIndentLevel: ->
|
||||
@@ -544,7 +550,7 @@ class Cursor extends Model
|
||||
# Returns a {Range}
|
||||
getBeginningOfNextWordBufferPosition: (options = {}) ->
|
||||
currentBufferPosition = @getBufferPosition()
|
||||
start = if @isInsideWord() then @getEndOfCurrentWordBufferPosition() else currentBufferPosition
|
||||
start = if @isInsideWord(options) then @getEndOfCurrentWordBufferPosition(options) else currentBufferPosition
|
||||
scanRange = [start, @editor.getEofBufferPosition()]
|
||||
|
||||
beginningOfNextWordPosition = null
|
||||
@@ -636,7 +642,7 @@ class Cursor extends Model
|
||||
# Returns a {RegExp}.
|
||||
wordRegExp: ({includeNonWordCharacters}={}) ->
|
||||
includeNonWordCharacters ?= true
|
||||
nonWordCharacters = atom.config.get(@getScopeDescriptor(), 'editor.nonWordCharacters')
|
||||
nonWordCharacters = atom.config.get('editor.nonWordCharacters', scope: @getScopeDescriptor())
|
||||
segments = ["^[\t ]*$"]
|
||||
segments.push("[^\\s#{_.escapeRegExp(nonWordCharacters)}]+")
|
||||
if includeNonWordCharacters
|
||||
|
||||
@@ -67,24 +67,24 @@ class DisplayBuffer extends Model
|
||||
|
||||
oldConfigSettings = @configSettings
|
||||
@configSettings =
|
||||
scrollPastEnd: atom.config.get(scopeDescriptor, 'editor.scrollPastEnd')
|
||||
softWrap: atom.config.get(scopeDescriptor, 'editor.softWrap')
|
||||
softWrapAtPreferredLineLength: atom.config.get(scopeDescriptor, 'editor.softWrapAtPreferredLineLength')
|
||||
preferredLineLength: atom.config.get(scopeDescriptor, 'editor.preferredLineLength')
|
||||
scrollPastEnd: atom.config.get('editor.scrollPastEnd', scope: scopeDescriptor)
|
||||
softWrap: atom.config.get('editor.softWrap', scope: scopeDescriptor)
|
||||
softWrapAtPreferredLineLength: atom.config.get('editor.softWrapAtPreferredLineLength', scope: scopeDescriptor)
|
||||
preferredLineLength: atom.config.get('editor.preferredLineLength', scope: scopeDescriptor)
|
||||
|
||||
subscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.softWrap', ({newValue}) =>
|
||||
subscriptions.add atom.config.onDidChange 'editor.softWrap', scope: scopeDescriptor, ({newValue}) =>
|
||||
@configSettings.softWrap = newValue
|
||||
@updateWrappedScreenLines()
|
||||
|
||||
subscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.softWrapAtPreferredLineLength', ({newValue}) =>
|
||||
subscriptions.add atom.config.onDidChange 'editor.softWrapAtPreferredLineLength', scope: scopeDescriptor, ({newValue}) =>
|
||||
@configSettings.softWrapAtPreferredLineLength = newValue
|
||||
@updateWrappedScreenLines() if @isSoftWrapped()
|
||||
|
||||
subscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.preferredLineLength', ({newValue}) =>
|
||||
subscriptions.add atom.config.onDidChange 'editor.preferredLineLength', scope: scopeDescriptor, ({newValue}) =>
|
||||
@configSettings.preferredLineLength = newValue
|
||||
@updateWrappedScreenLines() if @isSoftWrapped() and atom.config.get(scopeDescriptor, 'editor.softWrapAtPreferredLineLength')
|
||||
@updateWrappedScreenLines() if @isSoftWrapped() and atom.config.get('editor.softWrapAtPreferredLineLength', scope: scopeDescriptor)
|
||||
|
||||
subscriptions.add atom.config.observe scopeDescriptor, 'editor.scrollPastEnd', (value) =>
|
||||
subscriptions.add atom.config.observe 'editor.scrollPastEnd', scope: scopeDescriptor, (value) =>
|
||||
@configSettings.scrollPastEnd = value
|
||||
|
||||
@updateWrappedScreenLines() if oldConfigSettings? and not _.isEqual(oldConfigSettings, @configSettings)
|
||||
|
||||
@@ -67,5 +67,5 @@ class GrammarRegistry extends FirstMate.GrammarRegistry
|
||||
atom.config.getRawScopedValue(scope, keyPath)
|
||||
|
||||
propertiesForScope: (scope, keyPath) ->
|
||||
deprecate 'A direct (but private) replacement is available at atom.config.scopedSettingsForScopeDescriptor().'
|
||||
deprecate 'Use atom.config.getAll instead.'
|
||||
atom.config.settingsForScopeDescriptor(scope, keyPath)
|
||||
|
||||
@@ -26,17 +26,16 @@ class LanguageMode
|
||||
#
|
||||
# startRow - The row {Number} to start at
|
||||
# endRow - The row {Number} to end at
|
||||
#
|
||||
# Returns an {Array} of the commented {Ranges}.
|
||||
toggleLineCommentsForBufferRows: (start, end) ->
|
||||
scopeDescriptor = @editor.scopeDescriptorForBufferPosition([start, 0])
|
||||
properties = atom.config.settingsForScopeDescriptor(scopeDescriptor, 'editor.commentStart')[0]
|
||||
return unless properties
|
||||
scope = @editor.scopeDescriptorForBufferPosition([start, 0])
|
||||
commentStartEntry = atom.config.getAll('editor.commentStart', {scope})[0]
|
||||
|
||||
commentStartString = _.valueForKeyPath(properties, 'editor.commentStart')
|
||||
commentEndString = _.valueForKeyPath(properties, 'editor.commentEnd')
|
||||
return unless commentStartEntry?
|
||||
|
||||
return unless commentStartString
|
||||
commentEndEntry = atom.config.getAll('editor.commentEnd', {scope}).find (entry) ->
|
||||
entry.scopeSelector is commentStartEntry.scopeSelector
|
||||
commentStartString = commentStartEntry?.value
|
||||
commentEndString = commentEndEntry?.value
|
||||
|
||||
buffer = @editor.buffer
|
||||
commentStartRegexString = _.escapeRegExp(commentStartString).replace(/(\s+)$/, '(?:$1)?')
|
||||
@@ -96,6 +95,7 @@ class LanguageMode
|
||||
buffer.insert([row, indentLength], commentStartString)
|
||||
else
|
||||
buffer.setTextInRange([[row, 0], [row, indentString.length]], indentString + commentStartString)
|
||||
return
|
||||
|
||||
# Folds all the foldable lines in the buffer.
|
||||
foldAll: ->
|
||||
@@ -113,6 +113,7 @@ class LanguageMode
|
||||
#
|
||||
# indentLevel - A {Number} indicating indentLevel; 0 based.
|
||||
foldAllAtIndentLevel: (indentLevel) ->
|
||||
@unfoldAll()
|
||||
for currentRow in [0..@buffer.getLastRow()]
|
||||
[startRow, endRow] = @rowRangeForFoldAtBufferRow(currentRow) ? []
|
||||
continue unless startRow?
|
||||
@@ -316,7 +317,7 @@ class LanguageMode
|
||||
@editor.setIndentationForBufferRow(bufferRow, desiredIndentLevel)
|
||||
|
||||
getRegexForProperty: (scopeDescriptor, property) ->
|
||||
if pattern = atom.config.get(scopeDescriptor, property)
|
||||
if pattern = atom.config.get(property, scope: scopeDescriptor)
|
||||
new OnigRegExp(pattern)
|
||||
|
||||
increaseIndentRegexForScopeDescriptor: (scopeDescriptor) ->
|
||||
|
||||
@@ -12,6 +12,49 @@ MenuHelpers = require './menu-helpers'
|
||||
# application menu.
|
||||
#
|
||||
# An instance of this class is always available as the `atom.menu` global.
|
||||
#
|
||||
# ## Menu CSON Format
|
||||
#
|
||||
# Here is an example from the [tree-view](https://github.com/atom/tree-view/blob/master/menus/tree-view.cson):
|
||||
#
|
||||
# ```coffee
|
||||
# [
|
||||
# {
|
||||
# 'label': 'View'
|
||||
# 'submenu': [
|
||||
# { 'label': 'Toggle Tree View', 'command': 'tree-view:toggle' }
|
||||
# ]
|
||||
# }
|
||||
# {
|
||||
# 'label': 'Packages'
|
||||
# 'submenu': [
|
||||
# 'label': 'Tree View'
|
||||
# 'submenu': [
|
||||
# { 'label': 'Focus', 'command': 'tree-view:toggle-focus' }
|
||||
# { 'label': 'Toggle', 'command': 'tree-view:toggle' }
|
||||
# { 'label': 'Reveal Active File', 'command': 'tree-view:reveal-active-file' }
|
||||
# { 'label': 'Toggle Tree Side', 'command': 'tree-view:toggle-side' }
|
||||
# ]
|
||||
# ]
|
||||
# }
|
||||
# ]
|
||||
# ```
|
||||
#
|
||||
# Use in your package's menu `.cson` file requires that you place your menu
|
||||
# structure under a `menu` key.
|
||||
#
|
||||
# ```coffee
|
||||
# 'menu': [
|
||||
# {
|
||||
# 'label': 'View'
|
||||
# 'submenu': [
|
||||
# { 'label': 'Toggle Tree View', 'command': 'tree-view:toggle' }
|
||||
# ]
|
||||
# }
|
||||
# ]
|
||||
# ```
|
||||
#
|
||||
# See {::add} for more info about adding menu's directly.
|
||||
module.exports =
|
||||
class MenuManager
|
||||
constructor: ({@resourcePath}) ->
|
||||
|
||||
@@ -59,6 +59,8 @@ loadDependencies = (modulePath, rootPath, rootMetadata, moduleCache) ->
|
||||
if childMetadata?.version
|
||||
try
|
||||
mainPath = require.resolve(childPath)
|
||||
catch error
|
||||
mainPath = null
|
||||
|
||||
if mainPath
|
||||
moduleCache.dependencies.push
|
||||
|
||||
@@ -295,12 +295,12 @@ class PackageManager
|
||||
pack = new Package(packagePath, metadata)
|
||||
pack.load()
|
||||
@loadedPackages[pack.name] = pack
|
||||
pack
|
||||
return pack
|
||||
catch error
|
||||
console.warn "Failed to load package.json '#{path.basename(packagePath)}'", error.stack ? error
|
||||
|
||||
else
|
||||
throw new Error("Could not resolve '#{nameOrPath}' to a package path")
|
||||
console.warn "Could not resolve '#{nameOrPath}' to a package path"
|
||||
null
|
||||
|
||||
unloadPackages: ->
|
||||
@unloadPackage(name) for name in _.keys(@loadedPackages)
|
||||
@@ -329,22 +329,25 @@ class PackageManager
|
||||
@packageActivators.push([activator, types])
|
||||
|
||||
activatePackages: (packages) ->
|
||||
@activatePackage(pack.name) for pack in packages
|
||||
atom.config.transact =>
|
||||
@activatePackage(pack.name) for pack in packages
|
||||
@observeDisabledPackages()
|
||||
|
||||
# Activate a single package by name
|
||||
activatePackage: (name) ->
|
||||
if pack = @getActivePackage(name)
|
||||
Q(pack)
|
||||
else
|
||||
pack = @loadPackage(name)
|
||||
else if pack = @loadPackage(name)
|
||||
pack.activate().then =>
|
||||
@activePackages[pack.name] = pack
|
||||
pack
|
||||
else
|
||||
Q.reject(new Error("Failed to load package '#{name}'"))
|
||||
|
||||
# Deactivate all packages
|
||||
deactivatePackages: ->
|
||||
@deactivatePackage(pack.name) for pack in @getLoadedPackages()
|
||||
atom.config.transact =>
|
||||
@deactivatePackage(pack.name) for pack in @getLoadedPackages()
|
||||
@unobserveDisabledPackages()
|
||||
|
||||
# Deactivate the package with the given name
|
||||
|
||||
+30
-24
@@ -9,7 +9,6 @@ EmitterMixin = require('emissary').Emitter
|
||||
Q = require 'q'
|
||||
{deprecate} = require 'grim'
|
||||
|
||||
$ = null # Defer require in case this is in the window-less browser process
|
||||
ModuleCache = require './module-cache'
|
||||
ScopedProperties = require './scoped-properties'
|
||||
|
||||
@@ -52,7 +51,7 @@ class Package
|
||||
stylesheets: null
|
||||
stylesheetDisposables: null
|
||||
grammars: null
|
||||
scopedProperties: null
|
||||
settings: null
|
||||
mainModulePath: null
|
||||
resolvedMainModulePath: false
|
||||
mainModule: null
|
||||
@@ -110,7 +109,7 @@ class Package
|
||||
|
||||
getType: -> 'atom'
|
||||
|
||||
getStylesheetType: -> 'bundled'
|
||||
getStyleSheetPriority: -> 0
|
||||
|
||||
load: ->
|
||||
@measure 'loadTime', =>
|
||||
@@ -118,7 +117,7 @@ class Package
|
||||
@loadKeymaps()
|
||||
@loadMenus()
|
||||
@loadStylesheets()
|
||||
@scopedPropertiesPromise = @loadScopedProperties()
|
||||
@settingsPromise = @loadSettings()
|
||||
@requireMainModule() unless @hasActivationCommands()
|
||||
|
||||
catch error
|
||||
@@ -130,7 +129,7 @@ class Package
|
||||
@keymaps = []
|
||||
@menus = []
|
||||
@grammars = []
|
||||
@scopedProperties = []
|
||||
@settings = []
|
||||
|
||||
activate: ->
|
||||
@grammarsPromise ?= @loadGrammars()
|
||||
@@ -144,7 +143,7 @@ class Package
|
||||
else
|
||||
@activateNow()
|
||||
|
||||
Q.all([@grammarsPromise, @scopedPropertiesPromise, @activationDeferred.promise])
|
||||
Q.all([@grammarsPromise, @settingsPromise, @activationDeferred.promise])
|
||||
|
||||
activateNow: ->
|
||||
try
|
||||
@@ -176,8 +175,9 @@ class Package
|
||||
activateStylesheets: ->
|
||||
return if @stylesheetsActivated
|
||||
|
||||
group = @getStylesheetType()
|
||||
@stylesheetDisposables = new CompositeDisposable
|
||||
|
||||
priority = @getStyleSheetPriority()
|
||||
for [sourcePath, source] in @stylesheets
|
||||
if match = path.basename(sourcePath).match(/[^.]*\.([^.]*)\./)
|
||||
context = match[1]
|
||||
@@ -186,7 +186,7 @@ class Package
|
||||
else
|
||||
context = undefined
|
||||
|
||||
@stylesheetDisposables.add(atom.styles.addStyleSheet(source, {sourcePath, group, context}))
|
||||
@stylesheetDisposables.add(atom.styles.addStyleSheet(source, {sourcePath, priority, context}))
|
||||
@stylesheetsActivated = true
|
||||
|
||||
activateResources: ->
|
||||
@@ -199,20 +199,20 @@ class Package
|
||||
grammar.activate() for grammar in @grammars
|
||||
@grammarsActivated = true
|
||||
|
||||
scopedProperties.activate() for scopedProperties in @scopedProperties
|
||||
@scopedPropertiesActivated = true
|
||||
settings.activate() for settings in @settings
|
||||
@settingsActivated = true
|
||||
|
||||
loadKeymaps: ->
|
||||
if @bundledPackage and packagesCache[@name]?
|
||||
@keymaps = (["#{atom.packages.resourcePath}#{path.sep}#{keymapPath}", keymapObject] for keymapPath, keymapObject of packagesCache[@name].keymaps)
|
||||
else
|
||||
@keymaps = @getKeymapPaths().map (keymapPath) -> [keymapPath, CSON.readFileSync(keymapPath)]
|
||||
@keymaps = @getKeymapPaths().map (keymapPath) -> [keymapPath, CSON.readFileSync(keymapPath) ? {}]
|
||||
|
||||
loadMenus: ->
|
||||
if @bundledPackage and packagesCache[@name]?
|
||||
@menus = (["#{atom.packages.resourcePath}#{path.sep}#{menuPath}", menuObject] for menuPath, menuObject of packagesCache[@name].menus)
|
||||
else
|
||||
@menus = @getMenuPaths().map (menuPath) -> [menuPath, CSON.readFileSync(menuPath)]
|
||||
@menus = @getMenuPaths().map (menuPath) -> [menuPath, CSON.readFileSync(menuPath) ? {}]
|
||||
|
||||
getKeymapPaths: ->
|
||||
keymapsDirPath = path.join(@path, 'keymaps')
|
||||
@@ -283,22 +283,28 @@ class Package
|
||||
async.each grammarPaths, loadGrammar, -> deferred.resolve()
|
||||
deferred.promise
|
||||
|
||||
loadScopedProperties: ->
|
||||
@scopedProperties = []
|
||||
loadSettings: ->
|
||||
@settings = []
|
||||
|
||||
loadScopedPropertiesFile = (scopedPropertiesPath, callback) =>
|
||||
ScopedProperties.load scopedPropertiesPath, (error, scopedProperties) =>
|
||||
loadSettingsFile = (settingsPath, callback) =>
|
||||
ScopedProperties.load settingsPath, (error, settings) =>
|
||||
if error?
|
||||
console.warn("Failed to load scoped properties: #{scopedPropertiesPath}", error.stack ? error)
|
||||
console.warn("Failed to load package settings: #{settingsPath}", error.stack ? error)
|
||||
else
|
||||
@scopedProperties.push(scopedProperties)
|
||||
scopedProperties.activate() if @scopedPropertiesActivated
|
||||
@settings.push(settings)
|
||||
settings.activate() if @settingsActivated
|
||||
callback()
|
||||
|
||||
deferred = Q.defer()
|
||||
scopedPropertiesDirPath = path.join(@path, 'scoped-properties')
|
||||
fs.list scopedPropertiesDirPath, ['json', 'cson'], (error, scopedPropertiesPaths=[]) ->
|
||||
async.each scopedPropertiesPaths, loadScopedPropertiesFile, -> deferred.resolve()
|
||||
|
||||
if fs.isDirectorySync(path.join(@path, 'scoped-properties'))
|
||||
settingsDirPath = path.join(@path, 'scoped-properties')
|
||||
deprecate("Store package settings files in the `settings` directory instead of `scoped-properties`")
|
||||
else
|
||||
settingsDirPath = path.join(@path, 'settings')
|
||||
|
||||
fs.list settingsDirPath, ['json', 'cson'], (error, settingsPaths=[]) ->
|
||||
async.each settingsPaths, loadSettingsFile, -> deferred.resolve()
|
||||
deferred.promise
|
||||
|
||||
serialize: ->
|
||||
@@ -328,12 +334,12 @@ class Package
|
||||
|
||||
deactivateResources: ->
|
||||
grammar.deactivate() for grammar in @grammars
|
||||
scopedProperties.deactivate() for scopedProperties in @scopedProperties
|
||||
settings.deactivate() for settings in @settings
|
||||
@stylesheetDisposables?.dispose()
|
||||
@activationDisposables?.dispose()
|
||||
@stylesheetsActivated = false
|
||||
@grammarsActivated = false
|
||||
@scopedPropertiesActivated = false
|
||||
@settingsActivated = false
|
||||
|
||||
reloadStylesheets: ->
|
||||
oldSheets = _.clone(@stylesheets)
|
||||
|
||||
@@ -153,7 +153,9 @@ class PaneView extends View
|
||||
activeItemModifiedChanged: =>
|
||||
@trigger 'pane:active-item-modified-status-changed'
|
||||
|
||||
@::accessor 'activeView', -> atom.views.getView(@activeItem)?.__spacePenView
|
||||
@::accessor 'activeView', ->
|
||||
element = atom.views.getView(@activeItem)
|
||||
$(element).view() ? element
|
||||
|
||||
splitLeft: (items...) -> atom.views.getView(@model.splitLeft({items})).__spacePenView
|
||||
|
||||
|
||||
+29
-83
@@ -166,9 +166,33 @@ class Project extends Model
|
||||
return fullPath if fullPath?.match(/[A-Za-z0-9+-.]+:\/\//) # leave path alone if it has a scheme
|
||||
@rootDirectory?.relativize(fullPath) ? fullPath
|
||||
|
||||
# Public: Returns whether the given path is inside this project.
|
||||
# Public: Determines whether the given path (real or symbolic) is inside the
|
||||
# project's directory.
|
||||
#
|
||||
# This method does not actually check if the path exists, it just checks their
|
||||
# locations relative to each other.
|
||||
#
|
||||
# ## Examples
|
||||
#
|
||||
# Basic operation
|
||||
#
|
||||
# ```coffee
|
||||
# # Project's root directory is /foo/bar
|
||||
# project.contains('/foo/bar/baz') # => true
|
||||
# project.contains('/usr/lib/baz') # => false
|
||||
# ```
|
||||
#
|
||||
# Existence of the path is not required
|
||||
#
|
||||
# ```coffee
|
||||
# # Project's root directory is /foo/bar
|
||||
# fs.existsSync('/foo/bar/baz') # => false
|
||||
# project.contains('/foo/bar/baz') # => true
|
||||
# ```
|
||||
#
|
||||
# * `pathToCheck` {String} path
|
||||
#
|
||||
# Returns whether the path is inside the project's root directory.
|
||||
contains: (pathToCheck) ->
|
||||
@rootDirectory?.contains(pathToCheck) ? false
|
||||
|
||||
@@ -176,91 +200,13 @@ class Project extends Model
|
||||
Section: Searching and Replacing
|
||||
###
|
||||
|
||||
# Public: Performs a search across all the files in the project.
|
||||
#
|
||||
# * `regex` {RegExp} to search with.
|
||||
# * `options` (optional) {Object} (default: {})
|
||||
# * `paths` An {Array} of glob patterns to search within
|
||||
# * `iterator` {Function} callback on each file found
|
||||
scan: (regex, options={}, iterator) ->
|
||||
if _.isFunction(options)
|
||||
iterator = options
|
||||
options = {}
|
||||
Grim.deprecate("Use atom.workspace.scan instead of atom.project.scan")
|
||||
atom.workspace.scan(regex, options, iterator)
|
||||
|
||||
deferred = Q.defer()
|
||||
|
||||
searchOptions =
|
||||
ignoreCase: regex.ignoreCase
|
||||
inclusions: options.paths
|
||||
includeHidden: true
|
||||
excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths')
|
||||
exclusions: atom.config.get('core.ignoredNames')
|
||||
|
||||
# TODO: need to support all paths in @getPaths()
|
||||
task = Task.once require.resolve('./scan-handler'), @getPaths()[0], regex.source, searchOptions, ->
|
||||
deferred.resolve()
|
||||
|
||||
task.on 'scan:result-found', (result) =>
|
||||
iterator(result) unless @isPathModified(result.filePath)
|
||||
|
||||
task.on 'scan:file-error', (error) ->
|
||||
iterator(null, error)
|
||||
|
||||
if _.isFunction(options.onPathsSearched)
|
||||
task.on 'scan:paths-searched', (numberOfPathsSearched) ->
|
||||
options.onPathsSearched(numberOfPathsSearched)
|
||||
|
||||
for buffer in @getBuffers() when buffer.isModified()
|
||||
filePath = buffer.getPath()
|
||||
continue unless @contains(filePath)
|
||||
matches = []
|
||||
buffer.scan regex, (match) -> matches.push match
|
||||
iterator {filePath, matches} if matches.length > 0
|
||||
|
||||
promise = deferred.promise
|
||||
promise.cancel = ->
|
||||
task.terminate()
|
||||
deferred.resolve('cancelled')
|
||||
promise
|
||||
|
||||
# Public: Performs a replace across all the specified files in the project.
|
||||
#
|
||||
# * `regex` A {RegExp} to search with.
|
||||
# * `replacementText` Text to replace all matches of regex with
|
||||
# * `filePaths` List of file path strings to run the replace on.
|
||||
# * `iterator` A {Function} callback on each file with replacements:
|
||||
# * `options` {Object} with keys `filePath` and `replacements`
|
||||
replace: (regex, replacementText, filePaths, iterator) ->
|
||||
deferred = Q.defer()
|
||||
|
||||
openPaths = (buffer.getPath() for buffer in @getBuffers())
|
||||
outOfProcessPaths = _.difference(filePaths, openPaths)
|
||||
|
||||
inProcessFinished = !openPaths.length
|
||||
outOfProcessFinished = !outOfProcessPaths.length
|
||||
checkFinished = ->
|
||||
deferred.resolve() if outOfProcessFinished and inProcessFinished
|
||||
|
||||
unless outOfProcessFinished.length
|
||||
flags = 'g'
|
||||
flags += 'i' if regex.ignoreCase
|
||||
|
||||
task = Task.once require.resolve('./replace-handler'), outOfProcessPaths, regex.source, flags, replacementText, ->
|
||||
outOfProcessFinished = true
|
||||
checkFinished()
|
||||
|
||||
task.on 'replace:path-replaced', iterator
|
||||
task.on 'replace:file-error', (error) -> iterator(null, error)
|
||||
|
||||
for buffer in @getBuffers()
|
||||
continue unless buffer.getPath() in filePaths
|
||||
replacements = buffer.replace(regex, replacementText, iterator)
|
||||
iterator({filePath: buffer.getPath(), replacements}) if replacements
|
||||
|
||||
inProcessFinished = true
|
||||
checkFinished()
|
||||
|
||||
deferred.promise
|
||||
Grim.deprecate("Use atom.workspace.replace instead of atom.project.replace")
|
||||
atom.workspace.replace(regex, replacementText, filePaths, iterator)
|
||||
|
||||
###
|
||||
Section: Private
|
||||
|
||||
@@ -11,12 +11,13 @@ class ScopedProperties
|
||||
callback(null, new ScopedProperties(scopedPropertiesPath, scopedProperties))
|
||||
|
||||
constructor: (@path, @scopedProperties) ->
|
||||
@propertyDisposable = new CompositeDisposable
|
||||
|
||||
activate: ->
|
||||
for selector, properties of @scopedProperties
|
||||
@propertyDisposable.add atom.config.addScopedSettings(@path, selector, properties)
|
||||
atom.config.set(null, properties, scopeSelector: selector, source: @path)
|
||||
return
|
||||
|
||||
deactivate: ->
|
||||
@propertyDisposable.dispose()
|
||||
for selector of @scopedProperties
|
||||
atom.config.unset(null, scopeSelector: selector, source: @path)
|
||||
return
|
||||
|
||||
@@ -536,8 +536,6 @@ class Selection extends Model
|
||||
# of a comment.
|
||||
#
|
||||
# Removes the comment if they are currently wrapped in a comment.
|
||||
#
|
||||
# Returns an Array of the commented {Range}s.
|
||||
toggleLineComments: ->
|
||||
@editor.toggleLineCommentsForBufferRows(@getBufferRowRange()...)
|
||||
|
||||
|
||||
+10
-10
@@ -92,7 +92,7 @@ class StyleManager
|
||||
addStyleSheet: (source, params) ->
|
||||
sourcePath = params?.sourcePath
|
||||
context = params?.context
|
||||
group = params?.group
|
||||
priority = params?.priority
|
||||
|
||||
if sourcePath? and styleElement = @styleElementsBySourcePath[sourcePath]
|
||||
updated = true
|
||||
@@ -106,9 +106,9 @@ class StyleManager
|
||||
styleElement.context = context
|
||||
styleElement.setAttribute('context', context)
|
||||
|
||||
if group?
|
||||
styleElement.group = group
|
||||
styleElement.setAttribute('group', group)
|
||||
if priority?
|
||||
styleElement.priority = priority
|
||||
styleElement.setAttribute('priority', priority)
|
||||
|
||||
styleElement.textContent = source
|
||||
|
||||
@@ -120,14 +120,14 @@ class StyleManager
|
||||
new Disposable => @removeStyleElement(styleElement)
|
||||
|
||||
addStyleElement: (styleElement) ->
|
||||
{sourcePath, group} = styleElement
|
||||
{sourcePath, priority} = styleElement
|
||||
|
||||
if group?
|
||||
if priority?
|
||||
for existingElement, index in @styleElements
|
||||
if existingElement.group is group
|
||||
insertIndex = index + 1
|
||||
else
|
||||
break if insertIndex?
|
||||
if existingElement.priority > priority
|
||||
insertIndex = index
|
||||
break
|
||||
|
||||
insertIndex ?= @styleElements.length
|
||||
|
||||
@styleElements.splice(insertIndex, 0, styleElement)
|
||||
|
||||
@@ -53,13 +53,14 @@ class StylesElement extends HTMLElement
|
||||
styleElementClone = styleElement.cloneNode(true)
|
||||
styleElementClone.sourcePath = styleElement.sourcePath
|
||||
styleElementClone.context = styleElement.context
|
||||
styleElementClone.priority = styleElement.priority
|
||||
@styleElementClonesByOriginalElement.set(styleElement, styleElementClone)
|
||||
|
||||
group = styleElement.getAttribute('group')
|
||||
if group?
|
||||
priority = styleElement.priority
|
||||
if priority?
|
||||
for child in @children
|
||||
if child.getAttribute('group') is group and child.nextSibling?.getAttribute('group') isnt group
|
||||
insertBefore = child.nextSibling
|
||||
if child.priority > priority
|
||||
insertBefore = child
|
||||
break
|
||||
|
||||
@insertBefore(styleElementClone, insertBefore)
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
_ = require 'underscore-plus'
|
||||
child_process = require 'child_process'
|
||||
{fork} = require 'child_process'
|
||||
{Emitter} = require 'emissary'
|
||||
|
||||
# Extended: Run a node script in a separate process.
|
||||
@@ -98,7 +98,7 @@ class Task
|
||||
taskPath = taskPath.replace(/\\/g, "\\\\")
|
||||
|
||||
env = _.extend({}, process.env, {taskPath, userAgent: navigator.userAgent})
|
||||
@childProcess = child_process.fork '--eval', [bootstrap], {env, cwd: __dirname}
|
||||
@childProcess = fork '--eval', [bootstrap], {env, cwd: __dirname}
|
||||
|
||||
@on "task:log", -> console.log(arguments...)
|
||||
@on "task:warn", -> console.warn(arguments...)
|
||||
|
||||
@@ -404,7 +404,7 @@ TextEditorComponent = React.createClass
|
||||
window.addEventListener 'resize', @requestHeightAndWidthMeasurement
|
||||
|
||||
@listenForIMEEvents()
|
||||
@listenForMiddleMousePaste() if process.platform is 'linux'
|
||||
@trackSelectionClipboard() if process.platform is 'linux'
|
||||
|
||||
listenForIMEEvents: ->
|
||||
node = @getDOMNode()
|
||||
@@ -432,21 +432,21 @@ TextEditorComponent = React.createClass
|
||||
editor.insertText(selectedText, select: true, undo: 'skip')
|
||||
event.target.value = ''
|
||||
|
||||
listenForMiddleMousePaste: ->
|
||||
clipboard = require 'clipboard'
|
||||
|
||||
@refs.scrollView.getDOMNode().addEventListener 'mouseup', ({which}) =>
|
||||
return unless which is 2
|
||||
|
||||
if selection = clipboard.readText('selection')
|
||||
@props.editor.insertText(selection)
|
||||
|
||||
@subscribe @props.editor.onDidChangeSelectionRange =>
|
||||
if selectedText = @props.editor.getSelectedText()
|
||||
# Listen for selection changes and store the currently selected text
|
||||
# in the selection clipboard. This is only applicable on Linux.
|
||||
trackSelectionClipboard: ->
|
||||
timeoutId = null
|
||||
{editor} = @props
|
||||
writeSelectedTextToSelectionClipboard = ->
|
||||
return if editor.isDestroyed()
|
||||
if selectedText = editor.getSelectedText()
|
||||
# This uses ipc.send instead of clipboard.writeText because
|
||||
# clipboard.writeText is a sync ipc call on Linux and that
|
||||
# will slow down selections.
|
||||
ipc.send('write-text-to-selection-clipboard', selectedText)
|
||||
@subscribe editor.onDidChangeSelectionRange ->
|
||||
clearTimeout(timeoutId)
|
||||
timeoutId = setTimeout(writeSelectedTextToSelectionClipboard)
|
||||
|
||||
observeConfig: ->
|
||||
@subscribe atom.config.observe 'editor.useHardwareAcceleration', @setUseHardwareAcceleration
|
||||
@@ -462,9 +462,9 @@ TextEditorComponent = React.createClass
|
||||
|
||||
scopeDescriptor = editor.getRootScopeDescriptor()
|
||||
|
||||
subscriptions.add atom.config.observe scopeDescriptor, 'editor.showIndentGuide', @setShowIndentGuide
|
||||
subscriptions.add atom.config.observe scopeDescriptor, 'editor.showLineNumbers', @setShowLineNumbers
|
||||
subscriptions.add atom.config.observe scopeDescriptor, 'editor.scrollSensitivity', @setScrollSensitivity
|
||||
subscriptions.add atom.config.observe 'editor.showIndentGuide', scope: scopeDescriptor, @setShowIndentGuide
|
||||
subscriptions.add atom.config.observe 'editor.showLineNumbers', scope: scopeDescriptor, @setShowLineNumbers
|
||||
subscriptions.add atom.config.observe 'editor.scrollSensitivity', scope: scopeDescriptor, @setScrollSensitivity
|
||||
|
||||
focused: ->
|
||||
if @isMounted()
|
||||
@@ -560,7 +560,11 @@ TextEditorComponent = React.createClass
|
||||
scrollViewNode.scrollLeft = 0
|
||||
|
||||
onMouseDown: (event) ->
|
||||
return unless event.button is 0 # only handle the left mouse button
|
||||
unless event.button is 0 or (event.button is 1 and process.platform is 'linux')
|
||||
# Only handle mouse down events for left mouse button on all platforms
|
||||
# and middle mouse button on Linux since it pastes the selection clipboard
|
||||
return
|
||||
|
||||
return if event.target?.classList.contains('horizontal-scrollbar')
|
||||
|
||||
{editor} = @props
|
||||
@@ -750,10 +754,12 @@ TextEditorComponent = React.createClass
|
||||
lastMousePosition = {}
|
||||
animationLoop = =>
|
||||
@requestAnimationFrame =>
|
||||
if dragging
|
||||
if dragging and @isMounted()
|
||||
screenPosition = @screenPositionForMouseEvent(lastMousePosition)
|
||||
dragHandler(screenPosition)
|
||||
animationLoop()
|
||||
else if not @isMounted()
|
||||
stopDragging()
|
||||
|
||||
onMouseMove = (event) ->
|
||||
lastMousePosition.clientX = event.clientX
|
||||
@@ -767,11 +773,20 @@ TextEditorComponent = React.createClass
|
||||
# Stop dragging when cursor enters dev tools because we can't detect mouseup
|
||||
onMouseUp() if event.which is 0
|
||||
|
||||
onMouseUp = ->
|
||||
onMouseUp = (event) ->
|
||||
stopDragging()
|
||||
editor.finalizeSelections()
|
||||
pasteSelectionClipboard(event)
|
||||
|
||||
stopDragging = ->
|
||||
dragging = false
|
||||
window.removeEventListener('mousemove', onMouseMove)
|
||||
window.removeEventListener('mouseup', onMouseUp)
|
||||
editor.finalizeSelections()
|
||||
|
||||
pasteSelectionClipboard = (event) ->
|
||||
if event?.which is 2 and process.platform is 'linux'
|
||||
if selection = require('clipboard').readText('selection')
|
||||
editor.insertText(selection)
|
||||
|
||||
window.addEventListener('mousemove', onMouseMove)
|
||||
window.addEventListener('mouseup', onMouseUp)
|
||||
|
||||
@@ -67,6 +67,7 @@ class TextEditorElement extends HTMLElement
|
||||
@emitter.emit("did-attach")
|
||||
|
||||
detachedCallback: ->
|
||||
@unmountComponent()
|
||||
@emitter.emit("did-detach")
|
||||
|
||||
initialize: (model) ->
|
||||
|
||||
@@ -168,8 +168,8 @@ class TextEditor extends Model
|
||||
|
||||
scopeDescriptor = @getRootScopeDescriptor()
|
||||
|
||||
subscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.showInvisibles', => @updateInvisibles()
|
||||
subscriptions.add atom.config.onDidChange scopeDescriptor, 'editor.invisibles', => @updateInvisibles()
|
||||
subscriptions.add atom.config.onDidChange 'editor.showInvisibles', scope: scopeDescriptor, => @updateInvisibles()
|
||||
subscriptions.add atom.config.onDidChange 'editor.invisibles', scope: scopeDescriptor, => @updateInvisibles()
|
||||
|
||||
getViewClass: ->
|
||||
require './text-editor-view'
|
||||
@@ -998,8 +998,6 @@ class TextEditor extends Model
|
||||
# Extended: Toggle line comments for rows intersecting selections.
|
||||
#
|
||||
# If the current grammar doesn't support comments, does nothing.
|
||||
#
|
||||
# Returns an {Array} of the commented {Range}s.
|
||||
toggleLineCommentsInSelection: ->
|
||||
@mutateSelectedText (selection) -> selection.toggleLineComments()
|
||||
|
||||
@@ -2812,17 +2810,17 @@ class TextEditor extends Model
|
||||
###
|
||||
|
||||
shouldAutoIndent: ->
|
||||
atom.config.get(@getRootScopeDescriptor(), "editor.autoIndent")
|
||||
atom.config.get("editor.autoIndent", scope: @getRootScopeDescriptor())
|
||||
|
||||
shouldAutoIndentOnPaste: ->
|
||||
atom.config.get(@getRootScopeDescriptor(), "editor.autoIndentOnPaste")
|
||||
atom.config.get("editor.autoIndentOnPaste", scope: @getRootScopeDescriptor())
|
||||
|
||||
shouldShowInvisibles: ->
|
||||
not @mini and atom.config.get(@getRootScopeDescriptor(), 'editor.showInvisibles')
|
||||
not @mini and atom.config.get('editor.showInvisibles', scope: @getRootScopeDescriptor())
|
||||
|
||||
updateInvisibles: ->
|
||||
if @shouldShowInvisibles()
|
||||
@displayBuffer.setInvisibles(atom.config.get(@getRootScopeDescriptor(), 'editor.invisibles'))
|
||||
@displayBuffer.setInvisibles(atom.config.get('editor.invisibles', scope: @getRootScopeDescriptor()))
|
||||
else
|
||||
@displayBuffer.setInvisibles(null)
|
||||
|
||||
@@ -2838,7 +2836,7 @@ class TextEditor extends Model
|
||||
@subscribeToScopedConfigSettings()
|
||||
@unfoldAll()
|
||||
@emit 'grammar-changed'
|
||||
@emitter.emit 'did-change-grammar'
|
||||
@emitter.emit 'did-change-grammar', @getGrammar()
|
||||
|
||||
handleMarkerCreated: (marker) =>
|
||||
if marker.matchesProperties(@getSelectionMarkerAttributes())
|
||||
|
||||
@@ -219,28 +219,30 @@ class ThemeManager
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to remove the
|
||||
# required stylesheet.
|
||||
requireStylesheet: (stylesheetPath, type='bundled') ->
|
||||
requireStylesheet: (stylesheetPath) ->
|
||||
if fullPath = @resolveStylesheet(stylesheetPath)
|
||||
content = @loadStylesheet(fullPath)
|
||||
@applyStylesheet(fullPath, content, type)
|
||||
@applyStylesheet(fullPath, content)
|
||||
else
|
||||
throw new Error("Could not find a file at path '#{stylesheetPath}'")
|
||||
|
||||
unwatchUserStylesheet: ->
|
||||
@userStylesheetFile?.off()
|
||||
@userStylesheetFile = null
|
||||
@removeStylesheet(@userStylesheetPath) if @userStylesheetPath?
|
||||
@userStyleSheetDisposable?.dispose()
|
||||
@userStyleSheetDisposable = null
|
||||
|
||||
loadUserStylesheet: ->
|
||||
@unwatchUserStylesheet()
|
||||
|
||||
userStylesheetPath = atom.styles.getUserStyleSheetPath()
|
||||
return unless fs.isFileSync(userStylesheetPath)
|
||||
|
||||
@userStylesheetPath = userStylesheetPath
|
||||
@userStylesheetFile = new File(userStylesheetPath)
|
||||
@userStylesheetFile.on 'contents-changed moved removed', => @loadUserStylesheet()
|
||||
userStylesheetContents = @loadStylesheet(userStylesheetPath, true)
|
||||
@applyStylesheet(userStylesheetPath, userStylesheetContents, 'userTheme')
|
||||
|
||||
@userStyleSheetDisposable = atom.styles.addStyleSheet(userStylesheetContents, sourcePath: userStylesheetPath, priority: 2)
|
||||
|
||||
loadBaseStylesheets: ->
|
||||
@requireStylesheet('../static/bootstrap')
|
||||
@@ -291,8 +293,8 @@ class ThemeManager
|
||||
removeStylesheet: (stylesheetPath) ->
|
||||
@styleSheetDisposablesBySourcePath[stylesheetPath]?.dispose()
|
||||
|
||||
applyStylesheet: (path, text, type='bundled') ->
|
||||
@styleSheetDisposablesBySourcePath[path] = atom.styles.addStyleSheet(text, sourcePath: path, group: type)
|
||||
applyStylesheet: (path, text) ->
|
||||
@styleSheetDisposablesBySourcePath[path] = atom.styles.addStyleSheet(text, sourcePath: path)
|
||||
|
||||
stringToId: (string) ->
|
||||
string.replace(/\\/g, '/')
|
||||
|
||||
@@ -5,7 +5,7 @@ module.exports =
|
||||
class ThemePackage extends Package
|
||||
getType: -> 'theme'
|
||||
|
||||
getStylesheetType: -> 'theme'
|
||||
getStyleSheetPriority: -> 1
|
||||
|
||||
enable: ->
|
||||
atom.config.unshiftAtKeyPath('core.themes', @name)
|
||||
|
||||
@@ -84,10 +84,10 @@ class TokenizedBuffer extends Model
|
||||
@currentGrammarScore = score ? grammar.getScore(@buffer.getPath(), @buffer.getText())
|
||||
@subscribe @grammar.onDidUpdate => @retokenizeLines()
|
||||
|
||||
@configSettings = tabLength: atom.config.get(@rootScopeDescriptor, 'editor.tabLength')
|
||||
@configSettings = tabLength: atom.config.get('editor.tabLength', scope: @rootScopeDescriptor)
|
||||
|
||||
@grammarTabLengthSubscription?.dispose()
|
||||
@grammarTabLengthSubscription = atom.config.onDidChange @rootScopeDescriptor, 'editor.tabLength', ({newValue}) =>
|
||||
@grammarTabLengthSubscription = atom.config.onDidChange 'editor.tabLength', scope: @rootScopeDescriptor, ({newValue}) =>
|
||||
@configSettings.tabLength = newValue
|
||||
@retokenizeLines()
|
||||
@subscribe @grammarTabLengthSubscription
|
||||
|
||||
@@ -65,7 +65,7 @@ class ViewRegistry
|
||||
# * `modelConstructor` Constructor {Function} for your model.
|
||||
# * `viewConstructor` (Optional) Constructor {Function} for your view. It
|
||||
# should be a subclass of `HTMLElement` (that is, your view should be a
|
||||
# DOM node) and have a `::setModel()` method which will be called
|
||||
# DOM node) and have a `::setModel()` method which will be called
|
||||
# immediately after construction. If you don't supply this property, you
|
||||
# must supply the `createView` property with a function that never returns
|
||||
# `undefined`.
|
||||
@@ -97,12 +97,14 @@ class ViewRegistry
|
||||
# ## Examples
|
||||
#
|
||||
# ### Getting An Editor Element
|
||||
#
|
||||
# ```coffee
|
||||
# textEditor = atom.workspace.getActiveTextEditor()
|
||||
# textEditorElement = atom.views.getView(textEditor)
|
||||
# ```
|
||||
#
|
||||
# ### Getting A Pane Element
|
||||
#
|
||||
# ```coffee
|
||||
# pane = atom.workspace.getActivePane()
|
||||
# paneElement = atom.views.getView(pane)
|
||||
@@ -132,7 +134,6 @@ class ViewRegistry
|
||||
if object instanceof HTMLElement
|
||||
object
|
||||
else if object?.jquery
|
||||
object[0]?.__spacePenView ?= object
|
||||
object[0]
|
||||
else if provider = @findProvider(object)
|
||||
element = provider.createView?(object)
|
||||
@@ -142,7 +143,6 @@ class ViewRegistry
|
||||
element
|
||||
else if viewConstructor = object?.getViewClass?()
|
||||
view = new viewConstructor(object)
|
||||
view[0].__spacePenView ?= view
|
||||
view[0]
|
||||
else
|
||||
throw new Error("Can't create a view for #{object.constructor.name} instance. Please register a view provider.")
|
||||
|
||||
@@ -92,7 +92,7 @@ class WindowEventHandler
|
||||
|
||||
document.addEventListener 'dragover', @onDragOver
|
||||
@subscribe new Disposable =>
|
||||
document.removeEventListener('dragover', @onKeydown)
|
||||
document.removeEventListener('dragover', @onDragOver)
|
||||
|
||||
@subscribe $(document), 'click', 'a', @openLink
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ class WorkspaceView extends View
|
||||
return atom.views.getView(atom.workspace).__spacePenView
|
||||
super
|
||||
@deprecateViewEvents()
|
||||
@attachedEditorViews = new WeakSet
|
||||
|
||||
setModel: (@model) ->
|
||||
@horizontal = @find('atom-workspace-axis.horizontal')
|
||||
@@ -95,10 +96,17 @@ class WorkspaceView extends View
|
||||
# Returns a subscription object with an `.off` method that you can call to
|
||||
# unregister the callback.
|
||||
eachEditorView: (callback) ->
|
||||
callback(editorView) for editorView in @getEditorViews()
|
||||
attachedCallback = (e, editorView) ->
|
||||
callback(editorView) unless editorView.mini
|
||||
for editorView in @getEditorViews()
|
||||
@attachedEditorViews.add(editorView)
|
||||
callback(editorView)
|
||||
|
||||
attachedCallback = (e, editorView) =>
|
||||
unless @attachedEditorViews.has(editorView)
|
||||
@attachedEditorViews.add(editorView)
|
||||
callback(editorView) unless editorView.mini
|
||||
|
||||
@on('editor:attached', attachedCallback)
|
||||
|
||||
off: => @off('editor:attached', attachedCallback)
|
||||
|
||||
# Essential: Register a function to be called for every current and future
|
||||
@@ -229,7 +237,7 @@ class WorkspaceView extends View
|
||||
when 'cursor:moved'
|
||||
deprecate('Use TextEditor::onDidChangeCursorPosition instead')
|
||||
when 'editor:attached'
|
||||
deprecate('Use TextEditor::onDidAddTextEditor instead')
|
||||
deprecate('Use Workspace::onDidAddTextEditor instead')
|
||||
when 'editor:detached'
|
||||
deprecate('Use TextEditor::onDidDestroy instead')
|
||||
when 'editor:will-be-removed'
|
||||
|
||||
+109
-1
@@ -14,6 +14,7 @@ PanelElement = require './panel-element'
|
||||
PanelContainer = require './panel-container'
|
||||
PanelContainerElement = require './panel-container-element'
|
||||
WorkspaceElement = require './workspace-element'
|
||||
Task = require './task'
|
||||
|
||||
# Essential: Represents the state of the user interface for the entire window.
|
||||
# An instance of this class is available via the `atom.workspace` global.
|
||||
@@ -455,6 +456,8 @@ class Workspace extends Model
|
||||
@itemOpened(item)
|
||||
pane.activateItem(item)
|
||||
pane.activate() if activatePane
|
||||
if options.initialLine? or options.initialColumn?
|
||||
item.setCursorBufferPosition?([options.initialLine, options.initialColumn])
|
||||
index = pane.getActiveItemIndex()
|
||||
@emit "uri-opened"
|
||||
@emitter.emit 'did-open', {uri, pane, item, index}
|
||||
@@ -645,7 +648,7 @@ class Workspace extends Model
|
||||
|
||||
# Restore to a default editor font size.
|
||||
resetFontSize: ->
|
||||
atom.config.restoreDefault("editor.fontSize")
|
||||
atom.config.unset("editor.fontSize")
|
||||
|
||||
# Removes the item's uri from the list of potential items to reopen.
|
||||
itemOpened: (item) ->
|
||||
@@ -665,6 +668,16 @@ class Workspace extends Model
|
||||
|
||||
###
|
||||
Section: Panels
|
||||
|
||||
Panels are used to display UI related to an editor window. They are placed at one of the four
|
||||
edges of the window: left, right, top or bottom. If there are multiple panels on the same window
|
||||
edge they are stacked in order of priority: higher priority is closer to the center, lower
|
||||
priority towards the edge.
|
||||
|
||||
*Note:* If your panel changes its size throughout its lifetime, consider giving it a higher
|
||||
priority, allowing fixed size panels to be closer to the edge. This allows control targets to
|
||||
remain more static for easier targeting by users that employ mice or trackpads. (See
|
||||
[atom/atom#4834](https://github.com/atom/atom/issues/4834) for discussion.)
|
||||
###
|
||||
|
||||
# Essential: Get an {Array} of all the panel items at the bottom of the editor window.
|
||||
@@ -778,3 +791,98 @@ class Workspace extends Model
|
||||
addPanel: (location, options) ->
|
||||
options ?= {}
|
||||
@panelContainers[location].addPanel(new Panel(options))
|
||||
|
||||
###
|
||||
Section: Searching and Replacing
|
||||
###
|
||||
|
||||
# Public: Performs a search across all the files in the workspace.
|
||||
#
|
||||
# * `regex` {RegExp} to search with.
|
||||
# * `options` (optional) {Object} (default: {})
|
||||
# * `paths` An {Array} of glob patterns to search within
|
||||
# * `iterator` {Function} callback on each file found
|
||||
#
|
||||
# Returns a `Promise`.
|
||||
scan: (regex, options={}, iterator) ->
|
||||
if _.isFunction(options)
|
||||
iterator = options
|
||||
options = {}
|
||||
|
||||
deferred = Q.defer()
|
||||
|
||||
searchOptions =
|
||||
ignoreCase: regex.ignoreCase
|
||||
inclusions: options.paths
|
||||
includeHidden: true
|
||||
excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths')
|
||||
exclusions: atom.config.get('core.ignoredNames')
|
||||
follow: atom.config.get('core.followSymlinks')
|
||||
|
||||
# TODO: need to support all paths in @getPaths()
|
||||
task = Task.once require.resolve('./scan-handler'), atom.project.getPaths()[0], regex.source, searchOptions, ->
|
||||
deferred.resolve()
|
||||
|
||||
task.on 'scan:result-found', (result) =>
|
||||
iterator(result) unless atom.project.isPathModified(result.filePath)
|
||||
|
||||
task.on 'scan:file-error', (error) ->
|
||||
iterator(null, error)
|
||||
|
||||
if _.isFunction(options.onPathsSearched)
|
||||
task.on 'scan:paths-searched', (numberOfPathsSearched) ->
|
||||
options.onPathsSearched(numberOfPathsSearched)
|
||||
|
||||
for buffer in atom.project.getBuffers() when buffer.isModified()
|
||||
filePath = buffer.getPath()
|
||||
continue unless atom.project.contains(filePath)
|
||||
matches = []
|
||||
buffer.scan regex, (match) -> matches.push match
|
||||
iterator {filePath, matches} if matches.length > 0
|
||||
|
||||
promise = deferred.promise
|
||||
promise.cancel = ->
|
||||
task.terminate()
|
||||
deferred.resolve('cancelled')
|
||||
promise
|
||||
|
||||
# Public: Performs a replace across all the specified files in the project.
|
||||
#
|
||||
# * `regex` A {RegExp} to search with.
|
||||
# * `replacementText` Text to replace all matches of regex with
|
||||
# * `filePaths` List of file path strings to run the replace on.
|
||||
# * `iterator` A {Function} callback on each file with replacements:
|
||||
# * `options` {Object} with keys `filePath` and `replacements`
|
||||
#
|
||||
# Returns a `Promise`.
|
||||
replace: (regex, replacementText, filePaths, iterator) ->
|
||||
deferred = Q.defer()
|
||||
|
||||
openPaths = (buffer.getPath() for buffer in atom.project.getBuffers())
|
||||
outOfProcessPaths = _.difference(filePaths, openPaths)
|
||||
|
||||
inProcessFinished = !openPaths.length
|
||||
outOfProcessFinished = !outOfProcessPaths.length
|
||||
checkFinished = ->
|
||||
deferred.resolve() if outOfProcessFinished and inProcessFinished
|
||||
|
||||
unless outOfProcessFinished.length
|
||||
flags = 'g'
|
||||
flags += 'i' if regex.ignoreCase
|
||||
|
||||
task = Task.once require.resolve('./replace-handler'), outOfProcessPaths, regex.source, flags, replacementText, ->
|
||||
outOfProcessFinished = true
|
||||
checkFinished()
|
||||
|
||||
task.on 'replace:path-replaced', iterator
|
||||
task.on 'replace:file-error', (error) -> iterator(null, error)
|
||||
|
||||
for buffer in atom.project.getBuffers()
|
||||
continue unless buffer.getPath() in filePaths
|
||||
replacements = buffer.replace(regex, replacementText, iterator)
|
||||
iterator({filePath: buffer.getPath(), replacements}) if replacements
|
||||
|
||||
inProcessFinished = true
|
||||
checkFinished()
|
||||
|
||||
deferred.promise
|
||||
|
||||
+8
-16
@@ -26,6 +26,7 @@
|
||||
.make-icon(beer);
|
||||
.make-icon(book);
|
||||
.make-icon(bookmark);
|
||||
.make-icon(briefcase);
|
||||
.make-icon(broadcast);
|
||||
.make-icon(browser);
|
||||
.make-icon(bug);
|
||||
@@ -37,6 +38,7 @@
|
||||
.make-icon(chevron-right);
|
||||
.make-icon(chevron-up);
|
||||
.make-icon(circle-slash);
|
||||
.make-icon(circuit-board);
|
||||
.make-icon(clippy);
|
||||
.make-icon(clock);
|
||||
.make-icon(cloud-download);
|
||||
@@ -114,6 +116,7 @@
|
||||
.make-icon(jump-up);
|
||||
.make-icon(key);
|
||||
.make-icon(keyboard);
|
||||
.make-icon(law);
|
||||
.make-icon(light-bulb);
|
||||
.make-icon(link);
|
||||
.make-icon(link-external);
|
||||
@@ -123,36 +126,26 @@
|
||||
.make-icon(lock);
|
||||
.make-icon(log-in);
|
||||
.make-icon(log-out);
|
||||
.make-icon(logo-apps);
|
||||
.make-icon(logo-atom);
|
||||
.make-icon(logo-chat);
|
||||
.make-icon(logo-gist);
|
||||
.make-icon(logo-github);
|
||||
.make-icon(logo-octicons);
|
||||
.make-icon(logo-talks);
|
||||
.make-icon(mail);
|
||||
.make-icon(mail-read);
|
||||
.make-icon(mail-reply);
|
||||
.make-icon(mark-facebook);
|
||||
.make-icon(mark-github);
|
||||
.make-icon(mark-github-detail);
|
||||
.make-icon(mark-google);
|
||||
.make-icon(mark-twitter);
|
||||
.make-icon(markdown);
|
||||
.make-icon(megaphone);
|
||||
.make-icon(mention);
|
||||
.make-icon(microscope);
|
||||
.make-icon(milestone);
|
||||
.make-icon(mirror);
|
||||
.make-icon(mirror-private);
|
||||
.make-icon(mirror-public);
|
||||
.make-icon(mortar-board);
|
||||
.make-icon(move-down);
|
||||
.make-icon(move-left);
|
||||
.make-icon(move-right);
|
||||
.make-icon(move-up);
|
||||
.make-icon(mute);
|
||||
.make-icon(mute-video);
|
||||
.make-icon(no-newline);
|
||||
.make-icon(node-js);
|
||||
.make-icon(octoface);
|
||||
.make-icon(organization);
|
||||
.make-icon(package);
|
||||
@@ -161,12 +154,12 @@
|
||||
.make-icon(person);
|
||||
.make-icon(person-add);
|
||||
.make-icon(person-follow);
|
||||
.make-icon(person-remove);
|
||||
.make-icon(pin);
|
||||
.make-icon(playback-fast-forward);
|
||||
.make-icon(playback-pause);
|
||||
.make-icon(playback-play);
|
||||
.make-icon(playback-rewind);
|
||||
.make-icon(plug);
|
||||
.make-icon(plus);
|
||||
.make-icon(podium);
|
||||
.make-icon(primitive-dot);
|
||||
@@ -187,7 +180,6 @@
|
||||
.make-icon(repo-push);
|
||||
.make-icon(repo-sync);
|
||||
.make-icon(rocket);
|
||||
.make-icon(rohan);
|
||||
.make-icon(rss);
|
||||
.make-icon(ruby);
|
||||
.make-icon(screen-full);
|
||||
@@ -196,6 +188,8 @@
|
||||
.make-icon(search-save);
|
||||
.make-icon(server);
|
||||
.make-icon(settings);
|
||||
.make-icon(sign-in);
|
||||
.make-icon(sign-out);
|
||||
.make-icon(split);
|
||||
.make-icon(squirrel);
|
||||
.make-icon(star);
|
||||
@@ -216,10 +210,8 @@
|
||||
.make-icon(triangle-left);
|
||||
.make-icon(triangle-right);
|
||||
.make-icon(triangle-up);
|
||||
.make-icon(trollface);
|
||||
.make-icon(unfold);
|
||||
.make-icon(unmute);
|
||||
.make-icon(unmute-video);
|
||||
.make-icon(versions);
|
||||
.make-icon(x);
|
||||
.make-icon(zap);
|
||||
|
||||
Arquivo normal → Arquivo executável
BIN
Arquivo binário não exibido.
+2
-5
@@ -33,17 +33,14 @@ atom-pane-container {
|
||||
min-width: 0;
|
||||
position: relative;
|
||||
|
||||
.pane-item {
|
||||
color: @text-color;
|
||||
background-color: @pane-item-background-color;
|
||||
}
|
||||
|
||||
> *, > atom-text-editor.react > * {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
color: @text-color;
|
||||
background-color: @pane-item-background-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
@beer: "\f069";
|
||||
@book: "\f007";
|
||||
@bookmark: "\f07b";
|
||||
@briefcase: "\f0d3";
|
||||
@broadcast: "\f048";
|
||||
@browser: "\f0c5";
|
||||
@bug: "\f091";
|
||||
@@ -24,6 +25,7 @@
|
||||
@chevron-right: "\f078";
|
||||
@chevron-up: "\f0a2";
|
||||
@circle-slash: "\f084";
|
||||
@circuit-board: "\f0d6";
|
||||
@clippy: "\f035";
|
||||
@clock: "\f046";
|
||||
@cloud-download: "\f00b";
|
||||
@@ -31,7 +33,7 @@
|
||||
@code: "\f05f";
|
||||
@color-mode: "\f065";
|
||||
@comment: "\f02b";
|
||||
@comment-add: "\f06f";
|
||||
@comment-add: "\f02b";
|
||||
@comment-discussion: "\f04f";
|
||||
@credit-card: "\f045";
|
||||
@dash: "\f0ca";
|
||||
@@ -49,13 +51,13 @@
|
||||
@diff-renamed: "\f06e";
|
||||
@ellipsis: "\f09a";
|
||||
@eye: "\f04e";
|
||||
@eye-unwatch: "\f01e";
|
||||
@eye-watch: "\f01d";
|
||||
@file-add: "\f086";
|
||||
@eye-unwatch: "\f04e";
|
||||
@eye-watch: "\f04e";
|
||||
@file-add: "\f05d";
|
||||
@file-binary: "\f094";
|
||||
@file-code: "\f010";
|
||||
@file-directory: "\f016";
|
||||
@file-directory-create: "\f095";
|
||||
@file-directory-create: "\f05d";
|
||||
@file-media: "\f012";
|
||||
@file-pdf: "\f014";
|
||||
@file-submodule: "\f017";
|
||||
@@ -68,19 +70,19 @@
|
||||
@gear: "\f02f";
|
||||
@gift: "\f042";
|
||||
@gist: "\f00e";
|
||||
@gist-fork: "\f079";
|
||||
@gist-new: "\f07a";
|
||||
@gist-private: "\f00f";
|
||||
@gist-fork: "\f002";
|
||||
@gist-new: "\f05d";
|
||||
@gist-private: "\f06a";
|
||||
@gist-secret: "\f08c";
|
||||
@git-branch: "\f020";
|
||||
@git-branch-create: "\f098";
|
||||
@git-branch-delete: "\f09b";
|
||||
@git-branch-create: "\f020";
|
||||
@git-branch-delete: "\f020";
|
||||
@git-commit: "\f01f";
|
||||
@git-compare: "\f0ac";
|
||||
@git-fork-private: "\f021";
|
||||
@git-fork-private: "\f06a";
|
||||
@git-merge: "\f023";
|
||||
@git-pull-request: "\f009";
|
||||
@git-pull-request-abandoned: "\f090";
|
||||
@git-pull-request-abandoned: "\f009";
|
||||
@globe: "\f0b6";
|
||||
@graph: "\f043";
|
||||
@heart: "\2665";
|
||||
@@ -101,6 +103,7 @@
|
||||
@jump-up: "\f073";
|
||||
@key: "\f049";
|
||||
@keyboard: "\f00d";
|
||||
@law: "\f0d8";
|
||||
@light-bulb: "\f000";
|
||||
@link: "\f05c";
|
||||
@link-external: "\f07f";
|
||||
@@ -110,50 +113,40 @@
|
||||
@lock: "\f06a";
|
||||
@log-in: "\f036";
|
||||
@log-out: "\f032";
|
||||
@logo-apps: "\f0b3";
|
||||
@logo-atom: "\f0b7";
|
||||
@logo-chat: "\f0b4";
|
||||
@logo-gist: "\f0ad";
|
||||
@logo-github: "\f092";
|
||||
@logo-octicons: "\f0ab";
|
||||
@logo-talks: "\f0b5";
|
||||
@mail: "\f03b";
|
||||
@mail-read: "\f03c";
|
||||
@mail-reply: "\f051";
|
||||
@mark-facebook: "\f0ce";
|
||||
@mark-github: "\f00a";
|
||||
@mark-github-detail: "\f093";
|
||||
@mark-google: "\f0cd";
|
||||
@mark-twitter: "\f0ae";
|
||||
@markdown: "\f0c9";
|
||||
@megaphone: "\f077";
|
||||
@mention: "\f0be";
|
||||
@microscope: "\f089";
|
||||
@milestone: "\f075";
|
||||
@mirror-private: "\f025";
|
||||
@mirror: "\f024";
|
||||
@mirror-private: "\f06a";
|
||||
@mirror-public: "\f024";
|
||||
@mortar-board: "\f0d7";
|
||||
@move-down: "\f0a8";
|
||||
@move-left: "\f074";
|
||||
@move-right: "\f0a9";
|
||||
@move-up: "\f0a7";
|
||||
@mute: "\f080";
|
||||
@mute-video: "\f0b8";
|
||||
@no-newline: "\f09c";
|
||||
@node-js: "\f0c3";
|
||||
@octoface: "\f008";
|
||||
@organization: "\f037";
|
||||
@package: "\f0c4";
|
||||
@paintcan: "\f0d1";
|
||||
@pencil: "\f058";
|
||||
@person: "\f018";
|
||||
@person-add: "\f01a";
|
||||
@person-follow: "\f01c";
|
||||
@person-remove: "\f01b";
|
||||
@person-add: "\f018";
|
||||
@person-follow: "\f018";
|
||||
@pin: "\f041";
|
||||
@playback-fast-forward: "\f0bd";
|
||||
@playback-pause: "\f0bb";
|
||||
@playback-play: "\f0bf";
|
||||
@playback-rewind: "\f0bc";
|
||||
@plug: "\f0d4";
|
||||
@plus: "\f05d";
|
||||
@podium: "\f0af";
|
||||
@primitive-dot: "\f052";
|
||||
@@ -163,37 +156,38 @@
|
||||
@question: "\f02c";
|
||||
@quote: "\f063";
|
||||
@radio-tower: "\f030";
|
||||
@remove-close: "\f050";
|
||||
@remove-close: "\f081";
|
||||
@repo: "\f001";
|
||||
@repo-clone: "\f04c";
|
||||
@repo-create: "\f003";
|
||||
@repo-delete: "\f004";
|
||||
@repo-create: "\f05d";
|
||||
@repo-delete: "\f001";
|
||||
@repo-force-push: "\f04a";
|
||||
@repo-forked: "\f002";
|
||||
@repo-pull: "\f006";
|
||||
@repo-push: "\f005";
|
||||
@repo-sync: "\f04b";
|
||||
@repo-sync: "\f087";
|
||||
@rocket: "\f033";
|
||||
@rohan: "\f022";
|
||||
@rss: "\f034";
|
||||
@ruby: "\f047";
|
||||
@screen-full: "\f066";
|
||||
@screen-normal: "\f067";
|
||||
@search: "\f02e";
|
||||
@search-save: "\f0cb";
|
||||
@search-save: "\f02e";
|
||||
@server: "\f097";
|
||||
@settings: "\f07c";
|
||||
@sign-in: "\f036";
|
||||
@sign-out: "\f032";
|
||||
@split: "\f0c6";
|
||||
@squirrel: "\f0b2";
|
||||
@star: "\f02a";
|
||||
@star-add: "\f082";
|
||||
@star-delete: "\f083";
|
||||
@star-add: "\f02a";
|
||||
@star-delete: "\f02a";
|
||||
@steps: "\f0c7";
|
||||
@stop: "\f08f";
|
||||
@sync: "\f087";
|
||||
@tag: "\f015";
|
||||
@tag-add: "\f054";
|
||||
@tag-remove: "\f055";
|
||||
@tag-add: "\f015";
|
||||
@tag-remove: "\f015";
|
||||
@telescope: "\f088";
|
||||
@terminal: "\f0c8";
|
||||
@three-bars: "\f05e";
|
||||
@@ -203,10 +197,8 @@
|
||||
@triangle-left: "\f044";
|
||||
@triangle-right: "\f05a";
|
||||
@triangle-up: "\f0aa";
|
||||
@trollface: "\f029";
|
||||
@unfold: "\f039";
|
||||
@unmute: "\f0ba";
|
||||
@unmute-video: "\f0b9";
|
||||
@versions: "\f064";
|
||||
@x: "\f081";
|
||||
@zap: "\26A1";
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário