mirror of
https://github.com/atom/atom.git
synced 2026-02-10 22:55:09 -05:00
Merge branch 'master' into overdraw
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 "…"
|
||||
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 ' ' if line.text == ''
|
||||
else
|
||||
for token in line.tokens
|
||||
@span { class: token.type.replace('.', ' ') }, token.value
|
||||
@raw ' ' 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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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])
|
||||
|
||||
Reference in New Issue
Block a user