mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-11-10 10:17:11 +03:00
Merge branch 'master' into dh-async-repo
This commit is contained in:
commit
9765cb55ea
@ -8,6 +8,7 @@
|
||||
"dependencies": {
|
||||
"asar": "^0.8.0",
|
||||
"async": "~0.2.9",
|
||||
"aws-sdk": "^2.2.18",
|
||||
"donna": "^1.0.13",
|
||||
"formidable": "~1.0.14",
|
||||
"fs-plus": "2.x",
|
||||
|
@ -6,6 +6,7 @@ async = require 'async'
|
||||
fs = require 'fs-plus'
|
||||
GitHub = require 'github-releases'
|
||||
request = require 'request'
|
||||
AWS = require 'aws-sdk'
|
||||
|
||||
grunt = null
|
||||
|
||||
@ -210,7 +211,7 @@ deleteExistingAssets = (release, assetNames, callback) ->
|
||||
async.parallel(tasks, callback)
|
||||
|
||||
uploadAssets = (release, buildDir, assets, callback) ->
|
||||
upload = (release, assetName, assetPath, callback) ->
|
||||
uploadToReleases = (release, assetName, assetPath, callback) ->
|
||||
options =
|
||||
uri: release.upload_url.replace(/\{.*$/, "?name=#{assetName}")
|
||||
method: 'POST'
|
||||
@ -221,15 +222,43 @@ uploadAssets = (release, buildDir, assets, callback) ->
|
||||
|
||||
assetRequest = request options, (error, response, body='') ->
|
||||
if error? or response.statusCode >= 400
|
||||
logError("Upload release asset #{assetName} failed", error, body)
|
||||
logError("Upload release asset #{assetName} to Releases failed", error, body)
|
||||
callback(error ? new Error(response.statusCode))
|
||||
else
|
||||
callback(null, release)
|
||||
|
||||
fs.createReadStream(assetPath).pipe(assetRequest)
|
||||
|
||||
uploadToS3 = (release, assetName, assetPath, callback) ->
|
||||
s3Key = process.env.BUILD_ATOM_RELEASES_S3_KEY
|
||||
s3Secret = process.env.BUILD_ATOM_RELEASES_S3_SECRET
|
||||
s3Bucket = process.env.BUILD_ATOM_RELEASES_S3_BUCKET
|
||||
|
||||
unless s3Key and s3Secret and s3Bucket
|
||||
callback(new Error('BUILD_ATOM_RELEASES_S3_KEY, BUILD_ATOM_RELEASES_S3_SECRET, and BUILD_ATOM_RELEASES_S3_BUCKET environment variables must be set.'))
|
||||
return
|
||||
|
||||
s3Info =
|
||||
accessKeyId: s3Key
|
||||
secretAccessKey: s3Secret
|
||||
s3 = new AWS.S3 s3Info
|
||||
|
||||
key = "releases/#{release.tag_name}/#{assetName}"
|
||||
uploadParams =
|
||||
Bucket: s3Bucket
|
||||
ACL: 'public-read'
|
||||
Key: key
|
||||
Body: fs.createReadStream(assetPath)
|
||||
s3.upload uploadParams, (error, data) ->
|
||||
if error?
|
||||
logError("Upload release asset #{assetName} to S3 failed", error)
|
||||
callback(error)
|
||||
else
|
||||
callback(null, release)
|
||||
|
||||
tasks = []
|
||||
for {assetName} in assets
|
||||
assetPath = path.join(buildDir, assetName)
|
||||
tasks.push(upload.bind(this, release, assetName, assetPath))
|
||||
tasks.push(uploadToReleases.bind(this, release, assetName, assetPath))
|
||||
tasks.push(uploadToS3.bind(this, release, assetName, assetPath))
|
||||
async.parallel(tasks, callback)
|
||||
|
12
package.json
12
package.json
@ -77,7 +77,7 @@
|
||||
"autocomplete-css": "0.11.0",
|
||||
"autocomplete-html": "0.7.2",
|
||||
"autocomplete-plus": "2.23.1",
|
||||
"autocomplete-snippets": "1.8.0",
|
||||
"autocomplete-snippets": "1.9.0",
|
||||
"autoflow": "0.26.0",
|
||||
"autosave": "0.23.0",
|
||||
"background-tips": "0.26.0",
|
||||
@ -98,7 +98,7 @@
|
||||
"keybinding-resolver": "0.33.0",
|
||||
"line-ending-selector": "0.3.0",
|
||||
"link": "0.31.0",
|
||||
"markdown-preview": "0.156.2",
|
||||
"markdown-preview": "0.157.0",
|
||||
"metrics": "0.53.1",
|
||||
"notifications": "0.62.1",
|
||||
"open-on-github": "0.40.0",
|
||||
@ -125,13 +125,13 @@
|
||||
"language-gfm": "0.81.0",
|
||||
"language-git": "0.10.0",
|
||||
"language-go": "0.40.0",
|
||||
"language-html": "0.42.0",
|
||||
"language-html": "0.43.0",
|
||||
"language-hyperlink": "0.15.0",
|
||||
"language-java": "0.17.0",
|
||||
"language-javascript": "0.102.2",
|
||||
"language-javascript": "0.103.0",
|
||||
"language-json": "0.17.1",
|
||||
"language-less": "0.29.0",
|
||||
"language-make": "0.20.0",
|
||||
"language-make": "0.21.0",
|
||||
"language-mustache": "0.13.0",
|
||||
"language-objective-c": "0.15.0",
|
||||
"language-perl": "0.31.0",
|
||||
@ -141,7 +141,7 @@
|
||||
"language-ruby": "0.64.1",
|
||||
"language-ruby-on-rails": "0.24.0",
|
||||
"language-sass": "0.44.1",
|
||||
"language-shellscript": "0.20.0",
|
||||
"language-shellscript": "0.21.0",
|
||||
"language-source": "0.9.0",
|
||||
"language-sql": "0.19.0",
|
||||
"language-text": "0.7.0",
|
||||
|
@ -40,6 +40,10 @@ function setEnvironmentVariables() {
|
||||
process.env.CC = 'clang';
|
||||
process.env.CXX = 'clang++';
|
||||
process.env.npm_config_clang = '1';
|
||||
} else if (process.platform === 'win32') {
|
||||
process.env.BUILD_ATOM_RELEASES_S3_KEY = process.env.BUILD_ATOM_WIN_RELEASES_S3_KEY
|
||||
process.env.BUILD_ATOM_RELEASES_S3_SECRET = process.env.BUILD_ATOM_WIN_RELEASES_S3_SECRET
|
||||
process.env.BUILD_ATOM_RELEASES_S3_BUCKET = process.env.BUILD_ATOM_WIN_RELEASES_S3_BUCKET
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,9 @@
|
||||
set -e
|
||||
|
||||
export ATOM_ACCESS_TOKEN=$BUILD_ATOM_LINUX_ACCESS_TOKEN
|
||||
export BUILD_ATOM_RELEASES_S3_KEY=$BUILD_ATOM_LINUX_RELEASES_S3_KEY
|
||||
export BUILD_ATOM_RELEASES_S3_SECRET=$BUILD_ATOM_LINUX_RELEASES_S3_SECRET
|
||||
export BUILD_ATOM_RELEASES_S3_BUCKET=$BUILD_ATOM_LINUX_RELEASES_S3_BUCKET
|
||||
|
||||
if [ -d /usr/local/share/nodenv ]; then
|
||||
export NODENV_ROOT=/usr/local/share/nodenv
|
||||
|
@ -8,5 +8,8 @@ docker run \
|
||||
--env JANKY_SHA1="$JANKY_SHA1" \
|
||||
--env JANKY_BRANCH="$JANKY_BRANCH" \
|
||||
--env ATOM_ACCESS_TOKEN="$BUILD_ATOM_RPM_ACCESS_TOKEN" \
|
||||
--env BUILD_ATOM_RELEASES_S3_KEY="$BUILD_ATOM_RPM_RELEASES_S3_KEY" \
|
||||
--env BUILD_ATOM_RELEASES_S3_SECRET="$BUILD_ATOM_RPM_RELEASES_S3_SECRET" \
|
||||
--env BUILD_ATOM_RELEASES_S3_BUCKET="$BUILD_ATOM_RPM_RELEASES_S3_BUCKET" \
|
||||
atom-rpm /atom/script/rpmbuild
|
||||
docker rmi atom-rpm
|
||||
|
@ -81,6 +81,27 @@ describe 'CompileCache', ->
|
||||
waits(1)
|
||||
runs ->
|
||||
error = new Error("Oops again")
|
||||
console.log error.stack
|
||||
expect(error.stack).toContain('compile-cache-spec.coffee')
|
||||
expect(Array.isArray(error.getRawStack())).toBe true
|
||||
|
||||
it 'does not infinitely loop when the original prepareStackTrace value is reassigned', ->
|
||||
originalPrepareStackTrace = Error.prepareStackTrace
|
||||
|
||||
Error.prepareStackTrace = -> 'a-stack-trace'
|
||||
Error.prepareStackTrace = originalPrepareStackTrace
|
||||
|
||||
error = new Error('Oops')
|
||||
expect(error.stack).toContain('compile-cache-spec.coffee')
|
||||
expect(Array.isArray(error.getRawStack())).toBe true
|
||||
|
||||
it 'does not infinitely loop when the assigned prepareStackTrace calls the original prepareStackTrace', ->
|
||||
originalPrepareStackTrace = Error.prepareStackTrace
|
||||
|
||||
Error.prepareStackTrace = (error, stack) ->
|
||||
error.foo = 'bar'
|
||||
originalPrepareStackTrace(error, stack)
|
||||
|
||||
error = new Error('Oops')
|
||||
expect(error.stack).toContain('compile-cache-spec.coffee')
|
||||
expect(error.foo).toBe('bar')
|
||||
expect(Array.isArray(error.getRawStack())).toBe true
|
||||
|
6
spec/fixtures/packages/package-with-deserializers/deserializer-1.js
vendored
Normal file
6
spec/fixtures/packages/package-with-deserializers/deserializer-1.js
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
module.exports = function (state) {
|
||||
return {
|
||||
wasDeserializedBy: 'Deserializer1',
|
||||
state: state
|
||||
}
|
||||
}
|
6
spec/fixtures/packages/package-with-deserializers/deserializer-2.js
vendored
Normal file
6
spec/fixtures/packages/package-with-deserializers/deserializer-2.js
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
module.exports = function (state) {
|
||||
return {
|
||||
wasDeserializedBy: 'Deserializer2',
|
||||
state: state
|
||||
}
|
||||
}
|
3
spec/fixtures/packages/package-with-deserializers/index.js
vendored
Normal file
3
spec/fixtures/packages/package-with-deserializers/index.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
activate: function() {}
|
||||
}
|
9
spec/fixtures/packages/package-with-deserializers/package.json
vendored
Normal file
9
spec/fixtures/packages/package-with-deserializers/package.json
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "package-with-deserializers",
|
||||
"version": "1.0.0",
|
||||
"main": "./index",
|
||||
"deserializers": {
|
||||
"Deserializer1": "./deserializer-1.js",
|
||||
"Deserializer2": "./deserializer-2.js"
|
||||
}
|
||||
}
|
5
spec/fixtures/packages/package-with-eval-time-api-calls/index.js
vendored
Normal file
5
spec/fixtures/packages/package-with-eval-time-api-calls/index.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
atom.deserializers.add('MyDeserializer', function (state) {
|
||||
return {state: state, a: 'b'}
|
||||
})
|
||||
|
||||
exports.activate = function () {}
|
5
spec/fixtures/packages/package-with-eval-time-api-calls/package.json
vendored
Normal file
5
spec/fixtures/packages/package-with-eval-time-api-calls/package.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "package-with-eval-time-api-calls",
|
||||
"version": "1.2.3",
|
||||
"main": "./index"
|
||||
}
|
13
spec/fixtures/packages/package-with-json-config-schema/package.json
vendored
Normal file
13
spec/fixtures/packages/package-with-json-config-schema/package.json
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "package-with-json-config-schema",
|
||||
"configSchema": {
|
||||
"a": {
|
||||
"type": "number",
|
||||
"default": 5
|
||||
},
|
||||
"b": {
|
||||
"type": "string",
|
||||
"default": "five"
|
||||
}
|
||||
}
|
||||
}
|
@ -1 +1,2 @@
|
||||
'main': 'main-module.coffee'
|
||||
'version': '2.3.4'
|
||||
|
3
spec/fixtures/packages/package-with-view-providers/deserializer.js
vendored
Normal file
3
spec/fixtures/packages/package-with-view-providers/deserializer.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
module.exports = function (state) {
|
||||
return {state: state}
|
||||
}
|
3
spec/fixtures/packages/package-with-view-providers/index.js
vendored
Normal file
3
spec/fixtures/packages/package-with-view-providers/index.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
activate: function() {}
|
||||
}
|
12
spec/fixtures/packages/package-with-view-providers/package.json
vendored
Normal file
12
spec/fixtures/packages/package-with-view-providers/package.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "package-with-view-providers",
|
||||
"main": "./index",
|
||||
"version": "1.0.0",
|
||||
"deserializers": {
|
||||
"DeserializerFromPackageWithViewProviders": "./deserializer"
|
||||
},
|
||||
"viewProviders": [
|
||||
"./view-provider-1",
|
||||
"./view-provider-2"
|
||||
]
|
||||
}
|
9
spec/fixtures/packages/package-with-view-providers/view-provider-1.js
vendored
Normal file
9
spec/fixtures/packages/package-with-view-providers/view-provider-1.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = function (model) {
|
||||
if (model.worksWithViewProvider1) {
|
||||
let element = document.createElement('div')
|
||||
element.dataset['createdBy'] = 'view-provider-1'
|
||||
return element
|
||||
}
|
||||
}
|
9
spec/fixtures/packages/package-with-view-providers/view-provider-2.js
vendored
Normal file
9
spec/fixtures/packages/package-with-view-providers/view-provider-2.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = function (model) {
|
||||
if (model.worksWithViewProvider2) {
|
||||
let element = document.createElement('div')
|
||||
element.dataset['createdBy'] = 'view-provider-2'
|
||||
return element
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
path = require 'path'
|
||||
Package = require '../src/package'
|
||||
{Disposable} = require 'atom'
|
||||
{mockLocalStorage} = require './spec-helper'
|
||||
|
||||
describe "PackageManager", ->
|
||||
workspaceElement = null
|
||||
@ -79,6 +80,111 @@ describe "PackageManager", ->
|
||||
|
||||
expect(loadedPackage.name).toBe "package-with-main"
|
||||
|
||||
it "registers any deserializers specified in the package's package.json", ->
|
||||
pack = atom.packages.loadPackage("package-with-deserializers")
|
||||
|
||||
state1 = {deserializer: 'Deserializer1', a: 'b'}
|
||||
expect(atom.deserializers.deserialize(state1)).toEqual {
|
||||
wasDeserializedBy: 'Deserializer1'
|
||||
state: state1
|
||||
}
|
||||
|
||||
state2 = {deserializer: 'Deserializer2', c: 'd'}
|
||||
expect(atom.deserializers.deserialize(state2)).toEqual {
|
||||
wasDeserializedBy: 'Deserializer2'
|
||||
state: state2
|
||||
}
|
||||
|
||||
expect(pack.mainModule).toBeNull()
|
||||
|
||||
describe "when there are view providers specified in the package's package.json", ->
|
||||
model1 = {worksWithViewProvider1: true}
|
||||
model2 = {worksWithViewProvider2: true}
|
||||
|
||||
afterEach ->
|
||||
atom.packages.deactivatePackage('package-with-view-providers')
|
||||
atom.packages.unloadPackage('package-with-view-providers')
|
||||
|
||||
it "does not load the view providers immediately", ->
|
||||
pack = atom.packages.loadPackage("package-with-view-providers")
|
||||
expect(pack.mainModule).toBeNull()
|
||||
|
||||
expect(-> atom.views.getView(model1)).toThrow()
|
||||
expect(-> atom.views.getView(model2)).toThrow()
|
||||
|
||||
it "registers the view providers when the package is activated", ->
|
||||
pack = atom.packages.loadPackage("package-with-view-providers")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-view-providers").then ->
|
||||
element1 = atom.views.getView(model1)
|
||||
expect(element1 instanceof HTMLDivElement).toBe true
|
||||
expect(element1.dataset.createdBy).toBe 'view-provider-1'
|
||||
|
||||
element2 = atom.views.getView(model2)
|
||||
expect(element2 instanceof HTMLDivElement).toBe true
|
||||
expect(element2.dataset.createdBy).toBe 'view-provider-2'
|
||||
|
||||
it "registers the view providers when any of the package's deserializers are used", ->
|
||||
pack = atom.packages.loadPackage("package-with-view-providers")
|
||||
|
||||
spyOn(atom.views, 'addViewProvider').andCallThrough()
|
||||
atom.deserializers.deserialize({
|
||||
deserializer: 'DeserializerFromPackageWithViewProviders',
|
||||
a: 'b'
|
||||
})
|
||||
expect(atom.views.addViewProvider.callCount).toBe 2
|
||||
|
||||
atom.deserializers.deserialize({
|
||||
deserializer: 'DeserializerFromPackageWithViewProviders',
|
||||
a: 'b'
|
||||
})
|
||||
expect(atom.views.addViewProvider.callCount).toBe 2
|
||||
|
||||
element1 = atom.views.getView(model1)
|
||||
expect(element1 instanceof HTMLDivElement).toBe true
|
||||
expect(element1.dataset.createdBy).toBe 'view-provider-1'
|
||||
|
||||
element2 = atom.views.getView(model2)
|
||||
expect(element2 instanceof HTMLDivElement).toBe true
|
||||
expect(element2.dataset.createdBy).toBe 'view-provider-2'
|
||||
|
||||
it "registers the config schema in the package's metadata, if present", ->
|
||||
pack = atom.packages.loadPackage("package-with-json-config-schema")
|
||||
|
||||
expect(atom.config.getSchema('package-with-json-config-schema')).toEqual {
|
||||
type: 'object'
|
||||
properties: {
|
||||
a: {type: 'number', default: 5}
|
||||
b: {type: 'string', default: 'five'}
|
||||
}
|
||||
}
|
||||
|
||||
expect(pack.mainModule).toBeNull()
|
||||
|
||||
describe "when a package does not have deserializers, view providers or a config schema in its package.json", ->
|
||||
beforeEach ->
|
||||
atom.packages.unloadPackage('package-with-main')
|
||||
mockLocalStorage()
|
||||
|
||||
it "defers loading the package's main module if the package previously used no Atom APIs when its main module was required", ->
|
||||
pack1 = atom.packages.loadPackage('package-with-main')
|
||||
expect(pack1.mainModule).toBeDefined()
|
||||
|
||||
atom.packages.unloadPackage('package-with-main')
|
||||
|
||||
pack2 = atom.packages.loadPackage('package-with-main')
|
||||
expect(pack2.mainModule).toBeNull()
|
||||
|
||||
it "does not defer loading the package's main module if the package previously used Atom APIs when its main module was required", ->
|
||||
pack1 = atom.packages.loadPackage('package-with-eval-time-api-calls')
|
||||
expect(pack1.mainModule).toBeDefined()
|
||||
|
||||
atom.packages.unloadPackage('package-with-eval-time-api-calls')
|
||||
|
||||
pack2 = atom.packages.loadPackage('package-with-eval-time-api-calls')
|
||||
expect(pack2.mainModule).not.toBeNull()
|
||||
|
||||
describe "::unloadPackage(name)", ->
|
||||
describe "when the package is active", ->
|
||||
it "throws an error", ->
|
||||
|
@ -1,6 +1,7 @@
|
||||
path = require 'path'
|
||||
Package = require '../src/package'
|
||||
ThemePackage = require '../src/theme-package'
|
||||
{mockLocalStorage} = require './spec-helper'
|
||||
|
||||
describe "Package", ->
|
||||
build = (constructor, path) ->
|
||||
@ -10,6 +11,7 @@ describe "Package", ->
|
||||
keymapManager: atom.keymaps, commandRegistry: atom.command,
|
||||
grammarRegistry: atom.grammars, themeManager: atom.themes,
|
||||
menuManager: atom.menu, contextMenuManager: atom.contextMenu,
|
||||
deserializerManager: atom.deserializers, viewRegistry: atom.views,
|
||||
devMode: false
|
||||
)
|
||||
|
||||
@ -19,10 +21,7 @@ describe "Package", ->
|
||||
|
||||
describe "when the package contains incompatible native modules", ->
|
||||
beforeEach ->
|
||||
items = {}
|
||||
spyOn(global.localStorage, 'setItem').andCallFake (key, item) -> items[key] = item; undefined
|
||||
spyOn(global.localStorage, 'getItem').andCallFake (key) -> items[key] ? null
|
||||
spyOn(global.localStorage, 'removeItem').andCallFake (key) -> delete items[key]; undefined
|
||||
mockLocalStorage()
|
||||
|
||||
it "does not activate it", ->
|
||||
packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-incompatible-native-module')
|
||||
@ -54,10 +53,7 @@ describe "Package", ->
|
||||
|
||||
describe "::rebuild()", ->
|
||||
beforeEach ->
|
||||
items = {}
|
||||
spyOn(global.localStorage, 'setItem').andCallFake (key, item) -> items[key] = item; undefined
|
||||
spyOn(global.localStorage, 'getItem').andCallFake (key) -> items[key] ? null
|
||||
spyOn(global.localStorage, 'removeItem').andCallFake (key) -> delete items[key]; undefined
|
||||
mockLocalStorage()
|
||||
|
||||
it "returns a promise resolving to the results of `apm rebuild`", ->
|
||||
packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-index')
|
||||
|
@ -265,3 +265,9 @@ window.advanceClock = (delta=1) ->
|
||||
true
|
||||
|
||||
callback() for callback in callbacks
|
||||
|
||||
exports.mockLocalStorage = ->
|
||||
items = {}
|
||||
spyOn(global.localStorage, 'setItem').andCallFake (key, item) -> items[key] = item.toString(); undefined
|
||||
spyOn(global.localStorage, 'getItem').andCallFake (key) -> items[key] ? null
|
||||
spyOn(global.localStorage, 'removeItem').andCallFake (key) -> delete items[key]; undefined
|
||||
|
@ -47,6 +47,21 @@ describe "ViewRegistry", ->
|
||||
expect(view2 instanceof TestView).toBe true
|
||||
expect(view2.model).toBe subclassModel
|
||||
|
||||
describe "when a view provider is registered generically, and works with the object", ->
|
||||
it "constructs a view element and assigns the model on it", ->
|
||||
model = {a: 'b'}
|
||||
|
||||
registry.addViewProvider (model) ->
|
||||
if model.a is 'b'
|
||||
element = document.createElement('div')
|
||||
element.className = 'test-element'
|
||||
element
|
||||
|
||||
view = registry.getView({a: 'b'})
|
||||
expect(view.className).toBe 'test-element'
|
||||
|
||||
expect(-> registry.getView({a: 'c'})).toThrow()
|
||||
|
||||
describe "when no view provider is registered for the object's constructor", ->
|
||||
it "throws an exception", ->
|
||||
expect(-> registry.getView(new Object)).toThrow()
|
||||
|
@ -661,7 +661,7 @@ describe "Workspace", ->
|
||||
describe "::isTextEditor(obj)", ->
|
||||
it "returns true when the passed object is an instance of `TextEditor`", ->
|
||||
expect(workspace.isTextEditor(atom.workspace.buildTextEditor())).toBe(true)
|
||||
expect(workspace.isTextEditor({getText: ->})).toBe(false)
|
||||
expect(workspace.isTextEditor({getText: -> null})).toBe(false)
|
||||
expect(workspace.isTextEditor(null)).toBe(false)
|
||||
expect(workspace.isTextEditor(undefined)).toBe(false)
|
||||
|
||||
|
@ -151,7 +151,7 @@ class AtomEnvironment extends Model
|
||||
@packages = new PackageManager({
|
||||
devMode, configDirPath, resourcePath, safeMode, @config, styleManager: @styles,
|
||||
commandRegistry: @commands, keymapManager: @keymaps, notificationManager: @notifications,
|
||||
grammarRegistry: @grammars
|
||||
grammarRegistry: @grammars, deserializerManager: @deserializers, viewRegistry: @views
|
||||
})
|
||||
|
||||
@themes = new ThemeManager({
|
||||
|
@ -82,6 +82,7 @@ class AtomApplication
|
||||
@listenForArgumentsFromNewProcess()
|
||||
@setupJavaScriptArguments()
|
||||
@handleEvents()
|
||||
@setupDockMenu()
|
||||
@storageFolder = new StorageFolder(process.env.ATOM_HOME)
|
||||
|
||||
if options.pathsToOpen?.length > 0 or options.urlsToOpen?.length > 0 or options.test
|
||||
@ -280,6 +281,13 @@ class AtomApplication
|
||||
ipc.on 'write-to-stderr', (event, output) ->
|
||||
process.stderr.write(output)
|
||||
|
||||
setupDockMenu: ->
|
||||
if process.platform is 'darwin'
|
||||
dockMenu = Menu.buildFromTemplate [
|
||||
{label: 'New Window', click: => @emit('application:new-window')}
|
||||
]
|
||||
app.dock.setMenu dockMenu
|
||||
|
||||
# Public: Executes the given command.
|
||||
#
|
||||
# If it isn't handled globally, delegate to the currently focused window.
|
||||
|
@ -163,8 +163,12 @@ var prepareStackTraceWithSourceMapping = Error.prepareStackTrace
|
||||
let prepareStackTrace = prepareStackTraceWithSourceMapping
|
||||
|
||||
function prepareStackTraceWithRawStackAssignment (error, frames) {
|
||||
error.rawStack = frames
|
||||
return prepareStackTrace(error, frames)
|
||||
if (error.rawStack) { // avoid infinite recursion
|
||||
return prepareStackTraceWithSourceMapping(error, frames)
|
||||
} else {
|
||||
error.rawStack = frames
|
||||
return prepareStackTrace(error, frames)
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(Error, 'prepareStackTrace', {
|
||||
|
@ -381,8 +381,8 @@ class Config
|
||||
# ```
|
||||
#
|
||||
# * `keyPath` {String} name of the key to observe
|
||||
# * `options` {Object}
|
||||
# * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from
|
||||
# * `options` (optional) {Object}
|
||||
# * `scope` (optional) {ScopeDescriptor} describing a path from
|
||||
# the root of the syntax tree to a token. Get one by calling
|
||||
# {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples.
|
||||
# See [the scopes docs](https://atom.io/docs/latest/behind-atom-scoped-settings-scopes-and-scope-descriptors)
|
||||
@ -412,8 +412,8 @@ class Config
|
||||
#
|
||||
# * `keyPath` (optional) {String} name of the key to observe. Must be
|
||||
# specified if `scopeDescriptor` is specified.
|
||||
# * `optional` (optional) {Object}
|
||||
# * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from
|
||||
# * `options` (optional) {Object}
|
||||
# * `scope` (optional) {ScopeDescriptor} describing a path from
|
||||
# the root of the syntax tree to a token. Get one by calling
|
||||
# {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples.
|
||||
# See [the scopes docs](https://atom.io/docs/latest/behind-atom-scoped-settings-scopes-and-scope-descriptors)
|
||||
|
@ -39,6 +39,9 @@ class DeserializerManager
|
||||
delete @deserializers[deserializer.name] for deserializer in deserializers
|
||||
return
|
||||
|
||||
getDeserializerCount: ->
|
||||
Object.keys(@deserializers).length
|
||||
|
||||
# Public: Deserialize the state and params.
|
||||
#
|
||||
# * `state` The state {Object} to deserialize.
|
||||
|
@ -31,7 +31,8 @@ class PackageManager
|
||||
constructor: (params) ->
|
||||
{
|
||||
configDirPath, @devMode, safeMode, @resourcePath, @config, @styleManager,
|
||||
@notificationManager, @keymapManager, @commandRegistry, @grammarRegistry
|
||||
@notificationManager, @keymapManager, @commandRegistry, @grammarRegistry,
|
||||
@deserializerManager, @viewRegistry
|
||||
} = params
|
||||
|
||||
@emitter = new Emitter
|
||||
@ -375,7 +376,8 @@ class PackageManager
|
||||
options = {
|
||||
path: packagePath, metadata, packageManager: this, @config, @styleManager,
|
||||
@commandRegistry, @keymapManager, @devMode, @notificationManager,
|
||||
@grammarRegistry, @themeManager, @menuManager, @contextMenuManager
|
||||
@grammarRegistry, @themeManager, @menuManager, @contextMenuManager,
|
||||
@deserializerManager, @viewRegistry
|
||||
}
|
||||
if metadata.theme
|
||||
pack = new ThemePackage(options)
|
||||
|
@ -33,7 +33,7 @@ class Package
|
||||
{
|
||||
@path, @metadata, @packageManager, @config, @styleManager, @commandRegistry,
|
||||
@keymapManager, @devMode, @notificationManager, @grammarRegistry, @themeManager,
|
||||
@menuManager, @contextMenuManager
|
||||
@menuManager, @contextMenuManager, @deserializerManager, @viewRegistry
|
||||
} = params
|
||||
|
||||
@emitter = new Emitter
|
||||
@ -84,12 +84,24 @@ class Package
|
||||
@loadKeymaps()
|
||||
@loadMenus()
|
||||
@loadStylesheets()
|
||||
@loadDeserializers()
|
||||
@configSchemaRegisteredOnLoad = @registerConfigSchemaFromMetadata()
|
||||
@settingsPromise = @loadSettings()
|
||||
@requireMainModule() unless @mainModule? or @activationShouldBeDeferred()
|
||||
if @shouldRequireMainModuleOnLoad() and not @mainModule?
|
||||
@requireMainModule()
|
||||
catch error
|
||||
@handleError("Failed to load the #{@name} package", error)
|
||||
this
|
||||
|
||||
shouldRequireMainModuleOnLoad: ->
|
||||
not (
|
||||
@metadata.deserializers? or
|
||||
@metadata.viewProviders? or
|
||||
@metadata.configSchema? or
|
||||
@activationShouldBeDeferred() or
|
||||
localStorage.getItem(@getCanDeferMainModuleRequireStorageKey()) is 'true'
|
||||
)
|
||||
|
||||
reset: ->
|
||||
@stylesheets = []
|
||||
@keymaps = []
|
||||
@ -117,9 +129,12 @@ class Package
|
||||
|
||||
activateNow: ->
|
||||
try
|
||||
@activateConfig()
|
||||
@requireMainModule() unless @mainModule?
|
||||
@configSchemaRegisteredOnActivate = @registerConfigSchemaFromMainModule()
|
||||
@registerViewProviders()
|
||||
@activateStylesheets()
|
||||
if @mainModule? and not @mainActivated
|
||||
@mainModule.activateConfig?()
|
||||
@mainModule.activate?(@packageManager.getPackageState(@name) ? {})
|
||||
@mainActivated = true
|
||||
@activateServices()
|
||||
@ -128,15 +143,22 @@ class Package
|
||||
|
||||
@resolveActivationPromise?()
|
||||
|
||||
activateConfig: ->
|
||||
return if @configActivated
|
||||
registerConfigSchemaFromMetadata: ->
|
||||
if configSchema = @metadata.configSchema
|
||||
@config.setSchema @name, {type: 'object', properties: configSchema}
|
||||
true
|
||||
else
|
||||
false
|
||||
|
||||
@requireMainModule() unless @mainModule?
|
||||
if @mainModule?
|
||||
registerConfigSchemaFromMainModule: ->
|
||||
if @mainModule? and not @configSchemaRegisteredOnLoad
|
||||
if @mainModule.config? and typeof @mainModule.config is 'object'
|
||||
@config.setSchema @name, {type: 'object', properties: @mainModule.config}
|
||||
@mainModule.activateConfig?()
|
||||
@configActivated = true
|
||||
return true
|
||||
false
|
||||
|
||||
# TODO: Remove. Settings view calls this method currently.
|
||||
activateConfig: -> @registerConfigSchemaFromMainModule()
|
||||
|
||||
activateStylesheets: ->
|
||||
return if @stylesheetsActivated
|
||||
@ -253,6 +275,26 @@ class Package
|
||||
@stylesheets = @getStylesheetPaths().map (stylesheetPath) =>
|
||||
[stylesheetPath, @themeManager.loadStylesheet(stylesheetPath, true)]
|
||||
|
||||
loadDeserializers: ->
|
||||
if @metadata.deserializers?
|
||||
for name, implementationPath of @metadata.deserializers
|
||||
do =>
|
||||
deserializePath = path.join(@path, implementationPath)
|
||||
deserializeFunction = null
|
||||
atom.deserializers.add
|
||||
name: name,
|
||||
deserialize: =>
|
||||
@registerViewProviders()
|
||||
deserializeFunction ?= require(deserializePath)
|
||||
deserializeFunction.apply(this, arguments)
|
||||
return
|
||||
|
||||
registerViewProviders: ->
|
||||
if @metadata.viewProviders? and not @registeredViewProviders
|
||||
for implementationPath in @metadata.viewProviders
|
||||
@viewRegistry.addViewProvider(require(path.join(@path, implementationPath)))
|
||||
@registeredViewProviders = true
|
||||
|
||||
getStylesheetsPath: ->
|
||||
path.join(@path, 'styles')
|
||||
|
||||
@ -343,21 +385,18 @@ class Package
|
||||
@activationPromise = null
|
||||
@resolveActivationPromise = null
|
||||
@activationCommandSubscriptions?.dispose()
|
||||
@configSchemaRegisteredOnActivate = false
|
||||
@deactivateResources()
|
||||
@deactivateConfig()
|
||||
@deactivateKeymaps()
|
||||
if @mainActivated
|
||||
try
|
||||
@mainModule?.deactivate?()
|
||||
@mainModule?.deactivateConfig?()
|
||||
@mainActivated = false
|
||||
catch e
|
||||
console.error "Error deactivating package '#{@name}'", e.stack
|
||||
@emitter.emit 'did-deactivate'
|
||||
|
||||
deactivateConfig: ->
|
||||
@mainModule?.deactivateConfig?()
|
||||
@configActivated = false
|
||||
|
||||
deactivateResources: ->
|
||||
grammar.deactivate() for grammar in @grammars
|
||||
settings.deactivate() for settings in @settings
|
||||
@ -392,7 +431,13 @@ class Package
|
||||
mainModulePath = @getMainModulePath()
|
||||
if fs.isFileSync(mainModulePath)
|
||||
@mainModuleRequired = true
|
||||
|
||||
previousViewProviderCount = @viewRegistry.getViewProviderCount()
|
||||
previousDeserializerCount = @deserializerManager.getDeserializerCount()
|
||||
@mainModule = require(mainModulePath)
|
||||
if (@viewRegistry.getViewProviderCount() is previousViewProviderCount and
|
||||
@deserializerManager.getDeserializerCount() is previousDeserializerCount)
|
||||
localStorage.setItem(@getCanDeferMainModuleRequireStorageKey(), 'true')
|
||||
|
||||
getMainModulePath: ->
|
||||
return @mainModulePath if @resolvedMainModulePath
|
||||
@ -586,6 +631,9 @@ class Package
|
||||
electronVersion = process.versions['electron'] ? process.versions['atom-shell']
|
||||
"installed-packages:#{@name}:#{@metadata.version}:electron-#{electronVersion}:incompatible-native-modules"
|
||||
|
||||
getCanDeferMainModuleRequireStorageKey: ->
|
||||
"installed-packages:#{@name}:#{@metadata.version}:can-defer-main-module-require"
|
||||
|
||||
# Get the incompatible native modules that this package depends on.
|
||||
# This recurses through all dependencies and requires all modules that
|
||||
# contain a `.node` file.
|
||||
|
@ -3,6 +3,8 @@ Grim = require 'grim'
|
||||
{Disposable} = require 'event-kit'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
AnyConstructor = Symbol('any-constructor')
|
||||
|
||||
# Essential: `ViewRegistry` handles the association between model and view
|
||||
# types in Atom. We call this association a View Provider. As in, for a given
|
||||
# model, this class can provide a view via {::getView}, as long as the
|
||||
@ -76,16 +78,27 @@ class ViewRegistry
|
||||
# textEditorElement
|
||||
# ```
|
||||
#
|
||||
# * `modelConstructor` Constructor {Function} for your model.
|
||||
# * `modelConstructor` (optional) Constructor {Function} for your model. If
|
||||
# a constructor is given, the `createView` function will only be used
|
||||
# for model objects inheriting from that constructor. Otherwise, it will
|
||||
# will be called for any object.
|
||||
# * `createView` Factory {Function} that is passed an instance of your model
|
||||
# and must return a subclass of `HTMLElement` or `undefined`.
|
||||
# and must return a subclass of `HTMLElement` or `undefined`. If it returns
|
||||
# `undefined`, then the registry will continue to search for other view
|
||||
# providers.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to remove the
|
||||
# added provider.
|
||||
addViewProvider: (modelConstructor, createView) ->
|
||||
if arguments.length is 1
|
||||
Grim.deprecate("atom.views.addViewProvider now takes 2 arguments: a model constructor and a createView function. See docs for details.")
|
||||
provider = modelConstructor
|
||||
switch typeof modelConstructor
|
||||
when 'function'
|
||||
provider = {createView: modelConstructor, modelConstructor: AnyConstructor}
|
||||
when 'object'
|
||||
Grim.deprecate("atom.views.addViewProvider now takes 2 arguments: a model constructor and a createView function. See docs for details.")
|
||||
provider = modelConstructor
|
||||
else
|
||||
throw new TypeError("Arguments to addViewProvider must be functions")
|
||||
else
|
||||
provider = {modelConstructor, createView}
|
||||
|
||||
@ -93,6 +106,9 @@ class ViewRegistry
|
||||
new Disposable =>
|
||||
@providers = @providers.filter (p) -> p isnt provider
|
||||
|
||||
getViewProviderCount: ->
|
||||
@providers.length
|
||||
|
||||
# Essential: Get the view associated with an object in the workspace.
|
||||
#
|
||||
# If you're just *using* the workspace, you shouldn't need to access the view
|
||||
@ -153,25 +169,34 @@ class ViewRegistry
|
||||
|
||||
createView: (object) ->
|
||||
if object instanceof HTMLElement
|
||||
object
|
||||
else if object?.element instanceof HTMLElement
|
||||
object.element
|
||||
else if object?.jquery
|
||||
object[0]
|
||||
else if provider = @findProvider(object)
|
||||
element = provider.createView?(object, @atomEnvironment)
|
||||
unless element?
|
||||
element = new provider.viewConstructor
|
||||
element.initialize?(object) ? element.setModel?(object)
|
||||
element
|
||||
else if viewConstructor = object?.getViewClass?()
|
||||
view = new viewConstructor(object)
|
||||
view[0]
|
||||
else
|
||||
throw new Error("Can't create a view for #{object.constructor.name} instance. Please register a view provider.")
|
||||
return object
|
||||
|
||||
findProvider: (object) ->
|
||||
find @providers, ({modelConstructor}) -> object instanceof modelConstructor
|
||||
if object?.element instanceof HTMLElement
|
||||
return object.element
|
||||
|
||||
if object?.jquery
|
||||
return object[0]
|
||||
|
||||
for provider in @providers
|
||||
if provider.modelConstructor is AnyConstructor
|
||||
if element = provider.createView(object, @atomEnvironment)
|
||||
return element
|
||||
continue
|
||||
|
||||
if object instanceof provider.modelConstructor
|
||||
if element = provider.createView?(object, @atomEnvironment)
|
||||
return element
|
||||
|
||||
if viewConstructor = provider.viewConstructor
|
||||
element = new viewConstructor
|
||||
element.initialize?(object) ? element.setModel?(object)
|
||||
return element
|
||||
|
||||
if viewConstructor = object?.getViewClass?()
|
||||
view = new viewConstructor(object)
|
||||
return view[0]
|
||||
|
||||
throw new Error("Can't create a view for #{object.constructor.name} instance. Please register a view provider.")
|
||||
|
||||
updateDocument: (fn) ->
|
||||
@documentWriters.push(fn)
|
||||
|
Loading…
Reference in New Issue
Block a user