Skip to content
This repository has been archived by the owner on Dec 15, 2022. It is now read-only.

Commit

Permalink
Always update display layer before emitting a marker layer update event
Browse files Browse the repository at this point in the history
Previously, when a change was happening outside of a transaction (e.g.
undo, redo, etc.), we were emitting a marker layer update event as soon
as we spliced each marker layer. This was causing display layers to be
out of date when the marker layer event occurred and could therefore
cause problems if users performed a display layer query display layer
inside the update event.

With this commit, marker layer update events will now always be emitted
after updating display layers, thus fixing the errors we were observing
in Atom (https://circleci.com/gh/atom/atom/2806).
  • Loading branch information
Antonio Scandurra committed Mar 3, 2017
1 parent 2b211c1 commit faa5ccc
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 5 deletions.
11 changes: 11 additions & 0 deletions spec/marker-layer-spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ describe "MarkerLayer", ->
it "notifies observers at the end of the outermost transaction when markers are created, updated, or destroyed", ->
[marker1, marker2] = []

displayLayer = buffer.addDisplayLayer()
displayLayerDidChange = false

updateCount = 0
layer1.onDidUpdate ->
updateCount++
Expand All @@ -193,6 +196,8 @@ describe "MarkerLayer", ->
else if updateCount is 3
marker1.destroy()
marker2.destroy()
else if updateCount is 6
expect(displayLayerDidChange).toBe(true, 'Display layer was updated after marker layer.')

buffer.transact ->
buffer.transact ->
Expand All @@ -205,6 +210,12 @@ describe "MarkerLayer", ->
layer1.markRange([[0, 2], [0, 4]])
expect(updateCount).toBe(5)

# update events happen after updating display layers when there is no parent transaction.
displayLayer.onDidChangeSync ->
displayLayerDidChange = true
buffer.undo()
expect(updateCount).toBe(6)

describe "::clear()", ->
it "destroys all of the layer's markers", (done) ->
buffer = new TextBuffer(text: 'abc')
Expand Down
1 change: 0 additions & 1 deletion src/marker-layer.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,6 @@ class MarkerLayer
marker.destroy()
else
marker.valid = false
@delegate.markersUpdated(this)

restoreFromSnapshot: (snapshots) ->
return unless snapshots?
Expand Down
14 changes: 10 additions & 4 deletions src/text-buffer.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -737,19 +737,25 @@ class TextBuffer
newRange

emitDidChangeEvent: (changeEvent) ->
# 1. Emit the change event on all the registered text decoration layers.
# Emit the change event on all the registered text decoration layers.
@textDecorationLayers.forEach (textDecorationLayer) ->
textDecorationLayer.bufferDidChange(changeEvent)
# 2. Emit the change event on all the registered display layers.
# Emit the change event on all the registered display layers.
changeEventsByDisplayLayer = new Map()
for id, displayLayer of @displayLayers
event = displayLayer.bufferDidChange(changeEvent)
changeEventsByDisplayLayer.set(displayLayer, event)
# 3. Emit a normal `did-change` event for other subscribers too.
# Emit a normal `did-change` event for other subscribers too.
@emitter.emit 'did-change', changeEvent
# 4. Emit a `did-change-sync` event from all the registered display layers.
# Emit a `did-change-sync` event from all the registered display layers.
changeEventsByDisplayLayer.forEach (event, displayLayer) ->
displayLayer.emitDidChangeSyncEvent(event)
# Emit a `did-update` event from all the registered marker layers. If this
# happens inside a nested transaction, the event will be emitted at the end
# of the outermost transaction.
if @markerLayers?
for id, markerLayer of @markerLayers
@markersUpdated(markerLayer)

# Public: Delete the text in the given range.
#
Expand Down

0 comments on commit faa5ccc

Please sign in to comment.