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

Deprecate individual Marker events #152

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
52 changes: 37 additions & 15 deletions spec/display-marker-layer-spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -131,24 +131,46 @@ describe "DisplayMarkerLayer", ->
marker.destroy()
expect(destroyEventCount).toBe 1

it "emits update events when markers are created, updated directly, updated indirectly, or destroyed", (done) ->
buffer = new TextBuffer(text: 'hello world')
it "emits update events when markers are created, updated directly, updated indirectly, or destroyed", ->
buffer = new TextBuffer(text: 'hello world\nhow are you?')
displayLayer = buffer.addDisplayLayer(tabLength: 4)
markerLayer = displayLayer.addMarkerLayer()

updateEventCount = 0
markerLayer.onDidUpdate ->
updateEventCount++
if updateEventCount is 1
marker.setScreenRange([[0, 5], [1, 0]])
else if updateEventCount is 2
buffer.insert([0, 0], '\t')
else if updateEventCount is 3
marker.destroy()
else if updateEventCount is 4
done()

marker = markerLayer.markScreenRange([[0, 4], [1, 4]])
events = []
markerLayer.onDidUpdate (event) -> events.push({
created: Array.from(event.created),
updated: Array.from(event.updated),
touched: Array.from(event.touched),
destroyed: Array.from(event.destroyed)
})

events = []
marker = markerLayer.markScreenRange([[0, 4], [1, 4]], {invalidate: 'inside'})
expect(events).toEqual([
{created: [marker.id], updated: [], touched: [], destroyed: []}
])

events = []
marker.setScreenRange([[0, 5], [1, 0]])
expect(events).toEqual([
{created: [], updated: [marker.id], touched: [], destroyed: []}
])

events = []
buffer.insert([0, 8], 'foo')
expect(events).toEqual([
{created: [], updated: [], touched: [marker.id], destroyed: []}
])

events = []
buffer.insert([0, 0], '\t')
expect(events).toEqual([])

events = []
marker.destroy()
expect(events).toEqual([
{created: [], updated: [], touched: [], destroyed: [marker.id]}
])

it "allows markers to be copied", ->
buffer = new TextBuffer(text: '\ta\tbc\tdef\tg\n\th')
Expand Down
135 changes: 116 additions & 19 deletions spec/marker-layer-spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ describe "MarkerLayer", ->

beforeEach ->
jasmine.addCustomEqualityTester(require("underscore-plus").isEqual)
buffer = new TextBuffer(text: "abcdefghijklmnopqrstuvwxyz")
buffer = new TextBuffer(text: """
Lorem ipsum dolor sit amet,
consectetur adipisicing elit,
sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris.
""")
layer1 = buffer.addMarkerLayer()
layer2 = buffer.addMarkerLayer()

Expand Down Expand Up @@ -68,6 +75,26 @@ describe "MarkerLayer", ->
expect(createEventCount).toBe 1
expect(updateEventCount).toBe 2

describe "::getLastMarker()", ->
it "returns the last (in terms of time) non-destroyed marker added to the layer", ->
marker1 = layer1.markRange([[0, 0], [0, 3]])
marker2 = layer1.markRange([[0, 2], [0, 6]])
marker3 = layer1.markRange([[0, 8], [0, 10]])
marker4 = layer1.markRange([[1, 0], [1, 10]])
expect(layer1.getLastMarker()).toBe(marker4)

marker4.destroy()
expect(layer1.getLastMarker()).toBe(marker3)

marker1.destroy()
expect(layer1.getLastMarker()).toBe(marker3)

marker3.destroy()
expect(layer1.getLastMarker()).toBe(marker2)

marker2.destroy()
expect(layer1.getLastMarker()).toBeFalsy()

describe "when destroyInvalidatedMarkers is enabled for the layer", ->
it "destroys markers when they are invalidated via a splice", ->
layer3 = buffer.addMarkerLayer(destroyInvalidatedMarkers: true)
Expand Down Expand Up @@ -169,24 +196,94 @@ describe "MarkerLayer", ->
expect(layer2.findMarkers(containsPoint: [0, 4])).toEqual [layer2Marker]

describe "::onDidUpdate", ->
it "notifies observers asynchronously when markers are created, updated, or destroyed", (done) ->
updateCount = 0
layer1.onDidUpdate ->
updateCount++
if updateCount is 1
marker1.setRange([[1, 2], [3, 4]])
marker2.setRange([[4, 5], [6, 7]])
else if updateCount is 2
buffer.insert([0, 1], "xxx")
buffer.insert([0, 1], "yyy")
else if updateCount is 3
marker1.destroy()
marker2.destroy()
else if updateCount is 4
done()

marker1 = layer1.markRange([[0, 2], [0, 4]])
marker2 = layer1.markRange([[0, 6], [0, 8]])
it "notifies observers synchronously or at the end of a transaction when markers are created, updated directly, updated indirectly, or destroyed", ->
layer = buffer.addMarkerLayer({maintainHistory: true})
events = []
[marker1, marker2, marker3] = []
layer.onDidUpdate (event) -> events.push({
created: Array.from(event.created),
updated: Array.from(event.updated),
touched: Array.from(event.touched),
destroyed: Array.from(event.destroyed)
})

