mirror of
https://github.com/atom/atom.git
synced 2026-02-09 14:15:24 -05:00
Selection and Cursor use Anchor to hold their buffer and screen positions
This commit is contained in:
47
src/atom/anchor.coffee
Normal file
47
src/atom/anchor.coffee
Normal file
@@ -0,0 +1,47 @@
|
||||
Point = require 'point'
|
||||
|
||||
module.exports =
|
||||
class Anchor
|
||||
editor: null
|
||||
bufferPosition: null
|
||||
screenPosition: null
|
||||
|
||||
constructor: (editor) ->
|
||||
@editor = editor
|
||||
@bufferPosition = new Point(0, 0)
|
||||
@screenPosition = new Point(0, 0)
|
||||
|
||||
handleBufferChange: (e) ->
|
||||
{ oldRange, newRange } = e
|
||||
position = @getBufferPosition()
|
||||
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]
|
||||
|
||||
getBufferPosition: ->
|
||||
@bufferPosition
|
||||
|
||||
setBufferPosition: (position) ->
|
||||
screenPosition = @editor.screenPositionForBufferPosition(position)
|
||||
@setScreenPosition(screenPosition, clip: false)
|
||||
|
||||
getScreenPosition: ->
|
||||
@screenPosition
|
||||
|
||||
setScreenPosition: (position, options={}) ->
|
||||
position = Point.fromObject(position)
|
||||
clip = options.clip ? true
|
||||
|
||||
@screenPosition = if clip then @editor.clipScreenPosition(position) else position
|
||||
@bufferPosition = @editor.bufferPositionForScreenPosition(position)
|
||||
|
||||
Object.freeze @screenPosition
|
||||
Object.freeze @bufferPosition
|
||||
@@ -45,8 +45,8 @@ class CompositeCursor
|
||||
setBufferPosition: (bufferPosition) ->
|
||||
@moveCursors (cursor) -> cursor.setBufferPosition(bufferPosition)
|
||||
|
||||
refreshScreenPosition: ->
|
||||
@moveCursors (cursor) -> cursor.refreshScreenPosition()
|
||||
updateBufferPosition: ->
|
||||
@moveCursors (cursor) -> cursor.setBufferPosition(cursor.getBufferPosition())
|
||||
|
||||
moveLeft: ->
|
||||
@moveCursors (cursor) -> cursor.moveLeft()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{View} = require 'space-pen'
|
||||
Anchor = require 'anchor'
|
||||
Point = require 'point'
|
||||
_ = require 'underscore'
|
||||
|
||||
@@ -7,45 +8,38 @@ class Cursor extends View
|
||||
@content: ->
|
||||
@pre class: 'cursor idle', => @raw ' '
|
||||
|
||||
anchor: null
|
||||
editor: null
|
||||
screenPosition: null
|
||||
bufferPosition: null
|
||||
wordRegex: /(\w+)|([^\w\s]+)/g
|
||||
|
||||
initialize: (@editor) ->
|
||||
@screenPosition = new Point(0, 0)
|
||||
@anchor = new Anchor(@editor)
|
||||
@one 'attach', => @updateAppearance()
|
||||
|
||||
handleBufferChange: (e) ->
|
||||
{ newRange, oldRange } = e
|
||||
position = @getBufferPosition()
|
||||
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])
|
||||
@anchor.handleBufferChange(e)
|
||||
@refreshScreenPosition()
|
||||
|
||||
remove: ->
|
||||
@editor.compositeCursor.removeCursor(this)
|
||||
@editor.compositeSelection.removeSelectionForCursor(this)
|
||||
super
|
||||
|
||||
getBufferPosition: ->
|
||||
@anchor.getBufferPosition()
|
||||
|
||||
setBufferPosition: (bufferPosition) ->
|
||||
@anchor.setBufferPosition(bufferPosition)
|
||||
@refreshScreenPosition()
|
||||
|
||||
getScreenPosition: ->
|
||||
@anchor.getScreenPosition()
|
||||
|
||||
setScreenPosition: (position, options={}) ->
|
||||
position = Point.fromObject(position)
|
||||
clip = options.clip ? true
|
||||
|
||||
@screenPosition = if clip then @editor.clipScreenPosition(position) else position
|
||||
@bufferPosition = @editor.bufferPositionForScreenPosition(position)
|
||||
|
||||
Object.freeze @screenPosition
|
||||
Object.freeze @bufferPosition
|
||||
@anchor.setScreenPosition(position, options)
|
||||
@refreshScreenPosition(position, options)
|
||||
|
||||
refreshScreenPosition: ->
|
||||
@goalColumn = null
|
||||
@updateAppearance()
|
||||
@trigger 'cursor:position-changed'
|
||||
@@ -54,18 +48,6 @@ class Cursor extends View
|
||||
window.clearTimeout(@idleTimeout) if @idleTimeout
|
||||
@idleTimeout = window.setTimeout (=> @addClass 'idle'), 200
|
||||
|
||||
setBufferPosition: (bufferPosition) ->
|
||||
@setScreenPosition(@editor.screenPositionForBufferPosition(bufferPosition), clip: false)
|
||||
|
||||
refreshScreenPosition: ->
|
||||
@setBufferPosition(@bufferPosition)
|
||||
|
||||
getBufferPosition: ->
|
||||
@bufferPosition
|
||||
|
||||
getScreenPosition: ->
|
||||
@screenPosition
|
||||
|
||||
getCurrentBufferLine: ->
|
||||
@editor.lineForBufferRow(@getBufferPosition().row)
|
||||
|
||||
|
||||
@@ -222,7 +222,7 @@ class Editor extends View
|
||||
unless newRange.isSingleLine() and newRange.coversSameRows(oldRange)
|
||||
@gutter.renderLineNumbers(@getScreenLines())
|
||||
|
||||
@compositeCursor.refreshScreenPosition() unless e.bufferChanged
|
||||
@compositeCursor.updateBufferPosition() unless e.bufferChanged
|
||||
|
||||
lineElements = @buildLineElements(newRange.start.row, newRange.end.row)
|
||||
@replaceLineElements(oldRange.start.row, oldRange.end.row, lineElements)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
Anchor = require 'anchor'
|
||||
Cursor = require 'cursor'
|
||||
AceOutdentAdaptor = require 'ace-outdent-adaptor'
|
||||
Point = require 'point'
|
||||
@@ -22,33 +23,25 @@ class Selection extends View
|
||||
@clearSelection()
|
||||
|
||||
handleBufferChange: (e) ->
|
||||
return unless @anchorScreenPosition
|
||||
return unless @anchor
|
||||
@anchor.handleBufferChange(e)
|
||||
|
||||
{ oldRange, newRange } = e
|
||||
position = @anchorBufferPosition
|
||||
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
|
||||
|
||||
@setAnchorBufferPosition([newRow, newColumn])
|
||||
placeAnchor: ->
|
||||
return if @anchor
|
||||
@anchor = new Anchor(@editor)
|
||||
@anchor.setScreenPosition @cursor.getScreenPosition()
|
||||
|
||||
isEmpty: ->
|
||||
@getBufferRange().isEmpty()
|
||||
|
||||
isReversed: ->
|
||||
not @isEmpty() and @cursor.getBufferPosition().isLessThan(@anchorBufferPosition)
|
||||
not @isEmpty() and @cursor.getBufferPosition().isLessThan(@anchor.getBufferPosition())
|
||||
|
||||
intersectsWith: (otherSelection) ->
|
||||
@getScreenRange().intersectsWith(otherSelection.getScreenRange())
|
||||
|
||||
clearSelection: ->
|
||||
@anchorScreenPosition = null
|
||||
@anchor = null
|
||||
@updateAppearance()
|
||||
|
||||
updateAppearance: ->
|
||||
@@ -87,8 +80,8 @@ class Selection extends View
|
||||
@regions = []
|
||||
|
||||
getScreenRange: ->
|
||||
if @anchorScreenPosition
|
||||
new Range(@anchorScreenPosition, @cursor.getScreenPosition())
|
||||
if @anchor
|
||||
new Range(@anchor.getScreenPosition(), @cursor.getScreenPosition())
|
||||
else
|
||||
new Range(@cursor.getScreenPosition(), @cursor.getScreenPosition())
|
||||
|
||||
@@ -168,24 +161,6 @@ class Selection extends View
|
||||
fn()
|
||||
@retainSelection = false
|
||||
|
||||
placeAnchor: ->
|
||||
return if @anchorScreenPosition
|
||||
@setAnchorScreenPosition(@cursor.getScreenPosition())
|
||||
|
||||
setAnchorScreenPosition: (screenPosition) ->
|
||||
bufferPosition = Point.fromObject(screenPosition)
|
||||
@anchorScreenPosition = screenPosition
|
||||
@anchorBufferPosition = @editor.bufferPositionForScreenPosition(screenPosition)
|
||||
|
||||
setAnchorBufferPosition: (bufferPosition) ->
|
||||
bufferPosition = Point.fromObject(bufferPosition)
|
||||
@anchorBufferPosition = bufferPosition
|
||||
@anchorScreenPosition = @editor.screenPositionForBufferPosition(bufferPosition)
|
||||
|
||||
selectToScreenPosition: (position) ->
|
||||
@modifySelection =>
|
||||
@cursor.setScreenPosition(position)
|
||||
|
||||
selectWord: ->
|
||||
row = @cursor.getScreenPosition().row
|
||||
column = @cursor.getScreenPosition().column
|
||||
@@ -207,6 +182,9 @@ class Selection extends View
|
||||
rowLength = @editor.buffer.lineForRow(row).length
|
||||
@setBufferRange new Range([row, 0], [row, rowLength])
|
||||
|
||||
selectToScreenPosition: (position) ->
|
||||
@modifySelection => @cursor.setScreenPosition(position)
|
||||
|
||||
selectRight: ->
|
||||
@modifySelection => @cursor.moveRight()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user