From b4cfd7fc85837f5ea580d75629d93e0c501a097e Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Tue, 3 Apr 2012 08:53:02 -0700 Subject: [PATCH] Selection and Cursor use Anchor to hold their buffer and screen positions --- spec/atom/selection-spec.coffee | 2 +- src/atom/anchor.coffee | 47 +++++++++++++++++++++++++++ src/atom/composite-cursor.coffee | 4 +-- src/atom/cursor.coffee | 54 +++++++++++--------------------- src/atom/editor.coffee | 2 +- src/atom/selection.coffee | 50 +++++++++-------------------- 6 files changed, 83 insertions(+), 76 deletions(-) create mode 100644 src/atom/anchor.coffee diff --git a/spec/atom/selection-spec.coffee b/spec/atom/selection-spec.coffee index 158770d6f..4ba0336d0 100644 --- a/spec/atom/selection-spec.coffee +++ b/spec/atom/selection-spec.coffee @@ -17,7 +17,7 @@ describe "Selection", -> it "places the anchor at the start of the range and the cursor at the end", -> range = new Range({row: 2, column: 7}, {row: 3, column: 18}) selection.setBufferRange(range) - expect(selection.anchorScreenPosition).toEqual range.start + expect(selection.anchor.getScreenPosition()).toEqual range.start expect(selection.cursor.getScreenPosition()).toEqual range.end describe ".deleteSelectedText()", -> diff --git a/src/atom/anchor.coffee b/src/atom/anchor.coffee new file mode 100644 index 000000000..d1eeb105f --- /dev/null +++ b/src/atom/anchor.coffee @@ -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 \ No newline at end of file diff --git a/src/atom/composite-cursor.coffee b/src/atom/composite-cursor.coffee index 6e2ae19dc..ac852e926 100644 --- a/src/atom/composite-cursor.coffee +++ b/src/atom/composite-cursor.coffee @@ -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() diff --git a/src/atom/cursor.coffee b/src/atom/cursor.coffee index b1f8056bc..1085c74be 100644 --- a/src/atom/cursor.coffee +++ b/src/atom/cursor.coffee @@ -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) diff --git a/src/atom/editor.coffee b/src/atom/editor.coffee index 7b490325d..be413aa15 100644 --- a/src/atom/editor.coffee +++ b/src/atom/editor.coffee @@ -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) diff --git a/src/atom/selection.coffee b/src/atom/selection.coffee index 4ee6a68fb..274468e7d 100644 --- a/src/atom/selection.coffee +++ b/src/atom/selection.coffee @@ -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()