Merge branch 'master' into overdraw

This commit is contained in:
Nathan Sobo
2012-05-25 13:13:06 -07:00
28 changed files with 1279 additions and 693 deletions

View File

@@ -242,4 +242,9 @@ class Buffer
backwardsScanInRange: (regex, range, iterator) ->
@scanInRange regex, range, iterator, true
logLines: (start=0, end=@getLastRow())->
for row in [start..end]
line = @lineForRow(row)
console.log row, line, line.length
_.extend(Buffer.prototype, EventEmitter)

View File

@@ -74,6 +74,10 @@ class CompositeSeleciton
getText: ->
@getLastSelection().getText()
intersectsBufferRange: (bufferRange) ->
_.any @getSelections(), (selection) ->
selection.intersectsBufferRange(bufferRange)
expandSelectionsForward: (fn) ->
fn(selection) for selection in @getSelections()
@mergeIntersectingSelections()

View File

@@ -177,4 +177,9 @@ class Cursor extends View
if this == _.last(@editor.getCursors())
@editor.scrollTo(pixelPosition)
if @editor.isFoldedAtScreenRow(screenPosition.row)
@hide()
else
@show()
@selection.updateAppearance()

View File

@@ -63,6 +63,7 @@ class Editor extends View
requireStylesheet 'theme/twilight.css'
@id = Editor.idCounter++
@lineCache = []
@bindKeys()
@autoIndent = true
@buildCursorAndSelection()
@@ -120,6 +121,7 @@ class Editor extends View
'redo': @redo
'toggle-soft-wrap': @toggleSoftWrap
'fold-selection': @foldSelection
'unfold': => @unfoldRow(@getCursorBufferPosition().row)
'split-left': @splitLeft
'split-right': @splitRight
'split-up': @splitUp
@@ -174,8 +176,8 @@ class Editor extends View
@isFocused = false
@removeClass 'focused'
@visibleLines.on 'mousedown', '.fold-placeholder', (e) =>
@destroyFold($(e.currentTarget).attr('foldId'))
@visibleLines.on 'mousedown', '.fold.line', (e) =>
@destroyFold($(e.currentTarget).attr('fold-id'))
false
@visibleLines.on 'mousedown', (e) =>
@@ -276,8 +278,11 @@ class Editor extends View
if options?.adjustVerticalScrollbar ? true
@verticalScrollbar.scrollTop(scrollTop)
scrollBottom: ->
@scrollTop() + @scrollView.height()
scrollBottom: (scrollBottom) ->
if scrollBottom?
@scrollTop(scrollBottom - @scrollView.height())
else
@scrollTop() + @scrollView.height()
renderVisibleLines: ->
@clearLines()
@@ -294,8 +299,6 @@ class Editor extends View
firstVisibleScreenRow = @getFirstVisibleScreenRow()
lastVisibleScreenRow = @getLastVisibleScreenRow()
return if @firstRenderedScreenRow <= firstVisibleScreenRow and @lastRenderedScreenRow >= lastVisibleScreenRow
@gutter.renderLineNumbers(firstVisibleScreenRow, lastVisibleScreenRow)
renderFrom = Math.max(0, firstVisibleScreenRow - @lineOverdraw)
@@ -349,10 +352,24 @@ class Editor extends View
getLastVisibleScreenRow: ->
Math.ceil((@scrollTop() + @scrollView.height()) / @lineHeight) - 1
highlightSelectedFolds: ->
screenLines = @screenLinesForRows(@firstRenderedScreenRow, @lastRenderedScreenRow)
for screenLine, i in screenLines
if fold = screenLine.fold
screenRow = @firstRenderedScreenRow + i
element = @lineElementForScreenRow(screenRow)
if @compositeSelection.intersectsBufferRange(fold.getBufferRange())
element.addClass('selected')
else
element.removeClass('selected')
getScreenLines: ->
@renderer.getLines()
linesForRows: (start, end) ->
screenLineForRow: (start) ->
@renderer.lineForRow(start)
screenLinesForRows: (start, end) ->
@renderer.linesForRows(start, end)
screenLineCount: ->
@@ -361,6 +378,12 @@ class Editor extends View
getLastScreenRow: ->
@screenLineCount() - 1
isFoldedAtScreenRow: (screenRow) ->
@screenLineForRow(screenRow).fold?
destroyFoldsContainingBufferRow: (bufferRow) ->
@renderer.destroyFoldsContainingBufferRow(bufferRow)
setBuffer: (buffer) ->
if @buffer
@saveCurrentEditSession()
@@ -438,33 +461,60 @@ class Editor extends View
@compositeCursor.updateBufferPosition() unless e.bufferChanged
if @attached
unless newScreenRange.isSingleLine() and newScreenRange.coversSameRows(oldScreenRange)
if e.lineNumbersChanged
@gutter.renderLineNumbers(@getFirstVisibleScreenRow(), @getLastVisibleScreenRow())
@verticalScrollbarContent.height(@lineHeight * @screenLineCount())
return if oldScreenRange.start.row > @lastRenderedScreenRow
newScreenRange = newScreenRange.copy()
oldScreenRange = oldScreenRange.copy()
endOfShortestRange = Math.min(oldScreenRange.end.row, newScreenRange.end.row)
delta = @firstRenderedScreenRow - endOfShortestRange
if delta > 0
newScreenRange.start.row += delta
newScreenRange.end.row += delta
oldScreenRange.start.row += delta
oldScreenRange.end.row += delta
newScreenRange.start.row = Math.max(newScreenRange.start.row, @firstRenderedScreenRow)
oldScreenRange.start.row = Math.max(oldScreenRange.start.row, @firstRenderedScreenRow)
newScreenRange.end.row = Math.min(newScreenRange.end.row, @lastRenderedScreenRow)
oldScreenRange.end.row = Math.min(oldScreenRange.end.row, @lastRenderedScreenRow)
lineElements = @buildLineElements(newScreenRange.start.row, newScreenRange.end.row)
@replaceLineElements(oldScreenRange.start.row, oldScreenRange.end.row, lineElements)
@verticalScrollbarContent.height(@lineHeight * @screenLineCount())
rowDelta = newScreenRange.end.row - oldScreenRange.end.row
@lastRenderedScreenRow += rowDelta
@updateVisibleLines() if rowDelta < 0
if rowDelta > 0
@removeLineElements(@lastRenderedScreenRow + 1, @lastRenderedScreenRow + rowDelta)
else if rowDelta < 0
@lastRenderedScreenRow += rowDelta
@updateVisibleLines()
buildLineElements: (startRow, endRow) ->
charWidth = @charWidth
charHeight = @charHeight
lines = @renderer.linesForRows(startRow, endRow)
compositeSelection = @compositeSelection
$$ ->
for line in lines
@div class: 'line', =>
appendNbsp = true
for token in line.tokens
if token.type is 'fold-placeholder'
@span ' ', class: 'fold-placeholder', style: "width: #{3 * charWidth}px; height: #{charHeight}px;", 'foldId': token.fold.id, =>
@div class: "ellipsis", => @raw "&hellip;"
else
appendNbsp = false
if fold = line.fold
lineAttributes = { class: 'fold line', 'fold-id': fold.id }
if compositeSelection.intersectsBufferRange(fold.getBufferRange())
lineAttributes.class += ' selected'
else
lineAttributes = { class: 'line' }
@div lineAttributes, =>
if line.text == ''
@raw '&nbsp;' if line.text == ''
else
for token in line.tokens
@span { class: token.type.replace('.', ' ') }, token.value
@raw '&nbsp;' if appendNbsp
insertLineElements: (row, lineElements) ->
@spliceLineElements(row, 0, lineElements)
@@ -499,8 +549,9 @@ class Editor extends View
elementsToReplace.forEach (element) =>
lines.removeChild(element)
getLineElement: (row) ->
@lineCache[row]
lineElementForScreenRow: (screenRow) ->
element = @lineCache[screenRow - @firstRenderedScreenRow]
$(element)
toggleSoftWrap: ->
@setSoftWrap(not @softWrap)
@@ -515,8 +566,8 @@ class Editor extends View
maxLineLength ?= @calcMaxLineLength()
@renderer.setMaxLineLength(maxLineLength) if maxLineLength
createFold: (range) ->
@renderer.createFold(range)
createFold: (startRow, endRow) ->
@renderer.createFold(startRow, endRow)
setSoftWrap: (@softWrap, maxLineLength=undefined) ->
@setMaxLineLength(maxLineLength) if @attached
@@ -673,6 +724,9 @@ class Editor extends View
foldSelection: -> @getSelection().fold()
unfoldRow: (row) ->
@renderer.largestFoldForBufferRow(row)?.destroy()
undo: ->
if ranges = @buffer.undo()
@setSelectedBufferRanges(ranges)
@@ -684,7 +738,7 @@ class Editor extends View
destroyFold: (foldId) ->
fold = @renderer.foldsById[foldId]
fold.destroy()
@setCursorBufferPosition(fold.start)
@setCursorBufferPosition([fold.startRow, 0])
splitLeft: ->
@pane()?.splitLeft(@copy()).wrappedView
@@ -729,6 +783,9 @@ class Editor extends View
@scrollVertically(pixelPosition)
@scrollHorizontally(pixelPosition)
scrollToBottom: ->
@scrollBottom(@scrollView.prop('scrollHeight'))
scrollVertically: (pixelPosition) ->
linesInView = @scrollView.height() / @lineHeight
maxScrollMargin = Math.floor((linesInView - 1) / 2)
@@ -762,5 +819,5 @@ class Editor extends View
for cursor in @getCursors()
do (cursor) -> cursor.resetCursorAnimation()
logLines: ->
@renderer.logLines()
logLines: (start, end) ->
@renderer.logLines(start, end)

