mirror of
https://github.com/atom/atom.git
synced 2026-01-15 01:48:15 -05:00
Merge branch 'master' into wl-electron-35
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
temp = require('temp').track()
|
||||
|
||||
_ = require 'underscore-plus'
|
||||
async = require 'async'
|
||||
@@ -86,7 +87,7 @@ module.exports = (grunt) ->
|
||||
packageSpecQueue.concurrency = Math.max(1, concurrency - 1)
|
||||
packageSpecQueue.drain = -> callback(null, failedPackages)
|
||||
|
||||
runCoreSpecs = (callback) ->
|
||||
runCoreSpecs = (callback, logOutput = false) ->
|
||||
appPath = getAppPath()
|
||||
resourcePath = process.cwd()
|
||||
coreSpecsPath = path.resolve('spec')
|
||||
@@ -94,7 +95,7 @@ module.exports = (grunt) ->
|
||||
if process.platform in ['darwin', 'linux']
|
||||
options =
|
||||
cmd: appPath
|
||||
args: ['--test', "--resource-path=#{resourcePath}", coreSpecsPath]
|
||||
args: ['--test', "--resource-path=#{resourcePath}", coreSpecsPath, "--user-data-dir=#{temp.mkdirSync('atom-user-data-dir')}"]
|
||||
opts:
|
||||
env: _.extend({}, process.env,
|
||||
ATOM_INTEGRATION_TESTS_ENABLED: true
|
||||
@@ -109,6 +110,9 @@ module.exports = (grunt) ->
|
||||
ATOM_INTEGRATION_TESTS_ENABLED: true
|
||||
)
|
||||
|
||||
if logOutput
|
||||
options.opts.stdio = 'inherit'
|
||||
|
||||
grunt.log.ok "Launching core specs."
|
||||
spawn options, (error, results, code) ->
|
||||
if process.platform is 'win32'
|
||||
@@ -130,11 +134,17 @@ module.exports = (grunt) ->
|
||||
else
|
||||
async.parallel
|
||||
|
||||
# If we're just running the core specs then we won't have any output to
|
||||
# indicate the tests actually *are* running. This upsets Travis:
|
||||
# https://github.com/atom/atom/issues/10837. So pass the test output
|
||||
# through.
|
||||
runCoreSpecsWithLogging = (callback) -> runCoreSpecs(callback, true)
|
||||
|
||||
specs =
|
||||
if process.env.ATOM_SPECS_TASK is 'packages'
|
||||
[runPackageSpecs]
|
||||
else if process.env.ATOM_SPECS_TASK is 'core'
|
||||
[runCoreSpecs]
|
||||
[runCoreSpecsWithLogging]
|
||||
else
|
||||
[runCoreSpecs, runPackageSpecs]
|
||||
|
||||
|
||||
@@ -52,8 +52,10 @@ module.exports = (grunt) ->
|
||||
stderr = []
|
||||
error = null
|
||||
proc = childProcess.spawn(options.cmd, options.args, options.opts)
|
||||
proc.stdout.on 'data', (data) -> stdout.push(data.toString())
|
||||
proc.stderr.on 'data', (data) -> stderr.push(data.toString())
|
||||
if proc.stdout?
|
||||
proc.stdout.on 'data', (data) -> stdout.push(data.toString())
|
||||
if proc.stderr?
|
||||
proc.stderr.on 'data', (data) -> stderr.push(data.toString())
|
||||
proc.on 'error', (processError) -> error ?= processError
|
||||
proc.on 'close', (exitCode, signal) ->
|
||||
error ?= new Error(signal) if exitCode isnt 0
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
"service-hub": "^0.7.0",
|
||||
"source-map-support": "^0.3.2",
|
||||
"temp": "0.8.1",
|
||||
"text-buffer": "8.3.0",
|
||||
"text-buffer": "8.3.1",
|
||||
"typescript-simple": "1.0.0",
|
||||
"underscore-plus": "^1.6.6",
|
||||
"yargs": "^3.23.0"
|
||||
@@ -173,7 +173,8 @@
|
||||
"runs",
|
||||
"spyOn",
|
||||
"waitsFor",
|
||||
"waitsForPromise"
|
||||
"waitsForPromise",
|
||||
"indexedDB"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,6 +152,8 @@ describe "AtomEnvironment", ->
|
||||
atom.enablePersistence = false
|
||||
|
||||
it "selects the state based on the current project paths", ->
|
||||
jasmine.useRealClock()
|
||||
|
||||
[dir1, dir2] = [temp.mkdirSync("dir1-"), temp.mkdirSync("dir2-")]
|
||||
|
||||
loadSettings = _.extend atom.getLoadSettings(),
|
||||
@@ -159,20 +161,40 @@ describe "AtomEnvironment", ->
|
||||
windowState: null
|
||||
|
||||
spyOn(atom, 'getLoadSettings').andCallFake -> loadSettings
|
||||
spyOn(atom.getStorageFolder(), 'getPath').andReturn(temp.mkdirSync("storage-dir-"))
|
||||
spyOn(atom, 'serialize').andReturn({stuff: 'cool'})
|
||||
spyOn(atom, 'deserialize')
|
||||
|
||||
atom.state.stuff = "cool"
|
||||
atom.project.setPaths([dir1, dir2])
|
||||
atom.saveStateSync()
|
||||
# State persistence will fail if other Atom instances are running
|
||||
waitsForPromise ->
|
||||
atom.stateStore.connect().then (isConnected) ->
|
||||
expect(isConnected).toBe true
|
||||
|
||||
atom.state = {}
|
||||
atom.loadStateSync()
|
||||
expect(atom.state.stuff).toBeUndefined()
|
||||
waitsForPromise ->
|
||||
atom.saveState().then ->
|
||||
atom.loadState()
|
||||
|
||||
loadSettings.initialPaths = [dir2, dir1]
|
||||
atom.state = {}
|
||||
atom.loadStateSync()
|
||||
expect(atom.state.stuff).toBe("cool")
|
||||
runs ->
|
||||
expect(atom.deserialize).not.toHaveBeenCalled()
|
||||
|
||||
waitsForPromise ->
|
||||
loadSettings.initialPaths = [dir2, dir1]
|
||||
atom.loadState()
|
||||
runs ->
|
||||
expect(atom.deserialize).toHaveBeenCalledWith({stuff: 'cool'})
|
||||
|
||||
it "saves state on keydown and mousedown events", ->
|
||||
spyOn(atom, 'saveState')
|
||||
|
||||
keydown = new KeyboardEvent('keydown')
|
||||
atom.document.dispatchEvent(keydown)
|
||||
advanceClock atom.saveStateDebounceInterval
|
||||
expect(atom.saveState).toHaveBeenCalled()
|
||||
|
||||
mousedown = new MouseEvent('mousedown')
|
||||
atom.document.dispatchEvent(mousedown)
|
||||
advanceClock atom.saveStateDebounceInterval
|
||||
expect(atom.saveState).toHaveBeenCalled()
|
||||
|
||||
describe "openInitialEmptyEditorIfNecessary", ->
|
||||
describe "when there are no paths set", ->
|
||||
@@ -230,23 +252,6 @@ describe "AtomEnvironment", ->
|
||||
|
||||
atomEnvironment.destroy()
|
||||
|
||||
it "saves the serialized state of the window so it can be deserialized after reload", ->
|
||||
atomEnvironment = new AtomEnvironment({applicationDelegate: atom.applicationDelegate, window, document})
|
||||
spyOn(atomEnvironment, 'saveStateSync')
|
||||
|
||||
workspaceState = atomEnvironment.workspace.serialize()
|
||||
grammarsState = {grammarOverridesByPath: atomEnvironment.grammars.grammarOverridesByPath}
|
||||
projectState = atomEnvironment.project.serialize()
|
||||
|
||||
atomEnvironment.unloadEditorWindow()
|
||||
|
||||
expect(atomEnvironment.state.workspace).toEqual workspaceState
|
||||
expect(atomEnvironment.state.grammars).toEqual grammarsState
|
||||
expect(atomEnvironment.state.project).toEqual projectState
|
||||
expect(atomEnvironment.saveStateSync).toHaveBeenCalled()
|
||||
|
||||
atomEnvironment.destroy()
|
||||
|
||||
describe "::destroy()", ->
|
||||
it "does not throw exceptions when unsubscribing from ipc events (regression)", ->
|
||||
configDirPath = temp.mkdirSync()
|
||||
|
||||
@@ -338,10 +338,10 @@ describe('GitRepositoryAsync', () => {
|
||||
})
|
||||
|
||||
describe('.refreshStatus()', () => {
|
||||
let newPath, modifiedPath, cleanPath
|
||||
let newPath, modifiedPath, cleanPath, workingDirectory
|
||||
|
||||
beforeEach(() => {
|
||||
const workingDirectory = copyRepository()
|
||||
workingDirectory = copyRepository()
|
||||
repo = GitRepositoryAsync.open(workingDirectory)
|
||||
modifiedPath = path.join(workingDirectory, 'file.txt')
|
||||
newPath = path.join(workingDirectory, 'untracked.txt')
|
||||
@@ -362,7 +362,7 @@ describe('GitRepositoryAsync', () => {
|
||||
|
||||
describe('in a repository with submodules', () => {
|
||||
beforeEach(() => {
|
||||
const workingDirectory = copySubmoduleRepository()
|
||||
workingDirectory = copySubmoduleRepository()
|
||||
repo = GitRepositoryAsync.open(workingDirectory)
|
||||
modifiedPath = path.join(workingDirectory, 'jstips', 'README.md')
|
||||
newPath = path.join(workingDirectory, 'You-Dont-Need-jQuery', 'untracked.txt')
|
||||
@@ -380,6 +380,48 @@ describe('GitRepositoryAsync', () => {
|
||||
expect(repo.isStatusModified(await repo.getCachedPathStatus(modifiedPath))).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
it('caches the proper statuses when a subdir is open', async () => {
|
||||
const subDir = path.join(workingDirectory, 'dir')
|
||||
fs.mkdirSync(subDir)
|
||||
|
||||
const filePath = path.join(subDir, 'b.txt')
|
||||
fs.writeFileSync(filePath, '')
|
||||
|
||||
atom.project.setPaths([subDir])
|
||||
|
||||
await atom.workspace.open('b.txt')
|
||||
|
||||
const repo = atom.project.getRepositories()[0].async
|
||||
|
||||
await repo.refreshStatus()
|
||||
|
||||
const status = await repo.getCachedPathStatus(filePath)
|
||||
expect(repo.isStatusModified(status)).toBe(false)
|
||||
expect(repo.isStatusNew(status)).toBe(false)
|
||||
})
|
||||
|
||||
it('caches the proper statuses when multiple project are open', async () => {
|
||||
const otherWorkingDirectory = copyRepository()
|
||||
|
||||
atom.project.setPaths([workingDirectory, otherWorkingDirectory])
|
||||
|
||||
await atom.workspace.open('b.txt')
|
||||
|
||||
const repo = atom.project.getRepositories()[0].async
|
||||
|
||||
await repo.refreshStatus()
|
||||
|
||||
const subDir = path.join(workingDirectory, 'dir')
|
||||
fs.mkdirSync(subDir)
|
||||
|
||||
const filePath = path.join(subDir, 'b.txt')
|
||||
fs.writeFileSync(filePath, 'some content!')
|
||||
|
||||
const status = await repo.getCachedPathStatus(filePath)
|
||||
expect(repo.isStatusModified(status)).toBe(true)
|
||||
expect(repo.isStatusNew(status)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('.isProjectAtRoot()', () => {
|
||||
|
||||
@@ -15,6 +15,8 @@ ChromedriverPort = 9515
|
||||
ChromedriverURLBase = "/wd/hub"
|
||||
ChromedriverStatusURL = "http://localhost:#{ChromedriverPort}#{ChromedriverURLBase}/status"
|
||||
|
||||
userDataDir = temp.mkdirSync('atom-user-data-dir')
|
||||
|
||||
chromeDriverUp = (done) ->
|
||||
checkStatus = ->
|
||||
http
|
||||
@@ -48,7 +50,7 @@ buildAtomClient = (args, env) ->
|
||||
"atom-env=#{map(env, (value, key) -> "#{key}=#{value}").join(" ")}"
|
||||
"dev"
|
||||
"safe"
|
||||
"user-data-dir=#{temp.mkdirSync('atom-user-data-dir')}"
|
||||
"user-data-dir=#{userDataDir}"
|
||||
"socket-path=#{SocketPath}"
|
||||
])
|
||||
|
||||
|
||||
@@ -28,13 +28,12 @@ describe "Starting Atom", ->
|
||||
it "opens the parent directory and creates an empty text editor", ->
|
||||
runAtom [path.join(tempDirPath, "new-file")], {ATOM_HOME: atomHome}, (client) ->
|
||||
client
|
||||
.waitForPaneItemCount(1, 1000)
|
||||
|
||||
.treeViewRootDirectories()
|
||||
.then ({value}) -> expect(value).toEqual([tempDirPath])
|
||||
|
||||
.waitForExist("atom-text-editor", 5000)
|
||||
.then (exists) -> expect(exists).toBe true
|
||||
.waitForPaneItemCount(1, 1000)
|
||||
.click("atom-text-editor")
|
||||
.keys("Hello!")
|
||||
.execute -> atom.workspace.getActiveTextEditor().getText()
|
||||
@@ -153,6 +152,8 @@ describe "Starting Atom", ->
|
||||
.waitForPaneItemCount(0, 3000)
|
||||
.execute -> atom.workspace.open()
|
||||
.waitForPaneItemCount(1, 3000)
|
||||
.keys("Hello!")
|
||||
.waitUntil((-> Promise.resolve(false)), 1100)
|
||||
|
||||
runAtom [tempDirPath], {ATOM_HOME: atomHome}, (client) ->
|
||||
client
|
||||
|
||||
@@ -446,16 +446,15 @@ describe "PackageManager", ->
|
||||
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()
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-serialization")
|
||||
runs ->
|
||||
expect(pack.mainModule.activate).toHaveBeenCalledWith({someNumber: 77})
|
||||
waitsForPromise ->
|
||||
atom.packages.activatePackage("package-with-serialization")
|
||||
runs ->
|
||||
expect(pack.mainModule.activate).toHaveBeenCalledWith({someNumber: 77})
|
||||
|
||||
it "invokes ::onDidActivatePackage listeners with the activated package", ->
|
||||
activatedPackage = null
|
||||
@@ -819,6 +818,34 @@ describe "PackageManager", ->
|
||||
expect(atom.packages.isPackageActive("package-with-missing-provided-services")).toBe true
|
||||
expect(addErrorHandler.callCount).toBe 0
|
||||
|
||||
describe "::serialize", ->
|
||||
it "does not serialize packages that threw an error during activation", ->
|
||||
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.serialize()
|
||||
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.serialize()
|
||||
expect(atom.packages.packageStates['package-with-serialize-error']).toBeUndefined()
|
||||
expect(atom.packages.packageStates['package-with-serialization']).toEqual someNumber: 1
|
||||
expect(console.error).toHaveBeenCalled()
|
||||
|
||||
describe "::deactivatePackage(id)", ->
|
||||
afterEach ->
|
||||
atom.packages.unloadPackages()
|
||||
@@ -850,33 +877,6 @@ describe "PackageManager", ->
|
||||
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')
|
||||
|
||||
|
||||
61
spec/state-store-spec.js
Normal file
61
spec/state-store-spec.js
Normal file
@@ -0,0 +1,61 @@
|
||||
/** @babel */
|
||||
import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers'
|
||||
|
||||
const StateStore = require('../src/state-store.js')
|
||||
|
||||
describe("StateStore", () => {
|
||||
let databaseName = `test-database-${Date.now()}`
|
||||
let version = 1
|
||||
|
||||
it("can save and load states", () => {
|
||||
const store = new StateStore(databaseName, version)
|
||||
return store.save('key', {foo:'bar'})
|
||||
.then(() => store.load('key'))
|
||||
.then((state) => {
|
||||
expect(state).toEqual({foo:'bar'})
|
||||
})
|
||||
})
|
||||
|
||||
it("resolves with null when a non-existent key is loaded", () => {
|
||||
const store = new StateStore(databaseName, version)
|
||||
return store.load('no-such-key').then((value) => {
|
||||
expect(value).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
it("can clear the state object store", () => {
|
||||
const store = new StateStore(databaseName, version)
|
||||
return store.save('key', {foo:'bar'})
|
||||
.then(() => store.count())
|
||||
.then((count) =>
|
||||
expect(count).toBe(1)
|
||||
)
|
||||
.then(() => store.clear())
|
||||
.then(() => store.count())
|
||||
.then((count) => {
|
||||
expect(count).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe("when there is an error reading from the database", () => {
|
||||
it("rejects the promise returned by load", () => {
|
||||
const store = new StateStore(databaseName, version)
|
||||
|
||||
const fakeErrorEvent = {target: {errorCode: "Something bad happened"}}
|
||||
|
||||
spyOn(IDBObjectStore.prototype, 'get').andCallFake((key) => {
|
||||
let request = {}
|
||||
process.nextTick(() => request.onerror(fakeErrorEvent))
|
||||
return request
|
||||
})
|
||||
|
||||
return store.load('nonexistentKey')
|
||||
.then(() => {
|
||||
throw new Error("Promise should have been rejected")
|
||||
})
|
||||
.catch((event) => {
|
||||
expect(event).toBe(fakeErrorEvent)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -92,10 +92,10 @@ describe "TextEditorPresenter", ->
|
||||
|
||||
waitsForStateToUpdate = (presenter, fn) ->
|
||||
waitsFor "presenter state to update", 1000, (done) ->
|
||||
fn?()
|
||||
disposable = presenter.onDidUpdateState ->
|
||||
disposable.dispose()
|
||||
process.nextTick(done)
|
||||
fn?()
|
||||
|
||||
tiledContentContract = (stateFn) ->
|
||||
it "contains states for tiles that are visible on screen", ->
|
||||
@@ -1336,9 +1336,9 @@ describe "TextEditorPresenter", ->
|
||||
presenter = buildPresenter()
|
||||
blockDecoration2 = addBlockDecorationBeforeScreenRow(3)
|
||||
blockDecoration3 = addBlockDecorationBeforeScreenRow(7)
|
||||
blockDecoration4 = addBlockDecorationAfterScreenRow(7)
|
||||
blockDecoration4 = null
|
||||
|
||||
waitsForStateToUpdate presenter
|
||||
waitsForStateToUpdate presenter, blockDecoration4 = addBlockDecorationAfterScreenRow(7)
|
||||
runs ->
|
||||
expect(lineStateForScreenRow(presenter, 0).precedingBlockDecorations).toEqual([blockDecoration1])
|
||||
expect(lineStateForScreenRow(presenter, 0).followingBlockDecorations).toEqual([])
|
||||
@@ -1472,9 +1472,9 @@ describe "TextEditorPresenter", ->
|
||||
decoration1 = editor.decorateMarker(marker1, type: 'line', class: 'a')
|
||||
presenter = buildPresenter()
|
||||
marker2 = editor.addMarkerLayer(maintainHistory: true).markBufferRange([[4, 0], [6, 2]], invalidate: 'touch')
|
||||
decoration2 = editor.decorateMarker(marker2, type: 'line', class: 'b')
|
||||
decoration2 = null
|
||||
|
||||
waitsForStateToUpdate presenter
|
||||
waitsForStateToUpdate presenter, -> decoration2 = editor.decorateMarker(marker2, type: 'line', class: 'b')
|
||||
runs ->
|
||||
expect(lineStateForScreenRow(presenter, 3).decorationClasses).toBeNull()
|
||||
expect(lineStateForScreenRow(presenter, 4).decorationClasses).toEqual ['a', 'b']
|
||||
@@ -2150,31 +2150,40 @@ describe "TextEditorPresenter", ->
|
||||
}
|
||||
|
||||
# becoming empty
|
||||
waitsForStateToUpdate presenter, -> editor.getSelections()[1].clear(autoscroll: false)
|
||||
runs ->
|
||||
editor.getSelections()[1].clear(autoscroll: false)
|
||||
waitsForStateToUpdate presenter
|
||||
runs ->
|
||||
expectUndefinedStateForSelection(presenter, 1)
|
||||
|
||||
# becoming non-empty
|
||||
waitsForStateToUpdate presenter, -> editor.getSelections()[1].setBufferRange([[2, 4], [2, 6]], autoscroll: false)
|
||||
runs ->
|
||||
editor.getSelections()[1].setBufferRange([[2, 4], [2, 6]], autoscroll: false)
|
||||
waitsForStateToUpdate presenter
|
||||
runs ->
|
||||
expectValues stateForSelectionInTile(presenter, 1, 2), {
|
||||
regions: [{top: 0, left: 4 * 10, width: 2 * 10, height: 10}]
|
||||
}
|
||||
|
||||
# moving out of view
|
||||
waitsForStateToUpdate presenter, -> editor.getSelections()[1].setBufferRange([[3, 4], [3, 6]], autoscroll: false)
|
||||
runs ->
|
||||
editor.getSelections()[1].setBufferRange([[3, 4], [3, 6]], autoscroll: false)
|
||||
waitsForStateToUpdate presenter
|
||||
runs ->
|
||||
expectUndefinedStateForSelection(presenter, 1)
|
||||
|
||||
# adding
|
||||
waitsForStateToUpdate presenter, -> editor.addSelectionForBufferRange([[1, 4], [1, 6]], autoscroll: false)
|
||||
runs -> editor.addSelectionForBufferRange([[1, 4], [1, 6]], autoscroll: false)
|
||||
waitsForStateToUpdate presenter
|
||||
runs ->
|
||||
expectValues stateForSelectionInTile(presenter, 2, 0), {
|
||||
regions: [{top: 10, left: 4 * 10, width: 2 * 10, height: 10}]
|
||||
}
|
||||
|
||||
# moving added selection
|
||||
waitsForStateToUpdate presenter, -> editor.getSelections()[2].setBufferRange([[1, 4], [1, 8]], autoscroll: false)
|
||||
runs ->
|
||||
editor.getSelections()[2].setBufferRange([[1, 4], [1, 8]], autoscroll: false)
|
||||
waitsForStateToUpdate presenter
|
||||
|
||||
destroyedSelection = null
|
||||
runs ->
|
||||
@@ -2208,8 +2217,9 @@ describe "TextEditorPresenter", ->
|
||||
presenter = buildPresenter(explicitHeight: 30, scrollTop: 20, tileSize: 2)
|
||||
|
||||
marker = editor.markBufferPosition([2, 2])
|
||||
highlight = editor.decorateMarker(marker, type: 'highlight', class: 'a')
|
||||
highlight = null
|
||||
waitsForStateToUpdate presenter, ->
|
||||
highlight = editor.decorateMarker(marker, type: 'highlight', class: 'a')
|
||||
marker.setBufferRange([[2, 2], [5, 2]])
|
||||
highlight.flash('b', 500)
|
||||
runs ->
|
||||
@@ -2969,9 +2979,8 @@ describe "TextEditorPresenter", ->
|
||||
presenter.setBlockDecorationDimensions(blockDecoration4, 0, 35)
|
||||
presenter.setBlockDecorationDimensions(blockDecoration4, 0, 40)
|
||||
presenter.setBlockDecorationDimensions(blockDecoration5, 0, 50)
|
||||
presenter.setBlockDecorationDimensions(blockDecoration6, 0, 60)
|
||||
|
||||
waitsForStateToUpdate presenter
|
||||
waitsForStateToUpdate presenter, -> presenter.setBlockDecorationDimensions(blockDecoration6, 0, 60)
|
||||
runs ->
|
||||
expect(lineNumberStateForScreenRow(presenter, 0).blockDecorationsHeight).toBe(10)
|
||||
expect(lineNumberStateForScreenRow(presenter, 1).blockDecorationsHeight).toBe(0)
|
||||
@@ -3460,9 +3469,9 @@ describe "TextEditorPresenter", ->
|
||||
gutterName: 'test-gutter-2'
|
||||
class: 'test-class'
|
||||
marker4 = editor.markBufferRange([[0, 0], [1, 0]])
|
||||
decoration4 = editor.decorateMarker(marker4, decorationParams)
|
||||
decoration4 = null
|
||||
|
||||
waitsForStateToUpdate presenter
|
||||
waitsForStateToUpdate presenter, -> decoration4 = editor.decorateMarker(marker4, decorationParams)
|
||||
|
||||
runs ->
|
||||
expectStateUpdate presenter, -> editor.addGutter({name: 'test-gutter-2'})
|
||||
|
||||
@@ -4,13 +4,13 @@ path = require 'path'
|
||||
|
||||
_ = require 'underscore-plus'
|
||||
{deprecate} = require 'grim'
|
||||
{CompositeDisposable, Emitter} = require 'event-kit'
|
||||
{CompositeDisposable, Disposable, Emitter} = require 'event-kit'
|
||||
fs = require 'fs-plus'
|
||||
{mapSourcePosition} = require 'source-map-support'
|
||||
Model = require './model'
|
||||
WindowEventHandler = require './window-event-handler'
|
||||
StylesElement = require './styles-element'
|
||||
StorageFolder = require './storage-folder'
|
||||
StateStore = require './state-store'
|
||||
{getWindowLoadSettings, setWindowLoadSettings} = require './window-load-settings-helpers'
|
||||
registerDefaultCommands = require './register-default-commands'
|
||||
|
||||
@@ -111,6 +111,8 @@ class AtomEnvironment extends Model
|
||||
# Public: A {Workspace} instance
|
||||
workspace: null
|
||||
|
||||
saveStateDebounceInterval: 1000
|
||||
|
||||
###
|
||||
Section: Construction and Destruction
|
||||
###
|
||||
@@ -119,14 +121,16 @@ class AtomEnvironment extends Model
|
||||
constructor: (params={}) ->
|
||||
{@blobStore, @applicationDelegate, @window, @document, configDirPath, @enablePersistence, onlyLoadBaseStyleSheets} = params
|
||||
|
||||
@state = {version: @constructor.version}
|
||||
|
||||
@loadTime = null
|
||||
{devMode, safeMode, resourcePath} = @getLoadSettings()
|
||||
{devMode, safeMode, resourcePath, clearWindowState} = @getLoadSettings()
|
||||
|
||||
@emitter = new Emitter
|
||||
@disposables = new CompositeDisposable
|
||||
|
||||
@stateStore = new StateStore('AtomEnvironments', 1)
|
||||
|
||||
@stateStore.clear() if clearWindowState
|
||||
|
||||
@deserializers = new DeserializerManager(this)
|
||||
@deserializeTimings = {}
|
||||
|
||||
@@ -200,6 +204,7 @@ class AtomEnvironment extends Model
|
||||
@registerDefaultViewProviders()
|
||||
|
||||
@installUncaughtErrorHandler()
|
||||
@attachSaveStateListeners()
|
||||
@installWindowEventHandler()
|
||||
|
||||
@observeAutoHideMenuBar()
|
||||
@@ -213,6 +218,14 @@ class AtomEnvironment extends Model
|
||||
|
||||
checkPortableHomeWritable()
|
||||
|
||||
attachSaveStateListeners: ->
|
||||
debouncedSaveState = _.debounce((=> @saveState()), @saveStateDebounceInterval)
|
||||
@document.addEventListener('mousedown', debouncedSaveState, true)
|
||||
@document.addEventListener('keydown', debouncedSaveState, true)
|
||||
@disposables.add new Disposable =>
|
||||
@document.removeEventListener('mousedown', debouncedSaveState, true)
|
||||
@document.removeEventListener('keydown', debouncedSaveState, true)
|
||||
|
||||
setConfigSchema: ->
|
||||
@config.setSchema null, {type: 'object', properties: _.clone(require('./config-schema'))}
|
||||
|
||||
@@ -302,9 +315,6 @@ class AtomEnvironment extends Model
|
||||
@views.clear()
|
||||
@registerDefaultViewProviders()
|
||||
|
||||
@state.packageStates = {}
|
||||
delete @state.workspace
|
||||
|
||||
destroy: ->
|
||||
return if not @project
|
||||
|
||||
@@ -611,7 +621,7 @@ class AtomEnvironment extends Model
|
||||
# But after that, e.g., when the window's been reloaded, we want to use the
|
||||
# dimensions we've saved for it.
|
||||
if not @isFirstLoad()
|
||||
dimensions = @state.windowDimensions
|
||||
dimensions = @windowDimensions
|
||||
|
||||
unless @isValidDimensions(dimensions)
|
||||
dimensions = @getDefaultWindowDimensions()
|
||||
@@ -619,7 +629,7 @@ class AtomEnvironment extends Model
|
||||
|
||||
storeWindowDimensions: ->
|
||||
dimensions = @getWindowDimensions()
|
||||
@state.windowDimensions = dimensions if @isValidDimensions(dimensions)
|
||||
@windowDimensions = dimensions if @isValidDimensions(dimensions)
|
||||
|
||||
restoreWindowBackground: ->
|
||||
if backgroundColor = window.localStorage.getItem('atom:window-background-color')
|
||||
@@ -664,17 +674,20 @@ class AtomEnvironment extends Model
|
||||
|
||||
@openInitialEmptyEditorIfNecessary()
|
||||
|
||||
serialize: ->
|
||||
version: @constructor.version
|
||||
project: @project.serialize()
|
||||
workspace: @workspace.serialize()
|
||||
packageStates: @packages.serialize()
|
||||
grammars: {grammarOverridesByPath: @grammars.grammarOverridesByPath}
|
||||
fullScreen: @isFullScreen()
|
||||
windowDimensions: @windowDimensions
|
||||
|
||||
unloadEditorWindow: ->
|
||||
return if not @project
|
||||
|
||||
@storeWindowBackground()
|
||||
@state.grammars = {grammarOverridesByPath: @grammars.grammarOverridesByPath}
|
||||
@state.project = @project.serialize()
|
||||
@state.workspace = @workspace.serialize()
|
||||
@packages.deactivatePackages()
|
||||
@state.packageStates = @packages.packageStates
|
||||
@state.fullScreen = @isFullScreen()
|
||||
@saveStateSync()
|
||||
@saveBlobStoreSync()
|
||||
|
||||
openInitialEmptyEditorIfNecessary: ->
|
||||
@@ -808,45 +821,54 @@ class AtomEnvironment extends Model
|
||||
|
||||
@blobStore.save()
|
||||
|
||||
saveStateSync: ->
|
||||
return unless @enablePersistence
|
||||
saveState: ->
|
||||
return Promise.resolve() unless @enablePersistence
|
||||
state = @serialize()
|
||||
|
||||
if storageKey = @getStateKey(@project?.getPaths())
|
||||
@getStorageFolder().store(storageKey, @state)
|
||||
@stateStore.save(storageKey, state)
|
||||
else
|
||||
@getCurrentWindow().loadSettings.windowState = JSON.stringify(@state)
|
||||
@getCurrentWindow().loadSettings.windowState = JSON.stringify(state)
|
||||
Promise.resolve()
|
||||
|
||||
loadStateSync: ->
|
||||
return unless @enablePersistence
|
||||
loadState: ->
|
||||
return Promise.resolve() unless @enablePersistence
|
||||
|
||||
startTime = Date.now()
|
||||
|
||||
statePromise = null
|
||||
if stateKey = @getStateKey(@getLoadSettings().initialPaths)
|
||||
if state = @getStorageFolder().load(stateKey)
|
||||
@state = state
|
||||
statePromise = @stateStore.load(stateKey)
|
||||
|
||||
if not @state? and windowState = @getLoadSettings().windowState
|
||||
if not statePromise? and windowState = @getLoadSettings().windowState
|
||||
try
|
||||
if state = JSON.parse(@getLoadSettings().windowState)
|
||||
@state = state
|
||||
statePromise = Promise.resolve(JSON.parse(@getLoadSettings().windowState))
|
||||
catch error
|
||||
console.warn "Error parsing window state: #{statePath} #{error.stack}", error
|
||||
|
||||
@deserializeTimings.atom = Date.now() - startTime
|
||||
if statePromise?
|
||||
statePromise.then (state) =>
|
||||
@deserializeTimings.atom = Date.now() - startTime
|
||||
@deserialize(state) if state?
|
||||
else
|
||||
Promise.resolve()
|
||||
|
||||
if grammarOverridesByPath = @state.grammars?.grammarOverridesByPath
|
||||
deserialize: (state) ->
|
||||
if grammarOverridesByPath = state.grammars?.grammarOverridesByPath
|
||||
@grammars.grammarOverridesByPath = grammarOverridesByPath
|
||||
|
||||
@setFullScreen(@state.fullScreen)
|
||||
@setFullScreen(state.fullScreen)
|
||||
|
||||
@packages.packageStates = @state.packageStates ? {}
|
||||
@windowDimensions = state.windowDimensions if state.windowDimensions
|
||||
|
||||
@packages.packageStates = state.packageStates ? {}
|
||||
|
||||
startTime = Date.now()
|
||||
@project.deserialize(@state.project, @deserializers) if @state.project?
|
||||
@project.deserialize(state.project, @deserializers) if state.project?
|
||||
@deserializeTimings.project = Date.now() - startTime
|
||||
|
||||
startTime = Date.now()
|
||||
@workspace.deserialize(@state.workspace, @deserializers) if @state.workspace?
|
||||
@workspace.deserialize(state.workspace, @deserializers) if state.workspace?
|
||||
@deserializeTimings.workspace = Date.now() - startTime
|
||||
|
||||
getStateKey: (paths) ->
|
||||
@@ -859,9 +881,6 @@ class AtomEnvironment extends Model
|
||||
getConfigDirPath: ->
|
||||
@configDirPath ?= process.env.ATOM_HOME
|
||||
|
||||
getStorageFolder: ->
|
||||
@storageFolder ?= new StorageFolder(@getConfigDirPath())
|
||||
|
||||
getUserInitScriptPath: ->
|
||||
initScriptPath = fs.resolve(@getConfigDirPath(), 'init', ['js', 'coffee'])
|
||||
initScriptPath ? path.join(@getConfigDirPath(), 'init.coffee')
|
||||
|
||||
@@ -61,7 +61,7 @@ class AtomApplication
|
||||
exit: (status) -> app.exit(status)
|
||||
|
||||
constructor: (options) ->
|
||||
{@resourcePath, @devResourcePath, @version, @devMode, @safeMode, @socketPath, timeout} = options
|
||||
{@resourcePath, @devResourcePath, @version, @devMode, @safeMode, @socketPath, timeout, clearWindowState} = options
|
||||
|
||||
@socketPath = null if options.test
|
||||
|
||||
@@ -85,16 +85,16 @@ class AtomApplication
|
||||
else
|
||||
@loadState(options) or @openPath(options)
|
||||
|
||||
openWithOptions: ({pathsToOpen, executedFrom, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, newWindow, logFile, profileStartup, timeout}) ->
|
||||
openWithOptions: ({pathsToOpen, executedFrom, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, newWindow, logFile, profileStartup, timeout, clearWindowState}) ->
|
||||
if test
|
||||
@runTests({headless: true, devMode, @resourcePath, executedFrom, pathsToOpen, logFile, timeout})
|
||||
else if pathsToOpen.length > 0
|
||||
@openPaths({pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup})
|
||||
@openPaths({pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, clearWindowState})
|
||||
else if urlsToOpen.length > 0
|
||||
@openUrl({urlToOpen, devMode, safeMode}) for urlToOpen in urlsToOpen
|
||||
else
|
||||
# Always open a editor window if this is the first instance of Atom.
|
||||
@openPath({pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup})
|
||||
@openPath({pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, clearWindowState})
|
||||
|
||||
# Public: Removes the {AtomWindow} from the global window list.
|
||||
removeWindow: (window) ->
|
||||
@@ -403,8 +403,8 @@ class AtomApplication
|
||||
# :safeMode - Boolean to control the opened window's safe mode.
|
||||
# :profileStartup - Boolean to control creating a profile of the startup time.
|
||||
# :window - {AtomWindow} to open file paths in.
|
||||
openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window} = {}) ->
|
||||
@openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window})
|
||||
openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window, clearWindowState} = {}) ->
|
||||
@openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window, clearWindowState})
|
||||
|
||||
# Public: Opens multiple paths, in existing windows if possible.
|
||||
#
|
||||
@@ -416,9 +416,10 @@ class AtomApplication
|
||||
# :safeMode - Boolean to control the opened window's safe mode.
|
||||
# :windowDimensions - Object with height and width keys.
|
||||
# :window - {AtomWindow} to open file paths in.
|
||||
openPaths: ({pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, profileStartup, window}={}) ->
|
||||
openPaths: ({pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, profileStartup, window, clearWindowState}={}) ->
|
||||
devMode = Boolean(devMode)
|
||||
safeMode = Boolean(safeMode)
|
||||
clearWindowState = Boolean(clearWindowState)
|
||||
locationsToOpen = (@locationForPathToOpen(pathToOpen, executedFrom) for pathToOpen in pathsToOpen)
|
||||
pathsToOpen = (locationToOpen.pathToOpen for locationToOpen in locationsToOpen)
|
||||
|
||||
@@ -451,7 +452,7 @@ class AtomApplication
|
||||
windowInitializationScript ?= require.resolve('../initialize-application-window')
|
||||
resourcePath ?= @resourcePath
|
||||
windowDimensions ?= @getDimensionsForNewWindow()
|
||||
openedWindow = new AtomWindow({locationsToOpen, windowInitializationScript, resourcePath, devMode, safeMode, windowDimensions, profileStartup})
|
||||
openedWindow = new AtomWindow({locationsToOpen, windowInitializationScript, resourcePath, devMode, safeMode, windowDimensions, profileStartup, clearWindowState})
|
||||
|
||||
if pidToKillWhenClosed?
|
||||
@pidsToOpenWindows[pidToKillWhenClosed] = openedWindow
|
||||
@@ -488,7 +489,7 @@ class AtomApplication
|
||||
if loadSettings = window.getLoadSettings()
|
||||
states.push(initialPaths: loadSettings.initialPaths)
|
||||
if states.length > 0 or allowEmpty
|
||||
@storageFolder.store('application.json', states)
|
||||
@storageFolder.storeSync('application.json', states)
|
||||
|
||||
loadState: (options) ->
|
||||
if (states = @storageFolder.load('application.json'))?.length > 0
|
||||
|
||||
@@ -48,6 +48,7 @@ class AtomWindow
|
||||
loadSettings.safeMode ?= false
|
||||
loadSettings.atomHome = process.env.ATOM_HOME
|
||||
loadSettings.firstLoad = true
|
||||
loadSettings.clearWindowState ?= false
|
||||
|
||||
# Only send to the first non-spec window created
|
||||
if @constructor.includeShellLoadTime and not @isSpec
|
||||
|
||||
@@ -31,6 +31,9 @@ start = ->
|
||||
app.on 'open-url', addUrlToOpen
|
||||
app.on 'will-finish-launching', setupCrashReporter
|
||||
|
||||
if args.userDataDir?
|
||||
app.setPath('userData', args.userDataDir)
|
||||
|
||||
app.on 'ready', ->
|
||||
app.removeListener 'open-file', addPathToOpen
|
||||
app.removeListener 'open-url', addUrlToOpen
|
||||
@@ -118,6 +121,8 @@ parseCommandLine = ->
|
||||
options.alias('v', 'version').boolean('v').describe('v', 'Print the version.')
|
||||
options.alias('w', 'wait').boolean('w').describe('w', 'Wait for window to be closed before returning.')
|
||||
options.string('socket-path')
|
||||
options.string('user-data-dir')
|
||||
options.boolean('clear-window-state').describe('clear-window-state', 'Delete all Atom environment state.')
|
||||
|
||||
args = options.argv
|
||||
|
||||
@@ -139,7 +144,9 @@ parseCommandLine = ->
|
||||
pidToKillWhenClosed = args['pid'] if args['wait']
|
||||
logFile = args['log-file']
|
||||
socketPath = args['socket-path']
|
||||
userDataDir = args['user-data-dir']
|
||||
profileStartup = args['profile-startup']
|
||||
clearWindowState = args['clear-window-state']
|
||||
urlsToOpen = []
|
||||
devResourcePath = process.env.ATOM_DEV_RESOURCE_PATH ? path.join(app.getPath('home'), 'github', 'atom')
|
||||
setPortable = args.portable
|
||||
@@ -163,6 +170,7 @@ parseCommandLine = ->
|
||||
|
||||
{resourcePath, devResourcePath, pathsToOpen, urlsToOpen, executedFrom, test,
|
||||
version, pidToKillWhenClosed, devMode, safeMode, newWindow,
|
||||
logFile, socketPath, profileStartup, timeout, setPortable}
|
||||
logFile, socketPath, userDataDir, profileStartup, timeout, setPortable,
|
||||
clearWindowState}
|
||||
|
||||
start()
|
||||
|
||||
@@ -20,6 +20,7 @@ else
|
||||
fileKeyPath = 'HKCU\\Software\\Classes\\*\\shell\\Atom'
|
||||
directoryKeyPath = 'HKCU\\Software\\Classes\\directory\\shell\\Atom'
|
||||
backgroundKeyPath = 'HKCU\\Software\\Classes\\directory\\background\\shell\\Atom'
|
||||
applicationsKeyPath = 'HKCU\\Software\\Classes\\Applications\\atom.exe'
|
||||
environmentKeyPath = 'HKCU\\Environment'
|
||||
|
||||
# Spawn a command and invoke the callback when it completes with an error
|
||||
@@ -64,6 +65,10 @@ installContextMenu = (callback) ->
|
||||
args.push('/f')
|
||||
spawnReg(args, callback)
|
||||
|
||||
installFileHandler = (callback) ->
|
||||
args = ["#{applicationsKeyPath}\\shell\\open\\command", '/ve', '/d', "\"#{process.execPath}\" \"%1\""]
|
||||
addToRegistry(args, callback)
|
||||
|
||||
installMenu = (keyPath, arg, callback) ->
|
||||
args = [keyPath, '/ve', '/d', 'Open with Atom']
|
||||
addToRegistry args, ->
|
||||
@@ -74,7 +79,8 @@ installContextMenu = (callback) ->
|
||||
|
||||
installMenu fileKeyPath, '%1', ->
|
||||
installMenu directoryKeyPath, '%1', ->
|
||||
installMenu(backgroundKeyPath, '%V', callback)
|
||||
installMenu backgroundKeyPath, '%V', ->
|
||||
installFileHandler(callback)
|
||||
|
||||
isAscii = (text) ->
|
||||
index = 0
|
||||
@@ -124,7 +130,8 @@ uninstallContextMenu = (callback) ->
|
||||
|
||||
deleteFromRegistry fileKeyPath, ->
|
||||
deleteFromRegistry directoryKeyPath, ->
|
||||
deleteFromRegistry(backgroundKeyPath, callback)
|
||||
deleteFromRegistry backgroundKeyPath, ->
|
||||
deleteFromRegistry(applicationsKeyPath, callback)
|
||||
|
||||
# Add atom and apm to the PATH
|
||||
#
|
||||
|
||||
@@ -456,7 +456,10 @@ export default class GitRepositoryAsync {
|
||||
// information.
|
||||
getDirectoryStatus (directoryPath) {
|
||||
return this.relativizeToWorkingDirectory(directoryPath)
|
||||
.then(relativePath => this._getStatus([relativePath]))
|
||||
.then(relativePath => {
|
||||
const pathspec = relativePath + '/**'
|
||||
return this._getStatus([pathspec])
|
||||
})
|
||||
.then(statuses => {
|
||||
return Promise.all(statuses.map(s => s.statusBit())).then(bits => {
|
||||
return bits
|
||||
@@ -800,7 +803,7 @@ export default class GitRepositoryAsync {
|
||||
}
|
||||
|
||||
return Promise.all(projectPathsPromises)
|
||||
.then(paths => paths.filter(p => p.length > 0))
|
||||
.then(paths => paths.map(p => p.length > 0 ? p + '/**' : '*'))
|
||||
.then(projectPaths => {
|
||||
return this._getStatus(projectPaths.length > 0 ? projectPaths : null)
|
||||
})
|
||||
@@ -1032,7 +1035,7 @@ export default class GitRepositoryAsync {
|
||||
return this.getRepo()
|
||||
.then(repo => {
|
||||
const opts = {
|
||||
flags: Git.Status.OPT.INCLUDE_UNTRACKED | Git.Status.OPT.RECURSE_UNTRACKED_DIRS | Git.Status.OPT.DISABLE_PATHSPEC_MATCH
|
||||
flags: Git.Status.OPT.INCLUDE_UNTRACKED | Git.Status.OPT.RECURSE_UNTRACKED_DIRS
|
||||
}
|
||||
|
||||
if (paths) {
|
||||
|
||||
@@ -23,12 +23,12 @@ module.exports = ({blobStore}) ->
|
||||
enablePersistence: true
|
||||
})
|
||||
|
||||
atom.loadStateSync()
|
||||
atom.displayWindow().then ->
|
||||
atom.startEditorWindow()
|
||||
atom.loadState().then ->
|
||||
atom.displayWindow().then ->
|
||||
atom.startEditorWindow()
|
||||
|
||||
# Workaround for focus getting cleared upon window creation
|
||||
windowFocused = ->
|
||||
window.removeEventListener('focus', windowFocused)
|
||||
setTimeout (-> document.querySelector('atom-workspace').focus()), 0
|
||||
window.addEventListener('focus', windowFocused)
|
||||
# Workaround for focus getting cleared upon window creation
|
||||
windowFocused = ->
|
||||
window.removeEventListener('focus', windowFocused)
|
||||
setTimeout (-> document.querySelector('atom-workspace').focus()), 0
|
||||
window.addEventListener('focus', windowFocused)
|
||||
|
||||
@@ -68,8 +68,8 @@ module.exports = ({blobStore}) ->
|
||||
logFile, headless, testPaths, buildAtomEnvironment, buildDefaultApplicationDelegate, legacyTestRunner
|
||||
})
|
||||
|
||||
promise.then (code) ->
|
||||
exitWithStatusCode(code) if getWindowLoadSettings().headless
|
||||
promise.then (statusCode) ->
|
||||
exitWithStatusCode(statusCode) if getWindowLoadSettings().headless
|
||||
catch error
|
||||
if getWindowLoadSettings().headless
|
||||
console.error(error.stack ? error)
|
||||
|
||||
@@ -467,6 +467,14 @@ class PackageManager
|
||||
return unless hook? and _.isString(hook) and hook.length > 0
|
||||
@activationHookEmitter.on(hook, callback)
|
||||
|
||||
serialize: ->
|
||||
for pack in @getActivePackages()
|
||||
@serializePackage(pack)
|
||||
@packageStates
|
||||
|
||||
serializePackage: (pack) ->
|
||||
@setPackageState(pack.name, state) if state = pack.serialize?()
|
||||
|
||||
# Deactivate all packages
|
||||
deactivatePackages: ->
|
||||
@config.transact =>
|
||||
@@ -478,8 +486,7 @@ class PackageManager
|
||||
# Deactivate the package with the given name
|
||||
deactivatePackage: (name) ->
|
||||
pack = @getLoadedPackage(name)
|
||||
if @isPackageActive(name)
|
||||
@setPackageState(pack.name, state) if state = pack.serialize?()
|
||||
@serializePackage(pack) if @isPackageActive(pack.name)
|
||||
pack.deactivate()
|
||||
delete @activePackages[pack.name]
|
||||
delete @activatingPackages[pack.name]
|
||||
|
||||
@@ -713,7 +713,7 @@ class Pane extends Model
|
||||
if @parent.orientation is 'vertical'
|
||||
bottommostSibling = last(@parent.children)
|
||||
if bottommostSibling instanceof PaneAxis
|
||||
@splitRight()
|
||||
@splitDown()
|
||||
else
|
||||
bottommostSibling
|
||||
else
|
||||
|
||||
91
src/state-store.js
Normal file
91
src/state-store.js
Normal file
@@ -0,0 +1,91 @@
|
||||
'use strict'
|
||||
|
||||
module.exports =
|
||||
class StateStore {
|
||||
constructor (databaseName, version) {
|
||||
this.dbPromise = new Promise((resolve) => {
|
||||
let dbOpenRequest = indexedDB.open(databaseName, version)
|
||||
dbOpenRequest.onupgradeneeded = (event) => {
|
||||
let db = event.target.result
|
||||
db.createObjectStore('states')
|
||||
}
|
||||
dbOpenRequest.onsuccess = () => {
|
||||
resolve(dbOpenRequest.result)
|
||||
}
|
||||
dbOpenRequest.onerror = (error) => {
|
||||
console.error('Could not connect to indexedDB', error)
|
||||
resolve(null)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
connect () {
|
||||
return this.dbPromise.then(db => !!db)
|
||||
}
|
||||
|
||||
save (key, value) {
|
||||
return this.dbPromise.then(db => {
|
||||
if (!db) return
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
var request = db.transaction(['states'], 'readwrite')
|
||||
.objectStore('states')
|
||||
.put({value: value, storedAt: new Date().toString()}, key)
|
||||
|
||||
request.onsuccess = resolve
|
||||
request.onerror = reject
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
load (key) {
|
||||
return this.dbPromise.then(db => {
|
||||
if (!db) return
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
var request = db.transaction(['states'])
|
||||
.objectStore('states')
|
||||
.get(key)
|
||||
|
||||
request.onsuccess = (event) => {
|
||||
let result = event.target.result
|
||||
resolve(result ? result.value : null)
|
||||
}
|
||||
|
||||
request.onerror = (event) => reject(event)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
clear () {
|
||||
return this.dbPromise.then(db => {
|
||||
if (!db) return
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
var request = db.transaction(['states'], 'readwrite')
|
||||
.objectStore('states')
|
||||
.clear()
|
||||
|
||||
request.onsuccess = resolve
|
||||
request.onerror = reject
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
count () {
|
||||
return this.dbPromise.then(db => {
|
||||
if (!db) return
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
var request = db.transaction(['states'])
|
||||
.objectStore('states')
|
||||
.count()
|
||||
|
||||
request.onsuccess = () => {
|
||||
resolve(request.result)
|
||||
}
|
||||
request.onerror = reject
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ class StorageFolder
|
||||
constructor: (containingPath) ->
|
||||
@path = path.join(containingPath, "storage") if containingPath?
|
||||
|
||||
store: (name, object) ->
|
||||
storeSync: (name, object) ->
|
||||
return unless @path?
|
||||
|
||||
fs.writeFileSync(@pathForKey(name), JSON.stringify(object), 'utf8')
|
||||
|
||||
@@ -394,11 +394,11 @@ class Workspace extends Model
|
||||
# initially. Defaults to `0`.
|
||||
# * `initialColumn` A {Number} indicating which column to move the cursor to
|
||||
# initially. Defaults to `0`.
|
||||
# * `split` Either 'left', 'right', 'top' or 'bottom'.
|
||||
# * `split` Either 'left', 'right', 'up' or 'down'.
|
||||
# If 'left', the item will be opened in leftmost pane of the current active pane's row.
|
||||
# If 'right', the item will be opened in the rightmost pane of the current active pane's row.
|
||||
# If 'up', the item will be opened in topmost pane of the current active pane's row.
|
||||
# If 'down', the item will be opened in the bottommost pane of the current active pane's row.
|
||||
# If 'right', the item will be opened in the rightmost pane of the current active pane's row. If only one pane exists in the row, a new pane will be created.
|
||||
# If 'up', the item will be opened in topmost pane of the current active pane's column.
|
||||
# If 'down', the item will be opened in the bottommost pane of the current active pane's column. If only one pane exists in the column, a new pane will be created.
|
||||
# * `activatePane` A {Boolean} indicating whether to call {Pane::activate} on
|
||||
# containing pane. Defaults to `true`.
|
||||
# * `activateItem` A {Boolean} indicating whether to call {Pane::activateItem}
|
||||
|
||||
@@ -84,7 +84,6 @@
|
||||
setupCsonCache(CompileCache.getCacheDirectory())
|
||||
|
||||
var initialize = require(loadSettings.windowInitializationScript)
|
||||
|
||||
return initialize({blobStore: blobStore}).then(function () {
|
||||
require('electron').ipcRenderer.send('window-command', 'window:loaded')
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user