Store project directory paths as state on AtomWindow in browser process

Fixes #9574

Previously, we were storing the project directory paths as the
`initialPaths` key in load settings, which were accessed in the browser
process by reading the URL hash. However, this URL hash was not always
available, subjecting us to timing issues when opening multiple files
in the same folder in rapid succession.

We now store the project directory paths directly on AtomWindow
instances on creation, then RPC changes from the render process to the
browser process with a custom code path.

Shout out to :airplane::finnadie:’d @as-cii on this for pairing with me.
This commit is contained in:
Nathan Sobo
2015-11-17 21:00:13 -08:00
parent 6b877df0d9
commit d0cb8e2c55
8 changed files with 26 additions and 33 deletions

View File

@@ -151,7 +151,7 @@ describe "AtomEnvironment", ->
[dir1, dir2] = [temp.mkdirSync("dir1-"), temp.mkdirSync("dir2-")]
loadSettings = _.extend atom.getLoadSettings(),
initialPaths: [dir1]
projectDirectoryPaths: [dir1]
windowState: null
spyOn(atom, 'getLoadSettings').andCallFake -> loadSettings
@@ -165,7 +165,7 @@ describe "AtomEnvironment", ->
atom.loadStateSync()
expect(atom.state.stuff).toBeUndefined()
loadSettings.initialPaths = [dir2, dir1]
loadSettings.projectDirectoryPaths = [dir2, dir1]
atom.state = {}
atom.loadStateSync()
expect(atom.state.stuff).toBe("cool")
@@ -173,7 +173,7 @@ describe "AtomEnvironment", ->
describe "openInitialEmptyEditorIfNecessary", ->
describe "when there are no paths set", ->
beforeEach ->
spyOn(atom, 'getLoadSettings').andReturn(initialPaths: [])
spyOn(atom, 'getLoadSettings').andReturn(projectDirectoryPaths: [])
it "opens an empty buffer", ->
spyOn(atom.workspace, 'open')
@@ -191,7 +191,7 @@ describe "AtomEnvironment", ->
describe "when the project has a path", ->
beforeEach ->
spyOn(atom, 'getLoadSettings').andReturn(initialPaths: ['something'])
spyOn(atom, 'getLoadSettings').andReturn(projectDirectoryPaths: ['something'])
spyOn(atom.workspace, 'open')
it "does not open an empty buffer", ->

View File

@@ -4,7 +4,7 @@ remote = require 'remote'
shell = require 'shell'
webFrame = require 'web-frame'
{Disposable} = require 'event-kit'
{getWindowLoadSettings, setWindowLoadSettings} = require './window-load-settings-helpers'
getWindowLoadSettings = require './get-window-load-settings'
module.exports =
class ApplicationDelegate
@@ -80,10 +80,8 @@ class ApplicationDelegate
setRepresentedFilename: (filename) ->
ipc.send("call-window-method", "setRepresentedFilename", filename)
setRepresentedDirectoryPaths: (paths) ->
loadSettings = getWindowLoadSettings()
loadSettings['initialPaths'] = paths
setWindowLoadSettings(loadSettings)
setProjectDirectoryPaths: (paths) ->
ipc.send("window-command", "set-project-directory-paths", paths)
setAutoHideWindowMenuBar: (autoHide) ->
ipc.send("call-window-method", "setAutoHideMenuBar", autoHide)
@@ -124,7 +122,7 @@ class ApplicationDelegate
else
params = _.clone(params)
params.title ?= 'Save File'
params.defaultPath ?= getWindowLoadSettings().initialPaths[0]
params.defaultPath ?= getWindowLoadSettings().projectDirectoryPaths[0]
dialog = remote.require('dialog')
dialog.showSaveDialog remote.getCurrentWindow(), params

View File

@@ -11,7 +11,7 @@ Model = require './model'
WindowEventHandler = require './window-event-handler'
StylesElement = require './styles-element'
StorageFolder = require './storage-folder'
{getWindowLoadSettings} = require './window-load-settings-helpers'
getWindowLoadSettings = require './get-window-load-settings'
registerDefaultCommands = require './register-default-commands'
DeserializerManager = require './deserializer-manager'
@@ -651,7 +651,7 @@ class AtomEnvironment extends Model
openInitialEmptyEditorIfNecessary: ->
return unless @config.get('core.openEmptyEditorOnStart')
if @getLoadSettings().initialPaths?.length is 0 and @workspace.getPaneItems().length is 0
if @getLoadSettings().projectDirectoryPaths?.length is 0 and @workspace.getPaneItems().length is 0
@workspace.open(null)
installUncaughtErrorHandler: ->
@@ -753,7 +753,7 @@ class AtomEnvironment extends Model
# Notify the browser project of the window's current project path
watchProjectPath: ->
@disposables.add @project.onDidChangePaths =>
@applicationDelegate.setRepresentedDirectoryPaths(@project.getPaths())
@applicationDelegate.setProjectDirectoryPaths(@project.getPaths())
setDocumentEdited: (edited) ->
@applicationDelegate.setWindowDocumentEdited?(edited)
@@ -789,7 +789,7 @@ class AtomEnvironment extends Model
startTime = Date.now()
if stateKey = @getStateKey(@getLoadSettings().initialPaths)
if stateKey = @getStateKey(@getLoadSettings().projectDirectoryPaths)
if state = @getStorageFolder().load(stateKey)
@state = state