View File

@@ -1,51 +1,66 @@
Range = require 'range'
Point = require 'point'
module.exports =
class Fold
@idCounter: 1
start: null
end: null
constructor: (@lineFolder, {@start, @end}) ->
renderer: null
startRow: null
endRow: null
constructor: (@renderer, @startRow, @endRow) ->
@id = @constructor.idCounter++
destroy: ->
@lineFolder.destroyFold(this)
@renderer.destroyFold(this)
getRange: ->
new Range(@start, @end)
inspect: ->
"Fold(#{@startRow}, #{@endRow})"
getBufferRange: ->
new Range([@startRow, 0], [@endRow, Infinity])
getBufferDelta: ->
new Point(@endRow - @startRow + 1, 0)
handleBufferChange: (event) ->
oldStartRow = @start.row
oldStartRow = @startRow
{ oldRange } = event
if oldRange.start.isLessThanOrEqual(@start) and oldRange.end.isGreaterThanOrEqual(@end)
@lineFolder.unregisterFold(oldStartRow, this)
if @isContainedByRange(event.oldRange)
@renderer.unregisterFold(@startRow, this)
return
changeInsideFold = @start.isLessThanOrEqual(oldRange.start) and @end.isGreaterThan(oldRange.end)
@updateStartRow(event)
@updateEndRow(event)
@start = @updateAnchorPoint(@start, event)
@end = @updateAnchorPoint(@end, event, false)
if @startRow != oldStartRow
@renderer.unregisterFold(oldStartRow, this)
@renderer.registerFold(this)
if @start.row != oldStartRow
@lineFolder.unregisterFold(oldStartRow, this)
@lineFolder.registerFold(@start.row, this)
isContainedByRange: (range) ->
range.start.row <= @startRow and @endRow <= range.end.row
changeInsideFold
updateAnchorPoint: (point, event, inclusive=true) ->
updateStartRow: (event) ->
{ newRange, oldRange } = event
if inclusive
return point if oldRange.end.isGreaterThan(point)
else
return point if oldRange.end.isGreaterThanOrEqual(point)
newRange.end.add(point.subtract(oldRange.end))
compare: (other) ->
startComparison = @start.compare(other.start)
if startComparison == 0
other.end.compare(@end)
if oldRange.end.row < @startRow
delta = newRange.end.row - oldRange.end.row
else if newRange.end.row < @startRow
delta = newRange.end.row - @startRow
else
startComparison
delta = 0
@startRow += delta
updateEndRow: (event) ->
{ newRange, oldRange } = event
if oldRange.end.row <= @endRow
delta = newRange.end.row - oldRange.end.row
else if newRange.end.row <= @endRow
delta = newRange.end.row - @endRow
else
delta = 0
@endRow += delta

