mirror of
https://github.com/atom/atom.git
synced 2026-02-06 12:44:59 -05:00
188 lines
6.5 KiB
CoffeeScript
188 lines
6.5 KiB
CoffeeScript
Range = require 'range'
|
|
_ = require 'underscore'
|
|
EventEmitter = require 'event-emitter'
|
|
|
|
module.exports =
|
|
class DisplayBufferMarker
|
|
bufferMarkerSubscription: null
|
|
headScreenPosition: null
|
|
tailScreenPosition: null
|
|
valid: true
|
|
|
|
###
|
|
# Internal #
|
|
###
|
|
|
|
constructor: ({@id, @displayBuffer}) ->
|
|
@buffer = @displayBuffer.buffer
|
|
|
|
###
|
|
# Public #
|
|
###
|
|
|
|
# Public: Gets the screen range of the display marker.
|
|
#
|
|
# Returns a {Range}.
|
|
getScreenRange: ->
|
|
@displayBuffer.screenRangeForBufferRange(@getBufferRange(), wrapAtSoftNewlines: true)
|
|
|
|
# Public: Modifies the screen range of the display marker.
|
|
#
|
|
# screenRange - The new {Range} to use
|
|
# options - A hash of options matching those found in {BufferMarker.setRange}
|
|
setScreenRange: (screenRange, options) ->
|
|
@setBufferRange(@displayBuffer.bufferRangeForScreenRange(screenRange), options)
|
|
|
|
# Public: Gets the buffer range of the display marker.
|
|
#
|
|
# Returns a {Range}.
|
|
getBufferRange: ->
|
|
@buffer.getMarkerRange(@id)
|
|
|
|
# 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)
|
|
|
|
# Public: Retrieves the screen position of the marker's head.
|
|
#
|
|
# Returns a {Point}.
|
|
getHeadScreenPosition: ->
|
|
@headScreenPosition ?= @displayBuffer.screenPositionForBufferPosition(@getHeadBufferPosition(), wrapAtSoftNewlines: true)
|
|
|
|
# Public: Sets the screen position of the marker's head.
|
|
#
|
|
# screenRange - The new {Point} to use
|
|
# options - A hash of options matching those found in {DisplayBuffer.bufferPositionForScreenPosition}
|
|
setHeadScreenPosition: (screenPosition, options) ->
|
|
screenPosition = @displayBuffer.clipScreenPosition(screenPosition, options)
|
|
@setHeadBufferPosition(@displayBuffer.bufferPositionForScreenPosition(screenPosition, options))
|
|
|
|
# Public: Retrieves the buffer position of the marker's head.
|
|
#
|
|
# Returns a {Point}.
|
|
getHeadBufferPosition: ->
|
|
@buffer.getMarkerHeadPosition(@id)
|
|
|
|
# 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)
|
|
|
|
# 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
|
|
# options - A hash of options matching those found in {DisplayBuffer.bufferPositionForScreenPosition}
|
|
setTailScreenPosition: (screenPosition, options) ->
|
|
screenPosition = @displayBuffer.clipScreenPosition(screenPosition, options)
|
|
@setTailBufferPosition(@displayBuffer.bufferPositionForScreenPosition(screenPosition, options))
|
|
|
|
# Public: Retrieves the buffer position of the marker's tail.
|
|
#
|
|
# Returns a {Point}.
|
|
getTailBufferPosition: ->
|
|
@buffer.getMarkerTailPosition(@id)
|
|
|
|
# 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)
|
|
|
|
# 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.
|
|
#
|
|
# Returns a {Point} representing the new tail position.
|
|
placeTail: ->
|
|
@buffer.placeMarkerTail(@id)
|
|
|
|
# Public: Removes the tail from the marker.
|
|
clearTail: ->
|
|
@buffer.clearMarkerTail(@id)
|
|
|
|
# Public: Sets a callback to be fired whenever the marker is changed.
|
|
#
|
|
# callback - A {Function} to execute
|
|
observe: (callback) ->
|
|
@observeBufferMarkerIfNeeded()
|
|
@on 'changed', callback
|
|
cancel: => @unobserve(callback)
|
|
|
|
# Public: Removes the callback that's fired whenever the marker changes.
|
|
#
|
|
# callback - A {Function} to remove
|
|
unobserve: (callback) ->
|
|
@off 'changed', callback
|
|
@unobserveBufferMarkerIfNeeded()
|
|
|
|
###
|
|
# Internal #
|
|
###
|
|
|
|
observeBufferMarkerIfNeeded: ->
|
|
return if @subscriptionCount()
|
|
@getHeadScreenPosition() # memoize current value
|
|
@getTailScreenPosition() # memoize current value
|
|
@bufferMarkerSubscription =
|
|
@buffer.observeMarker @id, ({oldHeadPosition, newHeadPosition, oldTailPosition, newTailPosition, bufferChanged, valid}) =>
|
|
@notifyObservers
|
|
oldHeadBufferPosition: oldHeadPosition
|
|
newHeadBufferPosition: newHeadPosition
|
|
oldTailBufferPosition: oldTailPosition
|
|
newTailBufferPosition: newTailPosition
|
|
bufferChanged: bufferChanged
|
|
valid: valid
|
|
@displayBuffer.markers[@id] = this
|
|
|
|
unobserveBufferMarkerIfNeeded: ->
|
|
return if @subscriptionCount()
|
|
@bufferMarkerSubscription.cancel()
|
|
delete @displayBuffer.markers[@id]
|
|
|
|
notifyObservers: ({oldHeadBufferPosition, oldTailBufferPosition, bufferChanged, valid} = {}) ->
|
|
oldHeadScreenPosition = @getHeadScreenPosition()
|
|
newHeadScreenPosition = oldHeadScreenPosition
|
|
oldTailScreenPosition = @getTailScreenPosition()
|
|
newTailScreenPosition = oldTailScreenPosition
|
|
valid ?= true
|
|
|
|
if valid
|
|
@headScreenPosition = null
|
|
newHeadScreenPosition = @getHeadScreenPosition()
|
|
@tailScreenPosition = null
|
|
newTailScreenPosition = @getTailScreenPosition()
|
|
|
|
validChanged = valid isnt @valid
|
|
headScreenPositionChanged = not _.isEqual(newHeadScreenPosition, oldHeadScreenPosition)
|
|
tailScreenPositionChanged = not _.isEqual(newTailScreenPosition, oldTailScreenPosition)
|
|
return unless validChanged or headScreenPositionChanged or tailScreenPositionChanged
|
|
|
|
oldHeadBufferPosition ?= @getHeadBufferPosition()
|
|
newHeadBufferPosition = @getHeadBufferPosition() ? oldHeadBufferPosition
|
|
oldTailBufferPosition ?= @getTailBufferPosition()
|
|
newTailBufferPosition = @getTailBufferPosition() ? oldTailBufferPosition
|
|
@valid = valid
|
|
|
|
@trigger 'changed', {
|
|
oldHeadScreenPosition, newHeadScreenPosition,
|
|
oldTailScreenPosition, newTailScreenPosition,
|
|
oldHeadBufferPosition, newHeadBufferPosition,
|
|
oldTailBufferPosition, newTailBufferPosition,
|
|
bufferChanged
|
|
valid
|
|
}
|
|
|
|
_.extend DisplayBufferMarker.prototype, EventEmitter
|