mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-11-10 18:24:09 +03:00
Start adding ability to observe marker head positions
This commit is contained in:
parent
2df0b9fa19
commit
bc44540b10
@ -705,6 +705,17 @@ describe 'Buffer', ->
|
||||
buffer.setMarkerTailPosition(marker, [Infinity, Infinity])
|
||||
expect(buffer.getMarkerRange(marker)).toEqual([[0, 0], [12, 2]])
|
||||
|
||||
describe "marker observation", ->
|
||||
describe ".observeMarkerHeadPosition(marker, callback)", ->
|
||||
it "calls the given callback whenever the marker's head position changes", ->
|
||||
marker = buffer.markRange([[4, 20], [4, 23]])
|
||||
observeHandler = jasmine.createSpy("observeHandler")
|
||||
buffer.observeMarkerHeadPosition(marker, observeHandler)
|
||||
|
||||
buffer.setMarkerHeadPosition(marker, [6, 2])
|
||||
expect(observeHandler).toHaveBeenCalled()
|
||||
expect(observeHandler.argsForCall[0][0]).toEqual [6, 2]
|
||||
|
||||
describe "marker updates due to buffer changes", ->
|
||||
[marker1, marker2] = []
|
||||
|
||||
|
@ -581,10 +581,10 @@ describe "DisplayBuffer", ->
|
||||
expect(displayBuffer.maxLineLength()).toBe 65
|
||||
|
||||
fdescribe "markers", ->
|
||||
describe "creation and manipulation", ->
|
||||
beforeEach ->
|
||||
displayBuffer.foldBufferRow(4)
|
||||
beforeEach ->
|
||||
displayBuffer.foldBufferRow(4)
|
||||
|
||||
describe "creation and manipulation", ->
|
||||
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]])
|
||||
@ -603,10 +603,49 @@ describe "DisplayBuffer", ->
|
||||
expect(displayBuffer.isMarkerReversed(marker)).toBeTruthy()
|
||||
expect(displayBuffer.getMarkerBufferRange(marker)).toEqual [[5, 4], [8, 4]]
|
||||
|
||||
describe "observation", ->
|
||||
describe ".observeMarkerHeadScreenPosition(marker, callback)", ->
|
||||
it "calls the callback whenever the markers head's screen position changes", ->
|
||||
marker = displayBuffer.markScreenRange([[5, 4], [5, 10]])
|
||||
observeHandler = jasmine.createSpy("observeHandler")
|
||||
displayBuffer.observeMarkerHeadScreenPosition(marker, observeHandler)
|
||||
displayBuffer.setMarkerHeadScreenPosition(marker, [8, 20])
|
||||
expect(observeHandler).toHaveBeenCalled()
|
||||
expect(observeHandler.argsForCall[0][0]).toEqual [8, 20]
|
||||
observeHandler.reset()
|
||||
|
||||
buffer.insert([11, 0], '...')
|
||||
expect(observeHandler).toHaveBeenCalled()
|
||||
expect(observeHandler.argsForCall[0][0]).toEqual [8, 23]
|
||||
observeHandler.reset()
|
||||
|
||||
displayBuffer.unfoldBufferRow(4)
|
||||
expect(observeHandler).toHaveBeenCalled()
|
||||
expect(observeHandler.argsForCall[0][0]).toEqual [11, 23]
|
||||
observeHandler.reset()
|
||||
|
||||
displayBuffer.foldBufferRow(4)
|
||||
expect(observeHandler).toHaveBeenCalled()
|
||||
expect(observeHandler.argsForCall[0][0]).toEqual [8, 23]
|
||||
|
||||
it "does not call the callback for screen changes that don't change the position of the marker", ->
|
||||
marker = displayBuffer.markScreenPosition([3, 4])
|
||||
observeHandler = jasmine.createSpy("observeHandler")
|
||||
displayBuffer.observeMarkerHeadScreenPosition(marker, observeHandler)
|
||||
|
||||
buffer.insert([3, 0], '...')
|
||||
expect(observeHandler).toHaveBeenCalled()
|
||||
expect(observeHandler.argsForCall[0][0]).toEqual [3, 7]
|
||||
observeHandler.reset()
|
||||
|
||||
displayBuffer.unfoldBufferRow(4)
|
||||
expect(observeHandler).not.toHaveBeenCalled()
|
||||
|
||||
fold = displayBuffer.createFold(0, 2)
|
||||
expect(observeHandler).toHaveBeenCalled()
|
||||
expect(observeHandler.argsForCall[0][0]).toEqual [1, 7]
|
||||
observeHandler.reset()
|
||||
|
||||
fold.destroy()
|
||||
expect(observeHandler).toHaveBeenCalled()
|
||||
expect(observeHandler.argsForCall[0][0]).toEqual [3, 7]
|
||||
|
@ -6,19 +6,21 @@ module.exports =
|
||||
class BufferMarker
|
||||
headPosition: null
|
||||
tailPosition: null
|
||||
headPositionObservers: null
|
||||
stayValid: false
|
||||
|
||||
constructor: ({@id, @buffer, range, @stayValid, noTail, reverse}) ->
|
||||
@headPositionObservers = []
|
||||
@setRange(range, {noTail, reverse})
|
||||
|
||||
setRange: (range, options={}) ->
|
||||
range = @buffer.clipRange(range)
|
||||
range = Range.fromObject(range)
|
||||
if options.reverse
|
||||
@tailPosition = range.end unless options.noTail
|
||||
@headPosition = range.start
|
||||
@setTailPosition(range.end) unless options.noTail
|
||||
@setHeadPosition(range.start)
|
||||
else
|
||||
@tailPosition = range.start unless options.noTail
|
||||
@headPosition = range.end
|
||||
@setTailPosition(range.start) unless options.noTail
|
||||
@setHeadPosition(range.end)
|
||||
|
||||
isReversed: ->
|
||||
@tailPosition? and @headPosition.isLessThan(@tailPosition)
|
||||
@ -36,6 +38,8 @@ class BufferMarker
|
||||
setHeadPosition: (headPosition, options={}) ->
|
||||
@headPosition = Point.fromObject(headPosition)
|
||||
@headPosition = @buffer.clipPosition(@headPosition) if options.clip ? true
|
||||
observer(@headPosition) for observer in @headPositionObservers
|
||||
@headPosition
|
||||
|
||||
setTailPosition: (tailPosition, options={}) ->
|
||||
@tailPosition = Point.fromObject(tailPosition)
|
||||
@ -47,6 +51,9 @@ class BufferMarker
|
||||
getEndPosition: ->
|
||||
@getRange().end
|
||||
|
||||
observeHeadPosition: (callback) ->
|
||||
@headPositionObservers.push(callback)
|
||||
|
||||
tryToInvalidate: (oldRange) ->
|
||||
containsStart = oldRange.containsPoint(@getStartPosition(), exclusive: true)
|
||||
containsEnd = oldRange.containsPoint(@getEndPosition(), exclusive: true)
|
||||
@ -66,8 +73,8 @@ class BufferMarker
|
||||
[@id]
|
||||
|
||||
handleBufferChange: (bufferChange) ->
|
||||
@setTailPosition(@updatePosition(@tailPosition, bufferChange, true), clip: false)
|
||||
@setHeadPosition(@updatePosition(@headPosition, bufferChange, false), clip: false)
|
||||
@setTailPosition(@updatePosition(@tailPosition, bufferChange, true), clip: false) if @tailPosition
|
||||
|
||||
updatePosition: (position, bufferChange, isFirstPoint) ->
|
||||
{ oldRange, newRange } = bufferChange
|
||||
|
@ -307,6 +307,9 @@ class Buffer
|
||||
isMarkerReversed: (id) ->
|
||||
@validMarkers[id]?.isReversed()
|
||||
|
||||
observeMarkerHeadPosition: (id, callback) ->
|
||||
@validMarkers[id]?.observeHeadPosition(callback)
|
||||
|
||||
getAnchors: -> new Array(@anchors...)
|
||||
|
||||
addAnchor: (options) ->
|
||||
|
@ -16,6 +16,8 @@ class DisplayBuffer
|
||||
tokenizedBuffer: null
|
||||
activeFolds: null
|
||||
foldsById: null
|
||||
markerScreenPositionObservers: null
|
||||
markerScreenPositions: null
|
||||
|
||||
constructor: (@buffer, options={}) ->
|
||||
@id = @constructor.idCounter++
|
||||
@ -24,6 +26,9 @@ class DisplayBuffer
|
||||
@softWrapColumn = options.softWrapColumn ? Infinity
|
||||
@activeFolds = {}
|
||||
@foldsById = {}
|
||||
@markerScreenPositionObservers = {}
|
||||
@markerScreenPositions = {}
|
||||
|
||||
@buildLineMap()
|
||||
@tokenizedBuffer.on 'changed', (e) => @handleTokenizedBufferChange(e)
|
||||
|
||||
@ -33,13 +38,17 @@ class DisplayBuffer
|
||||
@lineMap = new LineMap
|
||||
@lineMap.insertAtScreenRow 0, @buildLinesForBufferRows(0, @buffer.getLastRow())
|
||||
|
||||
triggerChanged: (eventProperties) ->
|
||||
@notifyMarkerScreenPositionObservers() unless eventProperties.bufferChange
|
||||
@trigger 'changed', eventProperties
|
||||
|
||||
setSoftWrapColumn: (@softWrapColumn) ->
|
||||
start = 0
|
||||
end = @getLastRow()
|
||||
@buildLineMap()
|
||||
screenDelta = @getLastRow() - end
|
||||
bufferDelta = 0
|
||||
@trigger 'changed', { start, end, screenDelta, bufferDelta }
|
||||
@triggerChanged({ start, end, screenDelta, bufferDelta })
|
||||
|
||||
lineForRow: (row) ->
|
||||
@lineMap.lineForScreenRow(row)
|
||||
@ -95,7 +104,7 @@ class DisplayBuffer
|
||||
end = oldScreenRange.end.row
|
||||
screenDelta = newScreenRange.end.row - oldScreenRange.end.row
|
||||
bufferDelta = 0
|
||||
@trigger 'changed', { start, end, screenDelta, bufferDelta }
|
||||
@triggerChanged({ start, end, screenDelta, bufferDelta })
|
||||
|
||||
fold
|
||||
|
||||
@ -124,7 +133,8 @@ class DisplayBuffer
|
||||
screenDelta = newScreenRange.end.row - oldScreenRange.end.row
|
||||
bufferDelta = 0
|
||||
|
||||
@trigger 'changed', { start, end, screenDelta, bufferDelta }
|
||||
@notifyMarkerScreenPositionObservers()
|
||||
@triggerChanged({ start, end, screenDelta, bufferDelta })
|
||||
|
||||
destroyFoldsContainingBufferRow: (bufferRow) ->
|
||||
for row, folds of @activeFolds
|
||||
@ -225,7 +235,7 @@ class DisplayBuffer
|
||||
@lineMap.replaceScreenRows(start, end, newScreenLines)
|
||||
screenDelta = @lastScreenRowForBufferRow(tokenizedBufferEnd + tokenizedBufferDelta) - end
|
||||
|
||||
@trigger 'changed', { start, end, screenDelta, bufferDelta, bufferChange }
|
||||
@triggerChanged({ start, end, screenDelta, bufferDelta, bufferChange })
|
||||
|
||||
buildLineForBufferRow: (bufferRow) ->
|
||||
@buildLinesForBufferRows(bufferRow, bufferRow)
|
||||
@ -341,6 +351,24 @@ class DisplayBuffer
|
||||
isMarkerReversed: (id) ->
|
||||
@buffer.isMarkerReversed(id)
|
||||
|
||||
observeMarkerHeadScreenPosition: (id, callback) ->
|
||||
@markerScreenPositionObservers[id] ?= { head: [], tail: [] }
|
||||
@cacheMarkerScreenPositions(id) unless @markerScreenPositions[id]
|
||||
@markerScreenPositionObservers[id].head.push(callback)
|
||||
@buffer.observeMarkerHeadPosition id, (bufferPosition) =>
|
||||
@cacheMarkerScreenPositions(id)
|
||||
callback(@screenPositionForBufferPosition(bufferPosition))
|
||||
|
||||
cacheMarkerScreenPositions: (id) ->
|
||||
@markerScreenPositions[id] = { head: @getMarkerHeadScreenPosition(id), tail: @getMarkerTailScreenPosition }
|
||||
|
||||
notifyMarkerScreenPositionObservers: ->
|
||||
for id, { head } of @markerScreenPositions
|
||||
currentHeadPosition = @getMarkerHeadScreenPosition(id)
|
||||
unless currentHeadPosition.isEqual(head)
|
||||
@cacheMarkerScreenPositions(id)
|
||||
observer(currentHeadPosition) for observer in @markerScreenPositionObservers[id].head
|
||||
|
||||
destroy: ->
|
||||
@tokenizedBuffer.destroy()
|
||||
|
||||
|
@ -440,11 +440,20 @@ class EditSession
|
||||
markBufferPosition: (args...) ->
|
||||
@displayBuffer.markBufferPosition(args...)
|
||||
|
||||
getMarkerBufferRange: (marker) ->
|
||||
@displayBuffer.getMarkerBufferRange(marker)
|
||||
getMarkerBufferRange: (args...) ->
|
||||
@displayBuffer.getMarkerBufferRange(args...)
|
||||
|
||||
getMarkerScreenRange: (marker) ->
|
||||
@displayBuffer.getMarkerScreenRange(marker)
|
||||
getMarkerScreenRange: (args...) ->
|
||||
@displayBuffer.getMarkerScreenRange(args...)
|
||||
|
||||
getMarkerBufferPosition: (args...) ->
|
||||
@displayBuffer.getMarkerBufferPosition(args...)
|
||||
|
||||
getMarkerHeadBufferPosition: (args...) ->
|
||||
@displayBuffer.getMarkerHeadBufferPosition(args...)
|
||||
|
||||
getMarkerTailBufferPosition: (args...) ->
|
||||
@displayBuffer.getMarkerTailBufferPosition(args...)
|
||||
|
||||
addAnchor: (options={}) ->
|
||||
anchor = @buffer.addAnchor(_.extend({editSession: this}, options))
|
||||
|
Loading…
Reference in New Issue
Block a user