View File

@@ -17,4 +17,6 @@ class Gutter extends View
@lineNumbers[0].innerHTML = $$$ ->
for row in rows
@div {class: 'line-number'}, if row == lastScreenRow then '' else row + 1
lastScreenRow = row
lastScreenRow = row
@lineNumbers.width(editor.getLastScreenRow().toString().length * editor.charWidth)

View File

@@ -28,6 +28,7 @@ window.keymap.bindKeys '.editor',
'meta-Z': 'redo'
'alt-meta-w': 'toggle-soft-wrap'
'alt-meta-f': 'fold-selection'
'alt-meta-u': 'unfold'
'alt-meta-left': 'split-left'
'alt-meta-right': 'split-right'
'alt-meta-up': 'split-up'

View File

@@ -121,8 +121,8 @@ class LineMap
targetDelta = traversalResult[targetDeltaType]
return targetDelta unless lastLineFragment
maxSourceColumn = sourceDelta.column + lastLineFragment.text.length
maxTargetColumn = targetDelta.column + lastLineFragment.text.length
maxSourceColumn = sourceDelta.column + lastLineFragment.textLength()
maxTargetColumn = targetDelta.column + lastLineFragment.textLength()
if lastLineFragment.isSoftWrapped() and sourcePosition.column >= maxSourceColumn
if wrapAtSoftNewlines

