Convert display buffer markers to object-oriented API

This commit is contained in:
Nathan Sobo 2013-04-26 16:45:16 -06:00
parent 482eb6c0de
commit 5403bc647a
3 changed files with 56 additions and 207 deletions

View File

@ -522,42 +522,40 @@ describe "DisplayBuffer", ->
it "allows markers to be created in terms of both screen and buffer coordinates", ->
marker1 = displayBuffer.markScreenRange([[5, 4], [5, 10]])
marker2 = displayBuffer.markBufferRange([[8, 4], [8, 10]])
expect(displayBuffer.getMarkerBufferRange(marker1)).toEqual [[8, 4], [8, 10]]
expect(displayBuffer.getMarkerScreenRange(marker2)).toEqual [[5, 4], [5, 10]]
expect(marker1.getBufferRange()).toEqual [[8, 4], [8, 10]]
expect(marker2.getScreenRange()).toEqual [[5, 4], [5, 10]]
it "allows marker head and tail positions to be manipulated in both screen and buffer coordinates", ->
marker = displayBuffer.markScreenRange([[5, 4], [5, 10]])
displayBuffer.setMarkerHeadScreenPosition(marker, [5, 4])
displayBuffer.setMarkerTailBufferPosition(marker, [5, 4])
expect(displayBuffer.isMarkerReversed(marker)).toBeFalsy()
expect(displayBuffer.getMarkerBufferRange(marker)).toEqual [[5, 4], [8, 4]]
displayBuffer.setMarkerHeadBufferPosition(marker, [5, 4])
displayBuffer.setMarkerTailScreenPosition(marker, [5, 4])
expect(displayBuffer.isMarkerReversed(marker)).toBeTruthy()
expect(displayBuffer.getMarkerBufferRange(marker)).toEqual [[5, 4], [8, 4]]
marker.setHeadScreenPosition([5, 4])
marker.setTailBufferPosition([5, 4])
expect(marker.isReversed()).toBeFalsy()
expect(marker.getBufferRange()).toEqual [[5, 4], [8, 4]]
marker.setHeadBufferPosition([5, 4])
marker.setTailScreenPosition([5, 4])
expect(marker.isReversed()).toBeTruthy()
expect(marker.getBufferRange()).toEqual [[5, 4], [8, 4]]
it "returns whether a position changed when it is assigned", ->
marker = displayBuffer.markScreenRange([[0, 0], [0, 0]])
expect(displayBuffer.setMarkerHeadScreenPosition(marker, [5, 4])).toBeTruthy()
expect(displayBuffer.setMarkerHeadScreenPosition(marker, [5, 4])).toBeFalsy()
expect(displayBuffer.setMarkerHeadBufferPosition(marker, [1, 0])).toBeTruthy()
expect(displayBuffer.setMarkerHeadBufferPosition(marker, [1, 0])).toBeFalsy()
expect(displayBuffer.setMarkerTailScreenPosition(marker, [5, 4])).toBeTruthy()
expect(displayBuffer.setMarkerTailScreenPosition(marker, [5, 4])).toBeFalsy()
expect(displayBuffer.setMarkerTailBufferPosition(marker, [1, 0])).toBeTruthy()
expect(displayBuffer.setMarkerTailBufferPosition(marker, [1, 0])).toBeFalsy()
expect(marker.setHeadScreenPosition([5, 4])).toBeTruthy()
expect(marker.setHeadScreenPosition([5, 4])).toBeFalsy()
expect(marker.setHeadBufferPosition([1, 0])).toBeTruthy()
expect(marker.setHeadBufferPosition([1, 0])).toBeFalsy()
expect(marker.setTailScreenPosition([5, 4])).toBeTruthy()
expect(marker.setTailScreenPosition([5, 4])).toBeFalsy()
expect(marker.setTailBufferPosition([1, 0])).toBeTruthy()
expect(marker.setTailBufferPosition([1, 0])).toBeFalsy()
describe ".observeMarker(marker, callback)", ->
describe "marker observation", ->
[observeHandler, marker, subscription] = []
beforeEach ->
observeHandler = jasmine.createSpy("observeHandler")
marker = displayBuffer.markScreenRange([[5, 4], [5, 10]])
subscription = displayBuffer.observeMarker(marker, observeHandler)
subscription = marker.observe(observeHandler = jasmine.createSpy("observeHandler"))
it "calls the callback whenever the markers head's screen position changes in the buffer or on screen", ->
displayBuffer.setMarkerHeadScreenPosition(marker, [8, 20])
marker.setHeadScreenPosition([8, 20])
expect(observeHandler).toHaveBeenCalled()
expect(observeHandler.argsForCall[0][0]).toEqual {
oldHeadScreenPosition: [5, 10]
@ -621,7 +619,7 @@ describe "DisplayBuffer", ->
}
it "calls the callback whenever the marker tail's position changes in the buffer or on screen", ->
displayBuffer.setMarkerTailScreenPosition(marker, [8, 20])
marker.setTailScreenPosition([8, 20])
expect(observeHandler).toHaveBeenCalled()
expect(observeHandler.argsForCall[0][0]).toEqual {
oldHeadScreenPosition: [5, 10]
@ -691,20 +689,18 @@ describe "DisplayBuffer", ->
it "allows observation subscriptions to be cancelled", ->
subscription.cancel()
displayBuffer.setMarkerHeadScreenPosition(marker, [8, 20])
marker.setHeadScreenPosition([8, 20])
displayBuffer.destroyFoldsContainingBufferRow(4)
expect(observeHandler).not.toHaveBeenCalled()
it "updates the position of markers before emitting buffer change events, but does not notify their observers until the change event", ->
changeHandler = jasmine.createSpy("changeHandler").andCallFake ->
displayBuffer.on 'changed', changeHandler = jasmine.createSpy("changeHandler").andCallFake ->
# calls change handler first
expect(observeHandler).not.toHaveBeenCalled()
# but still updates the markers
expect(displayBuffer.getMarkerScreenRange(marker)).toEqual [[5, 7], [5, 13]]
expect(displayBuffer.getMarkerHeadScreenPosition(marker)).toEqual [5, 13]
expect(displayBuffer.getMarkerTailScreenPosition(marker)).toEqual [5, 7]
displayBuffer.on 'changed', changeHandler
expect(marker.getScreenRange()).toEqual [[5, 7], [5, 13]]
expect(marker.getHeadScreenPosition()).toEqual [5, 13]
expect(marker.getTailScreenPosition()).toEqual [5, 7]
buffer.insert([8, 1], "...")
@ -712,14 +708,13 @@ describe "DisplayBuffer", ->
expect(observeHandler).toHaveBeenCalled()
it "updates the position of markers before emitting change events that aren't caused by a buffer change", ->
changeHandler = jasmine.createSpy("changeHandler").andCallFake ->
displayBuffer.on 'changed', changeHandler = jasmine.createSpy("changeHandler").andCallFake ->
# calls change handler first
expect(observeHandler).not.toHaveBeenCalled()
# but still updates the markers
expect(displayBuffer.getMarkerScreenRange(marker)).toEqual [[8, 4], [8, 10]]
expect(displayBuffer.getMarkerHeadScreenPosition(marker)).toEqual [8, 10]
expect(displayBuffer.getMarkerTailScreenPosition(marker)).toEqual [8, 4]
displayBuffer.on 'changed', changeHandler
expect(marker.getScreenRange()).toEqual [[8, 4], [8, 10]]
expect(marker.getHeadScreenPosition()).toEqual [8, 10]
expect(marker.getTailScreenPosition()).toEqual [8, 4]
displayBuffer.destroyFoldsContainingBufferRow(4)
@ -739,5 +734,6 @@ describe "DisplayBuffer", ->
describe "marker destruction", ->
it "allows markers to be destroyed", ->
marker = displayBuffer.markScreenRange([[5, 4], [5, 10]])
displayBuffer.destroyMarker(marker)
expect(displayBuffer.getMarkerBufferRange(marker)).toBeUndefined()
marker.destroy()(marker)
expect(marker.isValid()).toBeFalsy()
expect(displayBuffer.getMarker(marker.id)).toBeUndefined()

View File

@ -13,8 +13,8 @@ class DisplayBufferMarker
# Internal #
###
constructor: ({@id, @displayBuffer}) ->
@buffer = @displayBuffer.buffer
constructor: ({@bufferMarker, @displayBuffer}) ->
@id = @bufferMarker.id
###
# Public #
@ -37,14 +37,14 @@ class DisplayBufferMarker
#
# Returns a {Range}.
getBufferRange: ->
@buffer.getMarkerRange(@id)
@bufferMarker.getRange()
# Public: Modifies the buffer range of the display marker.
#
# screenRange - The new {Range} to use
# options - A hash of options matching those found in {BufferMarker.setRange}
setBufferRange: (bufferRange, options) ->
@buffer.setMarkerRange(@id, bufferRange, options)
@bufferMarker.setRange(bufferRange, options)
# Public: Retrieves the screen position of the marker's head.
#
@ -64,21 +64,21 @@ class DisplayBufferMarker
#
# Returns a {Point}.
getHeadBufferPosition: ->
@buffer.getMarkerHeadPosition(@id)
@bufferMarker.getHeadPosition()
# Public: Sets the buffer position of the marker's head.
#
# screenRange - The new {Point} to use
# options - A hash of options matching those found in {DisplayBuffer.bufferPositionForScreenPosition}
setHeadBufferPosition: (bufferPosition) ->
@buffer.setMarkerHeadPosition(@id, bufferPosition)
@bufferMarker.setHeadPosition(bufferPosition)
# Public: Retrieves the screen position of the marker's tail.
#
# Returns a {Point}.
getTailScreenPosition: ->
@tailScreenPosition ?= @displayBuffer.screenPositionForBufferPosition(@getTailBufferPosition(), wrapAtSoftNewlines: true)
# Public: Sets the screen position of the marker's tail.
#
# screenRange - The new {Point} to use
@ -91,14 +91,14 @@ class DisplayBufferMarker
#
# Returns a {Point}.
getTailBufferPosition: ->
@buffer.getMarkerTailPosition(@id)
@bufferMarker.getTailPosition()
# Public: Sets the buffer position of the marker's tail.
#
# screenRange - The new {Point} to use
# options - A hash of options matching those found in {DisplayBuffer.bufferPositionForScreenPosition}
setTailBufferPosition: (bufferPosition) ->
@buffer.setMarkerTailPosition(@id, bufferPosition)
@bufferMarker.setTailPosition(bufferPosition)
# Public: Sets the marker's tail to the same position as the marker's head.
#
@ -106,11 +106,11 @@ class DisplayBufferMarker
#
# Returns a {Point} representing the new tail position.
placeTail: ->
@buffer.placeMarkerTail(@id)
@bufferMarker.placeTail()
# Public: Removes the tail from the marker.
clearTail: ->
@buffer.clearMarkerTail(@id)
@bufferMarker.clearTail()
# Public: Sets a callback to be fired whenever the marker is changed.
#
@ -127,6 +127,10 @@ class DisplayBufferMarker
@off 'changed', callback
@unobserveBufferMarkerIfNeeded()
# Returns whether the head precedes the tail in the buffer
isReversed: ->
@bufferMarker.isReversed()
###
# Internal #
###
@ -136,7 +140,7 @@ class DisplayBufferMarker
@getHeadScreenPosition() # memoize current value
@getTailScreenPosition() # memoize current value
@bufferMarkerSubscription =
@buffer.observeMarker @id, ({oldHeadPosition, newHeadPosition, oldTailPosition, newTailPosition, bufferChanged, valid}) =>
@bufferMarker.observe ({oldHeadPosition, newHeadPosition, oldTailPosition, newTailPosition, bufferChanged, valid}) =>
@notifyObservers
oldHeadBufferPosition: oldHeadPosition
newHeadBufferPosition: newHeadPosition

View File

@ -468,7 +468,9 @@ class DisplayBuffer
#
# Returns the {DisplayBufferMarker} (if it exists).
getMarker: (id) ->
@markers[id] ? new DisplayBufferMarker({id, displayBuffer: this})
@markers[id] ? do =>
if bufferMarker = @buffer.getMarker(id)
new DisplayBufferMarker({bufferMarker, displayBuffer: this})
# Public: Retrieves the active markers in the buffer.
#
@ -493,7 +495,7 @@ class DisplayBuffer
#
# Returns a {Number} representing the new marker's ID.
markBufferRange: (args...) ->
@buffer.markRange(args...)
@getMarker(@buffer.markRange(args...).id)
# Public: Constructs a new marker at the given screen position.
#
@ -511,7 +513,7 @@ class DisplayBuffer
#
# Returns a {Number} representing the new marker's ID.
markBufferPosition: (bufferPosition, options) ->
@buffer.markPosition(bufferPosition, options)
@getMarker(@buffer.markPosition(bufferPosition, options).id)
# Public: Removes the marker with the given id.
#
@ -520,159 +522,6 @@ class DisplayBuffer
@buffer.destroyMarker(id)
delete @markers[id]
# Public: Gets the screen range of the display marker.
#
# id - The {Number} of the ID to check
#
# Returns a {Range}.
getMarkerScreenRange: (id) ->
@getMarker(id).getScreenRange()
# Public: Modifies the screen range of the display marker.
#
# id - The {Number} of the ID to change
# screenRange - The new {Range} to use
# options - A hash of options matching those found in {BufferMarker.setRange}
setMarkerScreenRange: (id, screenRange, options) ->
@getMarker(id).setScreenRange(screenRange, options)
# Public: Gets the buffer range of the display marker.
#
# id - The {Number} of the ID to check
#
# Returns a {Range}.
getMarkerBufferRange: (id) ->
@getMarker(id).getBufferRange()
# Public: Modifies the buffer range of the display marker.
#
# id - The {Number} of the ID to change
# screenRange - The new {Range} to use
# options - A hash of options matching those found in {BufferMarker.setRange}
setMarkerBufferRange: (id, bufferRange, options) ->
@getMarker(id).setBufferRange(bufferRange, options)
# Public: Retrieves the screen position of the marker's head.
#
# id - The {Number} of the ID to check
#
# Returns a {Point}.
getMarkerScreenPosition: (id) ->
@getMarkerHeadScreenPosition(id)
# Public: Retrieves the buffer position of the marker's head.
#
# id - The {Number} of the ID to check
#
# Returns a {Point}.
getMarkerBufferPosition: (id) ->
@getMarkerHeadBufferPosition(id)
# Public: Retrieves the screen position of the marker's head.
#
# id - The {Number} of the ID to check
#
# Returns a {Point}.
getMarkerHeadScreenPosition: (id) ->
@getMarker(id).getHeadScreenPosition()
# Public: Sets the screen position of the marker's head.
#
# id - The {Number} of the ID to change
# screenRange - The new {Point} to use
# options - A hash of options matching those found in {DisplayBuffer.bufferPositionForScreenPosition}
setMarkerHeadScreenPosition: (id, screenPosition, options) ->
@getMarker(id).setHeadScreenPosition(screenPosition, options)
# Public: Retrieves the buffer position of the marker's head.
#
# id - The {Number} of the ID to check
#
# Returns a {Point}.
getMarkerHeadBufferPosition: (id) ->
@getMarker(id).getHeadBufferPosition()
# Public: Sets the buffer position of the marker's head.
#
# id - The {Number} of the ID to check
# screenRange - The new {Point} to use
# options - A hash of options matching those found in {DisplayBuffer.bufferPositionForScreenPosition}
setMarkerHeadBufferPosition: (id, bufferPosition) ->
@getMarker(id).setHeadBufferPosition(bufferPosition)
# Public: Retrieves the screen position of the marker's tail.
#
# id - The {Number} of the ID to check
#
# Returns a {Point}.
getMarkerTailScreenPosition: (id) ->
@getMarker(id).getTailScreenPosition()
# Public: Sets the screen position of the marker's tail.
#
# id - The {Number} of the ID to change
# screenRange - The new {Point} to use
# options - A hash of options matching those found in {DisplayBuffer.bufferPositionForScreenPosition}
setMarkerTailScreenPosition: (id, screenPosition, options) ->
@getMarker(id).setTailScreenPosition(screenPosition, options)
# Public: Retrieves the buffer position of the marker's tail.
#
# id - The {Number} of the ID to check
#
# Returns a {Point}.
getMarkerTailBufferPosition: (id) ->
@getMarker(id).getTailBufferPosition()
# Public: Sets the buffer position of the marker's tail.
#
# id - The {Number} of the ID to check
# screenRange - The new {Point} to use
# options - A hash of options matching those found in {DisplayBuffer.bufferPositionForScreenPosition}
setMarkerTailBufferPosition: (id, bufferPosition) ->
@getMarker(id).setTailBufferPosition(bufferPosition)
# Public: Sets the marker's tail to the same position as the marker's head.
#
# This only works if there isn't already a tail position.
#
# id - A {Number} representing the marker to change
#
# Returns a {Point} representing the new tail position.
placeMarkerTail: (id) ->
@getMarker(id).placeTail()
# Public: Removes the tail from the marker.
#
# id - A {Number} representing the marker to change
clearMarkerTail: (id) ->
@getMarker(id).clearTail()
# Public: Identifies if the ending position of a marker is greater than the starting position.
#
# This can happen when, for example, you highlight text "up" in a {Buffer}.
#
# id - A {Number} representing the marker to check
#
# Returns a {Boolean}.
isMarkerReversed: (id) ->
@buffer.isMarkerReversed(id)
# Public: Identifies if the marker's head position is equal to its tail.
#
# id - A {Number} representing the marker to check
#
# Returns a {Boolean}.
isMarkerRangeEmpty: (id) ->
@buffer.isMarkerRangeEmpty(id)
# Public: Sets a callback to be fired whenever a marker is changed.
#
# id - A {Number} representing the marker to watch
# callback - A {Function} to execute
observeMarker: (id, callback) ->
@getMarker(id).observe(callback)
findMarker: (attributes) ->
@findMarkers(attributes)[0]