mirror of
https://github.com/atom/atom.git
synced 2026-04-28 03:01:47 -04:00
Merge pull request #19169 from atom/aw/launch-it
Improve launch behavior
This commit is contained in:
@@ -170,8 +170,8 @@ class ApplicationDelegate {
|
||||
return ipcRenderer.send('add-recent-document', filename)
|
||||
}
|
||||
|
||||
setRepresentedDirectoryPaths (paths) {
|
||||
return ipcHelpers.call('window-method', 'setRepresentedDirectoryPaths', paths)
|
||||
setProjectRoots (paths) {
|
||||
return ipcHelpers.call('window-method', 'setProjectRoots', paths)
|
||||
}
|
||||
|
||||
setAutoHideWindowMenuBar (autoHide) {
|
||||
|
||||
@@ -784,7 +784,9 @@ class AtomEnvironment {
|
||||
|
||||
const loadStatePromise = this.loadState().then(async state => {
|
||||
this.windowDimensions = state && state.windowDimensions
|
||||
await this.displayWindow()
|
||||
if (!this.getLoadSettings().headless) {
|
||||
await this.displayWindow()
|
||||
}
|
||||
this.commandInstaller.installAtomCommand(false, (error) => {
|
||||
if (error) console.warn(error.message)
|
||||
})
|
||||
@@ -838,7 +840,7 @@ class AtomEnvironment {
|
||||
}
|
||||
}
|
||||
previousProjectPaths = newPaths
|
||||
this.applicationDelegate.setRepresentedDirectoryPaths(newPaths)
|
||||
this.applicationDelegate.setProjectRoots(newPaths)
|
||||
}))
|
||||
this.disposables.add(this.workspace.onDidDestroyPaneItem(({item}) => {
|
||||
const path = item.getPath && item.getPath()
|
||||
@@ -916,8 +918,8 @@ class AtomEnvironment {
|
||||
|
||||
openInitialEmptyEditorIfNecessary () {
|
||||
if (!this.config.get('core.openEmptyEditorOnStart')) return
|
||||
const {initialPaths} = this.getLoadSettings()
|
||||
if (initialPaths && initialPaths.length === 0 && this.workspace.getPaneItems().length === 0) {
|
||||
const {hasOpenFiles} = this.getLoadSettings()
|
||||
if (!hasOpenFiles && this.workspace.getPaneItems().length === 0) {
|
||||
return this.workspace.open(null)
|
||||
}
|
||||
}
|
||||
@@ -1213,7 +1215,7 @@ or use Pane::saveItemAs for programmatic saving.`)
|
||||
|
||||
loadState (stateKey) {
|
||||
if (this.enablePersistence) {
|
||||
if (!stateKey) stateKey = this.getStateKey(this.getLoadSettings().initialPaths)
|
||||
if (!stateKey) stateKey = this.getStateKey(this.getLoadSettings().initialProjectRoots)
|
||||
if (stateKey) {
|
||||
return this.stateStore.load(stateKey)
|
||||
} else {
|
||||
@@ -1388,7 +1390,7 @@ or use Pane::saveItemAs for programmatic saving.`)
|
||||
// Directory: add as a project folder
|
||||
foldersToAddToProject.add(this.project.getDirectoryForProjectPath(pathToOpen).getPath())
|
||||
} else if (stats.isFile()) {
|
||||
if (location.mustBeDirectory) {
|
||||
if (location.isDirectory) {
|
||||
// File: no longer a directory
|
||||
missingFolders.push(location)
|
||||
} else {
|
||||
@@ -1403,7 +1405,7 @@ or use Pane::saveItemAs for programmatic saving.`)
|
||||
if (directory) {
|
||||
// Found: add as a project folder
|
||||
foldersToAddToProject.add(directory.getPath())
|
||||
} else if (location.mustBeDirectory) {
|
||||
} else if (location.isDirectory) {
|
||||
// Not found and must be a directory: add to missing list and use to derive state key
|
||||
missingFolders.push(location)
|
||||
} else {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
const fs = require('fs-plus')
|
||||
|
||||
// Converts a query string parameter for a line or column number
|
||||
// to a zero-based line or column number for the Atom API.
|
||||
function getLineColNumber (numStr) {
|
||||
@@ -17,7 +19,14 @@ function openFile (atom, {query}) {
|
||||
|
||||
function windowShouldOpenFile ({query}) {
|
||||
const {filename} = query
|
||||
return (win) => win.containsPath(filename)
|
||||
const stat = fs.statSyncNoException(filename)
|
||||
|
||||
return win => win.containsLocation({
|
||||
pathToOpen: filename,
|
||||
exists: Boolean(stat),
|
||||
isFile: stat.isFile(),
|
||||
isDirectory: stat.isDirectory()
|
||||
})
|
||||
}
|
||||
|
||||
const ROUTER = {
|
||||
@@ -39,7 +48,7 @@ module.exports = {
|
||||
if (config && config.getWindowPredicate) {
|
||||
return config.getWindowPredicate(parsed)
|
||||
} else {
|
||||
return (win) => true
|
||||
return () => true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ exports.respondTo = function (channel, callback) {
|
||||
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)
|
||||
if (!event.sender.isDestroyed()) {
|
||||
event.sender.send(responseChannel, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -120,6 +120,11 @@ class AtomApplication extends EventEmitter {
|
||||
static open (options) {
|
||||
const socketSecret = getExistingSocketSecret(options.version)
|
||||
const socketPath = getSocketPath(socketSecret)
|
||||
const createApplication = options.createApplication || (async () => {
|
||||
const app = new AtomApplication(options)
|
||||
await app.initialize(options)
|
||||
return app
|
||||
})
|
||||
|
||||
// FIXME: Sometimes when socketPath doesn't exist, net.connect would strangely
|
||||
// take a few seconds to trigger 'error' event, it could be a bug of node
|
||||
@@ -129,18 +134,20 @@ class AtomApplication extends EventEmitter {
|
||||
!socketPath || options.test || options.benchmark || options.benchmarkTest ||
|
||||
(process.platform !== 'win32' && !fs.existsSync(socketPath))
|
||||
) {
|
||||
new AtomApplication(options).initialize(options)
|
||||
return
|
||||
return createApplication(options)
|
||||
}
|
||||
|
||||
const client = net.connect({path: socketPath}, () => {
|
||||
client.write(encryptOptions(options, socketSecret), () => {
|
||||
client.end()
|
||||
app.quit()
|
||||
return new Promise(resolve => {
|
||||
const client = net.connect({path: socketPath}, () => {
|
||||
client.write(encryptOptions(options, socketSecret), () => {
|
||||
client.end()
|
||||
app.quit()
|
||||
resolve(null)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
client.on('error', () => new AtomApplication(options).initialize(options))
|
||||
client.on('error', () => resolve(createApplication(options)))
|
||||
})
|
||||
}
|
||||
|
||||
exit (status) {
|
||||
@@ -246,19 +253,19 @@ class AtomApplication extends EventEmitter {
|
||||
|
||||
if (options.test || options.benchmark || options.benchmarkTest) {
|
||||
optionsForWindowsToOpen.push(options)
|
||||
} else if (options.newWindow) {
|
||||
shouldReopenPreviousWindows = false
|
||||
} else if ((options.pathsToOpen && options.pathsToOpen.length > 0) ||
|
||||
(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'
|
||||
}
|
||||
|
||||
if (shouldReopenPreviousWindows) {
|
||||
for (const previousOptions of await this.loadPreviousWindowOptions()) {
|
||||
optionsForWindowsToOpen.push(Object.assign({}, options, previousOptions))
|
||||
optionsForWindowsToOpen.push(previousOptions)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +273,12 @@ class AtomApplication extends EventEmitter {
|
||||
optionsForWindowsToOpen.push(options)
|
||||
}
|
||||
|
||||
return optionsForWindowsToOpen.map(options => this.openWithOptions(options))
|
||||
// Preserve window opening order
|
||||
const windows = []
|
||||
for (const options of optionsForWindowsToOpen) {
|
||||
windows.push(await this.openWithOptions(options))
|
||||
}
|
||||
return windows
|
||||
}
|
||||
|
||||
openWithOptions (options) {
|
||||
@@ -287,10 +299,13 @@ class AtomApplication extends EventEmitter {
|
||||
timeout,
|
||||
clearWindowState,
|
||||
addToLastWindow,
|
||||
preserveFocus,
|
||||
env
|
||||
} = options
|
||||
|
||||
app.focus()
|
||||
if (!preserveFocus) {
|
||||
app.focus()
|
||||
}
|
||||
|
||||
if (test) {
|
||||
return this.runTests({
|
||||
@@ -327,11 +342,14 @@ class AtomApplication extends EventEmitter {
|
||||
addToLastWindow,
|
||||
env
|
||||
})
|
||||
} else if (urlsToOpen.length > 0) {
|
||||
return urlsToOpen.map(urlToOpen => this.openUrl({urlToOpen, devMode, safeMode, env}))
|
||||
} else if (urlsToOpen && urlsToOpen.length > 0) {
|
||||
return Promise.all(
|
||||
urlsToOpen.map(urlToOpen => this.openUrl({urlToOpen, devMode, safeMode, env}))
|
||||
)
|
||||
} else {
|
||||
// Always open a editor window if this is the first instance of Atom.
|
||||
// Always open an editor window if this is the first instance of Atom.
|
||||
return this.openPath({
|
||||
pathToOpen: null,
|
||||
pidToKillWhenClosed,
|
||||
newWindow,
|
||||
devMode,
|
||||
@@ -344,6 +362,11 @@ class AtomApplication extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
// Public: Create a new {AtomWindow} bound to this application.
|
||||
createWindow (settings) {
|
||||
return new AtomWindow(this, this.fileRecoveryService, settings)
|
||||
}
|
||||
|
||||
// Public: Removes the {AtomWindow} from the global window list.
|
||||
removeWindow (window) {
|
||||
this.windowStack.removeWindow(window)
|
||||
@@ -379,6 +402,7 @@ class AtomApplication extends EventEmitter {
|
||||
window.browserWindow.removeListener('blur', blurHandler)
|
||||
})
|
||||
window.browserWindow.webContents.once('did-finish-load', blurHandler)
|
||||
this.saveCurrentWindowOptions(false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,8 +437,10 @@ class AtomApplication extends EventEmitter {
|
||||
})
|
||||
})
|
||||
|
||||
server.listen(this.socketPath)
|
||||
server.on('error', error => console.error('Application server failed', error))
|
||||
return new Promise(resolve => {
|
||||
server.listen(this.socketPath, resolve)
|
||||
server.on('error', error => console.error('Application server failed', error))
|
||||
})
|
||||
}
|
||||
|
||||
deleteSocketFile () {
|
||||
@@ -455,9 +481,9 @@ class AtomApplication extends EventEmitter {
|
||||
const getLoadSettings = includeWindow => {
|
||||
const window = this.focusedWindow()
|
||||
return {
|
||||
devMode: window && window.devMode,
|
||||
safeMode: window && window.safeMode,
|
||||
window: includeWindow && window
|
||||
devMode: window ? window.devMode : false,
|
||||
safeMode: window ? window.safeMode : false,
|
||||
window: includeWindow && window ? window : null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -609,7 +635,7 @@ class AtomApplication extends EventEmitter {
|
||||
options.window = window
|
||||
this.openPaths(options)
|
||||
} else {
|
||||
this.addWindow(new AtomWindow(this, this.fileRecoveryService, options))
|
||||
this.addWindow(this.createWindow(options))
|
||||
}
|
||||
} else {
|
||||
this.promptForPathToOpen('all', {window})
|
||||
@@ -657,7 +683,7 @@ class AtomApplication extends EventEmitter {
|
||||
|
||||
this.disposable.add(ipcHelpers.on(ipcMain, 'window-command', (event, command, ...args) => {
|
||||
const window = BrowserWindow.fromWebContents(event.sender)
|
||||
return window.emit(command, ...args)
|
||||
return window && window.emit(command, ...args)
|
||||
}))
|
||||
|
||||
this.disposable.add(ipcHelpers.respondTo('window-method', (browserWindow, method, ...args) => {
|
||||
@@ -729,10 +755,6 @@ class AtomApplication extends EventEmitter {
|
||||
this.fileRecoveryService.didSavePath(window, path)
|
||||
))
|
||||
|
||||
this.disposable.add(ipcHelpers.on(ipcMain, 'did-change-paths', () =>
|
||||
this.saveCurrentWindowOptions(false)
|
||||
))
|
||||
|
||||
this.disposable.add(this.disableZoomOnDisplayChange())
|
||||
}
|
||||
|
||||
@@ -831,10 +853,12 @@ class AtomApplication extends EventEmitter {
|
||||
})
|
||||
}
|
||||
|
||||
// Returns the {AtomWindow} for the given paths.
|
||||
windowForPaths (pathsToOpen, devMode) {
|
||||
return this.getAllWindows().find(window =>
|
||||
window.devMode === devMode && window.containsPaths(pathsToOpen)
|
||||
// Returns the {AtomWindow} for the given locations.
|
||||
windowForLocations (locationsToOpen, devMode, safeMode) {
|
||||
return this.getLastFocusedWindow(window =>
|
||||
window.devMode === devMode &&
|
||||
window.safeMode === safeMode &&
|
||||
window.containsLocations(locationsToOpen)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -924,7 +948,7 @@ class AtomApplication extends EventEmitter {
|
||||
// :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 ({
|
||||
async openPaths ({
|
||||
pathsToOpen,
|
||||
foldersToOpen,
|
||||
executedFrom,
|
||||
@@ -947,20 +971,19 @@ class AtomApplication extends EventEmitter {
|
||||
safeMode = Boolean(safeMode)
|
||||
clearWindowState = Boolean(clearWindowState)
|
||||
|
||||
const locationsToOpen = pathsToOpen.map(pathToOpen => {
|
||||
return this.parsePathToOpen(pathToOpen, executedFrom, {
|
||||
forceAddToWindow: addToLastWindow,
|
||||
const locationsToOpen = await Promise.all(
|
||||
pathsToOpen.map(pathToOpen => this.parsePathToOpen(pathToOpen, executedFrom, {
|
||||
hasWaitSession: pidToKillWhenClosed != null
|
||||
})
|
||||
})
|
||||
}))
|
||||
)
|
||||
|
||||
for (const folderToOpen of foldersToOpen) {
|
||||
locationsToOpen.push({
|
||||
pathToOpen: folderToOpen,
|
||||
initialLine: null,
|
||||
initialColumn: null,
|
||||
mustBeDirectory: true,
|
||||
forceAddToWindow: addToLastWindow,
|
||||
exists: true,
|
||||
isDirectory: true,
|
||||
hasWaitSession: pidToKillWhenClosed != null
|
||||
})
|
||||
}
|
||||
@@ -969,27 +992,42 @@ class AtomApplication extends EventEmitter {
|
||||
return
|
||||
}
|
||||
|
||||
const normalizedPathsToOpen = locationsToOpen.map(location => location.pathToOpen).filter(Boolean)
|
||||
const hasNonEmptyPath = locationsToOpen.some(location => location.pathToOpen)
|
||||
const createNewWindow = newWindow || !hasNonEmptyPath
|
||||
|
||||
let existingWindow
|
||||
|
||||
// Explicitly provided AtomWindow has precedence unless a new window is forced.
|
||||
if (!newWindow) {
|
||||
if (!createNewWindow) {
|
||||
// An explicitly provided AtomWindow has precedence.
|
||||
existingWindow = window
|
||||
}
|
||||
|
||||
// If no window is specified, a new window is not forced, and at least one path is provided, locate
|
||||
// an existing window that contains all paths.
|
||||
if (!existingWindow && !newWindow && normalizedPathsToOpen.length > 0) {
|
||||
existingWindow = this.windowForPaths(normalizedPathsToOpen, devMode)
|
||||
}
|
||||
// If no window is specified and at least one path is provided, locate an existing window that contains all
|
||||
// provided paths.
|
||||
if (!existingWindow && hasNonEmptyPath) {
|
||||
existingWindow = this.windowForLocations(locationsToOpen, devMode, safeMode)
|
||||
}
|
||||
|
||||
// No window specified, new window not forced, no existing window found, and addition to the last window
|
||||
// requested. Find the last focused window.
|
||||
if (!existingWindow && !newWindow && addToLastWindow) {
|
||||
let lastWindow = window || this.getLastFocusedWindow()
|
||||
if (lastWindow && lastWindow.devMode === devMode) {
|
||||
existingWindow = lastWindow
|
||||
// No window specified, no existing window found, and addition to the last window requested. Find the last
|
||||
// focused window that matches the requested dev and safe modes.
|
||||
if (!existingWindow && addToLastWindow) {
|
||||
existingWindow = this.getLastFocusedWindow(win => {
|
||||
return win.devMode === devMode && win.safeMode === safeMode
|
||||
})
|
||||
}
|
||||
|
||||
// Fall back to the last focused window that has no project roots.
|
||||
if (!existingWindow) {
|
||||
existingWindow = this.getLastFocusedWindow(win => !win.hasProjectPaths())
|
||||
}
|
||||
|
||||
// One last case: if *no* paths are directories, add to the last focused window.
|
||||
if (!existingWindow) {
|
||||
const noDirectories = locationsToOpen.every(location => !location.isDirectory)
|
||||
if (noDirectories) {
|
||||
existingWindow = this.getLastFocusedWindow(win => {
|
||||
return win.devMode === devMode && win.safeMode === safeMode
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1020,7 +1058,7 @@ class AtomApplication extends EventEmitter {
|
||||
if (!resourcePath) resourcePath = this.resourcePath
|
||||
if (!windowDimensions) windowDimensions = this.getDimensionsForNewWindow()
|
||||
|
||||
openedWindow = new AtomWindow(this, this.fileRecoveryService, {
|
||||
openedWindow = this.createWindow({
|
||||
locationsToOpen,
|
||||
windowInitializationScript,
|
||||
resourcePath,
|
||||
@@ -1041,7 +1079,7 @@ class AtomApplication extends EventEmitter {
|
||||
}
|
||||
this.waitSessionsByWindow.get(openedWindow).push({
|
||||
pid: pidToKillWhenClosed,
|
||||
remainingPaths: new Set(normalizedPathsToOpen)
|
||||
remainingPaths: new Set(locationsToOpen.map(location => location.pathToOpen).filter(Boolean))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1095,7 +1133,7 @@ class AtomApplication extends EventEmitter {
|
||||
|
||||
const states = []
|
||||
for (let window of this.getAllWindows()) {
|
||||
if (!window.isSpec) states.push({initialPaths: window.representedDirectoryPaths})
|
||||
if (!window.isSpec) states.push({initialPaths: window.projectRoots})
|
||||
}
|
||||
states.reverse()
|
||||
|
||||
@@ -1110,7 +1148,6 @@ class AtomApplication extends EventEmitter {
|
||||
if (states) {
|
||||
return states.map(state => ({
|
||||
foldersToOpen: state.initialPaths,
|
||||
urlsToOpen: [],
|
||||
devMode: this.devMode,
|
||||
safeMode: this.safeMode
|
||||
}))
|
||||
@@ -1161,6 +1198,7 @@ class AtomApplication extends EventEmitter {
|
||||
if (bestWindow) {
|
||||
bestWindow.sendURIMessage(url)
|
||||
bestWindow.focus()
|
||||
return bestWindow
|
||||
} else {
|
||||
let windowInitializationScript
|
||||
let {resourcePath} = this
|
||||
@@ -1178,7 +1216,7 @@ class AtomApplication extends EventEmitter {
|
||||
}
|
||||
|
||||
const windowDimensions = this.getDimensionsForNewWindow()
|
||||
const window = new AtomWindow(this, this.fileRecoveryService, {
|
||||
const window = this.createWindow({
|
||||
resourcePath,
|
||||
windowInitializationScript,
|
||||
devMode,
|
||||
@@ -1202,7 +1240,7 @@ class AtomApplication extends EventEmitter {
|
||||
const packagePath = this.getPackageManager(devMode).resolvePackagePath(packageName)
|
||||
const windowInitializationScript = path.resolve(packagePath, packageUrlMain)
|
||||
const windowDimensions = this.getDimensionsForNewWindow()
|
||||
const window = new AtomWindow(this, this.fileRecoveryService, {
|
||||
const window = this.createWindow({
|
||||
windowInitializationScript,
|
||||
resourcePath: this.resourcePath,
|
||||
devMode,
|
||||
@@ -1284,7 +1322,7 @@ class AtomApplication extends EventEmitter {
|
||||
if (safeMode == null) {
|
||||
safeMode = false
|
||||
}
|
||||
const window = new AtomWindow(this, this.fileRecoveryService, {
|
||||
const window = this.createWindow({
|
||||
windowInitializationScript,
|
||||
resourcePath,
|
||||
headless,
|
||||
@@ -1333,7 +1371,7 @@ class AtomApplication extends EventEmitter {
|
||||
const devMode = true
|
||||
const isSpec = true
|
||||
const safeMode = false
|
||||
const window = new AtomWindow(this, this.fileRecoveryService, {
|
||||
const window = this.createWindow({
|
||||
windowInitializationScript,
|
||||
resourcePath,
|
||||
headless,
|
||||
@@ -1388,31 +1426,58 @@ class AtomApplication extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
parsePathToOpen (pathToOpen, executedFrom, extra) {
|
||||
let initialColumn, initialLine
|
||||
async parsePathToOpen (pathToOpen, executedFrom, extra) {
|
||||
const result = Object.assign({
|
||||
pathToOpen,
|
||||
initialColumn: null,
|
||||
initialLine: null,
|
||||
exists: false,
|
||||
isDirectory: false,
|
||||
isFile: false
|
||||
}, extra)
|
||||
|
||||
if (!pathToOpen) {
|
||||
return {pathToOpen}
|
||||
return result
|
||||
}
|
||||
|
||||
pathToOpen = pathToOpen.replace(/[:\s]+$/, '')
|
||||
const match = pathToOpen.match(LocationSuffixRegExp)
|
||||
result.pathToOpen = result.pathToOpen.replace(/[:\s]+$/, '')
|
||||
const match = result.pathToOpen.match(LocationSuffixRegExp)
|
||||
|
||||
if (match != null) {
|
||||
pathToOpen = pathToOpen.slice(0, -match[0].length)
|
||||
result.pathToOpen = result.pathToOpen.slice(0, -match[0].length)
|
||||
if (match[1]) {
|
||||
initialLine = Math.max(0, parseInt(match[1].slice(1)) - 1)
|
||||
result.initialLine = Math.max(0, parseInt(match[1].slice(1), 10) - 1)
|
||||
}
|
||||
if (match[2]) {
|
||||
initialColumn = Math.max(0, parseInt(match[2].slice(1)) - 1)
|
||||
result.initialColumn = Math.max(0, parseInt(match[2].slice(1), 10) - 1)
|
||||
}
|
||||
} else {
|
||||
initialLine = initialColumn = null
|
||||
}
|
||||
|
||||
const normalizedPath = path.normalize(path.resolve(executedFrom, fs.normalize(pathToOpen)))
|
||||
if (!url.parse(pathToOpen).protocol) pathToOpen = normalizedPath
|
||||
const normalizedPath = path.normalize(path.resolve(executedFrom, fs.normalize(result.pathToOpen)))
|
||||
if (!url.parse(pathToOpen).protocol) {
|
||||
result.pathToOpen = normalizedPath
|
||||
}
|
||||
|
||||
return Object.assign({pathToOpen, initialLine, initialColumn}, extra)
|
||||
await new Promise((resolve, reject) => {
|
||||
fs.stat(result.pathToOpen, (err, st) => {
|
||||
if (err) {
|
||||
if (err.code === 'ENOENT' || err.code === 'EACCES') {
|
||||
result.exists = false
|
||||
resolve()
|
||||
} else {
|
||||
reject(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
result.exists = true
|
||||
result.isFile = st.isFile()
|
||||
result.isDirectory = st.isDirectory()
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Opens a native dialog to prompt the user for a path.
|
||||
@@ -1467,8 +1532,8 @@ class AtomApplication extends EventEmitter {
|
||||
}
|
||||
})()
|
||||
|
||||
// Show the open dialog as child window on Windows and Linux, and as
|
||||
// independent dialog on macOS. This matches most native apps.
|
||||
// Show the open dialog as child window on Windows and Linux, and as an independent dialog on macOS. This matches
|
||||
// most native apps.
|
||||
const parentWindow = process.platform === 'darwin' ? null : BrowserWindow.getFocusedWindow()
|
||||
|
||||
const openOptions = {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
const {BrowserWindow, app, dialog, ipcMain} = require('electron')
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
const url = require('url')
|
||||
const {EventEmitter} = require('events')
|
||||
|
||||
@@ -51,7 +50,9 @@ class AtomWindow extends EventEmitter {
|
||||
if (this.shouldAddCustomTitleBar()) options.titleBarStyle = 'hidden'
|
||||
if (this.shouldAddCustomInsetTitleBar()) options.titleBarStyle = 'hiddenInset'
|
||||
if (this.shouldHideTitleBar()) options.frame = false
|
||||
this.browserWindow = new BrowserWindow(options)
|
||||
|
||||
const BrowserWindowConstructor = settings.browserWindowConstructor || BrowserWindow
|
||||
this.browserWindow = new BrowserWindowConstructor(options)
|
||||
|
||||
Object.defineProperty(this.browserWindow, 'loadSettingsJSON', {
|
||||
get: () => JSON.stringify(Object.assign({
|
||||
@@ -71,8 +72,14 @@ class AtomWindow extends EventEmitter {
|
||||
if (this.loadSettings.safeMode == null) this.loadSettings.safeMode = false
|
||||
if (this.loadSettings.clearWindowState == null) this.loadSettings.clearWindowState = false
|
||||
|
||||
this.loadSettings.initialPaths = locationsToOpen.map(location => location.pathToOpen).filter(Boolean)
|
||||
this.loadSettings.initialPaths.sort()
|
||||
this.projectRoots = locationsToOpen
|
||||
.filter(location => location.pathToOpen && location.exists && location.isDirectory)
|
||||
.map(location => location.pathToOpen)
|
||||
this.projectRoots.sort()
|
||||
|
||||
this.loadSettings.hasOpenFiles = locationsToOpen
|
||||
.some(location => location.pathToOpen && !location.isDirectory)
|
||||
this.loadSettings.initialProjectRoots = this.projectRoots
|
||||
|
||||
// Only send to the first non-spec window created
|
||||
if (includeShellLoadTime && !this.isSpec) {
|
||||
@@ -82,7 +89,6 @@ class AtomWindow extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
this.representedDirectoryPaths = this.loadSettings.initialPaths
|
||||
if (!this.loadSettings.env) this.env = this.loadSettings.env
|
||||
|
||||
this.browserWindow.on('window:loaded', () => {
|
||||
@@ -119,8 +125,8 @@ class AtomWindow extends EventEmitter {
|
||||
if (hasPathToOpen && !this.isSpecWindow()) this.openLocations(locationsToOpen)
|
||||
}
|
||||
|
||||
hasProjectPath () {
|
||||
return this.representedDirectoryPaths.length > 0
|
||||
hasProjectPaths () {
|
||||
return this.projectRoots.length > 0
|
||||
}
|
||||
|
||||
setupContextMenu () {
|
||||
@@ -131,18 +137,20 @@ class AtomWindow extends EventEmitter {
|
||||
})
|
||||
}
|
||||
|
||||
containsPaths (paths) {
|
||||
return paths.every(p => this.containsPath(p))
|
||||
containsLocations (locations) {
|
||||
return locations.every(location => this.containsLocation(location))
|
||||
}
|
||||
|
||||
containsPath (pathToCheck) {
|
||||
if (!pathToCheck) return false
|
||||
let stat
|
||||
return this.representedDirectoryPaths.some(projectPath => {
|
||||
if (pathToCheck === projectPath) return true
|
||||
if (!pathToCheck.startsWith(path.join(projectPath, path.sep))) return false
|
||||
if (stat === undefined) stat = fs.statSyncNoException(pathToCheck)
|
||||
return !stat || !stat.isDirectory()
|
||||
containsLocation (location) {
|
||||
if (!location.pathToOpen) return false
|
||||
|
||||
return this.projectRoots.some(projectPath => {
|
||||
if (location.pathToOpen === projectPath) return true
|
||||
if (location.pathToOpen.startsWith(path.join(projectPath, path.sep))) {
|
||||
if (!location.exists) return true
|
||||
if (!location.isDirectory) return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
@@ -376,7 +384,7 @@ class AtomWindow extends EventEmitter {
|
||||
showSaveDialog (options, callback) {
|
||||
options = Object.assign({
|
||||
title: 'Save File',
|
||||
defaultPath: this.representedDirectoryPaths[0]
|
||||
defaultPath: this.projectRoots[0]
|
||||
}, options)
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
@@ -408,10 +416,10 @@ class AtomWindow extends EventEmitter {
|
||||
return this.browserWindow.setRepresentedFilename(representedFilename)
|
||||
}
|
||||
|
||||
setRepresentedDirectoryPaths (representedDirectoryPaths) {
|
||||
this.representedDirectoryPaths = representedDirectoryPaths
|
||||
this.representedDirectoryPaths.sort()
|
||||
this.loadSettings.initialPaths = this.representedDirectoryPaths
|
||||
setProjectRoots (projectRootPaths) {
|
||||
this.projectRoots = projectRootPaths
|
||||
this.projectRoots.sort()
|
||||
this.loadSettings.initialProjectRoots = this.projectRoots
|
||||
return this.atomApplication.saveCurrentWindowOptions()
|
||||
}
|
||||
|
||||
@@ -426,4 +434,8 @@ class AtomWindow extends EventEmitter {
|
||||
disableZoom () {
|
||||
return this.browserWindow.webContents.setVisualZoomLevelLimits(1, 1)
|
||||
}
|
||||
|
||||
getLoadedPromise () {
|
||||
return this.loadedPromise
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user