mirror of
https://github.com/atom/atom.git
synced 2026-01-25 23:08:18 -05:00
WIP: Start adding new anchorPoint API on edit session
These will replace anchors, but they won't be stored on the Buffer at all. The API user will access them by a returned scalar id rather than calling methods on the returned anchor object directly.
This commit is contained in:
@@ -1775,24 +1775,54 @@ describe "EditSession", ->
|
||||
describe "anchors", ->
|
||||
[anchor, destroyHandler] = []
|
||||
|
||||
beforeEach ->
|
||||
destroyHandler = jasmine.createSpy("destroyHandler")
|
||||
anchor = editSession.addAnchorAtBufferPosition([4, 25])
|
||||
anchor.on 'destroyed', destroyHandler
|
||||
fdescribe "anchor points", ->
|
||||
[anchor1Id, anchor2Id, anchor3Id] = []
|
||||
beforeEach ->
|
||||
anchor1Id = editSession.addAnchorPointAtBufferPosition([4, 23])
|
||||
anchor2Id = editSession.addAnchorPointAtBufferPosition([4, 23], ignoreSameLocationInserts: true)
|
||||
anchor3Id = editSession.addAnchorPointAtBufferPosition([4, 23], surviveSurroundingChanges: true)
|
||||
|
||||
describe "when a buffer change precedes an anchor", ->
|
||||
it "moves the anchor in accordance with the change", ->
|
||||
editSession.setSelectedBufferRange([[3, 0], [4, 10]])
|
||||
editSession.delete()
|
||||
expect(anchor.getBufferPosition()).toEqual [3, 15]
|
||||
expect(destroyHandler).not.toHaveBeenCalled()
|
||||
describe "when the buffer changes", ->
|
||||
describe "when the change precedes the anchor point", ->
|
||||
it "moves the anchor", ->
|
||||
buffer.insert([4, 5], '...')
|
||||
expect(editSession.getAnchorPointBufferPosition(anchor1Id)).toEqual [4, 26]
|
||||
buffer.delete([[4, 5], [4, 8]])
|
||||
expect(editSession.getAnchorPointBufferPosition(anchor1Id)).toEqual [4, 23]
|
||||
buffer.insert([0, 0], '\nhi\n')
|
||||
expect(editSession.getAnchorPointBufferPosition(anchor1Id)).toEqual [6, 23]
|
||||
|
||||
describe "when a buffer change surrounds an anchor", ->
|
||||
it "destroys the anchor", ->
|
||||
editSession.setSelectedBufferRange([[3, 0], [5, 0]])
|
||||
editSession.delete()
|
||||
expect(destroyHandler).toHaveBeenCalled()
|
||||
expect(editSession.getAnchors().indexOf(anchor)).toBe -1
|
||||
describe "when the change follows the anchor point", ->
|
||||
it "does not move the anchor", ->
|
||||
buffer.insert([6, 5], '...')
|
||||
expect(editSession.getAnchorPointBufferPosition(anchor1Id)).toEqual [4, 23]
|
||||
buffer.delete([[6, 5], [6, 8]])
|
||||
expect(editSession.getAnchorPointBufferPosition(anchor1Id)).toEqual [4, 23]
|
||||
buffer.insert([10, 0], '\nhi\n')
|
||||
expect(editSession.getAnchorPointBufferPosition(anchor1Id)).toEqual [4, 23]
|
||||
|
||||
describe "when the change is an insertion at the same location as the anchor point", ->
|
||||
describe "if the anchor ignores same location inserts", ->
|
||||
it "treats the insertion as being to the right of the anchor and does not move it", ->
|
||||
buffer.insert([4, 23], '...')
|
||||
expect(editSession.getAnchorPointBufferPosition(anchor2Id)).toEqual [4, 23]
|
||||
|
||||
describe "if the anchor observes same location inserts", ->
|
||||
it "treats the insertion as being to the left of the anchor and moves it accordingly", ->
|
||||
buffer.insert([4, 23], '...')
|
||||
expect(editSession.getAnchorPointBufferPosition(anchor1Id)).toEqual [4, 26]
|
||||
|
||||
describe "when the change surrounds the anchor point", ->
|
||||
beforeEach ->
|
||||
buffer.delete([[4, 20], [4, 26]])
|
||||
|
||||
describe "when the anchor survives surrounding changes", ->
|
||||
it "moves the anchor to the start of the change, but does not invalidate it", ->
|
||||
expect(editSession.getAnchorPointBufferPosition(anchor3Id)).toEqual [4, 20]
|
||||
|
||||
describe "when the anchor does not survive surrounding changes", ->
|
||||
it "invalidates the anchor", ->
|
||||
expect(editSession.getAnchorPointBufferPosition(anchor1Id)).toBeUndefined()
|
||||
|
||||
describe ".clipBufferPosition(bufferPosition)", ->
|
||||
it "clips the given position to a valid position", ->
|
||||
|
||||
79
src/app/anchor-point.coffee
Normal file
79
src/app/anchor-point.coffee
Normal file
@@ -0,0 +1,79 @@
|
||||
_ = require 'underscore'
|
||||
Point = require 'point'
|
||||
|
||||
module.exports =
|
||||
class AnchorPoint
|
||||
bufferPosition: null
|
||||
screenPosition: null
|
||||
ignoreSameLocationInserts: false
|
||||
surviveSurroundingChanges: false
|
||||
|
||||
constructor: ({@id, @editSession, bufferPosition, @ignoreSameLocationInserts, @surviveSurroundingChanges}) ->
|
||||
@setBufferPosition(bufferPosition)
|
||||
|
||||
handleBufferChange: (e) ->
|
||||
{ oldRange, newRange } = e
|
||||
position = @getBufferPosition()
|
||||
|
||||
if oldRange.containsPoint(position, exclusive: true)
|
||||
if @surviveSurroundingChanges
|
||||
@setBufferPosition(oldRange.start)
|
||||
else
|
||||
@invalidate()
|
||||
return
|
||||
return if @ignoreSameLocationInserts 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])
|
||||
|
||||
setBufferPosition: (position, options={}) ->
|
||||
@bufferPosition = Point.fromObject(position)
|
||||
clip = options.clip ? true
|
||||
@bufferPosition = @editSession.clipBufferPosition(@bufferPosition) if clip
|
||||
@refreshScreenPosition(options)
|
||||
|
||||
getBufferPosition: ->
|
||||
@bufferPosition
|
||||
|
||||
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
|
||||
|
||||
getScreenPosition: ->
|
||||
@screenPosition
|
||||
|
||||
getScreenRow: ->
|
||||
@screenPosition.row
|
||||
|
||||
refreshScreenPosition: (options={}) ->
|
||||
return unless @editSession
|
||||
screenPosition = @editSession.screenPositionForBufferPosition(@bufferPosition, options)
|
||||
@setScreenPosition(screenPosition, bufferChange: options.bufferChange, clip: false, assignBufferPosition: false)
|
||||
|
||||
invalidate: ->
|
||||
@editSession.removeAnchorPoint(@id)
|
||||
@@ -225,7 +225,7 @@ class DisplayBuffer
|
||||
@lineMap.replaceScreenRows(start, end, newScreenLines)
|
||||
screenDelta = @lastScreenRowForBufferRow(tokenizedBufferEnd + tokenizedBufferDelta) - end
|
||||
|
||||
@trigger 'changed', { start, end, screenDelta, bufferDelta }
|
||||
@trigger 'changed', { start, end, screenDelta, bufferDelta, bufferChange }
|
||||
|
||||
buildLineForBufferRow: (bufferRow) ->
|
||||
@buildLinesForBufferRows(bufferRow, bufferRow)
|
||||
|
||||
@@ -9,6 +9,7 @@ EventEmitter = require 'event-emitter'
|
||||
Subscriber = require 'subscriber'
|
||||
Range = require 'range'
|
||||
AnchorRange = require 'anchor-range'
|
||||
AnchorPoint = require 'anchor-point'
|
||||
_ = require 'underscore'
|
||||
fs = require 'fs'
|
||||
|
||||
@@ -40,6 +41,8 @@ class EditSession
|
||||
@softTabs = @buffer.usesSoftTabs() ? softTabs ? true
|
||||
@languageMode = new LanguageMode(this, @buffer.getExtension())
|
||||
@displayBuffer = new DisplayBuffer(@buffer, { @languageMode, tabLength })
|
||||
@nextAnchorPointId = 1
|
||||
@anchorPointsById = {}
|
||||
@anchors = []
|
||||
@anchorRanges = []
|
||||
@cursors = []
|
||||
@@ -54,6 +57,7 @@ class EditSession
|
||||
@preserveCursorPositionOnBufferReload()
|
||||
|
||||
@subscribe @displayBuffer, "changed", (e) =>
|
||||
@updateAnchorPoints(e.bufferChange)
|
||||
@refreshAnchorScreenPositions() unless e.bufferDelta
|
||||
@trigger 'screen-lines-changed', e
|
||||
|
||||
@@ -351,6 +355,25 @@ class EditSession
|
||||
pushOperation: (operation) ->
|
||||
@buffer.pushOperation(operation, this)
|
||||
|
||||
updateAnchorPoints: (bufferChange) ->
|
||||
return unless bufferChange
|
||||
anchorPoint.handleBufferChange(bufferChange) for anchorPoint in @getAnchorPoints()
|
||||
|
||||
getAnchorPoints: ->
|
||||
_.values(@anchorPointsById)
|
||||
|
||||
addAnchorPointAtBufferPosition: (bufferPosition, options) ->
|
||||
id = @nextAnchorPointId++
|
||||
params = _.extend({editSession: this, id, bufferPosition}, options)
|
||||
@anchorPointsById[id] = new AnchorPoint(params)
|
||||
id
|
||||
|
||||
getAnchorPointBufferPosition: (id) ->
|
||||
@anchorPointsById[id]?.getBufferPosition()
|
||||
|
||||
removeAnchorPoint: (id) ->
|
||||
delete @anchorPointsById[id]
|
||||
|
||||
getAnchors: ->
|
||||
new Array(@anchors...)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user