Comparar commits
193 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 8f9f422406 | |||
| 211a1c75e2 | |||
| fd3cb1a232 | |||
| f205fe81ce | |||
| c74b1b971d | |||
| 54af7eced1 | |||
| 10f7a671c8 | |||
| 51475fe231 | |||
| 33a5ca30dc | |||
| df1ae64f62 | |||
| 83710ed254 | |||
| 8cb8f09803 | |||
| ff0a7be48a | |||
| 5e6e3c8d72 | |||
| dfc502b9a0 | |||
| a8d93f9cf4 | |||
| 50cf5f3e95 | |||
| 5a9b34b31a | |||
| 3efaeff669 | |||
| 443df29236 | |||
| 05b3f16eb2 | |||
| b54deccfae | |||
| 9808264b7f | |||
| f3ed3dc357 | |||
| 33b25c7312 | |||
| 454f9c4c65 | |||
| 1b506673bb | |||
| 5651ebbb48 | |||
| a7185a894f | |||
| 16c7fd3d70 | |||
| 98290b31ab | |||
| 08b138997d | |||
| 1f7aee00ac | |||
| 3977596084 | |||
| 804d0d9911 | |||
| 04d045227a | |||
| 4e1d13ceea | |||
| ef19e925e9 | |||
| 2c1fa19e27 | |||
| 11fad1bd12 | |||
| 1408d69641 | |||
| 38d2303857 | |||
| 96207ffbdb | |||
| fcf2143e70 | |||
| 3a8f842de3 | |||
| 452e34db90 | |||
| 8b39ce77b1 | |||
| 604158647a | |||
| 22fb5adda9 | |||
| e607d45f0d | |||
| 94d470002b | |||
| 33d4ace8e9 | |||
| 800dee09ba | |||
| 6b4ce902ba | |||
| c6f7c75c8a | |||
| cb1f8e02aa | |||
| 885a19492c | |||
| 8f738aae53 | |||
| f09e58b434 | |||
| 98e828b337 | |||
| 03a9a67ba8 | |||
| beb96cc025 | |||
| ae76bd6c96 | |||
| 694dd05e7b | |||
| 662fc443dc | |||
| 0fc773c1fc | |||
| aa5b0ce41f | |||
| 832b4ae4d8 | |||
| af1bdaf901 | |||
| 969ca048e8 | |||
| 0d2fdec326 | |||
| f57dbfd9f5 | |||
| fc3ba775c8 | |||
| 9b07158337 | |||
| 0bb8821644 | |||
| 5fdf3f894c | |||
| 5bf09716ef | |||
| 9fff544955 | |||
| 6a29630c82 | |||
| 74ba3c6a49 | |||
| 601c603bbe | |||
| 9fbbd1e59b | |||
| ba4df1b002 | |||
| 2c1190b552 | |||
| 9ff976021e | |||
| 5e9a269278 | |||
| 18e0adbfa8 | |||
| f7f28e7995 | |||
| ac67430926 | |||
| 409b5536e1 | |||
| 2526ba0efb | |||
| 1a8c5ba551 | |||
| f909d32826 | |||
| d0bb49dea0 | |||
| 02e87555f4 | |||
| a84dd69f55 | |||
| a79c015774 | |||
| 9e46ab1b48 | |||
| 69f24a157a | |||
| ea75636e44 | |||
| e7ad9ae15a | |||
| 0499ee65a4 | |||
| c56babec8d | |||
| f6f891fa14 | |||
| 2f93032a37 | |||
| c058b44a1b | |||
| 81a7f65832 | |||
| bbeb0b5919 | |||
| 60d34576d5 | |||
| 1539a90ee7 | |||
| b958286d22 | |||
| 6ce13a9c3e | |||
| d1ba8b0140 | |||
| f4b23b801d | |||
| 14c8c463fb | |||
| b5fc4aec84 | |||
| 1f2fc4bf00 | |||
| 3601d113ad | |||
| 6a81f3c6ce | |||
| 00baedbdf9 | |||
| 2c3bec7468 | |||
| 409816ef07 | |||
| 8871d45227 | |||
| c5fa8fdf11 | |||
| e060e08f93 | |||
| 039afff1de | |||
| d33bd291dd | |||
| b422c7a678 | |||
| 55d243215a | |||
| 0bc2b45200 | |||
| 683d0d1b16 | |||
| 82c53b539a | |||
| c2f44efe31 | |||
| b3038eb968 | |||
| 3694111211 | |||
| bf2d307cbe | |||
| 38016b205c | |||
| b4dcd019c1 | |||
| 13a5bfd1dd | |||
| 9e0c4d1fb6 | |||
| cabcf19297 | |||
| 9aa7331e6e | |||
| 3daf505f3e | |||
| cd92f882bf | |||
| 707ac0b043 | |||
| 4a812707d8 | |||
| f2ef7beae6 | |||
| c64a4dd70f | |||
| 3ab0b16923 | |||
| fac72fbf10 | |||
| 7d71eeedf4 | |||
| 6d55bab4c8 | |||
| d506ccbaad | |||
| 8275ddd882 | |||
| b7765d9416 | |||
| 47f8f7eb11 | |||
| 63181a17c8 | |||
| c71457e9d4 | |||
| 7d31b17273 | |||
| 066f6bf03c | |||
| 40f8b990d0 | |||
| a492596f7f | |||
| 2df5957f9b | |||
| a7196ec906 | |||
| c094b7a0ef | |||
| 09b5ac887a | |||
| 67ff8f4382 | |||
| 0c9fd46030 | |||
| cf4a7c22ee | |||
| 30f04360dd | |||
| 02d34b3ba9 | |||
| 69217b2d8f | |||
| 1dc5593380 | |||
| 42e0f83259 | |||
| 428532cd24 | |||
| 7581832658 | |||
| c61c07f07d | |||
| abe7dde205 | |||
| 4bc49b82ef | |||
| de1fd977e0 | |||
| afce21f37d | |||
| 5230d040eb | |||
| 1080eb2d11 | |||
| 246575390a | |||
| bc6c85ceca | |||
| a0b405fe6f | |||
| 54b89cebcc | |||
| 7b9b044394 | |||
| 23cb0eda2f | |||
| a354d9f880 | |||
| 7526038f9a | |||
| c0973f8c0f | |||
| dededd80dd |
@@ -234,8 +234,9 @@ module.exports = (grunt) ->
|
||||
ciTasks.push('dump-symbols') if process.platform isnt 'win32'
|
||||
ciTasks.push('set-version', 'check-licenses', 'lint')
|
||||
ciTasks.push('mkdeb') if process.platform is 'linux'
|
||||
ciTasks.push('test') if process.platform isnt 'linux'
|
||||
ciTasks.push('codesign', 'publish-build')
|
||||
ciTasks.push('test') if process.platform is 'darwin'
|
||||
ciTasks.push('codesign')
|
||||
ciTasks.push('publish-build')
|
||||
grunt.registerTask('ci', ciTasks)
|
||||
|
||||
defaultTasks = ['download-atom-shell', 'build', 'set-version']
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
"dependencies": {
|
||||
"async": "~0.2.9",
|
||||
"donna": "1.0.1",
|
||||
"tello": "1.0.3",
|
||||
"formidable": "~1.0.14",
|
||||
"fs-plus": "2.x",
|
||||
"github-releases": "~0.2.0",
|
||||
@@ -35,6 +34,8 @@
|
||||
"request": "~2.27.0",
|
||||
"rimraf": "~2.2.2",
|
||||
"runas": "~1.0.1",
|
||||
"tello": "1.0.3",
|
||||
"temp": "~0.8.1",
|
||||
"underscore-plus": "1.x",
|
||||
"unzip": "~0.1.9",
|
||||
"vm-compatibility-layer": "~0.1.0"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
path = require 'path'
|
||||
fs = require 'fs-plus'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
{spawn} = require('./task-helpers')(grunt)
|
||||
@@ -25,12 +26,21 @@ module.exports = (grunt) ->
|
||||
switch process.platform
|
||||
when 'darwin'
|
||||
cmd = 'codesign'
|
||||
args = ['-f', '-v', '-s', 'Developer ID Application: GitHub', grunt.config.get('atom.shellAppDir')]
|
||||
args = ['--deep', '--force', '--verbose', '--sign', 'Developer ID Application: GitHub', grunt.config.get('atom.shellAppDir')]
|
||||
spawn {cmd, args}, (error) -> callback(error)
|
||||
when 'win32'
|
||||
spawn {cmd: 'taskkill', args: ['/F', '/IM', 'atom.exe']}, ->
|
||||
cmd = process.env.JANKY_SIGNTOOL ? 'signtool'
|
||||
args = [path.join(grunt.config.get('atom.shellAppDir'), 'atom.exe')]
|
||||
spawn {cmd, args}, (error) -> callback(error)
|
||||
|
||||
spawn {cmd, args}, (error) ->
|
||||
return callback(error) if error?
|
||||
|
||||
setupExePath = path.join(grunt.config.get('atom.shellAppDir'), '..', 'Releases', 'setup.exe')
|
||||
if fs.isFileSync(setupExePath)
|
||||
args = [setupExePath]
|
||||
spawn {cmd, args}, (error) -> callback(error)
|
||||
else
|
||||
callback()
|
||||
else
|
||||
callback()
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
{spawn, rm} = require('./task-helpers')(grunt)
|
||||
|
||||
grunt.registerTask 'create-installer', 'Create the Windows installer', ->
|
||||
return unless process.platform is 'win32'
|
||||
|
||||
done = @async()
|
||||
|
||||
buildDir = grunt.config.get('atom.buildDir')
|
||||
atomDir = path.join(buildDir, 'Atom')
|
||||
|
||||
packageInfo = grunt.file.readJSON(path.join(atomDir, 'resources', 'app', 'package.json'))
|
||||
inputTemplate = grunt.file.read(path.join('build', 'windows', 'atom.nuspec.erb'))
|
||||
|
||||
# NB: Build server has some sort of stamp on the version number
|
||||
packageInfo.version = packageInfo.version.replace(/-.*$/, '')
|
||||
|
||||
targetNuspecPath = path.join(buildDir, 'atom.nuspec')
|
||||
grunt.file.write(targetNuspecPath, _.template(inputTemplate, packageInfo))
|
||||
|
||||
cmd = 'build/windows/nuget.exe'
|
||||
args = ['pack', targetNuspecPath, '-BasePath', atomDir, '-OutputDirectory', buildDir]
|
||||
|
||||
spawn {cmd, args}, (error, result, code) ->
|
||||
return done(error) if error?
|
||||
|
||||
pkgs = pkg for pkg in fs.readdirSync(buildDir) when path.extname(pkg) is '.nupkg'
|
||||
|
||||
releasesDir = path.join(buildDir, 'Releases')
|
||||
|
||||
# NB: Gonna clear Releases for now, in the future we need to pull down
|
||||
# the existing version
|
||||
rm(releasesDir)
|
||||
|
||||
cmd = 'build/windows/update.com'
|
||||
args = ['--releasify', path.join(buildDir, pkgs), '-r', releasesDir, '-g', 'build/windows/install-spinner.gif']
|
||||
spawn {cmd, args}, (error, result, code) -> done(error)
|
||||
@@ -3,6 +3,7 @@ path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
runas = null
|
||||
temp = require 'temp'
|
||||
|
||||
module.exports = (grunt) ->
|
||||
{cp, mkdir, rm} = require('./task-helpers')(grunt)
|
||||
@@ -22,7 +23,11 @@ module.exports = (grunt) ->
|
||||
else if process.platform is 'darwin'
|
||||
rm installDir
|
||||
mkdir path.dirname(installDir)
|
||||
cp shellAppDir, installDir
|
||||
|
||||
tempFolder = temp.path()
|
||||
mkdir tempFolder
|
||||
cp shellAppDir, tempFolder
|
||||
fs.renameSync(tempFolder, installDir)
|
||||
else
|
||||
binDir = path.join(installDir, 'bin')
|
||||
shareDir = path.join(installDir, 'share', 'atom')
|
||||
|
||||
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id><%= name %></id>
|
||||
<version><%= version %></version>
|
||||
<authors>The Atom Community</authors>
|
||||
<owners>The Atom Community</owners>
|
||||
<iconUrl>https://raw.githubusercontent.com/atom/atom/master/resources/win/atom.ico</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description><%= description %></description>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="locales\**" target="lib\net45\locales" />
|
||||
<file src="resources\**" target="lib\net45\resources" />
|
||||
<file src="*.pak" target="lib\net45" />
|
||||
|
||||
<file src="atom.exe" target="lib\net45\atom.exe" />
|
||||
<file src="atom.exe.gui" target="lib\net45\atom.exe.gui" />
|
||||
<file src="chromiumcontent.dll" target="lib\net45\chromiumcontent.dll" />
|
||||
<file src="d3dcompiler_43.dll" target="lib\net45\d3dcompiler_43.dll" />
|
||||
<file src="ffmpegsumo.dll" target="lib\net45\ffmpegsumo.dll" />
|
||||
<file src="icudtl.dat" target="lib\net45\icudtl.dat" />
|
||||
<file src="libEGL.dll" target="lib\net45\libEGL.dll" />
|
||||
<file src="libGLESv2.dll" target="lib\net45\libGLESv2.dll" />
|
||||
<file src="LICENSE" target="lib\net45\LICENSE" />
|
||||
<file src="msvcp120.dll" target="lib\net45\msvcp120.dll" />
|
||||
<file src="msvcr120.dll" target="lib\net45\msvcr120.dll" />
|
||||
<file src="vccorlib120.dll" target="lib\net45\vccorlib120.dll" />
|
||||
<file src="version" target="lib\net45\version" />
|
||||
<file src="xinput1_3.dll" target="lib\net45\xinput1_3.dll" />
|
||||
</files>
|
||||
</package>
|
||||
Arquivo binário não exibido.
|
Depois Largura: | Altura: | Tamanho: 43 KiB |
@@ -48,15 +48,6 @@ but you can programmatically write to it with `atom.config.set`:
|
||||
atom.config.set("core.showInvisibles", true)
|
||||
```
|
||||
|
||||
You should never mutate the value of a config key, because that would circumvent
|
||||
the notification of observers. You can however use methods like `pushAtKeyPath`,
|
||||
`unshiftAtKeyPath`, and `removeAtKeyPath` to manipulate mutable config values.
|
||||
|
||||
```coffeescript
|
||||
atom.config.pushAtKeyPath("core.disabledPackages", "wrap-guide")
|
||||
atom.config.removeAtKeyPath("core.disabledPackages", "terminal")
|
||||
```
|
||||
|
||||
You can also use `setDefaults`, which will assign default values for keys that
|
||||
are always overridden by values assigned with `set`. Defaults are not written
|
||||
out to the the `config.json` file to prevent it from becoming cluttered.
|
||||
|
||||
@@ -321,6 +321,29 @@ extensions your grammar supports:
|
||||
]
|
||||
```
|
||||
|
||||
## Adding Configuration Settings
|
||||
|
||||
You can support config settings in your package that are editable in the
|
||||
settings view. Specify a `config` key in your package main:
|
||||
|
||||
```coffeescript
|
||||
module.exports =
|
||||
# Your config schema!
|
||||
config:
|
||||
someInt:
|
||||
type: 'integer'
|
||||
default: 23
|
||||
minimum: 1
|
||||
activate: (state) -> # ...
|
||||
# ...
|
||||
```
|
||||
|
||||
To define the configuration, we use [json schema][json-schema] which allows you
|
||||
to indicate the type your value should be, its default, etc.
|
||||
|
||||
See the [Config API Docs](https://atom.io/docs/api/latest/Config) for more
|
||||
details specifying your configuration.
|
||||
|
||||
## Bundle External Resources
|
||||
|
||||
It's common to ship external resources like images and fonts in the package, to
|
||||
@@ -392,3 +415,4 @@ all the other available commands.
|
||||
[first-package]: your-first-package.html
|
||||
[convert-bundle]: converting-a-text-mate-bundle.html
|
||||
[convert-theme]: converting-a-text-mate-theme.html
|
||||
[json-schema]: http://json-schema.org/
|
||||
|
||||
@@ -8,10 +8,6 @@ module.exports =
|
||||
Point: Point
|
||||
Range: Range
|
||||
|
||||
Object.defineProperty module.exports, 'Git', get: ->
|
||||
deprecate "Please require `GitRepository` instead of `Git`: `{GitRepository} = require 'atom'`"
|
||||
module.exports.GitRepository
|
||||
|
||||
# The following classes can't be used from a Task handler and should therefore
|
||||
# only be exported when not running as a child node process
|
||||
unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
@@ -20,7 +16,7 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
module.exports.$ = $
|
||||
module.exports.$$ = $$
|
||||
module.exports.$$$ = $$$
|
||||
module.exports.EditorView = require '../src/editor-view'
|
||||
module.exports.TextEditorView = require '../src/text-editor-view'
|
||||
module.exports.ScrollView = require '../src/scroll-view'
|
||||
module.exports.SelectListView = require '../src/select-list-view'
|
||||
module.exports.Task = require '../src/task'
|
||||
@@ -29,3 +25,11 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
module.exports.Workspace = require '../src/workspace'
|
||||
module.exports.React = require 'react-atom-fork'
|
||||
module.exports.Reactionary = require 'reactionary-atom-fork'
|
||||
|
||||
Object.defineProperty module.exports, 'Git', get: ->
|
||||
deprecate "Please require `GitRepository` instead of `Git`: `{GitRepository} = require 'atom'`"
|
||||
module.exports.GitRepository
|
||||
|
||||
Object.defineProperty module.exports, 'EditorView', get: ->
|
||||
deprecate "Please require `TextEditorView` instead of `EditorView`: `{TextEditorView} = require 'atom'`"
|
||||
module.exports.TextEditorView
|
||||
|
||||
@@ -199,8 +199,15 @@
|
||||
'.overlayer':
|
||||
'Undo': 'core:undo'
|
||||
'Redo': 'core:redo'
|
||||
'separator1': '-'
|
||||
'Cut': 'core:cut'
|
||||
'Copy': 'core:copy'
|
||||
'Paste': 'core:paste'
|
||||
'Delete': 'core:delete'
|
||||
'Select All': 'core:select-all'
|
||||
'separator2': '-'
|
||||
'Split Up': 'pane:split-up'
|
||||
'Split Down': 'pane:split-down'
|
||||
'Split Left': 'pane:split-left'
|
||||
'Split Right': 'pane:split-right'
|
||||
'separator3': '-'
|
||||
|
||||
@@ -156,8 +156,15 @@
|
||||
'.overlayer':
|
||||
'Undo': 'core:undo'
|
||||
'Redo': 'core:redo'
|
||||
'separator1': '-'
|
||||
'Cut': 'core:cut'
|
||||
'Copy': 'core:copy'
|
||||
'Paste': 'core:paste'
|
||||
'Delete': 'core:delete'
|
||||
'Select All': 'core:select-all'
|
||||
'separator2': '-'
|
||||
'Split Up': 'pane:split-up'
|
||||
'Split Down': 'pane:split-down'
|
||||
'Split Left': 'pane:split-left'
|
||||
'Split Right': 'pane:split-right'
|
||||
'separator3': '-'
|
||||
|
||||
+9
-2
@@ -33,8 +33,8 @@
|
||||
{ label: '&Undo', command: 'core:undo' }
|
||||
{ label: '&Redo', command: 'core:redo' }
|
||||
{ type: 'separator' }
|
||||
{ label: '&Cut', command: 'core:cut' }
|
||||
{ label: 'C&opy', command: 'core:copy' }
|
||||
{ label: 'Cu&t', command: 'core:cut' }
|
||||
{ label: '&Copy', command: 'core:copy' }
|
||||
{ label: 'Copy Pat&h', command: 'editor:copy-path' }
|
||||
{ label: '&Paste', command: 'core:paste' }
|
||||
{ label: 'Select &All', command: 'core:select-all' }
|
||||
@@ -174,8 +174,15 @@
|
||||
'.overlayer':
|
||||
'Undo': 'core:undo'
|
||||
'Redo': 'core:redo'
|
||||
'separator1': '-'
|
||||
'Cut': 'core:cut'
|
||||
'Copy': 'core:copy'
|
||||
'Paste': 'core:paste'
|
||||
'Delete': 'core:delete'
|
||||
'Select All': 'core:select-all'
|
||||
'separator2': '-'
|
||||
'Split Up': 'pane:split-up'
|
||||
'Split Down': 'pane:split-down'
|
||||
'Split Left': 'pane:split-left'
|
||||
'Split Right': 'pane:split-right'
|
||||
'separator3': '-'
|
||||
|
||||
+12
-12
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "atom",
|
||||
"productName": "Atom",
|
||||
"version": "0.131.0",
|
||||
"version": "0.133.0",
|
||||
"description": "A hackable text editor for the 21st Century.",
|
||||
"main": "./src/browser/main.js",
|
||||
"repository": {
|
||||
@@ -20,7 +20,7 @@
|
||||
"atomShellVersion": "0.16.2",
|
||||
"dependencies": {
|
||||
"async": "0.2.6",
|
||||
"atom-keymap": "^2.1.3",
|
||||
"atom-keymap": "^2.2.0",
|
||||
"bootstrap": "git+https://github.com/atom/bootstrap.git#6af81906189f1747fd6c93479e3d998ebe041372",
|
||||
"clear-cut": "0.4.0",
|
||||
"coffee-script": "1.7.0",
|
||||
@@ -28,7 +28,7 @@
|
||||
"delegato": "^1",
|
||||
"emissary": "^1.3.1",
|
||||
"event-kit": "0.7.2",
|
||||
"first-mate": "^2.1.2",
|
||||
"first-mate": "^2.2.0",
|
||||
"fs-plus": "^2.2.6",
|
||||
"fstream": "0.1.24",
|
||||
"fuzzaldrin": "^2.1",
|
||||
@@ -77,13 +77,13 @@
|
||||
"autosave": "0.17.0",
|
||||
"background-tips": "0.17.0",
|
||||
"bookmarks": "0.28.0",
|
||||
"bracket-matcher": "0.59.0",
|
||||
"command-palette": "0.25.0",
|
||||
"bracket-matcher": "0.61.0",
|
||||
"command-palette": "0.26.0",
|
||||
"deprecation-cop": "0.10.0",
|
||||
"dev-live-reload": "0.34.0",
|
||||
"exception-reporting": "0.20.0",
|
||||
"feedback": "0.33.0",
|
||||
"find-and-replace": "0.138.0",
|
||||
"find-and-replace": "0.139.0",
|
||||
"fuzzy-finder": "0.58.0",
|
||||
"git-diff": "0.39.0",
|
||||
"go-to-line": "0.25.0",
|
||||
@@ -93,25 +93,25 @@
|
||||
"keybinding-resolver": "0.20.0",
|
||||
"link": "0.25.0",
|
||||
"markdown-preview": "0.103.0",
|
||||
"metrics": "0.34.0",
|
||||
"metrics": "0.36.0",
|
||||
"open-on-github": "0.30.0",
|
||||
"package-generator": "0.31.0",
|
||||
"release-notes": "0.36.0",
|
||||
"settings-view": "0.145.0",
|
||||
"settings-view": "0.148.0",
|
||||
"snippets": "0.53.0",
|
||||
"spell-check": "0.42.0",
|
||||
"status-bar": "0.45.0",
|
||||
"styleguide": "0.30.0",
|
||||
"symbols-view": "0.66.0",
|
||||
"tabs": "0.52.0",
|
||||
"tabs": "0.54.0",
|
||||
"timecop": "0.22.0",
|
||||
"tree-view": "0.126.0",
|
||||
"tree-view": "0.127.0",
|
||||
"update-package-dependencies": "0.6.0",
|
||||
"welcome": "0.18.0",
|
||||
"whitespace": "0.25.0",
|
||||
"wrap-guide": "0.22.0",
|
||||
"language-c": "0.28.0",
|
||||
"language-coffee-script": "0.34.0",
|
||||
"language-coffee-script": "0.35.0",
|
||||
"language-css": "0.17.0",
|
||||
"language-gfm": "0.50.0",
|
||||
"language-git": "0.9.0",
|
||||
@@ -131,7 +131,7 @@
|
||||
"language-python": "0.19.0",
|
||||
"language-ruby": "0.38.0",
|
||||
"language-ruby-on-rails": "0.18.0",
|
||||
"language-sass": "0.21.0",
|
||||
"language-sass": "0.22.0",
|
||||
"language-shellscript": "0.8.0",
|
||||
"language-source": "0.8.0",
|
||||
"language-sql": "0.11.0",
|
||||
|
||||
@@ -76,6 +76,9 @@ class AtomReporter extends View
|
||||
@addSpecs(specs)
|
||||
$(document.body).append this
|
||||
|
||||
@on 'click', '.stack-trace', ->
|
||||
$(this).toggleClass('expanded')
|
||||
|
||||
reportRunnerResults: (runner) ->
|
||||
@updateSpecCounts()
|
||||
@status.addClass('alert-success').removeClass('alert-info') if @failedCount is 0
|
||||
|
||||
+5
-535
@@ -25,541 +25,6 @@ describe "the `atom` global", ->
|
||||
atom.setSize(100, 400)
|
||||
expect(atom.getSize()).toEqual width: 100, height: 400
|
||||
|
||||
describe "package lifecycle methods", ->
|
||||
describe ".loadPackage(name)", ->
|
||||
it "continues if the package has an invalid package.json", ->
|
||||
spyOn(console, 'warn')
|
||||
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", ->
|
||||
atom.config.set("core.disabledPackages", [])
|
||||
expect(-> atom.packages.loadPackage("package-with-broken-keymap")).not.toThrow()
|
||||
|
||||
describe ".unloadPackage(name)", ->
|
||||
describe "when the package is active", ->
|
||||
it "throws an error", ->
|
||||
pack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-main').then (p) -> pack = p
|
||||
|
||||
runs ->
|
||||
expect(atom.packages.isPackageLoaded(pack.name)).toBeTruthy()
|
||||
expect(atom.packages.isPackageActive(pack.name)).toBeTruthy()
|
||||
expect( -> atom.packages.unloadPackage(pack.name)).toThrow()
|
||||
expect(atom.packages.isPackageLoaded(pack.name)).toBeTruthy()
|
||||
expect(atom.packages.isPackageActive(pack.name)).toBeTruthy()
|
||||
|
||||
describe "when the package is not loaded", ->
|
||||
it "throws an error", ->
|
||||
expect(atom.packages.isPackageLoaded('unloaded')).toBeFalsy()
|
||||
expect( -> atom.packages.unloadPackage('unloaded')).toThrow()
|
||||
expect(atom.packages.isPackageLoaded('unloaded')).toBeFalsy()
|
||||
|
||||
describe "when the package is loaded", ->
|
||||
it "no longers reports it as being loaded", ->
|
||||
pack = atom.packages.loadPackage('package-with-main')
|
||||
expect(atom.packages.isPackageLoaded(pack.name)).toBeTruthy()
|
||||
atom.packages.unloadPackage(pack.name)
|
||||
expect(atom.packages.isPackageLoaded(pack.name)).toBeFalsy()
|
||||
|
||||
describe ".activatePackage(id)", ->
|
||||
describe "atom packages", ->
|
||||
describe "when called multiple times", ->
|
||||
it "it only calls activate on the package once", ->
|
||||
spyOn(Package.prototype, 'activateNow').andCallThrough()
|
||||
atom.packages.activatePackage('package-with-index')
|
||||
atom.packages.activatePackage('package-with-index')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-index')
|
||||
|
||||
runs ->
|
||||
expect(Package.prototype.activateNow.callCount).toBe 1
|
||||
|
||||
describe "when the package has a main module", ->
|
||||
describe "when the metadata specifies a main module path˜", ->
|
||||
it "requires the module at the specified path", ->
|
||||
mainModule = require('./fixtures/packages/package-with-main/main-module')
|
||||
spyOn(mainModule, 'activate')
|
||||
pack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-main').then (p) -> pack = p
|
||||
|
||||
runs ->
|
||||
expect(mainModule.activate).toHaveBeenCalled()
|
||||
expect(pack.mainModule).toBe mainModule
|
||||
|
||||
describe "when the metadata does not specify a main module", ->
|
||||
it "requires index.coffee", ->
|
||||
indexModule = require('./fixtures/packages/package-with-index/index')
|
||||
spyOn(indexModule, 'activate')
|
||||
pack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-index').then (p) -> pack = p
|
||||
|
||||
runs ->
|
||||
expect(indexModule.activate).toHaveBeenCalled()
|
||||
expect(pack.mainModule).toBe indexModule
|
||||
|
||||
it "assigns config defaults from the module", ->
|
||||
expect(atom.config.get('package-with-config-defaults.numbers.one')).toBeUndefined()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-config-defaults')
|
||||
|
||||
runs ->
|
||||
expect(atom.config.get('package-with-config-defaults.numbers.one')).toBe 1
|
||||
expect(atom.config.get('package-with-config-defaults.numbers.two')).toBe 2
|
||||
|
||||
describe "when the package metadata includes activation events", ->
|
||||
[mainModule, promise] = []
|
||||
|
||||
beforeEach ->
|
||||
mainModule = require './fixtures/packages/package-with-activation-events/index'
|
||||
spyOn(mainModule, 'activate').andCallThrough()
|
||||
spyOn(Package.prototype, 'requireMainModule').andCallThrough()
|
||||
|
||||
promise = atom.packages.activatePackage('package-with-activation-events')
|
||||
|
||||
it "defers requiring/activating the main module until an activation event bubbles to the root view", ->
|
||||
expect(promise.isFulfilled()).not.toBeTruthy()
|
||||
atom.workspaceView.trigger 'activation-event'
|
||||
|
||||
waitsForPromise ->
|
||||
promise
|
||||
|
||||
it "triggers the activation event on all handlers registered during activation", ->
|
||||
waitsForPromise ->
|
||||
atom.workspaceView.open()
|
||||
|
||||
runs ->
|
||||
editorView = atom.workspaceView.getActiveView()
|
||||
eventHandler = jasmine.createSpy("activation-event")
|
||||
editorView.command 'activation-event', eventHandler
|
||||
editorView.trigger 'activation-event'
|
||||
expect(mainModule.activate.callCount).toBe 1
|
||||
expect(mainModule.activationEventCallCount).toBe 1
|
||||
expect(eventHandler.callCount).toBe 1
|
||||
editorView.trigger 'activation-event'
|
||||
expect(mainModule.activationEventCallCount).toBe 2
|
||||
expect(eventHandler.callCount).toBe 2
|
||||
expect(mainModule.activate.callCount).toBe 1
|
||||
|
||||
it "activates the package immediately when the events are empty", ->
|
||||
mainModule = require './fixtures/packages/package-with-empty-activation-events/index'
|
||||
spyOn(mainModule, 'activate').andCallThrough()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-empty-activation-events')
|
||||
|
||||
runs ->
|
||||
expect(mainModule.activate.callCount).toBe 1
|
||||
|
||||
describe "when the package has no main module", ->
|
||||
it "does not throw an exception", ->
|
||||
spyOn(console, "error")
|
||||
spyOn(console, "warn").andCallThrough()
|
||||
expect(-> atom.packages.activatePackage('package-without-module')).not.toThrow()
|
||||
expect(console.error).not.toHaveBeenCalled()
|
||||
expect(console.warn).not.toHaveBeenCalled()
|
||||
|
||||
it "passes the activate method the package's previously serialized state if it exists", ->
|
||||
pack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-serialization").then (p) -> pack = p
|
||||
|
||||
runs ->
|
||||
expect(pack.mainModule.someNumber).not.toBe 77
|
||||
pack.mainModule.someNumber = 77
|
||||
atom.packages.deactivatePackage("package-with-serialization")
|
||||
spyOn(pack.mainModule, 'activate').andCallThrough()
|
||||
atom.packages.activatePackage("package-with-serialization")
|
||||
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 "keymap loading", ->
|
||||
describe "when the metadata does not contain a 'keymaps' manifest", ->
|
||||
it "loads all the .cson/.json files in the keymaps directory", ->
|
||||
element1 = $$ -> @div class: 'test-1'
|
||||
element2 = $$ -> @div class: 'test-2'
|
||||
element3 = $$ -> @div class: 'test-3'
|
||||
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element2[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element3[0])).toHaveLength 0
|
||||
|
||||
atom.packages.activatePackage("package-with-keymaps")
|
||||
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])[0].command).toBe "test-1"
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element2[0])[0].command).toBe "test-2"
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element3[0])).toHaveLength 0
|
||||
|
||||
describe "when the metadata contains a 'keymaps' manifest", ->
|
||||
it "loads only the keymaps specified by the manifest, in the specified order", ->
|
||||
element1 = $$ -> @div class: 'test-1'
|
||||
element3 = $$ -> @div class: 'test-3'
|
||||
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])).toHaveLength 0
|
||||
|
||||
atom.packages.activatePackage("package-with-keymaps-manifest")
|
||||
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])[0].command).toBe 'keymap-1'
|
||||
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 "menu loading", ->
|
||||
beforeEach ->
|
||||
atom.contextMenu.definitions = []
|
||||
atom.menu.template = []
|
||||
|
||||
describe "when the metadata does not contain a 'menus' manifest", ->
|
||||
it "loads all the .cson/.json files in the menus directory", ->
|
||||
element = ($$ -> @div class: 'test-1')[0]
|
||||
|
||||
expect(atom.contextMenu.definitionsForElement(element)).toEqual []
|
||||
|
||||
atom.packages.activatePackage("package-with-menus")
|
||||
|
||||
expect(atom.menu.template.length).toBe 2
|
||||
expect(atom.menu.template[0].label).toBe "Second to Last"
|
||||
expect(atom.menu.template[1].label).toBe "Last"
|
||||
expect(atom.contextMenu.definitionsForElement(element)[0].label).toBe "Menu item 1"
|
||||
expect(atom.contextMenu.definitionsForElement(element)[1].label).toBe "Menu item 2"
|
||||
expect(atom.contextMenu.definitionsForElement(element)[2].label).toBe "Menu item 3"
|
||||
|
||||
describe "when the metadata contains a 'menus' manifest", ->
|
||||
it "loads only the menus specified by the manifest, in the specified order", ->
|
||||
element = ($$ -> @div class: 'test-1')[0]
|
||||
|
||||
expect(atom.contextMenu.definitionsForElement(element)).toEqual []
|
||||
|
||||
atom.packages.activatePackage("package-with-menus-manifest")
|
||||
|
||||
expect(atom.menu.template[0].label).toBe "Second to Last"
|
||||
expect(atom.menu.template[1].label).toBe "Last"
|
||||
expect(atom.contextMenu.definitionsForElement(element)[0].label).toBe "Menu item 2"
|
||||
expect(atom.contextMenu.definitionsForElement(element)[1].label).toBe "Menu item 1"
|
||||
expect(atom.contextMenu.definitionsForElement(element)[2]).toBeUndefined()
|
||||
|
||||
describe "stylesheet loading", ->
|
||||
describe "when the metadata contains a 'stylesheets' manifest", ->
|
||||
it "loads stylesheets from the stylesheets directory as specified by the manifest", ->
|
||||
one = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/1.css")
|
||||
two = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/2.less")
|
||||
three = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/3.css")
|
||||
|
||||
one = atom.themes.stringToId(one)
|
||||
two = atom.themes.stringToId(two)
|
||||
three = atom.themes.stringToId(three)
|
||||
|
||||
expect(atom.themes.stylesheetElementForId(one)).toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(two)).toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(three)).toBeNull()
|
||||
|
||||
atom.packages.activatePackage("package-with-stylesheets-manifest")
|
||||
|
||||
expect(atom.themes.stylesheetElementForId(one)).not.toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(two)).not.toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(three)).toBeNull()
|
||||
expect($('#jasmine-content').css('font-size')).toBe '1px'
|
||||
|
||||
describe "when the metadata does not contain a 'stylesheets' manifest", ->
|
||||
it "loads all stylesheets from the stylesheets directory", ->
|
||||
one = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/1.css")
|
||||
two = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/2.less")
|
||||
three = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/3.css")
|
||||
|
||||
|
||||
one = atom.themes.stringToId(one)
|
||||
two = atom.themes.stringToId(two)
|
||||
three = atom.themes.stringToId(three)
|
||||
|
||||
expect(atom.themes.stylesheetElementForId(one)).toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(two)).toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(three)).toBeNull()
|
||||
|
||||
atom.packages.activatePackage("package-with-stylesheets")
|
||||
expect(atom.themes.stylesheetElementForId(one)).not.toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(two)).not.toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(three)).not.toBeNull()
|
||||
expect($('#jasmine-content').css('font-size')).toBe '3px'
|
||||
|
||||
describe "grammar loading", ->
|
||||
it "loads the package's grammars", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-grammars')
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.selectGrammar('a.alot').name).toBe 'Alot'
|
||||
expect(atom.syntax.selectGrammar('a.alittle').name).toBe 'Alittle'
|
||||
|
||||
describe "scoped-property loading", ->
|
||||
it "loads the scoped properties", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-scoped-properties")
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
|
||||
|
||||
describe "converted textmate packages", ->
|
||||
it "loads the package's grammars", ->
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Ruby"
|
||||
|
||||
it "loads the translated scoped properties", ->
|
||||
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBe '# '
|
||||
|
||||
describe ".deactivatePackage(id)", ->
|
||||
describe "atom packages", ->
|
||||
it "calls `deactivate` on the package's main module if activate was successful", ->
|
||||
pack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-deactivate").then (p) -> pack = p
|
||||
|
||||
runs ->
|
||||
expect(atom.packages.isPackageActive("package-with-deactivate")).toBeTruthy()
|
||||
spyOn(pack.mainModule, 'deactivate').andCallThrough()
|
||||
|
||||
atom.packages.deactivatePackage("package-with-deactivate")
|
||||
expect(pack.mainModule.deactivate).toHaveBeenCalled()
|
||||
expect(atom.packages.isPackageActive("package-with-module")).toBeFalsy()
|
||||
|
||||
spyOn(console, 'warn')
|
||||
|
||||
badPack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-that-throws-on-activate").then (p) -> badPack = p
|
||||
|
||||
runs ->
|
||||
expect(atom.packages.isPackageActive("package-that-throws-on-activate")).toBeTruthy()
|
||||
spyOn(badPack.mainModule, 'deactivate').andCallThrough()
|
||||
|
||||
atom.packages.deactivatePackage("package-that-throws-on-activate")
|
||||
expect(badPack.mainModule.deactivate).not.toHaveBeenCalled()
|
||||
expect(atom.packages.isPackageActive("package-that-throws-on-activate")).toBeFalsy()
|
||||
|
||||
it "does not serialize packages that have not been activated called on their main module", ->
|
||||
spyOn(console, 'warn')
|
||||
badPack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-that-throws-on-activate").then (p) -> badPack = p
|
||||
|
||||
runs ->
|
||||
spyOn(badPack.mainModule, 'serialize').andCallThrough()
|
||||
|
||||
atom.packages.deactivatePackage("package-that-throws-on-activate")
|
||||
expect(badPack.mainModule.serialize).not.toHaveBeenCalled()
|
||||
|
||||
it "absorbs exceptions that are thrown by the package module's serialize method", ->
|
||||
spyOn(console, 'error')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-serialize-error')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-serialization')
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackages()
|
||||
expect(atom.packages.packageStates['package-with-serialize-error']).toBeUndefined()
|
||||
expect(atom.packages.packageStates['package-with-serialization']).toEqual someNumber: 1
|
||||
expect(console.error).toHaveBeenCalled()
|
||||
|
||||
it "absorbs exceptions that are thrown by the package module's deactivate method", ->
|
||||
spyOn(console, 'error')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-that-throws-on-deactivate")
|
||||
|
||||
runs ->
|
||||
expect(-> atom.packages.deactivatePackage("package-that-throws-on-deactivate")).not.toThrow()
|
||||
expect(console.error).toHaveBeenCalled()
|
||||
|
||||
it "removes the package's grammars", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-grammars')
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackage('package-with-grammars')
|
||||
expect(atom.syntax.selectGrammar('a.alot').name).toBe 'Null Grammar'
|
||||
expect(atom.syntax.selectGrammar('a.alittle').name).toBe 'Null Grammar'
|
||||
|
||||
it "removes the package's keymaps", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-keymaps')
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackage('package-with-keymaps')
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target: ($$ -> @div class: 'test-1')[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target: ($$ -> @div class: 'test-2')[0])).toHaveLength 0
|
||||
|
||||
it "removes the package's stylesheets", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-stylesheets')
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackage('package-with-stylesheets')
|
||||
one = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/1.css")
|
||||
two = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/2.less")
|
||||
three = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/3.css")
|
||||
expect(atom.themes.stylesheetElementForId(one)).not.toExist()
|
||||
expect(atom.themes.stylesheetElementForId(two)).not.toExist()
|
||||
expect(atom.themes.stylesheetElementForId(three)).not.toExist()
|
||||
|
||||
it "removes the package's scoped-properties", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-scoped-properties")
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
|
||||
atom.packages.deactivatePackage("package-with-scoped-properties")
|
||||
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBeUndefined()
|
||||
|
||||
describe "textmate packages", ->
|
||||
it "removes the package's grammars", ->
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Ruby"
|
||||
atom.packages.deactivatePackage('language-ruby')
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
|
||||
it "removes the package's scoped properties", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackage('language-ruby')
|
||||
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
|
||||
describe ".activate()", ->
|
||||
packageActivator = null
|
||||
themeActivator = null
|
||||
|
||||
beforeEach ->
|
||||
spyOn(console, 'warn')
|
||||
atom.packages.loadPackages()
|
||||
|
||||
loadedPackages = atom.packages.getLoadedPackages()
|
||||
expect(loadedPackages.length).toBeGreaterThan 0
|
||||
|
||||
packageActivator = spyOn(atom.packages, 'activatePackages')
|
||||
themeActivator = spyOn(atom.themes, 'activatePackages')
|
||||
|
||||
afterEach ->
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
Syntax = require '../src/syntax'
|
||||
atom.syntax = window.syntax = new Syntax()
|
||||
|
||||
it "activates all the packages, and none of the themes", ->
|
||||
atom.packages.activate()
|
||||
|
||||
expect(packageActivator).toHaveBeenCalled()
|
||||
expect(themeActivator).toHaveBeenCalled()
|
||||
|
||||
packages = packageActivator.mostRecentCall.args[0]
|
||||
expect(['atom', 'textmate']).toContain(pack.getType()) for pack in packages
|
||||
|
||||
themes = themeActivator.mostRecentCall.args[0]
|
||||
expect(['theme']).toContain(theme.getType()) for theme in themes
|
||||
|
||||
describe ".enablePackage() and disablePackage()", ->
|
||||
describe "with packages", ->
|
||||
it ".enablePackage() enables a disabled package", ->
|
||||
packageName = 'package-with-main'
|
||||
atom.config.pushAtKeyPath('core.disabledPackages', packageName)
|
||||
atom.packages.observeDisabledPackages()
|
||||
expect(atom.config.get('core.disabledPackages')).toContain packageName
|
||||
|
||||
pack = atom.packages.enablePackage(packageName)
|
||||
loadedPackages = atom.packages.getLoadedPackages()
|
||||
activatedPackages = null
|
||||
waitsFor ->
|
||||
activatedPackages = atom.packages.getActivePackages()
|
||||
activatedPackages.length > 0
|
||||
|
||||
runs ->
|
||||
expect(loadedPackages).toContain(pack)
|
||||
expect(activatedPackages).toContain(pack)
|
||||
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
|
||||
|
||||
it ".disablePackage() disables an enabled package", ->
|
||||
packageName = 'package-with-main'
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage(packageName)
|
||||
|
||||
runs ->
|
||||
atom.packages.observeDisabledPackages()
|
||||
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
|
||||
|
||||
pack = atom.packages.disablePackage(packageName)
|
||||
|
||||
activatedPackages = atom.packages.getActivePackages()
|
||||
expect(activatedPackages).not.toContain(pack)
|
||||
expect(atom.config.get('core.disabledPackages')).toContain packageName
|
||||
|
||||
describe "with themes", ->
|
||||
reloadedHandler = null
|
||||
|
||||
beforeEach ->
|
||||
waitsForPromise ->
|
||||
atom.themes.activateThemes()
|
||||
|
||||
afterEach ->
|
||||
atom.themes.deactivateThemes()
|
||||
|
||||
it ".enablePackage() and .disablePackage() enables and disables a theme", ->
|
||||
packageName = 'theme-with-package-file'
|
||||
|
||||
expect(atom.config.get('core.themes')).not.toContain packageName
|
||||
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
|
||||
|
||||
# enabling of theme
|
||||
pack = atom.packages.enablePackage(packageName)
|
||||
|
||||
waitsFor ->
|
||||
pack in atom.packages.getActivePackages()
|
||||
|
||||
runs ->
|
||||
expect(atom.config.get('core.themes')).toContain packageName
|
||||
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
|
||||
|
||||
reloadedHandler = jasmine.createSpy('reloadedHandler')
|
||||
reloadedHandler.reset()
|
||||
atom.themes.onDidReloadAll reloadedHandler
|
||||
|
||||
pack = atom.packages.disablePackage(packageName)
|
||||
|
||||
waitsFor ->
|
||||
reloadedHandler.callCount is 1
|
||||
|
||||
runs ->
|
||||
expect(atom.packages.getActivePackages()).not.toContain pack
|
||||
expect(atom.config.get('core.themes')).not.toContain packageName
|
||||
expect(atom.config.get('core.themes')).not.toContain packageName
|
||||
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
|
||||
|
||||
describe ".isReleasedVersion()", ->
|
||||
it "returns false if the version is a SHA and true otherwise", ->
|
||||
version = '0.1.0'
|
||||
@@ -582,3 +47,8 @@ describe "the `atom` global", ->
|
||||
[event, version, notes] = updateAvailableHandler.mostRecentCall.args
|
||||
expect(notes).toBe 'notes'
|
||||
expect(version).toBe 'version'
|
||||
|
||||
describe "loading default config", ->
|
||||
it 'loads the default core config', ->
|
||||
expect(atom.config.get('core.excludeVcsIgnoredPaths')).toBe true
|
||||
expect(atom.config.get('editor.showInvisibles')).toBe false
|
||||
|
||||
@@ -66,8 +66,11 @@ describe "CommandRegistry", ->
|
||||
registry.add '.child', 'command', -> calls.push('child-2')
|
||||
registry.add '.child', 'command', (event) -> calls.push('child-1'); event.stopPropagation()
|
||||
|
||||
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
|
||||
dispatchedEvent = new CustomEvent('command', bubbles: true)
|
||||
spyOn(dispatchedEvent, 'stopPropagation')
|
||||
grandchild.dispatchEvent(dispatchedEvent)
|
||||
expect(calls).toEqual ['child-1', 'child-2']
|
||||
expect(dispatchedEvent.stopPropagation).toHaveBeenCalled()
|
||||
|
||||
it "stops invoking callbacks when .stopImmediatePropagation() is called on the event", ->
|
||||
calls = []
|
||||
@@ -76,8 +79,21 @@ describe "CommandRegistry", ->
|
||||
registry.add '.child', 'command', -> calls.push('child-2')
|
||||
registry.add '.child', 'command', (event) -> calls.push('child-1'); event.stopImmediatePropagation()
|
||||
|
||||
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
|
||||
dispatchedEvent = new CustomEvent('command', bubbles: true)
|
||||
spyOn(dispatchedEvent, 'stopImmediatePropagation')
|
||||
grandchild.dispatchEvent(dispatchedEvent)
|
||||
expect(calls).toEqual ['child-1']
|
||||
expect(dispatchedEvent.stopImmediatePropagation).toHaveBeenCalled()
|
||||
|
||||
it "forwards .preventDefault() calls from the synthetic event to the original", ->
|
||||
calls = []
|
||||
|
||||
registry.add '.child', 'command', (event) -> event.preventDefault()
|
||||
|
||||
dispatchedEvent = new CustomEvent('command', bubbles: true)
|
||||
spyOn(dispatchedEvent, 'preventDefault')
|
||||
grandchild.dispatchEvent(dispatchedEvent)
|
||||
expect(dispatchedEvent.preventDefault).toHaveBeenCalled()
|
||||
|
||||
it "allows listeners to be removed via a disposable returned by ::add", ->
|
||||
calls = []
|
||||
@@ -124,3 +140,52 @@ describe "CommandRegistry", ->
|
||||
{name: 'namespace:command-2', displayName: 'Namespace: Command 2'}
|
||||
{name: 'namespace:command-1', displayName: 'Namespace: Command 1'}
|
||||
]
|
||||
|
||||
describe "::dispatch(target, commandName)", ->
|
||||
it "simulates invocation of the given command ", ->
|
||||
called = false
|
||||
registry.add '.grandchild', 'command', (event) ->
|
||||
expect(this).toBe grandchild
|
||||
expect(event.type).toBe 'command'
|
||||
expect(event.eventPhase).toBe Event.BUBBLING_PHASE
|
||||
expect(event.target).toBe grandchild
|
||||
expect(event.currentTarget).toBe grandchild
|
||||
called = true
|
||||
|
||||
registry.dispatch(grandchild, 'command')
|
||||
expect(called).toBe true
|
||||
|
||||
it "returns a boolean indicating whether any listeners matched the command", ->
|
||||
registry.add '.grandchild', 'command', ->
|
||||
|
||||
expect(registry.dispatch(grandchild, 'command')).toBe true
|
||||
expect(registry.dispatch(grandchild, 'bogus')).toBe false
|
||||
expect(registry.dispatch(parent, 'command')).toBe false
|
||||
|
||||
describe "::getSnapshot and ::restoreSnapshot", ->
|
||||
it "removes all command handlers except for those in the snapshot", ->
|
||||
registry.add '.parent', 'namespace:command-1', ->
|
||||
registry.add '.child', 'namespace:command-2', ->
|
||||
snapshot = registry.getSnapshot()
|
||||
registry.add '.grandchild', 'namespace:command-3', ->
|
||||
|
||||
expect(registry.findCommands(target: grandchild)[0..2]).toEqual [
|
||||
{name: 'namespace:command-3', displayName: 'Namespace: Command 3'}
|
||||
{name: 'namespace:command-2', displayName: 'Namespace: Command 2'}
|
||||
{name: 'namespace:command-1', displayName: 'Namespace: Command 1'}
|
||||
]
|
||||
|
||||
registry.restoreSnapshot(snapshot)
|
||||
|
||||
expect(registry.findCommands(target: grandchild)[0..1]).toEqual [
|
||||
{name: 'namespace:command-2', displayName: 'Namespace: Command 2'}
|
||||
{name: 'namespace:command-1', displayName: 'Namespace: Command 1'}
|
||||
]
|
||||
|
||||
registry.add '.grandchild', 'namespace:command-3', ->
|
||||
registry.restoreSnapshot(snapshot)
|
||||
|
||||
expect(registry.findCommands(target: grandchild)[0..1]).toEqual [
|
||||
{name: 'namespace:command-2', displayName: 'Namespace: Command 2'}
|
||||
{name: 'namespace:command-1', displayName: 'Namespace: Command 1'}
|
||||
]
|
||||
|
||||
+476
-19
@@ -12,7 +12,7 @@ describe "Config", ->
|
||||
|
||||
describe ".get(keyPath)", ->
|
||||
it "allows a key path's value to be read", ->
|
||||
expect(atom.config.set("foo.bar.baz", 42)).toBe 42
|
||||
expect(atom.config.set("foo.bar.baz", 42)).toBe true
|
||||
expect(atom.config.get("foo.bar.baz")).toBe 42
|
||||
expect(atom.config.get("bogus.key.path")).toBeUndefined()
|
||||
|
||||
@@ -37,7 +37,7 @@ describe "Config", ->
|
||||
|
||||
describe ".set(keyPath, value)", ->
|
||||
it "allows a key path's value to be written", ->
|
||||
expect(atom.config.set("foo.bar.baz", 42)).toBe 42
|
||||
expect(atom.config.set("foo.bar.baz", 42)).toBe true
|
||||
expect(atom.config.get("foo.bar.baz")).toBe 42
|
||||
|
||||
it "updates observers and saves when a key path is set", ->
|
||||
@@ -48,7 +48,7 @@ describe "Config", ->
|
||||
atom.config.set("foo.bar.baz", 42)
|
||||
|
||||
expect(atom.config.save).toHaveBeenCalled()
|
||||
expect(observeHandler).toHaveBeenCalledWith 42, {previous: undefined}
|
||||
expect(observeHandler).toHaveBeenCalledWith 42
|
||||
|
||||
describe "when the value equals the default value", ->
|
||||
it "does not store the value", ->
|
||||
@@ -139,7 +139,7 @@ describe "Config", ->
|
||||
|
||||
expect(atom.config.pushAtKeyPath("foo.bar.baz", "b")).toBe 2
|
||||
expect(atom.config.get("foo.bar.baz")).toEqual ["a", "b"]
|
||||
expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz"), {previous: ['a']}
|
||||
expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz")
|
||||
|
||||
describe ".unshiftAtKeyPath(keyPath, value)", ->
|
||||
it "unshifts the given value to the array at the key path and updates observers", ->
|
||||
@@ -150,7 +150,7 @@ describe "Config", ->
|
||||
|
||||
expect(atom.config.unshiftAtKeyPath("foo.bar.baz", "a")).toBe 2
|
||||
expect(atom.config.get("foo.bar.baz")).toEqual ["a", "b"]
|
||||
expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz"), {previous: ['b']}
|
||||
expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz")
|
||||
|
||||
describe ".removeAtKeyPath(keyPath, value)", ->
|
||||
it "removes the given value from the array at the key path and updates observers", ->
|
||||
@@ -161,16 +161,22 @@ describe "Config", ->
|
||||
|
||||
expect(atom.config.removeAtKeyPath("foo.bar.baz", "b")).toEqual ["a", "c"]
|
||||
expect(atom.config.get("foo.bar.baz")).toEqual ["a", "c"]
|
||||
expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz"), {previous: ['a', 'b', 'c']}
|
||||
expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz")
|
||||
|
||||
describe ".getPositiveInt(keyPath, defaultValue)", ->
|
||||
it "returns the proper current or default value", ->
|
||||
it "returns the proper coerced value", ->
|
||||
atom.config.set('editor.preferredLineLength', 0)
|
||||
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80
|
||||
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 1
|
||||
|
||||
it "returns the proper coerced value", ->
|
||||
atom.config.set('editor.preferredLineLength', -1234)
|
||||
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80
|
||||
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 1
|
||||
|
||||
it "returns the default value when a string is passed in", ->
|
||||
atom.config.set('editor.preferredLineLength', 'abcd')
|
||||
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80
|
||||
|
||||
it "returns the default value when null is passed in", ->
|
||||
atom.config.set('editor.preferredLineLength', null)
|
||||
expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80
|
||||
|
||||
@@ -226,11 +232,54 @@ describe "Config", ->
|
||||
|
||||
it "emits an updated event", ->
|
||||
updatedCallback = jasmine.createSpy('updated')
|
||||
atom.config.observe('foo.bar.baz.a', callNow: false, updatedCallback)
|
||||
atom.config.onDidChange('foo.bar.baz.a', updatedCallback)
|
||||
expect(updatedCallback.callCount).toBe 0
|
||||
atom.config.setDefaults("foo.bar.baz", a: 2)
|
||||
expect(updatedCallback.callCount).toBe 1
|
||||
|
||||
describe ".onDidChange(keyPath)", ->
|
||||
[observeHandler, observeSubscription] = []
|
||||
|
||||
describe 'when a keyPath is specified', ->
|
||||
beforeEach ->
|
||||
observeHandler = jasmine.createSpy("observeHandler")
|
||||
atom.config.set("foo.bar.baz", "value 1")
|
||||
observeSubscription = atom.config.onDidChange "foo.bar.baz", observeHandler
|
||||
|
||||
it "does not fire the given callback with the current value at the keypath", ->
|
||||
expect(observeHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "fires the callback every time the observed value changes", ->
|
||||
observeHandler.reset() # clear the initial call
|
||||
atom.config.set('foo.bar.baz', "value 2")
|
||||
expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 2', oldValue: 'value 1', keyPath: 'foo.bar.baz'})
|
||||
observeHandler.reset()
|
||||
|
||||
atom.config.set('foo.bar.baz', "value 1")
|
||||
expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 1', oldValue: 'value 2', keyPath: 'foo.bar.baz'})
|
||||
|
||||
describe 'when a keyPath is not specified', ->
|
||||
beforeEach ->
|
||||
observeHandler = jasmine.createSpy("observeHandler")
|
||||
atom.config.set("foo.bar.baz", "value 1")
|
||||
observeSubscription = atom.config.onDidChange observeHandler
|
||||
|
||||
it "does not fire the given callback initially", ->
|
||||
expect(observeHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "fires the callback every time any value changes", ->
|
||||
observeHandler.reset() # clear the initial call
|
||||
atom.config.set('foo.bar.baz', "value 2")
|
||||
expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 2', oldValue: 'value 1', keyPath: 'foo.bar.baz'})
|
||||
|
||||
observeHandler.reset()
|
||||
atom.config.set('foo.bar.baz', "value 1")
|
||||
expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 1', oldValue: 'value 2', keyPath: 'foo.bar.baz'})
|
||||
|
||||
observeHandler.reset()
|
||||
atom.config.set('foo.bar.int', 1)
|
||||
expect(observeHandler).toHaveBeenCalledWith({newValue: 1, oldValue: undefined, keyPath: 'foo.bar.int'})
|
||||
|
||||
describe ".observe(keyPath)", ->
|
||||
[observeHandler, observeSubscription] = []
|
||||
|
||||
@@ -245,26 +294,25 @@ describe "Config", ->
|
||||
it "fires the callback every time the observed value changes", ->
|
||||
observeHandler.reset() # clear the initial call
|
||||
atom.config.set('foo.bar.baz', "value 2")
|
||||
expect(observeHandler).toHaveBeenCalledWith("value 2", {previous: 'value 1'})
|
||||
expect(observeHandler).toHaveBeenCalledWith("value 2")
|
||||
observeHandler.reset()
|
||||
|
||||
atom.config.set('foo.bar.baz', "value 1")
|
||||
expect(observeHandler).toHaveBeenCalledWith("value 1", {previous: 'value 2'})
|
||||
expect(observeHandler).toHaveBeenCalledWith("value 1")
|
||||
|
||||
it "fires the callback when the observed value is deleted", ->
|
||||
observeHandler.reset() # clear the initial call
|
||||
atom.config.set('foo.bar.baz', undefined)
|
||||
expect(observeHandler).toHaveBeenCalledWith(undefined, {previous: 'value 1'})
|
||||
expect(observeHandler).toHaveBeenCalledWith(undefined)
|
||||
|
||||
it "fires the callback when the full key path goes into and out of existence", ->
|
||||
observeHandler.reset() # clear the initial call
|
||||
atom.config.set("foo.bar", undefined)
|
||||
expect(observeHandler).toHaveBeenCalledWith(undefined)
|
||||
|
||||
expect(observeHandler).toHaveBeenCalledWith(undefined, {previous: 'value 1'})
|
||||
observeHandler.reset()
|
||||
|
||||
atom.config.set("foo.bar.baz", "i'm back")
|
||||
expect(observeHandler).toHaveBeenCalledWith("i'm back", {previous: undefined})
|
||||
expect(observeHandler).toHaveBeenCalledWith("i'm back")
|
||||
|
||||
it "does not fire the callback once the observe subscription is off'ed", ->
|
||||
observeHandler.reset() # clear the initial call
|
||||
@@ -311,11 +359,19 @@ describe "Config", ->
|
||||
describe "when the config file contains valid cson", ->
|
||||
beforeEach ->
|
||||
fs.writeFileSync(atom.config.configFilePath, "foo: bar: 'baz'")
|
||||
atom.config.loadUserConfig()
|
||||
|
||||
it "updates the config data based on the file contents", ->
|
||||
atom.config.loadUserConfig()
|
||||
expect(atom.config.get("foo.bar")).toBe 'baz'
|
||||
|
||||
it "notifies observers for updated keypaths on load", ->
|
||||
observeHandler = jasmine.createSpy("observeHandler")
|
||||
observeSubscription = atom.config.observe "foo.bar", observeHandler
|
||||
|
||||
atom.config.loadUserConfig()
|
||||
|
||||
expect(observeHandler).toHaveBeenCalledWith 'baz'
|
||||
|
||||
describe "when the config file contains invalid cson", ->
|
||||
beforeEach ->
|
||||
spyOn(console, 'error')
|
||||
@@ -334,10 +390,43 @@ describe "Config", ->
|
||||
expect(fs.existsSync(atom.config.configFilePath)).toBe true
|
||||
expect(CSON.readFileSync(atom.config.configFilePath)).toEqual {}
|
||||
|
||||
describe "when a schema is specified", ->
|
||||
beforeEach ->
|
||||
schema =
|
||||
type: 'object'
|
||||
properties:
|
||||
bar:
|
||||
type: 'string'
|
||||
default: 'def'
|
||||
int:
|
||||
type: 'integer'
|
||||
default: 12
|
||||
|
||||
atom.config.setSchema('foo', schema)
|
||||
|
||||
describe "when the config file contains values that do not adhere to the schema", ->
|
||||
warnSpy = null
|
||||
beforeEach ->
|
||||
warnSpy = spyOn console, 'warn'
|
||||
fs.writeFileSync atom.config.configFilePath, """
|
||||
foo:
|
||||
bar: 'baz'
|
||||
int: 'bad value'
|
||||
"""
|
||||
atom.config.loadUserConfig()
|
||||
|
||||
it "updates the only the settings that have values matching the schema", ->
|
||||
expect(atom.config.get("foo.bar")).toBe 'baz'
|
||||
expect(atom.config.get("foo.int")).toBe 12
|
||||
|
||||
expect(warnSpy).toHaveBeenCalled()
|
||||
expect(warnSpy.mostRecentCall.args[0]).toContain "'foo.int' could not be set"
|
||||
|
||||
describe ".observeUserConfig()", ->
|
||||
updatedHandler = null
|
||||
|
||||
beforeEach ->
|
||||
atom.config.setDefaults('foo', bar: 'def')
|
||||
atom.config.configDirPath = dotAtomPath
|
||||
atom.config.configFilePath = path.join(atom.config.configDirPath, "atom.config.cson")
|
||||
expect(fs.existsSync(atom.config.configDirPath)).toBeFalsy()
|
||||
@@ -345,7 +434,7 @@ describe "Config", ->
|
||||
atom.config.loadUserConfig()
|
||||
atom.config.observeUserConfig()
|
||||
updatedHandler = jasmine.createSpy("updatedHandler")
|
||||
atom.config.on 'updated', updatedHandler
|
||||
atom.config.onDidChange updatedHandler
|
||||
|
||||
afterEach ->
|
||||
atom.config.unobserveUserConfig()
|
||||
@@ -359,6 +448,34 @@ describe "Config", ->
|
||||
expect(atom.config.get('foo.bar')).toBe 'quux'
|
||||
expect(atom.config.get('foo.baz')).toBe 'bar'
|
||||
|
||||
describe "when the config file changes to omit a setting with a default", ->
|
||||
it "resets the setting back to the default", ->
|
||||
fs.writeFileSync(atom.config.configFilePath, "foo: { baz: 'new'}")
|
||||
waitsFor 'update event', -> updatedHandler.callCount > 0
|
||||
runs ->
|
||||
expect(atom.config.get('foo.bar')).toBe 'def'
|
||||
expect(atom.config.get('foo.baz')).toBe 'new'
|
||||
|
||||
describe "when the config file changes to be empty", ->
|
||||
beforeEach ->
|
||||
fs.writeFileSync(atom.config.configFilePath, "")
|
||||
waitsFor 'update event', -> updatedHandler.callCount > 0
|
||||
|
||||
it "resets all settings back to the defaults", ->
|
||||
expect(updatedHandler.callCount).toBe 1
|
||||
expect(atom.config.get('foo.bar')).toBe 'def'
|
||||
atom.config.set("hair", "blonde") # trigger a save
|
||||
expect(atom.config.save).toHaveBeenCalled()
|
||||
|
||||
describe "when the config file subsequently changes again to contain configuration", ->
|
||||
beforeEach ->
|
||||
updatedHandler.reset()
|
||||
fs.writeFileSync(atom.config.configFilePath, "foo: bar: 'newVal'")
|
||||
waitsFor 'update event', -> updatedHandler.callCount > 0
|
||||
|
||||
it "sets the setting to the value specified in the config file", ->
|
||||
expect(atom.config.get('foo.bar')).toBe 'newVal'
|
||||
|
||||
describe "when the config file changes to contain invalid cson", ->
|
||||
beforeEach ->
|
||||
spyOn(console, 'error')
|
||||
@@ -373,9 +490,349 @@ describe "Config", ->
|
||||
|
||||
describe "when the config file subsequently changes again to contain valid cson", ->
|
||||
beforeEach ->
|
||||
fs.writeFileSync(atom.config.configFilePath, "foo: bar: 'baz'")
|
||||
fs.writeFileSync(atom.config.configFilePath, "foo: bar: 'newVal'")
|
||||
waitsFor 'update event', -> updatedHandler.callCount > 0
|
||||
|
||||
it "updates the config data and resumes saving", ->
|
||||
atom.config.set("hair", "blonde")
|
||||
expect(atom.config.save).toHaveBeenCalled()
|
||||
|
||||
describe "when a schema is specified", ->
|
||||
schema = null
|
||||
|
||||
describe '.setSchema(keyPath, schema)', ->
|
||||
it 'creates a properly nested schema', ->
|
||||
schema =
|
||||
type: 'object'
|
||||
properties:
|
||||
anInt:
|
||||
type: 'integer'
|
||||
default: 12
|
||||
|
||||
atom.config.setSchema('foo.bar', schema)
|
||||
|
||||
expect(atom.config.getSchema('foo')).toEqual
|
||||
type: 'object'
|
||||
properties:
|
||||
bar:
|
||||
type: 'object'
|
||||
properties:
|
||||
anInt:
|
||||
type: 'integer'
|
||||
default: 12
|
||||
|
||||
it 'sets defaults specified by the schema', ->
|
||||
schema =
|
||||
type: 'object'
|
||||
properties:
|
||||
anInt:
|
||||
type: 'integer'
|
||||
default: 12
|
||||
anObject:
|
||||
type: 'object'
|
||||
properties:
|
||||
nestedInt:
|
||||
type: 'integer'
|
||||
default: 24
|
||||
nestedObject:
|
||||
type: 'object'
|
||||
properties:
|
||||
superNestedInt:
|
||||
type: 'integer'
|
||||
default: 36
|
||||
|
||||
atom.config.setSchema('foo.bar', schema)
|
||||
expect(atom.config.get("foo.bar.anInt")).toBe 12
|
||||
expect(atom.config.get("foo.bar.anObject")).toEqual
|
||||
nestedInt: 24
|
||||
nestedObject:
|
||||
superNestedInt: 36
|
||||
|
||||
it 'can set a non-object schema', ->
|
||||
schema =
|
||||
type: 'integer'
|
||||
default: 12
|
||||
|
||||
atom.config.setSchema('foo.bar.anInt', schema)
|
||||
expect(atom.config.get("foo.bar.anInt")).toBe 12
|
||||
expect(atom.config.getSchema('foo.bar.anInt')).toEqual
|
||||
type: 'integer'
|
||||
default: 12
|
||||
|
||||
describe '.getSchema(keyPath)', ->
|
||||
schema =
|
||||
type: 'object'
|
||||
properties:
|
||||
anInt:
|
||||
type: 'integer'
|
||||
default: 12
|
||||
|
||||
atom.config.setSchema('foo.bar', schema)
|
||||
|
||||
expect(atom.config.getSchema('foo.bar')).toEqual
|
||||
type: 'object'
|
||||
properties:
|
||||
anInt:
|
||||
type: 'integer'
|
||||
default: 12
|
||||
|
||||
expect(atom.config.getSchema('foo.bar.anInt')).toEqual
|
||||
type: 'integer'
|
||||
default: 12
|
||||
|
||||
describe 'when the value has an "integer" type', ->
|
||||
beforeEach ->
|
||||
schema =
|
||||
type: 'integer'
|
||||
default: 12
|
||||
atom.config.setSchema('foo.bar.anInt', schema)
|
||||
|
||||
it 'coerces a string to an int', ->
|
||||
atom.config.set('foo.bar.anInt', '123')
|
||||
expect(atom.config.get('foo.bar.anInt')).toBe 123
|
||||
|
||||
it 'does not allow infinity', ->
|
||||
atom.config.set('foo.bar.anInt', Infinity)
|
||||
expect(atom.config.get('foo.bar.anInt')).toBe 12
|
||||
|
||||
it 'coerces a float to an int', ->
|
||||
atom.config.set('foo.bar.anInt', 12.3)
|
||||
expect(atom.config.get('foo.bar.anInt')).toBe 12
|
||||
|
||||
it 'will not set non-integers', ->
|
||||
atom.config.set('foo.bar.anInt', null)
|
||||
expect(atom.config.get('foo.bar.anInt')).toBe 12
|
||||
|
||||
atom.config.set('foo.bar.anInt', 'nope')
|
||||
expect(atom.config.get('foo.bar.anInt')).toBe 12
|
||||
|
||||
describe 'when the minimum and maximum keys are used', ->
|
||||
beforeEach ->
|
||||
schema =
|
||||
type: 'integer'
|
||||
minimum: 10
|
||||
maximum: 20
|
||||
default: 12
|
||||
atom.config.setSchema('foo.bar.anInt', schema)
|
||||
|
||||
it 'keeps the specified value within the specified range', ->
|
||||
atom.config.set('foo.bar.anInt', '123')
|
||||
expect(atom.config.get('foo.bar.anInt')).toBe 20
|
||||
|
||||
atom.config.set('foo.bar.anInt', '1')
|
||||
expect(atom.config.get('foo.bar.anInt')).toBe 10
|
||||
|
||||
describe 'when the value has an "integer" and "string" type', ->
|
||||
beforeEach ->
|
||||
schema =
|
||||
type: ['integer', 'string']
|
||||
default: 12
|
||||
atom.config.setSchema('foo.bar.anInt', schema)
|
||||
|
||||
it 'can coerce an int, and fallback to a string', ->
|
||||
atom.config.set('foo.bar.anInt', '123')
|
||||
expect(atom.config.get('foo.bar.anInt')).toBe 123
|
||||
|
||||
atom.config.set('foo.bar.anInt', 'cats')
|
||||
expect(atom.config.get('foo.bar.anInt')).toBe 'cats'
|
||||
|
||||
describe 'when the value has an "string" and "boolean" type', ->
|
||||
beforeEach ->
|
||||
schema =
|
||||
type: ['string', 'boolean']
|
||||
default: 'def'
|
||||
atom.config.setSchema('foo.bar', schema)
|
||||
|
||||
it 'can set a string, a boolean, and revert back to the default', ->
|
||||
atom.config.set('foo.bar', 'ok')
|
||||
expect(atom.config.get('foo.bar')).toBe 'ok'
|
||||
|
||||
atom.config.set('foo.bar', false)
|
||||
expect(atom.config.get('foo.bar')).toBe false
|
||||
|
||||
atom.config.set('foo.bar', undefined)
|
||||
expect(atom.config.get('foo.bar')).toBe 'def'
|
||||
|
||||
describe 'when the value has a "number" type', ->
|
||||
beforeEach ->
|
||||
schema =
|
||||
type: 'number'
|
||||
default: 12.1
|
||||
atom.config.setSchema('foo.bar.aFloat', schema)
|
||||
|
||||
it 'coerces a string to a float', ->
|
||||
atom.config.set('foo.bar.aFloat', '12.23')
|
||||
expect(atom.config.get('foo.bar.aFloat')).toBe 12.23
|
||||
|
||||
it 'will not set non-numbers', ->
|
||||
atom.config.set('foo.bar.aFloat', null)
|
||||
expect(atom.config.get('foo.bar.aFloat')).toBe 12.1
|
||||
|
||||
atom.config.set('foo.bar.aFloat', 'nope')
|
||||
expect(atom.config.get('foo.bar.aFloat')).toBe 12.1
|
||||
|
||||
describe 'when the minimum and maximum keys are used', ->
|
||||
beforeEach ->
|
||||
schema =
|
||||
type: 'number'
|
||||
minimum: 11.2
|
||||
maximum: 25.4
|
||||
default: 12.1
|
||||
atom.config.setSchema('foo.bar.aFloat', schema)
|
||||
|
||||
it 'keeps the specified value within the specified range', ->
|
||||
atom.config.set('foo.bar.aFloat', '123.2')
|
||||
expect(atom.config.get('foo.bar.aFloat')).toBe 25.4
|
||||
|
||||
atom.config.set('foo.bar.aFloat', '1.0')
|
||||
expect(atom.config.get('foo.bar.aFloat')).toBe 11.2
|
||||
|
||||
describe 'when the value has a "boolean" type', ->
|
||||
beforeEach ->
|
||||
schema =
|
||||
type: 'boolean'
|
||||
default: true
|
||||
atom.config.setSchema('foo.bar.aBool', schema)
|
||||
|
||||
it 'coerces various types to a boolean', ->
|
||||
atom.config.set('foo.bar.aBool', 'true')
|
||||
expect(atom.config.get('foo.bar.aBool')).toBe true
|
||||
atom.config.set('foo.bar.aBool', 'false')
|
||||
expect(atom.config.get('foo.bar.aBool')).toBe false
|
||||
atom.config.set('foo.bar.aBool', 'TRUE')
|
||||
expect(atom.config.get('foo.bar.aBool')).toBe true
|
||||
atom.config.set('foo.bar.aBool', 'FALSE')
|
||||
expect(atom.config.get('foo.bar.aBool')).toBe false
|
||||
atom.config.set('foo.bar.aBool', 1)
|
||||
expect(atom.config.get('foo.bar.aBool')).toBe false
|
||||
atom.config.set('foo.bar.aBool', 0)
|
||||
expect(atom.config.get('foo.bar.aBool')).toBe false
|
||||
atom.config.set('foo.bar.aBool', {})
|
||||
expect(atom.config.get('foo.bar.aBool')).toBe false
|
||||
atom.config.set('foo.bar.aBool', null)
|
||||
expect(atom.config.get('foo.bar.aBool')).toBe false
|
||||
|
||||
it 'reverts back to the default value when undefined is passed to set', ->
|
||||
atom.config.set('foo.bar.aBool', 'false')
|
||||
expect(atom.config.get('foo.bar.aBool')).toBe false
|
||||
|
||||
atom.config.set('foo.bar.aBool', undefined)
|
||||
expect(atom.config.get('foo.bar.aBool')).toBe true
|
||||
|
||||
describe 'when the value has an "string" type', ->
|
||||
beforeEach ->
|
||||
schema =
|
||||
type: 'string'
|
||||
default: 'ok'
|
||||
atom.config.setSchema('foo.bar.aString', schema)
|
||||
|
||||
it 'allows strings', ->
|
||||
atom.config.set('foo.bar.aString', 'yep')
|
||||
expect(atom.config.get('foo.bar.aString')).toBe 'yep'
|
||||
|
||||
it 'will only set strings', ->
|
||||
expect(atom.config.set('foo.bar.aString', 123)).toBe false
|
||||
expect(atom.config.get('foo.bar.aString')).toBe 'ok'
|
||||
|
||||
expect(atom.config.set('foo.bar.aString', true)).toBe false
|
||||
expect(atom.config.get('foo.bar.aString')).toBe 'ok'
|
||||
|
||||
expect(atom.config.set('foo.bar.aString', null)).toBe false
|
||||
expect(atom.config.get('foo.bar.aString')).toBe 'ok'
|
||||
|
||||
expect(atom.config.set('foo.bar.aString', [])).toBe false
|
||||
expect(atom.config.get('foo.bar.aString')).toBe 'ok'
|
||||
|
||||
expect(atom.config.set('foo.bar.aString', nope: 'nope')).toBe false
|
||||
expect(atom.config.get('foo.bar.aString')).toBe 'ok'
|
||||
|
||||
describe 'when the value has an "object" type', ->
|
||||
beforeEach ->
|
||||
schema =
|
||||
type: 'object'
|
||||
properties:
|
||||
anInt:
|
||||
type: 'integer'
|
||||
default: 12
|
||||
nestedObject:
|
||||
type: 'object'
|
||||
properties:
|
||||
nestedBool:
|
||||
type: 'boolean'
|
||||
default: false
|
||||
atom.config.setSchema('foo.bar', schema)
|
||||
|
||||
it 'converts and validates all the children', ->
|
||||
atom.config.set 'foo.bar',
|
||||
anInt: '23'
|
||||
nestedObject:
|
||||
nestedBool: 'true'
|
||||
expect(atom.config.get('foo.bar')).toEqual
|
||||
anInt: 23
|
||||
nestedObject:
|
||||
nestedBool: true
|
||||
|
||||
it 'will set only the values that adhere to the schema', ->
|
||||
expect(atom.config.set 'foo.bar',
|
||||
anInt: 'nope'
|
||||
nestedObject:
|
||||
nestedBool: true
|
||||
).toBe true
|
||||
expect(atom.config.get('foo.bar.anInt')).toEqual 12
|
||||
expect(atom.config.get('foo.bar.nestedObject.nestedBool')).toEqual true
|
||||
|
||||
describe 'when the value has an "array" type', ->
|
||||
beforeEach ->
|
||||
schema =
|
||||
type: 'array'
|
||||
default: [1, 2, 3]
|
||||
items:
|
||||
type: 'integer'
|
||||
atom.config.setSchema('foo.bar', schema)
|
||||
|
||||
it 'converts an array of strings to an array of ints', ->
|
||||
atom.config.set 'foo.bar', ['2', '3', '4']
|
||||
expect(atom.config.get('foo.bar')).toEqual [2, 3, 4]
|
||||
|
||||
describe 'when the `enum` key is used', ->
|
||||
beforeEach ->
|
||||
schema =
|
||||
type: 'object'
|
||||
properties:
|
||||
str:
|
||||
type: 'string'
|
||||
default: 'ok'
|
||||
enum: ['ok', 'one', 'two']
|
||||
int:
|
||||
type: 'integer'
|
||||
default: 2
|
||||
enum: [2, 3, 5]
|
||||
arr:
|
||||
type: 'array'
|
||||
default: ['one', 'two']
|
||||
items:
|
||||
type: 'string'
|
||||
enum: ['one', 'two', 'three']
|
||||
|
||||
atom.config.setSchema('foo.bar', schema)
|
||||
|
||||
it 'will only set a string when the string is in the enum values', ->
|
||||
expect(atom.config.set('foo.bar.str', 'nope')).toBe false
|
||||
expect(atom.config.get('foo.bar.str')).toBe 'ok'
|
||||
|
||||
expect(atom.config.set('foo.bar.str', 'one')).toBe true
|
||||
expect(atom.config.get('foo.bar.str')).toBe 'one'
|
||||
|
||||
it 'will only set an integer when the integer is in the enum values', ->
|
||||
expect(atom.config.set('foo.bar.int', '400')).toBe false
|
||||
expect(atom.config.get('foo.bar.int')).toBe 2
|
||||
|
||||
expect(atom.config.set('foo.bar.int', '3')).toBe true
|
||||
expect(atom.config.get('foo.bar.int')).toBe 3
|
||||
|
||||
it 'will only set an array when the array values are in the enum values', ->
|
||||
expect(atom.config.set('foo.bar.arr', ['one', 'five'])).toBe true
|
||||
expect(atom.config.get('foo.bar.arr')).toEqual ['one']
|
||||
|
||||
expect(atom.config.set('foo.bar.arr', ['two', 'three'])).toBe true
|
||||
expect(atom.config.get('foo.bar.arr')).toEqual ['two', 'three']
|
||||
|
||||
@@ -1,33 +1,44 @@
|
||||
DeserializerManager = require '../src/deserializer-manager'
|
||||
|
||||
describe ".deserialize(state)", ->
|
||||
deserializer = null
|
||||
describe "DeserializerManager", ->
|
||||
manager = null
|
||||
|
||||
class Foo
|
||||
@deserialize: ({name}) -> new Foo(name)
|
||||
constructor: (@name) ->
|
||||
|
||||
beforeEach ->
|
||||
deserializer = new DeserializerManager()
|
||||
deserializer.add(Foo)
|
||||
manager = new DeserializerManager
|
||||
|
||||
it "calls deserialize on the deserializer for the given state object, or returns undefined if one can't be found", ->
|
||||
spyOn(console, 'warn')
|
||||
object = deserializer.deserialize({ deserializer: 'Foo', name: 'Bar' })
|
||||
expect(object.name).toBe 'Bar'
|
||||
expect(deserializer.deserialize({ deserializer: 'Bogus' })).toBeUndefined()
|
||||
describe "::add(deserializer)", ->
|
||||
it "returns a disposable that can be used to remove the manager", ->
|
||||
disposable = manager.add(Foo)
|
||||
expect(manager.deserialize({deserializer: 'Foo', name: 'Bar'})).toBeDefined()
|
||||
disposable.dispose()
|
||||
spyOn(console, 'warn')
|
||||
expect(manager.deserialize({deserializer: 'Foo', name: 'Bar'})).toBeUndefined()
|
||||
|
||||
describe "when the deserializer has a version", ->
|
||||
describe "::deserialize(state)", ->
|
||||
beforeEach ->
|
||||
Foo.version = 2
|
||||
manager.add(Foo)
|
||||
|
||||
describe "when the deserialized state has a matching version", ->
|
||||
it "attempts to deserialize the state", ->
|
||||
object = deserializer.deserialize({ deserializer: 'Foo', version: 2, name: 'Bar' })
|
||||
expect(object.name).toBe 'Bar'
|
||||
it "calls deserialize on the manager for the given state object, or returns undefined if one can't be found", ->
|
||||
spyOn(console, 'warn')
|
||||
object = manager.deserialize({deserializer: 'Foo', name: 'Bar'})
|
||||
expect(object.name).toBe 'Bar'
|
||||
expect(manager.deserialize({deserializer: 'Bogus'})).toBeUndefined()
|
||||
|
||||
describe "when the deserialized state has a non-matching version", ->
|
||||
it "returns undefined", ->
|
||||
expect(deserializer.deserialize({ deserializer: 'Foo', version: 3, name: 'Bar' })).toBeUndefined()
|
||||
expect(deserializer.deserialize({ deserializer: 'Foo', version: 1, name: 'Bar' })).toBeUndefined()
|
||||
expect(deserializer.deserialize({ deserializer: 'Foo', name: 'Bar' })).toBeUndefined()
|
||||
describe "when the manager has a version", ->
|
||||
beforeEach ->
|
||||
Foo.version = 2
|
||||
|
||||
describe "when the deserialized state has a matching version", ->
|
||||
it "attempts to deserialize the state", ->
|
||||
object = manager.deserialize({deserializer: 'Foo', version: 2, name: 'Bar'})
|
||||
expect(object.name).toBe 'Bar'
|
||||
|
||||
describe "when the deserialized state has a non-matching version", ->
|
||||
it "returns undefined", ->
|
||||
expect(manager.deserialize({deserializer: 'Foo', version: 3, name: 'Bar'})).toBeUndefined()
|
||||
expect(manager.deserialize({deserializer: 'Foo', version: 1, name: 'Bar'})).toBeUndefined()
|
||||
expect(manager.deserialize({deserializer: 'Foo', name: 'Bar'})).toBeUndefined()
|
||||
|
||||
@@ -1100,6 +1100,33 @@ describe "DisplayBuffer", ->
|
||||
expect(displayBuffer.setScrollTop(maxScrollTop + 50)).toBe maxScrollTop
|
||||
expect(displayBuffer.getScrollTop()).toBe maxScrollTop
|
||||
|
||||
describe "editor.scrollPastEnd", ->
|
||||
describe "when editor.scrollPastEnd is false", ->
|
||||
beforeEach ->
|
||||
atom.config.set("editor.scrollPastEnd", false)
|
||||
displayBuffer.manageScrollPosition = true
|
||||
displayBuffer.setLineHeightInPixels(10)
|
||||
|
||||
it "does not add the height of the view to the scroll height", ->
|
||||
lineHeight = displayBuffer.getLineHeightInPixels()
|
||||
originalScrollHeight = displayBuffer.getScrollHeight()
|
||||
displayBuffer.setHeight(50)
|
||||
|
||||
expect(displayBuffer.getScrollHeight()).toBe originalScrollHeight
|
||||
|
||||
describe "when editor.scrollPastEnd is true", ->
|
||||
beforeEach ->
|
||||
atom.config.set("editor.scrollPastEnd", true)
|
||||
displayBuffer.manageScrollPosition = true
|
||||
displayBuffer.setLineHeightInPixels(10)
|
||||
|
||||
it "adds the height of the view to the scroll height", ->
|
||||
lineHeight = displayBuffer.getLineHeightInPixels()
|
||||
originalScrollHeight = displayBuffer.getScrollHeight()
|
||||
displayBuffer.setHeight(50)
|
||||
|
||||
expect(displayBuffer.getScrollHeight()).toEqual(originalScrollHeight + displayBuffer.height - (lineHeight * 3))
|
||||
|
||||
describe "::setScrollLeft", ->
|
||||
beforeEach ->
|
||||
displayBuffer.manageScrollPosition = true
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
module.exports =
|
||||
activateCallCount: 0
|
||||
activationCommandCallCount: 0
|
||||
legacyActivationCommandCallCount: 0
|
||||
|
||||
activate: ->
|
||||
@activateCallCount++
|
||||
|
||||
atom.commands.add '.workspace', 'activation-command', =>
|
||||
@activationCommandCallCount++
|
||||
|
||||
atom.workspaceView.getActiveView()?.command 'activation-command', =>
|
||||
@legacyActivationCommandCallCount++
|
||||
@@ -0,0 +1,2 @@
|
||||
'activationCommands':
|
||||
'.workspace': 'activation-command'
|
||||
@@ -1,13 +0,0 @@
|
||||
class Foo
|
||||
atom.deserializers.add(this)
|
||||
@deserialize: ({data}) -> new Foo(data)
|
||||
constructor: (@data) ->
|
||||
|
||||
module.exports =
|
||||
activateCallCount: 0
|
||||
activationEventCallCount: 0
|
||||
|
||||
activate: ->
|
||||
@activateCallCount++
|
||||
atom.workspaceView.getActiveView()?.command 'activation-event', =>
|
||||
@activationEventCallCount++
|
||||
@@ -1 +0,0 @@
|
||||
'activationEvents': ['activation-event']
|
||||
@@ -0,0 +1,13 @@
|
||||
module.exports =
|
||||
config:
|
||||
numbers:
|
||||
type: 'object'
|
||||
properties:
|
||||
one:
|
||||
type: 'integer'
|
||||
default: 1
|
||||
two:
|
||||
type: 'integer'
|
||||
default: 2
|
||||
|
||||
activate: -> # no-op
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "no events",
|
||||
"version": "0.1.0",
|
||||
"activationEvents": []
|
||||
"activationCommands": {".workspace": []}
|
||||
}
|
||||
@@ -14,6 +14,10 @@ describe "LanguageMode", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
afterEach ->
|
||||
atom.packages.deactivatePackages()
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
describe ".minIndentLevelForRowRange(startRow, endRow)", ->
|
||||
it "returns the minimum indent level for the given row range", ->
|
||||
expect(languageMode.minIndentLevelForRowRange(4, 7)).toBe 2
|
||||
@@ -149,6 +153,10 @@ describe "LanguageMode", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-coffee-script')
|
||||
|
||||
afterEach ->
|
||||
atom.packages.deactivatePackages()
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
describe ".toggleLineCommentsForBufferRows(start, end)", ->
|
||||
it "comments/uncomments lines in the given range", ->
|
||||
languageMode.toggleLineCommentsForBufferRows(4, 6)
|
||||
@@ -200,6 +208,10 @@ describe "LanguageMode", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-css')
|
||||
|
||||
afterEach ->
|
||||
atom.packages.deactivatePackages()
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
describe ".toggleLineCommentsForBufferRows(start, end)", ->
|
||||
it "comments/uncomments lines in the given range", ->
|
||||
languageMode.toggleLineCommentsForBufferRows(0, 1)
|
||||
@@ -248,6 +260,10 @@ describe "LanguageMode", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-css')
|
||||
|
||||
afterEach ->
|
||||
atom.packages.deactivatePackages()
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
describe "when commenting lines", ->
|
||||
it "only uses the `commentEnd` pattern if it comes from the same grammar as the `commentStart`", ->
|
||||
languageMode.toggleLineCommentsForBufferRows(0, 0)
|
||||
@@ -264,6 +280,10 @@ describe "LanguageMode", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-xml')
|
||||
|
||||
afterEach ->
|
||||
atom.packages.deactivatePackages()
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
describe "when uncommenting lines", ->
|
||||
it "removes the leading whitespace from the comment end pattern match", ->
|
||||
languageMode.toggleLineCommentsForBufferRows(0, 0)
|
||||
@@ -279,6 +299,10 @@ describe "LanguageMode", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
afterEach ->
|
||||
atom.packages.deactivatePackages()
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
it "maintains cursor buffer position when a folding/unfolding", ->
|
||||
editor.setCursorBufferPosition([5,5])
|
||||
languageMode.foldAll()
|
||||
@@ -366,6 +390,10 @@ describe "LanguageMode", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-javascript')
|
||||
|
||||
afterEach ->
|
||||
atom.packages.deactivatePackages()
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
describe ".unfoldAll()", ->
|
||||
it "unfolds every folded line", ->
|
||||
initialScreenLineCount = editor.getScreenLineCount()
|
||||
@@ -435,6 +463,10 @@ describe "LanguageMode", ->
|
||||
atom.packages.activatePackage('language-source')
|
||||
atom.packages.activatePackage('language-css')
|
||||
|
||||
afterEach ->
|
||||
atom.packages.deactivatePackages()
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
describe "suggestedIndentForBufferRow", ->
|
||||
it "does not return negative values (regression)", ->
|
||||
editor.setText('.test {\npadding: 0;\n}')
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
MenuManager = require '../src/menu-manager'
|
||||
|
||||
describe "MenuManager", ->
|
||||
menu = null
|
||||
|
||||
beforeEach ->
|
||||
menu = new MenuManager(resourcePath: atom.getLoadSettings().resourcePath)
|
||||
|
||||
describe "::add(items)", ->
|
||||
it "can add new menus that can be removed with the returned disposable", ->
|
||||
disposable = menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}]
|
||||
expect(menu.template).toEqual [{label: "A", submenu: [{label: "B", command: "b"}]}]
|
||||
disposable.dispose()
|
||||
expect(menu.template).toEqual []
|
||||
|
||||
it "can add submenu items to existing menus that can be removed with the returned disposable", ->
|
||||
disposable1 = menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}]
|
||||
disposable2 = menu.add [{label: "A", submenu: [{label: "C", submenu: [{label: "D", command: 'd'}]}]}]
|
||||
disposable3 = menu.add [{label: "A", submenu: [{label: "C", submenu: [{label: "E", command: 'e'}]}]}]
|
||||
|
||||
expect(menu.template).toEqual [{
|
||||
label: "A",
|
||||
submenu: [
|
||||
{label: "B", command: "b"},
|
||||
{label: "C", submenu: [{label: 'D', command: 'd'}, {label: 'E', command: 'e'}]}
|
||||
]
|
||||
}]
|
||||
|
||||
disposable3.dispose()
|
||||
expect(menu.template).toEqual [{
|
||||
label: "A",
|
||||
submenu: [
|
||||
{label: "B", command: "b"},
|
||||
{label: "C", submenu: [{label: 'D', command: 'd'}]}
|
||||
]
|
||||
}]
|
||||
|
||||
disposable2.dispose()
|
||||
expect(menu.template).toEqual [{label: "A", submenu: [{label: "B", command: "b"}]}]
|
||||
|
||||
disposable1.dispose()
|
||||
expect(menu.template).toEqual []
|
||||
|
||||
it "does not add duplicate labels to the same menu", ->
|
||||
originalItemCount = menu.template.length
|
||||
menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}]
|
||||
menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}]
|
||||
expect(menu.template[originalItemCount]).toEqual {label: "A", submenu: [{label: "B", command: "b"}]}
|
||||
@@ -0,0 +1,570 @@
|
||||
{$, $$, WorkspaceView} = require 'atom'
|
||||
Package = require '../src/package'
|
||||
|
||||
describe "PackageManager", ->
|
||||
beforeEach ->
|
||||
atom.workspaceView = new WorkspaceView
|
||||
|
||||
describe "::loadPackage(name)", ->
|
||||
it "continues if the package has an invalid package.json", ->
|
||||
spyOn(console, 'warn')
|
||||
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", ->
|
||||
spyOn(console, 'warn')
|
||||
atom.config.set("core.disabledPackages", [])
|
||||
expect(-> atom.packages.loadPackage("package-with-broken-keymap")).not.toThrow()
|
||||
|
||||
describe "::unloadPackage(name)", ->
|
||||
describe "when the package is active", ->
|
||||
it "throws an error", ->
|
||||
pack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-main').then (p) -> pack = p
|
||||
|
||||
runs ->
|
||||
expect(atom.packages.isPackageLoaded(pack.name)).toBeTruthy()
|
||||
expect(atom.packages.isPackageActive(pack.name)).toBeTruthy()
|
||||
expect( -> atom.packages.unloadPackage(pack.name)).toThrow()
|
||||
expect(atom.packages.isPackageLoaded(pack.name)).toBeTruthy()
|
||||
expect(atom.packages.isPackageActive(pack.name)).toBeTruthy()
|
||||
|
||||
describe "when the package is not loaded", ->
|
||||
it "throws an error", ->
|
||||
expect(atom.packages.isPackageLoaded('unloaded')).toBeFalsy()
|
||||
expect( -> atom.packages.unloadPackage('unloaded')).toThrow()
|
||||
expect(atom.packages.isPackageLoaded('unloaded')).toBeFalsy()
|
||||
|
||||
describe "when the package is loaded", ->
|
||||
it "no longers reports it as being loaded", ->
|
||||
pack = atom.packages.loadPackage('package-with-main')
|
||||
expect(atom.packages.isPackageLoaded(pack.name)).toBeTruthy()
|
||||
atom.packages.unloadPackage(pack.name)
|
||||
expect(atom.packages.isPackageLoaded(pack.name)).toBeFalsy()
|
||||
|
||||
describe "::activatePackage(id)", ->
|
||||
describe "atom packages", ->
|
||||
describe "when called multiple times", ->
|
||||
it "it only calls activate on the package once", ->
|
||||
spyOn(Package.prototype, 'activateNow').andCallThrough()
|
||||
atom.packages.activatePackage('package-with-index')
|
||||
atom.packages.activatePackage('package-with-index')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-index')
|
||||
|
||||
runs ->
|
||||
expect(Package.prototype.activateNow.callCount).toBe 1
|
||||
|
||||
describe "when the package has a main module", ->
|
||||
describe "when the metadata specifies a main module path˜", ->
|
||||
it "requires the module at the specified path", ->
|
||||
mainModule = require('./fixtures/packages/package-with-main/main-module')
|
||||
spyOn(mainModule, 'activate')
|
||||
pack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-main').then (p) -> pack = p
|
||||
|
||||
runs ->
|
||||
expect(mainModule.activate).toHaveBeenCalled()
|
||||
expect(pack.mainModule).toBe mainModule
|
||||
|
||||
describe "when the metadata does not specify a main module", ->
|
||||
it "requires index.coffee", ->
|
||||
indexModule = require('./fixtures/packages/package-with-index/index')
|
||||
spyOn(indexModule, 'activate')
|
||||
pack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-index').then (p) -> pack = p
|
||||
|
||||
runs ->
|
||||
expect(indexModule.activate).toHaveBeenCalled()
|
||||
expect(pack.mainModule).toBe indexModule
|
||||
|
||||
it "assigns config schema, including defaults when package contains a schema", ->
|
||||
expect(atom.config.get('package-with-config-schema.numbers.one')).toBeUndefined()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-config-schema')
|
||||
|
||||
runs ->
|
||||
expect(atom.config.get('package-with-config-schema.numbers.one')).toBe 1
|
||||
expect(atom.config.get('package-with-config-schema.numbers.two')).toBe 2
|
||||
|
||||
expect(atom.config.set('package-with-config-schema.numbers.one', 'nope')).toBe false
|
||||
expect(atom.config.set('package-with-config-schema.numbers.one', '10')).toBe true
|
||||
expect(atom.config.get('package-with-config-schema.numbers.one')).toBe 10
|
||||
|
||||
it "still assigns configDefaults from the module though deprecated", ->
|
||||
expect(atom.config.get('package-with-config-defaults.numbers.one')).toBeUndefined()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-config-defaults')
|
||||
|
||||
runs ->
|
||||
expect(atom.config.get('package-with-config-defaults.numbers.one')).toBe 1
|
||||
expect(atom.config.get('package-with-config-defaults.numbers.two')).toBe 2
|
||||
|
||||
describe "when the package metadata includes `activationCommands`", ->
|
||||
[mainModule, promise, workspaceCommandListener] = []
|
||||
|
||||
beforeEach ->
|
||||
atom.workspaceView.attachToDom()
|
||||
mainModule = require './fixtures/packages/package-with-activation-commands/index'
|
||||
mainModule.legacyActivationCommandCallCount = 0
|
||||
mainModule.activationCommandCallCount = 0
|
||||
spyOn(mainModule, 'activate').andCallThrough()
|
||||
spyOn(Package.prototype, 'requireMainModule').andCallThrough()
|
||||
|
||||
workspaceCommandListener = jasmine.createSpy('workspaceCommandListener')
|
||||
atom.commands.add '.workspace', 'activation-command', workspaceCommandListener
|
||||
|
||||
promise = atom.packages.activatePackage('package-with-activation-commands')
|
||||
|
||||
it "defers requiring/activating the main module until an activation event bubbles to the root view", ->
|
||||
expect(promise.isFulfilled()).not.toBeTruthy()
|
||||
atom.workspaceView[0].dispatchEvent(new CustomEvent('activation-command', bubbles: true))
|
||||
|
||||
waitsForPromise ->
|
||||
promise
|
||||
|
||||
it "triggers the activation event on all handlers registered during activation", ->
|
||||
waitsForPromise ->
|
||||
atom.workspaceView.open()
|
||||
|
||||
runs ->
|
||||
editorView = atom.workspaceView.getActiveView()
|
||||
legacyCommandListener = jasmine.createSpy("legacyCommandListener")
|
||||
editorView.command 'activation-command', legacyCommandListener
|
||||
editorCommandListener = jasmine.createSpy("editorCommandListener")
|
||||
atom.commands.add '.editor', 'activation-command', editorCommandListener
|
||||
editorView[0].dispatchEvent(new CustomEvent('activation-command', bubbles: true))
|
||||
expect(mainModule.activate.callCount).toBe 1
|
||||
expect(mainModule.legacyActivationCommandCallCount).toBe 1
|
||||
expect(mainModule.activationCommandCallCount).toBe 1
|
||||
expect(legacyCommandListener.callCount).toBe 1
|
||||
expect(editorCommandListener.callCount).toBe 1
|
||||
expect(workspaceCommandListener.callCount).toBe 1
|
||||
editorView[0].dispatchEvent(new CustomEvent('activation-command', bubbles: true))
|
||||
expect(mainModule.legacyActivationCommandCallCount).toBe 2
|
||||
expect(mainModule.activationCommandCallCount).toBe 2
|
||||
expect(legacyCommandListener.callCount).toBe 2
|
||||
expect(editorCommandListener.callCount).toBe 2
|
||||
expect(workspaceCommandListener.callCount).toBe 2
|
||||
expect(mainModule.activate.callCount).toBe 1
|
||||
|
||||
it "activates the package immediately when the events are empty", ->
|
||||
mainModule = require './fixtures/packages/package-with-empty-activation-commands/index'
|
||||
spyOn(mainModule, 'activate').andCallThrough()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-empty-activation-commands')
|
||||
|
||||
runs ->
|
||||
expect(mainModule.activate.callCount).toBe 1
|
||||
|
||||
describe "when the package has no main module", ->
|
||||
it "does not throw an exception", ->
|
||||
spyOn(console, "error")
|
||||
spyOn(console, "warn").andCallThrough()
|
||||
expect(-> atom.packages.activatePackage('package-without-module')).not.toThrow()
|
||||
expect(console.error).not.toHaveBeenCalled()
|
||||
expect(console.warn).not.toHaveBeenCalled()
|
||||
|
||||
it "passes the activate method the package's previously serialized state if it exists", ->
|
||||
pack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-serialization").then (p) -> pack = p
|
||||
|
||||
runs ->
|
||||
expect(pack.mainModule.someNumber).not.toBe 77
|
||||
pack.mainModule.someNumber = 77
|
||||
atom.packages.deactivatePackage("package-with-serialization")
|
||||
spyOn(pack.mainModule, 'activate').andCallThrough()
|
||||
atom.packages.activatePackage("package-with-serialization")
|
||||
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 "keymap loading", ->
|
||||
describe "when the metadata does not contain a 'keymaps' manifest", ->
|
||||
it "loads all the .cson/.json files in the keymaps directory", ->
|
||||
element1 = $$ -> @div class: 'test-1'
|
||||
element2 = $$ -> @div class: 'test-2'
|
||||
element3 = $$ -> @div class: 'test-3'
|
||||
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element2[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element3[0])).toHaveLength 0
|
||||
|
||||
atom.packages.activatePackage("package-with-keymaps")
|
||||
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])[0].command).toBe "test-1"
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element2[0])[0].command).toBe "test-2"
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element3[0])).toHaveLength 0
|
||||
|
||||
describe "when the metadata contains a 'keymaps' manifest", ->
|
||||
it "loads only the keymaps specified by the manifest, in the specified order", ->
|
||||
element1 = $$ -> @div class: 'test-1'
|
||||
element3 = $$ -> @div class: 'test-3'
|
||||
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])).toHaveLength 0
|
||||
|
||||
atom.packages.activatePackage("package-with-keymaps-manifest")
|
||||
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target:element1[0])[0].command).toBe 'keymap-1'
|
||||
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 "menu loading", ->
|
||||
beforeEach ->
|
||||
atom.contextMenu.definitions = []
|
||||
atom.menu.template = []
|
||||
|
||||
describe "when the metadata does not contain a 'menus' manifest", ->
|
||||
it "loads all the .cson/.json files in the menus directory", ->
|
||||
element = ($$ -> @div class: 'test-1')[0]
|
||||
|
||||
expect(atom.contextMenu.definitionsForElement(element)).toEqual []
|
||||
|
||||
atom.packages.activatePackage("package-with-menus")
|
||||
|
||||
expect(atom.menu.template.length).toBe 2
|
||||
expect(atom.menu.template[0].label).toBe "Second to Last"
|
||||
expect(atom.menu.template[1].label).toBe "Last"
|
||||
expect(atom.contextMenu.definitionsForElement(element)[0].label).toBe "Menu item 1"
|
||||
expect(atom.contextMenu.definitionsForElement(element)[1].label).toBe "Menu item 2"
|
||||
expect(atom.contextMenu.definitionsForElement(element)[2].label).toBe "Menu item 3"
|
||||
|
||||
describe "when the metadata contains a 'menus' manifest", ->
|
||||
it "loads only the menus specified by the manifest, in the specified order", ->
|
||||
element = ($$ -> @div class: 'test-1')[0]
|
||||
|
||||
expect(atom.contextMenu.definitionsForElement(element)).toEqual []
|
||||
|
||||
atom.packages.activatePackage("package-with-menus-manifest")
|
||||
|
||||
expect(atom.menu.template[0].label).toBe "Second to Last"
|
||||
expect(atom.menu.template[1].label).toBe "Last"
|
||||
expect(atom.contextMenu.definitionsForElement(element)[0].label).toBe "Menu item 2"
|
||||
expect(atom.contextMenu.definitionsForElement(element)[1].label).toBe "Menu item 1"
|
||||
expect(atom.contextMenu.definitionsForElement(element)[2]).toBeUndefined()
|
||||
|
||||
describe "stylesheet loading", ->
|
||||
describe "when the metadata contains a 'stylesheets' manifest", ->
|
||||
it "loads stylesheets from the stylesheets directory as specified by the manifest", ->
|
||||
one = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/1.css")
|
||||
two = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/2.less")
|
||||
three = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/3.css")
|
||||
|
||||
one = atom.themes.stringToId(one)
|
||||
two = atom.themes.stringToId(two)
|
||||
three = atom.themes.stringToId(three)
|
||||
|
||||
expect(atom.themes.stylesheetElementForId(one)).toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(two)).toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(three)).toBeNull()
|
||||
|
||||
atom.packages.activatePackage("package-with-stylesheets-manifest")
|
||||
|
||||
expect(atom.themes.stylesheetElementForId(one)).not.toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(two)).not.toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(three)).toBeNull()
|
||||
expect($('#jasmine-content').css('font-size')).toBe '1px'
|
||||
|
||||
describe "when the metadata does not contain a 'stylesheets' manifest", ->
|
||||
it "loads all stylesheets from the stylesheets directory", ->
|
||||
one = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/1.css")
|
||||
two = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/2.less")
|
||||
three = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/3.css")
|
||||
|
||||
|
||||
one = atom.themes.stringToId(one)
|
||||
two = atom.themes.stringToId(two)
|
||||
three = atom.themes.stringToId(three)
|
||||
|
||||
expect(atom.themes.stylesheetElementForId(one)).toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(two)).toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(three)).toBeNull()
|
||||
|
||||
atom.packages.activatePackage("package-with-stylesheets")
|
||||
expect(atom.themes.stylesheetElementForId(one)).not.toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(two)).not.toBeNull()
|
||||
expect(atom.themes.stylesheetElementForId(three)).not.toBeNull()
|
||||
expect($('#jasmine-content').css('font-size')).toBe '3px'
|
||||
|
||||
describe "grammar loading", ->
|
||||
it "loads the package's grammars", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-grammars')
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.selectGrammar('a.alot').name).toBe 'Alot'
|
||||
expect(atom.syntax.selectGrammar('a.alittle').name).toBe 'Alittle'
|
||||
|
||||
describe "scoped-property loading", ->
|
||||
it "loads the scoped properties", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-scoped-properties")
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
|
||||
|
||||
describe "converted textmate packages", ->
|
||||
it "loads the package's grammars", ->
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Ruby"
|
||||
|
||||
it "loads the translated scoped properties", ->
|
||||
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBe '# '
|
||||
|
||||
describe "::deactivatePackage(id)", ->
|
||||
describe "atom packages", ->
|
||||
it "calls `deactivate` on the package's main module if activate was successful", ->
|
||||
pack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-deactivate").then (p) -> pack = p
|
||||
|
||||
runs ->
|
||||
expect(atom.packages.isPackageActive("package-with-deactivate")).toBeTruthy()
|
||||
spyOn(pack.mainModule, 'deactivate').andCallThrough()
|
||||
|
||||
atom.packages.deactivatePackage("package-with-deactivate")
|
||||
expect(pack.mainModule.deactivate).toHaveBeenCalled()
|
||||
expect(atom.packages.isPackageActive("package-with-module")).toBeFalsy()
|
||||
|
||||
spyOn(console, 'warn')
|
||||
|
||||
badPack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-that-throws-on-activate").then (p) -> badPack = p
|
||||
|
||||
runs ->
|
||||
expect(atom.packages.isPackageActive("package-that-throws-on-activate")).toBeTruthy()
|
||||
spyOn(badPack.mainModule, 'deactivate').andCallThrough()
|
||||
|
||||
atom.packages.deactivatePackage("package-that-throws-on-activate")
|
||||
expect(badPack.mainModule.deactivate).not.toHaveBeenCalled()
|
||||
expect(atom.packages.isPackageActive("package-that-throws-on-activate")).toBeFalsy()
|
||||
|
||||
it "does not serialize packages that have not been activated called on their main module", ->
|
||||
spyOn(console, 'warn')
|
||||
badPack = null
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-that-throws-on-activate").then (p) -> badPack = p
|
||||
|
||||
runs ->
|
||||
spyOn(badPack.mainModule, 'serialize').andCallThrough()
|
||||
|
||||
atom.packages.deactivatePackage("package-that-throws-on-activate")
|
||||
expect(badPack.mainModule.serialize).not.toHaveBeenCalled()
|
||||
|
||||
it "absorbs exceptions that are thrown by the package module's serialize method", ->
|
||||
spyOn(console, 'error')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-serialize-error')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-serialization')
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackages()
|
||||
expect(atom.packages.packageStates['package-with-serialize-error']).toBeUndefined()
|
||||
expect(atom.packages.packageStates['package-with-serialization']).toEqual someNumber: 1
|
||||
expect(console.error).toHaveBeenCalled()
|
||||
|
||||
it "absorbs exceptions that are thrown by the package module's deactivate method", ->
|
||||
spyOn(console, 'error')
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-that-throws-on-deactivate")
|
||||
|
||||
runs ->
|
||||
expect(-> atom.packages.deactivatePackage("package-that-throws-on-deactivate")).not.toThrow()
|
||||
expect(console.error).toHaveBeenCalled()
|
||||
|
||||
it "removes the package's grammars", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-grammars')
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackage('package-with-grammars')
|
||||
expect(atom.syntax.selectGrammar('a.alot').name).toBe 'Null Grammar'
|
||||
expect(atom.syntax.selectGrammar('a.alittle').name).toBe 'Null Grammar'
|
||||
|
||||
it "removes the package's keymaps", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-keymaps')
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackage('package-with-keymaps')
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target: ($$ -> @div class: 'test-1')[0])).toHaveLength 0
|
||||
expect(atom.keymaps.findKeyBindings(keystrokes:'ctrl-z', target: ($$ -> @div class: 'test-2')[0])).toHaveLength 0
|
||||
|
||||
it "removes the package's stylesheets", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('package-with-stylesheets')
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackage('package-with-stylesheets')
|
||||
one = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/1.css")
|
||||
two = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/2.less")
|
||||
three = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/3.css")
|
||||
expect(atom.themes.stylesheetElementForId(one)).not.toExist()
|
||||
expect(atom.themes.stylesheetElementForId(two)).not.toExist()
|
||||
expect(atom.themes.stylesheetElementForId(three)).not.toExist()
|
||||
|
||||
it "removes the package's scoped-properties", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-scoped-properties")
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBe '^a'
|
||||
atom.packages.deactivatePackage("package-with-scoped-properties")
|
||||
expect(atom.syntax.getProperty ['.source.omg'], 'editor.increaseIndentPattern').toBeUndefined()
|
||||
|
||||
describe "textmate packages", ->
|
||||
it "removes the package's grammars", ->
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
runs ->
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Ruby"
|
||||
atom.packages.deactivatePackage('language-ruby')
|
||||
expect(atom.syntax.selectGrammar("file.rb").name).toBe "Null Grammar"
|
||||
|
||||
it "removes the package's scoped properties", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
runs ->
|
||||
atom.packages.deactivatePackage('language-ruby')
|
||||
expect(atom.syntax.getProperty(['.source.ruby'], 'editor.commentStart')).toBeUndefined()
|
||||
|
||||
describe "::activate()", ->
|
||||
packageActivator = null
|
||||
themeActivator = null
|
||||
|
||||
beforeEach ->
|
||||
spyOn(console, 'warn')
|
||||
atom.packages.loadPackages()
|
||||
|
||||
loadedPackages = atom.packages.getLoadedPackages()
|
||||
expect(loadedPackages.length).toBeGreaterThan 0
|
||||
|
||||
packageActivator = spyOn(atom.packages, 'activatePackages')
|
||||
themeActivator = spyOn(atom.themes, 'activatePackages')
|
||||
|
||||
afterEach ->
|
||||
atom.packages.deactivatePackages()
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
Syntax = require '../src/syntax'
|
||||
atom.syntax = window.syntax = new Syntax()
|
||||
|
||||
it "activates all the packages, and none of the themes", ->
|
||||
atom.packages.activate()
|
||||
|
||||
expect(packageActivator).toHaveBeenCalled()
|
||||
expect(themeActivator).toHaveBeenCalled()
|
||||
|
||||
packages = packageActivator.mostRecentCall.args[0]
|
||||
expect(['atom', 'textmate']).toContain(pack.getType()) for pack in packages
|
||||
|
||||
themes = themeActivator.mostRecentCall.args[0]
|
||||
expect(['theme']).toContain(theme.getType()) for theme in themes
|
||||
|
||||
describe "::enablePackage() and ::disablePackage()", ->
|
||||
describe "with packages", ->
|
||||
it ".enablePackage() enables a disabled package", ->
|
||||
packageName = 'package-with-main'
|
||||
atom.config.pushAtKeyPath('core.disabledPackages', packageName)
|
||||
atom.packages.observeDisabledPackages()
|
||||
expect(atom.config.get('core.disabledPackages')).toContain packageName
|
||||
|
||||
pack = atom.packages.enablePackage(packageName)
|
||||
loadedPackages = atom.packages.getLoadedPackages()
|
||||
activatedPackages = null
|
||||
waitsFor ->
|
||||
activatedPackages = atom.packages.getActivePackages()
|
||||
activatedPackages.length > 0
|
||||
|
||||
runs ->
|
||||
expect(loadedPackages).toContain(pack)
|
||||
expect(activatedPackages).toContain(pack)
|
||||
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
|
||||
|
||||
it ".disablePackage() disables an enabled package", ->
|
||||
packageName = 'package-with-main'
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage(packageName)
|
||||
|
||||
runs ->
|
||||
atom.packages.observeDisabledPackages()
|
||||
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
|
||||
|
||||
pack = atom.packages.disablePackage(packageName)
|
||||
|
||||
activatedPackages = atom.packages.getActivePackages()
|
||||
expect(activatedPackages).not.toContain(pack)
|
||||
expect(atom.config.get('core.disabledPackages')).toContain packageName
|
||||
|
||||
describe "with themes", ->
|
||||
reloadedHandler = null
|
||||
|
||||
beforeEach ->
|
||||
waitsForPromise ->
|
||||
atom.themes.activateThemes()
|
||||
|
||||
afterEach ->
|
||||
atom.themes.deactivateThemes()
|
||||
|
||||
it ".enablePackage() and .disablePackage() enables and disables a theme", ->
|
||||
packageName = 'theme-with-package-file'
|
||||
|
||||
expect(atom.config.get('core.themes')).not.toContain packageName
|
||||
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
|
||||
|
||||
# enabling of theme
|
||||
pack = atom.packages.enablePackage(packageName)
|
||||
|
||||
waitsFor ->
|
||||
pack in atom.packages.getActivePackages()
|
||||
|
||||
runs ->
|
||||
expect(atom.config.get('core.themes')).toContain packageName
|
||||
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
|
||||
|
||||
reloadedHandler = jasmine.createSpy('reloadedHandler')
|
||||
reloadedHandler.reset()
|
||||
atom.themes.onDidReloadAll reloadedHandler
|
||||
|
||||
pack = atom.packages.disablePackage(packageName)
|
||||
|
||||
waitsFor ->
|
||||
reloadedHandler.callCount is 1
|
||||
|
||||
runs ->
|
||||
expect(atom.packages.getActivePackages()).not.toContain pack
|
||||
expect(atom.config.get('core.themes')).not.toContain packageName
|
||||
expect(atom.config.get('core.themes')).not.toContain packageName
|
||||
expect(atom.config.get('core.disabledPackages')).not.toContain packageName
|
||||
@@ -5,11 +5,11 @@ PaneView = require '../src/pane-view'
|
||||
{$, View, $$} = require 'atom'
|
||||
|
||||
describe "PaneContainerView", ->
|
||||
[TestView, container, pane1, pane2, pane3] = []
|
||||
[TestView, container, pane1, pane2, pane3, deserializerDisposable] = []
|
||||
|
||||
beforeEach ->
|
||||
class TestView extends View
|
||||
atom.deserializers.add(this)
|
||||
deserializerDisposable = atom.deserializers.add(this)
|
||||
@deserialize: ({name}) -> new TestView(name)
|
||||
@content: -> @div tabindex: -1
|
||||
initialize: (@name) -> @text(@name)
|
||||
@@ -25,7 +25,7 @@ describe "PaneContainerView", ->
|
||||
pane3 = pane2.splitDown(new TestView('3'))
|
||||
|
||||
afterEach ->
|
||||
atom.deserializers.remove(TestView)
|
||||
deserializerDisposable.dispose()
|
||||
|
||||
describe ".getActivePaneView()", ->
|
||||
it "returns the most-recently focused pane", ->
|
||||
|
||||
@@ -4,6 +4,8 @@ PaneAxis = require '../src/pane-axis'
|
||||
PaneContainer = require '../src/pane-container'
|
||||
|
||||
describe "Pane", ->
|
||||
deserializerDisposable = null
|
||||
|
||||
class Item extends Model
|
||||
@deserialize: ({name, uri}) -> new this(name, uri)
|
||||
constructor: (@name, @uri) ->
|
||||
@@ -13,10 +15,10 @@ describe "Pane", ->
|
||||
isEqual: (other) -> @name is other?.name
|
||||
|
||||
beforeEach ->
|
||||
atom.deserializers.add(Item)
|
||||
deserializerDisposable = atom.deserializers.add(Item)
|
||||
|
||||
afterEach ->
|
||||
atom.deserializers.remove(Item)
|
||||
deserializerDisposable.dispose()
|
||||
|
||||
describe "construction", ->
|
||||
it "sets the active item to the first item", ->
|
||||
|
||||
@@ -7,7 +7,7 @@ path = require 'path'
|
||||
temp = require 'temp'
|
||||
|
||||
describe "PaneView", ->
|
||||
[container, containerModel, view1, view2, editor1, editor2, pane, paneModel] = []
|
||||
[container, containerModel, view1, view2, editor1, editor2, pane, paneModel, deserializerDisposable] = []
|
||||
|
||||
class TestView extends View
|
||||
@deserialize: ({id, text}) -> new TestView({id, text})
|
||||
@@ -23,7 +23,7 @@ describe "PaneView", ->
|
||||
@emitter.on 'did-change-title', callback
|
||||
|
||||
beforeEach ->
|
||||
atom.deserializers.add(TestView)
|
||||
deserializerDisposable = atom.deserializers.add(TestView)
|
||||
container = new PaneContainerView
|
||||
containerModel = container.model
|
||||
view1 = new TestView(id: 'view-1', text: 'View 1')
|
||||
@@ -40,7 +40,7 @@ describe "PaneView", ->
|
||||
paneModel.addItems([view1, editor1, view2, editor2])
|
||||
|
||||
afterEach ->
|
||||
atom.deserializers.remove(TestView)
|
||||
deserializerDisposable.dispose()
|
||||
|
||||
describe "when the active pane item changes", ->
|
||||
it "hides all item views except the active one", ->
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{times, random} = require 'underscore-plus'
|
||||
randomWords = require 'random-words'
|
||||
TextBuffer = require 'text-buffer'
|
||||
Editor = require '../src/editor'
|
||||
TextEditor = require '../src/text-editor'
|
||||
|
||||
describe "Editor", ->
|
||||
describe "TextEditor", ->
|
||||
[editor, tokenizedBuffer, buffer, steps, previousSteps] = []
|
||||
|
||||
softWrapColumn = 80
|
||||
@@ -17,7 +17,7 @@ describe "Editor", ->
|
||||
|
||||
times 10, (i) ->
|
||||
buffer = new TextBuffer
|
||||
editor = new Editor({buffer})
|
||||
editor = new TextEditor({buffer})
|
||||
editor.setEditorWidthInChars(80)
|
||||
tokenizedBuffer = editor.displayBuffer.tokenizedBuffer
|
||||
steps = []
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
Editor = require '../src/editor'
|
||||
TextEditor = require '../src/text-editor'
|
||||
|
||||
describe "Selection", ->
|
||||
[buffer, editor, selection] = []
|
||||
|
||||
beforeEach ->
|
||||
buffer = atom.project.bufferForPathSync('sample.js')
|
||||
editor = new Editor(buffer: buffer, tabLength: 2)
|
||||
editor = new TextEditor(buffer: buffer, tabLength: 2)
|
||||
selection = editor.getLastSelection()
|
||||
|
||||
afterEach ->
|
||||
|
||||
+11
-11
@@ -12,10 +12,10 @@ KeymapManager = require '../src/keymap-extensions'
|
||||
Config = require '../src/config'
|
||||
{Point} = require 'text-buffer'
|
||||
Project = require '../src/project'
|
||||
Editor = require '../src/editor'
|
||||
EditorView = require '../src/editor-view'
|
||||
TextEditor = require '../src/text-editor'
|
||||
TextEditorView = require '../src/text-editor-view'
|
||||
TokenizedBuffer = require '../src/tokenized-buffer'
|
||||
EditorComponent = require '../src/editor-component'
|
||||
TextEditorComponent = require '../src/text-editor-component'
|
||||
pathwatcher = require 'pathwatcher'
|
||||
clipboard = require 'clipboard'
|
||||
|
||||
@@ -27,6 +27,7 @@ fixturePackagesPath = path.resolve(__dirname, './fixtures/packages')
|
||||
atom.packages.packageDirPaths.unshift(fixturePackagesPath)
|
||||
atom.keymaps.loadBundledKeymaps()
|
||||
keyBindingsToRestore = atom.keymaps.getKeyBindings()
|
||||
commandsToRestore = atom.commands.getSnapshot()
|
||||
|
||||
$(window).on 'core:close', -> window.close()
|
||||
$(window).on 'beforeunload', ->
|
||||
@@ -65,6 +66,7 @@ beforeEach ->
|
||||
atom.workspace = new Workspace()
|
||||
atom.keymaps.keyBindings = _.clone(keyBindingsToRestore)
|
||||
atom.commands.setRootNode(document.body)
|
||||
atom.commands.restoreSnapshot(commandsToRestore)
|
||||
|
||||
window.resetTimeouts()
|
||||
atom.packages.packageStates = {}
|
||||
@@ -89,26 +91,26 @@ beforeEach ->
|
||||
config = new Config({resourcePath, configDirPath: atom.getConfigDirPath()})
|
||||
spyOn(config, 'load')
|
||||
spyOn(config, 'save')
|
||||
config.setDefaults('core', WorkspaceView.configDefaults)
|
||||
config.setDefaults('editor', EditorView.configDefaults)
|
||||
atom.config = config
|
||||
atom.loadConfig()
|
||||
config.set "core.destroyEmptyPanes", false
|
||||
config.set "editor.fontFamily", "Courier"
|
||||
config.set "editor.fontSize", 16
|
||||
config.set "editor.autoIndent", false
|
||||
config.set "core.disabledPackages", ["package-that-throws-an-exception",
|
||||
"package-with-broken-package-json", "package-with-broken-keymap"]
|
||||
config.load.reset()
|
||||
config.save.reset()
|
||||
atom.config = config
|
||||
|
||||
# make editor display updates synchronous
|
||||
spyOn(EditorView.prototype, 'requestDisplayUpdate').andCallFake -> @updateDisplay()
|
||||
EditorComponent.performSyncUpdates = true
|
||||
spyOn(TextEditorView.prototype, 'requestDisplayUpdate').andCallFake -> @updateDisplay()
|
||||
TextEditorComponent.performSyncUpdates = true
|
||||
|
||||
spyOn(WorkspaceView.prototype, 'setTitle').andCallFake (@title) ->
|
||||
spyOn(window, "setTimeout").andCallFake window.fakeSetTimeout
|
||||
spyOn(window, "clearTimeout").andCallFake window.fakeClearTimeout
|
||||
spyOn(pathwatcher.File.prototype, "detectResurrectionAfterDelay").andCallFake -> @detectResurrection()
|
||||
spyOn(Editor.prototype, "shouldPromptToSave").andReturn false
|
||||
spyOn(TextEditor.prototype, "shouldPromptToSave").andReturn false
|
||||
|
||||
# make tokenization synchronous
|
||||
TokenizedBuffer.prototype.chunkSize = Infinity
|
||||
@@ -121,8 +123,6 @@ beforeEach ->
|
||||
addCustomMatchers(this)
|
||||
|
||||
afterEach ->
|
||||
atom.commands.clear()
|
||||
|
||||
atom.packages.deactivatePackages()
|
||||
atom.menu.template = []
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ temp = require 'temp'
|
||||
|
||||
describe "the `syntax` global", ->
|
||||
beforeEach ->
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-text')
|
||||
|
||||
@@ -17,6 +16,10 @@ describe "the `syntax` global", ->
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage('language-ruby')
|
||||
|
||||
afterEach ->
|
||||
atom.packages.deactivatePackages()
|
||||
atom.packages.unloadPackages()
|
||||
|
||||
describe "serialization", ->
|
||||
it "remembers grammar overrides by path", ->
|
||||
filePath = '/foo/bar/file.js'
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
_ = require 'underscore-plus'
|
||||
{extend, flatten, toArray, last} = _
|
||||
|
||||
EditorView = require '../src/editor-view'
|
||||
EditorComponent = require '../src/editor-component'
|
||||
TextEditorView = require '../src/text-editor-view'
|
||||
TextEditorComponent = require '../src/text-editor-component'
|
||||
nbsp = String.fromCharCode(160)
|
||||
|
||||
describe "EditorComponent", ->
|
||||
describe "TextEditorComponent", ->
|
||||
[contentNode, editor, wrapperView, wrapperNode, component, componentNode, verticalScrollbarNode, horizontalScrollbarNode] = []
|
||||
[lineHeightInPixels, charWidth, nextAnimationFrame, noAnimationFrame, lineOverdrawMargin] = []
|
||||
|
||||
@@ -34,7 +34,7 @@ describe "EditorComponent", ->
|
||||
contentNode = document.querySelector('#jasmine-content')
|
||||
contentNode.style.width = '1000px'
|
||||
|
||||
wrapperView = new EditorView(editor, {lineOverdrawMargin})
|
||||
wrapperView = new TextEditorView(editor, {lineOverdrawMargin})
|
||||
wrapperView.attachToDom()
|
||||
wrapperNode = wrapperView.element
|
||||
|
||||
@@ -1734,11 +1734,11 @@ describe "EditorComponent", ->
|
||||
nextAnimationFrame()
|
||||
expect(verticalScrollbarNode.scrollTop).toBe 10
|
||||
|
||||
it "parses negative scrollSensitivity values as positive", ->
|
||||
it "parses negative scrollSensitivity values at the minimum", ->
|
||||
atom.config.set('editor.scrollSensitivity', -50)
|
||||
componentNode.dispatchEvent(new WheelEvent('mousewheel', wheelDeltaX: 0, wheelDeltaY: -10))
|
||||
nextAnimationFrame()
|
||||
expect(verticalScrollbarNode.scrollTop).toBe 5
|
||||
expect(verticalScrollbarNode.scrollTop).toBe 1
|
||||
|
||||
describe "when the mousewheel event's target is a line", ->
|
||||
it "keeps the line on the DOM if it is scrolled off-screen", ->
|
||||
@@ -1999,7 +1999,7 @@ describe "EditorComponent", ->
|
||||
hiddenParent.style.display = 'none'
|
||||
contentNode.appendChild(hiddenParent)
|
||||
|
||||
wrapperView = new EditorView(editor, {lineOverdrawMargin})
|
||||
wrapperView = new TextEditorView(editor, {lineOverdrawMargin})
|
||||
wrapperNode = wrapperView.element
|
||||
wrapperView.appendTo(hiddenParent)
|
||||
|
||||
@@ -2259,6 +2259,15 @@ describe "EditorComponent", ->
|
||||
editor.setGrammar(atom.syntax.nullGrammar)
|
||||
expect(wrapperNode.dataset.grammar).toBe 'text plain null-grammar'
|
||||
|
||||
describe "detaching and reattaching the editor (regression)", ->
|
||||
it "does not throw an exception", ->
|
||||
wrapperView.detach()
|
||||
wrapperView.attachToDom()
|
||||
|
||||
wrapperView.trigger('core:move-right')
|
||||
|
||||
expect(editor.getCursorBufferPosition()).toEqual [0, 1]
|
||||
|
||||
buildMouseEvent = (type, properties...) ->
|
||||
properties = extend({bubbles: true, cancelable: true}, properties...)
|
||||
properties.detail ?= 1
|
||||
@@ -1,7 +1,7 @@
|
||||
clipboard = require 'clipboard'
|
||||
Editor = require '../src/editor'
|
||||
TextEditor = require '../src/text-editor'
|
||||
|
||||
describe "Editor", ->
|
||||
describe "TextEditor", ->
|
||||
[buffer, editor, lineLengths] = []
|
||||
|
||||
convertToHardTabs = (buffer) ->
|
||||
@@ -49,7 +49,7 @@ describe "Editor", ->
|
||||
|
||||
state = editor.serialize()
|
||||
atom.config.set('editor.invisibles', eol: '?')
|
||||
editor2 = Editor.deserialize(state)
|
||||
editor2 = TextEditor.deserialize(state)
|
||||
|
||||
expect(editor2.displayBuffer.invisibles.eol).toBe '?'
|
||||
expect(editor2.displayBuffer.tokenizedBuffer.invisibles.eol).toBe '?'
|
||||
@@ -3263,6 +3263,9 @@ describe "Editor", ->
|
||||
runs ->
|
||||
expect(editor.softTabs).toBe false
|
||||
|
||||
atom.packages.deactivatePackage('language-coffee-script')
|
||||
atom.packages.unloadPackage('language-coffee-script')
|
||||
|
||||
describe ".destroy()", ->
|
||||
it "destroys all markers associated with the edit session", ->
|
||||
expect(buffer.getMarkerCount()).toBeGreaterThan 0
|
||||
@@ -3669,7 +3672,7 @@ describe "Editor", ->
|
||||
describe '.get/setPlaceholderText()', ->
|
||||
it 'can be created with placeholderText', ->
|
||||
TextBuffer = require 'text-buffer'
|
||||
newEditor = new Editor
|
||||
newEditor = new TextEditor
|
||||
buffer: new TextBuffer
|
||||
mini: true
|
||||
placeholderText: 'yep'
|
||||
@@ -52,7 +52,7 @@ describe "ThemeManager", ->
|
||||
|
||||
expect(themeManager.getEnabledThemeNames()).toEqual ['atom-dark-ui', 'atom-light-ui']
|
||||
|
||||
describe "getImportPaths()", ->
|
||||
describe "::getImportPaths()", ->
|
||||
it "returns the theme directories before the themes are loaded", ->
|
||||
atom.config.set('core.themes', ['theme-with-index-less', 'atom-dark-ui', 'atom-light-ui'])
|
||||
|
||||
@@ -129,7 +129,7 @@ describe "ThemeManager", ->
|
||||
spyOn(console, 'warn')
|
||||
expect(-> atom.packages.activatePackage('a-theme-that-will-not-be-found')).toThrow()
|
||||
|
||||
describe "requireStylesheet(path)", ->
|
||||
describe "::requireStylesheet(path)", ->
|
||||
it "synchronously loads css at the given path and installs a style tag for it in the head", ->
|
||||
themeManager.onDidChangeStylesheets stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
|
||||
themeManager.onDidAddStylesheet stylesheetAddedHandler = jasmine.createSpy("stylesheetAddedHandler")
|
||||
@@ -185,18 +185,17 @@ describe "ThemeManager", ->
|
||||
$('head style[id*="css.css"]').remove()
|
||||
$('head style[id*="sample.less"]').remove()
|
||||
|
||||
describe ".removeStylesheet(path)", ->
|
||||
it "removes styling applied by given stylesheet path", ->
|
||||
it "returns a disposable allowing styles applied by the given path to be removed", ->
|
||||
cssPath = require.resolve('./fixtures/css.css')
|
||||
|
||||
expect($(document.body).css('font-weight')).not.toBe("bold")
|
||||
themeManager.requireStylesheet(cssPath)
|
||||
disposable = themeManager.requireStylesheet(cssPath)
|
||||
expect($(document.body).css('font-weight')).toBe("bold")
|
||||
|
||||
themeManager.onDidRemoveStylesheet stylesheetRemovedHandler = jasmine.createSpy("stylesheetRemovedHandler")
|
||||
themeManager.onDidChangeStylesheets stylesheetsChangedHandler = jasmine.createSpy("stylesheetsChangedHandler")
|
||||
|
||||
themeManager.removeStylesheet(cssPath)
|
||||
disposable.dispose()
|
||||
|
||||
expect($(document.body).css('font-weight')).not.toBe("bold")
|
||||
|
||||
|
||||
@@ -586,7 +586,7 @@ describe "TokenizedBuffer", ->
|
||||
atom.config.set('editor.tabLength', 1)
|
||||
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
|
||||
atom.config.set('editor.tabLength', 0)
|
||||
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
|
||||
expect(tokenizedBuffer.tokenForPosition([0,0]).value).toBe ' '
|
||||
|
||||
describe "when the invisibles value changes", ->
|
||||
beforeEach ->
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{$, $$} = require 'atom'
|
||||
path = require 'path'
|
||||
Editor = require '../src/editor'
|
||||
TextEditor = require '../src/text-editor'
|
||||
WindowEventHandler = require '../src/window-event-handler'
|
||||
|
||||
describe "Window", ->
|
||||
@@ -59,7 +59,7 @@ describe "Window", ->
|
||||
[beforeUnloadEvent] = []
|
||||
|
||||
beforeEach ->
|
||||
jasmine.unspy(Editor.prototype, "shouldPromptToSave")
|
||||
jasmine.unspy(TextEditor.prototype, "shouldPromptToSave")
|
||||
beforeUnloadEvent = $.Event(new Event('beforeunload'))
|
||||
|
||||
describe "when pane items are are modified", ->
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Q = require 'q'
|
||||
path = require 'path'
|
||||
temp = require 'temp'
|
||||
EditorView = require '../src/editor-view'
|
||||
TextEditorView = require '../src/text-editor-view'
|
||||
PaneView = require '../src/pane-view'
|
||||
Workspace = require '../src/workspace'
|
||||
|
||||
@@ -253,7 +253,7 @@ describe "WorkspaceView", ->
|
||||
editorViewCreatedHandler = jasmine.createSpy('editorViewCreatedHandler')
|
||||
atom.workspaceView.eachEditorView(editorViewCreatedHandler)
|
||||
editorViewCreatedHandler.reset()
|
||||
miniEditor = new EditorView(mini: true)
|
||||
miniEditor = new TextEditorView(mini: true)
|
||||
atom.workspaceView.append(miniEditor)
|
||||
expect(editorViewCreatedHandler).not.toHaveBeenCalled()
|
||||
|
||||
|
||||
+6
-4
@@ -215,7 +215,7 @@ class Atom extends Model
|
||||
@deserializers.add(TextBuffer)
|
||||
TokenizedBuffer = require './tokenized-buffer'
|
||||
DisplayBuffer = require './display-buffer'
|
||||
Editor = require './editor'
|
||||
TextEditor = require './text-editor'
|
||||
|
||||
@windowEventHandler = new WindowEventHandler
|
||||
|
||||
@@ -466,9 +466,7 @@ class Atom extends Model
|
||||
console.warn error.message if error?
|
||||
|
||||
dimensions = @restoreWindowDimensions()
|
||||
@config.load()
|
||||
@config.setDefaults('core', require('./workspace-view').configDefaults)
|
||||
@config.setDefaults('editor', require('./editor-view').configDefaults)
|
||||
@loadConfig()
|
||||
@keymaps.loadBundledKeymaps()
|
||||
@themes.loadBaseStylesheets()
|
||||
@packages.loadPackages()
|
||||
@@ -604,6 +602,10 @@ class Atom extends Model
|
||||
@deserializeProject()
|
||||
@deserializeWorkspaceView()
|
||||
|
||||
loadConfig: ->
|
||||
@config.setSchema null, {type: 'object', properties: _.clone(require('./config-schema'))}
|
||||
@config.load()
|
||||
|
||||
loadThemes: ->
|
||||
@themes.load()
|
||||
|
||||
|
||||
@@ -492,6 +492,14 @@ class AtomApplication
|
||||
else
|
||||
BrowserWindow.getFocusedWindow()
|
||||
|
||||
openOptions =
|
||||
properties: properties.concat(['multiSelections', 'createDirectory'])
|
||||
title: 'Open'
|
||||
|
||||
if process.platform is 'linux'
|
||||
if projectPath = @lastFocusedWindow?.projectPath
|
||||
openOptions.defaultPath = projectPath
|
||||
|
||||
dialog = require 'dialog'
|
||||
dialog.showOpenDialog parentWindow, title: 'Open', properties: properties.concat(['multiSelections', 'createDirectory']), (pathsToOpen) =>
|
||||
dialog.showOpenDialog parentWindow, openOptions, (pathsToOpen) =>
|
||||
@openPaths({pathsToOpen, devMode, safeMode, window})
|
||||
|
||||
@@ -46,13 +46,15 @@ class CommandRegistry
|
||||
constructor: (@rootNode) ->
|
||||
@listenersByCommandName = {}
|
||||
|
||||
getRootNode: -> @rootNode
|
||||
|
||||
setRootNode: (newRootNode) ->
|
||||
oldRootNode = @rootNode
|
||||
@rootNode = newRootNode
|
||||
|
||||
for commandName of @listenersByCommandName
|
||||
oldRootNode?.removeEventListener(commandName, @dispatchCommand, true)
|
||||
newRootNode?.addEventListener(commandName, @dispatchCommand, true)
|
||||
@removeCommandListener(oldRootNode, commandName)
|
||||
@addCommandListener(newRootNode, commandName)
|
||||
|
||||
# Public: Add one or more command listeners associated with a selector.
|
||||
#
|
||||
@@ -88,7 +90,7 @@ class CommandRegistry
|
||||
return disposable
|
||||
|
||||
unless @listenersByCommandName[commandName]?
|
||||
@rootNode?.addEventListener(commandName, @dispatchCommand, true)
|
||||
@addCommandListener(@rootNode, commandName)
|
||||
@listenersByCommandName[commandName] = []
|
||||
|
||||
listener = new CommandListener(selector, callback)
|
||||
@@ -99,35 +101,7 @@ class CommandRegistry
|
||||
listenersForCommand.splice(listenersForCommand.indexOf(listener), 1)
|
||||
if listenersForCommand.length is 0
|
||||
delete @listenersByCommandName[commandName]
|
||||
@rootNode.removeEventListener(commandName, @dispatchCommand, true)
|
||||
|
||||
dispatchCommand: (event) =>
|
||||
propagationStopped = false
|
||||
immediatePropagationStopped = false
|
||||
currentTarget = event.target
|
||||
|
||||
syntheticEvent = Object.create event,
|
||||
eventPhase: value: Event.BUBBLING_PHASE
|
||||
currentTarget: get: -> currentTarget
|
||||
stopPropagation: value: ->
|
||||
propagationStopped = true
|
||||
stopImmediatePropagation: value: ->
|
||||
propagationStopped = true
|
||||
immediatePropagationStopped = true
|
||||
|
||||
loop
|
||||
matchingListeners =
|
||||
@listenersByCommandName[event.type]
|
||||
.filter (listener) -> currentTarget.webkitMatchesSelector(listener.selector)
|
||||
.sort (a, b) -> a.compare(b)
|
||||
|
||||
for listener in matchingListeners
|
||||
break if immediatePropagationStopped
|
||||
listener.callback.call(currentTarget, syntheticEvent)
|
||||
|
||||
break if propagationStopped
|
||||
break if currentTarget is @rootNode
|
||||
currentTarget = currentTarget.parentNode
|
||||
@removeCommandListener(@rootNode, commandName)
|
||||
|
||||
# Public: Find all registered commands matching a query.
|
||||
#
|
||||
@@ -154,6 +128,7 @@ class CommandRegistry
|
||||
|
||||
break if currentTarget is @rootNode
|
||||
currentTarget = currentTarget.parentNode
|
||||
break unless currentTarget?
|
||||
|
||||
for name, displayName of $(target).events() when displayName
|
||||
commands.push({name, displayName, jQuery: true})
|
||||
@@ -163,10 +138,91 @@ class CommandRegistry
|
||||
|
||||
commands
|
||||
|
||||
clear: ->
|
||||
# Public: Simulate the dispatch of a command on a DOM node.
|
||||
#
|
||||
# This can be useful for testing when you want to simulate the invocation of a
|
||||
# command on a detached DOM node. Otherwise, the DOM node in question needs to
|
||||
# be attached to the document so the event bubbles up to the root node to be
|
||||
# processed.
|
||||
#
|
||||
# * `target` The DOM node at which to start bubbling the command event.
|
||||
# * `commandName` {String} indicating the name of the command to dispatch.
|
||||
dispatch: (target, commandName) ->
|
||||
event = new CustomEvent(commandName, bubbles: true)
|
||||
eventWithTarget = Object.create(event, target: value: target)
|
||||
@handleCommandEvent(eventWithTarget)
|
||||
|
||||
getSnapshot: ->
|
||||
snapshot = {}
|
||||
for commandName, listeners of @listenersByCommandName
|
||||
snapshot[commandName] = listeners.slice()
|
||||
snapshot
|
||||
|
||||
restoreSnapshot: (snapshot) ->
|
||||
rootNode = @getRootNode()
|
||||
@setRootNode(null) # clear listeners for current commands
|
||||
@listenersByCommandName = {}
|
||||
for commandName, listeners of snapshot
|
||||
@listenersByCommandName[commandName] = listeners.slice()
|
||||
@setRootNode(rootNode) # restore listeners for commands in snapshot
|
||||
|
||||
handleCommandEvent: (originalEvent) =>
|
||||
originalEvent.__handledByCommandRegistry = true
|
||||
|
||||
propagationStopped = false
|
||||
immediatePropagationStopped = false
|
||||
matched = false
|
||||
currentTarget = originalEvent.target
|
||||
invokedListeners = []
|
||||
|
||||
syntheticEvent = Object.create originalEvent,
|
||||
eventPhase: value: Event.BUBBLING_PHASE
|
||||
currentTarget: get: -> currentTarget
|
||||
stopPropagation: value: ->
|
||||
originalEvent.stopPropagation()
|
||||
propagationStopped = true
|
||||
stopImmediatePropagation: value: ->
|
||||
originalEvent.stopImmediatePropagation()
|
||||
propagationStopped = true
|
||||
immediatePropagationStopped = true
|
||||
disableInvokedListeners: value: ->
|
||||
listener.enabled = false for listener in invokedListeners
|
||||
-> listener.enabled = true for listener in invokedListeners
|
||||
|
||||
loop
|
||||
matchingListeners =
|
||||
(@listenersByCommandName[originalEvent.type] ? [])
|
||||
.filter (listener) -> currentTarget.webkitMatchesSelector(listener.selector)
|
||||
.sort (a, b) -> a.compare(b)
|
||||
|
||||
matched = true if matchingListeners.length > 0
|
||||
|
||||
for listener in matchingListeners when listener.enabled
|
||||
break if immediatePropagationStopped
|
||||
invokedListeners.push(listener)
|
||||
listener.callback.call(currentTarget, syntheticEvent)
|
||||
|
||||
break if currentTarget is @rootNode
|
||||
break if propagationStopped
|
||||
currentTarget = currentTarget.parentNode
|
||||
break unless currentTarget?
|
||||
|
||||
matched
|
||||
|
||||
handleJQueryCommandEvent: (event) =>
|
||||
@handleCommandEvent(event) unless event.originalEvent?.__handledByCommandRegistry
|
||||
|
||||
addCommandListener: (node, commandName, listener) ->
|
||||
node?.addEventListener(commandName, @handleCommandEvent, true)
|
||||
$(node).on commandName, @handleJQueryCommandEvent
|
||||
|
||||
removeCommandListener: (node, commandName) ->
|
||||
node?.removeEventListener(commandName, @handleCommandEvent, true)
|
||||
$(node).off commandName, @handleJQueryCommandEvent
|
||||
|
||||
class CommandListener
|
||||
enabled: true
|
||||
|
||||
constructor: (@selector, @callback) ->
|
||||
@specificity = (SpecificityCache[@selector] ?= specificity(@selector))
|
||||
@sequenceNumber = SequenceCount++
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
path = require 'path'
|
||||
fs = require 'fs-plus'
|
||||
|
||||
# This is loaded by atom.coffee
|
||||
module.exports =
|
||||
core:
|
||||
type: 'object'
|
||||
properties:
|
||||
ignoredNames:
|
||||
type: 'array'
|
||||
default: [".git", ".hg", ".svn", ".DS_Store", "Thumbs.db"]
|
||||
items:
|
||||
type: 'string'
|
||||
excludeVcsIgnoredPaths:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
disabledPackages:
|
||||
type: 'array'
|
||||
default: []
|
||||
items:
|
||||
type: 'string'
|
||||
themes:
|
||||
type: 'array'
|
||||
default: ['atom-dark-ui', 'atom-dark-syntax']
|
||||
items:
|
||||
type: 'string'
|
||||
projectHome:
|
||||
type: 'string'
|
||||
default: path.join(fs.getHomeDirectory(), 'github')
|
||||
audioBeep:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
destroyEmptyPanes:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
|
||||
editor:
|
||||
type: 'object'
|
||||
properties:
|
||||
fontFamily:
|
||||
type: 'string'
|
||||
default: ''
|
||||
fontSize:
|
||||
type: 'integer'
|
||||
default: 16
|
||||
minimum: 1
|
||||
lineHeight:
|
||||
type: ['string', 'number']
|
||||
default: 1.3
|
||||
showInvisibles:
|
||||
type: 'boolean'
|
||||
default: false
|
||||
showIndentGuide:
|
||||
type: 'boolean'
|
||||
default: false
|
||||
showLineNumbers:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
autoIndent:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
normalizeIndentOnPaste:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
nonWordCharacters:
|
||||
type: 'string'
|
||||
default: "/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-"
|
||||
preferredLineLength:
|
||||
type: 'integer'
|
||||
default: 80
|
||||
minimum: 1
|
||||
tabLength:
|
||||
type: 'integer'
|
||||
default: 2
|
||||
minimum: 1
|
||||
softWrap:
|
||||
type: 'boolean'
|
||||
default: false
|
||||
softTabs:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
softWrapAtPreferredLineLength:
|
||||
type: 'boolean'
|
||||
default: false
|
||||
scrollSensitivity:
|
||||
type: 'integer'
|
||||
default: 40
|
||||
minimum: 10
|
||||
maximum: 200
|
||||
scrollPastEnd:
|
||||
type: 'boolean'
|
||||
default: false
|
||||
useHardwareAcceleration:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
confirmCheckoutHeadRevision:
|
||||
type: 'boolean'
|
||||
default: true
|
||||
invisibles:
|
||||
type: 'object'
|
||||
properties:
|
||||
eol:
|
||||
type: ['boolean', 'string']
|
||||
default: '\u00ac'
|
||||
space:
|
||||
type: ['boolean', 'string']
|
||||
default: '\u00b7'
|
||||
tab:
|
||||
type: ['boolean', 'string']
|
||||
default: '\u00bb'
|
||||
cr:
|
||||
type: ['boolean', 'string']
|
||||
default: '\u00a4'
|
||||
+670
-207
@@ -1,39 +1,510 @@
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
{Emitter} = require 'emissary'
|
||||
EmitterMixin = require('emissary').Emitter
|
||||
{Emitter} = require 'event-kit'
|
||||
CSON = require 'season'
|
||||
path = require 'path'
|
||||
async = require 'async'
|
||||
pathWatcher = require 'pathwatcher'
|
||||
{deprecate} = require 'grim'
|
||||
|
||||
# Essential: Used to access all of Atom's configuration details.
|
||||
#
|
||||
# An instance of this class is always available as the `atom.config` global.
|
||||
#
|
||||
# ## Best practices
|
||||
#
|
||||
# * Create your own root keypath using your package's name.
|
||||
# * Don't depend on (or write to) configuration keys outside of your keypath.
|
||||
#
|
||||
# ## Examples
|
||||
# ## Getting and setting config settings. Note that with no value set, {::get}
|
||||
# returns the setting's default value.
|
||||
#
|
||||
# ```coffee
|
||||
# atom.config.set('my-package.key', 'value')
|
||||
# atom.config.observe 'my-package.key', ->
|
||||
# console.log 'My configuration changed:', atom.config.get('my-package.key')
|
||||
# atom.config.get('my-package.myKey') # -> 'defaultValue'
|
||||
#
|
||||
# atom.config.set('my-package.myKey', 'value')
|
||||
# atom.config.get('my-package.myKey') # -> 'value'
|
||||
# ```
|
||||
#
|
||||
# You may want to watch for changes. Use {::observe} to catch changes to the setting.
|
||||
#
|
||||
# ```coffee
|
||||
# atom.config.set('my-package.myKey', 'value')
|
||||
# atom.config.observe 'my-package.myKey', (newValue) ->
|
||||
# # `observe` calls immediately and every time the value is changed
|
||||
# console.log 'My configuration changed:', newValue
|
||||
# ```
|
||||
#
|
||||
# If you want a notification only when the value changes, use {::onDidChange}.
|
||||
#
|
||||
# ```coffee
|
||||
# atom.config.onDidChange 'my-package.myKey', ({newValue, oldValue}) ->
|
||||
# console.log 'My configuration changed:', newValue, oldValue
|
||||
# ```
|
||||
#
|
||||
# ### Value Coercion
|
||||
#
|
||||
# Config settings each have a type specified by way of a
|
||||
# [schema](json-schema.org). For example we might an integer setting that only
|
||||
# allows integers greater than `0`:
|
||||
#
|
||||
# ```coffee
|
||||
# # When no value has been set, `::get` returns the setting's default value
|
||||
# atom.config.get('my-package.anInt') # -> 12
|
||||
#
|
||||
# # The string will be coerced to the integer 123
|
||||
# atom.config.set('my-package.anInt', '123')
|
||||
# atom.config.get('my-package.anInt') # -> 123
|
||||
#
|
||||
# # The string will be coerced to an integer, but it must be greater than 0, so is set to 1
|
||||
# atom.config.set('my-package.anInt', '-20')
|
||||
# atom.config.get('my-package.anInt') # -> 1
|
||||
# ```
|
||||
#
|
||||
# ## Defining settings for your package
|
||||
#
|
||||
# Define a schema under a `config` key in your package main.
|
||||
#
|
||||
# ```coffee
|
||||
# module.exports =
|
||||
# # Your config schema
|
||||
# config:
|
||||
# someInt:
|
||||
# type: 'integer'
|
||||
# default: 23
|
||||
# minimum: 1
|
||||
#
|
||||
# activate: (state) -> # ...
|
||||
# # ...
|
||||
# ```
|
||||
#
|
||||
# See [Creating a Package](https://atom.io/docs/latest/creating-a-package) for
|
||||
# more info.
|
||||
#
|
||||
# ## Config Schemas
|
||||
#
|
||||
# We use [json schema](json-schema.org) which allows you to define your value's
|
||||
# default, the type it should be, etc. A simple example:
|
||||
#
|
||||
# ```coffee
|
||||
# # We want to provide an `enableThing`, and a `thingVolume`
|
||||
# config:
|
||||
# enableThing:
|
||||
# type: 'boolean'
|
||||
# default: false
|
||||
# thingVolume:
|
||||
# type: 'integer'
|
||||
# default: 5
|
||||
# minimum: 1
|
||||
# maximum: 11
|
||||
# ```
|
||||
#
|
||||
# The type keyword allows for type coercion and validation. If a `thingVolume` is
|
||||
# set to a string `'10'`, it will be coerced into an integer.
|
||||
#
|
||||
# ```coffee
|
||||
# atom.config.set('my-package.thingVolume', '10')
|
||||
# atom.config.get('my-package.thingVolume') # -> 10
|
||||
#
|
||||
# # It respects the min / max
|
||||
# atom.config.set('my-package.thingVolume', '400')
|
||||
# atom.config.get('my-package.thingVolume') # -> 11
|
||||
#
|
||||
# # If it cannot be coerced, the value will not be set
|
||||
# atom.config.set('my-package.thingVolume', 'cats')
|
||||
# atom.config.get('my-package.thingVolume') # -> 11
|
||||
# ```
|
||||
#
|
||||
# ### Supported Types
|
||||
#
|
||||
# The `type` keyword can be a string with any one of the following. You can also
|
||||
# chain them by specifying multiple in an an array. For example
|
||||
#
|
||||
# ```coffee
|
||||
# config:
|
||||
# someSetting:
|
||||
# type: ['boolean', 'integer']
|
||||
# default: 5
|
||||
#
|
||||
# # Then
|
||||
# atom.config.set('my-package.someSetting', 'true')
|
||||
# atom.config.get('my-package.someSetting') # -> true
|
||||
#
|
||||
# atom.config.set('my-package.someSetting', '12')
|
||||
# atom.config.get('my-package.someSetting') # -> 12
|
||||
# ```
|
||||
#
|
||||
# #### string
|
||||
#
|
||||
# Values must be a string.
|
||||
#
|
||||
# ```coffee
|
||||
# config:
|
||||
# someSetting:
|
||||
# type: 'string'
|
||||
# default: 'hello'
|
||||
# ```
|
||||
#
|
||||
# #### integer
|
||||
#
|
||||
# Values will be coerced into integer. Supports the (optional) `minimum` and
|
||||
# `maximum` keys.
|
||||
#
|
||||
# ```coffee
|
||||
# config:
|
||||
# someSetting:
|
||||
# type: 'integer'
|
||||
# default: 5
|
||||
# minimum: 1
|
||||
# maximum: 11
|
||||
# ```
|
||||
#
|
||||
# #### number
|
||||
#
|
||||
# Values will be coerced into a number, including real numbers. Supports the
|
||||
# (optional) `minimum` and `maximum` keys.
|
||||
#
|
||||
# ```coffee
|
||||
# config:
|
||||
# someSetting:
|
||||
# type: 'number'
|
||||
# default: 5.3
|
||||
# minimum: 1.5
|
||||
# maximum: 11.5
|
||||
# ```
|
||||
#
|
||||
# #### boolean
|
||||
#
|
||||
# Values will be coerced into a Boolean. `'true'` and `'false'` will be coerced into
|
||||
# a boolean. Numbers, arrays, objects, and anything else will not be coerced.
|
||||
#
|
||||
# ```coffee
|
||||
# config:
|
||||
# someSetting:
|
||||
# type: 'boolean'
|
||||
# default: false
|
||||
# ```
|
||||
#
|
||||
# #### array
|
||||
#
|
||||
# Value must be an Array. The types of the values can be specified by a
|
||||
# subschema in the `items` key.
|
||||
#
|
||||
# ```coffee
|
||||
# config:
|
||||
# someSetting:
|
||||
# type: 'array'
|
||||
# default: [1, 2, 3]
|
||||
# items:
|
||||
# type: 'integer'
|
||||
# minimum: 1.5
|
||||
# maximum: 11.5
|
||||
# ```
|
||||
#
|
||||
# #### object
|
||||
#
|
||||
# Value must be an object. This allows you to nest config options. Sub options
|
||||
# must be under a `properties key`
|
||||
#
|
||||
# ```coffee
|
||||
# config:
|
||||
# someSetting:
|
||||
# type: 'object'
|
||||
# properties:
|
||||
# myChildIntOption:
|
||||
# type: 'integer'
|
||||
# minimum: 1.5
|
||||
# maximum: 11.5
|
||||
# ```
|
||||
#
|
||||
# ### Other Supported Keys
|
||||
#
|
||||
# #### enum
|
||||
#
|
||||
# All types support an `enum` key. The enum key lets you specify all values
|
||||
# that the config setting can possibly be. `enum` _must_ be an array of values
|
||||
# of your specified type.
|
||||
#
|
||||
# ```coffee
|
||||
# config:
|
||||
# someSetting:
|
||||
# type: 'integer'
|
||||
# default: 4
|
||||
# enum: [2, 4, 6, 8]
|
||||
# ```
|
||||
#
|
||||
# ```coffee
|
||||
# atom.config.set('my-package.someSetting', '2')
|
||||
# atom.config.get('my-package.someSetting') # -> 2
|
||||
#
|
||||
# # will not set values outside of the enum values
|
||||
# atom.config.set('my-package.someSetting', '3')
|
||||
# atom.config.get('my-package.someSetting') # -> 2
|
||||
#
|
||||
# # If it cannot be coerced, the value will not be set
|
||||
# atom.config.set('my-package.someSetting', '4')
|
||||
# atom.config.get('my-package.someSetting') # -> 4
|
||||
# ```
|
||||
#
|
||||
# #### title and description
|
||||
#
|
||||
# The settings view will use the `title` and `description` keys to display your
|
||||
# config setting in a readable way. By default the settings view humanizes your
|
||||
# config key, so `someSetting` becomes `Some Setting`. In some cases, this is
|
||||
# confusing for users, and a more descriptive title is useful.
|
||||
#
|
||||
# Descriptions will be displayed below the title in the settings view.
|
||||
#
|
||||
# ```coffee
|
||||
# config:
|
||||
# someSetting:
|
||||
# title: 'Setting Magnitude'
|
||||
# description: 'This will affect the blah and the other blah'
|
||||
# type: 'integer'
|
||||
# default: 4
|
||||
# ```
|
||||
#
|
||||
# __Note__: You should strive to be so clear in your naming of the setting that
|
||||
# you do not need to specify a title or description!
|
||||
#
|
||||
# ## Best practices
|
||||
#
|
||||
# * Don't depend on (or write to) configuration keys outside of your keypath.
|
||||
#
|
||||
module.exports =
|
||||
class Config
|
||||
Emitter.includeInto(this)
|
||||
EmitterMixin.includeInto(this)
|
||||
@schemaEnforcers = {}
|
||||
|
||||
@addSchemaEnforcer: (typeName, enforcerFunction) ->
|
||||
@schemaEnforcers[typeName] ?= []
|
||||
@schemaEnforcers[typeName].push(enforcerFunction)
|
||||
|
||||
@addSchemaEnforcers: (filters) ->
|
||||
for typeName, functions of filters
|
||||
for name, enforcerFunction of functions
|
||||
@addSchemaEnforcer(typeName, enforcerFunction)
|
||||
|
||||
@executeSchemaEnforcers: (keyPath, value, schema) ->
|
||||
error = null
|
||||
types = schema.type
|
||||
types = [types] unless Array.isArray(types)
|
||||
for type in types
|
||||
try
|
||||
enforcerFunctions = @schemaEnforcers[type].concat(@schemaEnforcers['*'])
|
||||
for enforcer in enforcerFunctions
|
||||
# At some point in one's life, one must call upon an enforcer.
|
||||
value = enforcer.call(this, keyPath, value, schema)
|
||||
error = null
|
||||
break
|
||||
catch e
|
||||
error = e
|
||||
|
||||
throw error if error?
|
||||
value
|
||||
|
||||
# Created during initialization, available as `atom.config`
|
||||
constructor: ({@configDirPath, @resourcePath}={}) ->
|
||||
@emitter = new Emitter
|
||||
@schema =
|
||||
type: 'object'
|
||||
properties: {}
|
||||
@defaultSettings = {}
|
||||
@settings = {}
|
||||
@configFileHasErrors = false
|
||||
@configFilePath = fs.resolve(@configDirPath, 'config', ['json', 'cson'])
|
||||
@configFilePath ?= path.join(@configDirPath, 'config.cson')
|
||||
|
||||
###
|
||||
Section: Config Subscription
|
||||
###
|
||||
|
||||
# Essential: Add a listener for changes to a given key path. This is different
|
||||
# than {::onDidChange} in that it will immediately call your callback with the
|
||||
# current value of the config entry.
|
||||
#
|
||||
# * `keyPath` {String} name of the key to observe
|
||||
# * `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: (keyPath, options={}, callback) ->
|
||||
if _.isFunction(options)
|
||||
callback = options
|
||||
options = {}
|
||||
else
|
||||
message = ""
|
||||
message = "`callNow` was set to false. Use ::onDidChange instead. Note that ::onDidChange calls back with different arguments." if options.callNow == false
|
||||
deprecate "Config::observe no longer supports options. #{message}"
|
||||
|
||||
callback(_.clone(@get(keyPath))) unless options.callNow == false
|
||||
@emitter.on 'did-change', (event) =>
|
||||
callback(event.newValue) if keyPath? and keyPath.indexOf(event?.keyPath) is 0
|
||||
|
||||
# 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.
|
||||
#
|
||||
# * `keyPath` (optional) {String} name of the key to observe
|
||||
# * `callback` {Function} to call when the value of the key changes.
|
||||
# * `event` {Object}
|
||||
# * `newValue` the new value of the key
|
||||
# * `oldValue` the prior value of the key.
|
||||
# * `keyPath` the keyPath of the changed key
|
||||
#
|
||||
# Returns a {Disposable} with the following keys on which you can call
|
||||
# `.dispose()` to unsubscribe.
|
||||
onDidChange: (keyPath, callback) ->
|
||||
if arguments.length is 1
|
||||
callback = keyPath
|
||||
keyPath = undefined
|
||||
|
||||
@emitter.on 'did-change', (event) =>
|
||||
callback(event) if not keyPath? or (keyPath? and keyPath.indexOf(event?.keyPath) is 0)
|
||||
|
||||
###
|
||||
Section: Managing Settings
|
||||
###
|
||||
|
||||
# Essential: Retrieves the setting for the given key.
|
||||
#
|
||||
# * `keyPath` The {String} name of the key to retrieve.
|
||||
#
|
||||
# Returns the value from Atom's default settings, the user's configuration
|
||||
# file in the type specified by the configuration schema.
|
||||
get: (keyPath) ->
|
||||
value = _.valueForKeyPath(@settings, keyPath)
|
||||
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
|
||||
|
||||
if value?
|
||||
value = _.deepClone(value)
|
||||
valueIsObject = _.isObject(value) and not _.isArray(value)
|
||||
defaultValueIsObject = _.isObject(defaultValue) and not _.isArray(defaultValue)
|
||||
if valueIsObject and defaultValueIsObject
|
||||
_.defaults(value, defaultValue)
|
||||
else
|
||||
value = _.deepClone(defaultValue)
|
||||
|
||||
value
|
||||
|
||||
# Essential: Sets the value for a configuration setting.
|
||||
#
|
||||
# This value is stored in Atom's internal configuration file.
|
||||
#
|
||||
# * `keyPath` The {String} name of the key.
|
||||
# * `value` The value of the setting. Passing `undefined` will revert the
|
||||
# setting to the default value.
|
||||
#
|
||||
# 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: (keyPath, value) ->
|
||||
unless value == undefined
|
||||
try
|
||||
value = @makeValueConformToSchema(keyPath, value)
|
||||
catch e
|
||||
return false
|
||||
|
||||
@setRawValue(keyPath, value)
|
||||
@save() unless @configFileHasErrors
|
||||
true
|
||||
|
||||
# Extended: Restore the key path to its default value.
|
||||
#
|
||||
# * `keyPath` The {String} name of the key.
|
||||
#
|
||||
# Returns the new value.
|
||||
restoreDefault: (keyPath) ->
|
||||
@set(keyPath, _.valueForKeyPath(@defaultSettings, keyPath))
|
||||
@get(keyPath)
|
||||
|
||||
# Extended: Get the 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.
|
||||
#
|
||||
# * `keyPath` The {String} name of the key.
|
||||
#
|
||||
# Returns the default value.
|
||||
getDefault: (keyPath) ->
|
||||
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
|
||||
_.deepClone(defaultValue)
|
||||
|
||||
# Extended: Is the key path value its default value?
|
||||
#
|
||||
# * `keyPath` The {String} name of the key.
|
||||
#
|
||||
# Returns a {Boolean}, `true` if the current value is the default, `false`
|
||||
# otherwise.
|
||||
isDefault: (keyPath) ->
|
||||
not _.valueForKeyPath(@settings, keyPath)?
|
||||
|
||||
# Extended: Retrieve the schema for a specific key path. The shema will tell
|
||||
# you what type the keyPath expects, and other metadata about the config
|
||||
# option.
|
||||
#
|
||||
# * `keyPath` The {String} name of the key.
|
||||
#
|
||||
# Returns an {Object} eg. `{type: 'integer', default: 23, minimum: 1}`.
|
||||
# Returns `null` when the keyPath has no schema specified.
|
||||
getSchema: (keyPath) ->
|
||||
keys = keyPath.split('.')
|
||||
schema = @schema
|
||||
for key in keys
|
||||
break unless schema?
|
||||
schema = schema.properties[key]
|
||||
schema
|
||||
|
||||
# Extended: Returns a new {Object} containing all of settings and defaults.
|
||||
getSettings: ->
|
||||
_.deepExtend(@settings, @defaultSettings)
|
||||
|
||||
# Extended: Get the {String} path to the config file being used.
|
||||
getUserConfigPath: ->
|
||||
@configFilePath
|
||||
|
||||
###
|
||||
Section: Deprecated
|
||||
###
|
||||
|
||||
getInt: (keyPath) ->
|
||||
deprecate '''Config::getInt is no longer necessary. Use ::get instead.
|
||||
Make sure the config option you are accessing has specified an `integer`
|
||||
schema. See the schema section of
|
||||
https://atom.io/docs/api/latest/Config for more info.'''
|
||||
parseInt(@get(keyPath))
|
||||
|
||||
getPositiveInt: (keyPath, defaultValue=0) ->
|
||||
deprecate '''Config::getPositiveInt is no longer necessary. Use ::get instead.
|
||||
Make sure the config option you are accessing has specified an `integer`
|
||||
schema with `minimum: 1`. See the schema section of
|
||||
https://atom.io/docs/api/latest/Config for more info.'''
|
||||
Math.max(@getInt(keyPath), 0) or defaultValue
|
||||
|
||||
toggle: (keyPath) ->
|
||||
deprecate 'Config::toggle is no longer supported. Please remove from your code.'
|
||||
@set(keyPath, !@get(keyPath))
|
||||
|
||||
unobserve: (keyPath) ->
|
||||
deprecate 'Config::unobserve no longer does anything. Call `.dispose()` on the object returned by Config::observe instead.'
|
||||
|
||||
###
|
||||
Section: Private
|
||||
###
|
||||
|
||||
pushAtKeyPath: (keyPath, value) ->
|
||||
arrayValue = @get(keyPath) ? []
|
||||
result = arrayValue.push(value)
|
||||
@set(keyPath, arrayValue)
|
||||
result
|
||||
|
||||
unshiftAtKeyPath: (keyPath, value) ->
|
||||
arrayValue = @get(keyPath) ? []
|
||||
result = arrayValue.unshift(value)
|
||||
@set(keyPath, arrayValue)
|
||||
result
|
||||
|
||||
removeAtKeyPath: (keyPath, value) ->
|
||||
arrayValue = @get(keyPath) ? []
|
||||
result = _.remove(arrayValue, value)
|
||||
@set(keyPath, arrayValue)
|
||||
result
|
||||
|
||||
initializeConfigDirectory: (done) ->
|
||||
return if fs.existsSync(@configDirPath)
|
||||
|
||||
@@ -62,210 +533,202 @@ class Config
|
||||
|
||||
try
|
||||
userConfig = CSON.readFileSync(@configFilePath)
|
||||
_.extend(@settings, userConfig)
|
||||
@settings = {} # Reset to the defaults
|
||||
if isPlainObject(userConfig)
|
||||
@setRecursive(null, userConfig)
|
||||
else
|
||||
@emitter.emit 'did-change'
|
||||
@configFileHasErrors = false
|
||||
@emit 'updated'
|
||||
catch e
|
||||
catch error
|
||||
@configFileHasErrors = true
|
||||
console.error "Failed to load user config '#{@configFilePath}'", e.message
|
||||
console.error e.stack
|
||||
console.error "Failed to load user config '#{@configFilePath}'", error.message
|
||||
console.error error.stack
|
||||
|
||||
observeUserConfig: ->
|
||||
@watchSubscription ?= pathWatcher.watch @configFilePath, (eventType) =>
|
||||
@loadUserConfig() if eventType is 'change' and @watchSubscription?
|
||||
try
|
||||
@watchSubscription ?= pathWatcher.watch @configFilePath, (eventType) =>
|
||||
@loadUserConfig() if eventType is 'change' and @watchSubscription?
|
||||
catch error
|
||||
console.error "Failed to watch user config '#{@configFilePath}'", error.message
|
||||
console.error error.stack
|
||||
|
||||
unobserveUserConfig: ->
|
||||
@watchSubscription?.close()
|
||||
@watchSubscription = null
|
||||
|
||||
setDefaults: (keyPath, defaults) ->
|
||||
keys = keyPath.split('.')
|
||||
hash = @defaultSettings
|
||||
for key in keys
|
||||
hash[key] ?= {}
|
||||
hash = hash[key]
|
||||
|
||||
_.extend hash, defaults
|
||||
@emit 'updated'
|
||||
|
||||
# Extended: Get the {String} path to the config file being used.
|
||||
getUserConfigPath: ->
|
||||
@configFilePath
|
||||
|
||||
# Extended: Returns a new {Object} containing all of settings and defaults.
|
||||
getSettings: ->
|
||||
_.deepExtend(@settings, @defaultSettings)
|
||||
|
||||
# Essential: Retrieves the setting for the given key.
|
||||
#
|
||||
# * `keyPath` The {String} name of the key to retrieve.
|
||||
#
|
||||
# Returns the value from Atom's default settings, the user's configuration
|
||||
# file, or `null` if the key doesn't exist in either.
|
||||
get: (keyPath) ->
|
||||
value = _.valueForKeyPath(@settings, keyPath)
|
||||
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
|
||||
|
||||
if value?
|
||||
value = _.deepClone(value)
|
||||
valueIsObject = _.isObject(value) and not _.isArray(value)
|
||||
defaultValueIsObject = _.isObject(defaultValue) and not _.isArray(defaultValue)
|
||||
if valueIsObject and defaultValueIsObject
|
||||
_.defaults(value, defaultValue)
|
||||
else
|
||||
value = _.deepClone(defaultValue)
|
||||
|
||||
value
|
||||
|
||||
# Extended: Retrieves the setting for the given key as an integer.
|
||||
#
|
||||
# * `keyPath` The {String} name of the key to retrieve
|
||||
#
|
||||
# Returns the value from Atom's default settings, the user's configuration
|
||||
# file, or `NaN` if the key doesn't exist in either.
|
||||
getInt: (keyPath) ->
|
||||
parseInt(@get(keyPath))
|
||||
|
||||
# Extended: Retrieves the setting for the given key as a positive integer.
|
||||
#
|
||||
# * `keyPath` The {String} name of the key to retrieve
|
||||
# * `defaultValue` The integer {Number} to fall back to if the value isn't
|
||||
# positive, defaults to 0.
|
||||
#
|
||||
# Returns the value from Atom's default settings, the user's configuration
|
||||
# file, or `defaultValue` if the key value isn't greater than zero.
|
||||
getPositiveInt: (keyPath, defaultValue=0) ->
|
||||
Math.max(@getInt(keyPath), 0) or defaultValue
|
||||
|
||||
# Essential: Sets the value for a configuration setting.
|
||||
#
|
||||
# This value is stored in Atom's internal configuration file.
|
||||
#
|
||||
# * `keyPath` The {String} name of the key.
|
||||
# * `value` The value of the setting.
|
||||
#
|
||||
# Returns the `value`.
|
||||
set: (keyPath, value) ->
|
||||
if @get(keyPath) isnt value
|
||||
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
|
||||
value = undefined if _.isEqual(defaultValue, value)
|
||||
_.setValueForKeyPath(@settings, keyPath, value)
|
||||
@update()
|
||||
value
|
||||
|
||||
# Extended: Toggle the value at the key path.
|
||||
#
|
||||
# The new value will be `true` if the value is currently falsy and will be
|
||||
# `false` if the value is currently truthy.
|
||||
#
|
||||
# * `keyPath` The {String} name of the key.
|
||||
#
|
||||
# Returns the new value.
|
||||
toggle: (keyPath) ->
|
||||
@set(keyPath, !@get(keyPath))
|
||||
|
||||
# Extended: Restore the key path to its default value.
|
||||
#
|
||||
# * `keyPath` The {String} name of the key.
|
||||
#
|
||||
# Returns the new value.
|
||||
restoreDefault: (keyPath) ->
|
||||
@set(keyPath, _.valueForKeyPath(@defaultSettings, keyPath))
|
||||
|
||||
# Extended: Get the default value of the key path.
|
||||
#
|
||||
# * `keyPath` The {String} name of the key.
|
||||
#
|
||||
# Returns the default value.
|
||||
getDefault: (keyPath) ->
|
||||
defaultValue = _.valueForKeyPath(@defaultSettings, keyPath)
|
||||
_.deepClone(defaultValue)
|
||||
|
||||
# Extended: Is the key path value its default value?
|
||||
#
|
||||
# * `keyPath` The {String} name of the key.
|
||||
#
|
||||
# Returns a {Boolean}, `true` if the current value is the default, `false`
|
||||
# otherwise.
|
||||
isDefault: (keyPath) ->
|
||||
not _.valueForKeyPath(@settings, keyPath)?
|
||||
|
||||
# Extended: Push the value to the array at the key path.
|
||||
#
|
||||
# * `keyPath` The {String} key path.
|
||||
# * `value` The value to push to the array.
|
||||
#
|
||||
# Returns the new array length {Number} of the setting.
|
||||
pushAtKeyPath: (keyPath, value) ->
|
||||
arrayValue = @get(keyPath) ? []
|
||||
result = arrayValue.push(value)
|
||||
@set(keyPath, arrayValue)
|
||||
result
|
||||
|
||||
# Extended: Add the value to the beginning of the array at the key path.
|
||||
#
|
||||
# * `keyPath` The {String} key path.
|
||||
# * `value` The value to shift onto the array.
|
||||
#
|
||||
# Returns the new array length {Number} of the setting.
|
||||
unshiftAtKeyPath: (keyPath, value) ->
|
||||
arrayValue = @get(keyPath) ? []
|
||||
result = arrayValue.unshift(value)
|
||||
@set(keyPath, arrayValue)
|
||||
result
|
||||
|
||||
# Public: Remove the value from the array at the key path.
|
||||
#
|
||||
# * `keyPath` The {String} key path.
|
||||
# * `value` The value to remove from the array.
|
||||
#
|
||||
# Returns the new array value of the setting.
|
||||
removeAtKeyPath: (keyPath, value) ->
|
||||
arrayValue = @get(keyPath) ? []
|
||||
result = _.remove(arrayValue, value)
|
||||
@set(keyPath, arrayValue)
|
||||
result
|
||||
|
||||
# Essential: Add a listener for changes to a given key path.
|
||||
#
|
||||
# * `keyPath` The {String} name of the key to observe
|
||||
# * `options` An optional {Object} containing the `callNow` key.
|
||||
# * `callback` The {Function} to call when the value of the key changes.
|
||||
# The first argument will be the new value of the key and the
|
||||
# second argument will be an {Object} with a `previous` property
|
||||
# that is the prior value of the key.
|
||||
#
|
||||
# Returns an {Object} with the following keys:
|
||||
# * `off` A {Function} that unobserves the `keyPath` when called.
|
||||
observe: (keyPath, options={}, callback) ->
|
||||
if _.isFunction(options)
|
||||
callback = options
|
||||
options = {}
|
||||
|
||||
value = @get(keyPath)
|
||||
previousValue = _.clone(value)
|
||||
updateCallback = =>
|
||||
value = @get(keyPath)
|
||||
unless _.isEqual(value, previousValue)
|
||||
previous = previousValue
|
||||
previousValue = _.clone(value)
|
||||
callback(value, {previous})
|
||||
|
||||
eventName = "updated.#{keyPath.replace(/\./, '-')}"
|
||||
subscription = @on eventName, updateCallback
|
||||
callback(value) if options.callNow ? true
|
||||
subscription
|
||||
|
||||
# Unobserve all callbacks on a given key.
|
||||
#
|
||||
# * `keyPath` The {String} name of the key to unobserve.
|
||||
unobserve: (keyPath) ->
|
||||
@off("updated.#{keyPath.replace(/\./, '-')}")
|
||||
|
||||
update: ->
|
||||
return if @configFileHasErrors
|
||||
@save()
|
||||
@emit 'updated'
|
||||
|
||||
save: ->
|
||||
CSON.writeFileSync(@configFilePath, @settings)
|
||||
|
||||
setRawValue: (keyPath, value) ->
|
||||
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} if newValue isnt oldValue
|
||||
|
||||
setRawDefault: (keyPath, value) ->
|
||||
oldValue = _.clone(@get(keyPath))
|
||||
_.setValueForKeyPath(@defaultSettings, keyPath, value)
|
||||
newValue = @get(keyPath)
|
||||
@emitter.emit 'did-change', {oldValue, newValue, keyPath} if newValue isnt oldValue
|
||||
|
||||
setRecursive: (keyPath, value) ->
|
||||
if value? and isPlainObject(value)
|
||||
keys = if keyPath? then keyPath.split('.') else []
|
||||
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))}")
|
||||
|
||||
return
|
||||
|
||||
setDefaults: (keyPath, defaults) ->
|
||||
if defaults? and isPlainObject(defaults)
|
||||
keys = if keyPath? then keyPath.split('.') else []
|
||||
for key, childValue of defaults
|
||||
continue unless defaults.hasOwnProperty(key)
|
||||
@setDefaults(keys.concat([key]).join('.'), childValue)
|
||||
else
|
||||
try
|
||||
defaults = @makeValueConformToSchema(keyPath, defaults)
|
||||
@setRawDefault(keyPath, defaults)
|
||||
catch e
|
||||
console.warn("'#{keyPath}' could not set the default. Attempted default: #{JSON.stringify(defaults)}; Schema: #{JSON.stringify(@getSchema(keyPath))}")
|
||||
|
||||
setSchema: (keyPath, schema) ->
|
||||
unless isPlainObject(schema)
|
||||
throw new Error("Error loading schema for #{keyPath}: schemas can only be objects!")
|
||||
|
||||
unless typeof schema.type?
|
||||
throw new Error("Error loading schema for #{keyPath}: schema objects must have a type attribute")
|
||||
|
||||
rootSchema = @schema
|
||||
if keyPath
|
||||
for key in keyPath.split('.')
|
||||
rootSchema.type = 'object'
|
||||
rootSchema.properties ?= {}
|
||||
properties = rootSchema.properties
|
||||
properties[key] ?= {}
|
||||
rootSchema = properties[key]
|
||||
|
||||
_.extend rootSchema, schema
|
||||
@setDefaults(keyPath, @extractDefaultsFromSchema(schema))
|
||||
|
||||
extractDefaultsFromSchema: (schema) ->
|
||||
if schema.default?
|
||||
schema.default
|
||||
else if schema.type is 'object' and schema.properties? and isPlainObject(schema.properties)
|
||||
defaults = {}
|
||||
properties = schema.properties or {}
|
||||
defaults[key] = @extractDefaultsFromSchema(value) for key, value of properties
|
||||
defaults
|
||||
|
||||
makeValueConformToSchema: (keyPath, value) ->
|
||||
value = @constructor.executeSchemaEnforcers(keyPath, value, schema) if schema = @getSchema(keyPath)
|
||||
value
|
||||
|
||||
# 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
|
||||
# will indicate that the value should not be set.
|
||||
#
|
||||
# Enforcers are run from most specific to least. For a schema with type
|
||||
# `integer`, all the enforcers for the `integer` type will be run first, in
|
||||
# order of specification. Then the `*` enforcers will be run, in order of
|
||||
# specification.
|
||||
Config.addSchemaEnforcers
|
||||
'integer':
|
||||
coerce: (keyPath, value, schema) ->
|
||||
value = parseInt(value)
|
||||
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} cannot be coerced into an int") if isNaN(value) or not isFinite(value)
|
||||
value
|
||||
|
||||
'number':
|
||||
coerce: (keyPath, value, schema) ->
|
||||
value = parseFloat(value)
|
||||
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} cannot be coerced into a number") if isNaN(value) or not isFinite(value)
|
||||
value
|
||||
|
||||
'boolean':
|
||||
coerce: (keyPath, value, schema) ->
|
||||
switch typeof value
|
||||
when 'string'
|
||||
if value.toLowerCase() is 'true'
|
||||
true
|
||||
else if value.toLowerCase() is 'false'
|
||||
false
|
||||
else
|
||||
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be a boolean or the string 'true' or 'false'")
|
||||
when 'boolean'
|
||||
value
|
||||
else
|
||||
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be a boolean or the string 'true' or 'false'")
|
||||
|
||||
'string':
|
||||
validate: (keyPath, value, schema) ->
|
||||
unless typeof value is 'string'
|
||||
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be a string")
|
||||
value
|
||||
|
||||
'null':
|
||||
# null sort of isnt supported. It will just unset in this case
|
||||
coerce: (keyPath, value, schema) ->
|
||||
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be null") unless value == null
|
||||
value
|
||||
|
||||
'object':
|
||||
coerce: (keyPath, value, schema) ->
|
||||
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be an object") unless isPlainObject(value)
|
||||
return value unless schema.properties?
|
||||
|
||||
newValue = {}
|
||||
for prop, childSchema of schema.properties
|
||||
continue unless value.hasOwnProperty(prop)
|
||||
try
|
||||
newValue[prop] = @executeSchemaEnforcers("#{keyPath}.#{prop}", value[prop], childSchema)
|
||||
catch error
|
||||
console.warn "Error setting item in object: #{error.message}"
|
||||
newValue
|
||||
|
||||
'array':
|
||||
coerce: (keyPath, value, schema) ->
|
||||
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be an array") unless Array.isArray(value)
|
||||
itemSchema = schema.items
|
||||
if itemSchema?
|
||||
newValue = []
|
||||
for item in value
|
||||
try
|
||||
newValue.push @executeSchemaEnforcers(keyPath, item, itemSchema)
|
||||
catch error
|
||||
console.warn "Error setting item in array: #{error.message}"
|
||||
newValue
|
||||
else
|
||||
value
|
||||
|
||||
'*':
|
||||
coerceMinimumAndMaximum: (keyPath, value, schema) ->
|
||||
return value unless typeof value is 'number'
|
||||
if schema.minimum? and typeof schema.minimum is 'number'
|
||||
value = Math.max(value, schema.minimum)
|
||||
if schema.maximum? and typeof schema.maximum is 'number'
|
||||
value = Math.min(value, schema.maximum)
|
||||
value
|
||||
|
||||
validateEnum: (keyPath, value, schema) ->
|
||||
possibleValues = schema.enum
|
||||
return value unless possibleValues? and Array.isArray(possibleValues) and possibleValues.length
|
||||
|
||||
for possibleValue in possibleValues
|
||||
# Using `isEqual` for possibility of placing enums on array and object schemas
|
||||
return value if _.isEqual(possibleValue, value)
|
||||
|
||||
throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} is not one of #{JSON.stringify(possibleValues)}")
|
||||
|
||||
isPlainObject = (value) ->
|
||||
_.isObject(value) and not _.isArray(value) and not _.isFunction(value) and not _.isString(value)
|
||||
|
||||
+5
-5
@@ -7,7 +7,7 @@ Grim = require 'grim'
|
||||
# Extended: The `Cursor` class represents the little blinking line identifying
|
||||
# where text can be inserted.
|
||||
#
|
||||
# Cursors belong to {Editor}s and have some metadata attached in the form
|
||||
# Cursors belong to {TextEditor}s and have some metadata attached in the form
|
||||
# of a {Marker}.
|
||||
module.exports =
|
||||
class Cursor extends Model
|
||||
@@ -17,7 +17,7 @@ class Cursor extends Model
|
||||
visible: true
|
||||
needsAutoscroll: null
|
||||
|
||||
# Instantiated by an {Editor}
|
||||
# Instantiated by an {TextEditor}
|
||||
constructor: ({@editor, @marker, id}) ->
|
||||
@emitter = new Emitter
|
||||
|
||||
@@ -114,7 +114,7 @@ class Cursor extends Model
|
||||
#
|
||||
# * `screenPosition` {Array} of two numbers: the screen row, and the screen column.
|
||||
# * `options` (optional) {Object} with the following keys:
|
||||
# * `autoscroll` A Boolean which, if `true`, scrolls the {Editor} to wherever
|
||||
# * `autoscroll` A Boolean which, if `true`, scrolls the {TextEditor} to wherever
|
||||
# the cursor moves to.
|
||||
setScreenPosition: (screenPosition, options={}) ->
|
||||
@changePosition options, =>
|
||||
@@ -128,7 +128,7 @@ class Cursor extends Model
|
||||
#
|
||||
# * `bufferPosition` {Array} of two numbers: the buffer row, and the buffer column.
|
||||
# * `options` (optional) {Object} with the following keys:
|
||||
# * `autoscroll` A Boolean which, if `true`, scrolls the {Editor} to wherever
|
||||
# * `autoscroll` A Boolean which, if `true`, scrolls the {TextEditor} to wherever
|
||||
# the cursor moves to.
|
||||
setBufferPosition: (bufferPosition, options={}) ->
|
||||
@changePosition options, =>
|
||||
@@ -232,7 +232,7 @@ class Cursor extends Model
|
||||
else
|
||||
bufferPosition.column > firstCharacterColumn
|
||||
|
||||
# Public: Identifies if this cursor is the last in the {Editor}.
|
||||
# Public: Identifies if this cursor is the last in the {TextEditor}.
|
||||
#
|
||||
# "Last" is defined as the most recently added cursor.
|
||||
#
|
||||
|
||||
@@ -12,7 +12,7 @@ nextId = -> idCounter++
|
||||
# around marked ranges of text.
|
||||
#
|
||||
# {Decoration} objects are not meant to be created directly, but created with
|
||||
# {Editor::decorateMarker}. eg.
|
||||
# {TextEditor::decorateMarker}. eg.
|
||||
#
|
||||
# ```coffee
|
||||
# range = editor.getSelectedBufferRange() # any range you like
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
{Disposable} = require 'event-kit'
|
||||
Grim = require 'grim'
|
||||
|
||||
# Extended: Manages the deserializers used for serialized state
|
||||
#
|
||||
# An instance of this class is always available as the `atom.deserializers`
|
||||
@@ -24,14 +27,17 @@ class DeserializerManager
|
||||
|
||||
# Public: Register the given class(es) as deserializers.
|
||||
#
|
||||
# * `classes` One or more classes to register.
|
||||
add: (classes...) ->
|
||||
@deserializers[klass.name] = klass for klass in classes
|
||||
# * `deserializers` One or more deserializers to register. A deserializer can
|
||||
# be any object with a `.name` property and a `.deserialize()` method. A
|
||||
# common approach is to register a *constructor* as the deserializer for its
|
||||
# instances by adding a `.deserialize()` class method.
|
||||
add: (deserializers...) ->
|
||||
@deserializers[deserializer.name] = deserializer for deserializer in deserializers
|
||||
new Disposable =>
|
||||
delete @deserializers[deserializer.name] for deserializer in deserializers
|
||||
|
||||
# Public: Remove the given class(es) as deserializers.
|
||||
#
|
||||
# * `classes` One or more classes to remove.
|
||||
remove: (classes...) ->
|
||||
Grim.deprecate("Call .dispose() on the Disposable return from ::add instead")
|
||||
delete @deserializers[name] for {name} in classes
|
||||
|
||||
# Public: Deserialize the state and params.
|
||||
|
||||
@@ -59,10 +59,10 @@ class DisplayBuffer extends Model
|
||||
@subscribe @buffer.onDidUpdateMarkers @handleBufferMarkersUpdated
|
||||
@subscribe @buffer.onDidCreateMarker @handleBufferMarkerCreated
|
||||
|
||||
@subscribe atom.config.observe 'editor.preferredLineLength', callNow: false, =>
|
||||
@subscribe atom.config.onDidChange 'editor.preferredLineLength', =>
|
||||
@updateWrappedScreenLines() if @isSoftWrapped() and atom.config.get('editor.softWrapAtPreferredLineLength')
|
||||
|
||||
@subscribe atom.config.observe 'editor.softWrapAtPreferredLineLength', callNow: false, =>
|
||||
@subscribe atom.config.onDidChange 'editor.softWrapAtPreferredLineLength', =>
|
||||
@updateWrappedScreenLines() if @isSoftWrapped()
|
||||
|
||||
@updateAllScreenLines()
|
||||
@@ -315,9 +315,14 @@ class DisplayBuffer extends Model
|
||||
@charWidthsByScope = {}
|
||||
|
||||
getScrollHeight: ->
|
||||
return 0 unless @getLineHeightInPixels() > 0
|
||||
lineHeight = @getLineHeightInPixels()
|
||||
return 0 unless lineHeight > 0
|
||||
|
||||
@getLineCount() * @getLineHeightInPixels()
|
||||
scrollHeight = @getLineCount() * lineHeight
|
||||
if @height? and atom.config.get('editor.scrollPastEnd')
|
||||
scrollHeight = scrollHeight + @height - (lineHeight * 3)
|
||||
|
||||
scrollHeight
|
||||
|
||||
getScrollWidth: ->
|
||||
@scrollWidth
|
||||
@@ -434,7 +439,7 @@ class DisplayBuffer extends Model
|
||||
|
||||
getSoftWrapColumn: ->
|
||||
if atom.config.get('editor.softWrapAtPreferredLineLength')
|
||||
Math.min(@getEditorWidthInChars(), atom.config.getPositiveInt('editor.preferredLineLength', @getEditorWidthInChars()))
|
||||
Math.min(@getEditorWidthInChars(), atom.config.get('editor.preferredLineLength'))
|
||||
else
|
||||
@getEditorWidthInChars()
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@ class LanguageMode
|
||||
Emitter.includeInto(this)
|
||||
Subscriber.includeInto(this)
|
||||
|
||||
# Sets up a `LanguageMode` for the given {Editor}.
|
||||
# Sets up a `LanguageMode` for the given {TextEditor}.
|
||||
#
|
||||
# editor - The {Editor} to associate with
|
||||
# editor - The {TextEditor} to associate with
|
||||
constructor: (@editor) ->
|
||||
{@buffer} = @editor
|
||||
|
||||
@@ -283,7 +283,7 @@ class LanguageMode
|
||||
# Given a buffer row, this indents it.
|
||||
#
|
||||
# bufferRow - The row {Number}.
|
||||
# options - An options {Object} to pass through to {Editor::setIndentationForBufferRow}.
|
||||
# options - An options {Object} to pass through to {TextEditor::setIndentationForBufferRow}.
|
||||
autoIndentBufferRow: (bufferRow, options) ->
|
||||
indentLevel = @suggestedIndentForBufferRow(bufferRow)
|
||||
@editor.setIndentationForBufferRow(bufferRow, indentLevel, options)
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@ Grim = require 'grim'
|
||||
#
|
||||
# ### Marker Creation
|
||||
#
|
||||
# Use {Editor::markBufferRange} rather than creating Markers directly.
|
||||
# Use {TextEditor::markBufferRange} rather than creating Markers directly.
|
||||
#
|
||||
# ### Head and Tail
|
||||
#
|
||||
@@ -42,7 +42,7 @@ Grim = require 'grim'
|
||||
# region in any way, including changes that end at the marker's
|
||||
# start or start at the marker's end. This is the most fragile strategy.
|
||||
#
|
||||
# See {Editor::markBufferRange} for usage.
|
||||
# See {TextEditor::markBufferRange} for usage.
|
||||
module.exports =
|
||||
class Marker
|
||||
EmitterMixin.includeInto(this)
|
||||
|
||||
@@ -4,6 +4,7 @@ _ = require 'underscore-plus'
|
||||
ipc = require 'ipc'
|
||||
CSON = require 'season'
|
||||
fs = require 'fs-plus'
|
||||
{Disposable} = require 'event-kit'
|
||||
|
||||
# Extended: Provides a registry for menu items that you'd like to appear in the
|
||||
# application menu.
|
||||
@@ -34,10 +35,17 @@ class MenuManager
|
||||
# * `submenu` An optional {Array} of sub menu items.
|
||||
# * `command` An optional {String} command to trigger when the item is
|
||||
# clicked.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to remove the
|
||||
# added menu items.
|
||||
add: (items) ->
|
||||
@merge(@template, item) for item in items
|
||||
@update()
|
||||
undefined
|
||||
new Disposable => @remove(items)
|
||||
|
||||
remove: (items) ->
|
||||
@unmerge(@template, item) for item in items
|
||||
@update()
|
||||
|
||||
# Should the binding for the given selector be included in the menu
|
||||
# commands.
|
||||
@@ -96,11 +104,29 @@ class MenuManager
|
||||
# appended to the bottom of existing menus where possible.
|
||||
merge: (menu, item) ->
|
||||
item = _.deepClone(item)
|
||||
matchingItem = @findMatchingItem(menu, item)
|
||||
|
||||
if item.submenu? and match = _.find(menu, ({label, submenu}) => submenu? and label and @normalizeLabel(label) is @normalizeLabel(item.label))
|
||||
@merge(match.submenu, i) for i in item.submenu
|
||||
if matchingItem?
|
||||
if item.submenu?
|
||||
@merge(matchingItem.submenu, submenuItem) for submenuItem in item.submenu
|
||||
else
|
||||
menu.push(item) unless _.find(menu, ({label}) => label and @normalizeLabel(label) is @normalizeLabel(item.label))
|
||||
menu.push(item)
|
||||
|
||||
unmerge: (menu, item) ->
|
||||
if matchingItem = @findMatchingItem(menu, item)
|
||||
if item.submenu?
|
||||
@unmerge(matchingItem.submenu, submenuItem) for submenuItem in item.submenu
|
||||
|
||||
unless matchingItem.submenu?.length > 0
|
||||
menu.splice(menu.indexOf(matchingItem), 1)
|
||||
|
||||
# find an existing menu item matching the given item
|
||||
findMatchingItem: (menu, {label, submenu}) ->
|
||||
debugger unless menu?
|
||||
for item in menu
|
||||
if @normalizeLabel(item.label) is @normalizeLabel(label) and item.submenu? is submenu?
|
||||
return item
|
||||
null
|
||||
|
||||
# OSX can't handle displaying accelerators for multiple keystrokes.
|
||||
# If they are sent across, it will stop processing accelerators for the rest
|
||||
|
||||
@@ -260,9 +260,9 @@ class PackageManager
|
||||
@disabledPackagesSubscription = null
|
||||
|
||||
observeDisabledPackages: ->
|
||||
@disabledPackagesSubscription ?= atom.config.observe 'core.disabledPackages', callNow: false, (disabledPackages, {previous}) =>
|
||||
packagesToEnable = _.difference(previous, disabledPackages)
|
||||
packagesToDisable = _.difference(disabledPackages, previous)
|
||||
@disabledPackagesSubscription ?= atom.config.onDidChange 'core.disabledPackages', ({newValue, oldValue}) =>
|
||||
packagesToEnable = _.difference(oldValue, newValue)
|
||||
packagesToDisable = _.difference(newValue, oldValue)
|
||||
|
||||
@deactivatePackage(packageName) for packageName in packagesToDisable when @getActivePackage(packageName)
|
||||
@activatePackage(packageName) for packageName in packagesToEnable
|
||||
|
||||
+58
-60
@@ -5,7 +5,7 @@ async = require 'async'
|
||||
CSON = require 'season'
|
||||
fs = require 'fs-plus'
|
||||
EmitterMixin = require('emissary').Emitter
|
||||
{Emitter} = require 'event-kit'
|
||||
{Emitter, CompositeDisposable} = require 'event-kit'
|
||||
Q = require 'q'
|
||||
{deprecate} = require 'grim'
|
||||
|
||||
@@ -99,7 +99,7 @@ class Package
|
||||
@loadMenus()
|
||||
@loadStylesheets()
|
||||
@scopedPropertiesPromise = @loadScopedProperties()
|
||||
@requireMainModule() unless @hasActivationEvents()
|
||||
@requireMainModule() unless @hasActivationCommands()
|
||||
|
||||
catch error
|
||||
console.warn "Failed to load package named '#{@name}'", error.stack ? error
|
||||
@@ -119,8 +119,8 @@ class Package
|
||||
@activationDeferred = Q.defer()
|
||||
@measure 'activateTime', =>
|
||||
@activateResources()
|
||||
if @hasActivationEvents()
|
||||
@subscribeToActivationEvents()
|
||||
if @hasActivationCommands()
|
||||
@subscribeToActivationCommands()
|
||||
else
|
||||
@activateNow()
|
||||
|
||||
@@ -143,7 +143,13 @@ class Package
|
||||
|
||||
@requireMainModule()
|
||||
if @mainModule?
|
||||
atom.config.setDefaults(@name, @mainModule.configDefaults)
|
||||
if @mainModule.config? and typeof @mainModule.config is 'object'
|
||||
atom.config.setSchema @name, {type: 'object', properties: @mainModule.config}
|
||||
else if @mainModule.configDefaults? and typeof @mainModule.configDefaults is 'object'
|
||||
deprecate """Use a config schema instead. See the configuration section
|
||||
of https://atom.io/docs/latest/creating-a-package and
|
||||
https://atom.io/docs/api/latest/Config for more details"""
|
||||
atom.config.setDefaults(@name, @mainModule.configDefaults)
|
||||
@mainModule.activateConfig?()
|
||||
@configActivated = true
|
||||
|
||||
@@ -270,7 +276,7 @@ class Package
|
||||
deactivate: ->
|
||||
@activationDeferred?.reject()
|
||||
@activationDeferred = null
|
||||
@unsubscribeFromActivationEvents()
|
||||
@activationCommandSubscriptions?.dispose()
|
||||
@deactivateResources()
|
||||
@deactivateConfig()
|
||||
if @mainActivated
|
||||
@@ -319,64 +325,56 @@ class Package
|
||||
path.join(@path, 'index')
|
||||
@mainModulePath = fs.resolveExtension(mainModulePath, ["", _.keys(require.extensions)...])
|
||||
|
||||
hasActivationEvents: ->
|
||||
if _.isArray(@metadata.activationEvents)
|
||||
return @metadata.activationEvents.some (activationEvent) ->
|
||||
activationEvent?.length > 0
|
||||
else if _.isString(@metadata.activationEvents)
|
||||
return @metadata.activationEvents.length > 0
|
||||
else if _.isObject(@metadata.activationEvents)
|
||||
for event, selector of @metadata.activationEvents
|
||||
return true if event.length > 0 and selector.length > 0
|
||||
|
||||
hasActivationCommands: ->
|
||||
for selector, commands of @getActivationCommands()
|
||||
return true if commands.length > 0
|
||||
false
|
||||
|
||||
subscribeToActivationEvents: ->
|
||||
return unless @metadata.activationEvents?
|
||||
if _.isArray(@metadata.activationEvents)
|
||||
atom.workspaceView.command(event, @handleActivationEvent) for event in @metadata.activationEvents
|
||||
else if _.isString(@metadata.activationEvents)
|
||||
atom.workspaceView.command(@metadata.activationEvents, @handleActivationEvent)
|
||||
else
|
||||
atom.workspaceView.command(event, selector, @handleActivationEvent) for event, selector of @metadata.activationEvents
|
||||
subscribeToActivationCommands: ->
|
||||
@activationCommandSubscriptions = new CompositeDisposable
|
||||
for selector, commands of @getActivationCommands()
|
||||
for command in commands
|
||||
@activationCommandSubscriptions.add(
|
||||
atom.commands.add(selector, command, @handleActivationCommand)
|
||||
)
|
||||
|
||||
handleActivationEvent: (event) =>
|
||||
bubblePathEventHandlers = @disableEventHandlersOnBubblePath(event)
|
||||
getActivationCommands: ->
|
||||
return @activationCommands if @activationCommands?
|
||||
|
||||
@activationCommands = {}
|
||||
|
||||
if @metadata.activationCommands?
|
||||
for selector, commands of @metadata.activationCommands
|
||||
@activationCommands[selector] ?= []
|
||||
if _.isString(commands)
|
||||
@activationCommands[selector].push(commands)
|
||||
else if _.isArray(commands)
|
||||
@activationCommands[selector].push(commands...)
|
||||
|
||||
if @metadata.activationEvents?
|
||||
if _.isArray(@metadata.activationEvents)
|
||||
for eventName in @metadata.activationEvents
|
||||
@activationCommands['.workspace'] ?= []
|
||||
@activationCommands['.workspace'].push(eventName)
|
||||
else if _.isString(@metadata.activationEvents)
|
||||
eventName = @metadata.activationEvents
|
||||
@activationCommands['.workspace'] ?= []
|
||||
@activationCommands['.workspace'].push(eventName)
|
||||
else
|
||||
for eventName, selector of @metadata.activationEvents
|
||||
selector ?= '.workspace'
|
||||
@activationCommands[selector] ?= []
|
||||
@activationCommands[selector].push(eventName)
|
||||
|
||||
@activationCommands
|
||||
|
||||
handleActivationCommand: (event) =>
|
||||
event.stopImmediatePropagation()
|
||||
@activationCommandSubscriptions.dispose()
|
||||
reenableInvokedListeners = event.disableInvokedListeners()
|
||||
@activateNow()
|
||||
$ ?= require('./space-pen-extensions').$
|
||||
$(event.target).trigger(event)
|
||||
@restoreEventHandlersOnBubblePath(bubblePathEventHandlers)
|
||||
@unsubscribeFromActivationEvents()
|
||||
false
|
||||
|
||||
unsubscribeFromActivationEvents: ->
|
||||
return unless atom.workspaceView?
|
||||
|
||||
if _.isArray(@metadata.activationEvents)
|
||||
atom.workspaceView.off(event, @handleActivationEvent) for event in @metadata.activationEvents
|
||||
else if _.isString(@metadata.activationEvents)
|
||||
atom.workspaceView.off(@metadata.activationEvents, @handleActivationEvent)
|
||||
else
|
||||
atom.workspaceView.off(event, selector, @handleActivationEvent) for event, selector of @metadata.activationEvents
|
||||
|
||||
disableEventHandlersOnBubblePath: (event) ->
|
||||
bubblePathEventHandlers = []
|
||||
disabledHandler = ->
|
||||
$ ?= require('./space-pen-extensions').$
|
||||
element = $(event.target)
|
||||
while element.length
|
||||
if eventHandlers = element.handlers()?[event.type]
|
||||
for eventHandler in eventHandlers
|
||||
eventHandler.disabledHandler = eventHandler.handler
|
||||
eventHandler.handler = disabledHandler
|
||||
bubblePathEventHandlers.push(eventHandler)
|
||||
element = element.parent()
|
||||
bubblePathEventHandlers
|
||||
|
||||
restoreEventHandlersOnBubblePath: (eventHandlers) ->
|
||||
for eventHandler in eventHandlers
|
||||
eventHandler.handler = eventHandler.disabledHandler
|
||||
delete eventHandler.disabledHandler
|
||||
event.target.dispatchEvent(new CustomEvent(event.type, bubbles: true))
|
||||
reenableInvokedListeners()
|
||||
|
||||
# Does the given module path contain native code?
|
||||
isNativeModule: (modulePath) ->
|
||||
|
||||
@@ -8,7 +8,7 @@ Pane = require './pane'
|
||||
|
||||
# A container which can contains multiple items to be switched between.
|
||||
#
|
||||
# Items can be almost anything however most commonly they're {EditorView}s.
|
||||
# Items can be almost anything however most commonly they're {TextEditorView}s.
|
||||
#
|
||||
# Most packages won't need to use this class, unless you're interested in
|
||||
# building a package that deals with switching between panes or items.
|
||||
|
||||
+3
-3
@@ -4,7 +4,7 @@
|
||||
Serializable = require 'serializable'
|
||||
Grim = require 'grim'
|
||||
PaneAxis = require './pane-axis'
|
||||
Editor = require './editor'
|
||||
TextEditor = require './text-editor'
|
||||
PaneView = null
|
||||
|
||||
# Extended: A container for presenting content in the center of the workspace.
|
||||
@@ -261,9 +261,9 @@ class Pane extends Model
|
||||
@emitter.emit 'did-change-active-item', @activeItem
|
||||
@activeItem
|
||||
|
||||
# Return an {Editor} if the pane item is an {Editor}, or null otherwise.
|
||||
# Return an {TextEditor} if the pane item is an {TextEditor}, or null otherwise.
|
||||
getActiveEditor: ->
|
||||
@activeItem if @activeItem instanceof Editor
|
||||
@activeItem if @activeItem instanceof TextEditor
|
||||
|
||||
# Public: Return the item at the given index.
|
||||
#
|
||||
|
||||
@@ -11,7 +11,7 @@ Serializable = require 'serializable'
|
||||
TextBuffer = require 'text-buffer'
|
||||
{Directory} = require 'pathwatcher'
|
||||
|
||||
Editor = require './editor'
|
||||
TextEditor = require './text-editor'
|
||||
Task = require './task'
|
||||
GitRepository = require './git-repository'
|
||||
|
||||
@@ -232,12 +232,12 @@ class Project extends Model
|
||||
###
|
||||
|
||||
# Given a path to a file, this constructs and associates a new
|
||||
# {Editor}, showing the file.
|
||||
# {TextEditor}, showing the file.
|
||||
#
|
||||
# * `filePath` The {String} path of the file to associate with.
|
||||
# * `options` Options that you can pass to the {Editor} constructor.
|
||||
# * `options` Options that you can pass to the {TextEditor} constructor.
|
||||
#
|
||||
# Returns a promise that resolves to an {Editor}.
|
||||
# Returns a promise that resolves to an {TextEditor}.
|
||||
open: (filePath, options={}) ->
|
||||
filePath = @resolve(filePath)
|
||||
@bufferForPath(filePath).then (buffer) =>
|
||||
@@ -330,7 +330,7 @@ class Project extends Model
|
||||
buffer?.destroy()
|
||||
|
||||
buildEditorForBuffer: (buffer, editorOptions) ->
|
||||
editor = new Editor(_.extend({buffer, registerEditor: true}, editorOptions))
|
||||
editor = new TextEditor(_.extend({buffer, registerEditor: true}, editorOptions))
|
||||
editor
|
||||
|
||||
eachBuffer: (args...) ->
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{$, View} = require './space-pen-extensions'
|
||||
EditorView = require './editor-view'
|
||||
TextEditorView = require './text-editor-view'
|
||||
fuzzyFilter = require('fuzzaldrin').filter
|
||||
|
||||
# Essential: Provides a view that renders a list of items with an editor that
|
||||
@@ -34,7 +34,7 @@ module.exports =
|
||||
class SelectListView extends View
|
||||
@content: ->
|
||||
@div class: 'select-list', =>
|
||||
@subview 'filterEditorView', new EditorView(mini: true)
|
||||
@subview 'filterEditorView', new TextEditorView(mini: true)
|
||||
@div class: 'error-message', outlet: 'error'
|
||||
@div class: 'loading', outlet: 'loadingArea', =>
|
||||
@span class: 'loading-message', outlet: 'loading'
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
{Emitter} = require 'event-kit'
|
||||
Grim = require 'grim'
|
||||
|
||||
# Extended: Represents a selection in the {Editor}.
|
||||
# Extended: Represents a selection in the {TextEditor}.
|
||||
module.exports =
|
||||
class Selection extends Model
|
||||
cursor: null
|
||||
@@ -93,7 +93,7 @@ class Selection extends Model
|
||||
# * `screenRange` The new {Range} to select.
|
||||
# * `options` (optional) {Object} with the keys:
|
||||
# * `preserveFolds` if `true`, the fold settings are preserved after the selection moves.
|
||||
# * `autoscroll` if `true`, the {Editor} scrolls to the new selection.
|
||||
# * `autoscroll` if `true`, the {TextEditor} scrolls to the new selection.
|
||||
setBufferRange: (bufferRange, options={}) ->
|
||||
bufferRange = Range.fromObject(bufferRange)
|
||||
@needsAutoscroll = options.autoscroll
|
||||
@@ -591,7 +591,7 @@ class Selection extends Model
|
||||
#
|
||||
# * `options` (optional) {Object} with the keys:
|
||||
# * `autoIndent` If `true`, the line is indented to an automatically-inferred
|
||||
# level. Otherwise, {Editor::getTabText} is inserted.
|
||||
# level. Otherwise, {TextEditor::getTabText} is inserted.
|
||||
indent: ({ autoIndent }={}) ->
|
||||
{ row, column } = @cursor.getBufferPosition()
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ ScrollbarCornerComponent = require './scrollbar-corner-component'
|
||||
SubscriberMixin = require './subscriber-mixin'
|
||||
|
||||
module.exports =
|
||||
EditorComponent = React.createClass
|
||||
displayName: 'EditorComponent'
|
||||
TextEditorComponent = React.createClass
|
||||
displayName: 'TextEditorComponent'
|
||||
mixins: [SubscriberMixin]
|
||||
|
||||
statics:
|
||||
@@ -236,7 +236,7 @@ EditorComponent = React.createClass
|
||||
@updateRequestedWhilePaused = true
|
||||
return
|
||||
|
||||
if @performSyncUpdates ? EditorComponent.performSyncUpdates
|
||||
if @performSyncUpdates ? TextEditorComponent.performSyncUpdates
|
||||
@forceUpdate()
|
||||
else unless @updateRequested
|
||||
@updateRequested = true
|
||||
@@ -506,16 +506,16 @@ EditorComponent = React.createClass
|
||||
'editor:move-line-down': -> editor.moveLineDown()
|
||||
'editor:duplicate-lines': -> editor.duplicateLines()
|
||||
'editor:join-lines': -> editor.joinLines()
|
||||
'editor:toggle-indent-guide': -> atom.config.toggle('editor.showIndentGuide')
|
||||
'editor:toggle-line-numbers': -> atom.config.toggle('editor.showLineNumbers')
|
||||
'editor:toggle-indent-guide': -> atom.config.set('editor.showIndentGuide', not atom.config.get('editor.showIndentGuide'))
|
||||
'editor:toggle-line-numbers': -> atom.config.set('editor.showLineNumbers', not atom.config.get('editor.showLineNumbers'))
|
||||
'editor:scroll-to-cursor': -> editor.scrollToCursorPosition()
|
||||
'benchmark:scroll': @runScrollBenchmark
|
||||
|
||||
addCommandListeners: (listenersByCommandName) ->
|
||||
{parentView} = @props
|
||||
|
||||
addListener = (command, listener) ->
|
||||
parentView.command command, (event) ->
|
||||
addListener = (command, listener) =>
|
||||
@subscribe parentView.command command, (event) ->
|
||||
event.stopPropagation()
|
||||
listener(event)
|
||||
|
||||
@@ -606,7 +606,7 @@ EditorComponent = React.createClass
|
||||
|
||||
onScrollViewScroll: ->
|
||||
if @isMounted()
|
||||
console.warn "EditorScrollView scrolled when it shouldn't have."
|
||||
console.warn "TextEditorScrollView scrolled when it shouldn't have."
|
||||
scrollViewNode = @refs.scrollView.getDOMNode()
|
||||
scrollViewNode.scrollTop = 0
|
||||
scrollViewNode.scrollLeft = 0
|
||||
@@ -2,24 +2,24 @@
|
||||
React = require 'react-atom-fork'
|
||||
{defaults} = require 'underscore-plus'
|
||||
TextBuffer = require 'text-buffer'
|
||||
Editor = require './editor'
|
||||
EditorComponent = require './editor-component'
|
||||
TextEditor = require './text-editor'
|
||||
TextEditorComponent = require './text-editor-component'
|
||||
{deprecate} = require 'grim'
|
||||
|
||||
# Public: Represents the entire visual pane in Atom.
|
||||
#
|
||||
# The EditorView manages the {Editor}, which manages the file buffers.
|
||||
# `EditorView` is intentionally sparse. Most of the things you'll want
|
||||
# to do are on {Editor}.
|
||||
# The TextEditorView manages the {TextEditor}, which manages the file buffers.
|
||||
# `TextEditorView` is intentionally sparse. Most of the things you'll want
|
||||
# to do are on {TextEditor}.
|
||||
#
|
||||
# ## Examples
|
||||
#
|
||||
# Requiring in packages
|
||||
#
|
||||
# ```coffee
|
||||
# {EditorView} = require 'atom'
|
||||
# {TextEditorView} = require 'atom'
|
||||
#
|
||||
# miniEditorView = new EditorView(mini: true)
|
||||
# miniEditorView = new TextEditorView(mini: true)
|
||||
# ```
|
||||
#
|
||||
# Iterating over the open editor views
|
||||
@@ -36,31 +36,7 @@ EditorComponent = require './editor-component'
|
||||
# console.log(editorView.getModel().getPath())
|
||||
# ```
|
||||
module.exports =
|
||||
class EditorView extends View
|
||||
@configDefaults:
|
||||
fontFamily: ''
|
||||
fontSize: 16
|
||||
lineHeight: 1.3
|
||||
showInvisibles: false
|
||||
showIndentGuide: false
|
||||
showLineNumbers: true
|
||||
autoIndent: true
|
||||
normalizeIndentOnPaste: true
|
||||
nonWordCharacters: "/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-"
|
||||
preferredLineLength: 80
|
||||
tabLength: 2
|
||||
softWrap: false
|
||||
softTabs: true
|
||||
softWrapAtPreferredLineLength: false
|
||||
scrollSensitivity: 40
|
||||
useHardwareAcceleration: true
|
||||
confirmCheckoutHeadRevision: true
|
||||
invisibles:
|
||||
eol: '\u00ac'
|
||||
space: '\u00b7'
|
||||
tab: '\u00bb'
|
||||
cr: '\u00a4'
|
||||
|
||||
class TextEditorView extends View
|
||||
@content: (params) ->
|
||||
attributes = params.attributes ? {}
|
||||
attributes.class = 'editor react editor-colors'
|
||||
@@ -69,23 +45,23 @@ class EditorView extends View
|
||||
|
||||
focusOnAttach: false
|
||||
|
||||
# The constructor for setting up an `EditorView` instance.
|
||||
# The constructor for setting up an `TextEditorView` instance.
|
||||
#
|
||||
# * `editorOrParams` Either an {Editor}, or an object with one property, `mini`.
|
||||
# If `mini` is `true`, a "miniature" `Editor` is constructed.
|
||||
# * `editorOrParams` Either an {TextEditor}, or an object with one property, `mini`.
|
||||
# If `mini` is `true`, a "miniature" `TextEditor` is constructed.
|
||||
# Typically, this is ideal for scenarios where you need an Atom editor,
|
||||
# but without all the chrome, like scrollbars, gutter, _e.t.c._.
|
||||
#
|
||||
constructor: (editorOrParams, props) ->
|
||||
super
|
||||
|
||||
if editorOrParams instanceof Editor
|
||||
if editorOrParams instanceof TextEditor
|
||||
@editor = editorOrParams
|
||||
else
|
||||
{@editor, mini, placeholderText} = editorOrParams
|
||||
props ?= {}
|
||||
props.mini = mini
|
||||
@editor ?= new Editor
|
||||
@editor ?= new TextEditor
|
||||
buffer: new TextBuffer
|
||||
softWrapped: false
|
||||
tabLength: 2
|
||||
@@ -94,7 +70,8 @@ class EditorView extends View
|
||||
placeholderText: placeholderText
|
||||
|
||||
props = defaults({@editor, parentView: this}, props)
|
||||
@component = React.renderComponent(EditorComponent(props), @element)
|
||||
@componentDescriptor = TextEditorComponent(props)
|
||||
@component = React.renderComponent(@componentDescriptor, @element)
|
||||
|
||||
node = @component.getDOMNode()
|
||||
|
||||
@@ -128,7 +105,7 @@ class EditorView extends View
|
||||
|
||||
# Public: Get the underlying editor model for this view.
|
||||
#
|
||||
# Returns an {Editor}
|
||||
# Returns an {TextEditor}
|
||||
getModel: -> @editor
|
||||
|
||||
getEditor: -> @editor
|
||||
@@ -145,6 +122,7 @@ class EditorView extends View
|
||||
return unless onDom
|
||||
return if @attached
|
||||
@attached = true
|
||||
@component = React.renderComponent(@componentDescriptor, @element) unless @component.isMounted()
|
||||
@component.checkForVisibilityChange()
|
||||
|
||||
@focus() if @focusOnAttach
|
||||
@@ -171,27 +149,27 @@ class EditorView extends View
|
||||
@editor.getScrollLeft()
|
||||
|
||||
scrollToBottom: ->
|
||||
deprecate 'Use Editor::scrollToBottom instead. You can get the editor via editorView.getModel()'
|
||||
deprecate 'Use TextEditor::scrollToBottom instead. You can get the editor via editorView.getModel()'
|
||||
@editor.setScrollBottom(Infinity)
|
||||
|
||||
scrollToScreenPosition: (screenPosition, options) ->
|
||||
deprecate 'Use Editor::scrollToScreenPosition instead. You can get the editor via editorView.getModel()'
|
||||
deprecate 'Use TextEditor::scrollToScreenPosition instead. You can get the editor via editorView.getModel()'
|
||||
@editor.scrollToScreenPosition(screenPosition, options)
|
||||
|
||||
scrollToBufferPosition: (bufferPosition, options) ->
|
||||
deprecate 'Use Editor::scrollToBufferPosition instead. You can get the editor via editorView.getModel()'
|
||||
deprecate 'Use TextEditor::scrollToBufferPosition instead. You can get the editor via editorView.getModel()'
|
||||
@editor.scrollToBufferPosition(bufferPosition, options)
|
||||
|
||||
scrollToCursorPosition: ->
|
||||
deprecate 'Use Editor::scrollToCursorPosition instead. You can get the editor via editorView.getModel()'
|
||||
deprecate 'Use TextEditor::scrollToCursorPosition instead. You can get the editor via editorView.getModel()'
|
||||
@editor.scrollToCursorPosition()
|
||||
|
||||
pixelPositionForBufferPosition: (bufferPosition) ->
|
||||
deprecate 'Use Editor::pixelPositionForBufferPosition instead. You can get the editor via editorView.getModel()'
|
||||
deprecate 'Use TextEditor::pixelPositionForBufferPosition instead. You can get the editor via editorView.getModel()'
|
||||
@editor.pixelPositionForBufferPosition(bufferPosition)
|
||||
|
||||
pixelPositionForScreenPosition: (screenPosition) ->
|
||||
deprecate 'Use Editor::pixelPositionForScreenPosition instead. You can get the editor via editorView.getModel()'
|
||||
deprecate 'Use TextEditor::pixelPositionForScreenPosition instead. You can get the editor via editorView.getModel()'
|
||||
@editor.pixelPositionForScreenPosition(screenPosition)
|
||||
|
||||
appendToLinesView: (view) ->
|
||||
@@ -251,13 +229,13 @@ class EditorView extends View
|
||||
pane = @getPaneView()
|
||||
pane?.splitDown(pane?.copyActiveItem()).activeView
|
||||
|
||||
# Public: Get this {EditorView}'s {PaneView}.
|
||||
# Public: Get this {TextEditorView}'s {PaneView}.
|
||||
#
|
||||
# Returns a {PaneView}
|
||||
getPaneView: ->
|
||||
@parent('.item-views').parents('.pane').view()
|
||||
getPane: ->
|
||||
deprecate 'Use EditorView::getPaneView() instead'
|
||||
deprecate 'Use TextEditorView::getPaneView() instead'
|
||||
@getPaneView()
|
||||
|
||||
show: ->
|
||||
@@ -277,11 +255,11 @@ class EditorView extends View
|
||||
@editor.pageUp()
|
||||
|
||||
getFirstVisibleScreenRow: ->
|
||||
deprecate 'Use Editor::getFirstVisibleScreenRow instead. You can get the editor via editorView.getModel()'
|
||||
deprecate 'Use TextEditor::getFirstVisibleScreenRow instead. You can get the editor via editorView.getModel()'
|
||||
@editor.getFirstVisibleScreenRow()
|
||||
|
||||
getLastVisibleScreenRow: ->
|
||||
deprecate 'Use Editor::getLastVisibleScreenRow instead. You can get the editor via editorView.getModel()'
|
||||
deprecate 'Use TextEditor::getLastVisibleScreenRow instead. You can get the editor via editorView.getModel()'
|
||||
@editor.getLastVisibleScreenRow()
|
||||
|
||||
getFontFamily: ->
|
||||
@@ -312,7 +290,7 @@ class EditorView extends View
|
||||
@component.setShowIndentGuide(showIndentGuide)
|
||||
|
||||
setSoftWrap: (softWrapped) ->
|
||||
deprecate 'Use Editor::setSoftWrapped instead. You can get the editor via editorView.getModel()'
|
||||
deprecate 'Use TextEditor::setSoftWrapped instead. You can get the editor via editorView.getModel()'
|
||||
@editor.setSoftWrapped(softWrapped)
|
||||
|
||||
setShowInvisibles: (showInvisibles) ->
|
||||
@@ -16,16 +16,16 @@ TextMateScopeSelector = require('first-mate').ScopeSelector
|
||||
# Public: This class represents all essential editing state for a single
|
||||
# {TextBuffer}, including cursor and selection positions, folds, and soft wraps.
|
||||
# If you're manipulating the state of an editor, use this class. If you're
|
||||
# interested in the visual appearance of editors, use {EditorView} instead.
|
||||
# interested in the visual appearance of editors, use {TextEditorView} instead.
|
||||
#
|
||||
# A single {TextBuffer} can belong to multiple editors. For example, if the
|
||||
# same file is open in two different panes, Atom creates a separate editor for
|
||||
# each pane. If the buffer is manipulated the changes are reflected in both
|
||||
# editors, but each maintains its own cursor position, folded lines, etc.
|
||||
#
|
||||
# ## Accessing Editor Instances
|
||||
# ## Accessing TextEditor Instances
|
||||
#
|
||||
# The easiest way to get hold of `Editor` objects is by registering a callback
|
||||
# The easiest way to get hold of `TextEditor` objects is by registering a callback
|
||||
# with `::observeTextEditors` on the `atom.workspace` global. Your callback will
|
||||
# then be called with all current editor instances and also when any editor is
|
||||
# created in the future.
|
||||
@@ -53,7 +53,7 @@ TextMateScopeSelector = require('first-mate').ScopeSelector
|
||||
# **When in doubt, just default to buffer coordinates**, then experiment with
|
||||
# soft wraps and folds to ensure your code interacts with them correctly.
|
||||
module.exports =
|
||||
class Editor extends Model
|
||||
class TextEditor extends Model
|
||||
Serializable.includeInto(this)
|
||||
atom.deserializers.add(this)
|
||||
Delegator.includeInto(this)
|
||||
@@ -113,8 +113,8 @@ class Editor extends Model
|
||||
@emit 'scroll-left-changed', scrollLeft
|
||||
@emitter.emit 'did-change-scroll-left', scrollLeft
|
||||
|
||||
@subscribe atom.config.observe 'editor.showInvisibles', callNow: false, (show) => @updateInvisibles()
|
||||
@subscribe atom.config.observe 'editor.invisibles', callNow: false, => @updateInvisibles()
|
||||
@subscribe atom.config.onDidChange 'editor.showInvisibles', => @updateInvisibles()
|
||||
@subscribe atom.config.onDidChange 'editor.invisibles', => @updateInvisibles()
|
||||
|
||||
atom.workspace?.editorAdded(this) if registerEditor
|
||||
|
||||
@@ -163,7 +163,7 @@ class Editor extends Model
|
||||
@subscribe @displayBuffer.onDidRemoveDecoration (decoration) => @emit 'decoration-removed', decoration
|
||||
|
||||
getViewClass: ->
|
||||
require './editor-view'
|
||||
require './text-editor-view'
|
||||
|
||||
destroyed: ->
|
||||
@unsubscribe()
|
||||
@@ -426,57 +426,57 @@ class Editor extends Model
|
||||
on: (eventName) ->
|
||||
switch eventName
|
||||
when 'title-changed'
|
||||
deprecate("Use Editor::onDidChangeTitle instead")
|
||||
deprecate("Use TextEditor::onDidChangeTitle instead")
|
||||
when 'path-changed'
|
||||
deprecate("Use Editor::onDidChangePath instead")
|
||||
deprecate("Use TextEditor::onDidChangePath instead")
|
||||
when 'modified-status-changed'
|
||||
deprecate("Use Editor::onDidChangeModified instead")
|
||||
deprecate("Use TextEditor::onDidChangeModified instead")
|
||||
when 'soft-wrap-changed'
|
||||
deprecate("Use Editor::onDidChangeSoftWrapped instead")
|
||||
deprecate("Use TextEditor::onDidChangeSoftWrapped instead")
|
||||
when 'grammar-changed'
|
||||
deprecate("Use Editor::onDidChangeGrammar instead")
|
||||
deprecate("Use TextEditor::onDidChangeGrammar instead")
|
||||
when 'character-widths-changed'
|
||||
deprecate("Use Editor::onDidChangeCharacterWidths instead")
|
||||
deprecate("Use TextEditor::onDidChangeCharacterWidths instead")
|
||||
when 'contents-modified'
|
||||
deprecate("Use Editor::onDidStopChanging instead")
|
||||
deprecate("Use TextEditor::onDidStopChanging instead")
|
||||
when 'contents-conflicted'
|
||||
deprecate("Use Editor::onDidConflict instead")
|
||||
deprecate("Use TextEditor::onDidConflict instead")
|
||||
|
||||
when 'will-insert-text'
|
||||
deprecate("Use Editor::onWillInsertText instead")
|
||||
deprecate("Use TextEditor::onWillInsertText instead")
|
||||
when 'did-insert-text'
|
||||
deprecate("Use Editor::onDidInsertText instead")
|
||||
deprecate("Use TextEditor::onDidInsertText instead")
|
||||
|
||||
when 'cursor-added'
|
||||
deprecate("Use Editor::onDidAddCursor instead")
|
||||
deprecate("Use TextEditor::onDidAddCursor instead")
|
||||
when 'cursor-removed'
|
||||
deprecate("Use Editor::onDidRemoveCursor instead")
|
||||
deprecate("Use TextEditor::onDidRemoveCursor instead")
|
||||
when 'cursor-moved'
|
||||
deprecate("Use Editor::onDidChangeCursorPosition instead")
|
||||
deprecate("Use TextEditor::onDidChangeCursorPosition instead")
|
||||
|
||||
when 'selection-added'
|
||||
deprecate("Use Editor::onDidAddSelection instead")
|
||||
deprecate("Use TextEditor::onDidAddSelection instead")
|
||||
when 'selection-removed'
|
||||
deprecate("Use Editor::onDidRemoveSelection instead")
|
||||
deprecate("Use TextEditor::onDidRemoveSelection instead")
|
||||
when 'selection-screen-range-changed'
|
||||
deprecate("Use Editor::onDidChangeSelectionRange instead")
|
||||
deprecate("Use TextEditor::onDidChangeSelectionRange instead")
|
||||
|
||||
when 'decoration-added'
|
||||
deprecate("Use Editor::onDidAddDecoration instead")
|
||||
deprecate("Use TextEditor::onDidAddDecoration instead")
|
||||
when 'decoration-removed'
|
||||
deprecate("Use Editor::onDidRemoveDecoration instead")
|
||||
deprecate("Use TextEditor::onDidRemoveDecoration instead")
|
||||
when 'decoration-updated'
|
||||
deprecate("Use Decoration::onDidChangeProperties instead. You will get the decoration back from `Editor::decorateMarker()`")
|
||||
deprecate("Use Decoration::onDidChangeProperties instead. You will get the decoration back from `TextEditor::decorateMarker()`")
|
||||
when 'decoration-changed'
|
||||
deprecate("Use Marker::onDidChange instead. eg. `editor::decorateMarker(...).getMarker().onDidChange()`")
|
||||
|
||||
when 'screen-lines-changed'
|
||||
deprecate("Use Editor::onDidChange instead")
|
||||
deprecate("Use TextEditor::onDidChange instead")
|
||||
|
||||
when 'scroll-top-changed'
|
||||
deprecate("Use Editor::onDidChangeScrollTop instead")
|
||||
deprecate("Use TextEditor::onDidChangeScrollTop instead")
|
||||
when 'scroll-left-changed'
|
||||
deprecate("Use Editor::onDidChangeScrollLeft instead")
|
||||
deprecate("Use TextEditor::onDidChangeScrollLeft instead")
|
||||
|
||||
EmitterMixin::on.apply(this, arguments)
|
||||
|
||||
@@ -486,12 +486,12 @@ class Editor extends Model
|
||||
# Retrieves the current buffer's URI.
|
||||
getUri: -> @buffer.getUri()
|
||||
|
||||
# Create an {Editor} with its initial state based on this object
|
||||
# Create an {TextEditor} with its initial state based on this object
|
||||
copy: ->
|
||||
tabLength = @getTabLength()
|
||||
displayBuffer = @displayBuffer.copy()
|
||||
softTabs = @getSoftTabs()
|
||||
newEditor = new Editor({@buffer, displayBuffer, tabLength, softTabs, suppressCursorCreation: true, registerEditor: true})
|
||||
newEditor = new TextEditor({@buffer, displayBuffer, tabLength, softTabs, suppressCursorCreation: true, registerEditor: true})
|
||||
for marker in @findMarkers(editorId: @id)
|
||||
marker.copy(editorId: newEditor.id, preserveFolds: true)
|
||||
newEditor
|
||||
@@ -507,7 +507,7 @@ class Editor extends Model
|
||||
# Set the number of characters that can be displayed horizontally in the
|
||||
# editor.
|
||||
#
|
||||
# * `editorWidthInChars` A {Number} representing the width of the {EditorView}
|
||||
# * `editorWidthInChars` A {Number} representing the width of the {TextEditorView}
|
||||
# in characters.
|
||||
setEditorWidthInChars: (editorWidthInChars) ->
|
||||
@displayBuffer.setEditorWidthInChars(editorWidthInChars)
|
||||
@@ -615,7 +615,7 @@ class Editor extends Model
|
||||
# * `bufferRow` A {Number} representing a zero-indexed buffer row.
|
||||
lineTextForBufferRow: (bufferRow) -> @buffer.lineForRow(bufferRow)
|
||||
lineForBufferRow: (bufferRow) ->
|
||||
deprecate 'Use Editor::lineTextForBufferRow(bufferRow) instead'
|
||||
deprecate 'Use TextEditor::lineTextForBufferRow(bufferRow) instead'
|
||||
@lineTextForBufferRow(bufferRow)
|
||||
|
||||
# Essential: Returns a {String} representing the contents of the line at the
|
||||
@@ -631,13 +631,13 @@ class Editor extends Model
|
||||
# Returns {TokenizedLine}
|
||||
tokenizedLineForScreenRow: (screenRow) -> @displayBuffer.tokenizedLineForScreenRow(screenRow)
|
||||
lineForScreenRow: (screenRow) ->
|
||||
deprecate "Editor::tokenizedLineForScreenRow(bufferRow) is the new name. But it's private. Try to use Editor::lineTextForScreenRow instead"
|
||||
deprecate "TextEditor::tokenizedLineForScreenRow(bufferRow) is the new name. But it's private. Try to use TextEditor::lineTextForScreenRow instead"
|
||||
@tokenizedLineForScreenRow(screenRow)
|
||||
|
||||
# {Delegates to: DisplayBuffer.tokenizedLinesForScreenRows}
|
||||
tokenizedLinesForScreenRows: (start, end) -> @displayBuffer.tokenizedLinesForScreenRows(start, end)
|
||||
linesForScreenRows: (start, end) ->
|
||||
deprecate "Use Editor::tokenizedLinesForScreenRows instead"
|
||||
deprecate "Use TextEditor::tokenizedLinesForScreenRows instead"
|
||||
@tokenizedLinesForScreenRows(start, end)
|
||||
|
||||
# Returns a {Number} representing the line length for the given
|
||||
@@ -889,7 +889,7 @@ class Editor extends Model
|
||||
|
||||
# Deprecated: Use {::duplicateLines} instead.
|
||||
duplicateLine: ->
|
||||
deprecate("Use Editor::duplicateLines() instead")
|
||||
deprecate("Use TextEditor::duplicateLines() instead")
|
||||
@duplicateLines()
|
||||
|
||||
replaceSelectedText: (options={}, fn) ->
|
||||
@@ -1024,12 +1024,12 @@ class Editor extends Model
|
||||
|
||||
# Deprecated: Use {::deleteToBeginningOfWord} instead.
|
||||
backspaceToBeginningOfWord: ->
|
||||
deprecate("Use Editor::deleteToBeginningOfWord() instead")
|
||||
deprecate("Use TextEditor::deleteToBeginningOfWord() instead")
|
||||
@deleteToBeginningOfWord()
|
||||
|
||||
# Deprecated: Use {::deleteToBeginningOfLine} instead.
|
||||
backspaceToBeginningOfLine: ->
|
||||
deprecate("Use Editor::deleteToBeginningOfLine() instead")
|
||||
deprecate("Use TextEditor::deleteToBeginningOfLine() instead")
|
||||
@deleteToBeginningOfLine()
|
||||
|
||||
###
|
||||
@@ -1075,7 +1075,7 @@ class Editor extends Model
|
||||
abortTransaction: -> @buffer.abortTransaction()
|
||||
|
||||
###
|
||||
Section: Editor Coordinates
|
||||
Section: TextEditor Coordinates
|
||||
###
|
||||
|
||||
# Essential: Convert a position in buffer-coordinates to screen-coordinates.
|
||||
@@ -1438,7 +1438,7 @@ class Editor extends Model
|
||||
moveUp: (lineCount) ->
|
||||
@moveCursors (cursor) -> cursor.moveUp(lineCount, moveToEndOfSelection: true)
|
||||
moveCursorUp: (lineCount) ->
|
||||
deprecate("Use Editor::moveUp() instead")
|
||||
deprecate("Use TextEditor::moveUp() instead")
|
||||
@moveUp(lineCount)
|
||||
|
||||
# Essential: Move every cursor down one row in screen coordinates.
|
||||
@@ -1447,7 +1447,7 @@ class Editor extends Model
|
||||
moveDown: (lineCount) ->
|
||||
@moveCursors (cursor) -> cursor.moveDown(lineCount, moveToEndOfSelection: true)
|
||||
moveCursorDown: (lineCount) ->
|
||||
deprecate("Use Editor::moveDown() instead")
|
||||
deprecate("Use TextEditor::moveDown() instead")
|
||||
@moveDown(lineCount)
|
||||
|
||||
# Essential: Move every cursor left one column.
|
||||
@@ -1456,7 +1456,7 @@ class Editor extends Model
|
||||
moveLeft: (columnCount) ->
|
||||
@moveCursors (cursor) -> cursor.moveLeft(columnCount, moveToEndOfSelection: true)
|
||||
moveCursorLeft: ->
|
||||
deprecate("Use Editor::moveLeft() instead")
|
||||
deprecate("Use TextEditor::moveLeft() instead")
|
||||
@moveLeft()
|
||||
|
||||
# Essential: Move every cursor right one column.
|
||||
@@ -1465,56 +1465,56 @@ class Editor extends Model
|
||||
moveRight: (columnCount) ->
|
||||
@moveCursors (cursor) -> cursor.moveRight(columnCount, moveToEndOfSelection: true)
|
||||
moveCursorRight: ->
|
||||
deprecate("Use Editor::moveRight() instead")
|
||||
deprecate("Use TextEditor::moveRight() instead")
|
||||
@moveRight()
|
||||
|
||||
# Essential: Move every cursor to the beginning of its line in buffer coordinates.
|
||||
moveToBeginningOfLine: ->
|
||||
@moveCursors (cursor) -> cursor.moveToBeginningOfLine()
|
||||
moveCursorToBeginningOfLine: ->
|
||||
deprecate("Use Editor::moveToBeginningOfLine() instead")
|
||||
deprecate("Use TextEditor::moveToBeginningOfLine() instead")
|
||||
@moveToBeginningOfLine()
|
||||
|
||||
# Essential: Move every cursor to the beginning of its line in screen coordinates.
|
||||
moveToBeginningOfScreenLine: ->
|
||||
@moveCursors (cursor) -> cursor.moveToBeginningOfScreenLine()
|
||||
moveCursorToBeginningOfScreenLine: ->
|
||||
deprecate("Use Editor::moveToBeginningOfScreenLine() instead")
|
||||
deprecate("Use TextEditor::moveToBeginningOfScreenLine() instead")
|
||||
@moveToBeginningOfScreenLine()
|
||||
|
||||
# Essential: Move every cursor to the first non-whitespace character of its line.
|
||||
moveToFirstCharacterOfLine: ->
|
||||
@moveCursors (cursor) -> cursor.moveToFirstCharacterOfLine()
|
||||
moveCursorToFirstCharacterOfLine: ->
|
||||
deprecate("Use Editor::moveToFirstCharacterOfLine() instead")
|
||||
deprecate("Use TextEditor::moveToFirstCharacterOfLine() instead")
|
||||
@moveToFirstCharacterOfLine()
|
||||
|
||||
# Essential: Move every cursor to the end of its line in buffer coordinates.
|
||||
moveToEndOfLine: ->
|
||||
@moveCursors (cursor) -> cursor.moveToEndOfLine()
|
||||
moveCursorToEndOfLine: ->
|
||||
deprecate("Use Editor::moveToEndOfLine() instead")
|
||||
deprecate("Use TextEditor::moveToEndOfLine() instead")
|
||||
@moveToEndOfLine()
|
||||
|
||||
# Essential: Move every cursor to the end of its line in screen coordinates.
|
||||
moveToEndOfScreenLine: ->
|
||||
@moveCursors (cursor) -> cursor.moveToEndOfScreenLine()
|
||||
moveCursorToEndOfScreenLine: ->
|
||||
deprecate("Use Editor::moveToEndOfScreenLine() instead")
|
||||
deprecate("Use TextEditor::moveToEndOfScreenLine() instead")
|
||||
@moveToEndOfScreenLine()
|
||||
|
||||
# Essential: Move every cursor to the beginning of its surrounding word.
|
||||
moveToBeginningOfWord: ->
|
||||
@moveCursors (cursor) -> cursor.moveToBeginningOfWord()
|
||||
moveCursorToBeginningOfWord: ->
|
||||
deprecate("Use Editor::moveToBeginningOfWord() instead")
|
||||
deprecate("Use TextEditor::moveToBeginningOfWord() instead")
|
||||
@moveToBeginningOfWord()
|
||||
|
||||
# Essential: Move every cursor to the end of its surrounding word.
|
||||
moveToEndOfWord: ->
|
||||
@moveCursors (cursor) -> cursor.moveToEndOfWord()
|
||||
moveCursorToEndOfWord: ->
|
||||
deprecate("Use Editor::moveToEndOfWord() instead")
|
||||
deprecate("Use TextEditor::moveToEndOfWord() instead")
|
||||
@moveToEndOfWord()
|
||||
|
||||
# Cursor Extended
|
||||
@@ -1525,7 +1525,7 @@ class Editor extends Model
|
||||
moveToTop: ->
|
||||
@moveCursors (cursor) -> cursor.moveToTop()
|
||||
moveCursorToTop: ->
|
||||
deprecate("Use Editor::moveToTop() instead")
|
||||
deprecate("Use TextEditor::moveToTop() instead")
|
||||
@moveToTop()
|
||||
|
||||
# Extended: Move every cursor to the bottom of the buffer.
|
||||
@@ -1534,42 +1534,42 @@ class Editor extends Model
|
||||
moveToBottom: ->
|
||||
@moveCursors (cursor) -> cursor.moveToBottom()
|
||||
moveCursorToBottom: ->
|
||||
deprecate("Use Editor::moveToBottom() instead")
|
||||
deprecate("Use TextEditor::moveToBottom() instead")
|
||||
@moveToBottom()
|
||||
|
||||
# Extended: Move every cursor to the beginning of the next word.
|
||||
moveToBeginningOfNextWord: ->
|
||||
@moveCursors (cursor) -> cursor.moveToBeginningOfNextWord()
|
||||
moveCursorToBeginningOfNextWord: ->
|
||||
deprecate("Use Editor::moveToBeginningOfNextWord() instead")
|
||||
deprecate("Use TextEditor::moveToBeginningOfNextWord() instead")
|
||||
@moveToBeginningOfNextWord()
|
||||
|
||||
# Extended: Move every cursor to the previous word boundary.
|
||||
moveToPreviousWordBoundary: ->
|
||||
@moveCursors (cursor) -> cursor.moveToPreviousWordBoundary()
|
||||
moveCursorToPreviousWordBoundary: ->
|
||||
deprecate("Use Editor::moveToPreviousWordBoundary() instead")
|
||||
deprecate("Use TextEditor::moveToPreviousWordBoundary() instead")
|
||||
@moveToPreviousWordBoundary()
|
||||
|
||||
# Extended: Move every cursor to the next word boundary.
|
||||
moveToNextWordBoundary: ->
|
||||
@moveCursors (cursor) -> cursor.moveToNextWordBoundary()
|
||||
moveCursorToNextWordBoundary: ->
|
||||
deprecate("Use Editor::moveToNextWordBoundary() instead")
|
||||
deprecate("Use TextEditor::moveToNextWordBoundary() instead")
|
||||
@moveToNextWordBoundary()
|
||||
|
||||
# Extended: Move every cursor to the beginning of the next paragraph.
|
||||
moveToBeginningOfNextParagraph: ->
|
||||
@moveCursors (cursor) -> cursor.moveToBeginningOfNextParagraph()
|
||||
moveCursorToBeginningOfNextParagraph: ->
|
||||
deprecate("Use Editor::moveToBeginningOfNextParagraph() instead")
|
||||
deprecate("Use TextEditor::moveToBeginningOfNextParagraph() instead")
|
||||
@moveToBeginningOfNextParagraph()
|
||||
|
||||
# Extended: Move every cursor to the beginning of the previous paragraph.
|
||||
moveToBeginningOfPreviousParagraph: ->
|
||||
@moveCursors (cursor) -> cursor.moveToBeginningOfPreviousParagraph()
|
||||
moveCursorToBeginningOfPreviousParagraph: ->
|
||||
deprecate("Use Editor::moveToBeginningOfPreviousParagraph() instead")
|
||||
deprecate("Use TextEditor::moveToBeginningOfPreviousParagraph() instead")
|
||||
@moveToBeginningOfPreviousParagraph()
|
||||
|
||||
# Extended: Returns the most recently added {Cursor}
|
||||
@@ -1578,7 +1578,7 @@ class Editor extends Model
|
||||
|
||||
# Deprecated:
|
||||
getCursor: ->
|
||||
deprecate("Use Editor::getLastCursor() instead")
|
||||
deprecate("Use TextEditor::getLastCursor() instead")
|
||||
@getLastCursor()
|
||||
|
||||
# Extended: Returns the word surrounding the most recently added cursor.
|
||||
@@ -1660,7 +1660,7 @@ class Editor extends Model
|
||||
|
||||
# Essential: Get the {Range}s of all selections in buffer coordinates.
|
||||
#
|
||||
# The ranges are sorted by their position in the buffer.
|
||||
# The ranges are sorted by when the selections were added. Most recent at the end.
|
||||
#
|
||||
# Returns an {Array} of {Range}s.
|
||||
getSelectedBufferRanges: ->
|
||||
@@ -1706,7 +1706,7 @@ class Editor extends Model
|
||||
|
||||
# Essential: Get the {Range}s of all selections in screen coordinates.
|
||||
#
|
||||
# The ranges are sorted by their position in the buffer.
|
||||
# The ranges are sorted by when the selections were added. Most recent at the end.
|
||||
#
|
||||
# Returns an {Array} of {Range}s.
|
||||
getSelectedScreenRanges: ->
|
||||
@@ -1892,14 +1892,14 @@ class Editor extends Model
|
||||
selectLinesContainingCursors: ->
|
||||
@expandSelectionsForward (selection) -> selection.selectLine()
|
||||
selectLine: ->
|
||||
deprecate('Use Editor::selectLinesContainingCursors instead')
|
||||
deprecate('Use TextEditor::selectLinesContainingCursors instead')
|
||||
@selectLinesContainingCursors()
|
||||
|
||||
# Essential: Select the word surrounding each cursor.
|
||||
selectWordsContainingCursors: ->
|
||||
@expandSelectionsForward (selection) -> selection.selectWord()
|
||||
selectWord: ->
|
||||
deprecate('Use Editor::selectWordsContainingCursors instead')
|
||||
deprecate('Use TextEditor::selectWordsContainingCursors instead')
|
||||
@selectWordsContainingCursors()
|
||||
|
||||
# Selection Extended
|
||||
@@ -1959,10 +1959,10 @@ class Editor extends Model
|
||||
# Deprecated:
|
||||
getSelection: (index) ->
|
||||
if index?
|
||||
deprecate("Use Editor::getSelections()[index] instead when getting a specific selection")
|
||||
deprecate("Use TextEditor::getSelections()[index] instead when getting a specific selection")
|
||||
@getSelections()[index]
|
||||
else
|
||||
deprecate("Use Editor::getLastSelection() instead")
|
||||
deprecate("Use TextEditor::getLastSelection() instead")
|
||||
@getLastSelection()
|
||||
|
||||
# Extended: Get current {Selection}s.
|
||||
@@ -2222,7 +2222,7 @@ class Editor extends Model
|
||||
# Returns a {Boolean}.
|
||||
isSoftWrapped: (softWrapped) -> @displayBuffer.isSoftWrapped()
|
||||
getSoftWrapped: ->
|
||||
deprecate("Use Editor::isSoftWrapped instead")
|
||||
deprecate("Use TextEditor::isSoftWrapped instead")
|
||||
@displayBuffer.isSoftWrapped()
|
||||
|
||||
# Essential: Enable or disable soft wrapping for this editor.
|
||||
@@ -2232,7 +2232,7 @@ class Editor extends Model
|
||||
# Returns a {Boolean}.
|
||||
setSoftWrapped: (softWrapped) -> @displayBuffer.setSoftWrapped(softWrapped)
|
||||
setSoftWrap: (softWrapped) ->
|
||||
deprecate("Use Editor::setSoftWrapped instead")
|
||||
deprecate("Use TextEditor::setSoftWrapped instead")
|
||||
@setSoftWrapped(softWrapped)
|
||||
|
||||
# Essential: Toggle soft wrapping for this editor
|
||||
@@ -2240,7 +2240,7 @@ class Editor extends Model
|
||||
# Returns a {Boolean}.
|
||||
toggleSoftWrapped: -> @setSoftWrapped(not @isSoftWrapped())
|
||||
toggleSoftWrap: ->
|
||||
deprecate("Use Editor::toggleSoftWrapped instead")
|
||||
deprecate("Use TextEditor::toggleSoftWrapped instead")
|
||||
@toggleSoftWrapped()
|
||||
|
||||
# Public: Gets the column at which column will soft wrap
|
||||
@@ -2354,7 +2354,7 @@ class Editor extends Model
|
||||
# Returns an {Array} of {String}s.
|
||||
scopesAtCursor: -> @getLastCursor().getScopes()
|
||||
getCursorScopes: ->
|
||||
deprecate 'Use Editor::scopesAtCursor() instead'
|
||||
deprecate 'Use TextEditor::scopesAtCursor() instead'
|
||||
@scopesAtCursor()
|
||||
|
||||
# Essential: Get the syntactic scopes for the given position in buffer
|
||||
@@ -2574,7 +2574,7 @@ class Editor extends Model
|
||||
@displayBuffer.outermostFoldsInBufferRowRange(startRow, endRow)
|
||||
|
||||
###
|
||||
Section: Scrolling the Editor
|
||||
Section: Scrolling the TextEditor
|
||||
###
|
||||
|
||||
# Essential: Scroll the editor to reveal the most recently added cursor if it is
|
||||
@@ -2676,7 +2676,7 @@ class Editor extends Model
|
||||
@addSelection(marker)
|
||||
|
||||
###
|
||||
Section: Editor Rendering
|
||||
Section: TextEditor Rendering
|
||||
###
|
||||
|
||||
# Public: Retrieves the greyed out placeholder of a mini editor.
|
||||
@@ -2783,7 +2783,7 @@ class Editor extends Model
|
||||
|
||||
# Deprecated: Call {::joinLines} instead.
|
||||
joinLine: ->
|
||||
deprecate("Use Editor::joinLines() instead")
|
||||
deprecate("Use TextEditor::joinLines() instead")
|
||||
@joinLines()
|
||||
|
||||
###
|
||||
@@ -2791,6 +2791,6 @@ class Editor extends Model
|
||||
###
|
||||
|
||||
inspect: ->
|
||||
"<Editor #{@id}>"
|
||||
"<TextEditor #{@id}>"
|
||||
|
||||
logScreenLines: (start, end) -> @displayBuffer.logLines(start, end)
|
||||
@@ -2,7 +2,7 @@ path = require 'path'
|
||||
|
||||
_ = require 'underscore-plus'
|
||||
EmitterMixin = require('emissary').Emitter
|
||||
{Emitter} = require 'event-kit'
|
||||
{Emitter, Disposable} = require 'event-kit'
|
||||
{File} = require 'pathwatcher'
|
||||
fs = require 'fs-plus'
|
||||
Q = require 'q'
|
||||
@@ -182,16 +182,16 @@ class ThemeManager
|
||||
# * `stylesheetPath` A {String} path to the stylesheet that can be an absolute
|
||||
# path or a relative path that will be resolved against the load path.
|
||||
#
|
||||
# Returns the absolute path to the required stylesheet.
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to remove the
|
||||
# required stylesheet.
|
||||
requireStylesheet: (stylesheetPath, type='bundled') ->
|
||||
if fullPath = @resolveStylesheet(stylesheetPath)
|
||||
content = @loadStylesheet(fullPath)
|
||||
@applyStylesheet(fullPath, content, type)
|
||||
new Disposable => @removeStylesheet(fullPath)
|
||||
else
|
||||
throw new Error("Could not find a file at path '#{stylesheetPath}'")
|
||||
|
||||
fullPath
|
||||
|
||||
unwatchUserStylesheet: ->
|
||||
@userStylesheetFile?.off()
|
||||
@userStylesheetFile = null
|
||||
|
||||
@@ -25,7 +25,7 @@ class TokenizedBuffer extends Model
|
||||
constructor: ({@buffer, @tabLength, @invisibles}) ->
|
||||
@emitter = new Emitter
|
||||
|
||||
@tabLength ?= atom.config.getPositiveInt('editor.tabLength', 2)
|
||||
@tabLength ?= atom.config.get('editor.tabLength')
|
||||
|
||||
@subscribe atom.syntax.onDidAddGrammar(@grammarAddedOrUpdated)
|
||||
@subscribe atom.syntax.onDidUpdateGrammar(@grammarAddedOrUpdated)
|
||||
@@ -35,8 +35,7 @@ class TokenizedBuffer extends Model
|
||||
|
||||
@subscribe @$tabLength.changes, (tabLength) => @retokenizeLines()
|
||||
|
||||
@subscribe atom.config.observe 'editor.tabLength', callNow: false, =>
|
||||
@setTabLength(atom.config.getPositiveInt('editor.tabLength', 2))
|
||||
@subscribe atom.config.onDidChange 'editor.tabLength', ({newValue}) => @setTabLength(newValue)
|
||||
|
||||
@reloadGrammar()
|
||||
|
||||
|
||||
+25
-35
@@ -6,14 +6,13 @@ Delegator = require 'delegato'
|
||||
{deprecate, logDeprecationWarnings} = require 'grim'
|
||||
scrollbarStyle = require 'scrollbar-style'
|
||||
{$, $$, View} = require './space-pen-extensions'
|
||||
fs = require 'fs-plus'
|
||||
Workspace = require './workspace'
|
||||
CommandInstaller = require './command-installer'
|
||||
PaneView = require './pane-view'
|
||||
PaneColumnView = require './pane-column-view'
|
||||
PaneRowView = require './pane-row-view'
|
||||
PaneContainerView = require './pane-container-view'
|
||||
Editor = require './editor'
|
||||
TextEditor = require './text-editor'
|
||||
|
||||
atom.commands.add '.workspace',
|
||||
'window:increase-font-size': -> @getModel().increaseFontSize()
|
||||
@@ -67,15 +66,6 @@ class WorkspaceView extends View
|
||||
|
||||
@version: 4
|
||||
|
||||
@configDefaults:
|
||||
ignoredNames: [".git", ".hg", ".svn", ".DS_Store", "Thumbs.db"]
|
||||
excludeVcsIgnoredPaths: true
|
||||
disabledPackages: []
|
||||
themes: ['atom-dark-ui', 'atom-dark-syntax']
|
||||
projectHome: path.join(fs.getHomeDirectory(), 'github')
|
||||
audioBeep: true
|
||||
destroyEmptyPanes: true
|
||||
|
||||
@content: ->
|
||||
@div class: 'workspace', tabindex: -1, =>
|
||||
@div class: 'horizontal', outlet: 'horizontal', =>
|
||||
@@ -155,11 +145,11 @@ class WorkspaceView extends View
|
||||
@command 'window:focus-pane-on-left', => @focusPaneViewOnLeft()
|
||||
@command 'window:focus-pane-on-right', => @focusPaneViewOnRight()
|
||||
@command 'window:save-all', => @saveAll()
|
||||
@command 'window:toggle-invisibles', -> atom.config.toggle("editor.showInvisibles")
|
||||
@command 'window:toggle-invisibles', -> atom.config.set("editor.showInvisibles", not atom.config.get("editor.showInvisibles"))
|
||||
@command 'window:log-deprecation-warnings', -> logDeprecationWarnings()
|
||||
|
||||
@command 'window:toggle-auto-indent', ->
|
||||
atom.config.toggle("editor.autoIndent")
|
||||
atom.config.set("editor.autoIndent", not atom.config.get("editor.autoIndent"))
|
||||
|
||||
@command 'pane:reopen-closed-item', => @getModel().reopenItem()
|
||||
|
||||
@@ -183,11 +173,11 @@ class WorkspaceView extends View
|
||||
###
|
||||
|
||||
# Essential: Register a function to be called for every current and future
|
||||
# editor view in the workspace (only includes {EditorView}s that are pane
|
||||
# editor view in the workspace (only includes {TextEditorView}s that are pane
|
||||
# items).
|
||||
#
|
||||
# * `callback` A {Function} with an {EditorView} as its only argument.
|
||||
# * `editorView` {EditorView}
|
||||
# * `callback` A {Function} with an {TextEditorView} as its only argument.
|
||||
# * `editorView` {TextEditorView}
|
||||
#
|
||||
# Returns a subscription object with an `.off` method that you can call to
|
||||
# unregister the callback.
|
||||
@@ -403,7 +393,7 @@ class WorkspaceView extends View
|
||||
# to the view objects. Also consider using {::eachEditorView}, which will call
|
||||
# a callback for all current and *future* editor views.
|
||||
#
|
||||
# Returns an {Array} of {EditorView}s.
|
||||
# Returns an {Array} of {TextEditorView}s.
|
||||
getEditorViews: ->
|
||||
for editorElement in @panes.element.querySelectorAll('.pane > .item-views > .editor')
|
||||
$(editorElement).view()
|
||||
@@ -421,13 +411,13 @@ class WorkspaceView extends View
|
||||
when 'beep'
|
||||
deprecate('Use Atom::onDidBeep instead')
|
||||
when 'cursor:moved'
|
||||
deprecate('Use Editor::onDidChangeCursorPosition instead')
|
||||
deprecate('Use TextEditor::onDidChangeCursorPosition instead')
|
||||
when 'editor:attached'
|
||||
deprecate('Use Editor::onDidAddTextEditor instead')
|
||||
deprecate('Use TextEditor::onDidAddTextEditor instead')
|
||||
when 'editor:detached'
|
||||
deprecate('Use Editor::onDidDestroy instead')
|
||||
deprecate('Use TextEditor::onDidDestroy instead')
|
||||
when 'editor:will-be-removed'
|
||||
deprecate('Use Editor::onDidDestroy instead')
|
||||
deprecate('Use TextEditor::onDidDestroy instead')
|
||||
when 'pane:active-item-changed'
|
||||
deprecate('Use Pane::onDidChangeActiveItem instead')
|
||||
when 'pane:active-item-modified-status-changed'
|
||||
@@ -451,38 +441,38 @@ class WorkspaceView extends View
|
||||
when 'pane-container:active-pane-item-changed'
|
||||
deprecate('Use Workspace::onDidChangeActivePaneItem instead')
|
||||
when 'selection:changed'
|
||||
deprecate('Use Editor::onDidChangeSelectionRange instead')
|
||||
deprecate('Use TextEditor::onDidChangeSelectionRange instead')
|
||||
when 'uri-opened'
|
||||
deprecate('Use Workspace::onDidOpen instead')
|
||||
originalWorkspaceViewOn.apply(this, arguments)
|
||||
|
||||
EditorView = require './editor-view'
|
||||
originalEditorViewOn = EditorView::on
|
||||
EditorView::on = (eventName) ->
|
||||
TextEditorView = require './text-editor-view'
|
||||
originalEditorViewOn = TextEditorView::on
|
||||
TextEditorView::on = (eventName) ->
|
||||
switch eventName
|
||||
when 'cursor:moved'
|
||||
deprecate('Use Editor::onDidChangeCursorPosition instead')
|
||||
deprecate('Use TextEditor::onDidChangeCursorPosition instead')
|
||||
when 'editor:attached'
|
||||
deprecate('Use Editor::onDidAddTextEditor instead')
|
||||
deprecate('Use TextEditor::onDidAddTextEditor instead')
|
||||
when 'editor:detached'
|
||||
deprecate('Use Editor::onDidDestroy instead')
|
||||
deprecate('Use TextEditor::onDidDestroy instead')
|
||||
when 'editor:will-be-removed'
|
||||
deprecate('Use Editor::onDidDestroy instead')
|
||||
deprecate('Use TextEditor::onDidDestroy instead')
|
||||
when 'selection:changed'
|
||||
deprecate('Use Editor::onDidChangeSelectionRange instead')
|
||||
deprecate('Use TextEditor::onDidChangeSelectionRange instead')
|
||||
originalEditorViewOn.apply(this, arguments)
|
||||
|
||||
originalPaneViewOn = PaneView::on
|
||||
PaneView::on = (eventName) ->
|
||||
switch eventName
|
||||
when 'cursor:moved'
|
||||
deprecate('Use Editor::onDidChangeCursorPosition instead')
|
||||
deprecate('Use TextEditor::onDidChangeCursorPosition instead')
|
||||
when 'editor:attached'
|
||||
deprecate('Use Editor::onDidAddTextEditor instead')
|
||||
deprecate('Use TextEditor::onDidAddTextEditor instead')
|
||||
when 'editor:detached'
|
||||
deprecate('Use Editor::onDidDestroy instead')
|
||||
deprecate('Use TextEditor::onDidDestroy instead')
|
||||
when 'editor:will-be-removed'
|
||||
deprecate('Use Editor::onDidDestroy instead')
|
||||
deprecate('Use TextEditor::onDidDestroy instead')
|
||||
when 'pane:active-item-changed'
|
||||
deprecate('Use Pane::onDidChangeActiveItem instead')
|
||||
when 'pane:active-item-modified-status-changed'
|
||||
@@ -504,7 +494,7 @@ class WorkspaceView extends View
|
||||
when 'pane:removed'
|
||||
deprecate('Use Pane::onDidDestroy instead')
|
||||
when 'selection:changed'
|
||||
deprecate('Use Editor::onDidChangeSelectionRange instead')
|
||||
deprecate('Use TextEditor::onDidChangeSelectionRange instead')
|
||||
originalPaneViewOn.apply(this, arguments)
|
||||
|
||||
# Deprecated
|
||||
|
||||
+14
-14
@@ -6,7 +6,7 @@ Q = require 'q'
|
||||
Serializable = require 'serializable'
|
||||
Delegator = require 'delegato'
|
||||
{Emitter} = require 'event-kit'
|
||||
Editor = require './editor'
|
||||
TextEditor = require './text-editor'
|
||||
PaneContainer = require './pane-container'
|
||||
Pane = require './pane'
|
||||
ViewRegistry = require './view-registry'
|
||||
@@ -19,7 +19,7 @@ WorkspaceView = null
|
||||
# editors, and manipulate panes. To add panels, you'll need to use the
|
||||
# {WorkspaceView} class for now until we establish APIs at the model layer.
|
||||
#
|
||||
# * `editor` {Editor} the new editor
|
||||
# * `editor` {TextEditor} the new editor
|
||||
#
|
||||
module.exports =
|
||||
class Workspace extends Model
|
||||
@@ -104,7 +104,7 @@ class Workspace extends Model
|
||||
# editors in the workspace.
|
||||
#
|
||||
# * `callback` {Function} to be called with current and future text editors.
|
||||
# * `editor` An {Editor} that is present in {::getTextEditors} at the time
|
||||
# * `editor` An {TextEditor} that is present in {::getTextEditors} at the time
|
||||
# of subscription or that is added at some later time.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
@@ -200,7 +200,7 @@ class Workspace extends Model
|
||||
#
|
||||
# * `callback` {Function} to be called panes are added.
|
||||
# * `event` {Object} with the following keys:
|
||||
# * `textEditor` {Editor} that was added.
|
||||
# * `textEditor` {TextEditor} that was added.
|
||||
# * `pane` {Pane} containing the added text editor.
|
||||
# * `index` {Number} indicating the index of the added text editor in its
|
||||
# pane.
|
||||
@@ -208,7 +208,7 @@ class Workspace extends Model
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
onDidAddTextEditor: (callback) ->
|
||||
@onDidAddPaneItem ({item, pane, index}) ->
|
||||
callback({textEditor: item, pane, index}) if item instanceof Editor
|
||||
callback({textEditor: item, pane, index}) if item instanceof TextEditor
|
||||
|
||||
eachEditor: (callback) ->
|
||||
deprecate("Use Workspace::observeTextEditors instead")
|
||||
@@ -221,7 +221,7 @@ class Workspace extends Model
|
||||
|
||||
editors = []
|
||||
for pane in @paneContainer.getPanes()
|
||||
editors.push(item) for item in pane.getItems() when item instanceof Editor
|
||||
editors.push(item) for item in pane.getItems() when item instanceof TextEditor
|
||||
|
||||
editors
|
||||
|
||||
@@ -258,7 +258,7 @@ class Workspace extends Model
|
||||
# If `false`, only the active pane will be searched for
|
||||
# an existing item for the same URI. Defaults to `false`.
|
||||
#
|
||||
# Returns a promise that resolves to the {Editor} for the file URI.
|
||||
# Returns a promise that resolves to the {TextEditor} for the file URI.
|
||||
open: (uri, options={}) ->
|
||||
searchAllPanes = options.searchAllPanes
|
||||
split = options.split
|
||||
@@ -352,7 +352,7 @@ class Workspace extends Model
|
||||
|
||||
# Public: Register an opener for a uri.
|
||||
#
|
||||
# An {Editor} will be used if no openers return a value.
|
||||
# An {TextEditor} will be used if no openers return a value.
|
||||
#
|
||||
# ## Examples
|
||||
#
|
||||
@@ -391,17 +391,17 @@ class Workspace extends Model
|
||||
|
||||
# Essential: Get all text editors in the workspace.
|
||||
#
|
||||
# Returns an {Array} of {Editor}s.
|
||||
# Returns an {Array} of {TextEditor}s.
|
||||
getTextEditors: ->
|
||||
@getPaneItems().filter (item) -> item instanceof Editor
|
||||
@getPaneItems().filter (item) -> item instanceof TextEditor
|
||||
|
||||
# Essential: Get the active item if it is an {Editor}.
|
||||
# Essential: Get the active item if it is an {TextEditor}.
|
||||
#
|
||||
# Returns an {Editor} or `undefined` if the current active item is not an
|
||||
# {Editor}.
|
||||
# Returns an {TextEditor} or `undefined` if the current active item is not an
|
||||
# {TextEditor}.
|
||||
getActiveTextEditor: ->
|
||||
activeItem = @getActivePaneItem()
|
||||
activeItem if activeItem instanceof Editor
|
||||
activeItem if activeItem instanceof TextEditor
|
||||
|
||||
# Deprecated:
|
||||
getActiveEditor: ->
|
||||
|
||||
@@ -173,7 +173,7 @@ body {
|
||||
-webkit-line-clamp: 10;
|
||||
overflow: hidden;
|
||||
|
||||
&:hover {
|
||||
&.expanded {
|
||||
-webkit-line-clamp: inherit;
|
||||
// overflow: hidden;
|
||||
}
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário