mirror of
https://github.com/atom/atom.git
synced 2026-04-06 03:02:13 -04:00
Set multiple project paths for multiple cmd-line paths
Signed-off-by: Jessica Lord <jlord@github.com>
This commit is contained in:
committed by
Jessica Lord
parent
81d07e2804
commit
f7e1629cfc
@@ -59,3 +59,45 @@ describe "Starting Atom", ->
|
||||
.waitForExist("atom-workspace", 5000)
|
||||
.then((exists) -> expect(exists).toBe true)
|
||||
.waitForPaneItemCount(0, 1000)
|
||||
|
||||
it "saves the state of closed windows", ->
|
||||
runAtom [otherTempDirPath], {ATOM_HOME: AtomHome}, (client) ->
|
||||
client
|
||||
|
||||
# Opening a file in another window creates another window with a tab
|
||||
# open for that file.
|
||||
.waitForExist("atom-workspace", 5000)
|
||||
.startAnotherWindow([tempFilePath], ATOM_HOME: AtomHome)
|
||||
.waitForWindowCount(2, 5000)
|
||||
.then(({value}) -> @window(value[1]))
|
||||
.waitForExist("atom-text-editor", 5000)
|
||||
.click("atom-text-editor")
|
||||
.execute(-> atom.workspace.getActiveTextEditor().getText())
|
||||
.then(({value}) -> expect(value).toBe "This file was already here.")
|
||||
|
||||
# Closing that window and reopening that directory shows the
|
||||
# previously-opened file.
|
||||
.execute(-> atom.unloadEditorWindow())
|
||||
.close()
|
||||
.waitForWindowCount(1, 5000)
|
||||
.startAnotherWindow([tempDirPath], ATOM_HOME: AtomHome)
|
||||
.waitForWindowCount(2, 5000)
|
||||
.then(({value}) -> @window(value[1]))
|
||||
.waitForExist("atom-text-editor", 5000)
|
||||
.execute(-> atom.workspace.getActiveTextEditor().getText())
|
||||
.then(({value}) -> expect(value).toBe "This file was already here.")
|
||||
|
||||
it "allows multiple project directories to be passed as separate arguments", ->
|
||||
runAtom [tempDirPath, otherTempDirPath], {ATOM_HOME: AtomHome}, (client) ->
|
||||
client
|
||||
.waitForExist("atom-workspace", 5000)
|
||||
.then((exists) -> expect(exists).toBe true)
|
||||
.execute(-> atom.project.getPaths())
|
||||
.then(({value}) -> expect(value).toEqual([tempDirPath, otherTempDirPath]))
|
||||
|
||||
# Opening a file in one of the directories reuses the same window
|
||||
# and does not change the project paths.
|
||||
.startAnotherWindow([tempFilePath], ATOM_HOME: AtomHome)
|
||||
.waitForPaneItemCount(1, 5000)
|
||||
.execute(-> atom.project.getPaths())
|
||||
.then(({value}) -> expect(value).toEqual([tempDirPath, otherTempDirPath]))
|
||||
|
||||
@@ -293,6 +293,21 @@ describe "Project", ->
|
||||
expect(onDidChangePathsSpy.callCount).toBe 1
|
||||
expect(onDidChangePathsSpy.mostRecentCall.args[0]).toEqual([oldPath, newPath])
|
||||
|
||||
describe "when the project already has the path or one of its descendants", ->
|
||||
it "doesn't add it again", ->
|
||||
onDidChangePathsSpy = jasmine.createSpy('onDidChangePaths spy')
|
||||
atom.project.onDidChangePaths(onDidChangePathsSpy)
|
||||
|
||||
[oldPath] = atom.project.getPaths()
|
||||
|
||||
atom.project.addPath(oldPath)
|
||||
atom.project.addPath(path.join(oldPath, "some-file.txt"))
|
||||
atom.project.addPath(path.join(oldPath, "a-dir"))
|
||||
atom.project.addPath(path.join(oldPath, "a-dir", "oh-git"))
|
||||
|
||||
expect(atom.project.getPaths()).toEqual([oldPath])
|
||||
expect(onDidChangePathsSpy).not.toHaveBeenCalled()
|
||||
|
||||
describe ".relativize(path)", ->
|
||||
it "returns the path, relative to whichever root directory it is inside of", ->
|
||||
rootPath = atom.project.getPaths()[0]
|
||||
|
||||
@@ -276,33 +276,31 @@ describe "Window", ->
|
||||
elements.trigger "core:focus-previous"
|
||||
expect(elements.find("[tabindex=1]:focus")).toExist()
|
||||
|
||||
describe "the window:open-path event", ->
|
||||
describe "the window:open-locations event", ->
|
||||
beforeEach ->
|
||||
spyOn(atom.workspace, 'open')
|
||||
atom.project.setPaths([])
|
||||
|
||||
describe "when the project does not have a path", ->
|
||||
beforeEach ->
|
||||
atom.project.setPaths([])
|
||||
describe "when the opened path exists", ->
|
||||
it "adds it to the project's paths", ->
|
||||
pathToOpen = __filename
|
||||
atom.getCurrentWindow().send 'message', 'open-locations', [{pathToOpen}]
|
||||
expect(atom.project.getPaths()[0]).toBe __dirname
|
||||
|
||||
describe "when the opened path exists", ->
|
||||
it "sets the project path to the opened path", ->
|
||||
atom.getCurrentWindow().send 'message', 'open-path', pathToOpen: __filename
|
||||
expect(atom.project.getPaths()[0]).toBe __dirname
|
||||
|
||||
describe "when the opened path does not exist but its parent directory does", ->
|
||||
it "sets the project path to the opened path's parent directory", ->
|
||||
pathToOpen = path.join(__dirname, 'this-path-does-not-exist.txt')
|
||||
atom.getCurrentWindow().send 'message', 'open-path', {pathToOpen}
|
||||
expect(atom.project.getPaths()[0]).toBe __dirname
|
||||
describe "when the opened path does not exist but its parent directory does", ->
|
||||
it "adds the parent directory to the project paths", ->
|
||||
pathToOpen = path.join(__dirname, 'this-path-does-not-exist.txt')
|
||||
atom.getCurrentWindow().send 'message', 'open-locations', [{pathToOpen}]
|
||||
expect(atom.project.getPaths()[0]).toBe __dirname
|
||||
|
||||
describe "when the opened path is a file", ->
|
||||
it "opens it in the workspace", ->
|
||||
atom.getCurrentWindow().send 'message', 'open-path', pathToOpen: __filename
|
||||
|
||||
pathToOpen = __filename
|
||||
atom.getCurrentWindow().send 'message', 'open-locations', [{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", ->
|
||||
atom.getCurrentWindow().send 'message', 'open-path', pathToOpen: __dirname
|
||||
|
||||
pathToOpen = __dirname
|
||||
atom.getCurrentWindow().send 'message', 'open-locations', [{pathToOpen}]
|
||||
expect(atom.workspace.open.callCount).toBe 0
|
||||
|
||||
@@ -95,9 +95,9 @@ class Atom extends Model
|
||||
when 'spec'
|
||||
filename = 'spec'
|
||||
when 'editor'
|
||||
{initialPath} = @getLoadSettings()
|
||||
if initialPath
|
||||
sha1 = crypto.createHash('sha1').update(initialPath).digest('hex')
|
||||
{initialPaths} = @getLoadSettings()
|
||||
if initialPaths
|
||||
sha1 = crypto.createHash('sha1').update(initialPaths.join("\n")).digest('hex')
|
||||
filename = "editor-#{sha1}"
|
||||
|
||||
if filename
|
||||
@@ -704,7 +704,7 @@ class Atom extends Model
|
||||
Project = require './project'
|
||||
|
||||
startTime = Date.now()
|
||||
@project ?= @deserializers.deserialize(@state.project) ? new Project(paths: [@getLoadSettings().initialPath])
|
||||
@project ?= @deserializers.deserialize(@state.project) ? new Project()
|
||||
@deserializeTimings.project = Date.now() - startTime
|
||||
|
||||
deserializeWorkspaceView: ->
|
||||
@@ -747,7 +747,7 @@ class Atom extends Model
|
||||
# Notify the browser project of the window's current project path
|
||||
watchProjectPath: ->
|
||||
onProjectPathChanged = =>
|
||||
ipc.send('window-command', 'project-path-changed', @project.getPaths()[0])
|
||||
ipc.send('window-command', 'project-path-changed', @project.getPaths())
|
||||
@subscribe @project.onDidChangePaths(onProjectPathChanged)
|
||||
onProjectPathChanged()
|
||||
|
||||
|
||||
@@ -311,9 +311,9 @@ class AtomApplication
|
||||
else
|
||||
@openPath({pathToOpen})
|
||||
|
||||
# Returns the {AtomWindow} for the given path.
|
||||
windowForPath: (pathToOpen) ->
|
||||
_.find @windows, (atomWindow) -> atomWindow.containsPath(pathToOpen)
|
||||
# Returns the {AtomWindow} for the given paths.
|
||||
windowForPaths: (pathsToOpen) ->
|
||||
_.find @windows, (atomWindow) -> atomWindow.containsPaths(pathsToOpen)
|
||||
|
||||
# Returns the {AtomWindow} for the given ipc event.
|
||||
windowForEvent: ({sender}) ->
|
||||
@@ -327,49 +327,35 @@ class AtomApplication
|
||||
# Public: Opens multiple paths, in existing windows if possible.
|
||||
#
|
||||
# options -
|
||||
# :pathsToOpen - The array of file paths to open
|
||||
# :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.
|
||||
# :window - {AtomWindow} to open file paths in.
|
||||
openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, window}) ->
|
||||
for pathToOpen in pathsToOpen ? []
|
||||
@openPath({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, window})
|
||||
openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, window}) ->
|
||||
@openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, window})
|
||||
|
||||
# Public: Opens a single path, in an existing window if possible.
|
||||
#
|
||||
# options -
|
||||
# :pathToOpen - The file path to open
|
||||
# :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.
|
||||
openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, window}={}) ->
|
||||
{pathToOpen, initialLine, initialColumn} = @locationForPathToOpen(pathToOpen)
|
||||
pathToOpen = fs.normalize(pathToOpen)
|
||||
openPaths: ({pathsToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, window}={}) ->
|
||||
pathsToOpen = (fs.normalize(pathToOpen) for pathToOpen in pathsToOpen)
|
||||
locationsToOpen = (@locationForPathToOpen(pathToOpen) for pathToOpen in pathsToOpen)
|
||||
|
||||
unless pidToKillWhenClosed or newWindow
|
||||
pathToOpenStat = fs.statSyncNoException(pathToOpen)
|
||||
|
||||
# Default to using the specified window or the last focused window
|
||||
currentWindow = window ? @lastFocusedWindow
|
||||
|
||||
if pathToOpenStat.isFile?()
|
||||
# Open the file in the current window
|
||||
existingWindow = currentWindow
|
||||
else if pathToOpenStat.isDirectory?()
|
||||
# Open the folder in the current window if it doesn't have a path
|
||||
existingWindow = currentWindow unless currentWindow?.hasProjectPath()
|
||||
|
||||
# Don't reuse windows in dev mode
|
||||
existingWindow ?= @windowForPath(pathToOpen) unless devMode
|
||||
unless pidToKillWhenClosed or newWindow # or devMode
|
||||
existingWindow = @windowForPaths(pathsToOpen)
|
||||
|
||||
if existingWindow?
|
||||
openedWindow = existingWindow
|
||||
openedWindow.openPath(pathToOpen, initialLine, initialColumn)
|
||||
openedWindow.openLocations(locationsToOpen)
|
||||
if openedWindow.isMinimized()
|
||||
openedWindow.restore()
|
||||
else
|
||||
@@ -382,7 +368,7 @@ class AtomApplication
|
||||
|
||||
bootstrapScript ?= require.resolve('../window-bootstrap')
|
||||
resourcePath ?= @resourcePath
|
||||
openedWindow = new AtomWindow({pathToOpen, initialLine, initialColumn, bootstrapScript, resourcePath, devMode, safeMode, windowDimensions})
|
||||
openedWindow = new AtomWindow({locationsToOpen, bootstrapScript, resourcePath, devMode, safeMode, windowDimensions})
|
||||
|
||||
if pidToKillWhenClosed?
|
||||
@pidsToOpenWindows[pidToKillWhenClosed] = openedWindow
|
||||
|
||||
@@ -18,7 +18,8 @@ class AtomWindow
|
||||
isSpec: null
|
||||
|
||||
constructor: (settings={}) ->
|
||||
{@resourcePath, pathToOpen, initialLine, initialColumn, @isSpec, @exitWhenDone, @safeMode, @devMode} = settings
|
||||
{@resourcePath, pathToOpen, @locationsToOpen, @isSpec, @exitWhenDone, @safeMode, @devMode} = settings
|
||||
@locationsToOpen ?= [{pathToOpen}] if pathToOpen
|
||||
|
||||
# Normalize to make sure drive letter case is consistent on Windows
|
||||
@resourcePath = path.normalize(@resourcePath) if @resourcePath
|
||||
@@ -51,21 +52,24 @@ class AtomWindow
|
||||
@constructor.includeShellLoadTime = false
|
||||
loadSettings.shellLoadTime ?= Date.now() - global.shellStartTime
|
||||
|
||||
loadSettings.initialPath = pathToOpen
|
||||
if fs.statSyncNoException(pathToOpen).isFile?()
|
||||
loadSettings.initialPath = path.dirname(pathToOpen)
|
||||
loadSettings.initialPaths = for {pathToOpen} in (@locationsToOpen ? [])
|
||||
if fs.statSyncNoException(pathToOpen).isFile?()
|
||||
path.dirname(pathToOpen)
|
||||
else
|
||||
pathToOpen
|
||||
loadSettings.initialPaths.sort()
|
||||
|
||||
@browserWindow.loadSettings = loadSettings
|
||||
@browserWindow.once 'window:loaded', =>
|
||||
@emit 'window:loaded'
|
||||
@loaded = true
|
||||
|
||||
@browserWindow.on 'project-path-changed', (@projectPath) =>
|
||||
@browserWindow.on 'project-path-changed', (@projectPaths) =>
|
||||
|
||||
@browserWindow.loadUrl @getUrl(loadSettings)
|
||||
@browserWindow.focusOnWebView() if @isSpec
|
||||
|
||||
@openPath(pathToOpen, initialLine, initialColumn) unless @isSpecWindow()
|
||||
@openLocations(@locationsToOpen) unless @isSpecWindow()
|
||||
|
||||
getUrl: (loadSettingsObj) ->
|
||||
# Ignore the windowState when passing loadSettings via URL, since it could
|
||||
@@ -79,10 +83,7 @@ class AtomWindow
|
||||
slashes: true
|
||||
query: {loadSettings: JSON.stringify(loadSettings)}
|
||||
|
||||
hasProjectPath: -> @projectPath?.length > 0
|
||||
|
||||
getInitialPath: ->
|
||||
@browserWindow.loadSettings.initialPath
|
||||
hasProjectPath: -> @projectPaths?.length > 0
|
||||
|
||||
setupContextMenu: ->
|
||||
ContextMenu = null
|
||||
@@ -91,20 +92,25 @@ class AtomWindow
|
||||
ContextMenu ?= require './context-menu'
|
||||
new ContextMenu(menuTemplate, this)
|
||||
|
||||
containsPaths: (paths) ->
|
||||
for pathToCheck in paths
|
||||
return false unless @containsPath(pathToCheck)
|
||||
true
|
||||
|
||||
containsPath: (pathToCheck) ->
|
||||
initialPath = @getInitialPath()
|
||||
if not initialPath
|
||||
false
|
||||
else if not pathToCheck
|
||||
false
|
||||
else if pathToCheck is initialPath
|
||||
true
|
||||
else if fs.statSyncNoException(pathToCheck).isDirectory?()
|
||||
false
|
||||
else if pathToCheck.indexOf(path.join(initialPath, path.sep)) is 0
|
||||
true
|
||||
else
|
||||
false
|
||||
@projectPaths.some (projectPath) ->
|
||||
if not projectPath
|
||||
false
|
||||
else if not pathToCheck
|
||||
false
|
||||
else if pathToCheck is projectPath
|
||||
true
|
||||
else if fs.statSyncNoException(pathToCheck).isDirectory?()
|
||||
false
|
||||
else if pathToCheck.indexOf(path.join(projectPath, path.sep)) is 0
|
||||
true
|
||||
else
|
||||
false
|
||||
|
||||
handleEvents: ->
|
||||
@browserWindow.on 'closed', =>
|
||||
@@ -148,11 +154,14 @@ class AtomWindow
|
||||
@browserWindow.focusOnWebView() unless @isWindowClosing
|
||||
|
||||
openPath: (pathToOpen, initialLine, initialColumn) ->
|
||||
@openLocations([{pathToOpen, initialLine, initialColumn}])
|
||||
|
||||
openLocations: (locationsToOpen) ->
|
||||
if @loaded
|
||||
@focus()
|
||||
@sendMessage 'open-path', {pathToOpen, initialLine, initialColumn}
|
||||
@sendMessage 'open-locations', locationsToOpen
|
||||
else
|
||||
@browserWindow.once 'window:loaded', => @openPath(pathToOpen, initialLine, initialColumn)
|
||||
@browserWindow.once 'window:loaded', => @openLocations(locationsToOpen)
|
||||
|
||||
sendMessage: (message, detail) ->
|
||||
@browserWindow.webContents.send 'message', message, detail
|
||||
|
||||
@@ -184,6 +184,11 @@ class Project extends Model
|
||||
projectPath
|
||||
else
|
||||
path.dirname(projectPath)
|
||||
|
||||
return if @getPaths().some (existingPath) ->
|
||||
(directoryPath is existingPath) or
|
||||
(directoryPath.indexOf(path.join(existingPath, path.sep)) is 0)
|
||||
|
||||
directory = new Directory(directoryPath)
|
||||
@rootDirectories.push(directory)
|
||||
|
||||
|
||||
@@ -17,15 +17,13 @@ class WindowEventHandler
|
||||
|
||||
@subscribe ipc, 'message', (message, detail) ->
|
||||
switch message
|
||||
when 'open-path'
|
||||
{pathToOpen, initialLine, initialColumn} = detail
|
||||
when 'open-locations'
|
||||
for {pathToOpen, initialLine, initialColumn} in detail
|
||||
if pathToOpen and (fs.existsSync(pathToOpen) or fs.existsSync(path.dirname(pathToOpen)))
|
||||
atom.project?.addPath(pathToOpen)
|
||||
|
||||
unless atom.project?.getPaths().length
|
||||
if fs.existsSync(pathToOpen) or fs.existsSync(path.dirname(pathToOpen))
|
||||
atom.project?.setPaths([pathToOpen])
|
||||
|
||||
unless fs.isDirectorySync(pathToOpen)
|
||||
atom.workspace?.open(pathToOpen, {initialLine, initialColumn})
|
||||
unless fs.isDirectorySync(pathToOpen)
|
||||
atom.workspace?.open(pathToOpen, {initialLine, initialColumn})
|
||||
|
||||
when 'update-available'
|
||||
atom.updateAvailable(detail)
|
||||
|
||||
Reference in New Issue
Block a user