mirror of
https://github.com/atom/atom.git
synced 2026-01-24 14:28:14 -05:00
Merge pull request #18608 from atom/aw/single-file
When only a file is specified, don't open and index the parent directory
This commit is contained in:
@@ -639,7 +639,6 @@ describe('AtomEnvironment', () => {
|
||||
|
||||
describe('::openLocations(locations) (called via IPC from browser process)', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(atom.workspace, 'open')
|
||||
atom.project.setPaths([])
|
||||
})
|
||||
|
||||
@@ -649,48 +648,50 @@ describe('AtomEnvironment', () => {
|
||||
})
|
||||
|
||||
describe('when the opened path exists', () => {
|
||||
it("adds it to the project's paths", async () => {
|
||||
it('opens a file', async () => {
|
||||
const pathToOpen = __filename
|
||||
await atom.openLocations([{pathToOpen}])
|
||||
expect(atom.project.getPaths()[0]).toBe(__dirname)
|
||||
expect(atom.project.getPaths()).toEqual([])
|
||||
})
|
||||
|
||||
describe('then a second path is opened with forceAddToWindow', () => {
|
||||
it("adds the second path to the project's paths", async () => {
|
||||
const firstPathToOpen = __dirname
|
||||
const secondPathToOpen = path.resolve(__dirname, './fixtures')
|
||||
await atom.openLocations([{pathToOpen: firstPathToOpen}])
|
||||
await atom.openLocations([{pathToOpen: secondPathToOpen, forceAddToWindow: true}])
|
||||
expect(atom.project.getPaths()).toEqual([firstPathToOpen, secondPathToOpen])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the opened path does not exist but its parent directory does', () => {
|
||||
it('adds the parent directory to the project paths', async () => {
|
||||
const pathToOpen = path.join(__dirname, 'this-path-does-not-exist.txt')
|
||||
await atom.openLocations([{pathToOpen}])
|
||||
expect(atom.project.getPaths()[0]).toBe(__dirname)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the opened path is a file', () => {
|
||||
it('opens it in the workspace', async () => {
|
||||
const pathToOpen = __filename
|
||||
await atom.openLocations([{pathToOpen}])
|
||||
expect(atom.workspace.open.mostRecentCall.args[0]).toBe(__filename)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the opened path is a directory', () => {
|
||||
it('does not open it in the workspace', async () => {
|
||||
it('opens a directory as a project folder', async () => {
|
||||
const pathToOpen = __dirname
|
||||
await atom.openLocations([{pathToOpen}])
|
||||
expect(atom.workspace.open.callCount).toBe(0)
|
||||
expect(atom.workspace.getTextEditors().map(e => e.getPath())).toEqual([])
|
||||
expect(atom.project.getPaths()).toEqual([pathToOpen])
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the opened path is a uri', () => {
|
||||
describe('when the opened path does not exist', () => {
|
||||
it('opens it as a new file', async () => {
|
||||
const pathToOpen = path.join(__dirname, 'this-path-does-not-exist.txt')
|
||||
await atom.openLocations([{pathToOpen}])
|
||||
expect(atom.workspace.getTextEditors().map(e => e.getPath())).toEqual([pathToOpen])
|
||||
expect(atom.project.getPaths()).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the opened path is handled by a registered directory provider', () => {
|
||||
let serviceDisposable
|
||||
|
||||
beforeEach(() => {
|
||||
serviceDisposable = atom.packages.serviceHub.provide('atom.directory-provider', '0.1.0', {
|
||||
directoryForURISync (uri) {
|
||||
if (uri.startsWith('remote://')) {
|
||||
return { getPath() { return uri } }
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
waitsFor(() => atom.project.directoryProviders.length > 0)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
serviceDisposable.dispose()
|
||||
})
|
||||
|
||||
it("adds it to the project's paths as is", async () => {
|
||||
const pathToOpen = 'remote://server:7644/some/dir/path'
|
||||
spyOn(atom.project, 'addPath')
|
||||
@@ -741,7 +742,7 @@ describe('AtomEnvironment', () => {
|
||||
const fileToOpen = path.join(pathToOpen, 'michelle-is-awesome.txt')
|
||||
await atom.openLocations([{pathToOpen}, {pathToOpen: fileToOpen}])
|
||||
expect(atom.attemptRestoreProjectStateForPaths).not.toHaveBeenCalledWith(state, [pathToOpen], [fileToOpen])
|
||||
expect(atom.project.getPaths()).toEqual([__dirname])
|
||||
expect(atom.project.getPaths()).toEqual([__dirname, pathToOpen])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -23,10 +23,14 @@ describe "Smoke Test", ->
|
||||
|
||||
it "can open a file in Atom and perform basic operations on it", ->
|
||||
tempDirPath = temp.mkdirSync("empty-dir")
|
||||
runAtom [path.join(tempDirPath, "new-file")], {ATOM_HOME: atomHome}, (client) ->
|
||||
filePath = path.join(tempDirPath, "new-file")
|
||||
|
||||
fs.writeFileSync filePath, "", {encoding: "utf8"}
|
||||
|
||||
runAtom [filePath], {ATOM_HOME: atomHome}, (client) ->
|
||||
client
|
||||
.treeViewRootDirectories()
|
||||
.then ({value}) -> expect(value).toEqual([tempDirPath])
|
||||
.then ({value}) -> expect(value).toEqual([])
|
||||
.waitForExist("atom-text-editor", 5000)
|
||||
.then (exists) -> expect(exists).toBe true
|
||||
.waitForPaneItemCount(1, 1000)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* globals assert */
|
||||
|
||||
const temp = require('temp').track()
|
||||
const season = require('season')
|
||||
const dedent = require('dedent')
|
||||
@@ -44,55 +46,226 @@ describe('AtomApplication', function () {
|
||||
})
|
||||
|
||||
describe('launch', () => {
|
||||
it('can open to a specific line number of a file', async () => {
|
||||
const filePath = path.join(makeTempDir(), 'new-file')
|
||||
fs.writeFileSync(filePath, '1\n2\n3\n4\n')
|
||||
const atomApplication = buildAtomApplication()
|
||||
describe('with no paths', () => {
|
||||
it('reopens any previously opened windows', async () => {
|
||||
if (process.platform === 'win32') return // Test is too flakey on Windows
|
||||
|
||||
const [window] = await atomApplication.launch(parseCommandLine([filePath + ':3']))
|
||||
await focusWindow(window)
|
||||
const tempDirPath1 = makeTempDir()
|
||||
const tempDirPath2 = makeTempDir()
|
||||
|
||||
const cursorRow = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(textEditor => {
|
||||
sendBackToMainProcess(textEditor.getCursorBufferPosition().row)
|
||||
})
|
||||
const atomApplication1 = buildAtomApplication()
|
||||
const [app1Window1] = await atomApplication1.launch(parseCommandLine([tempDirPath1]))
|
||||
await emitterEventPromise(app1Window1, 'window:locations-opened')
|
||||
|
||||
const [app1Window2] = await atomApplication1.launch(parseCommandLine([tempDirPath2]))
|
||||
await emitterEventPromise(app1Window2, 'window:locations-opened')
|
||||
|
||||
await Promise.all([
|
||||
app1Window1.prepareToUnload(),
|
||||
app1Window2.prepareToUnload()
|
||||
])
|
||||
|
||||
const atomApplication2 = buildAtomApplication()
|
||||
const [app2Window1, app2Window2] = await atomApplication2.launch(parseCommandLine([]))
|
||||
await Promise.all([
|
||||
emitterEventPromise(app2Window1, 'window:locations-opened'),
|
||||
emitterEventPromise(app2Window2, 'window:locations-opened')
|
||||
])
|
||||
|
||||
assert.deepEqual(await getTreeViewRootDirectories(app2Window1), [tempDirPath1])
|
||||
assert.deepEqual(await getTreeViewRootDirectories(app2Window2), [tempDirPath2])
|
||||
})
|
||||
|
||||
assert.equal(cursorRow, 2)
|
||||
it('when windows already exist, opens a new window with a single untitled buffer', async () => {
|
||||
const atomApplication = buildAtomApplication()
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([]))
|
||||
await focusWindow(window1)
|
||||
const window1EditorTitle = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
sendBackToMainProcess(atom.workspace.getActiveTextEditor().getTitle())
|
||||
})
|
||||
assert.equal(window1EditorTitle, 'untitled')
|
||||
|
||||
const window2 = atomApplication.openWithOptions(parseCommandLine([]))
|
||||
await window2.loadedPromise
|
||||
const window2EditorTitle = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
sendBackToMainProcess(atom.workspace.getActiveTextEditor().getTitle())
|
||||
})
|
||||
assert.equal(window2EditorTitle, 'untitled')
|
||||
|
||||
assert.deepEqual(atomApplication.getAllWindows(), [window2, window1])
|
||||
})
|
||||
|
||||
it('when no windows are open but --new-window is passed, opens a new window with a single untitled buffer', async () => {
|
||||
// Populate some saved state
|
||||
const tempDirPath1 = makeTempDir()
|
||||
const tempDirPath2 = makeTempDir()
|
||||
|
||||
const atomApplication1 = buildAtomApplication()
|
||||
const [app1Window1] = await atomApplication1.launch(parseCommandLine([tempDirPath1]))
|
||||
await emitterEventPromise(app1Window1, 'window:locations-opened')
|
||||
|
||||
const [app1Window2] = await atomApplication1.launch(parseCommandLine([tempDirPath2]))
|
||||
await emitterEventPromise(app1Window2, 'window:locations-opened')
|
||||
|
||||
await Promise.all([
|
||||
app1Window1.prepareToUnload(),
|
||||
app1Window2.prepareToUnload()
|
||||
])
|
||||
|
||||
// Launch with --new-window
|
||||
const atomApplication2 = buildAtomApplication()
|
||||
const appWindows2 = await atomApplication2.launch(parseCommandLine(['--new-window']))
|
||||
assert.lengthOf(appWindows2, 1)
|
||||
const [appWindow2] = appWindows2
|
||||
await appWindow2.loadedPromise
|
||||
const window2EditorTitle = await evalInWebContents(appWindow2.browserWindow.webContents, sendBackToMainProcess => {
|
||||
sendBackToMainProcess(atom.workspace.getActiveTextEditor().getTitle())
|
||||
})
|
||||
assert.equal(window2EditorTitle, 'untitled')
|
||||
})
|
||||
|
||||
it('does not open an empty editor if core.openEmptyEditorOnStart is false', async () => {
|
||||
const configPath = path.join(process.env.ATOM_HOME, 'config.cson')
|
||||
const config = season.readFileSync(configPath)
|
||||
if (!config['*'].core) config['*'].core = {}
|
||||
config['*'].core.openEmptyEditorOnStart = false
|
||||
season.writeFileSync(configPath, config)
|
||||
|
||||
const atomApplication = buildAtomApplication()
|
||||
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
|
||||
await timeoutPromise(1000)
|
||||
|
||||
const itemCount = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
sendBackToMainProcess(atom.workspace.getActivePane().getItems().length)
|
||||
})
|
||||
assert.equal(itemCount, 0)
|
||||
})
|
||||
})
|
||||
|
||||
it('can open to a specific line and column of a file', async () => {
|
||||
const filePath = path.join(makeTempDir(), 'new-file')
|
||||
fs.writeFileSync(filePath, '1\n2\n3\n4\n')
|
||||
const atomApplication = buildAtomApplication()
|
||||
describe('with file or folder paths', () => {
|
||||
it('shows all directories in the tree view when multiple directory paths are passed to Atom', async () => {
|
||||
const dirAPath = makeTempDir('a')
|
||||
const dirBPath = makeTempDir('b')
|
||||
const dirBSubdirPath = path.join(dirBPath, 'c')
|
||||
fs.mkdirSync(dirBSubdirPath)
|
||||
|
||||
const [window] = await atomApplication.launch(parseCommandLine([filePath + ':2:2']))
|
||||
await focusWindow(window)
|
||||
const atomApplication = buildAtomApplication()
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([dirAPath, dirBPath]))
|
||||
await focusWindow(window1)
|
||||
|
||||
const cursorPosition = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(textEditor => {
|
||||
sendBackToMainProcess(textEditor.getCursorBufferPosition())
|
||||
})
|
||||
await conditionPromise(async () => (await getTreeViewRootDirectories(window1)).length === 2)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath, dirBPath])
|
||||
})
|
||||
|
||||
assert.deepEqual(cursorPosition, {row: 1, column: 1})
|
||||
it('can open to a specific line number of a file', async () => {
|
||||
const filePath = path.join(makeTempDir(), 'new-file')
|
||||
fs.writeFileSync(filePath, '1\n2\n3\n4\n')
|
||||
const atomApplication = buildAtomApplication()
|
||||
|
||||
const [window] = await atomApplication.launch(parseCommandLine([filePath + ':3']))
|
||||
await focusWindow(window)
|
||||
|
||||
const cursorRow = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(textEditor => {
|
||||
sendBackToMainProcess(textEditor.getCursorBufferPosition().row)
|
||||
})
|
||||
})
|
||||
|
||||
assert.equal(cursorRow, 2)
|
||||
})
|
||||
|
||||
it('can open to a specific line and column of a file', async () => {
|
||||
const filePath = path.join(makeTempDir(), 'new-file')
|
||||
fs.writeFileSync(filePath, '1\n2\n3\n4\n')
|
||||
const atomApplication = buildAtomApplication()
|
||||
|
||||
const [window] = await atomApplication.launch(parseCommandLine([filePath + ':2:2']))
|
||||
await focusWindow(window)
|
||||
|
||||
const cursorPosition = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(textEditor => {
|
||||
sendBackToMainProcess(textEditor.getCursorBufferPosition())
|
||||
})
|
||||
})
|
||||
|
||||
assert.deepEqual(cursorPosition, {row: 1, column: 1})
|
||||
})
|
||||
|
||||
it('removes all trailing whitespace and colons from the specified path', async () => {
|
||||
let filePath = path.join(makeTempDir(), 'new-file')
|
||||
fs.writeFileSync(filePath, '1\n2\n3\n4\n')
|
||||
const atomApplication = buildAtomApplication()
|
||||
|
||||
const [window] = await atomApplication.launch(parseCommandLine([filePath + ':: ']))
|
||||
await focusWindow(window)
|
||||
|
||||
const openedPath = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(textEditor => {
|
||||
sendBackToMainProcess(textEditor.getPath())
|
||||
})
|
||||
})
|
||||
|
||||
assert.equal(openedPath, filePath)
|
||||
})
|
||||
|
||||
it('opens an empty text editor when launched with a new file path', async () => {
|
||||
// Choosing "Don't save"
|
||||
mockElectronShowMessageBox({response: 2})
|
||||
|
||||
const atomApplication = buildAtomApplication()
|
||||
const newFilePath = path.join(makeTempDir(), 'new-file')
|
||||
const [window] = await atomApplication.launch(parseCommandLine([newFilePath]))
|
||||
await focusWindow(window)
|
||||
const {editorTitle, editorText} = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(editor => {
|
||||
sendBackToMainProcess({editorTitle: editor.getTitle(), editorText: editor.getText()})
|
||||
})
|
||||
})
|
||||
assert.equal(editorTitle, path.basename(newFilePath))
|
||||
assert.equal(editorText, '')
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window), [])
|
||||
})
|
||||
})
|
||||
|
||||
it('removes all trailing whitespace and colons from the specified path', async () => {
|
||||
let filePath = path.join(makeTempDir(), 'new-file')
|
||||
fs.writeFileSync(filePath, '1\n2\n3\n4\n')
|
||||
const atomApplication = buildAtomApplication()
|
||||
describe('when the --add option is specified', () => {
|
||||
it('adds folders to existing windows when the --add option is used', async () => {
|
||||
const dirAPath = makeTempDir('a')
|
||||
const dirBPath = makeTempDir('b')
|
||||
const dirCPath = makeTempDir('c')
|
||||
const existingDirCFilePath = path.join(dirCPath, 'existing-file')
|
||||
fs.writeFileSync(existingDirCFilePath, 'this is an existing file')
|
||||
|
||||
const [window] = await atomApplication.launch(parseCommandLine([filePath + ':: ']))
|
||||
await focusWindow(window)
|
||||
const atomApplication = buildAtomApplication()
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([dirAPath]))
|
||||
await focusWindow(window1)
|
||||
|
||||
const openedPath = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(textEditor => {
|
||||
sendBackToMainProcess(textEditor.getPath())
|
||||
await conditionPromise(async () => (await getTreeViewRootDirectories(window1)).length === 1)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath])
|
||||
|
||||
// When opening *files* with --add, reuses an existing window
|
||||
let [reusedWindow] = await atomApplication.launch(parseCommandLine([existingDirCFilePath, '--add']))
|
||||
assert.equal(reusedWindow, window1)
|
||||
assert.deepEqual(atomApplication.getAllWindows(), [window1])
|
||||
let activeEditorPath = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
const subscription = atom.workspace.onDidChangeActivePaneItem(textEditor => {
|
||||
sendBackToMainProcess(textEditor.getPath())
|
||||
subscription.dispose()
|
||||
})
|
||||
})
|
||||
})
|
||||
assert.equal(activeEditorPath, existingDirCFilePath)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath])
|
||||
|
||||
assert.equal(openedPath, filePath)
|
||||
// When opening *directories* with --add, reuses an existing window and adds the directory to the project
|
||||
reusedWindow = (await atomApplication.launch(parseCommandLine([dirBPath, '-a'])))[0]
|
||||
assert.equal(reusedWindow, window1)
|
||||
assert.deepEqual(atomApplication.getAllWindows(), [window1])
|
||||
|
||||
await conditionPromise(async () => (await getTreeViewRootDirectories(reusedWindow)).length === 2)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath, dirBPath])
|
||||
})
|
||||
})
|
||||
|
||||
if (process.platform === 'darwin' || process.platform === 'win32') {
|
||||
@@ -114,95 +287,15 @@ describe('AtomApplication', function () {
|
||||
})
|
||||
}
|
||||
|
||||
it('reuses existing windows when opening paths, but not directories', async () => {
|
||||
const dirAPath = makeTempDir("a")
|
||||
const dirBPath = makeTempDir("b")
|
||||
const dirCPath = makeTempDir("c")
|
||||
const existingDirCFilePath = path.join(dirCPath, 'existing-file')
|
||||
fs.writeFileSync(existingDirCFilePath, 'this is an existing file')
|
||||
|
||||
const atomApplication = buildAtomApplication()
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([path.join(dirAPath, 'new-file')]))
|
||||
await emitterEventPromise(window1, 'window:locations-opened')
|
||||
await focusWindow(window1)
|
||||
|
||||
let activeEditorPath = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(textEditor => {
|
||||
sendBackToMainProcess(textEditor.getPath())
|
||||
})
|
||||
})
|
||||
assert.equal(activeEditorPath, path.join(dirAPath, 'new-file'))
|
||||
|
||||
// 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] = await atomApplication.launch(parseCommandLine([existingDirCFilePath]))
|
||||
assert.equal(reusedWindow, window1)
|
||||
assert.deepEqual(atomApplication.getAllWindows(), [window1])
|
||||
activeEditorPath = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
const subscription = atom.workspace.onDidChangeActivePaneItem(textEditor => {
|
||||
sendBackToMainProcess(textEditor.getPath())
|
||||
subscription.dispose()
|
||||
})
|
||||
})
|
||||
assert.equal(activeEditorPath, existingDirCFilePath)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath])
|
||||
|
||||
// Opens new windows when opening directories
|
||||
const [window2] = await atomApplication.launch(parseCommandLine([dirCPath]))
|
||||
await emitterEventPromise(window2, 'window:locations-opened')
|
||||
assert.notEqual(window2, window1)
|
||||
await focusWindow(window2)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window2), [dirCPath])
|
||||
})
|
||||
|
||||
it('adds folders to existing windows when the --add option is used', async () => {
|
||||
const dirAPath = makeTempDir("a")
|
||||
const dirBPath = makeTempDir("b")
|
||||
const dirCPath = makeTempDir("c")
|
||||
const existingDirCFilePath = path.join(dirCPath, 'existing-file')
|
||||
fs.writeFileSync(existingDirCFilePath, 'this is an existing file')
|
||||
|
||||
const atomApplication = buildAtomApplication()
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([path.join(dirAPath, 'new-file')]))
|
||||
await focusWindow(window1)
|
||||
|
||||
let activeEditorPath = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(textEditor => {
|
||||
sendBackToMainProcess(textEditor.getPath())
|
||||
})
|
||||
})
|
||||
assert.equal(activeEditorPath, path.join(dirAPath, 'new-file'))
|
||||
|
||||
// When opening *files* with --add, reuses an existing window and adds
|
||||
// parent directory to the project
|
||||
let [reusedWindow] = await atomApplication.launch(parseCommandLine([existingDirCFilePath, '--add']))
|
||||
assert.equal(reusedWindow, window1)
|
||||
assert.deepEqual(atomApplication.getAllWindows(), [window1])
|
||||
activeEditorPath = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
const subscription = atom.workspace.onDidChangeActivePaneItem(textEditor => {
|
||||
sendBackToMainProcess(textEditor.getPath())
|
||||
subscription.dispose()
|
||||
})
|
||||
})
|
||||
assert.equal(activeEditorPath, existingDirCFilePath)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath, dirCPath])
|
||||
|
||||
// When opening *directories* with add reuses an existing window and adds
|
||||
// the directory to the project
|
||||
reusedWindow = (await atomApplication.launch(parseCommandLine([dirBPath, '-a'])))[0]
|
||||
assert.equal(reusedWindow, window1)
|
||||
assert.deepEqual(atomApplication.getAllWindows(), [window1])
|
||||
|
||||
await conditionPromise(async () => (await getTreeViewRootDirectories(reusedWindow)).length === 3)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath, dirCPath, dirBPath])
|
||||
})
|
||||
|
||||
it('persists window state based on the project directories', async () => {
|
||||
// Choosing "Don't save"
|
||||
mockElectronShowMessageBox({response: 2})
|
||||
|
||||
const tempDirPath = makeTempDir()
|
||||
const atomApplication = buildAtomApplication()
|
||||
const nonExistentFilePath = path.join(tempDirPath, 'new-file')
|
||||
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([nonExistentFilePath]))
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([tempDirPath, nonExistentFilePath]))
|
||||
await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(textEditor => {
|
||||
textEditor.insertText('Hello World!')
|
||||
@@ -213,7 +306,7 @@ describe('AtomApplication', function () {
|
||||
window1.close()
|
||||
await window1.closedPromise
|
||||
|
||||
// Restore unsaved state when opening the directory itself
|
||||
// Restore unsaved state when opening the same project directory
|
||||
const [window2] = await atomApplication.launch(parseCommandLine([tempDirPath]))
|
||||
await window2.loadedPromise
|
||||
const window2Text = await evalInWebContents(window2.browserWindow.webContents, sendBackToMainProcess => {
|
||||
@@ -223,95 +316,6 @@ describe('AtomApplication', function () {
|
||||
sendBackToMainProcess(textEditor.getText())
|
||||
})
|
||||
assert.equal(window2Text, 'Hello World! How are you?')
|
||||
await window2.prepareToUnload()
|
||||
window2.close()
|
||||
await window2.closedPromise
|
||||
|
||||
// Restore unsaved state when opening a path to a non-existent file in the directory
|
||||
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()))
|
||||
})
|
||||
assert.include(window3Texts, 'Hello World! How are you?')
|
||||
})
|
||||
|
||||
it('shows all directories in the tree view when multiple directory paths are passed to Atom', async () => {
|
||||
const dirAPath = makeTempDir("a")
|
||||
const dirBPath = makeTempDir("b")
|
||||
const dirBSubdirPath = path.join(dirBPath, 'c')
|
||||
fs.mkdirSync(dirBSubdirPath)
|
||||
|
||||
const atomApplication = buildAtomApplication()
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([dirAPath, dirBPath]))
|
||||
await focusWindow(window1)
|
||||
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath, dirBPath])
|
||||
})
|
||||
|
||||
it('reuses windows with no project paths to open directories', async () => {
|
||||
const tempDirPath = makeTempDir()
|
||||
const atomApplication = buildAtomApplication()
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([]))
|
||||
await focusWindow(window1)
|
||||
|
||||
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] = await atomApplication.launch(parseCommandLine([]))
|
||||
await focusWindow(window1)
|
||||
const window1EditorTitle = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
sendBackToMainProcess(atom.workspace.getActiveTextEditor().getTitle())
|
||||
})
|
||||
assert.equal(window1EditorTitle, 'untitled')
|
||||
|
||||
const window2 = atomApplication.openWithOptions(parseCommandLine([]))
|
||||
await focusWindow(window2)
|
||||
const window2EditorTitle = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
sendBackToMainProcess(atom.workspace.getActiveTextEditor().getTitle())
|
||||
})
|
||||
assert.equal(window2EditorTitle, 'untitled')
|
||||
|
||||
assert.deepEqual(atomApplication.getAllWindows(), [window2, window1])
|
||||
})
|
||||
|
||||
it('does not open an empty editor when opened with no path if the core.openEmptyEditorOnStart config setting is false', async () => {
|
||||
const configPath = path.join(process.env.ATOM_HOME, 'config.cson')
|
||||
const config = season.readFileSync(configPath)
|
||||
if (!config['*'].core) config['*'].core = {}
|
||||
config['*'].core.openEmptyEditorOnStart = false
|
||||
season.writeFileSync(configPath, config)
|
||||
|
||||
const atomApplication = buildAtomApplication()
|
||||
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
|
||||
await timeoutPromise(1000)
|
||||
|
||||
const itemCount = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => {
|
||||
sendBackToMainProcess(atom.workspace.getActivePane().getItems().length)
|
||||
})
|
||||
assert.equal(itemCount, 0)
|
||||
})
|
||||
|
||||
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] = await atomApplication.launch(parseCommandLine([newFilePath]))
|
||||
await focusWindow(window)
|
||||
const {editorTitle, editorText} = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => {
|
||||
atom.workspace.observeTextEditors(editor => {
|
||||
sendBackToMainProcess({editorTitle: editor.getTitle(), editorText: editor.getText()})
|
||||
})
|
||||
})
|
||||
assert.equal(editorTitle, path.basename(newFilePath))
|
||||
assert.equal(editorText, '')
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window), [path.dirname(newFilePath)])
|
||||
})
|
||||
|
||||
it('adds a remote directory to the project when launched with a remote directory', async () => {
|
||||
@@ -343,38 +347,11 @@ describe('AtomApplication', function () {
|
||||
}
|
||||
})
|
||||
|
||||
it('reopens any previously opened windows when launched with no path', async () => {
|
||||
if (process.platform === 'win32') return; // Test is too flakey on Windows
|
||||
|
||||
const tempDirPath1 = makeTempDir()
|
||||
const tempDirPath2 = makeTempDir()
|
||||
|
||||
const atomApplication1 = buildAtomApplication()
|
||||
const [app1Window1] = await atomApplication1.launch(parseCommandLine([tempDirPath1]))
|
||||
await emitterEventPromise(app1Window1, 'window:locations-opened')
|
||||
const [app1Window2] = await atomApplication1.launch(parseCommandLine([tempDirPath2]))
|
||||
await emitterEventPromise(app1Window2, 'window:locations-opened')
|
||||
|
||||
await Promise.all([
|
||||
app1Window1.prepareToUnload(),
|
||||
app1Window2.prepareToUnload()
|
||||
])
|
||||
|
||||
const atomApplication2 = buildAtomApplication()
|
||||
const [app2Window1, app2Window2] = await atomApplication2.launch(parseCommandLine([]))
|
||||
await Promise.all([
|
||||
emitterEventPromise(app2Window1, 'window:locations-opened'),
|
||||
emitterEventPromise(app2Window2, 'window:locations-opened')
|
||||
])
|
||||
|
||||
assert.deepEqual(await getTreeViewRootDirectories(app2Window1), [tempDirPath1])
|
||||
assert.deepEqual(await getTreeViewRootDirectories(app2Window2), [tempDirPath2])
|
||||
})
|
||||
|
||||
it('does not reopen any previously opened windows when launched with no path and `core.restorePreviousWindowsOnStart` is no', async () => {
|
||||
const atomApplication1 = buildAtomApplication()
|
||||
const [app1Window1] = await atomApplication1.launch(parseCommandLine([makeTempDir()]))
|
||||
await focusWindow(app1Window1)
|
||||
|
||||
const [app1Window2] = await atomApplication1.launch(parseCommandLine([makeTempDir()]))
|
||||
await focusWindow(app1Window2)
|
||||
|
||||
@@ -424,15 +401,16 @@ describe('AtomApplication', function () {
|
||||
})
|
||||
|
||||
it('kills the specified pid after a newly-opened file in an existing window is closed', async () => {
|
||||
const [window] = await atomApplication.launch(parseCommandLine(['--wait', '--pid', '101']))
|
||||
await focusWindow(window)
|
||||
|
||||
const filePath1 = temp.openSync('test').path
|
||||
const filePath2 = temp.openSync('test').path
|
||||
const projectDir = makeTempDir('existing')
|
||||
const filePath1 = path.join(projectDir, 'file-1')
|
||||
const filePath2 = path.join(projectDir, 'file-2')
|
||||
fs.writeFileSync(filePath1, 'File 1')
|
||||
fs.writeFileSync(filePath2, 'File 2')
|
||||
|
||||
const [reusedWindow] = await atomApplication.launch(parseCommandLine(['--wait', '--pid', '102', filePath1, filePath2]))
|
||||
const [window] = await atomApplication.launch(parseCommandLine(['--wait', '--pid', '101', projectDir]))
|
||||
await focusWindow(window)
|
||||
|
||||
const [reusedWindow] = await atomApplication.launch(parseCommandLine(['--add', '--wait', '--pid', '102', filePath1, filePath2]))
|
||||
assert.equal(reusedWindow, window)
|
||||
|
||||
const activeEditorPath = await evalInWebContents(window.browserWindow.webContents, send => {
|
||||
@@ -471,8 +449,9 @@ describe('AtomApplication', function () {
|
||||
await focusWindow(window)
|
||||
|
||||
const dirPath1 = makeTempDir()
|
||||
const [reusedWindow] = await atomApplication.launch(parseCommandLine(['--wait', '--pid', '101', dirPath1]))
|
||||
const [reusedWindow] = await atomApplication.launch(parseCommandLine(['--add', '--wait', '--pid', '101', dirPath1]))
|
||||
assert.equal(reusedWindow, window)
|
||||
await conditionPromise(async () => (await getTreeViewRootDirectories(window)).length === 1)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window), [dirPath1])
|
||||
assert.deepEqual(killedPids, [])
|
||||
|
||||
@@ -498,7 +477,7 @@ describe('AtomApplication', function () {
|
||||
if (process.platform === 'linux' || process.platform === 'win32') {
|
||||
it('quits the application', async () => {
|
||||
const atomApplication = buildAtomApplication()
|
||||
const [window] = await 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 +487,7 @@ describe('AtomApplication', function () {
|
||||
} else if (process.platform === 'darwin') {
|
||||
it('leaves the application open', async () => {
|
||||
const atomApplication = buildAtomApplication()
|
||||
const [window] = await 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,24 +503,24 @@ describe('AtomApplication', function () {
|
||||
const dirB = makeTempDir()
|
||||
|
||||
const atomApplication = buildAtomApplication()
|
||||
const [window] = await atomApplication.launch(parseCommandLine([dirA, dirB]))
|
||||
await emitterEventPromise(window, 'window:locations-opened')
|
||||
await focusWindow(window)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window), [dirA, dirB])
|
||||
const [window0] = await atomApplication.launch(parseCommandLine([dirA, dirB]))
|
||||
await focusWindow(window0)
|
||||
await conditionPromise(async () => (await getTreeViewRootDirectories(window0)).length === 2)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window0), [dirA, dirB])
|
||||
|
||||
const saveStatePromise = emitterEventPromise(atomApplication, 'application:did-save-state')
|
||||
await evalInWebContents(window.browserWindow.webContents, (sendBackToMainProcess) => {
|
||||
await evalInWebContents(window0.browserWindow.webContents, (sendBackToMainProcess) => {
|
||||
atom.project.removePath(atom.project.getPaths()[0])
|
||||
sendBackToMainProcess(null)
|
||||
})
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window), [dirB])
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window0), [dirB])
|
||||
await saveStatePromise
|
||||
|
||||
// Window state should be saved when the project folder is removed
|
||||
const atomApplication2 = buildAtomApplication()
|
||||
const [window2] = await atomApplication2.launch(parseCommandLine([]))
|
||||
await emitterEventPromise(window2, 'window:locations-opened')
|
||||
await focusWindow(window2)
|
||||
await conditionPromise(async () => (await getTreeViewRootDirectories(window2)).length === 1)
|
||||
assert.deepEqual(await getTreeViewRootDirectories(window2), [dirB])
|
||||
})
|
||||
})
|
||||
@@ -562,11 +541,11 @@ describe('AtomApplication', function () {
|
||||
let reached = await evalInWebContents(windows[0].browserWindow.webContents, sendBackToMainProcess => {
|
||||
sendBackToMainProcess(global.reachedUrlMain)
|
||||
})
|
||||
assert.equal(reached, true);
|
||||
windows[0].close();
|
||||
assert.isTrue(reached)
|
||||
windows[0].close()
|
||||
})
|
||||
|
||||
it('triggers /core/open/file in the correct window', async function() {
|
||||
it('triggers /core/open/file in the correct window', async function () {
|
||||
const dirAPath = makeTempDir('a')
|
||||
const dirBPath = makeTempDir('b')
|
||||
|
||||
@@ -594,12 +573,12 @@ describe('AtomApplication', function () {
|
||||
})
|
||||
|
||||
it('waits until all the windows have saved their state before quitting', async () => {
|
||||
const dirAPath = makeTempDir("a")
|
||||
const dirBPath = makeTempDir("b")
|
||||
const dirAPath = makeTempDir('a')
|
||||
const dirBPath = makeTempDir('b')
|
||||
const atomApplication = buildAtomApplication()
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([path.join(dirAPath, 'file-a')]))
|
||||
const [window1] = await atomApplication.launch(parseCommandLine([dirAPath]))
|
||||
await focusWindow(window1)
|
||||
const [window2] = await atomApplication.launch(parseCommandLine([path.join(dirBPath, 'file-b')]))
|
||||
const [window2] = await atomApplication.launch(parseCommandLine([dirBPath]))
|
||||
await focusWindow(window2)
|
||||
electron.app.quit()
|
||||
await new Promise(process.nextTick)
|
||||
@@ -662,7 +641,7 @@ describe('AtomApplication', function () {
|
||||
function buildAtomApplication (params = {}) {
|
||||
const atomApplication = new AtomApplication(Object.assign({
|
||||
resourcePath: ATOM_RESOURCE_PATH,
|
||||
atomHomeDirPath: process.env.ATOM_HOME,
|
||||
atomHomeDirPath: process.env.ATOM_HOME
|
||||
}, params))
|
||||
atomApplicationsToDestroy.push(atomApplication)
|
||||
return atomApplication
|
||||
@@ -680,7 +659,7 @@ describe('AtomApplication', function () {
|
||||
electron.app.quit = function () {
|
||||
this.quit.callCount++
|
||||
let defaultPrevented = false
|
||||
this.emit('before-quit', {preventDefault() { defaultPrevented = true }})
|
||||
this.emit('before-quit', {preventDefault () { defaultPrevented = true }})
|
||||
if (!defaultPrevented) didQuit = true
|
||||
}
|
||||
|
||||
@@ -710,12 +689,15 @@ describe('AtomApplication', function () {
|
||||
resolve(result)
|
||||
}
|
||||
|
||||
webContents.executeJavaScript(dedent`
|
||||
const js = dedent`
|
||||
function sendBackToMainProcess (result) {
|
||||
require('electron').ipcRenderer.send('${channelId}', result)
|
||||
}
|
||||
(${source})(sendBackToMainProcess, ${args.map(JSON.stringify).join(', ')})
|
||||
`)
|
||||
`
|
||||
// console.log(`about to execute:\n${js}`)
|
||||
|
||||
webContents.executeJavaScript(js)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -728,6 +710,8 @@ describe('AtomApplication', function () {
|
||||
.from(treeView.element.querySelectorAll('.project-root > .header .name'))
|
||||
.map(element => element.dataset.path)
|
||||
)
|
||||
} else {
|
||||
sendBackToMainProcess([])
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const crypto = require('crypto')
|
||||
const path = require('path')
|
||||
const util = require('util')
|
||||
const {ipcRenderer} = require('electron')
|
||||
|
||||
const _ = require('underscore-plus')
|
||||
@@ -44,6 +45,8 @@ const TextBuffer = require('text-buffer')
|
||||
const TextEditorRegistry = require('./text-editor-registry')
|
||||
const AutoUpdateManager = require('./auto-update-manager')
|
||||
|
||||
const stat = util.promisify(fs.stat)
|
||||
|
||||
let nextId = 0
|
||||
|
||||
// Essential: Atom global for dealing with packages, themes, menus, and the window.
|
||||
@@ -1359,42 +1362,56 @@ or use Pane::saveItemAs for programmatic saving.`)
|
||||
|
||||
async openLocations (locations) {
|
||||
const needsProjectPaths = this.project && this.project.getPaths().length === 0
|
||||
const foldersToAddToProject = []
|
||||
const foldersToAddToProject = new Set()
|
||||
const fileLocationsToOpen = []
|
||||
|
||||
function pushFolderToOpen (folder) {
|
||||
if (!foldersToAddToProject.includes(folder)) {
|
||||
foldersToAddToProject.push(folder)
|
||||
}
|
||||
}
|
||||
// Asynchronously fetch stat information about each requested path to open.
|
||||
const locationStats = await Promise.all(
|
||||
locations.map(async location => {
|
||||
const stats = location.pathToOpen ? await stat(location.pathToOpen).catch(() => null) : null
|
||||
return {location, stats}
|
||||
}),
|
||||
)
|
||||
|
||||
for (const location of locations) {
|
||||
for (const {location, stats} of locationStats) {
|
||||
const {pathToOpen} = location
|
||||
if (pathToOpen && (needsProjectPaths || location.forceAddToWindow)) {
|
||||
if (fs.existsSync(pathToOpen)) {
|
||||
pushFolderToOpen(this.project.getDirectoryForProjectPath(pathToOpen).getPath())
|
||||
} else if (fs.existsSync(path.dirname(pathToOpen))) {
|
||||
pushFolderToOpen(this.project.getDirectoryForProjectPath(path.dirname(pathToOpen)).getPath())
|
||||
} else {
|
||||
pushFolderToOpen(this.project.getDirectoryForProjectPath(pathToOpen).getPath())
|
||||
}
|
||||
if (!pathToOpen) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (!fs.isDirectorySync(pathToOpen)) {
|
||||
fileLocationsToOpen.push(location)
|
||||
if (stats !== null) {
|
||||
// Path exists
|
||||
if (stats.isDirectory()) {
|
||||
// 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)
|
||||
}
|
||||
} else {
|
||||
// Path does not exist
|
||||
// Attempt to interpret as a URI from a non-default directory provider
|
||||
const directory = this.project.getProvidedDirectoryForProjectPath(pathToOpen)
|
||||
if (directory) {
|
||||
// Found: add as a project folder
|
||||
foldersToAddToProject.add(directory.getPath())
|
||||
} else {
|
||||
// Not found: open as a new file
|
||||
fileLocationsToOpen.push(location)
|
||||
}
|
||||
}
|
||||
|
||||
if (location.hasWaitSession) this.pathsWithWaitSessions.add(pathToOpen)
|
||||
}
|
||||
|
||||
let restoredState = false
|
||||
if (foldersToAddToProject.length > 0) {
|
||||
const state = await this.loadState(this.getStateKey(foldersToAddToProject))
|
||||
if (foldersToAddToProject.size > 0) {
|
||||
const state = await this.loadState(this.getStateKey(Array.from(foldersToAddToProject)))
|
||||
|
||||
// only restore state if this is the first path added to the project
|
||||
if (state && needsProjectPaths) {
|
||||
const files = fileLocationsToOpen.map((location) => location.pathToOpen)
|
||||
await this.attemptRestoreProjectStateForPaths(state, foldersToAddToProject, files)
|
||||
await this.attemptRestoreProjectStateForPaths(state, Array.from(foldersToAddToProject), files)
|
||||
restoredState = true
|
||||
} else {
|
||||
for (let folder of foldersToAddToProject) {
|
||||
|
||||
@@ -187,6 +187,8 @@ class AtomApplication extends EventEmitter {
|
||||
(options.urlsToOpen && options.urlsToOpen.length > 0)) {
|
||||
optionsForWindowsToOpen.push(options)
|
||||
shouldReopenPreviousWindows = this.config.get('core.restorePreviousWindowsOnStart') === 'always'
|
||||
} else if (options.newWindow) {
|
||||
shouldReopenPreviousWindows = false
|
||||
} else {
|
||||
shouldReopenPreviousWindows = this.config.get('core.restorePreviousWindowsOnStart') !== 'no'
|
||||
}
|
||||
@@ -206,7 +208,6 @@ class AtomApplication extends EventEmitter {
|
||||
|
||||
openWithOptions (options) {
|
||||
const {
|
||||
initialPaths,
|
||||
pathsToOpen,
|
||||
executedFrom,
|
||||
urlsToOpen,
|
||||
@@ -216,7 +217,6 @@ class AtomApplication extends EventEmitter {
|
||||
pidToKillWhenClosed,
|
||||
devMode,
|
||||
safeMode,
|
||||
newWindow,
|
||||
logFile,
|
||||
profileStartup,
|
||||
timeout,
|
||||
@@ -250,11 +250,9 @@ class AtomApplication extends EventEmitter {
|
||||
})
|
||||
} else if (pathsToOpen.length > 0) {
|
||||
return this.openPaths({
|
||||
initialPaths,
|
||||
pathsToOpen,
|
||||
executedFrom,
|
||||
pidToKillWhenClosed,
|
||||
newWindow,
|
||||
devMode,
|
||||
safeMode,
|
||||
profileStartup,
|
||||
@@ -267,9 +265,7 @@ class AtomApplication extends EventEmitter {
|
||||
} else {
|
||||
// Always open a editor window if this is the first instance of Atom.
|
||||
return this.openPath({
|
||||
initialPaths,
|
||||
pidToKillWhenClosed,
|
||||
newWindow,
|
||||
devMode,
|
||||
safeMode,
|
||||
profileStartup,
|
||||
@@ -777,17 +773,14 @@ class AtomApplication extends EventEmitter {
|
||||
// options -
|
||||
// :pathToOpen - The file path to open
|
||||
// :pidToKillWhenClosed - The integer of the pid to kill
|
||||
// :newWindow - Boolean of whether this should be opened in a new window.
|
||||
// :devMode - Boolean to control the opened window's dev mode.
|
||||
// :safeMode - Boolean to control the opened window's safe mode.
|
||||
// :profileStartup - Boolean to control creating a profile of the startup time.
|
||||
// :window - {AtomWindow} to open file paths in.
|
||||
// :addToLastWindow - Boolean of whether this should be opened in last focused window.
|
||||
openPath ({
|
||||
initialPaths,
|
||||
pathToOpen,
|
||||
pidToKillWhenClosed,
|
||||
newWindow,
|
||||
devMode,
|
||||
safeMode,
|
||||
profileStartup,
|
||||
@@ -797,10 +790,8 @@ class AtomApplication extends EventEmitter {
|
||||
env
|
||||
} = {}) {
|
||||
return this.openPaths({
|
||||
initialPaths,
|
||||
pathsToOpen: [pathToOpen],
|
||||
pidToKillWhenClosed,
|
||||
newWindow,
|
||||
devMode,
|
||||
safeMode,
|
||||
profileStartup,
|
||||
@@ -816,18 +807,15 @@ class AtomApplication extends EventEmitter {
|
||||
// options -
|
||||
// :pathsToOpen - The array of file paths to open
|
||||
// :pidToKillWhenClosed - The integer of the pid to kill
|
||||
// :newWindow - Boolean of whether this should be opened in a new window.
|
||||
// :devMode - Boolean to control the opened window's dev mode.
|
||||
// :safeMode - Boolean to control the opened window's safe mode.
|
||||
// :windowDimensions - Object with height and width keys.
|
||||
// :window - {AtomWindow} to open file paths in.
|
||||
// :addToLastWindow - Boolean of whether this should be opened in last focused window.
|
||||
openPaths ({
|
||||
initialPaths,
|
||||
pathsToOpen,
|
||||
executedFrom,
|
||||
pidToKillWhenClosed,
|
||||
newWindow,
|
||||
devMode,
|
||||
safeMode,
|
||||
windowDimensions,
|
||||
@@ -843,26 +831,21 @@ class AtomApplication extends EventEmitter {
|
||||
safeMode = Boolean(safeMode)
|
||||
clearWindowState = Boolean(clearWindowState)
|
||||
|
||||
const locationsToOpen = []
|
||||
for (let i = 0; i < pathsToOpen.length; i++) {
|
||||
const location = this.parsePathToOpen(pathsToOpen[i], executedFrom, addToLastWindow)
|
||||
location.forceAddToWindow = addToLastWindow
|
||||
location.hasWaitSession = pidToKillWhenClosed != null
|
||||
locationsToOpen.push(location)
|
||||
pathsToOpen[i] = location.pathToOpen
|
||||
}
|
||||
const locationsToOpen = pathsToOpen.map(pathToOpen => {
|
||||
return this.parsePathToOpen(pathToOpen, executedFrom, {
|
||||
forceAddToWindow: addToLastWindow,
|
||||
hasWaitSession: pidToKillWhenClosed != null
|
||||
})
|
||||
})
|
||||
const normalizedPathsToOpen = locationsToOpen.map(location => location.pathToOpen).filter(Boolean)
|
||||
|
||||
let existingWindow
|
||||
if (!newWindow) {
|
||||
existingWindow = this.windowForPaths(pathsToOpen, devMode)
|
||||
if (addToLastWindow && normalizedPathsToOpen.length > 0) {
|
||||
existingWindow = this.windowForPaths(normalizedPathsToOpen, devMode)
|
||||
if (!existingWindow) {
|
||||
let lastWindow = window || this.getLastFocusedWindow()
|
||||
if (lastWindow && lastWindow.devMode === devMode) {
|
||||
if (addToLastWindow || (
|
||||
locationsToOpen.every(({stat}) => stat && stat.isFile()) ||
|
||||
(locationsToOpen.some(({stat}) => stat && stat.isDirectory()) && !lastWindow.hasProjectPath()))) {
|
||||
existingWindow = lastWindow
|
||||
}
|
||||
existingWindow = lastWindow
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -895,7 +878,6 @@ class AtomApplication extends EventEmitter {
|
||||
if (!windowDimensions) windowDimensions = this.getDimensionsForNewWindow()
|
||||
|
||||
openedWindow = new AtomWindow(this, this.fileRecoveryService, {
|
||||
initialPaths,
|
||||
locationsToOpen,
|
||||
windowInitializationScript,
|
||||
resourcePath,
|
||||
@@ -916,7 +898,7 @@ class AtomApplication extends EventEmitter {
|
||||
}
|
||||
this.waitSessionsByWindow.get(openedWindow).push({
|
||||
pid: pidToKillWhenClosed,
|
||||
remainingPaths: new Set(pathsToOpen)
|
||||
remainingPaths: new Set(normalizedPathsToOpen)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -984,8 +966,7 @@ class AtomApplication extends EventEmitter {
|
||||
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)),
|
||||
pathsToOpen: state.initialPaths,
|
||||
urlsToOpen: [],
|
||||
devMode: this.devMode,
|
||||
safeMode: this.safeMode
|
||||
@@ -1264,7 +1245,7 @@ class AtomApplication extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
parsePathToOpen (pathToOpen, executedFrom = '') {
|
||||
parsePathToOpen (pathToOpen, executedFrom, extra) {
|
||||
let initialColumn, initialLine
|
||||
if (!pathToOpen) {
|
||||
return {pathToOpen}
|
||||
@@ -1286,10 +1267,9 @@ class AtomApplication extends EventEmitter {
|
||||
}
|
||||
|
||||
const normalizedPath = path.normalize(path.resolve(executedFrom, fs.normalize(pathToOpen)))
|
||||
const stat = fs.statSyncNoException(normalizedPath)
|
||||
if (stat || !url.parse(pathToOpen).protocol) pathToOpen = normalizedPath
|
||||
if (!url.parse(pathToOpen).protocol) pathToOpen = normalizedPath
|
||||
|
||||
return {pathToOpen, stat, initialLine, initialColumn}
|
||||
return Object.assign({pathToOpen, initialLine, initialColumn}, extra)
|
||||
}
|
||||
|
||||
// Opens a native dialog to prompt the user for a path.
|
||||
|
||||
@@ -23,9 +23,7 @@ class AtomWindow extends EventEmitter {
|
||||
this.devMode = settings.devMode
|
||||
this.resourcePath = settings.resourcePath
|
||||
|
||||
let {pathToOpen, locationsToOpen} = settings
|
||||
if (!locationsToOpen && pathToOpen) locationsToOpen = [{pathToOpen}]
|
||||
if (!locationsToOpen) locationsToOpen = []
|
||||
const locationsToOpen = settings.locationsToOpen || []
|
||||
|
||||
this.loadedPromise = new Promise(resolve => { this.resolveLoadedPromise = resolve })
|
||||
this.closedPromise = new Promise(resolve => { this.resolveClosedPromise = resolve })
|
||||
@@ -73,23 +71,7 @@ class AtomWindow extends EventEmitter {
|
||||
if (this.loadSettings.safeMode == null) this.loadSettings.safeMode = false
|
||||
if (this.loadSettings.clearWindowState == null) this.loadSettings.clearWindowState = false
|
||||
|
||||
if (!this.loadSettings.initialPaths) {
|
||||
this.loadSettings.initialPaths = []
|
||||
for (const {pathToOpen, stat} of locationsToOpen) {
|
||||
if (!pathToOpen) continue
|
||||
if (stat && stat.isDirectory()) {
|
||||
this.loadSettings.initialPaths.push(pathToOpen)
|
||||
} else {
|
||||
const parentDirectory = path.dirname(pathToOpen)
|
||||
if (stat && stat.isFile() || fs.existsSync(parentDirectory)) {
|
||||
this.loadSettings.initialPaths.push(parentDirectory)
|
||||
} else {
|
||||
this.loadSettings.initialPaths.push(pathToOpen)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.loadSettings.initialPaths = locationsToOpen.map(location => location.pathToOpen).filter(Boolean)
|
||||
this.loadSettings.initialPaths.sort()
|
||||
|
||||
// Only send to the first non-spec window created
|
||||
|
||||
@@ -11,16 +11,20 @@ module.exports = function parseCommandLine (processArgs) {
|
||||
dedent`Atom Editor v${version}
|
||||
|
||||
Usage:
|
||||
atom
|
||||
atom [options] [path ...]
|
||||
atom file[:line[:column]]
|
||||
|
||||
One or more paths to files or folders may be specified. If there is an
|
||||
existing Atom window that contains all of the given folders, the paths
|
||||
will be opened in that window. Otherwise, they will be opened in a new
|
||||
window.
|
||||
If no arguments are given and no Atom windows are already open, restore all windows
|
||||
from the previous editing session. Use "atom --new-window" to open a single empty
|
||||
Atom window instead.
|
||||
|
||||
A file may be opened at the desired line (and optionally column) by
|
||||
appending the numbers right after the file name, e.g. \`atom file:5:8\`.
|
||||
If no arguments are given and at least one Atom window is open, open a new, empty
|
||||
Atom window.
|
||||
|
||||
One or more paths to files or folders may be specified. All paths will be opened
|
||||
in a new Atom window. Each file may be opened at the desired line (and optionally
|
||||
column) by appending the numbers after the file name, e.g. \`atom file:5:8\`.
|
||||
|
||||
Paths that start with \`atom://\` will be interpreted as URLs.
|
||||
|
||||
@@ -39,7 +43,7 @@ module.exports = function parseCommandLine (processArgs) {
|
||||
options.alias('f', 'foreground').boolean('f').describe('f', 'Keep the main process in the foreground.')
|
||||
options.alias('h', 'help').boolean('h').describe('h', 'Print this usage message.')
|
||||
options.alias('l', 'log-file').string('l').describe('l', 'Log all output to file.')
|
||||
options.alias('n', 'new-window').boolean('n').describe('n', 'Open a new window.')
|
||||
options.alias('n', 'new-window').boolean('n').describe('n', 'Launch an empty Atom window instead of restoring previous session.')
|
||||
options.boolean('profile-startup').describe('profile-startup', 'Create a profile of the startup execution time.')
|
||||
options.alias('r', 'resource-path').string('r').describe('r', 'Set the path to the Atom source directory and enable dev-mode.')
|
||||
options.boolean('safe').describe(
|
||||
|
||||
@@ -441,14 +441,20 @@ class Project extends Model {
|
||||
}
|
||||
}
|
||||
|
||||
getDirectoryForProjectPath (projectPath) {
|
||||
let directory = null
|
||||
getProvidedDirectoryForProjectPath (projectPath) {
|
||||
for (let provider of this.directoryProviders) {
|
||||
if (typeof provider.directoryForURISync === 'function') {
|
||||
directory = provider.directoryForURISync(projectPath)
|
||||
if (directory) break
|
||||
const directory = provider.directoryForURISync(projectPath)
|
||||
if (directory) {
|
||||
return directory
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
getDirectoryForProjectPath (projectPath) {
|
||||
let directory = this.getProvidedDirectoryForProjectPath(projectPath)
|
||||
if (directory == null) {
|
||||
directory = this.defaultDirectoryProvider.directoryForURISync(projectPath)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user