Merge remote-tracking branch 'origin/folding' into chrome

This commit is contained in:
Corey Johnson & Nathan Sobo
2012-02-28 16:07:35 -08:00
12 changed files with 322 additions and 134 deletions

View File

@@ -13,11 +13,11 @@ class Cursor extends View
@one 'attach', => @updateAppearance()
bufferChanged: (e) ->
@setScreenPosition(e.newRange.end)
@setBufferPosition(e.newRange.end)
setScreenPosition: (point) ->
point = Point.fromObject(point)
@$position = @editor.clipPosition(point)
setScreenPosition: (position) ->
position = Point.fromObject(position)
@screenPosition = @editor.clipScreenPosition(position)
@goalColumn = null
@updateAppearance()
@trigger 'cursor:position-changed'
@@ -26,7 +26,13 @@ class Cursor extends View
window.clearTimeout(@idleTimeout) if @idleTimeout
@idleTimeout = window.setTimeout (=> @addClass 'idle'), 200
getScreenPosition: -> _.clone(@$position)
setBufferPosition: (bufferPosition) ->
@setScreenPosition(@editor.screenPositionForBufferPosition(bufferPosition))
getBufferPosition: ->
@editor.bufferPositionForScreenPosition(@getScreenPosition())
getScreenPosition: -> _.clone(@screenPosition)
getColumn: ->
@getScreenPosition().column
@@ -44,21 +50,13 @@ class Cursor extends View
moveUp: ->
{ row, column } = @getScreenPosition()
column = @goalColumn if @goalColumn?
if row > 0
@setScreenPosition({row: row - 1, column: column})
else
@moveToLineStart()
@setScreenPosition({row: row - 1, column: column})
@goalColumn = column
moveDown: ->
{ row, column } = @getScreenPosition()
column = @goalColumn if @goalColumn?
if row < @editor.buffer.numLines() - 1
@setScreenPosition({row: row + 1, column: column})
else
@moveToLineEnd()
@setScreenPosition({row: row + 1, column: column})
@goalColumn = column
moveToLineEnd: ->
@@ -71,20 +69,16 @@ class Cursor extends View
moveRight: ->
{ row, column } = @getScreenPosition()
if column < @editor.buffer.getLine(row).length
column++
else if row < @editor.buffer.numLines() - 1
row++
column = 0
@setScreenPosition({row, column})
@setScreenPosition(@editor.clipScreenPosition([row, column + 1], skipAtomicTokens: true, wrapBeyondNewlines: true, wrapAtSoftNewlines: true))
moveLeft: ->
{ row, column } = @getScreenPosition()
if column > 0
column--
else if row > 0
else
row--
column = @editor.buffer.getLine(row).length
column = Infinity
@setScreenPosition({row, column})
@@ -111,7 +105,7 @@ class Cursor extends View
@setScreenPosition [row, column + offset]
updateAppearance: ->
position = @editor.pixelPositionFromPoint(@getScreenPosition())
position = @editor.pixelPositionForScreenPosition(@getScreenPosition())
@css(position)
@autoScrollVertically(position)
@autoScrollHorizontally(position)

View File

