mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-19 23:17:16 +03:00
Merge pull request #18742 from atom/aw/deleted-project-folder
Improve behavior when restoring session that references a missing project folder
This commit is contained in:
commit
6055f289ae
@ -669,6 +669,28 @@ describe('AtomEnvironment', () => {
|
||||
expect(atom.workspace.getTextEditors().map(e => e.getPath())).toEqual([pathToOpen])
|
||||
expect(atom.project.getPaths()).toEqual([])
|
||||
})
|
||||
|
||||
it('may be required to be an existing directory', async () => {
|
||||
spyOn(atom.notifications, 'addWarning')
|
||||
|
||||
const nonExistent = path.join(__dirname, 'no')
|
||||
const existingFile = __filename
|
||||
const existingDir = path.join(__dirname, 'fixtures')
|
||||
|
||||
await atom.openLocations([
|
||||
{pathToOpen: nonExistent, mustBeDirectory: true},
|
||||
{pathToOpen: existingFile, mustBeDirectory: true},
|
||||
{pathToOpen: existingDir, mustBeDirectory: true}
|
||||
])
|
||||
|
||||
expect(atom.workspace.getTextEditors()).toEqual([])
|
||||
expect(atom.project.getPaths()).toEqual([existingDir])
|
||||
|
||||
expect(atom.notifications.addWarning).toHaveBeenCalledWith(
|
||||
'Unable to open project folders',
|
||||
{description: `The directories \`${nonExistent}\` and \`${existingFile}\` do not exist.`}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the opened path is handled by a registered directory provider', () => {
|
||||
@ -720,6 +742,27 @@ describe('AtomEnvironment', () => {
|
||||
expect(atom.project.getPaths()).toEqual([])
|
||||
})
|
||||
|
||||
it('includes missing mandatory project folders in computation of initial state key', async () => {
|
||||
const existingDir = path.join(__dirname, 'fixtures')
|
||||
const missingDir = path.join(__dirname, 'no')
|
||||
|
||||
atom.loadState.andCallFake(function (key) {
|
||||
if (key === `${existingDir}:${missingDir}`) {
|
||||
return Promise.resolve(state)
|
||||
} else {
|
||||
return Promise.resolve(null)
|
||||
}
|
||||
})
|
||||
|
||||
await atom.openLocations([
|
||||
{pathToOpen: existingDir},
|
||||
{pathToOpen: missingDir, mustBeDirectory: true}
|
||||
])
|
||||
|
||||
expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith(state, [existingDir], [])
|
||||
expect(atom.project.getPaths(), [existingDir])
|
||||
})
|
||||
|
||||
it('opens the specified files', async () => {
|
||||
await atom.openLocations([{pathToOpen: __dirname}, {pathToOpen: __filename}])
|
||||
expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith(state, [__dirname], [__filename])
|
||||
|
@ -1364,6 +1364,7 @@ or use Pane::saveItemAs for programmatic saving.`)
|
||||
const needsProjectPaths = this.project && this.project.getPaths().length === 0
|
||||
const foldersToAddToProject = new Set()
|
||||
const fileLocationsToOpen = []
|
||||
const missingFolders = []
|
||||
|
||||
// Asynchronously fetch stat information about each requested path to open.
|
||||
const locationStats = await Promise.all(
|
||||
@ -1387,8 +1388,13 @@ or use Pane::saveItemAs for programmatic saving.`)
|
||||
// Directory: add as a project folder
|
||||
foldersToAddToProject.add(this.project.getDirectoryForProjectPath(pathToOpen).getPath())
|
||||
} else if (stats.isFile()) {
|
||||
// File: add as a file location
|
||||
fileLocationsToOpen.push(location)
|
||||
if (location.mustBeDirectory) {
|
||||
// File: no longer a directory
|
||||
missingFolders.push(location)
|
||||
} else {
|
||||
// File: add as a file location
|
||||
fileLocationsToOpen.push(location)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Path does not exist
|
||||
@ -1397,6 +1403,9 @@ or use Pane::saveItemAs for programmatic saving.`)
|
||||
if (directory) {
|
||||
// Found: add as a project folder
|
||||
foldersToAddToProject.add(directory.getPath())
|
||||
} else if (location.mustBeDirectory) {
|
||||
// Not found and must be a directory: add to missing list and use to derive state key
|
||||
missingFolders.push(location)
|
||||
} else {
|
||||
// Not found: open as a new file
|
||||
fileLocationsToOpen.push(location)
|
||||
@ -1407,8 +1416,12 @@ or use Pane::saveItemAs for programmatic saving.`)
|
||||
}
|
||||
|
||||
let restoredState = false
|
||||
if (foldersToAddToProject.size > 0) {
|
||||
const state = await this.loadState(this.getStateKey(Array.from(foldersToAddToProject)))
|
||||
if (foldersToAddToProject.size > 0 || missingFolders.length > 0) {
|
||||
// Include missing folders in the state key so that sessions restored with no-longer-present project root folders
|
||||
// don't lose data.
|
||||
const foldersForStateKey = Array.from(foldersToAddToProject)
|
||||
.concat(missingFolders.map(location => location.pathToOpen))
|
||||
const state = await this.loadState(this.getStateKey(Array.from(foldersForStateKey)))
|
||||
|
||||
// only restore state if this is the first path added to the project
|
||||
if (state && needsProjectPaths) {
|
||||
@ -1430,6 +1443,33 @@ or use Pane::saveItemAs for programmatic saving.`)
|
||||
await Promise.all(fileOpenPromises)
|
||||
}
|
||||
|
||||
if (missingFolders.length > 0) {
|
||||
let message = 'Unable to open project folder'
|
||||
if (missingFolders.length > 1) {
|
||||
message += 's'
|
||||
}
|
||||
|
||||
let description = 'The '
|
||||
if (missingFolders.length === 1) {
|
||||
description += 'directory `'
|
||||
description += missingFolders[0].pathToOpen
|
||||
description += '` does not exist.'
|
||||
} else if (missingFolders.length === 2) {
|
||||
description += `directories \`${missingFolders[0].pathToOpen}\` `
|
||||
description += `and \`${missingFolders[1].pathToOpen}\` do not exist.`
|
||||
} else {
|
||||
description += 'directories '
|
||||
description += (missingFolders
|
||||
.slice(0, -1)
|
||||
.map(location => location.pathToOpen)
|
||||
.map(pathToOpen => '`' + pathToOpen + '`, ')
|
||||
.join(''))
|
||||
description += 'and `' + missingFolders[missingFolders.length - 1].pathToOpen + '` do not exist.'
|
||||
}
|
||||
|
||||
this.notifications.addWarning(message, {description})
|
||||
}
|
||||
|
||||
ipcRenderer.send('window-command', 'window:locations-opened')
|
||||
}
|
||||
|
||||
|
@ -210,6 +210,7 @@ class AtomApplication extends EventEmitter {
|
||||
const {
|
||||
pathsToOpen,
|
||||
executedFrom,
|
||||
foldersToOpen,
|
||||
urlsToOpen,
|
||||
benchmark,
|
||||
benchmarkTest,
|
||||
@ -248,9 +249,10 @@ class AtomApplication extends EventEmitter {
|
||||
timeout,
|
||||
env
|
||||
})
|
||||
} else if (pathsToOpen.length > 0) {
|
||||
} else if ((pathsToOpen && pathsToOpen.length > 0) || (foldersToOpen && foldersToOpen.length > 0)) {
|
||||
return this.openPaths({
|
||||
pathsToOpen,
|
||||
foldersToOpen,
|
||||
executedFrom,
|
||||
pidToKillWhenClosed,
|
||||
devMode,
|
||||
@ -806,6 +808,7 @@ class AtomApplication extends EventEmitter {
|
||||
//
|
||||
// options -
|
||||
// :pathsToOpen - The array of file paths to open
|
||||
// :foldersToOpen - An array of additional paths to open that must be existing directories
|
||||
// :pidToKillWhenClosed - The integer of the pid to kill
|
||||
// :devMode - Boolean to control the opened window's dev mode.
|
||||
// :safeMode - Boolean to control the opened window's safe mode.
|
||||
@ -814,6 +817,7 @@ class AtomApplication extends EventEmitter {
|
||||
// :addToLastWindow - Boolean of whether this should be opened in last focused window.
|
||||
openPaths ({
|
||||
pathsToOpen,
|
||||
foldersToOpen,
|
||||
executedFrom,
|
||||
pidToKillWhenClosed,
|
||||
devMode,
|
||||
@ -825,8 +829,10 @@ class AtomApplication extends EventEmitter {
|
||||
addToLastWindow,
|
||||
env
|
||||
} = {}) {
|
||||
if (!pathsToOpen || pathsToOpen.length === 0) return
|
||||
if (!env) env = process.env
|
||||
if (!pathsToOpen) pathsToOpen = []
|
||||
if (!foldersToOpen) foldersToOpen = []
|
||||
|
||||
devMode = Boolean(devMode)
|
||||
safeMode = Boolean(safeMode)
|
||||
clearWindowState = Boolean(clearWindowState)
|
||||
@ -837,6 +843,22 @@ class AtomApplication extends EventEmitter {
|
||||
hasWaitSession: pidToKillWhenClosed != null
|
||||
})
|
||||
})
|
||||
|
||||
for (const folderToOpen of foldersToOpen) {
|
||||
locationsToOpen.push({
|
||||
pathToOpen: folderToOpen,
|
||||
initialLine: null,
|
||||
initialColumn: null,
|
||||
mustBeDirectory: true,
|
||||
forceAddToWindow: addToLastWindow,
|
||||
hasWaitSession: pidToKillWhenClosed != null
|
||||
})
|
||||
}
|
||||
|
||||
if (locationsToOpen.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const normalizedPathsToOpen = locationsToOpen.map(location => location.pathToOpen).filter(Boolean)
|
||||
|
||||
let existingWindow
|
||||
@ -966,7 +988,7 @@ class AtomApplication extends EventEmitter {
|
||||
const states = await this.storageFolder.load('application.json')
|
||||
if (states) {
|
||||
return states.map(state => ({
|
||||
pathsToOpen: state.initialPaths,
|
||||
foldersToOpen: state.initialPaths,
|
||||
urlsToOpen: [],
|
||||
devMode: this.devMode,
|
||||
safeMode: this.safeMode
|
||||
|
Loading…
Reference in New Issue
Block a user