View File

@@ -37,7 +37,7 @@ class Renderer
oldRange = @rangeForAllLines()
@buildLineMap()
newRange = @rangeForAllLines()
@trigger 'change', { oldRange, newRange }
@trigger 'change', { oldRange, newRange, lineNumbersChanged: true }
lineForRow: (row) ->
@lineMap.lineForScreenRow(row)
@@ -51,40 +51,56 @@ class Renderer
bufferRowsForScreenRows: (startRow, endRow) ->
@lineMap.bufferRowsForScreenRows(startRow, endRow)
createFold: (bufferRange) ->
bufferRange = Range.fromObject(bufferRange)
return if bufferRange.isEmpty()
fold = new Fold(this, bufferRange)
@registerFold(bufferRange.start.row, fold)
createFold: (startRow, endRow) ->
fold = new Fold(this, startRow, endRow)
@registerFold(fold)
bufferRange = new Range([startRow, 0], [endRow, @buffer.lineLengthForRow(endRow)])
oldScreenRange = @screenLineRangeForBufferRange(bufferRange)
lines = @buildLineForBufferRow(bufferRange.start.row)
@lineMap.replaceScreenRows(
oldScreenRange.start.row,
oldScreenRange.end.row,
lines)
lines = @buildLineForBufferRow(startRow)
@lineMap.replaceScreenRows(oldScreenRange.start.row, oldScreenRange.end.row, lines)
newScreenRange = @screenLineRangeForBufferRange(bufferRange)
@trigger 'change', oldRange: oldScreenRange, newRange: newScreenRange
@trigger 'change', oldRange: oldScreenRange, newRange: newScreenRange, lineNumbersChanged: true
@trigger 'fold', bufferRange
fold
destroyFold: (fold) ->
bufferRange = fold.getRange()
@unregisterFold(bufferRange.start.row, fold)
startScreenRow = @screenRowForBufferRow(bufferRange.start.row)
@unregisterFold(fold.startRow, fold)
{ startRow, endRow } = fold
bufferRange = new Range([startRow, 0], [endRow, @buffer.lineLengthForRow(endRow)])
oldScreenRange = @screenLineRangeForBufferRange(bufferRange)
lines = @buildLinesForBufferRows(bufferRange.start.row, bufferRange.end.row)
@lineMap.replaceScreenRows(
oldScreenRange.start.row,
oldScreenRange.end.row
lines)
lines = @buildLinesForBufferRows(startRow, endRow)
@lineMap.replaceScreenRows(oldScreenRange.start.row, oldScreenRange.end.row, lines)
newScreenRange = @screenLineRangeForBufferRange(bufferRange)
@trigger 'change', oldRange: oldScreenRange, newRange: newScreenRange
@trigger 'unfold', fold.getRange()
@trigger 'change', oldRange: oldScreenRange, newRange: newScreenRange, lineNumbersChanged: true
@trigger 'unfold', bufferRange
destroyFoldsContainingBufferRow: (bufferRow) ->
folds = @activeFolds[bufferRow] ? []
fold.destroy() for fold in new Array(folds...)
registerFold: (fold) ->
@activeFolds[fold.startRow] ?= []
@activeFolds[fold.startRow].push(fold)
@foldsById[fold.id] = fold
unregisterFold: (bufferRow, fold) ->
folds = @activeFolds[bufferRow]
_.remove(folds, fold)
delete @foldsById[fold.id]
largestFoldForBufferRow: (bufferRow) ->
return unless folds = @activeFolds[bufferRow]
(folds.sort (a, b) -> b.endRow - a.endRow)[0]
screenLineRangeForBufferRange: (bufferRange) ->
@expandScreenRangeToLineEnds(
@lineMap.screenRangeForBufferRange(
@expandBufferRangeToLineEnds(bufferRange)))
screenRowForBufferRow: (bufferRow) ->
@lineMap.screenPositionForBufferPosition([bufferRow, 0]).row
@@ -111,23 +127,27 @@ class Renderer
@lineMap.clipScreenPosition(position, options)
handleBufferChange: (e) ->
for row, folds of @activeFolds
for fold in new Array(folds...)
changeInsideFold = true if fold.handleBufferChange(e)
allFolds = [] # Folds can modify @activeFolds, so first make sure we have a stable array of folds
allFolds.push(folds...) for row, folds of @activeFolds
fold.handleBufferChange(e) for fold in allFolds
unless changeInsideFold
@handleHighlighterChange(@lastHighlighterChangeEvent)
@handleHighlighterChange(@lastHighlighterChangeEvent)
handleHighlighterChange: (e) ->
oldBufferRange = e.oldRange
newBufferRange = e.newRange
newRange = e.newRange.copy()
newRange.start.row = @bufferRowForScreenRow(@screenRowForBufferRow(newRange.start.row))
oldScreenRange = @screenLineRangeForBufferRange(oldBufferRange)
newScreenLines = @buildLinesForBufferRows(newBufferRange.start.row, newBufferRange.end.row)
oldScreenRange = @screenLineRangeForBufferRange(e.oldRange)
newScreenLines = @buildLinesForBufferRows(newRange.start.row, newRange.end.row)
@lineMap.replaceScreenRows oldScreenRange.start.row, oldScreenRange.end.row, newScreenLines
newScreenRange = @screenLineRangeForBufferRange(newBufferRange)
newScreenRange = @screenLineRangeForBufferRange(newRange)
@trigger 'change', { oldRange: oldScreenRange, newRange: newScreenRange, bufferChanged: true }
@trigger 'change',
oldRange: oldScreenRange
newRange: newScreenRange
bufferChanged: true
lineNumbersChanged: !e.oldRange.coversSameRows(newRange) or !oldScreenRange.coversSameRows(newScreenRange)
buildLineForBufferRow: (bufferRow) ->
@buildLinesForBufferRows(bufferRow, bufferRow)
@@ -135,49 +155,36 @@ class Renderer
buildLinesForBufferRows: (startBufferRow, endBufferRow) ->
lineFragments = []
startBufferColumn = null
currentBufferRow = startBufferRow
currentScreenLineLength = 0
startBufferRow = @foldStartRowForBufferRow(startBufferRow)
loop
break if startBufferRow > endBufferRow and not startBufferColumn?
startBufferColumn = 0
while currentBufferRow <= endBufferRow
screenLine = @highlighter.lineForRow(currentBufferRow)
if fold = @largestFoldForBufferRow(currentBufferRow)
screenLine = screenLine.copy()
screenLine.fold = fold
screenLine.bufferDelta = fold.getBufferDelta()
lineFragments.push(screenLine)
currentBufferRow = fold.endRow + 1
continue
startBufferColumn ?= 0
line = @highlighter.lineForRow(startBufferRow)
line = line.splitAt(startBufferColumn)[1]
wrapScreenColumn = @findWrapColumn(line.text, @maxLineLength - currentScreenLineLength)
continueMainLoop = false
for fold in @foldsForBufferRow(startBufferRow)
if fold.start.column >= startBufferColumn
foldStartSceenColumn = fold.start.column - startBufferColumn
if (foldStartSceenColumn) > wrapScreenColumn - foldPlaceholderLength
wrapScreenColumn = Math.min(wrapScreenColumn, foldStartSceenColumn)
break
prefix = line.splitAt(foldStartSceenColumn)[0]
placeholder = @buildFoldPlaceholder(fold)
lineFragments.push(prefix, placeholder)
startBufferRow = fold.end.row
startBufferColumn = fold.end.column
currentScreenLineLength = currentScreenLineLength + (prefix?.text.length ? 0) + foldPlaceholderLength
continueMainLoop = true
break
continue if continueMainLoop
screenLine = screenLine.splitAt(startBufferColumn)[1] if startBufferColumn > 0
wrapScreenColumn = @findWrapColumn(screenLine.text, @maxLineLength)
if wrapScreenColumn?
line = line.splitAt(wrapScreenColumn)[0]
line.screenDelta = new Point(1, 0)
screenLine = screenLine.splitAt(wrapScreenColumn)[0]
screenLine.screenDelta = new Point(1, 0)
startBufferColumn += wrapScreenColumn
else
startBufferRow++
startBufferColumn = null
currentBufferRow++
startBufferColumn = 0
lineFragments.push(line)
currentScreenLineLength = 0
lineFragments.push(screenLine)
lineFragments
foldStartRowForBufferRow: (bufferRow) ->
@bufferRowForScreenRow(@screenRowForBufferRow(bufferRow))
findWrapColumn: (line, maxLineLength) ->
return unless line.length > maxLineLength
@@ -192,29 +199,6 @@ class Renderer
return column + 1 if /\s/.test(line[column])
return maxLineLength
registerFold: (bufferRow, fold) ->
@activeFolds[bufferRow] ?= []
@activeFolds[bufferRow].push(fold)
@foldsById[fold.id] = fold
unregisterFold: (bufferRow, fold) ->
folds = @activeFolds[bufferRow]
folds.splice(folds.indexOf(fold), 1)
delete @foldsById[fold.id]
foldsForBufferRow: (bufferRow) ->
folds = @activeFolds[bufferRow] or []
folds.sort (a, b) -> a.compare(b)
buildFoldPlaceholder: (fold) ->
token = new Token(value: '...', type: 'fold-placeholder', fold: fold, isAtomic: true)
new ScreenLineFragment([token], token.value, [0, token.value.length], fold.getRange().toDelta())
screenLineRangeForBufferRange: (bufferRange) ->
@expandScreenRangeToLineEnds(
@lineMap.screenRangeForBufferRange(
@expandBufferRangeToLineEnds(bufferRange)))
expandScreenRangeToLineEnds: (screenRange) ->
screenRange = Range.fromObject(screenRange)
{ start, end } = screenRange
@@ -232,7 +216,7 @@ class Renderer
@highlighter.destroy()
@buffer.off ".renderer#{@id}"
logLines: ->
@lineMap.logLines()
logLines: (start, end) ->
@lineMap.logLines(start, end)
_.extend Renderer.prototype, EventEmitter

