mirror of
https://github.com/atom/atom.git
synced 2026-01-24 14:28:14 -05:00
Restore state when opening folders to applicable windows
Note: "clean window" is defined as 1) having an empty project and 2) having no pane items or only empty unnamed buffers When project is empty and there is saved state associated with the opened/added folders... * Open a file or folder (from command line or Open menu) * If we have a clean window, restore project state in window * If window is dirty, restore saved state in new window
This commit is contained in:
committed by
Katrina Uychaco
parent
910fef97a0
commit
d9b73fa645
@@ -461,44 +461,91 @@ describe "AtomEnvironment", ->
|
||||
spyOn(atom.workspace, 'open')
|
||||
atom.project.setPaths([])
|
||||
|
||||
describe "when the opened path exists", ->
|
||||
it "adds it to the project's paths", ->
|
||||
pathToOpen = __filename
|
||||
atom.openLocations([{pathToOpen}])
|
||||
expect(atom.project.getPaths()[0]).toBe __dirname
|
||||
describe "when there is no saved state", ->
|
||||
beforeEach ->
|
||||
spyOn(atom, "loadState").andReturn(Promise.resolve(null))
|
||||
|
||||
describe "then a second path is opened with forceAddToWindow", ->
|
||||
it "adds the second path to the project's paths", ->
|
||||
firstPathToOpen = __dirname
|
||||
secondPathToOpen = path.resolve(__dirname, './fixtures')
|
||||
atom.openLocations([{pathToOpen: firstPathToOpen}])
|
||||
atom.openLocations([{pathToOpen: secondPathToOpen, forceAddToWindow: true}])
|
||||
expect(atom.project.getPaths()).toEqual([firstPathToOpen, secondPathToOpen])
|
||||
describe "when the opened path exists", ->
|
||||
it "adds it to the project's paths", ->
|
||||
pathToOpen = __filename
|
||||
waitsForPromise -> atom.openLocations([{pathToOpen}])
|
||||
runs -> expect(atom.project.getPaths()[0]).toBe __dirname
|
||||
|
||||
describe "when the opened path does not exist but its parent directory does", ->
|
||||
it "adds the parent directory to the project paths", ->
|
||||
pathToOpen = path.join(__dirname, 'this-path-does-not-exist.txt')
|
||||
atom.openLocations([{pathToOpen}])
|
||||
expect(atom.project.getPaths()[0]).toBe __dirname
|
||||
describe "then a second path is opened with forceAddToWindow", ->
|
||||
it "adds the second path to the project's paths", ->
|
||||
firstPathToOpen = __dirname
|
||||
secondPathToOpen = path.resolve(__dirname, './fixtures')
|
||||
waitsForPromise -> atom.openLocations([{pathToOpen: firstPathToOpen}])
|
||||
waitsForPromise -> atom.openLocations([{pathToOpen: secondPathToOpen, forceAddToWindow: true}])
|
||||
runs -> expect(atom.project.getPaths()).toEqual([firstPathToOpen, secondPathToOpen])
|
||||
|
||||
describe "when the opened path is a file", ->
|
||||
it "opens it in the workspace", ->
|
||||
pathToOpen = __filename
|
||||
atom.openLocations([{pathToOpen}])
|
||||
expect(atom.workspace.open.mostRecentCall.args[0]).toBe __filename
|
||||
describe "when the opened path does not exist but its parent directory does", ->
|
||||
it "adds the parent directory to the project paths", ->
|
||||
pathToOpen = path.join(__dirname, 'this-path-does-not-exist.txt')
|
||||
waitsForPromise -> atom.openLocations([{pathToOpen}])
|
||||
runs -> expect(atom.project.getPaths()[0]).toBe __dirname
|
||||
|
||||
describe "when the opened path is a directory", ->
|
||||
it "does not open it in the workspace", ->
|
||||
pathToOpen = __dirname
|
||||
atom.openLocations([{pathToOpen}])
|
||||
expect(atom.workspace.open.callCount).toBe 0
|
||||
describe "when the opened path is a file", ->
|
||||
it "opens it in the workspace", ->
|
||||
pathToOpen = __filename
|
||||
waitsForPromise -> atom.openLocations([{pathToOpen}])
|
||||
runs -> expect(atom.workspace.open.mostRecentCall.args[0]).toBe __filename
|
||||
|
||||
describe "when the opened path is a uri", ->
|
||||
it "adds it to the project's paths as is", ->
|
||||
pathToOpen = 'remote://server:7644/some/dir/path'
|
||||
spyOn(atom.project, 'addPath')
|
||||
atom.openLocations([{pathToOpen}])
|
||||
expect(atom.project.addPath).toHaveBeenCalledWith(pathToOpen)
|
||||
describe "when the opened path is a directory", ->
|
||||
it "does not open it in the workspace", ->
|
||||
pathToOpen = __dirname
|
||||
waitsForPromise -> atom.openLocations([{pathToOpen}])
|
||||
runs -> expect(atom.workspace.open.callCount).toBe 0
|
||||
|
||||
describe "when the opened path is a uri", ->
|
||||
it "adds it to the project's paths as is", ->
|
||||
pathToOpen = 'remote://server:7644/some/dir/path'
|
||||
spyOn(atom.project, 'addPath')
|
||||
waitsForPromise -> atom.openLocations([{pathToOpen}])
|
||||
runs -> expect(atom.project.addPath).toHaveBeenCalledWith(pathToOpen)
|
||||
|
||||
describe "when there is saved state for the relevant directories", ->
|
||||
state = Symbol('savedState')
|
||||
|
||||
beforeEach ->
|
||||
spyOn(atom, "getStateKey").andCallFake (dirs) -> dirs.join(':')
|
||||
spyOn(atom, "loadState").andCallFake (key) ->
|
||||
if key == __dirname then Promise.resolve(state) else Promise.resolve(null)
|
||||
spyOn(atom, "attemptRestoreProjectStateForPaths")
|
||||
|
||||
describe "when there are no project folders", ->
|
||||
it "attempts to restore the project state", ->
|
||||
pathToOpen = __dirname
|
||||
waitsForPromise -> atom.openLocations([{pathToOpen}])
|
||||
runs ->
|
||||
expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith(state, [pathToOpen], [])
|
||||
expect(atom.project.getPaths()).toEqual([])
|
||||
|
||||
it "opens the specified files", ->
|
||||
waitsForPromise -> atom.openLocations([{pathToOpen: __dirname}, {pathToOpen: __filename}])
|
||||
runs ->
|
||||
expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith(state, [__dirname], [__filename])
|
||||
expect(atom.project.getPaths()).toEqual([])
|
||||
|
||||
|
||||
describe "when there are already project folders", ->
|
||||
beforeEach ->
|
||||
atom.project.setPaths([__dirname])
|
||||
|
||||
it "does not attempt to restore the project state, instead adding the project paths", ->
|
||||
pathToOpen = path.join(__dirname, 'fixtures')
|
||||
waitsForPromise -> atom.openLocations([{pathToOpen, forceAddToWindow: true}])
|
||||
runs ->
|
||||
expect(atom.attemptRestoreProjectStateForPaths).not.toHaveBeenCalled()
|
||||
expect(atom.project.getPaths()).toEqual([__dirname, pathToOpen])
|
||||
|
||||
it "opens the specified files", ->
|
||||
pathToOpen = path.join(__dirname, 'fixtures')
|
||||
fileToOpen = path.join(pathToOpen, 'michelle-is-awesome.txt')
|
||||
waitsForPromise -> atom.openLocations([{pathToOpen}, {pathToOpen: fileToOpen}])
|
||||
runs ->
|
||||
expect(atom.attemptRestoreProjectStateForPaths).not.toHaveBeenCalledWith(state, [pathToOpen], [fileToOpen])
|
||||
expect(atom.project.getPaths()).toEqual([__dirname])
|
||||
|
||||
describe "::updateAvailable(info) (called via IPC from browser process)", ->
|
||||
subscription = null
|
||||
|
||||
@@ -1019,23 +1019,38 @@ class AtomEnvironment extends Model
|
||||
openLocations: (locations) ->
|
||||
needsProjectPaths = @project?.getPaths().length is 0
|
||||
|
||||
foldersToAddToProject = []
|
||||
fileLocationsToOpen = []
|
||||
|
||||
pushFolderToOpen = (folder) ->
|
||||
if folder not in foldersToAddToProject
|
||||
foldersToAddToProject.push(folder)
|
||||
|
||||
for {pathToOpen, initialLine, initialColumn, forceAddToWindow} in locations
|
||||
if pathToOpen? and (needsProjectPaths or forceAddToWindow)
|
||||
if fs.existsSync(pathToOpen)
|
||||
@project.addPath(pathToOpen)
|
||||
pushFolderToOpen @project.getDirectoryForProjectPath(pathToOpen).getPath()
|
||||
else if fs.existsSync(path.dirname(pathToOpen))
|
||||
@project.addPath(path.dirname(pathToOpen))
|
||||
pushFolderToOpen @project.getDirectoryForProjectPath(path.dirname(pathToOpen)).getPath()
|
||||
else
|
||||
@project.addPath(pathToOpen)
|
||||
pushFolderToOpen @project.getDirectoryForProjectPath(pathToOpen).getPath()
|
||||
|
||||
unless fs.isDirectorySync(pathToOpen)
|
||||
fileLocationsToOpen.push({pathToOpen, initialLine, initialColumn})
|
||||
|
||||
if foldersToAddToProject.length > 0
|
||||
@loadState(@getStateKey(foldersToAddToProject)).then (state) =>
|
||||
if state and needsProjectPaths # only load state if this is the first path added to the project
|
||||
files = (location.pathToOpen for location in fileLocationsToOpen)
|
||||
@attemptRestoreProjectStateForPaths(state, foldersToAddToProject, files)
|
||||
else
|
||||
@project.addPath(folder) for folder in foldersToAddToProject
|
||||
for {pathToOpen, initialLine, initialColumn} in fileLocationsToOpen
|
||||
@workspace?.open(pathToOpen, {initialLine, initialColumn})
|
||||
else
|
||||
for {pathToOpen, initialLine, initialColumn} in fileLocationsToOpen
|
||||
@workspace?.open(pathToOpen, {initialLine, initialColumn})
|
||||
|
||||
if needsProjectPaths
|
||||
@loadState(@getStateKey(@project.getPaths())).then (state) =>
|
||||
@restoreStateIntoEnvironment(state) if state
|
||||
|
||||
return
|
||||
Promise.resolve(null)
|
||||
|
||||
# Preserve this deprecation until 2.0. Sorry. Should have removed Q sooner.
|
||||
Promise.prototype.done = (callback) ->
|
||||
|
||||
@@ -184,11 +184,7 @@ class Project extends Model
|
||||
#
|
||||
# * `projectPath` {String} The path to the directory to add.
|
||||
addPath: (projectPath, options) ->
|
||||
directory = null
|
||||
for provider in @directoryProviders
|
||||
break if directory = provider.directoryForURISync?(projectPath)
|
||||
directory ?= @defaultDirectoryProvider.directoryForURISync(projectPath)
|
||||
|
||||
directory = @getDirectoryForProjectPath(projectPath)
|
||||
return unless directory.existsSync()
|
||||
for existingDirectory in @getDirectories()
|
||||
return if existingDirectory.getPath() is directory.getPath()
|
||||
@@ -203,6 +199,13 @@ class Project extends Model
|
||||
unless options?.emitEvent is false
|
||||
@emitter.emit 'did-change-paths', @getPaths()
|
||||
|
||||
getDirectoryForProjectPath: (projectPath) ->
|
||||
directory = null
|
||||
for provider in @directoryProviders
|
||||
break if directory = provider.directoryForURISync?(projectPath)
|
||||
directory ?= @defaultDirectoryProvider.directoryForURISync(projectPath)
|
||||
directory
|
||||
|
||||
# Public: remove a path from the project's list of root paths.
|
||||
#
|
||||
# * `projectPath` {String} The path to remove.
|
||||
|
||||
Reference in New Issue
Block a user