mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-20 07:28:08 +03:00
Merge pull request #16229 from atom/wl-async-confirm
Make atom.confirm async
This commit is contained in:
commit
cd123456ca
@ -1,4 +1,4 @@
|
||||
const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers')
|
||||
const {it, fit, ffit, beforeEach, afterEach, conditionPromise} = require('./async-spec-helpers')
|
||||
const _ = require('underscore-plus')
|
||||
const path = require('path')
|
||||
const temp = require('temp').track()
|
||||
@ -518,27 +518,31 @@ describe('AtomEnvironment', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('prompts the user to restore the state in a new window, discarding it and adding folder to current window', () => {
|
||||
spyOn(atom, 'confirm').andReturn(1)
|
||||
it('prompts the user to restore the state in a new window, discarding it and adding folder to current window', async () => {
|
||||
jasmine.useRealClock()
|
||||
spyOn(atom, 'confirm').andCallFake((options, callback) => callback(1))
|
||||
spyOn(atom.project, 'addPath')
|
||||
spyOn(atom.workspace, 'open')
|
||||
const state = Symbol()
|
||||
|
||||
atom.attemptRestoreProjectStateForPaths(state, [__dirname], [__filename])
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
expect(atom.project.addPath.callCount).toBe(1)
|
||||
await conditionPromise(() => atom.project.addPath.callCount === 1)
|
||||
|
||||
expect(atom.project.addPath).toHaveBeenCalledWith(__dirname)
|
||||
expect(atom.workspace.open.callCount).toBe(1)
|
||||
expect(atom.workspace.open).toHaveBeenCalledWith(__filename)
|
||||
})
|
||||
|
||||
it('prompts the user to restore the state in a new window, opening a new window', () => {
|
||||
spyOn(atom, 'confirm').andReturn(0)
|
||||
it('prompts the user to restore the state in a new window, opening a new window', async () => {
|
||||
jasmine.useRealClock()
|
||||
spyOn(atom, 'confirm').andCallFake((options, callback) => callback(0))
|
||||
spyOn(atom, 'open')
|
||||
const state = Symbol()
|
||||
|
||||
atom.attemptRestoreProjectStateForPaths(state, [__dirname], [__filename])
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
await conditionPromise(() => atom.open.callCount === 1)
|
||||
expect(atom.open).toHaveBeenCalledWith({
|
||||
pathsToOpen: [__dirname, __filename],
|
||||
newWindow: true,
|
||||
|
@ -35,9 +35,9 @@ describe('CommandInstaller on #darwin', () => {
|
||||
|
||||
installer.installShellCommandsInteractively()
|
||||
|
||||
expect(appDelegate.confirm).toHaveBeenCalledWith({
|
||||
expect(appDelegate.confirm.mostRecentCall.args[0]).toEqual({
|
||||
message: 'Failed to install shell commands',
|
||||
detailedMessage: 'an error'
|
||||
detail: 'an error'
|
||||
})
|
||||
|
||||
appDelegate.confirm.reset()
|
||||
@ -46,9 +46,9 @@ describe('CommandInstaller on #darwin', () => {
|
||||
|
||||
installer.installShellCommandsInteractively()
|
||||
|
||||
expect(appDelegate.confirm).toHaveBeenCalledWith({
|
||||
expect(appDelegate.confirm.mostRecentCall.args[0]).toEqual({
|
||||
message: 'Failed to install shell commands',
|
||||
detailedMessage: 'another error'
|
||||
detail: 'another error'
|
||||
})
|
||||
})
|
||||
|
||||
@ -61,9 +61,9 @@ describe('CommandInstaller on #darwin', () => {
|
||||
|
||||
installer.installShellCommandsInteractively()
|
||||
|
||||
expect(appDelegate.confirm).toHaveBeenCalledWith({
|
||||
expect(appDelegate.confirm.mostRecentCall.args[0]).toEqual({
|
||||
message: 'Commands installed.',
|
||||
detailedMessage: 'The shell commands `atom` and `apm` are installed.'
|
||||
detail: 'The shell commands `atom` and `apm` are installed.'
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -621,14 +621,14 @@ describe('AtomApplication', function () {
|
||||
})
|
||||
|
||||
// Choosing "Cancel"
|
||||
mockElectronShowMessageBox({choice: 1})
|
||||
mockElectronShowMessageBox({response: 1})
|
||||
electron.app.quit()
|
||||
await atomApplication.lastBeforeQuitPromise
|
||||
assert(!electron.app.didQuit())
|
||||
assert.equal(electron.app.quit.callCount, 1) // Ensure choosing "Cancel" doesn't try to quit the electron app more than once (regression)
|
||||
|
||||
// Choosing "Don't save"
|
||||
mockElectronShowMessageBox({choice: 2})
|
||||
mockElectronShowMessageBox({response: 2})
|
||||
electron.app.quit()
|
||||
await atomApplication.lastBeforeQuitPromise
|
||||
assert(electron.app.didQuit())
|
||||
@ -664,9 +664,9 @@ describe('AtomApplication', function () {
|
||||
electron.app.didQuit = () => didQuit
|
||||
}
|
||||
|
||||
function mockElectronShowMessageBox ({choice}) {
|
||||
electron.dialog.showMessageBox = () => {
|
||||
return choice
|
||||
function mockElectronShowMessageBox ({response}) {
|
||||
electron.dialog.showMessageBox = (window, options, callback) => {
|
||||
callback(response)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ describe('PaneContainer', () => {
|
||||
let confirm, params
|
||||
|
||||
beforeEach(() => {
|
||||
confirm = spyOn(atom.applicationDelegate, 'confirm').andReturn(0)
|
||||
confirm = spyOn(atom.applicationDelegate, 'confirm').andCallFake((options, callback) => callback(0))
|
||||
params = {
|
||||
location: 'center',
|
||||
config: atom.config,
|
||||
@ -280,14 +280,14 @@ describe('PaneContainer', () => {
|
||||
})
|
||||
|
||||
it('returns true if the user saves all modified files when prompted', async () => {
|
||||
confirm.andReturn(0)
|
||||
confirm.andCallFake((options, callback) => callback(0))
|
||||
const saved = await container.confirmClose()
|
||||
expect(confirm).toHaveBeenCalled()
|
||||
expect(saved).toBeTruthy()
|
||||
})
|
||||
|
||||
it('returns false if the user cancels saving any modified file', async () => {
|
||||
confirm.andReturn(1)
|
||||
confirm.andCallFake((options, callback) => callback(1))
|
||||
const saved = await container.confirmClose()
|
||||
expect(confirm).toHaveBeenCalled()
|
||||
expect(saved).toBeFalsy()
|
||||
|
@ -564,7 +564,7 @@ describe('Pane', () => {
|
||||
describe('when the item has a uri', () => {
|
||||
it('saves the item before destroying it', async () => {
|
||||
itemURI = 'test'
|
||||
confirm.andReturn(0)
|
||||
confirm.andCallFake((options, callback) => callback(0))
|
||||
|
||||
const success = await pane.destroyItem(item1)
|
||||
expect(item1.save).toHaveBeenCalled()
|
||||
@ -579,7 +579,7 @@ describe('Pane', () => {
|
||||
itemURI = null
|
||||
|
||||
showSaveDialog.andReturn('/selected/path')
|
||||
confirm.andReturn(0)
|
||||
confirm.andCallFake((options, callback) => callback(0))
|
||||
|
||||
const success = await pane.destroyItem(item1)
|
||||
expect(showSaveDialog).toHaveBeenCalledWith({})
|
||||
@ -593,7 +593,7 @@ describe('Pane', () => {
|
||||
|
||||
describe("if the [Don't Save] option is selected", () => {
|
||||
it('removes and destroys the item without saving it', async () => {
|
||||
confirm.andReturn(2)
|
||||
confirm.andCallFake((options, callback) => callback(2))
|
||||
|
||||
const success = await pane.destroyItem(item1)
|
||||
expect(item1.save).not.toHaveBeenCalled()
|
||||
@ -605,7 +605,7 @@ describe('Pane', () => {
|
||||
|
||||
describe('if the [Cancel] option is selected', () => {
|
||||
it('does not save, remove, or destroy the item', async () => {
|
||||
confirm.andReturn(1)
|
||||
confirm.andCallFake((options, callback) => callback(1))
|
||||
|
||||
const success = await pane.destroyItem(item1)
|
||||
expect(item1.save).not.toHaveBeenCalled()
|
||||
@ -1210,7 +1210,7 @@ describe('Pane', () => {
|
||||
item1.getURI = () => '/test/path'
|
||||
item1.save = jasmine.createSpy('save')
|
||||
|
||||
confirm.andReturn(0)
|
||||
confirm.andCallFake((options, callback) => callback(0))
|
||||
await pane.close()
|
||||
expect(confirm).toHaveBeenCalled()
|
||||
expect(item1.save).toHaveBeenCalled()
|
||||
@ -1225,7 +1225,7 @@ describe('Pane', () => {
|
||||
item1.getURI = () => '/test/path'
|
||||
item1.save = jasmine.createSpy('save')
|
||||
|
||||
confirm.andReturn(1)
|
||||
confirm.andCallFake((options, callback) => callback(1))
|
||||
|
||||
await pane.close()
|
||||
expect(confirm).toHaveBeenCalled()
|
||||
@ -1240,7 +1240,7 @@ describe('Pane', () => {
|
||||
item1.shouldPromptToSave = () => true
|
||||
item1.saveAs = jasmine.createSpy('saveAs')
|
||||
|
||||
confirm.andReturn(0)
|
||||
confirm.andCallFake((options, callback) => callback(0))
|
||||
showSaveDialog.andReturn(undefined)
|
||||
|
||||
await pane.close()
|
||||
@ -1270,12 +1270,12 @@ describe('Pane', () => {
|
||||
|
||||
it('does not destroy the pane if save fails and user clicks cancel', async () => {
|
||||
let confirmations = 0
|
||||
confirm.andCallFake(() => {
|
||||
confirm.andCallFake((options, callback) => {
|
||||
confirmations++
|
||||
if (confirmations === 1) {
|
||||
return 0 // click save
|
||||
callback(0) // click save
|
||||
} else {
|
||||
return 1
|
||||
callback(1)
|
||||
}
|
||||
}) // click cancel
|
||||
|
||||
@ -1290,9 +1290,9 @@ describe('Pane', () => {
|
||||
item1.saveAs = jasmine.createSpy('saveAs').andReturn(true)
|
||||
|
||||
let confirmations = 0
|
||||
confirm.andCallFake(() => {
|
||||
confirm.andCallFake((options, callback) => {
|
||||
confirmations++
|
||||
return 0
|
||||
callback(0)
|
||||
}) // save and then save as
|
||||
|
||||
showSaveDialog.andReturn('new/path')
|
||||
@ -1315,13 +1315,14 @@ describe('Pane', () => {
|
||||
})
|
||||
|
||||
let confirmations = 0
|
||||
confirm.andCallFake(() => {
|
||||
confirm.andCallFake((options, callback) => {
|
||||
confirmations++
|
||||
if (confirmations < 3) {
|
||||
return 0 // save, save as, save as
|
||||
callback(0) // save, save as, save as
|
||||
} else {
|
||||
callback(2) // don't save
|
||||
}
|
||||
return 2
|
||||
}) // don't save
|
||||
})
|
||||
|
||||
showSaveDialog.andReturn('new/path')
|
||||
|
||||
|
@ -10,7 +10,7 @@ const _ = require('underscore-plus')
|
||||
const fstream = require('fstream')
|
||||
const fs = require('fs-plus')
|
||||
const AtomEnvironment = require('../src/atom-environment')
|
||||
const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers')
|
||||
const {it, fit, ffit, fffit, beforeEach, afterEach, conditionPromise} = require('./async-spec-helpers')
|
||||
|
||||
describe('Workspace', () => {
|
||||
let workspace
|
||||
@ -659,47 +659,42 @@ describe('Workspace', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the file is over user-defined limit', () => {
|
||||
const shouldPromptForFileOfSize = (size, shouldPrompt) => {
|
||||
describe('when the file size is over the limit defined in `core.warnOnLargeFileLimit`', () => {
|
||||
const shouldPromptForFileOfSize = async (size, shouldPrompt) => {
|
||||
spyOn(fs, 'getSizeSync').andReturn(size * 1048577)
|
||||
atom.applicationDelegate.confirm.andCallFake(() => selectedButtonIndex)
|
||||
atom.applicationDelegate.confirm()
|
||||
var selectedButtonIndex = 1 // cancel
|
||||
|
||||
let editor = null
|
||||
waitsForPromise(() => workspace.open('sample.js').then(e => { editor = e }))
|
||||
let selectedButtonIndex = 1 // cancel
|
||||
atom.applicationDelegate.confirm.andCallFake((options, callback) => callback(selectedButtonIndex))
|
||||
|
||||
let editor = await workspace.open('sample.js')
|
||||
if (shouldPrompt) {
|
||||
runs(() => {
|
||||
expect(editor).toBeUndefined()
|
||||
expect(atom.applicationDelegate.confirm).toHaveBeenCalled()
|
||||
expect(editor).toBeUndefined()
|
||||
expect(atom.applicationDelegate.confirm).toHaveBeenCalled()
|
||||
|
||||
atom.applicationDelegate.confirm.reset()
|
||||
selectedButtonIndex = 0
|
||||
}) // open the file
|
||||
atom.applicationDelegate.confirm.reset()
|
||||
selectedButtonIndex = 0 // open the file
|
||||
|
||||
waitsForPromise(() => workspace.open('sample.js').then(e => { editor = e }))
|
||||
editor = await workspace.open('sample.js')
|
||||
|
||||
runs(() => {
|
||||
expect(atom.applicationDelegate.confirm).toHaveBeenCalled()
|
||||
})
|
||||
expect(atom.applicationDelegate.confirm).toHaveBeenCalled()
|
||||
} else {
|
||||
runs(() => expect(editor).not.toBeUndefined())
|
||||
expect(editor).not.toBeUndefined()
|
||||
}
|
||||
}
|
||||
|
||||
it('prompts the user to make sure they want to open a file this big', () => {
|
||||
it('prompts before opening the file', async () => {
|
||||
atom.config.set('core.warnOnLargeFileLimit', 20)
|
||||
shouldPromptForFileOfSize(20, true)
|
||||
await shouldPromptForFileOfSize(20, true)
|
||||
})
|
||||
|
||||
it("doesn't prompt on files below the limit", () => {
|
||||
it("doesn't prompt on files below the limit", async () => {
|
||||
atom.config.set('core.warnOnLargeFileLimit', 30)
|
||||
shouldPromptForFileOfSize(20, false)
|
||||
await shouldPromptForFileOfSize(20, false)
|
||||
})
|
||||
|
||||
it('prompts for smaller files with a lower limit', () => {
|
||||
it('prompts for smaller files with a lower limit', async () => {
|
||||
atom.config.set('core.warnOnLargeFileLimit', 5)
|
||||
shouldPromptForFileOfSize(10, true)
|
||||
await shouldPromptForFileOfSize(10, true)
|
||||
})
|
||||
})
|
||||
|
||||
@ -2809,29 +2804,30 @@ describe('Workspace', () => {
|
||||
|
||||
describe('.checkoutHeadRevision()', () => {
|
||||
let editor = null
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
jasmine.useRealClock()
|
||||
atom.config.set('editor.confirmCheckoutHeadRevision', false)
|
||||
|
||||
waitsForPromise(() => atom.workspace.open('sample-with-comments.js').then(o => { editor = o }))
|
||||
editor = await atom.workspace.open('sample-with-comments.js')
|
||||
})
|
||||
|
||||
it('reverts to the version of its file checked into the project repository', () => {
|
||||
it('reverts to the version of its file checked into the project repository', async () => {
|
||||
editor.setCursorBufferPosition([0, 0])
|
||||
editor.insertText('---\n')
|
||||
expect(editor.lineTextForBufferRow(0)).toBe('---')
|
||||
|
||||
waitsForPromise(() => atom.workspace.checkoutHeadRevision(editor))
|
||||
atom.workspace.checkoutHeadRevision(editor)
|
||||
|
||||
runs(() => expect(editor.lineTextForBufferRow(0)).toBe(''))
|
||||
await conditionPromise(() => editor.lineTextForBufferRow(0) === '')
|
||||
})
|
||||
|
||||
describe("when there's no repository for the editor's file", () => {
|
||||
it("doesn't do anything", () => {
|
||||
it("doesn't do anything", async () => {
|
||||
editor = new TextEditor()
|
||||
editor.setText('stuff')
|
||||
atom.workspace.checkoutHeadRevision(editor)
|
||||
|
||||
waitsForPromise(() => atom.workspace.checkoutHeadRevision(editor))
|
||||
atom.workspace.checkoutHeadRevision(editor)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -175,28 +175,38 @@ class ApplicationDelegate {
|
||||
return remote.systemPreferences.getUserDefault(key, type)
|
||||
}
|
||||
|
||||
confirm ({message, detailedMessage, buttons}) {
|
||||
let buttonLabels
|
||||
if (!buttons) buttons = {}
|
||||
if (Array.isArray(buttons)) {
|
||||
buttonLabels = buttons
|
||||
confirm (options, callback) {
|
||||
if (typeof callback === 'function') {
|
||||
// Async version: pass options directly to Electron but set sane defaults
|
||||
options = Object.assign({type: 'info', normalizeAccessKeys: true}, options)
|
||||
remote.dialog.showMessageBox(remote.getCurrentWindow(), options, callback)
|
||||
} else {
|
||||
buttonLabels = Object.keys(buttons)
|
||||
}
|
||||
// Legacy sync version: options can only have `message`,
|
||||
// `detailedMessage` (optional), and buttons array or object (optional)
|
||||
let {message, detailedMessage, buttons} = options
|
||||
|
||||
const chosen = remote.dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'info',
|
||||
message,
|
||||
detail: detailedMessage,
|
||||
buttons: buttonLabels,
|
||||
normalizeAccessKeys: true
|
||||
})
|
||||
let buttonLabels
|
||||
if (!buttons) buttons = {}
|
||||
if (Array.isArray(buttons)) {
|
||||
buttonLabels = buttons
|
||||
} else {
|
||||
buttonLabels = Object.keys(buttons)
|
||||
}
|
||||
|
||||
if (Array.isArray(buttons)) {
|
||||
return chosen
|
||||
} else {
|
||||
const callback = buttons[buttonLabels[chosen]]
|
||||
return (typeof callback === 'function' ? callback() : undefined)
|
||||
const chosen = remote.dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'info',
|
||||
message,
|
||||
detail: detailedMessage,
|
||||
buttons: buttonLabels,
|
||||
normalizeAccessKeys: true
|
||||
})
|
||||
|
||||
if (Array.isArray(buttons)) {
|
||||
return chosen
|
||||
} else {
|
||||
const callback = buttons[buttonLabels[chosen]]
|
||||
if (typeof callback === 'function') callback()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -965,29 +965,63 @@ class AtomEnvironment {
|
||||
|
||||
// Essential: A flexible way to open a dialog akin to an alert dialog.
|
||||
//
|
||||
// While both async and sync versions are provided, it is recommended to use the async version
|
||||
// such that the renderer process is not blocked while the dialog box is open.
|
||||
//
|
||||
// The async version accepts the same options as Electron's `dialog.showMessageBox`.
|
||||
// For convenience, it sets `type` to `'info'` and `normalizeAccessKeys` to `true` by default.
|
||||
//
|
||||
// If the dialog is closed (via `Esc` key or `X` in the top corner) without selecting a button
|
||||
// the first button will be clicked unless a "Cancel" or "No" button is provided.
|
||||
//
|
||||
// ## Examples
|
||||
//
|
||||
// ```coffee
|
||||
// atom.confirm
|
||||
// message: 'How you feeling?'
|
||||
// detailedMessage: 'Be honest.'
|
||||
// buttons:
|
||||
// Good: -> window.alert('good to hear')
|
||||
// Bad: -> window.alert('bummer')
|
||||
// ```js
|
||||
// // Async version (recommended)
|
||||
// atom.confirm({
|
||||
// message: 'How you feeling?',
|
||||
// detail: 'Be honest.',
|
||||
// buttons: ['Good', 'Bad']
|
||||
// }, response => {
|
||||
// if (response === 0) {
|
||||
// window.alert('good to hear')
|
||||
// } else {
|
||||
// window.alert('bummer')
|
||||
// }
|
||||
// })
|
||||
//
|
||||
// ```js
|
||||
// // Legacy sync version
|
||||
// const chosen = atom.confirm({
|
||||
// message: 'How you feeling?',
|
||||
// detailedMessage: 'Be honest.',
|
||||
// buttons: {
|
||||
// Good: () => window.alert('good to hear'),
|
||||
// Bad: () => window.alert('bummer')
|
||||
// }
|
||||
// })
|
||||
// ```
|
||||
//
|
||||
// * `options` An {Object} with the following keys:
|
||||
// * `options` An options {Object}. If the callback argument is also supplied, see the documentation at
|
||||
// https://electronjs.org/docs/api/dialog#dialogshowmessageboxbrowserwindow-options-callback for the list of
|
||||
// available options. Otherwise, only the following keys are accepted:
|
||||
// * `message` The {String} message to display.
|
||||
// * `detailedMessage` (optional) The {String} detailed message to display.
|
||||
// * `buttons` (optional) Either an array of strings or an object where keys are
|
||||
// button names and the values are callbacks to invoke when clicked.
|
||||
// * `buttons` (optional) Either an {Array} of {String}s or an {Object} where keys are
|
||||
// button names and the values are callback {Function}s to invoke when clicked.
|
||||
// * `callback` (optional) A {Function} that will be called with the index of the chosen option.
|
||||
// If a callback is supplied, the dialog will be non-blocking. This argument is recommended.
|
||||
//
|
||||
// Returns the chosen button index {Number} if the buttons option is an array or the return value of the callback if the buttons option is an object.
|
||||
confirm (params = {}) {
|
||||
return this.applicationDelegate.confirm(params)
|
||||
// Returns the chosen button index {Number} if the buttons option is an array
|
||||
// or the return value of the callback if the buttons option is an object.
|
||||
// If a callback function is supplied, returns `undefined`.
|
||||
confirm (options = {}, callback) {
|
||||
if (callback) {
|
||||
// Async: no return value
|
||||
this.applicationDelegate.confirm(options, callback)
|
||||
} else {
|
||||
return this.applicationDelegate.confirm(options)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1071,7 +1105,7 @@ class AtomEnvironment {
|
||||
}
|
||||
}
|
||||
|
||||
attemptRestoreProjectStateForPaths (state, projectPaths, filesToOpen = []) {
|
||||
async attemptRestoreProjectStateForPaths (state, projectPaths, filesToOpen = []) {
|
||||
const center = this.workspace.getCenter()
|
||||
const windowIsUnused = () => {
|
||||
for (let container of this.workspace.getPaneContainers()) {
|
||||
@ -1090,30 +1124,38 @@ class AtomEnvironment {
|
||||
this.restoreStateIntoThisEnvironment(state)
|
||||
return Promise.all(filesToOpen.map(file => this.workspace.open(file)))
|
||||
} else {
|
||||
let resolveDiscardStatePromise = null
|
||||
const discardStatePromise = new Promise((resolve) => {
|
||||
resolveDiscardStatePromise = resolve
|
||||
})
|
||||
const nouns = projectPaths.length === 1 ? 'folder' : 'folders'
|
||||
const choice = this.confirm({
|
||||
this.confirm({
|
||||
message: 'Previous automatically-saved project state detected',
|
||||
detailedMessage: `There is previously saved state for the selected ${nouns}. ` +
|
||||
detail: `There is previously saved state for the selected ${nouns}. ` +
|
||||
`Would you like to add the ${nouns} to this window, permanently discarding the saved state, ` +
|
||||
`or open the ${nouns} in a new window, restoring the saved state?`,
|
||||
buttons: [
|
||||
'&Open in new window and recover state',
|
||||
'&Add to this window and discard state'
|
||||
]})
|
||||
if (choice === 0) {
|
||||
this.open({
|
||||
pathsToOpen: projectPaths.concat(filesToOpen),
|
||||
newWindow: true,
|
||||
devMode: this.inDevMode(),
|
||||
safeMode: this.inSafeMode()
|
||||
})
|
||||
return Promise.resolve(null)
|
||||
} else if (choice === 1) {
|
||||
for (let selectedPath of projectPaths) {
|
||||
this.project.addPath(selectedPath)
|
||||
]
|
||||
}, response => {
|
||||
if (response === 0) {
|
||||
this.open({
|
||||
pathsToOpen: projectPaths.concat(filesToOpen),
|
||||
newWindow: true,
|
||||
devMode: this.inDevMode(),
|
||||
safeMode: this.inSafeMode()
|
||||
})
|
||||
resolveDiscardStatePromise(Promise.resolve(null))
|
||||
} else if (response === 1) {
|
||||
for (let selectedPath of projectPaths) {
|
||||
this.project.addPath(selectedPath)
|
||||
}
|
||||
resolveDiscardStatePromise(Promise.all(filesToOpen.map(file => this.workspace.open(file))))
|
||||
}
|
||||
return Promise.all(filesToOpen.map(file => this.workspace.open(file)))
|
||||
}
|
||||
})
|
||||
|
||||
return discardStatePromise
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,8 +23,8 @@ class CommandInstaller {
|
||||
const showErrorDialog = (error) => {
|
||||
this.applicationDelegate.confirm({
|
||||
message: 'Failed to install shell commands',
|
||||
detailedMessage: error.message
|
||||
})
|
||||
detail: error.message
|
||||
}, () => {})
|
||||
}
|
||||
|
||||
this.installAtomCommand(true, error => {
|
||||
@ -33,8 +33,8 @@ class CommandInstaller {
|
||||
if (error) return showErrorDialog(error)
|
||||
this.applicationDelegate.confirm({
|
||||
message: 'Commands installed.',
|
||||
detailedMessage: 'The shell commands `atom` and `apm` are installed.'
|
||||
})
|
||||
detail: 'The shell commands `atom` and `apm` are installed.'
|
||||
}, () => {})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
94
src/pane.js
94
src/pane.js
@ -790,57 +790,53 @@ class Pane {
|
||||
}
|
||||
|
||||
promptToSaveItem (item, options = {}) {
|
||||
if (typeof item.shouldPromptToSave !== 'function' || !item.shouldPromptToSave(options)) {
|
||||
return Promise.resolve(true)
|
||||
}
|
||||
|
||||
let uri
|
||||
if (typeof item.getURI === 'function') {
|
||||
uri = item.getURI()
|
||||
} else if (typeof item.getUri === 'function') {
|
||||
uri = item.getUri()
|
||||
} else {
|
||||
return Promise.resolve(true)
|
||||
}
|
||||
|
||||
const title = (typeof item.getTitle === 'function' && item.getTitle()) || uri
|
||||
|
||||
const saveDialog = (saveButtonText, saveFn, message) => {
|
||||
const chosen = this.applicationDelegate.confirm({
|
||||
message,
|
||||
detailedMessage: 'Your changes will be lost if you close this item without saving.',
|
||||
buttons: [saveButtonText, 'Cancel', "&Don't Save"]}
|
||||
)
|
||||
|
||||
switch (chosen) {
|
||||
case 0:
|
||||
return new Promise(resolve => {
|
||||
return saveFn(item, error => {
|
||||
if (error instanceof SaveCancelledError) {
|
||||
resolve(false)
|
||||
} else if (error) {
|
||||
saveDialog(
|
||||
'Save as',
|
||||
this.saveItemAs,
|
||||
`'${title}' could not be saved.\nError: ${this.getMessageForErrorCode(error.code)}`
|
||||
).then(resolve)
|
||||
} else {
|
||||
resolve(true)
|
||||
}
|
||||
})
|
||||
})
|
||||
case 1:
|
||||
return Promise.resolve(false)
|
||||
case 2:
|
||||
return Promise.resolve(true)
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof item.shouldPromptToSave !== 'function' || !item.shouldPromptToSave(options)) {
|
||||
return resolve(true)
|
||||
}
|
||||
}
|
||||
|
||||
return saveDialog(
|
||||
'Save',
|
||||
this.saveItem,
|
||||
`'${title}' has changes, do you want to save them?`
|
||||
)
|
||||
let uri
|
||||
if (typeof item.getURI === 'function') {
|
||||
uri = item.getURI()
|
||||
} else if (typeof item.getUri === 'function') {
|
||||
uri = item.getUri()
|
||||
} else {
|
||||
return resolve(true)
|
||||
}
|
||||
|
||||
const title = (typeof item.getTitle === 'function' && item.getTitle()) || uri
|
||||
|
||||
const saveDialog = (saveButtonText, saveFn, message) => {
|
||||
this.applicationDelegate.confirm({
|
||||
message,
|
||||
detail: 'Your changes will be lost if you close this item without saving.',
|
||||
buttons: [saveButtonText, 'Cancel', "&Don't Save"]
|
||||
}, response => {
|
||||
switch (response) {
|
||||
case 0:
|
||||
return saveFn(item, error => {
|
||||
if (error instanceof SaveCancelledError) {
|
||||
resolve(false)
|
||||
} else if (error) {
|
||||
saveDialog(
|
||||
'Save as',
|
||||
this.saveItemAs,
|
||||
`'${title}' could not be saved.\nError: ${this.getMessageForErrorCode(error.code)}`
|
||||
)
|
||||
} else {
|
||||
resolve(true)
|
||||
}
|
||||
})
|
||||
case 1:
|
||||
return resolve(false)
|
||||
case 2:
|
||||
return resolve(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
saveDialog('Save', this.saveItem, `'${title}' has changes, do you want to save them?`)
|
||||
})
|
||||
}
|
||||
|
||||
// Public: Save the active item.
|
||||
|
@ -1160,16 +1160,17 @@ module.exports = class Workspace extends Model {
|
||||
// * `uri` A {String} containing a URI.
|
||||
//
|
||||
// Returns a {Promise} that resolves to the {TextEditor} (or other item) for the given URI.
|
||||
createItemForURI (uri, options) {
|
||||
async createItemForURI (uri, options) {
|
||||
if (uri != null) {
|
||||
for (let opener of this.getOpeners()) {
|
||||
for (const opener of this.getOpeners()) {
|
||||
const item = opener(uri, options)
|
||||
if (item != null) return Promise.resolve(item)
|
||||
if (item != null) return item
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return this.openTextFile(uri, options)
|
||||
const item = await this.openTextFile(uri, options)
|
||||
return item
|
||||
} catch (error) {
|
||||
switch (error.code) {
|
||||
case 'CANCELLED':
|
||||
@ -1199,7 +1200,7 @@ module.exports = class Workspace extends Model {
|
||||
}
|
||||
}
|
||||
|
||||
openTextFile (uri, options) {
|
||||
async openTextFile (uri, options) {
|
||||
const filePath = this.project.resolvePath(uri)
|
||||
|
||||
if (filePath != null) {
|
||||
@ -1214,23 +1215,38 @@ module.exports = class Workspace extends Model {
|
||||
}
|
||||
|
||||
const fileSize = fs.getSizeSync(filePath)
|
||||
if (fileSize >= (this.config.get('core.warnOnLargeFileLimit') * 1048576)) {
|
||||
const choice = this.applicationDelegate.confirm({
|
||||
|
||||
let [resolveConfirmFileOpenPromise, rejectConfirmFileOpenPromise] = []
|
||||
const confirmFileOpenPromise = new Promise((resolve, reject) => {
|
||||
resolveConfirmFileOpenPromise = resolve
|
||||
rejectConfirmFileOpenPromise = reject
|
||||
})
|
||||
|
||||
if (fileSize >= (this.config.get('core.warnOnLargeFileLimit') * 1048576)) { // 40MB by default
|
||||
this.applicationDelegate.confirm({
|
||||
message: 'Atom will be unresponsive during the loading of very large files.',
|
||||
detailedMessage: 'Do you still want to load this file?',
|
||||
detail: 'Do you still want to load this file?',
|
||||
buttons: ['Proceed', 'Cancel']
|
||||
}, response => {
|
||||
if (response === 1) {
|
||||
rejectConfirmFileOpenPromise()
|
||||
} else {
|
||||
resolveConfirmFileOpenPromise()
|
||||
}
|
||||
})
|
||||
if (choice === 1) {
|
||||
const error = new Error()
|
||||
error.code = 'CANCELLED'
|
||||
throw error
|
||||
}
|
||||
} else {
|
||||
resolveConfirmFileOpenPromise()
|
||||
}
|
||||
|
||||
return this.project.bufferForPath(filePath, options)
|
||||
.then(buffer => {
|
||||
return this.textEditorRegistry.build(Object.assign({buffer, autoHeight: false}, options))
|
||||
})
|
||||
try {
|
||||
await confirmFileOpenPromise
|
||||
const buffer = await this.project.bufferForPath(filePath, options)
|
||||
return this.textEditorRegistry.build(Object.assign({buffer, autoHeight: false}, options))
|
||||
} catch (e) {
|
||||
const error = new Error()
|
||||
error.code = 'CANCELLED'
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
handleGrammarUsed (grammar) {
|
||||
@ -1987,25 +2003,22 @@ module.exports = class Workspace extends Model {
|
||||
|
||||
checkoutHeadRevision (editor) {
|
||||
if (editor.getPath()) {
|
||||
const checkoutHead = () => {
|
||||
return this.project.repositoryForDirectory(new Directory(editor.getDirectoryPath()))
|
||||
.then(repository => repository && repository.checkoutHeadForEditor(editor))
|
||||
const checkoutHead = async () => {
|
||||
const repository = await this.project.repositoryForDirectory(new Directory(editor.getDirectoryPath()))
|
||||
if (repository) repository.checkoutHeadForEditor(editor)
|
||||
}
|
||||
|
||||
if (this.config.get('editor.confirmCheckoutHeadRevision')) {
|
||||
this.applicationDelegate.confirm({
|
||||
message: 'Confirm Checkout HEAD Revision',
|
||||
detailedMessage: `Are you sure you want to discard all changes to "${editor.getFileName()}" since the last Git commit?`,
|
||||
buttons: {
|
||||
OK: checkoutHead,
|
||||
Cancel: null
|
||||
}
|
||||
detail: `Are you sure you want to discard all changes to "${editor.getFileName()}" since the last Git commit?`,
|
||||
buttons: ['OK', 'Cancel']
|
||||
}, response => {
|
||||
if (response === 0) checkoutHead()
|
||||
})
|
||||
} else {
|
||||
return checkoutHead()
|
||||
checkoutHead()
|
||||
}
|
||||
} else {
|
||||
return Promise.resolve(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user