mirror of
https://github.com/atom/atom.git
synced 2026-02-14 16:45:14 -05:00
Update markers before triggering 'changed' events
This prevents the editor from synchronously redrawing in specs with cursors in invalid locations. Markers are always updated under the hood before a change event is emitted from the Buffer or DisplayBuffer. We still wait to trigger marker observers, but if their position gets read, it is up to date.
This commit is contained in:
@@ -69,10 +69,14 @@ class BufferChangeOperation
|
||||
@buffer.cachedMemoryContents = null
|
||||
@buffer.conflict = false if @buffer.conflict and !@buffer.isModified()
|
||||
|
||||
@pauseMarkerObservation()
|
||||
event = { oldRange, newRange, oldText, newText }
|
||||
@updateMarkers(event)
|
||||
@buffer.trigger 'changed', event
|
||||
@buffer.scheduleStoppedChangingEvent()
|
||||
@updateMarkers(event)
|
||||
@resumeMarkerObservation()
|
||||
@buffer.trigger 'markers-updated'
|
||||
|
||||
newRange
|
||||
|
||||
calculateNewRange: (oldRange, newText) ->
|
||||
@@ -89,9 +93,14 @@ class BufferChangeOperation
|
||||
invalidateMarkers: (oldRange) ->
|
||||
_.compact(@buffer.getMarkers().map (marker) -> marker.tryToInvalidate(oldRange))
|
||||
|
||||
pauseMarkerObservation: ->
|
||||
marker.pauseEvents() for marker in @buffer.getMarkers()
|
||||
|
||||
resumeMarkerObservation: ->
|
||||
marker.resumeEvents() for marker in @buffer.getMarkers()
|
||||
|
||||
updateMarkers: (bufferChange) ->
|
||||
marker.handleBufferChange(bufferChange) for marker in @buffer.getMarkers()
|
||||
@buffer.trigger 'markers-updated'
|
||||
|
||||
restoreMarkers: (markersToRestore) ->
|
||||
for [id, previousRange] in markersToRestore
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
_ = require 'underscore'
|
||||
Point = require 'point'
|
||||
Range = require 'range'
|
||||
EventEmitter = require 'event-emitter'
|
||||
|
||||
module.exports =
|
||||
class BufferMarker
|
||||
headPosition: null
|
||||
tailPosition: null
|
||||
observers: null
|
||||
suppressObserverNotification: false
|
||||
stayValid: false
|
||||
|
||||
constructor: ({@id, @buffer, range, @stayValid, noTail, reverse}) ->
|
||||
@headPositionObservers = []
|
||||
@observers = []
|
||||
@setRange(range, {noTail, reverse})
|
||||
|
||||
setRange: (range, options={}) ->
|
||||
@@ -115,11 +113,11 @@ class BufferMarker
|
||||
[newRow, newColumn]
|
||||
|
||||
observe: (callback) ->
|
||||
@observers.push(callback)
|
||||
@on 'position-changed', callback
|
||||
cancel: => @unobserve(callback)
|
||||
|
||||
unobserve: (callback) ->
|
||||
_.remove(@observers, callback)
|
||||
@off 'position-changed', callback
|
||||
|
||||
containsPoint: (point) ->
|
||||
@getRange().containsPoint(point)
|
||||
@@ -131,11 +129,7 @@ class BufferMarker
|
||||
newHeadPosition ?= @getHeadPosition()
|
||||
oldTailPosition ?= @getTailPosition()
|
||||
newTailPosition ?= @getTailPosition()
|
||||
for observer in @getObservers()
|
||||
observer({oldHeadPosition, newHeadPosition, oldTailPosition, newTailPosition, bufferChanged})
|
||||
|
||||
getObservers: ->
|
||||
new Array(@observers...)
|
||||
@trigger 'position-changed', {oldHeadPosition, newHeadPosition, oldTailPosition, newTailPosition, bufferChanged}
|
||||
|
||||
consolidateObserverNotifications: (bufferChanged, fn) ->
|
||||
@suppressObserverNotification = true
|
||||
@@ -150,3 +144,5 @@ class BufferMarker
|
||||
invalidate: (preserve) ->
|
||||
delete @buffer.validMarkers[@id]
|
||||
@buffer.invalidMarkers[@id] = this
|
||||
|
||||
_.extend BufferMarker.prototype, EventEmitter
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
Range = require 'range'
|
||||
_ = require 'underscore'
|
||||
EventEmitter = require 'event-emitter'
|
||||
|
||||
module.exports =
|
||||
class DisplayBufferMarker
|
||||
observers: null
|
||||
bufferMarkerSubscription: null
|
||||
headScreenPosition: null
|
||||
tailScreenPosition: null
|
||||
@@ -57,16 +57,15 @@ class DisplayBufferMarker
|
||||
|
||||
observe: (callback) ->
|
||||
@observeBufferMarkerIfNeeded()
|
||||
@observers.push(callback)
|
||||
@on 'position-changed', callback
|
||||
cancel: => @unobserve(callback)
|
||||
|
||||
unobserve: (callback) ->
|
||||
_.remove(@observers, callback)
|
||||
@off 'position-changed', callback
|
||||
@unobserveBufferMarkerIfNeeded()
|
||||
|
||||
observeBufferMarkerIfNeeded: ->
|
||||
return if @observers
|
||||
@observers = []
|
||||
return if @subscriptionCount()
|
||||
@getHeadScreenPosition() # memoize current value
|
||||
@getTailScreenPosition() # memoize current value
|
||||
@bufferMarkerSubscription =
|
||||
@@ -80,8 +79,7 @@ class DisplayBufferMarker
|
||||
@displayBuffer.markers[@id] = this
|
||||
|
||||
unobserveBufferMarkerIfNeeded: ->
|
||||
return if @observers.length
|
||||
@observers = null
|
||||
return if @subscriptionCount()
|
||||
@bufferMarkerSubscription.cancel()
|
||||
delete @displayBuffer.markers[@id]
|
||||
|
||||
@@ -101,14 +99,12 @@ class DisplayBufferMarker
|
||||
oldTailBufferPosition ?= @getTailBufferPosition()
|
||||
newTailBufferPosition = @getTailBufferPosition()
|
||||
|
||||
for observer in @getObservers()
|
||||
observer({
|
||||
oldHeadScreenPosition, newHeadScreenPosition,
|
||||
oldTailScreenPosition, newTailScreenPosition,
|
||||
oldHeadBufferPosition, newHeadBufferPosition,
|
||||
oldTailBufferPosition, newTailBufferPosition,
|
||||
bufferChanged
|
||||
})
|
||||
@trigger 'position-changed', {
|
||||
oldHeadScreenPosition, newHeadScreenPosition,
|
||||
oldTailScreenPosition, newTailScreenPosition,
|
||||
oldHeadBufferPosition, newHeadBufferPosition,
|
||||
oldTailBufferPosition, newTailBufferPosition,
|
||||
bufferChanged
|
||||
}
|
||||
|
||||
getObservers: ->
|
||||
new Array(@observers...)
|
||||
_.extend DisplayBufferMarker.prototype, EventEmitter
|
||||
|
||||
@@ -28,7 +28,8 @@ class DisplayBuffer
|
||||
@foldsById = {}
|
||||
@markers = {}
|
||||
@buildLineMap()
|
||||
@tokenizedBuffer.on 'changed', (e) => @handleTokenizedBufferChange(e)
|
||||
@tokenizedBuffer.on 'changed', @handleTokenizedBufferChange
|
||||
@buffer.on 'markers-updated', @handleMarkersUpdated
|
||||
|
||||
setVisible: (visible) -> @tokenizedBuffer.setVisible(visible)
|
||||
|
||||
@@ -37,8 +38,11 @@ class DisplayBuffer
|
||||
@lineMap.insertAtScreenRow 0, @buildLinesForBufferRows(0, @buffer.getLastRow())
|
||||
|
||||
triggerChanged: (eventProperties, refreshMarkers=true) ->
|
||||
@refreshMarkerScreenPositions() if refreshMarkers
|
||||
if refreshMarkers
|
||||
@pauseMarkerObservers()
|
||||
@refreshMarkerScreenPositions()
|
||||
@trigger 'changed', eventProperties
|
||||
@resumeMarkerObservers()
|
||||
|
||||
setSoftWrapColumn: (@softWrapColumn) ->
|
||||
start = 0
|
||||
@@ -131,7 +135,6 @@ class DisplayBuffer
|
||||
screenDelta = newScreenRange.end.row - oldScreenRange.end.row
|
||||
bufferDelta = 0
|
||||
|
||||
@refreshMarkerScreenPositions()
|
||||
@triggerChanged({ start, end, screenDelta, bufferDelta })
|
||||
|
||||
destroyFoldsContainingBufferRow: (bufferRow) ->
|
||||
@@ -216,7 +219,7 @@ class DisplayBuffer
|
||||
allFolds.push(folds...) for row, folds of @activeFolds
|
||||
fold.handleBufferChange(e) for fold in allFolds
|
||||
|
||||
handleTokenizedBufferChange: (tokenizedBufferChange) ->
|
||||
handleTokenizedBufferChange: (tokenizedBufferChange) =>
|
||||
if bufferChange = tokenizedBufferChange.bufferChange
|
||||
@handleBufferChange(bufferChange)
|
||||
bufferDelta = bufferChange.newRange.end.row - bufferChange.oldRange.end.row
|
||||
@@ -231,7 +234,17 @@ class DisplayBuffer
|
||||
@lineMap.replaceScreenRows(start, end, newScreenLines)
|
||||
screenDelta = @lastScreenRowForBufferRow(tokenizedBufferEnd + tokenizedBufferDelta) - end
|
||||
|
||||
@triggerChanged({ start, end, screenDelta, bufferDelta }, false)
|
||||
changeEvent = { start, end, screenDelta, bufferDelta }
|
||||
if bufferChange
|
||||
@pauseMarkerObservers()
|
||||
@pendingChangeEvent = changeEvent
|
||||
else
|
||||
@triggerChanged(changeEvent, false)
|
||||
|
||||
handleMarkersUpdated: =>
|
||||
event = @pendingChangeEvent
|
||||
@pendingChangeEvent = null
|
||||
@triggerChanged(event, false)
|
||||
|
||||
buildLineForBufferRow: (bufferRow) ->
|
||||
@buildLinesForBufferRows(bufferRow, bufferRow)
|
||||
@@ -372,12 +385,19 @@ class DisplayBuffer
|
||||
observeMarker: (id, callback) ->
|
||||
@getMarker(id).observe(callback)
|
||||
|
||||
pauseMarkerObservers: ->
|
||||
marker.pauseEvents() for marker in @getMarkers()
|
||||
|
||||
resumeMarkerObservers: ->
|
||||
marker.resumeEvents() for marker in @getMarkers()
|
||||
|
||||
refreshMarkerScreenPositions: ->
|
||||
for marker in @getMarkers()
|
||||
marker.notifyObservers(bufferChanged: false)
|
||||
|
||||
destroy: ->
|
||||
@tokenizedBuffer.destroy()
|
||||
@buffer.off 'markers-updated', @handleMarkersUpdated
|
||||
|
||||
logLines: (start, end) ->
|
||||
@lineMap.logLines(start, end)
|
||||
|
||||
Reference in New Issue
Block a user