mirror of
https://github.com/atom/atom.git
synced 2026-02-14 16:45:14 -05:00
For this to work, I needed to make the updating of anchors transactional. Now, all anchors are updated and *then* they emit their events. That way when the cursor moves based on the user typing, the tab stop they're in has a chance to expand before we handle the move event. This prevents spurious cancellation of the snippet when typing on a tab stop.
89 lines
2.7 KiB
CoffeeScript
89 lines
2.7 KiB
CoffeeScript
Point = require 'point'
|
|
EventEmitter = require 'event-emitter'
|
|
_ = require 'underscore'
|
|
|
|
module.exports =
|
|
class Anchor
|
|
buffer: null
|
|
editSession: null # optional
|
|
bufferPosition: null
|
|
screenPosition: null
|
|
ignoreChangesStartingOnAnchor: false
|
|
strong: false
|
|
|
|
constructor: (@buffer, options = {}) ->
|
|
{ @editSession, @ignoreChangesStartingOnAnchor, @strong } = options
|
|
|
|
handleBufferChange: (e) ->
|
|
{ oldRange, newRange } = e
|
|
position = @getBufferPosition()
|
|
|
|
if oldRange.containsPoint(position, exclusive: true)
|
|
if @strong
|
|
@setBufferPosition(oldRange.start)
|
|
else
|
|
@destroy()
|
|
return
|
|
|
|
return if @ignoreChangesStartingOnAnchor and position.isEqual(oldRange.start)
|
|
return if position.isLessThan(oldRange.end)
|
|
|
|
newRow = newRange.end.row
|
|
newColumn = newRange.end.column
|
|
if position.row == oldRange.end.row
|
|
newColumn += position.column - oldRange.end.column
|
|
else
|
|
newColumn = position.column
|
|
newRow += position.row - oldRange.end.row
|
|
|
|
@setBufferPosition([newRow, newColumn], bufferChange: true)
|
|
|
|
getBufferPosition: ->
|
|
@bufferPosition
|
|
|
|
setBufferPosition: (position, options={}) ->
|
|
@bufferPosition = Point.fromObject(position)
|
|
clip = options.clip ? true
|
|
@bufferPosition = @buffer.clipPosition(@bufferPosition) if clip
|
|
@refreshScreenPosition(options)
|
|
|
|
getScreenPosition: ->
|
|
@screenPosition
|
|
|
|
getScreenRow: ->
|
|
@screenPosition.row
|
|
|
|
setScreenPosition: (position, options={}) ->
|
|
oldScreenPosition = @screenPosition
|
|
oldBufferPosition = @bufferPosition
|
|
@screenPosition = Point.fromObject(position)
|
|
clip = options.clip ? true
|
|
assignBufferPosition = options.assignBufferPosition ? true
|
|
|
|
@screenPosition = @editSession.clipScreenPosition(@screenPosition, options) if clip
|
|
@bufferPosition = @editSession.bufferPositionForScreenPosition(@screenPosition, options) if assignBufferPosition
|
|
|
|
Object.freeze @screenPosition
|
|
Object.freeze @bufferPosition
|
|
|
|
unless @screenPosition.isEqual(oldScreenPosition)
|
|
@trigger 'moved',
|
|
oldScreenPosition: oldScreenPosition
|
|
newScreenPosition: @screenPosition
|
|
oldBufferPosition: oldBufferPosition
|
|
newBufferPosition: @bufferPosition
|
|
bufferChange: options.bufferChange
|
|
autoscroll: options.autoscroll
|
|
|
|
refreshScreenPosition: (options={}) ->
|
|
return unless @editSession
|
|
screenPosition = @editSession.screenPositionForBufferPosition(@bufferPosition, options)
|
|
@setScreenPosition(screenPosition, bufferChange: options.bufferChange, clip: false, assignBufferPosition: false, autoscroll: options.autoscroll)
|
|
|
|
destroy: ->
|
|
@buffer.removeAnchor(this)
|
|
@editSession?.removeAnchor(this)
|
|
@trigger 'destroy'
|
|
|
|
_.extend(Anchor.prototype, EventEmitter)
|