buffer.transact ->
marker1 = layer.markRange([[0, 2], [0, 4]])
marker2 = layer.markRange([[0, 6], [0, 8]])
expect(events.length).toBe(0)

marker3 = layer.markRange([[4, 0], [4, 5]])

expect(events).toEqual([
{created: [marker1.id, marker2.id], updated: [], touched: [], destroyed: []},
{created: [marker3.id], updated: [], touched: [], destroyed: []}
])

events = []
buffer.transact ->
marker1.setRange([[1, 2], [3, 4]])
marker2.setRange([[3, 10], [4, 5]])
marker3.destroy()

expect(events).toEqual([
{created: [], updated: [marker1.id, marker2.id], touched: [], destroyed: [marker3.id]}
])

events = []
buffer.transact ->
buffer.insert([1, 3], "xxx")
buffer.insert([2, 0], "yyy")
buffer.insert([1, 5], 'zzz')

expect(events).toEqual([
{created: [], updated: [], touched: [marker1.id], destroyed: []},
{created: [], updated: [], touched: [marker1.id], destroyed: []}
])

events = []
buffer.undo()
buffer.undo()

expect(events).toEqual([
{created: [], updated: [], touched: [marker1.id], destroyed: []},
{created: [], updated: [], touched: [marker1.id], destroyed: []}
])

events = []
buffer.transact ->
buffer.insert([1, 3], 'aaa')
buffer.insert([3, 11], 'bbb')
buffer.transact ->
buffer.insert([1, 9], 'ccc')
buffer.insert([1, 12], 'ddd')
buffer.insert([4, 0], 'eee')
buffer.insert([4, 3], 'fff')

expect(events).toEqual([
{created: [], updated: [], touched: [marker1.id, marker2.id], destroyed: []},
{created: [], updated: [], touched: [marker2.id], destroyed: []}
])

events = []
buffer.transact ->
buffer.insert([3, 11], 'ggg')
buffer.undo()
marker1.clearTail()
marker2.clearTail()

expect(events).toEqual([
{created: [], updated: [], touched: [marker2.id], destroyed: []},
{created: [], updated: [marker1.id, marker2.id], touched: [], destroyed: []}
])

events = []
buffer.transact ->
marker1.destroy()
marker2.destroy()

expect(events).toEqual([
{created: [], updated: [], touched: [], destroyed: [marker1.id, marker2.id]}
])

describe "::copy", ->
it "creates a new marker layer with markers in the same states", ->
Expand Down
30 changes: 19 additions & 11 deletions src/display-marker-layer.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,21 @@ class DisplayMarkerLayer
onDidDestroy: (callback) ->
@emitter.on('did-destroy', callback)

# Public: Subscribe to be notified asynchronously whenever markers are
# created, updated, or destroyed on this layer. *Prefer this method for
# optimal performance when interacting with layers that could contain large
# numbers of markers.*
# Public: Subscribe to be notified whenever markers are created, updated,
# touched (moved because of a textual change), or destroyed on this layer.
# *Prefer this method for optimal performance when interacting with layers
# that could contain large numbers of markers.*
#
# * `callback` A {Function} that will be called with no arguments when changes
# occur on this layer.
#
# Subscribers are notified once, asynchronously when any number of changes
# occur in a given tick of the event loop. You should re-query the layer
# to determine the state of markers in which you're interested in. It may
# be counter-intuitive, but this is much more efficient than subscribing to
# events on individual markers, which are expensive to deliver.
# Subscribers are notified once when any number of changes occur in this
# {MarkerLayer}. The notification gets scheduled either at the end of a
# transaction, or synchronously when a marker changes and no transaction is
# present. You should re-query the layer to determine the state of markers in
# which you're interested in: it may be counter-intuitive, but this is much
# more efficient than subscribing to events on individual markers, which are
# expensive to deliver.
#
# Returns a {Disposable}.
onDidUpdate: (callback) ->
Expand Down Expand Up @@ -234,6 +236,12 @@ class DisplayMarkerLayer
getMarkers: ->
@bufferMarkerLayer.getMarkers().map ({id}) => @getMarker(id)

# Public: Get the last (in terms of time) non-destroyed marker added to this layer.
#
# Returns a {DisplayMarker}.
getLastMarker: ->
@getMarker(@bufferMarkerLayer.getLastMarker()?.id)

# Public: Get the number of markers in the marker layer.
#
# Returns a {Number}.
Expand Down Expand Up @@ -291,8 +299,8 @@ class DisplayMarkerLayer
translateScreenRange: (screenRange, options) ->
@displayLayer.translateScreenRange(screenRange, options)

emitDidUpdate: ->
@emitter.emit('did-update')
emitDidUpdate: (event) ->
@emitter.emit('did-update', event)

emitDidDestroy: ->
@emitter.emit('did-destroy')
Expand Down
Loading