mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2025-01-03 20:33:33 +03:00
Merge branch 'master' into ns-switch-to-display-layers
# Conflicts: # src/text-editor.coffee
This commit is contained in:
commit
3b46d7f50b
@ -6,6 +6,6 @@
|
||||
"url": "https://github.com/atom/atom.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"atom-package-manager": "1.9.3"
|
||||
"atom-package-manager": "1.10.0"
|
||||
}
|
||||
}
|
||||
|
14
package.json
14
package.json
@ -36,7 +36,7 @@
|
||||
"key-path-helpers": "^0.4.0",
|
||||
"less-cache": "0.23",
|
||||
"line-top-index": "0.2.0",
|
||||
"marked": "^0.3.4",
|
||||
"marked": "^0.3.5",
|
||||
"normalize-package-data": "^2.0.0",
|
||||
"nslog": "^3",
|
||||
"ohnogit": "0.0.11",
|
||||
@ -77,7 +77,7 @@
|
||||
"autocomplete-atom-api": "0.10.0",
|
||||
"autocomplete-css": "0.11.1",
|
||||
"autocomplete-html": "0.7.2",
|
||||
"autocomplete-plus": "2.30.0",
|
||||
"autocomplete-plus": "2.31.0",
|
||||
"autocomplete-snippets": "1.10.0",
|
||||
"autoflow": "0.27.0",
|
||||
"autosave": "0.23.1",
|
||||
@ -87,7 +87,7 @@
|
||||
"command-palette": "0.38.0",
|
||||
"deprecation-cop": "0.54.1",
|
||||
"dev-live-reload": "0.47.0",
|
||||
"encoding-selector": "0.21.0",
|
||||
"encoding-selector": "0.22.0",
|
||||
"exception-reporting": "0.38.1",
|
||||
"fuzzy-finder": "1.0.5",
|
||||
"git-diff": "1.0.1",
|
||||
@ -97,20 +97,20 @@
|
||||
"image-view": "0.57.0",
|
||||
"incompatible-packages": "0.26.1",
|
||||
"keybinding-resolver": "0.35.0",
|
||||
"line-ending-selector": "0.4.1",
|
||||
"line-ending-selector": "0.5.0",
|
||||
"link": "0.31.1",
|
||||
"markdown-preview": "0.158.0",
|
||||
"metrics": "0.53.1",
|
||||
"notifications": "0.63.2",
|
||||
"open-on-github": "1.1.0",
|
||||
"package-generator": "1.0.0",
|
||||
"settings-view": "0.235.1",
|
||||
"settings-view": "0.236.0",
|
||||
"snippets": "1.0.2",
|
||||
"spell-check": "0.67.1",
|
||||
"status-bar": "1.2.6",
|
||||
"styleguide": "0.45.2",
|
||||
"symbols-view": "0.112.0",
|
||||
"tabs": "0.93.1",
|
||||
"symbols-view": "0.113.0",
|
||||
"tabs": "0.93.2",
|
||||
"timecop": "0.33.1",
|
||||
"tree-view": "0.206.2",
|
||||
"update-package-dependencies": "0.10.0",
|
||||
|
@ -74,6 +74,13 @@ describe "CommandRegistry", ->
|
||||
grandchild.dispatchEvent(new CustomEvent('command', bubbles: true))
|
||||
expect(calls).toEqual ['.foo.bar', '.bar', '.foo']
|
||||
|
||||
it "orders inline listeners by reverse registration order", ->
|
||||
calls = []
|
||||
registry.add child, 'command', -> calls.push('child1')
|
||||
registry.add child, 'command', -> calls.push('child2')
|
||||
child.dispatchEvent(new CustomEvent('command', bubbles: true))
|
||||
expect(calls).toEqual ['child2', 'child1']
|
||||
|
||||
it "stops bubbling through ancestors when .stopPropagation() is called on the event", ->
|
||||
calls = []
|
||||
|
||||
|
@ -917,6 +917,82 @@ describe "Pane", ->
|
||||
expect(item1.save).not.toHaveBeenCalled()
|
||||
expect(pane.isDestroyed()).toBe false
|
||||
|
||||
describe "when item fails to save", ->
|
||||
[pane, item1, item2] = []
|
||||
|
||||
beforeEach ->
|
||||
pane = new Pane({items: [new Item("A"), new Item("B")], applicationDelegate: atom.applicationDelegate, config: atom.config})
|
||||
[item1, item2] = pane.getItems()
|
||||
|
||||
item1.shouldPromptToSave = -> true
|
||||
item1.getURI = -> "/test/path"
|
||||
|
||||
item1.save = jasmine.createSpy("save").andCallFake ->
|
||||
error = new Error("EACCES, permission denied '/test/path'")
|
||||
error.path = '/test/path'
|
||||
error.code = 'EACCES'
|
||||
throw error
|
||||
|
||||
it "does not destroy the pane if save fails and user clicks cancel", ->
|
||||
confirmations = 0
|
||||
confirm.andCallFake ->
|
||||
confirmations++
|
||||
if confirmations is 1
|
||||
return 0 # click save
|
||||
else
|
||||
return 1 # click cancel
|
||||
|
||||
pane.close()
|
||||
|
||||
expect(atom.applicationDelegate.confirm).toHaveBeenCalled()
|
||||
expect(confirmations).toBe(2)
|
||||
expect(item1.save).toHaveBeenCalled()
|
||||
expect(pane.isDestroyed()).toBe false
|
||||
|
||||
it "does destroy the pane if the user saves the file under a new name", ->
|
||||
item1.saveAs = jasmine.createSpy("saveAs").andReturn(true)
|
||||
|
||||
confirmations = 0
|
||||
confirm.andCallFake ->
|
||||
confirmations++
|
||||
return 0 # save and then save as
|
||||
|
||||
showSaveDialog.andReturn("new/path")
|
||||
|
||||
pane.close()
|
||||
|
||||
expect(atom.applicationDelegate.confirm).toHaveBeenCalled()
|
||||
expect(confirmations).toBe(2)
|
||||
expect(atom.applicationDelegate.showSaveDialog).toHaveBeenCalled()
|
||||
expect(item1.save).toHaveBeenCalled()
|
||||
expect(item1.saveAs).toHaveBeenCalled()
|
||||
expect(pane.isDestroyed()).toBe true
|
||||
|
||||
it "asks again if the saveAs also fails", ->
|
||||
item1.saveAs = jasmine.createSpy("saveAs").andCallFake ->
|
||||
error = new Error("EACCES, permission denied '/test/path'")
|
||||
error.path = '/test/path'
|
||||
error.code = 'EACCES'
|
||||
throw error
|
||||
|
||||
confirmations = 0
|
||||
confirm.andCallFake ->
|
||||
confirmations++
|
||||
if confirmations < 3
|
||||
return 0 # save, save as, save as
|
||||
return 2 # don't save
|
||||
|
||||
showSaveDialog.andReturn("new/path")
|
||||
|
||||
pane.close()
|
||||
|
||||
expect(atom.applicationDelegate.confirm).toHaveBeenCalled()
|
||||
expect(confirmations).toBe(3)
|
||||
expect(atom.applicationDelegate.showSaveDialog).toHaveBeenCalled()
|
||||
expect(item1.save).toHaveBeenCalled()
|
||||
expect(item1.saveAs).toHaveBeenCalled()
|
||||
expect(pane.isDestroyed()).toBe true
|
||||
|
||||
describe "::destroy()", ->
|
||||
[container, pane1, pane2] = []
|
||||
|
||||
|
@ -10,6 +10,7 @@ describe "TextEditorRegistry", ->
|
||||
it "gets added to the list of registered editors", ->
|
||||
editor = {}
|
||||
registry.add(editor)
|
||||
expect(editor.registered).toBe true
|
||||
expect(registry.editors.size).toBe 1
|
||||
expect(registry.editors.has(editor)).toBe(true)
|
||||
|
||||
@ -19,6 +20,16 @@ describe "TextEditorRegistry", ->
|
||||
expect(registry.editors.size).toBe 1
|
||||
disposable.dispose()
|
||||
expect(registry.editors.size).toBe 0
|
||||
expect(editor.registered).toBe false
|
||||
|
||||
it "can be removed", ->
|
||||
editor = {}
|
||||
registry.add(editor)
|
||||
expect(registry.editors.size).toBe 1
|
||||
success = registry.remove(editor)
|
||||
expect(success).toBe true
|
||||
expect(registry.editors.size).toBe 0
|
||||
expect(editor.registered).toBe false
|
||||
|
||||
describe "when the registry is observed", ->
|
||||
it "calls the callback for current and future editors until unsubscribed", ->
|
||||
|
@ -244,11 +244,14 @@ class CommandRegistry
|
||||
(@selectorBasedListenersByCommandName[event.type] ? [])
|
||||
.filter (listener) -> currentTarget.webkitMatchesSelector(listener.selector)
|
||||
.sort (a, b) -> a.compare(b)
|
||||
listeners = listeners.concat(selectorBasedListeners)
|
||||
listeners = selectorBasedListeners.concat(listeners)
|
||||
|
||||
matched = true if listeners.length > 0
|
||||
|
||||
for listener in listeners
|
||||
# Call inline listeners first in reverse registration order,
|
||||
# and selector-based listeners by specificity and reverse
|
||||
# registration order.
|
||||
for listener in listeners by -1
|
||||
break if immediatePropagationStopped
|
||||
listener.callback.call(currentTarget, dispatchedEvent)
|
||||
|
||||
@ -271,8 +274,8 @@ class SelectorBasedListener
|
||||
@sequenceNumber = SequenceCount++
|
||||
|
||||
compare: (other) ->
|
||||
other.specificity - @specificity or
|
||||
other.sequenceNumber - @sequenceNumber
|
||||
@specificity - other.specificity or
|
||||
@sequenceNumber - other.sequenceNumber
|
||||
|
||||
class InlineListener
|
||||
constructor: (@callback) ->
|
||||
|
@ -577,15 +577,23 @@ class Pane extends Model
|
||||
else
|
||||
return true
|
||||
|
||||
chosen = @applicationDelegate.confirm
|
||||
message: "'#{item.getTitle?() ? uri}' has changes, do you want to save them?"
|
||||
detailedMessage: "Your changes will be lost if you close this item without saving."
|
||||
buttons: ["Save", "Cancel", "Don't Save"]
|
||||
saveDialog = (saveButtonText, saveFn, message) =>
|
||||
chosen = @applicationDelegate.confirm
|
||||
message: message
|
||||
detailedMessage: "Your changes will be lost if you close this item without saving."
|
||||
buttons: [saveButtonText, "Cancel", "Don't save"]
|
||||
switch chosen
|
||||
when 0 then saveFn(item, saveError)
|
||||
when 1 then false
|
||||
when 2 then true
|
||||
|
||||
switch chosen
|
||||
when 0 then @saveItem(item, -> true)
|
||||
when 1 then false
|
||||
when 2 then true
|
||||
saveError = (error) =>
|
||||
if error
|
||||
saveDialog("Save as", @saveItemAs, "'#{item.getTitle?() ? uri}' could not be saved.\nError: #{@getMessageForErrorCode(error.code)}")
|
||||
else
|
||||
true
|
||||
|
||||
saveDialog("Save", @saveItem, "'#{item.getTitle?() ? uri}' has changes, do you want to save them?")
|
||||
|
||||
# Public: Save the active item.
|
||||
saveActiveItem: (nextAction) ->
|
||||
@ -602,9 +610,11 @@ class Pane extends Model
|
||||
# Public: Save the given item.
|
||||
#
|
||||
# * `item` The item to save.
|
||||
# * `nextAction` (optional) {Function} which will be called after the item is
|
||||
# successfully saved.
|
||||
saveItem: (item, nextAction) ->
|
||||
# * `nextAction` (optional) {Function} which will be called with no argument
|
||||
# after the item is successfully saved, or with the error if it failed.
|
||||
# The return value will be that of `nextAction` or `undefined` if it was not
|
||||
# provided
|
||||
saveItem: (item, nextAction) =>
|
||||
if typeof item?.getURI is 'function'
|
||||
itemURI = item.getURI()
|
||||
else if typeof item?.getUri is 'function'
|
||||
@ -613,9 +623,12 @@ class Pane extends Model
|
||||
if itemURI?
|
||||
try
|
||||
item.save?()
|
||||
nextAction?()
|
||||
catch error
|
||||
@handleSaveError(error, item)
|
||||
nextAction?()
|
||||
if nextAction
|
||||
nextAction(error)
|
||||
else
|
||||
@handleSaveError(error, item)
|
||||
else
|
||||
@saveItemAs(item, nextAction)
|
||||
|
||||
@ -623,9 +636,11 @@ class Pane extends Model
|
||||
# path they select.
|
||||
#
|
||||
# * `item` The item to save.
|
||||
# * `nextAction` (optional) {Function} which will be called after the item is
|
||||
# successfully saved.
|
||||
saveItemAs: (item, nextAction) ->
|
||||
# * `nextAction` (optional) {Function} which will be called with no argument
|
||||
# after the item is successfully saved, or with the error if it failed.
|
||||
# The return value will be that of `nextAction` or `undefined` if it was not
|
||||
# provided
|
||||
saveItemAs: (item, nextAction) =>
|
||||
return unless item?.saveAs?
|
||||
|
||||
saveOptions = item.getSaveDialogOptions?() ? {}
|
||||
@ -634,9 +649,12 @@ class Pane extends Model
|
||||
if newItemPath
|
||||
try
|
||||
item.saveAs(newItemPath)
|
||||
nextAction?()
|
||||
catch error
|
||||
@handleSaveError(error, item)
|
||||
nextAction?()
|
||||
if nextAction
|
||||
nextAction(error)
|
||||
else
|
||||
@handleSaveError(error, item)
|
||||
|
||||
# Public: Save all items.
|
||||
saveItems: ->
|
||||
|
@ -26,8 +26,20 @@ class TextEditorRegistry
|
||||
# editor is destroyed.
|
||||
add: (editor) ->
|
||||
@editors.add(editor)
|
||||
editor.registered = true
|
||||
|
||||
@emitter.emit 'did-add-editor', editor
|
||||
new Disposable => @editors.delete(editor)
|
||||
new Disposable => @remove(editor)
|
||||
|
||||
# Remove a `TextEditor`.
|
||||
#
|
||||
# * `editor` The editor to remove.
|
||||
#
|
||||
# Returns a {Boolean} indicating whether the editor was successfully removed.
|
||||
remove: (editor) ->
|
||||
removed = @editors.delete(editor)
|
||||
editor.registered = false
|
||||
removed
|
||||
|
||||
# Invoke the given callback with all the current and future registered
|
||||
# `TextEditors`.
|
||||
|
@ -76,6 +76,7 @@ class TextEditor extends Model
|
||||
defaultCharWidth: null
|
||||
height: null
|
||||
width: null
|
||||
registered: false
|
||||
|
||||
Object.defineProperty @prototype, "element",
|
||||
get: -> @getElement()
|
||||
@ -202,7 +203,7 @@ class TextEditor extends Model
|
||||
tokenizedBuffer: tokenizedBufferState
|
||||
largeFileMode: @largeFileMode
|
||||
displayLayerId: @displayLayer.id
|
||||
registered: atom.textEditors.editors.has this
|
||||
registered: @registered
|
||||
|
||||
subscribeToBuffer: ->
|
||||
@buffer.retain()
|
||||
|
@ -1092,7 +1092,7 @@ class Workspace extends Model
|
||||
if editor.getPath()
|
||||
checkoutHead = =>
|
||||
@project.repositoryForDirectory(new Directory(editor.getDirectoryPath()))
|
||||
.then (repository) =>
|
||||
.then (repository) ->
|
||||
repository?.async.checkoutHeadForEditor(editor)
|
||||
|
||||
if @config.get('editor.confirmCheckoutHeadRevision')
|
||||
|
Loading…
Reference in New Issue
Block a user