mirror of
https://github.com/atom/atom.git
synced 2026-01-24 06:18:03 -05:00
Merge branch 'master' into less-disk-io
This commit is contained in:
@@ -112,7 +112,7 @@
|
||||
"symbols-view": "0.112.0",
|
||||
"tabs": "0.92.0",
|
||||
"timecop": "0.33.1",
|
||||
"tree-view": "0.203.2",
|
||||
"tree-view": "0.203.3",
|
||||
"update-package-dependencies": "0.10.0",
|
||||
"welcome": "0.34.0",
|
||||
"whitespace": "0.32.2",
|
||||
|
||||
@@ -4,6 +4,7 @@ temp = require 'temp'
|
||||
Package = require '../src/package'
|
||||
ThemeManager = require '../src/theme-manager'
|
||||
AtomEnvironment = require '../src/atom-environment'
|
||||
StorageFolder = require '../src/storage-folder'
|
||||
|
||||
describe "AtomEnvironment", ->
|
||||
describe 'window sizing methods', ->
|
||||
@@ -172,13 +173,39 @@ describe "AtomEnvironment", ->
|
||||
waitsForPromise ->
|
||||
atom.saveState().then ->
|
||||
atom.loadState().then (state) ->
|
||||
expect(state).toBeNull()
|
||||
expect(state).toBeFalsy()
|
||||
|
||||
waitsForPromise ->
|
||||
loadSettings.initialPaths = [dir2, dir1]
|
||||
atom.loadState().then (state) ->
|
||||
expect(state).toEqual({stuff: 'cool'})
|
||||
|
||||
it "loads state from the storage folder when it can't be found in atom.stateStore", ->
|
||||
jasmine.useRealClock()
|
||||
|
||||
storageFolderState = {foo: 1, bar: 2}
|
||||
serializedState = {someState: 42}
|
||||
loadSettings = _.extend(atom.getLoadSettings(), {initialPaths: [temp.mkdirSync("project-directory")]})
|
||||
spyOn(atom, 'getLoadSettings').andReturn(loadSettings)
|
||||
spyOn(atom, 'serialize').andReturn(serializedState)
|
||||
spyOn(atom, 'getStorageFolder').andReturn(new StorageFolder(temp.mkdirSync("config-directory")))
|
||||
atom.project.setPaths(atom.getLoadSettings().initialPaths)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.stateStore.connect()
|
||||
|
||||
runs ->
|
||||
atom.getStorageFolder().storeSync(atom.getStateKey(loadSettings.initialPaths), storageFolderState)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.loadState().then (state) -> expect(state).toEqual(storageFolderState)
|
||||
|
||||
waitsForPromise ->
|
||||
atom.saveState()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.loadState().then (state) -> expect(state).toEqual(serializedState)
|
||||
|
||||
it "saves state on keydown, mousedown, and when the editor window unloads", ->
|
||||
spyOn(atom, 'saveState')
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ Model = require './model'
|
||||
WindowEventHandler = require './window-event-handler'
|
||||
StylesElement = require './styles-element'
|
||||
StateStore = require './state-store'
|
||||
StorageFolder = require './storage-folder'
|
||||
{getWindowLoadSettings, setWindowLoadSettings} = require './window-load-settings-helpers'
|
||||
registerDefaultCommands = require './register-default-commands'
|
||||
|
||||
@@ -127,7 +128,7 @@ class AtomEnvironment extends Model
|
||||
|
||||
# Call .loadOrCreate instead
|
||||
constructor: (params={}) ->
|
||||
{@blobStore, @applicationDelegate, @window, @document, configDirPath, @enablePersistence, onlyLoadBaseStyleSheets} = params
|
||||
{@blobStore, @applicationDelegate, @window, @document, @configDirPath, @enablePersistence, onlyLoadBaseStyleSheets} = params
|
||||
|
||||
@unloaded = false
|
||||
@loadTime = null
|
||||
@@ -138,7 +139,9 @@ class AtomEnvironment extends Model
|
||||
|
||||
@stateStore = new StateStore('AtomEnvironments', 1)
|
||||
|
||||
@stateStore.clear() if clearWindowState
|
||||
if clearWindowState
|
||||
@getStorageFolder().clear()
|
||||
@stateStore.clear()
|
||||
|
||||
@deserializers = new DeserializerManager(this)
|
||||
@deserializeTimings = {}
|
||||
@@ -147,10 +150,10 @@ class AtomEnvironment extends Model
|
||||
|
||||
@notifications = new NotificationManager
|
||||
|
||||
@config = new Config({configDirPath, resourcePath, notificationManager: @notifications, @enablePersistence})
|
||||
@config = new Config({@configDirPath, resourcePath, notificationManager: @notifications, @enablePersistence})
|
||||
@setConfigSchema()
|
||||
|
||||
@keymaps = new KeymapManager({configDirPath, resourcePath, notificationManager: @notifications})
|
||||
@keymaps = new KeymapManager({@configDirPath, resourcePath, notificationManager: @notifications})
|
||||
|
||||
@tooltips = new TooltipManager(keymapManager: @keymaps)
|
||||
|
||||
@@ -159,16 +162,16 @@ class AtomEnvironment extends Model
|
||||
|
||||
@grammars = new GrammarRegistry({@config})
|
||||
|
||||
@styles = new StyleManager({configDirPath})
|
||||
@styles = new StyleManager({@configDirPath})
|
||||
|
||||
@packages = new PackageManager({
|
||||
devMode, configDirPath, resourcePath, safeMode, @config, styleManager: @styles,
|
||||
devMode, @configDirPath, resourcePath, safeMode, @config, styleManager: @styles,
|
||||
commandRegistry: @commands, keymapManager: @keymaps, notificationManager: @notifications,
|
||||
grammarRegistry: @grammars, deserializerManager: @deserializers, viewRegistry: @views
|
||||
})
|
||||
|
||||
@themes = new ThemeManager({
|
||||
packageManager: @packages, configDirPath, resourcePath, safeMode, @config,
|
||||
packageManager: @packages, @configDirPath, resourcePath, safeMode, @config,
|
||||
styleManager: @styles, notificationManager: @notifications, viewRegistry: @views
|
||||
})
|
||||
|
||||
@@ -853,7 +856,12 @@ class AtomEnvironment extends Model
|
||||
loadState: ->
|
||||
if @enablePersistence
|
||||
if stateKey = @getStateKey(@getLoadSettings().initialPaths)
|
||||
@stateStore.load(stateKey)
|
||||
@stateStore.load(stateKey).then (state) =>
|
||||
if state
|
||||
state
|
||||
else
|
||||
# TODO: remove this when every user has migrated to the IndexedDb state store.
|
||||
@getStorageFolder().load(stateKey)
|
||||
else
|
||||
@applicationDelegate.getTemporaryWindowState()
|
||||
else
|
||||
@@ -882,6 +890,9 @@ class AtomEnvironment extends Model
|
||||
else
|
||||
null
|
||||
|
||||
getStorageFolder: ->
|
||||
@storageFolder ?= new StorageFolder(@getConfigDirPath())
|
||||
|
||||
getConfigDirPath: ->
|
||||
@configDirPath ?= process.env.ATOM_HOME
|
||||
|
||||
|
||||
@@ -83,11 +83,12 @@ class GitRepository
|
||||
asyncOptions.subscribeToBuffers = false
|
||||
@async = GitRepositoryAsync.open(path, asyncOptions)
|
||||
|
||||
@statuses = {}
|
||||
@upstream = {ahead: 0, behind: 0}
|
||||
for submodulePath, submoduleRepo of @repo.submodules
|
||||
submoduleRepo.upstream = {ahead: 0, behind: 0}
|
||||
|
||||
@statusesByPath = {}
|
||||
|
||||
{@project, @config, refreshOnWindowFocus} = options
|
||||
|
||||
refreshOnWindowFocus ?= true
|
||||
@@ -165,7 +166,7 @@ class GitRepository
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
onDidChangeStatuses: (callback) ->
|
||||
@emitter.on 'did-change-statuses', callback
|
||||
@async.onDidChangeStatuses callback
|
||||
|
||||
###
|
||||
Section: Repository Details
|
||||
@@ -317,7 +318,7 @@ class GitRepository
|
||||
getDirectoryStatus: (directoryPath) ->
|
||||
directoryPath = "#{@relativize(directoryPath)}/"
|
||||
directoryStatus = 0
|
||||
for path, status of @statuses
|
||||
for path, status of _.extend({}, @async.getCachedPathStatuses(), @statusesByPath)
|
||||
directoryStatus |= status if path.indexOf(directoryPath) is 0
|
||||
directoryStatus
|
||||
|
||||
@@ -328,18 +329,26 @@ class GitRepository
|
||||
# Returns a {Number} representing the status. This value can be passed to
|
||||
# {::isStatusModified} or {::isStatusNew} to get more information.
|
||||
getPathStatus: (path) ->
|
||||
repo = @getRepo(path)
|
||||
relativePath = @relativize(path)
|
||||
|
||||
# This is a bit particular. If a package calls `getPathStatus` like this:
|
||||
# - change the file
|
||||
# - getPathStatus
|
||||
# - change the file
|
||||
# - getPathStatus
|
||||
# We need to preserve the guarantee that each call to `getPathStatus` will
|
||||
# synchronously emit 'did-change-status'. So we need to keep a cache of the
|
||||
# statuses found from this call.
|
||||
currentPathStatus = @getCachedRelativePathStatus(relativePath) ? 0
|
||||
|
||||
# Trigger events emitted on the async repo as well
|
||||
@async.refreshStatusForPath(path)
|
||||
|
||||
repo = @getRepo(path)
|
||||
relativePath = @relativize(path)
|
||||
currentPathStatus = @statuses[relativePath] ? 0
|
||||
pathStatus = repo.getStatus(repo.relativize(path)) ? 0
|
||||
pathStatus = 0 if repo.isStatusIgnored(pathStatus)
|
||||
if pathStatus > 0
|
||||
@statuses[relativePath] = pathStatus
|
||||
else
|
||||
delete @statuses[relativePath]
|
||||
@statusesByPath[relativePath] = pathStatus
|
||||
|
||||
if currentPathStatus isnt pathStatus
|
||||
@emitter.emit 'did-change-status', {path, pathStatus}
|
||||
|
||||
@@ -351,7 +360,11 @@ class GitRepository
|
||||
#
|
||||
# Returns a status {Number} or null if the path is not in the cache.
|
||||
getCachedPathStatus: (path) ->
|
||||
@statuses[@relativize(path)]
|
||||
relativePath = @relativize(path)
|
||||
@getCachedRelativePathStatus(relativePath)
|
||||
|
||||
getCachedRelativePathStatus: (relativePath) ->
|
||||
@statusesByPath[relativePath] ? @async.getCachedPathStatuses()[relativePath]
|
||||
|
||||
# Public: Returns true if the given status indicates modification.
|
||||
#
|
||||
@@ -478,24 +491,16 @@ class GitRepository
|
||||
#
|
||||
# Returns a promise that resolves when the repository has been refreshed.
|
||||
refreshStatus: ->
|
||||
asyncRefresh = @async.refreshStatus()
|
||||
asyncRefresh = @async.refreshStatus().then =>
|
||||
@statusesByPath = {}
|
||||
@branch = @async?.branch
|
||||
|
||||
syncRefresh = new Promise (resolve, reject) =>
|
||||
@handlerPath ?= require.resolve('./repository-status-handler')
|
||||
|
||||
relativeProjectPaths = @project?.getPaths()
|
||||
.map (path) => @relativize(path)
|
||||
.map (path) -> if path.length > 0 then path + '/**' else '*'
|
||||
|
||||
@statusTask?.terminate()
|
||||
@statusTask = Task.once @handlerPath, @getPath(), relativeProjectPaths, ({statuses, upstream, branch, submodules}) =>
|
||||
statusesUnchanged = _.isEqual(statuses, @statuses) and
|
||||
_.isEqual(upstream, @upstream) and
|
||||
_.isEqual(branch, @branch) and
|
||||
_.isEqual(submodules, @submodules)
|
||||
|
||||
@statuses = statuses
|
||||
@statusTask = Task.once @handlerPath, @getPath(), ({upstream, submodules}) =>
|
||||
@upstream = upstream
|
||||
@branch = branch
|
||||
@submodules = submodules
|
||||
|
||||
for submodulePath, submoduleRepo of @getRepo().submodules
|
||||
@@ -503,7 +508,4 @@ class GitRepository
|
||||
|
||||
resolve()
|
||||
|
||||
unless statusesUnchanged
|
||||
@emitter.emit 'did-change-statuses'
|
||||
|
||||
return Promise.all([asyncRefresh, syncRefresh])
|
||||
|
||||
@@ -3,6 +3,9 @@ Notification = require '../src/notification'
|
||||
|
||||
# Public: A notification manager used to create {Notification}s to be shown
|
||||
# to the user.
|
||||
#
|
||||
# An instance of this class is always available as the `atom.notifications`
|
||||
# global.
|
||||
module.exports =
|
||||
class NotificationManager
|
||||
constructor: ->
|
||||
|
||||
@@ -5,32 +5,15 @@ module.exports = (repoPath, paths = []) ->
|
||||
repo = Git.open(repoPath)
|
||||
|
||||
upstream = {}
|
||||
statuses = {}
|
||||
submodules = {}
|
||||
branch = null
|
||||
|
||||
if repo?
|
||||
# Statuses in main repo
|
||||
workingDirectoryPath = repo.getWorkingDirectory()
|
||||
repoStatus = (if paths.length > 0 then repo.getStatusForPaths(paths) else repo.getStatus())
|
||||
for filePath, status of repoStatus
|
||||
statuses[filePath] = status
|
||||
|
||||
# Statuses in submodules
|
||||
for submodulePath, submoduleRepo of repo.submodules
|
||||
submodules[submodulePath] =
|
||||
branch: submoduleRepo.getHead()
|
||||
upstream: submoduleRepo.getAheadBehindCount()
|
||||
|
||||
workingDirectoryPath = submoduleRepo.getWorkingDirectory()
|
||||
for filePath, status of submoduleRepo.getStatus()
|
||||
absolutePath = path.join(workingDirectoryPath, filePath)
|
||||
# Make path relative to parent repository
|
||||
relativePath = repo.relativize(absolutePath)
|
||||
statuses[relativePath] = status
|
||||
|
||||
upstream = repo.getAheadBehindCount()
|
||||
branch = repo.getHead()
|
||||
repo.release()
|
||||
|
||||
{statuses, upstream, branch, submodules}
|
||||
{upstream, submodules}
|
||||
|
||||
@@ -6,6 +6,14 @@ class StorageFolder
|
||||
constructor: (containingPath) ->
|
||||
@path = path.join(containingPath, "storage") if containingPath?
|
||||
|
||||
clear: ->
|
||||
return unless @path?
|
||||
|
||||
try
|
||||
fs.removeSync(@path)
|
||||
catch error
|
||||
console.warn "Error deleting #{@path}", error.stack, error
|
||||
|
||||
storeSync: (name, object) ->
|
||||
return unless @path?
|
||||
|
||||
|
||||
Reference in New Issue
Block a user