@@ -95,7 +95,7 @@ class Editor extends View
clickCount = e.originalEvent.detail
if clickCount == 1
@setCursorScreenPosition @pointFromMouseEvent(e)
@setCursorScreenPosition @screenPositionFromMouseEvent(e)
else if clickCount == 2
@selection.selectWord()
else if clickCount >= 3
@@ -107,7 +107,7 @@ class Editor extends View
@insertText(e.originalEvent.data)
@on 'cursor:position-changed', =>
@hiddenInput.css(@pixelPositionFromPoint(@cursor.getScreenPosition()))
@hiddenInput.css(@pixelPositionForScreenPosition(@cursor.getScreenPosition()))
@one 'attach', =>
@calculateDimensions()
@@ -116,7 +116,7 @@ class Editor extends View
@focus()
selectTextOnMouseMovement: ->
moveHandler = (e) => @selectToPosition(@pointFromMouseEvent(e))
moveHandler = (e) => @selectToScreenPosition(@screenPositionFromMouseEvent(e))
@on 'mousemove', moveHandler
$(document).one 'mouseup', => @off 'mousemove', moveHandler
@@ -132,9 +132,21 @@ class Editor extends View
renderLines: ->
@lines.empty()
for screenLine in @lineWrapper.getLines()
for screenLine in @getScreenLines()
@lines.append @buildLineElement(screenLine)
getScreenLines: ->
@lineWrapper.getLines()
linesForScreenRows: (start, end) ->
@lineWrapper.linesForScreenRows(start, end)
screenLineCount: ->
@lineWrapper.lineCount()
lastScreenRow: ->
@screenLineCount() - 1
setBuffer: (@buffer) ->
@highlighter = new Highlighter(@buffer)
@lineFolder = new LineFolder(@highlighter)
@@ -146,9 +158,12 @@ class Editor extends View
@buffer.on 'change', (e) =>
@cursor.bufferChanged(e)
@lineFolder.on 'fold', (range) =>
@setCursorBufferPosition(range.end)
@lineWrapper.on 'change', (e) =>
{ oldRange, newRange } = e
screenLines = @lineWrapper.linesForScreenRows(newRange.start.row, newRange.end.row)
screenLines = @linesForScreenRows(newRange.start.row, newRange.end.row)
if newRange.end.row > oldRange.end.row
# update, then insert elements
for row in [newRange.start.row..newRange.end.row]
@@ -202,27 +217,30 @@ class Editor extends View
else
$(window).off 'resize', @_setMaxLineLength
clipPosition: ({row, column}) ->
if row > @buffer.lastRow()
row = @buffer.lastRow()
column = @buffer.getLine(row).length
else
row = Math.min(Math.max(0, row), @buffer.numLines() - 1)
column = Math.min(Math.max(0, column), @buffer.getLine(row).length)
clipScreenPosition: (screenPosition, eagerWrap=false) ->
@lineWrapper.clipScreenPosition(screenPosition, eagerWrap)
new Point(row, column)
pixelPositionFromPoint: (position) ->
{ row, column } = @lineWrapper.screenPositionForBufferPosition(position)
pixelPositionForScreenPosition: ({row, column}) ->
{ top: row * @lineHeight, left: column * @charWidth }
pointFromPixelPosition: ({top, left}) ->
screenPositionFromPixelPosition: ({top, left}) ->
screenPosition = new Point(Math.floor(top / @lineHeight), Math.floor(left / @charWidth))
@lineWrapper.bufferPositionForScreenPosition screenPosition
pointFromMouseEvent: (e) ->
screenPositionForBufferPosition: (position) ->
@lineWrapper.screenPositionForBufferPosition(position)
bufferPositionForScreenPosition: (position) ->
@lineWrapper.bufferPositionForScreenPosition(position)
screenRangeForBufferRange: (range) ->
@lineWrapper.screenRangeForBufferRange(range)
bufferRangeForScreenRange: (range) ->
@lineWrapper.bufferRangeForScreenRange(range)
screenPositionFromMouseEvent: (e) ->
{ pageX, pageY } = e
@pointFromPixelPosition
@screenPositionFromPixelPosition
top: pageY - @lines.offset().top
left: pageX - @lines.offset().left
@@ -254,8 +272,10 @@ class Editor extends View
moveCursorDown: -> @cursor.moveDown()
moveCursorRight: -> @cursor.moveRight()
moveCursorLeft: -> @cursor.moveLeft()
setCursorScreenPosition: (point) -> @cursor.setScreenPosition(point)
setCursorScreenPosition: (position) -> @cursor.setScreenPosition(position)
getCursorScreenPosition: -> @cursor.getScreenPosition()
setCursorBufferPosition: (position) -> @cursor.setBufferPosition(position)
getCursorBufferPosition: -> @cursor.getBufferPosition()
setCursorRow: (row) -> @cursor.setRow(row)
getCursorRow: -> @cursor.getRow()
setCursorColumn: (column) -> @cursor.setColumn(column)
@@ -265,8 +285,10 @@ class Editor extends View
selectLeft: -> @selection.selectLeft()
selectUp: -> @selection.selectUp()
selectDown: -> @selection.selectDown()
selectToPosition: (position) ->
@selection.selectToPosition(position)
selectToScreenPosition: (position) ->
@selection.selectToScreenPosition(position)
selectToBufferPosition: (position) ->
@selection.selectToBufferPosition(position)
insertText: (text) -> @selection.insertText(text)
insertNewline: -> @selection.insertNewline()

View File

@@ -21,9 +21,7 @@ class LineFolder
@lineMap.insertAtBufferRow(0, @highlighter.screenLines)
logLines: (start=0, end=@lastRow())->
for row in [start..end]
line = @lineForScreenRow(row).text
console.log row, line, line.length
@lineMap.logLines(start, end)
createFold: (bufferRange) ->
fold = new Fold(this, bufferRange)
@@ -116,7 +114,7 @@ class LineFolder
@lineMap.lineForScreenRow(screenRow)
getLines: ->
@lineMap.getScreenLines()
@lineMap.screenLinesForRows(0, @lastRow())
lineCount: ->
@lineMap.screenLineCount()
@@ -136,12 +134,15 @@ class LineFolder
bufferPositionForScreenPosition: (screenPosition) ->
@lineMap.bufferPositionForScreenPosition(screenPosition)
clipScreenPosition: (screenPosition) ->
@lineMap.clipScreenPosition(screenPosition)
clipScreenPosition: (screenPosition, options={}) ->
@lineMap.clipScreenPosition(screenPosition, options)
screenRangeForBufferRange: (bufferRange) ->
@lineMap.screenRangeForBufferRange(bufferRange)
bufferRangeForScreenRange: (screenRange) ->
@lineMap.bufferRangeForScreenRange(screenRange)
expandScreenRangeToLineEnds: (screenRange) ->
{ start, end } = screenRange
new Range([start.row, 0], [end.row, @lineMap.lineForScreenRow(end.row).text.length])