View File

@@ -14,6 +14,9 @@ class ScreenLineFragment
@bufferDelta = Point.fromObject(bufferDelta)
_.extend(this, extraFields)
copy: ->
new ScreenLineFragment(@tokens, @text, @screenDelta, @bufferDelta, { @state })
splitAt: (column) ->
return [new ScreenLineFragment([], '', [0, 0], [0, 0]), this] if column == 0
@@ -46,8 +49,7 @@ class ScreenLineFragment
translateColumn: (sourceDeltaType, targetDeltaType, sourceColumn, options={}) ->
{ skipAtomicTokens } = options
textLength = @text.length
sourceColumn = Math.min(sourceColumn, textLength)
sourceColumn = Math.min(sourceColumn, @textLength())
currentSourceColumn = 0
currentTargetColumn = 0
@@ -69,6 +71,12 @@ class ScreenLineFragment
remainingColumns = sourceColumn - currentSourceColumn
currentTargetColumn + remainingColumns
textLength: ->
if @fold
textLength = 0
else
textLength = @text.length
isSoftWrapped: ->
@screenDelta.row == 1 and @bufferDelta.row == 0

View File

@@ -45,6 +45,8 @@ class Selection extends View
@clearRegions()
range = @getScreenRange()
@editor.highlightSelectedFolds()
return if range.isEmpty()
rowSpan = range.end.row - range.start.row
@@ -57,6 +59,7 @@ class Selection extends View
@appendRegion(rowSpan - 1, { row: range.start.row + 1, column: 0}, null)
@appendRegion(1, { row: range.end.row, column: 0 }, range.end)
appendRegion: (rows, start, end) ->
{ lineHeight, charWidth } = @editor
css = @editor.pixelPositionForScreenPosition(start)
@@ -80,8 +83,7 @@ class Selection extends View
else
new Range(@cursor.getScreenPosition(), @cursor.getScreenPosition())
setScreenRange: (range, options={}) ->
{ reverse } = options
setScreenRange: (range, {reverse}={}) ->
{ start, end } = range
[start, end] = [end, start] if reverse
@@ -97,9 +99,13 @@ class Selection extends View
getText: ->
@editor.buffer.getTextInRange @getBufferRange()
intersectsBufferRange: (bufferRange) ->
@getBufferRange().intersectsWith(bufferRange)
insertText: (text) ->
{ text, shouldOutdent } = @autoIndentText(text)
oldBufferRange = @getBufferRange()
@editor.destroyFoldsContainingBufferRow(oldBufferRange.end.row)
isReversed = @isReversed()
@clearSelection()
newBufferRange = @editor.buffer.change(oldBufferRange, text)
@@ -139,6 +145,7 @@ class Selection extends View
@editor.getCurrentMode().autoOutdent(state, new AceOutdentAdaptor(@editor.buffer, @editor), bufferRow)
backspace: ->
@editor.destroyFoldsContainingBufferRow(@getBufferRange().end.row)
@selectLeft() if @isEmpty()
@deleteSelectedText()
@@ -237,5 +244,5 @@ class Selection extends View
fold: ->
range = @getBufferRange()
@editor.createFold(range)
@cursor.setBufferPosition(range.end)
@editor.createFold(range.start.row, range.end.row)
@cursor.setBufferPosition([range.end.row + 1, 0])