View File

@@ -437,9 +437,8 @@ class AtomApplication
return if @quitting
states = []
for window in @windows
unless window.isSpec
if loadSettings = window.getLoadSettings()
states.push(initialPaths: loadSettings.initialPaths)
if not window.isSpec and window.projectDirectoryPaths?
states.push(projectDirectoryPaths: window.projectDirectoryPaths)
if states.length > 0 or allowEmpty
@storageFolder.store('application.json', states)
@@ -447,7 +446,7 @@ class AtomApplication
if (states = @storageFolder.load('application.json'))?.length > 0
for state in states
@openWithOptions(_.extend(options, {
pathsToOpen: state.initialPaths
pathsToOpen: state.projectDirectoryPaths
urlsToOpen: []
devMode: @devMode
safeMode: @safeMode

View File

@@ -55,14 +55,15 @@ class AtomWindow
@constructor.includeShellLoadTime = false
loadSettings.shellLoadTime ?= Date.now() - global.shellStartTime
loadSettings.initialPaths =
loadSettings.projectDirectoryPaths =
for {pathToOpen} in locationsToOpen when pathToOpen
if fs.statSyncNoException(pathToOpen).isFile?()
path.dirname(pathToOpen)
else
pathToOpen
loadSettings.initialPaths.sort()
loadSettings.projectDirectoryPaths.sort()
@setProjectDirectoryPaths(loadSettings.projectDirectoryPaths)
@browserWindow.loadSettings = loadSettings
@browserWindow.once 'window:loaded', =>
@@ -87,12 +88,9 @@ class AtomWindow
slashes: true
hash: encodeURIComponent(JSON.stringify(loadSettings))
getLoadSettings: ->
if @browserWindow.webContents? and not @browserWindow.webContents.isLoading()
hash = url.parse(@browserWindow.webContents.getUrl()).hash.substr(1)
JSON.parse(decodeURIComponent(hash))
setProjectDirectoryPaths: (@projectDirectoryPaths) ->
hasProjectPath: -> @getLoadSettings().initialPaths?.length > 0
hasProjectPath: -> @projectDirectoryPaths?.length > 0
setupContextMenu: ->
ContextMenu = require './context-menu'
@@ -106,7 +104,7 @@ class AtomWindow
true
containsPath: (pathToCheck) ->
@getLoadSettings()?.initialPaths?.some (projectPath) ->
@projectDirectoryPaths?.some (projectPath) ->
if not projectPath
false
else if not pathToCheck
@@ -121,6 +119,8 @@ class AtomWindow
false
handleEvents: ->
@browserWindow.on 'set-project-directory-paths', @setProjectDirectoryPaths.bind(this)
@browserWindow.on 'closed', =>
global.atomApplication.removeWindow(this)

View File

@@ -3,7 +3,7 @@ _ = require 'underscore-plus'
windowLoadSettings = null
exports.getWindowLoadSettings = ->
module.exports = ->
windowLoadSettings ?= JSON.parse(window.decodeURIComponent(window.location.hash.substr(1)))
clone = _.deepClone(windowLoadSettings)
@@ -14,7 +14,3 @@ exports.getWindowLoadSettings = ->
remote.getCurrentWindow().loadSettings.windowState = value
clone
exports.setWindowLoadSettings = (settings) ->
windowLoadSettings = settings
location.hash = encodeURIComponent(JSON.stringify(settings))

View File

@@ -2,7 +2,7 @@
module.exports = ({blobStore}) ->
path = require 'path'
require './window'
{getWindowLoadSettings} = require './window-load-settings-helpers'
getWindowLoadSettings = require './get-window-load-settings'
{resourcePath, isSpec, devMode} = getWindowLoadSettings()

View File

@@ -15,7 +15,7 @@ module.exports = ({blobStore}) ->
try
path = require 'path'
ipc = require 'ipc'
{getWindowLoadSettings} = require './window-load-settings-helpers'
getWindowLoadSettings = require './get-window-load-settings'
AtomEnvironment = require '../src/atom-environment'
ApplicationDelegate = require '../src/application-delegate'