Merge branch 'master' of github.com:atom/atom into fb-pw-decaffeinate-config

This commit is contained in:
Philip Weiss
2018-01-22 09:57:57 -08:00
35 changed files with 344 additions and 338 deletions

View File

@@ -1,13 +1,12 @@
/** @babel */
import TextBuffer, {Point, Range} from 'text-buffer'
import {File, Directory} from 'pathwatcher'
import {Emitter, Disposable, CompositeDisposable} from 'event-kit'
import BufferedNodeProcess from '../src/buffered-node-process'
import BufferedProcess from '../src/buffered-process'
import GitRepository from '../src/git-repository'
import Notification from '../src/notification'
import {watchPath} from '../src/path-watcher'
const TextBuffer = require('text-buffer')
const {Point, Range} = TextBuffer
const {File, Directory} = require('pathwatcher')
const {Emitter, Disposable, CompositeDisposable} = require('event-kit')
const BufferedNodeProcess = require('../src/buffered-node-process')
const BufferedProcess = require('../src/buffered-process')
const GitRepository = require('../src/git-repository')
const Notification = require('../src/notification')
const {watchPath} = require('../src/path-watcher')
const atomExport = {
BufferedNodeProcess,
@@ -42,4 +41,4 @@ if (process.type === 'renderer') {
atomExport.TextEditor = require('../src/text-editor')
}
export default atomExport
module.exports = atomExport

View File

@@ -101,7 +101,7 @@
"autosave": "0.24.6",
"background-tips": "0.27.1",
"bookmarks": "0.45.1",
"bracket-matcher": "0.89.0",
"bracket-matcher": "0.89.1",
"command-palette": "0.43.0",
"dalek": "0.2.1",
"deprecation-cop": "0.56.9",

View File

@@ -16,9 +16,6 @@ module.exports = function () {
function getPathsToTranspile () {
let paths = []
paths = paths.concat(glob.sync(path.join(CONFIG.intermediateAppPath, 'benchmarks', '**', '*.js'), {nodir: true}))
paths = paths.concat(glob.sync(path.join(CONFIG.intermediateAppPath, 'exports', '**', '*.js'), {nodir: true}))
paths = paths.concat(glob.sync(path.join(CONFIG.intermediateAppPath, 'src', '**', '*.js'), {nodir: true}))
for (let packageName of Object.keys(CONFIG.appMetadata.packageDependencies)) {
paths = paths.concat(glob.sync(
path.join(CONFIG.intermediateAppPath, 'node_modules', packageName, '**', '*.js'),

View File

@@ -4,7 +4,6 @@ const fs = require('fs')
const path = require('path')
const temp = require('temp').track()
const AtomEnvironment = require('../src/atom-environment')
const StorageFolder = require('../src/storage-folder')
describe('AtomEnvironment', () => {
afterEach(() => {

View File

@@ -49,7 +49,7 @@ describe('AtomApplication', function () {
fs.writeFileSync(filePath, '1\n2\n3\n4\n')
const atomApplication = buildAtomApplication()
const window = atomApplication.launch(parseCommandLine([filePath + ':3']))
const [window] = await atomApplication.launch(parseCommandLine([filePath + ':3']))
await focusWindow(window)
const cursorRow = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => {
@@ -66,7 +66,7 @@ describe('AtomApplication', function () {
fs.writeFileSync(filePath, '1\n2\n3\n4\n')
const atomApplication = buildAtomApplication()
const window = atomApplication.launch(parseCommandLine([filePath + ':2:2']))
const [window] = await atomApplication.launch(parseCommandLine([filePath + ':2:2']))
await focusWindow(window)
const cursorPosition = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => {
@@ -83,7 +83,7 @@ describe('AtomApplication', function () {
fs.writeFileSync(filePath, '1\n2\n3\n4\n')
const atomApplication = buildAtomApplication()
const window = atomApplication.launch(parseCommandLine([filePath + ':: ']))
const [window] = await atomApplication.launch(parseCommandLine([filePath + ':: ']))
await focusWindow(window)
const openedPath = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => {
@@ -99,11 +99,11 @@ describe('AtomApplication', function () {
it('positions new windows at an offset distance from the previous window', async () => {
const atomApplication = buildAtomApplication()
const window1 = atomApplication.launch(parseCommandLine([makeTempDir()]))
const [window1] = await atomApplication.launch(parseCommandLine([makeTempDir()]))
await focusWindow(window1)
window1.browserWindow.setBounds({width: 400, height: 400, x: 0, y: 0})
const window2 = atomApplication.launch(parseCommandLine([makeTempDir()]))
const [window2] = await atomApplication.launch(parseCommandLine([makeTempDir()]))
await focusWindow(window2)
assert.notEqual(window1, window2)
@@ -122,7 +122,7 @@ describe('AtomApplication', function () {
fs.writeFileSync(existingDirCFilePath, 'this is an existing file')
const atomApplication = buildAtomApplication()
const window1 = atomApplication.launch(parseCommandLine([path.join(dirAPath, 'new-file')]))
const [window1] = await atomApplication.launch(parseCommandLine([path.join(dirAPath, 'new-file')]))
await emitterEventPromise(window1, 'window:locations-opened')
await focusWindow(window1)
@@ -135,7 +135,7 @@ describe('AtomApplication', function () {
// Reuses the window when opening *files*, even if they're in a different directory
// Does not change the project paths when doing so.
const reusedWindow = atomApplication.launch(parseCommandLine([existingDirCFilePath]))
const [reusedWindow] = await atomApplication.launch(parseCommandLine([existingDirCFilePath]))
assert.equal(reusedWindow, window1)
assert.deepEqual(atomApplication.getAllWindows(), [window1])
activeEditorPath = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
@@ -148,7 +148,7 @@ describe('AtomApplication', function () {
assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath])
// Opens new windows when opening directories
const window2 = atomApplication.launch(parseCommandLine([dirCPath]))
const [window2] = await atomApplication.launch(parseCommandLine([dirCPath]))
await emitterEventPromise(window2, 'window:locations-opened')
assert.notEqual(window2, window1)
await focusWindow(window2)
@@ -163,7 +163,7 @@ describe('AtomApplication', function () {
fs.writeFileSync(existingDirCFilePath, 'this is an existing file')
const atomApplication = buildAtomApplication()
const window1 = atomApplication.launch(parseCommandLine([path.join(dirAPath, 'new-file')]))
const [window1] = await atomApplication.launch(parseCommandLine([path.join(dirAPath, 'new-file')]))
await focusWindow(window1)
let activeEditorPath = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
@@ -175,7 +175,7 @@ describe('AtomApplication', function () {
// When opening *files* with --add, reuses an existing window and adds
// parent directory to the project
let reusedWindow = atomApplication.launch(parseCommandLine([existingDirCFilePath, '--add']))
let [reusedWindow] = await atomApplication.launch(parseCommandLine([existingDirCFilePath, '--add']))
assert.equal(reusedWindow, window1)
assert.deepEqual(atomApplication.getAllWindows(), [window1])
activeEditorPath = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
@@ -189,7 +189,7 @@ describe('AtomApplication', function () {
// When opening *directories* with add reuses an existing window and adds
// the directory to the project
reusedWindow = atomApplication.launch(parseCommandLine([dirBPath, '-a']))
reusedWindow = (await atomApplication.launch(parseCommandLine([dirBPath, '-a'])))[0]
assert.equal(reusedWindow, window1)
assert.deepEqual(atomApplication.getAllWindows(), [window1])
@@ -202,7 +202,7 @@ describe('AtomApplication', function () {
const atomApplication = buildAtomApplication()
const nonExistentFilePath = path.join(tempDirPath, 'new-file')
const window1 = atomApplication.launch(parseCommandLine([nonExistentFilePath]))
const [window1] = await atomApplication.launch(parseCommandLine([nonExistentFilePath]))
await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
atom.workspace.observeTextEditors(textEditor => {
textEditor.insertText('Hello World!')
@@ -214,7 +214,7 @@ describe('AtomApplication', function () {
await window1.closedPromise
// Restore unsaved state when opening the directory itself
const window2 = atomApplication.launch(parseCommandLine([tempDirPath]))
const [window2] = await atomApplication.launch(parseCommandLine([tempDirPath]))
await window2.loadedPromise
const window2Text = await evalInWebContents(window2.browserWindow.webContents, sendBackToMainProcess => {
const textEditor = atom.workspace.getActiveTextEditor()
@@ -228,7 +228,7 @@ describe('AtomApplication', function () {
await window2.closedPromise
// Restore unsaved state when opening a path to a non-existent file in the directory
const window3 = atomApplication.launch(parseCommandLine([path.join(tempDirPath, 'another-non-existent-file')]))
const [window3] = await atomApplication.launch(parseCommandLine([path.join(tempDirPath, 'another-non-existent-file')]))
await window3.loadedPromise
const window3Texts = await evalInWebContents(window3.browserWindow.webContents, (sendBackToMainProcess, nonExistentFilePath) => {
sendBackToMainProcess(atom.workspace.getTextEditors().map(editor => editor.getText()))
@@ -243,7 +243,7 @@ describe('AtomApplication', function () {
fs.mkdirSync(dirBSubdirPath)
const atomApplication = buildAtomApplication()
const window1 = atomApplication.launch(parseCommandLine([dirAPath, dirBPath]))
const [window1] = await atomApplication.launch(parseCommandLine([dirAPath, dirBPath]))
await focusWindow(window1)
assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath, dirBPath])
@@ -252,17 +252,17 @@ describe('AtomApplication', function () {
it('reuses windows with no project paths to open directories', async () => {
const tempDirPath = makeTempDir()
const atomApplication = buildAtomApplication()
const window1 = atomApplication.launch(parseCommandLine([]))
const [window1] = await atomApplication.launch(parseCommandLine([]))
await focusWindow(window1)
const reusedWindow = atomApplication.launch(parseCommandLine([tempDirPath]))
const [reusedWindow] = await atomApplication.launch(parseCommandLine([tempDirPath]))
assert.equal(reusedWindow, window1)
await conditionPromise(async () => (await getTreeViewRootDirectories(reusedWindow)).length > 0)
})
it('opens a new window with a single untitled buffer when launched with no path, even if windows already exist', async () => {
const atomApplication = buildAtomApplication()
const window1 = atomApplication.launch(parseCommandLine([]))
const [window1] = await atomApplication.launch(parseCommandLine([]))
await focusWindow(window1)
const window1EditorTitle = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
sendBackToMainProcess(atom.workspace.getActiveTextEditor().getTitle())
@@ -287,7 +287,7 @@ describe('AtomApplication', function () {
season.writeFileSync(configPath, config)
const atomApplication = buildAtomApplication()
const window1 = atomApplication.launch(parseCommandLine([]))
const [window1] = await atomApplication.launch(parseCommandLine([]))
await focusWindow(window1)
// wait a bit just to make sure we don't pass due to querying the render process before it loads
@@ -302,7 +302,7 @@ describe('AtomApplication', function () {
it('opens an empty text editor and loads its parent directory in the tree-view when launched with a new file path', async () => {
const atomApplication = buildAtomApplication()
const newFilePath = path.join(makeTempDir(), 'new-file')
const window = atomApplication.launch(parseCommandLine([newFilePath]))
const [window] = await atomApplication.launch(parseCommandLine([newFilePath]))
await focusWindow(window)
const {editorTitle, editorText} = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => {
atom.workspace.observeTextEditors(editor => {
@@ -324,7 +324,7 @@ describe('AtomApplication', function () {
atomApplication.config.set('core.disabledPackages', ['fuzzy-finder'])
const remotePath = 'remote://server:3437/some/directory/path'
let window = atomApplication.launch(parseCommandLine([remotePath]))
let [window] = await atomApplication.launch(parseCommandLine([remotePath]))
await focusWindow(window)
await conditionPromise(async () => (await getProjectDirectories()).length > 0)
@@ -350,9 +350,9 @@ describe('AtomApplication', function () {
const tempDirPath2 = makeTempDir()
const atomApplication1 = buildAtomApplication()
const app1Window1 = atomApplication1.launch(parseCommandLine([tempDirPath1]))
const [app1Window1] = await atomApplication1.launch(parseCommandLine([tempDirPath1]))
await emitterEventPromise(app1Window1, 'window:locations-opened')
const app1Window2 = atomApplication1.launch(parseCommandLine([tempDirPath2]))
const [app1Window2] = await atomApplication1.launch(parseCommandLine([tempDirPath2]))
await emitterEventPromise(app1Window2, 'window:locations-opened')
await Promise.all([
@@ -361,7 +361,7 @@ describe('AtomApplication', function () {
])
const atomApplication2 = buildAtomApplication()
const [app2Window1, app2Window2] = atomApplication2.launch(parseCommandLine([]))
const [app2Window1, app2Window2] = await atomApplication2.launch(parseCommandLine([]))
await Promise.all([
emitterEventPromise(app2Window1, 'window:locations-opened'),
emitterEventPromise(app2Window2, 'window:locations-opened')
@@ -373,9 +373,9 @@ describe('AtomApplication', function () {
it('does not reopen any previously opened windows when launched with no path and `core.restorePreviousWindowsOnStart` is no', async () => {
const atomApplication1 = buildAtomApplication()
const app1Window1 = atomApplication1.launch(parseCommandLine([makeTempDir()]))
const [app1Window1] = await atomApplication1.launch(parseCommandLine([makeTempDir()]))
await focusWindow(app1Window1)
const app1Window2 = atomApplication1.launch(parseCommandLine([makeTempDir()]))
const [app1Window2] = await atomApplication1.launch(parseCommandLine([makeTempDir()]))
await focusWindow(app1Window2)
const configPath = path.join(process.env.ATOM_HOME, 'config.cson')
@@ -385,7 +385,7 @@ describe('AtomApplication', function () {
season.writeFileSync(configPath, config)
const atomApplication2 = buildAtomApplication()
const app2Window = atomApplication2.launch(parseCommandLine([]))
const [app2Window] = await atomApplication2.launch(parseCommandLine([]))
await focusWindow(app2Window)
assert.deepEqual(app2Window.representedDirectoryPaths, [])
})
@@ -405,10 +405,10 @@ describe('AtomApplication', function () {
})
it('kills the specified pid after a newly-opened window is closed', async () => {
const window1 = atomApplication.launch(parseCommandLine(['--wait', '--pid', '101']))
const [window1] = await atomApplication.launch(parseCommandLine(['--wait', '--pid', '101']))
await focusWindow(window1)
const [window2] = atomApplication.launch(parseCommandLine(['--new-window', '--wait', '--pid', '102']))
const [window2] = await atomApplication.launch(parseCommandLine(['--new-window', '--wait', '--pid', '102']))
await focusWindow(window2)
assert.deepEqual(killedPids, [])
@@ -424,7 +424,7 @@ describe('AtomApplication', function () {
})
it('kills the specified pid after a newly-opened file in an existing window is closed', async () => {
const window = atomApplication.launch(parseCommandLine(['--wait', '--pid', '101']))
const [window] = await atomApplication.launch(parseCommandLine(['--wait', '--pid', '101']))
await focusWindow(window)
const filePath1 = temp.openSync('test').path
@@ -432,7 +432,7 @@ describe('AtomApplication', function () {
fs.writeFileSync(filePath1, 'File 1')
fs.writeFileSync(filePath2, 'File 2')
const reusedWindow = atomApplication.launch(parseCommandLine(['--wait', '--pid', '102', filePath1, filePath2]))
const [reusedWindow] = await atomApplication.launch(parseCommandLine(['--wait', '--pid', '102', filePath1, filePath2]))
assert.equal(reusedWindow, window)
const activeEditorPath = await evalInWebContents(window.browserWindow.webContents, send => {
@@ -467,11 +467,11 @@ describe('AtomApplication', function () {
})
it('kills the specified pid after a newly-opened directory in an existing window is closed', async () => {
const window = atomApplication.launch(parseCommandLine([]))
const [window] = await atomApplication.launch(parseCommandLine([]))
await focusWindow(window)
const dirPath1 = makeTempDir()
const reusedWindow = atomApplication.launch(parseCommandLine(['--wait', '--pid', '101', dirPath1]))
const [reusedWindow] = await atomApplication.launch(parseCommandLine(['--wait', '--pid', '101', dirPath1]))
assert.equal(reusedWindow, window)
assert.deepEqual(await getTreeViewRootDirectories(window), [dirPath1])
assert.deepEqual(killedPids, [])
@@ -498,7 +498,7 @@ describe('AtomApplication', function () {
if (process.platform === 'linux' || process.platform === 'win32') {
it('quits the application', async () => {
const atomApplication = buildAtomApplication()
const window = atomApplication.launch(parseCommandLine([path.join(makeTempDir("a"), 'file-a')]))
const [window] = await atomApplication.launch(parseCommandLine([path.join(makeTempDir("a"), 'file-a')]))
await focusWindow(window)
window.close()
await window.closedPromise
@@ -508,7 +508,7 @@ describe('AtomApplication', function () {
} else if (process.platform === 'darwin') {
it('leaves the application open', async () => {
const atomApplication = buildAtomApplication()
const window = atomApplication.launch(parseCommandLine([path.join(makeTempDir("a"), 'file-a')]))
const [window] = await atomApplication.launch(parseCommandLine([path.join(makeTempDir("a"), 'file-a')]))
await focusWindow(window)
window.close()
await window.closedPromise
@@ -524,7 +524,7 @@ describe('AtomApplication', function () {
const dirB = makeTempDir()
const atomApplication = buildAtomApplication()
const window = atomApplication.launch(parseCommandLine([dirA, dirB]))
const [window] = await atomApplication.launch(parseCommandLine([dirA, dirB]))
await emitterEventPromise(window, 'window:locations-opened')
await focusWindow(window)
assert.deepEqual(await getTreeViewRootDirectories(window), [dirA, dirB])
@@ -539,7 +539,7 @@ describe('AtomApplication', function () {
// Window state should be saved when the project folder is removed
const atomApplication2 = buildAtomApplication()
const [window2] = atomApplication2.launch(parseCommandLine([]))
const [window2] = await atomApplication2.launch(parseCommandLine([]))
await emitterEventPromise(window2, 'window:locations-opened')
await focusWindow(window2)
assert.deepEqual(await getTreeViewRootDirectories(window2), [dirB])
@@ -556,7 +556,7 @@ describe('AtomApplication', function () {
const atomApplication = buildAtomApplication()
const launchOptions = parseCommandLine([])
launchOptions.urlsToOpen = ['atom://package-with-url-main/test']
let windows = atomApplication.launch(launchOptions)
let [windows] = await atomApplication.launch(launchOptions)
await windows[0].loadedPromise
let reached = await evalInWebContents(windows[0].browserWindow.webContents, sendBackToMainProcess => {
@@ -571,9 +571,9 @@ describe('AtomApplication', function () {
const dirBPath = makeTempDir('b')
const atomApplication = buildAtomApplication()
const window1 = atomApplication.launch(parseCommandLine([path.join(dirAPath)]))
const [window1] = await atomApplication.launch(parseCommandLine([path.join(dirAPath)]))
await focusWindow(window1)
const window2 = atomApplication.launch(parseCommandLine([path.join(dirBPath)]))
const [window2] = await atomApplication.launch(parseCommandLine([path.join(dirBPath)]))
await focusWindow(window2)
const fileA = path.join(dirAPath, 'file-a')
@@ -597,9 +597,9 @@ describe('AtomApplication', function () {
const dirAPath = makeTempDir("a")
const dirBPath = makeTempDir("b")
const atomApplication = buildAtomApplication()
const window1 = atomApplication.launch(parseCommandLine([path.join(dirAPath, 'file-a')]))
const [window1] = await atomApplication.launch(parseCommandLine([path.join(dirAPath, 'file-a')]))
await focusWindow(window1)
const window2 = atomApplication.launch(parseCommandLine([path.join(dirBPath, 'file-b')]))
const [window2] = await atomApplication.launch(parseCommandLine([path.join(dirBPath, 'file-b')]))
await focusWindow(window2)
electron.app.quit()
await new Promise(process.nextTick)
@@ -612,8 +612,8 @@ describe('AtomApplication', function () {
it('prevents quitting if user cancels when prompted to save an item', async () => {
const atomApplication = buildAtomApplication()
const window1 = atomApplication.launch(parseCommandLine([]))
const window2 = atomApplication.launch(parseCommandLine([]))
const [window1] = await atomApplication.launch(parseCommandLine([]))
const [window2] = await atomApplication.launch(parseCommandLine([]))
await Promise.all([window1.loadedPromise, window2.loadedPromise])
await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
atom.workspace.getActiveTextEditor().insertText('unsaved text')

View File

@@ -1,21 +1,21 @@
/** @babel */
import {dialog} from 'electron'
import FileRecoveryService from '../../src/main-process/file-recovery-service'
import fs from 'fs-plus'
import sinon from 'sinon'
import {escapeRegExp} from 'underscore-plus'
const {dialog} = require('electron')
const FileRecoveryService = require('../../src/main-process/file-recovery-service')
const fs = require('fs-plus')
const sinon = require('sinon')
const {escapeRegExp} = require('underscore-plus')
const temp = require('temp').track()
describe("FileRecoveryService", () => {
let recoveryService, recoveryDirectory
let recoveryService, recoveryDirectory, spies
beforeEach(() => {
recoveryDirectory = temp.mkdirSync('atom-spec-file-recovery')
recoveryService = new FileRecoveryService(recoveryDirectory)
spies = sinon.sandbox.create()
})
afterEach(() => {
spies.restore()
try {
temp.cleanupSync()
} catch (e) {
@@ -24,38 +24,38 @@ describe("FileRecoveryService", () => {
})
describe("when no crash happens during a save", () => {
it("creates a recovery file and deletes it after saving", () => {
it("creates a recovery file and deletes it after saving", async () => {
const mockWindow = {}
const filePath = temp.path()
fs.writeFileSync(filePath, "some content")
recoveryService.willSavePath(mockWindow, filePath)
await recoveryService.willSavePath(mockWindow, filePath)
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
fs.writeFileSync(filePath, "changed")
recoveryService.didSavePath(mockWindow, filePath)
await recoveryService.didSavePath(mockWindow, filePath)
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
assert.equal(fs.readFileSync(filePath, 'utf8'), "changed")
fs.removeSync(filePath)
})
it("creates only one recovery file when many windows attempt to save the same file, deleting it when the last one finishes saving it", () => {
it("creates only one recovery file when many windows attempt to save the same file, deleting it when the last one finishes saving it", async () => {
const mockWindow = {}
const anotherMockWindow = {}
const filePath = temp.path()
fs.writeFileSync(filePath, "some content")
recoveryService.willSavePath(mockWindow, filePath)
recoveryService.willSavePath(anotherMockWindow, filePath)
await recoveryService.willSavePath(mockWindow, filePath)
await recoveryService.willSavePath(anotherMockWindow, filePath)
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
fs.writeFileSync(filePath, "changed")
recoveryService.didSavePath(mockWindow, filePath)
await recoveryService.didSavePath(mockWindow, filePath)
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
assert.equal(fs.readFileSync(filePath, 'utf8'), "changed")
recoveryService.didSavePath(anotherMockWindow, filePath)
await recoveryService.didSavePath(anotherMockWindow, filePath)
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
assert.equal(fs.readFileSync(filePath, 'utf8'), "changed")
@@ -64,66 +64,66 @@ describe("FileRecoveryService", () => {
})
describe("when a crash happens during a save", () => {
it("restores the created recovery file and deletes it", () => {
it("restores the created recovery file and deletes it", async () => {
const mockWindow = {}
const filePath = temp.path()
fs.writeFileSync(filePath, "some content")
recoveryService.willSavePath(mockWindow, filePath)
await recoveryService.willSavePath(mockWindow, filePath)
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
fs.writeFileSync(filePath, "changed")
recoveryService.didCrashWindow(mockWindow)
await recoveryService.didCrashWindow(mockWindow)
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
assert.equal(fs.readFileSync(filePath, 'utf8'), "some content")
fs.removeSync(filePath)
})
it("restores the created recovery file when many windows attempt to save the same file and one of them crashes", () => {
it("restores the created recovery file when many windows attempt to save the same file and one of them crashes", async () => {
const mockWindow = {}
const anotherMockWindow = {}
const filePath = temp.path()
fs.writeFileSync(filePath, "A")
recoveryService.willSavePath(mockWindow, filePath)
await recoveryService.willSavePath(mockWindow, filePath)
fs.writeFileSync(filePath, "B")
recoveryService.willSavePath(anotherMockWindow, filePath)
await recoveryService.willSavePath(anotherMockWindow, filePath)
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
fs.writeFileSync(filePath, "C")
recoveryService.didCrashWindow(mockWindow)
await recoveryService.didCrashWindow(mockWindow)
assert.equal(fs.readFileSync(filePath, 'utf8'), "A")
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
fs.writeFileSync(filePath, "D")
recoveryService.willSavePath(mockWindow, filePath)
await recoveryService.willSavePath(mockWindow, filePath)
fs.writeFileSync(filePath, "E")
recoveryService.willSavePath(anotherMockWindow, filePath)
await recoveryService.willSavePath(anotherMockWindow, filePath)
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
fs.writeFileSync(filePath, "F")
recoveryService.didCrashWindow(anotherMockWindow)
await recoveryService.didCrashWindow(anotherMockWindow)
assert.equal(fs.readFileSync(filePath, 'utf8'), "D")
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
fs.removeSync(filePath)
})
it("emits a warning when a file can't be recovered", sinon.test(function () {
it("emits a warning when a file can't be recovered", async () => {
const mockWindow = {}
const filePath = temp.path()
fs.writeFileSync(filePath, "content")
fs.chmodSync(filePath, 0444)
let logs = []
this.stub(console, 'log', (message) => logs.push(message))
this.stub(dialog, 'showMessageBox')
spies.stub(console, 'log', (message) => logs.push(message))
spies.stub(dialog, 'showMessageBox')
recoveryService.willSavePath(mockWindow, filePath)
recoveryService.didCrashWindow(mockWindow)
await recoveryService.willSavePath(mockWindow, filePath)
await recoveryService.didCrashWindow(mockWindow)
let recoveryFiles = fs.listTreeSync(recoveryDirectory)
assert.equal(recoveryFiles.length, 1)
assert.equal(logs.length, 1)
@@ -131,16 +131,16 @@ describe("FileRecoveryService", () => {
assert.match(logs[0], new RegExp(escapeRegExp(recoveryFiles[0])))
fs.removeSync(filePath)
}))
})
})
it("doesn't create a recovery file when the file that's being saved doesn't exist yet", () => {
it("doesn't create a recovery file when the file that's being saved doesn't exist yet", async () => {
const mockWindow = {}
recoveryService.willSavePath(mockWindow, "a-file-that-doesnt-exist")
await recoveryService.willSavePath(mockWindow, "a-file-that-doesnt-exist")
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
recoveryService.didSavePath(mockWindow, "a-file-that-doesnt-exist")
await recoveryService.didSavePath(mockWindow, "a-file-that-doesnt-exist")
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
})
})

View File

@@ -104,7 +104,7 @@ describe('TextEditorComponent', () => {
{
expect(editor.getApproximateLongestScreenRow()).toBe(3)
const expectedWidth = Math.round(
const expectedWidth = Math.ceil(
component.pixelPositionForScreenPosition(Point(3, Infinity)).left +
component.getBaseCharacterWidth()
)
@@ -121,7 +121,7 @@ describe('TextEditorComponent', () => {
// Capture the width of the lines before requesting the width of
// longest line, because making that request forces a DOM update
const actualWidth = element.querySelector('.lines').style.width
const expectedWidth = Math.round(
const expectedWidth = Math.ceil(
component.pixelPositionForScreenPosition(Point(6, Infinity)).left +
component.getBaseCharacterWidth()
)
@@ -3980,7 +3980,7 @@ describe('TextEditorComponent', () => {
// Capture the width of the lines before requesting the width of
// longest line, because making that request forces a DOM update
const actualWidth = element.querySelector('.lines').style.width
const expectedWidth = Math.round(
const expectedWidth = Math.ceil(
component.pixelPositionForScreenPosition(Point(3, Infinity)).left +
component.getBaseCharacterWidth()
)

View File

@@ -354,11 +354,11 @@ class ApplicationDelegate {
}
emitWillSavePath (path) {
return ipcRenderer.sendSync('will-save-path', path)
return ipcHelpers.call('will-save-path', path)
}
emitDidSavePath (path) {
return ipcRenderer.sendSync('did-save-path', path)
return ipcHelpers.call('did-save-path', path)
}
resolveProxy (requestId, url) {

View File

@@ -9,7 +9,6 @@ const fs = require('fs-plus')
const {mapSourcePosition} = require('@atom/source-map-support')
const WindowEventHandler = require('./window-event-handler')
const StateStore = require('./state-store')
const StorageFolder = require('./storage-folder')
const registerDefaultCommands = require('./register-default-commands')
const {updateProcessEnv} = require('./update-process-env')
const ConfigSchema = require('./config-schema')
@@ -208,12 +207,7 @@ class AtomEnvironment {
this.blobStore = params.blobStore
this.configDirPath = params.configDirPath
const {devMode, safeMode, resourcePath, clearWindowState} = this.getLoadSettings()
if (clearWindowState) {
this.getStorageFolder().clear()
this.stateStore.clear()
}
const {devMode, safeMode, resourcePath} = this.getLoadSettings()
ConfigSchema.projectHome = {
type: 'string',
@@ -764,7 +758,11 @@ class AtomEnvironment {
}
// Call this method when establishing a real application window.
startEditorWindow () {
async startEditorWindow () {
if (this.getLoadSettings().clearWindowState) {
await this.stateStore.clear()
}
this.unloaded = false
const updateProcessEnvPromise = this.updateProcessEnvAndTriggerHooks()
@@ -1264,11 +1262,6 @@ or use Pane::saveItemAs for programmatic saving.`)
}
}
getStorageFolder () {
if (!this.storageFolder) this.storageFolder = new StorageFolder(this.getConfigDirPath())
return this.storageFolder
}
getConfigDirPath () {
if (!this.configDirPath) this.configDirPath = process.env.ATOM_HOME
return this.configDirPath

View File

@@ -1,5 +1,3 @@
/** @babel */
const fs = require('fs-plus')
const path = require('path')

View File

@@ -1,8 +1,7 @@
'use babel'
const {Emitter, CompositeDisposable} = require('event-kit')
import {Emitter, CompositeDisposable} from 'event-kit'
export default class AutoUpdateManager {
module.exports =
class AutoUpdateManager {
constructor ({applicationDelegate}) {
this.applicationDelegate = applicationDelegate
this.subscriptions = new CompositeDisposable()

View File

@@ -1,6 +1,4 @@
/** @babel */
import BufferedProcess from './buffered-process'
const BufferedProcess = require('./buffered-process')
// Extended: Like {BufferedProcess}, but accepts a Node script as the command
// to run.
@@ -12,7 +10,8 @@ import BufferedProcess from './buffered-process'
// ```js
// const {BufferedNodeProcess} = require('atom')
// ```
export default class BufferedNodeProcess extends BufferedProcess {
module.exports =
class BufferedNodeProcess extends BufferedProcess {
// Public: Runs the given Node script by spawning a new child process.
//

View File

@@ -1,9 +1,7 @@
/** @babel */
import _ from 'underscore-plus'
import ChildProcess from 'child_process'
import {Emitter} from 'event-kit'
import path from 'path'
const _ = require('underscore-plus')
const ChildProcess = require('child_process')
const {Emitter} = require('event-kit')
const path = require('path')
// Extended: A wrapper which provides standard error/output line buffering for
// Node's ChildProcess.
@@ -19,7 +17,8 @@ import path from 'path'
// const exit = (code) => console.log("ps -ef exited with #{code}")
// const process = new BufferedProcess({command, args, stdout, exit})
// ```
export default class BufferedProcess {
module.exports =
class BufferedProcess {
/*
Section: Construction
*/

View File

@@ -1,7 +1,5 @@
/** @babel */
import crypto from 'crypto'
import clipboard from './safe-clipboard'
const crypto = require('crypto')
const clipboard = require('./safe-clipboard')
// Extended: Represents the clipboard used for copying and pasting in Atom.
//
@@ -14,7 +12,8 @@ import clipboard from './safe-clipboard'
//
// console.log(atom.clipboard.read()) # 'hello'
// ```
export default class Clipboard {
module.exports =
class Clipboard {
constructor () {
this.reset()
}

View File

@@ -1,10 +1,9 @@
/** @babel */
let ParsedColor = null
// Essential: A simple color class returned from {Config::get} when the value
// at the key path is of type 'color'.
export default class Color {
module.exports =
class Color {
// Essential: Parse a {String} or {Object} into a {Color}.
//
// * `value` A {String} such as `'white'`, `#ff00ff`, or

View File

@@ -1,6 +1,4 @@
/** @babel */
import {Disposable} from 'event-kit'
const {Disposable} = require('event-kit')
// Extended: Manages the deserializers used for serialized state
//
@@ -21,7 +19,8 @@ import {Disposable} from 'event-kit'
// serialize: ->
// @state
// ```
export default class DeserializerManager {
module.exports =
class DeserializerManager {
constructor (atomEnvironment) {
this.atomEnvironment = atomEnvironment
this.deserializers = {}

View File

@@ -1,13 +1,11 @@
/** @babel */
import {Emitter, CompositeDisposable} from 'event-kit'
const {Emitter, CompositeDisposable} = require('event-kit')
// Extended: History manager for remembering which projects have been opened.
//
// An instance of this class is always available as the `atom.history` global.
//
// The project history is used to enable the 'Reopen Project' menu.
export class HistoryManager {
class HistoryManager {
constructor ({project, commands, stateStore}) {
this.stateStore = stateStore
this.emitter = new Emitter()
@@ -116,7 +114,7 @@ function arrayEquivalent (a, b) {
return true
}
export class HistoryProject {
class HistoryProject {
constructor (paths, lastOpened) {
this.paths = paths
this.lastOpened = lastOpened || new Date()
@@ -128,3 +126,5 @@ export class HistoryProject {
set lastOpened (lastOpened) { this._lastOpened = lastOpened }
get lastOpened () { return this._lastOpened }
}
module.exports = {HistoryManager, HistoryProject}

View File

@@ -1,11 +1,9 @@
/** @babel */
const {remote} = require('electron')
const path = require('path')
const ipcHelpers = require('./ipc-helpers')
const util = require('util')
import {remote} from 'electron'
import path from 'path'
import ipcHelpers from './ipc-helpers'
import util from 'util'
export default async function () {
module.exports = async function () {
const getWindowLoadSettings = require('./get-window-load-settings')
const {test, headless, resourcePath, benchmarkPaths} = getWindowLoadSettings()
try {

View File

@@ -1,15 +1,13 @@
'use strict'
const Disposable = require('event-kit').Disposable
let ipcRenderer = null
let ipcMain = null
let BrowserWindow = null
let nextResponseChannelId = 0
exports.on = function (emitter, eventName, callback) {
emitter.on(eventName, callback)
return new Disposable(function () {
emitter.removeListener(eventName, callback)
})
return new Disposable(() => emitter.removeListener(eventName, callback))
}
exports.call = function (channel, ...args) {
@@ -18,34 +16,28 @@ exports.call = function (channel, ...args) {
ipcRenderer.setMaxListeners(20)
}
var responseChannel = getResponseChannel(channel)
const responseChannel = `ipc-helpers-response-${nextResponseChannelId++}`
return new Promise(function (resolve) {
ipcRenderer.on(responseChannel, function (event, result) {
return new Promise(resolve => {
ipcRenderer.on(responseChannel, (event, result) => {
ipcRenderer.removeAllListeners(responseChannel)
resolve(result)
})
ipcRenderer.send(channel, ...args)
ipcRenderer.send(channel, responseChannel, ...args)
})
}
exports.respondTo = function (channel, callback) {
if (!ipcMain) {
var electron = require('electron')
const electron = require('electron')
ipcMain = electron.ipcMain
BrowserWindow = electron.BrowserWindow
}
var responseChannel = getResponseChannel(channel)
return exports.on(ipcMain, channel, function (event, ...args) {
var browserWindow = BrowserWindow.fromWebContents(event.sender)
var result = callback(browserWindow, ...args)
return exports.on(ipcMain, channel, async (event, responseChannel, ...args) => {
const browserWindow = BrowserWindow.fromWebContents(event.sender)
const result = await callback(browserWindow, ...args)
event.sender.send(responseChannel, result)
})
}
function getResponseChannel (channel) {
return 'ipc-helpers-' + channel + '-response'
}

View File

@@ -169,18 +169,32 @@ class AtomApplication extends EventEmitter {
this.disposable.dispose()
}
launch (options) {
async launch (options) {
const optionsForWindowsToOpen = []
let shouldReopenPreviousWindows = false
if (options.test || options.benchmark || options.benchmarkTest) {
return this.openWithOptions(options)
optionsForWindowsToOpen.push(options)
} else if ((options.pathsToOpen && options.pathsToOpen.length > 0) ||
(options.urlsToOpen && options.urlsToOpen.length > 0)) {
if (this.config.get('core.restorePreviousWindowsOnStart') === 'always') {
this.loadState(_.deepClone(options))
}
return this.openWithOptions(options)
optionsForWindowsToOpen.push(options)
shouldReopenPreviousWindows = this.config.get('core.restorePreviousWindowsOnStart') === 'always'
} else {
return this.loadState(options) || this.openPath(options)
shouldReopenPreviousWindows = this.config.get('core.restorePreviousWindowsOnStart') !== 'no'
}
if (shouldReopenPreviousWindows) {
for (const previousOptions of await this.loadPreviousWindowOptions()) {
optionsForWindowsToOpen.push(Object.assign({}, options, previousOptions))
}
}
if (optionsForWindowsToOpen.length === 0) {
optionsForWindowsToOpen.push(options)
}
return optionsForWindowsToOpen.map(options => this.openWithOptions(options))
}
openWithOptions (options) {
@@ -271,7 +285,7 @@ class AtomApplication extends EventEmitter {
return
}
}
if (!window.isSpec) this.saveState(true)
if (!window.isSpec) this.saveCurrentWindowOptions(true)
}
// Public: Adds the {AtomWindow} to the global window list.
@@ -285,7 +299,7 @@ class AtomApplication extends EventEmitter {
if (!window.isSpec) {
const focusHandler = () => this.windowStack.touch(window)
const blurHandler = () => this.saveState(false)
const blurHandler = () => this.saveCurrentWindowOptions(false)
window.browserWindow.on('focus', focusHandler)
window.browserWindow.on('blur', blurHandler)
window.browserWindow.once('closed', () => {
@@ -569,18 +583,16 @@ class AtomApplication extends EventEmitter {
event.returnValue = this.autoUpdateManager.getErrorMessage()
}))
this.disposable.add(ipcHelpers.on(ipcMain, 'will-save-path', (event, path) => {
this.fileRecoveryService.willSavePath(this.atomWindowForEvent(event), path)
event.returnValue = true
}))
this.disposable.add(ipcHelpers.respondTo('will-save-path', (window, path) =>
this.fileRecoveryService.willSavePath(window, path)
))
this.disposable.add(ipcHelpers.on(ipcMain, 'did-save-path', (event, path) => {
this.fileRecoveryService.didSavePath(this.atomWindowForEvent(event), path)
event.returnValue = true
}))
this.disposable.add(ipcHelpers.respondTo('did-save-path', (window, path) =>
this.fileRecoveryService.didSavePath(window, path)
))
this.disposable.add(ipcHelpers.on(ipcMain, 'did-change-paths', () =>
this.saveState(false)
this.saveCurrentWindowOptions(false)
))
this.disposable.add(this.disableZoomOnDisplayChange())
@@ -911,7 +923,7 @@ class AtomApplication extends EventEmitter {
}
}
saveState (allowEmpty = false) {
async saveCurrentWindowOptions (allowEmpty = false) {
if (this.quitting) return
const states = []
@@ -921,28 +933,23 @@ class AtomApplication extends EventEmitter {
states.reverse()
if (states.length > 0 || allowEmpty) {
this.storageFolder.storeSync('application.json', states)
await this.storageFolder.store('application.json', states)
this.emit('application:did-save-state')
}
}
loadState (options) {
const states = this.storageFolder.load('application.json')
if (
['yes', 'always'].includes(this.config.get('core.restorePreviousWindowsOnStart')) &&
states && states.length > 0
) {
return states.map(state =>
this.openWithOptions(Object.assign(options, {
initialPaths: state.initialPaths,
pathsToOpen: state.initialPaths.filter(p => fs.isDirectorySync(p)),
urlsToOpen: [],
devMode: this.devMode,
safeMode: this.safeMode
}))
)
async loadPreviousWindowOptions () {
const states = await this.storageFolder.load('application.json')
if (states) {
return states.map(state => ({
initialPaths: state.initialPaths,
pathsToOpen: state.initialPaths.filter(p => fs.isDirectorySync(p)),
urlsToOpen: [],
devMode: this.devMode,
safeMode: this.safeMode
}))
} else {
return null
return []
}
}
@@ -1293,17 +1300,16 @@ class AtomApplication extends EventEmitter {
// File dialog defaults to project directory of currently active editor
if (path) openOptions.defaultPath = path
return dialog.showOpenDialog(parentWindow, openOptions, callback)
dialog.showOpenDialog(parentWindow, openOptions, callback)
}
promptForRestart () {
const chosen = dialog.showMessageBox(BrowserWindow.getFocusedWindow(), {
dialog.showMessageBox(BrowserWindow.getFocusedWindow(), {
type: 'warning',
title: 'Restart required',
message: 'You will need to restart Atom for this change to take effect.',
buttons: ['Restart Atom', 'Cancel']
})
if (chosen === 0) return this.restart()
}, response => { if (response === 0) this.restart() })
}
restart () {

View File

@@ -163,7 +163,7 @@ class AtomWindow extends EventEmitter {
if (!this.atomApplication.quitting && !this.unloading) {
event.preventDefault()
this.unloading = true
this.atomApplication.saveState(false)
this.atomApplication.saveCurrentWindowOptions(false)
if (await this.prepareToUnload()) this.close()
}
})
@@ -176,34 +176,34 @@ class AtomWindow extends EventEmitter {
this.browserWindow.on('unresponsive', () => {
if (this.isSpec) return
const chosen = dialog.showMessageBox(this.browserWindow, {
dialog.showMessageBox(this.browserWindow, {
type: 'warning',
buttons: ['Force Close', 'Keep Waiting'],
message: 'Editor is not responding',
detail:
'The editor is not responding. Would you like to force close it or just keep waiting?'
})
if (chosen === 0) this.browserWindow.destroy()
}, response => { if (response === 0) this.browserWindow.destroy() })
})
this.browserWindow.webContents.on('crashed', () => {
this.browserWindow.webContents.on('crashed', async () => {
if (this.headless) {
console.log('Renderer process crashed, exiting')
this.atomApplication.exit(100)
return
}
this.fileRecoveryService.didCrashWindow(this)
const chosen = dialog.showMessageBox(this.browserWindow, {
await this.fileRecoveryService.didCrashWindow(this)
dialog.showMessageBox(this.browserWindow, {
type: 'warning',
buttons: ['Close Window', 'Reload', 'Keep It Open'],
message: 'The editor has crashed',
detail: 'Please report this issue to https://github.com/atom/atom'
}, response => {
switch (response) {
case 0: return this.browserWindow.destroy()
case 1: return this.browserWindow.reload()
}
})
switch (chosen) {
case 0: return this.browserWindow.destroy()
case 1: return this.browserWindow.reload()
}
})
this.browserWindow.webContents.on('will-navigate', (event, url) => {
@@ -415,7 +415,7 @@ class AtomWindow extends EventEmitter {
this.representedDirectoryPaths.sort()
this.loadSettings.initialPaths = this.representedDirectoryPaths
this.browserWindow.loadSettingsJSON = JSON.stringify(this.loadSettings)
return this.atomApplication.saveState()
return this.atomApplication.saveCurrentWindowOptions()
}
didClosePathWithWaitSession (path) {

View File

@@ -118,24 +118,26 @@ class AutoUpdateManager
onUpdateNotAvailable: =>
autoUpdater.removeListener 'error', @onUpdateError
{dialog} = require 'electron'
dialog.showMessageBox
dialog.showMessageBox {
type: 'info'
buttons: ['OK']
icon: @iconPath
message: 'No update available.'
title: 'No Update Available'
detail: "Version #{@version} is the latest version."
}, -> # noop callback to get async behavior
onUpdateError: (event, message) =>
autoUpdater.removeListener 'update-not-available', @onUpdateNotAvailable
{dialog} = require 'electron'
dialog.showMessageBox
dialog.showMessageBox {
type: 'warning'
buttons: ['OK']
icon: @iconPath
message: 'There was an error checking for updates.'
title: 'Update Error'
detail: message
}, -> # noop callback to get async behavior
getWindows: ->
global.atomApplication.getAllWindows()

View File

@@ -1,11 +1,10 @@
'use babel'
const {dialog} = require('electron')
const crypto = require('crypto')
const Path = require('path')
const fs = require('fs-plus')
import {dialog} from 'electron'
import crypto from 'crypto'
import Path from 'path'
import fs from 'fs-plus'
export default class FileRecoveryService {
module.exports =
class FileRecoveryService {
constructor (recoveryDirectory) {
this.recoveryDirectory = recoveryDirectory
this.recoveryFilesByFilePath = new Map()
@@ -13,15 +12,16 @@ export default class FileRecoveryService {
this.windowsByRecoveryFile = new Map()
}
willSavePath (window, path) {
if (!fs.existsSync(path)) return
async willSavePath (window, path) {
const stats = await tryStatFile(path)
if (!stats) return
const recoveryPath = Path.join(this.recoveryDirectory, RecoveryFile.fileNameForPath(path))
const recoveryFile =
this.recoveryFilesByFilePath.get(path) || new RecoveryFile(path, recoveryPath)
this.recoveryFilesByFilePath.get(path) || new RecoveryFile(path, stats.mode, recoveryPath)
try {
recoveryFile.retain()
await recoveryFile.retain()
} catch (err) {
console.log(`Couldn't retain ${recoveryFile.recoveryPath}. Code: ${err.code}. Message: ${err.message}`)
return
@@ -39,11 +39,11 @@ export default class FileRecoveryService {
this.recoveryFilesByFilePath.set(path, recoveryFile)
}
didSavePath (window, path) {
async didSavePath (window, path) {
const recoveryFile = this.recoveryFilesByFilePath.get(path)
if (recoveryFile != null) {
try {
recoveryFile.release()
await recoveryFile.release()
} catch (err) {
console.log(`Couldn't release ${recoveryFile.recoveryPath}. Code: ${err.code}. Message: ${err.message}`)
}
@@ -53,27 +53,31 @@ export default class FileRecoveryService {
}
}
didCrashWindow (window) {
async didCrashWindow (window) {
if (!this.recoveryFilesByWindow.has(window)) return
const promises = []
for (const recoveryFile of this.recoveryFilesByWindow.get(window)) {
try {
recoveryFile.recoverSync()
} catch (error) {
const message = 'A file that Atom was saving could be corrupted'
const detail =
`Error ${error.code}. There was a crash while saving "${recoveryFile.originalPath}", so this file might be blank or corrupted.\n` +
`Atom couldn't recover it automatically, but a recovery file has been saved at: "${recoveryFile.recoveryPath}".`
console.log(detail)
dialog.showMessageBox(window.browserWindow, {type: 'info', buttons: ['OK'], message, detail})
} finally {
for (let window of this.windowsByRecoveryFile.get(recoveryFile)) {
this.recoveryFilesByWindow.get(window).delete(recoveryFile)
}
this.windowsByRecoveryFile.delete(recoveryFile)
this.recoveryFilesByFilePath.delete(recoveryFile.originalPath)
}
promises.push(recoveryFile.recover()
.catch(error => {
const message = 'A file that Atom was saving could be corrupted'
const detail =
`Error ${error.code}. There was a crash while saving "${recoveryFile.originalPath}", so this file might be blank or corrupted.\n` +
`Atom couldn't recover it automatically, but a recovery file has been saved at: "${recoveryFile.recoveryPath}".`
console.log(detail)
dialog.showMessageBox(window, {type: 'info', buttons: ['OK'], message, detail}, () => { /* noop callback to get async behavior */ })
})
.then(() => {
for (let window of this.windowsByRecoveryFile.get(recoveryFile)) {
this.recoveryFilesByWindow.get(window).delete(recoveryFile)
}
this.windowsByRecoveryFile.delete(recoveryFile)
this.recoveryFilesByFilePath.delete(recoveryFile.originalPath)
})
)
}
await Promise.all(promises)
}
didCloseWindow (window) {
@@ -94,36 +98,64 @@ class RecoveryFile {
return `${basename}-${randomSuffix}${extension}`
}
constructor (originalPath, recoveryPath) {
constructor (originalPath, fileMode, recoveryPath) {
this.originalPath = originalPath
this.fileMode = fileMode
this.recoveryPath = recoveryPath
this.refCount = 0
}
storeSync () {
fs.copyFileSync(this.originalPath, this.recoveryPath)
async store () {
await copyFile(this.originalPath, this.recoveryPath, this.fileMode)
}
recoverSync () {
fs.copyFileSync(this.recoveryPath, this.originalPath)
this.removeSync()
async recover () {
await copyFile(this.recoveryPath, this.originalPath, this.fileMode)
await this.remove()
}
removeSync () {
fs.unlinkSync(this.recoveryPath)
async remove () {
return new Promise((resolve, reject) =>
fs.unlink(this.recoveryPath, error =>
error && error.code !== 'ENOENT' ? reject(error) : resolve()
)
)
}
retain () {
if (this.isReleased()) this.storeSync()
async retain () {
if (this.isReleased()) await this.store()
this.refCount++
}
release () {
async release () {
this.refCount--
if (this.isReleased()) this.removeSync()
if (this.isReleased()) await this.remove()
}
isReleased () {
return this.refCount === 0
}
}
async function tryStatFile (path) {
return new Promise((resolve, reject) =>
fs.stat(path, (error, result) =>
resolve(error == null && result)
)
)
}
async function copyFile (source, destination, mode) {
return new Promise((resolve, reject) => {
const readStream = fs.createReadStream(source)
readStream
.on('error', reject)
.once('open', () => {
const writeStream = fs.createWriteStream(destination, {mode})
writeStream
.on('error', reject)
.on('open', () => readStream.pipe(writeStream))
.once('close', () => resolve())
})
})
}

View File

@@ -1,7 +1,5 @@
'use babel'
import Registry from 'winreg'
import Path from 'path'
const Registry = require('winreg')
const Path = require('path')
let exeName = Path.basename(process.execPath)
let appPath = `\"${process.execPath}\"`

View File

@@ -1,5 +1,3 @@
/** @babel */
const path = require('path')
// Private: re-join the segments split from an absolute path to form another absolute path.

View File

@@ -1,8 +1,6 @@
/** @babel */
const {Disposable} = require('event-kit')
import {Disposable} from 'event-kit'
export default {
module.exports = {
name: 'Null Grammar',
scopeName: 'text.plain.null-grammar',
scopeForId (id) {

View File

@@ -1,5 +1,3 @@
/** @babel */
const fs = require('fs')
const path = require('path')

View File

@@ -695,7 +695,7 @@ class Project extends Model {
}
subscribeToBuffer (buffer) {
buffer.onWillSave(({path}) => this.applicationDelegate.emitWillSavePath(path))
buffer.onWillSave(async ({path}) => this.applicationDelegate.emitWillSavePath(path))
buffer.onDidSave(({path}) => this.applicationDelegate.emitDidSavePath(path))
buffer.onDidDestroy(() => this.removeBuffer(buffer))
buffer.onDidChangePath(() => {

View File

@@ -1,8 +1,7 @@
/** @babel */
const SelectListView = require('atom-select-list')
import SelectListView from 'atom-select-list'
export default class ReopenProjectListView {
module.exports =
class ReopenProjectListView {
constructor (callback) {
this.callback = callback
this.selectListView = new SelectListView({

View File

@@ -1,9 +1,8 @@
/** @babel */
const {CompositeDisposable} = require('event-kit')
const path = require('path')
import {CompositeDisposable} from 'event-kit'
import path from 'path'
export default class ReopenProjectMenuManager {
module.exports =
class ReopenProjectMenuManager {
constructor ({menu, commands, history, config, open}) {
this.menuManager = menu
this.historyManager = history

View File

@@ -1,39 +0,0 @@
path = require "path"
fs = require "fs-plus"
module.exports =
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?
fs.writeFileSync(@pathForKey(name), JSON.stringify(object), 'utf8')
load: (name) ->
return unless @path?
statePath = @pathForKey(name)
try
stateString = fs.readFileSync(statePath, 'utf8')
catch error
unless error.code is 'ENOENT'
console.warn "Error reading state file: #{statePath}", error.stack, error
return undefined
try
JSON.parse(stateString)
catch error
console.warn "Error parsing state file: #{statePath}", error.stack, error
pathForKey: (name) -> path.join(@getPath(), name)
getPath: -> @path

49
src/storage-folder.js Normal file
View File

@@ -0,0 +1,49 @@
const path = require('path')
const fs = require('fs-plus')
module.exports =
class StorageFolder {
constructor (containingPath) {
if (containingPath) {
this.path = path.join(containingPath, 'storage')
}
}
store (name, object) {
return new Promise((resolve, reject) => {
if (!this.path) return resolve()
fs.writeFile(this.pathForKey(name), JSON.stringify(object), 'utf8', error =>
error ? reject(error) : resolve()
)
})
}
load (name) {
return new Promise(resolve => {
if (!this.path) return resolve(null)
const statePath = this.pathForKey(name)
fs.readFile(statePath, 'utf8', (error, stateString) => {
if (error && error.code !== 'ENOENT') {
console.warn(`Error reading state file: ${statePath}`, error.stack, error)
}
if (!stateString) return resolve(null)
try {
resolve(JSON.parse(stateString))
} catch (error) {
console.warn(`Error parsing state file: ${statePath}`, error.stack, error)
resolve(null)
}
})
})
}
pathForKey (name) {
return path.join(this.getPath(), name)
}
getPath () {
return this.path
}
}

View File

@@ -2694,7 +2694,7 @@ class TextEditorComponent {
}
getContentWidth () {
return Math.round(this.getLongestLineWidth() + this.getBaseCharacterWidth())
return Math.ceil(this.getLongestLineWidth() + this.getBaseCharacterWidth())
}
getScrollContainerClientWidthInBaseCharacters () {

View File

@@ -1,7 +1,5 @@
/** @babel */
import fs from 'fs'
import childProcess from 'child_process'
const fs = require('fs')
const childProcess = require('child_process')
const ENVIRONMENT_VARIABLES_TO_PRESERVE = new Set([
'NODE_ENV',
@@ -120,4 +118,4 @@ async function getEnvFromShell (env) {
return result
}
export default { updateProcessEnv, shouldGetEnvFromShell }
module.exports = {updateProcessEnv, shouldGetEnvFromShell}

View File

@@ -1,5 +1,3 @@
'use babel'
const _ = require('underscore-plus')
const url = require('url')
const path = require('path')