View File

@@ -50,14 +50,10 @@ class LineMap
replaceScreenRows: (start, end, screenLines) ->
@spliceAtScreenRow(start, end - start + 1, screenLines)
getScreenLines: ->
return @screenLines
lineForScreenRow: (row) ->
@linesForScreenRows(row, row)[0]
linesForScreenRows: (startRow, endRow) ->
lastLine = null
lines = []
delta = new Point
@@ -67,11 +63,13 @@ class LineMap
if pendingFragment
pendingFragment = pendingFragment.concat(fragment)
else
pendingFragment = fragment
pendingFragment = _.clone(fragment)
if pendingFragment.screenDelta.row > 0
pendingFragment.bufferDelta = new Point(1, 0)
lines.push pendingFragment
pendingFragment = null
delta = delta.add(fragment.screenDelta)
lines
lineForBufferRow: (row) ->
@@ -99,6 +97,9 @@ class LineMap
delta = delta.add(screenLine.screenDelta)
delta.row
lastScreenRow: ->
@screenLineCount() - 1
screenPositionForBufferPosition: (bufferPosition, eagerWrap=true) ->
bufferPosition = Point.fromObject(bufferPosition)
bufferDelta = new Point
@@ -135,18 +136,52 @@ class LineMap
end = @screenPositionForBufferPosition(bufferRange.end)
new Range(start, end)
clipScreenPosition: (screenPosition) ->
bufferRangeForScreenRange: (screenRange) ->
start = @bufferPositionForScreenPosition(screenRange.start)
end = @bufferPositionForScreenPosition(screenRange.end)
new Range(start, end)
clipScreenPosition: (screenPosition, options) ->
wrapBeyondNewlines = options.wrapBeyondNewlines ? false
wrapAtSoftNewlines = options.wrapAtSoftNewlines ? false
skipAtomicTokens = options.skipAtomicTokens ? false
screenPosition = Point.fromObject(screenPosition)
screenPosition = new Point(Math.max(0, screenPosition.row), Math.max(0, screenPosition.column))
screenPosition.column = Math.max(0, screenPosition.column)
if screenPosition.row < 0
screenPosition.row = 0
screenPosition.column = 0
if screenPosition.row > @lastScreenRow()
screenPosition.row = @lastScreenRow()
screenPosition.column = Infinity
screenDelta = new Point
for screenLine in @screenLines
nextDelta = screenDelta.add(screenLine.screenDelta)
for lineFragment in @screenLines
nextDelta = screenDelta.add(lineFragment.screenDelta)
break if nextDelta.isGreaterThan(screenPosition)
screenDelta = nextDelta
maxColumn = screenDelta.column + screenLine.lengthForClipping()
screenDelta.column = Math.min(maxColumn, screenPosition.column)
if lineFragment.isAtomic
if skipAtomicTokens and screenPosition.column > screenDelta.column
return new Point(screenDelta.row, screenDelta.column + lineFragment.text.length)
else
return screenDelta
screenDelta
maxColumn = screenDelta.column + lineFragment.text.length
if lineFragment.isSoftWrapped() and screenPosition.column >= maxColumn
if wrapAtSoftNewlines
return new Point(screenDelta.row + 1, 0)
else
return new Point(screenDelta.row, maxColumn - 1)
if screenPosition.column > maxColumn and wrapBeyondNewlines
return new Point(screenDelta.row + 1, 0)
new Point(screenDelta.row, Math.min(maxColumn, screenPosition.column))
logLines: (start=0, end=@screenLineCount() - 1)->
for row in [start..end]
line = @lineForScreenRow(row).text
console.log row, line, line.length

View File

@@ -76,9 +76,6 @@ class LineWrapper
return column + 1 if /\s/.test(line[column])
return @maxLength
screenRangeForBufferRange: (bufferRange) ->
@lineMap.screenRangeForBufferRange(bufferRange)
screenPositionForBufferPosition: (bufferPosition, eagerWrap=true) ->
@lineMap.screenPositionForBufferPosition(
@lineFolder.screenPositionForBufferPosition(bufferPosition),
@@ -88,6 +85,22 @@ class LineWrapper
@lineFolder.bufferPositionForScreenPosition(
@lineMap.bufferPositionForScreenPosition(screenPosition))
screenRangeForBufferRange: (bufferRange) ->
@lineMap.screenRangeForBufferRange(
@lineFolder.screenRangeForBufferRange(bufferRange))
bufferRangeForScreenRange: (screenRange) ->
@lineFolder.bufferRangeForScreenRange(
@lineMap.bufferRangeForScreenRange(screenRange))
clipScreenPosition: (screenPosition, options={}) ->
@lineMap.screenPositionForBufferPosition(
@lineFolder.clipScreenPosition(
@lineMap.bufferPositionForScreenPosition(@lineMap.clipScreenPosition(screenPosition, options)),
options
)
)
lineForScreenRow: (screenRow) ->
@linesForScreenRows(screenRow, screenRow)[0]
@@ -95,9 +108,15 @@ class LineWrapper
@lineMap.linesForScreenRows(startRow, endRow)
getLines: ->
@linesForScreenRows(0, @lineCount() - 1)
@linesForScreenRows(0, @lastRow())
lineCount: ->
@lineMap.screenLineCount()
lastRow: ->
@lineCount() - 1
logLines: (start=0, end=@lineCount() - 1)->
@lineMap.logLines(start, end)
_.extend(LineWrapper.prototype, EventEmitter)

View File

@@ -52,5 +52,8 @@ class ScreenLineFragment
else
@text.length
isSoftWrapped: ->
@screenDelta.row == 1 and @bufferDelta.row == 0
isEqual: (other) ->
_.isEqual(@tokens, other.tokens) and @screenDelta.isEqual(other.screenDelta) and @bufferDelta.isEqual(other.bufferDelta)

View File

@@ -60,35 +60,38 @@ class Selection extends View
region.remove() for region in @regions
@regions = []
getRange: ->
getScreenRange: ->
if @anchor
new Range(@anchor.getScreenPosition(), @cursor.getScreenPosition())
else
new Range(@cursor.getScreenPosition(), @cursor.getScreenPosition())
setRange: (range) ->
setScreenRange: (range) ->
@cursor.setScreenPosition(range.start)
@modifySelection =>
@cursor.setScreenPosition(range.end)
getScreenRange: ->
@editor.lineWrapper.screenRangeForBufferRange(@getRange())
getBufferRange: ->
@editor.bufferRangeForScreenRange(@getScreenRange())
setBufferRange: (bufferRange) ->
@setScreenRange(@editor.screenRangeForBufferRange(bufferRange))
getText: ->
@editor.buffer.getTextInRange @getRange()
@editor.buffer.getTextInRange @getBufferRange()
insertText: (text) ->
@editor.buffer.change(@getRange(), text)
@editor.buffer.change(@getBufferRange(), text)
insertNewline: ->
@insertText('\n')
delete: ->
range = @getRange()
range = @getBufferRange()
@editor.buffer.change(range, '') unless range.isEmpty()
isEmpty: ->
@getRange().isEmpty()
@getBufferRange().isEmpty()
modifySelection: (fn) ->
@placeAnchor()
@@ -114,11 +117,11 @@ class Selection extends View
endOffset = regex.exec(rightSide)?[0]?.length or 0
range = new Range([row, column + startOffset], [row, column + endOffset])
@setRange range
@setBufferRange range
selectLine: (row) ->
rowLength = @editor.buffer.getLine(row).length
@setRange new Range([row, 0], [row, rowLength])
@setBufferRange new Range([row, 0], [row, rowLength])
selectRight: ->
@modifySelection =>
@@ -140,10 +143,14 @@ class Selection extends View
@modifySelection =>
@cursor.moveLeftUntilMatch(regex)
selectToPosition: (position) ->
selectToScreenPosition: (position) ->
@modifySelection =>
@cursor.setScreenPosition(position)
selectToBufferPosition: (position) ->
@modifySelection =>
@cursor.setBufferPosition(position)
moveCursorToLineEnd: ->
@cursor.moveToLineEnd()
@@ -156,8 +163,8 @@ class Selection extends View
copy: ->
return if @isEmpty()
text = @editor.buffer.getTextInRange @getRange()
text = @editor.buffer.getTextInRange(@getBufferRange())
atom.native.writeToPasteboard text
fold: ->
@editor.lineFolder.createFold(@getRange())
@editor.lineFolder.createFold(@getBufferRange())

View File

@@ -13,7 +13,7 @@ class MoveLeft extends Motion
select: ->
position = @editor.getCursorScreenPosition()
position.column-- if position.column > 0
@editor.selectToPosition position
@editor.selectToBufferPosition(position)
class MoveRight extends Motion
execute: ->
@@ -42,7 +42,7 @@ class MoveToNextWord extends Motion
@editor.setCursorScreenPosition(@nextWordPosition())
select: ->
@editor.selectToPosition(@nextWordPosition())
@editor.selectToBufferPosition(@nextWordPosition())
nextWordPosition: ->
regex = getWordRegex()