Files
atom/src/app/buffer-change-operation.coffee
Nathan Sobo 3e937e9811 Merge remote-tracking branch 'origin/master' into know-when-to-foldem
Conflicts:
	src/app/buffer-marker.coffee
	src/app/cursor.coffee
	src/app/display-buffer-marker.coffee
	src/app/display-buffer.coffee
	src/app/edit-session.coffee
	src/app/fold.coffee
	src/app/line-map.coffee
	src/app/range.coffee
	src/app/selection.coffee
	src/app/text-buffer.coffee
2013-05-03 18:29:52 -06:00

121 lines
3.7 KiB
CoffeeScript

Range = require 'range'
_ = require 'underscore'
### Internal ###
module.exports =
class BufferChangeOperation
buffer: null
oldRange: null
oldText: null
newRange: null
newText: null
markersToRestoreOnUndo: null
markersToRestoreOnRedo: null
constructor: ({@buffer, @oldRange, @newText, @options}) ->
@options ?= {}
do: ->
@buffer.pauseEvents()
@pauseMarkerObservation()
@markersToRestoreOnUndo = @invalidateMarkers(@oldRange)
if @oldRange?
@oldText = @buffer.getTextInRange(@oldRange)
@newRange = @calculateNewRange(@oldRange, @newText)
newRange = @changeBuffer
oldRange: @oldRange
newRange: @newRange
oldText: @oldText
newText: @newText
@restoreMarkers(@markersToRestoreOnRedo) if @markersToRestoreOnRedo
@buffer.resumeEvents()
@resumeMarkerObservation()
newRange
undo: ->
@buffer.pauseEvents()
@pauseMarkerObservation()
@markersToRestoreOnRedo = @invalidateMarkers(@newRange)
if @oldRange?
@changeBuffer
oldRange: @newRange
newRange: @oldRange
oldText: @newText
newText: @oldText
@restoreMarkers(@markersToRestoreOnUndo)
@buffer.resumeEvents()
@resumeMarkerObservation()
splitLines: (text) ->
lines = text.split('\n')
lineEndings = []
for line, index in lines
if _.endsWith(line, '\r')
lines[index] = line[...-1]
lineEndings[index] = '\r\n'
else
lineEndings[index] = '\n'
{lines, lineEndings}
changeBuffer: ({ oldRange, newRange, newText, oldText }) ->
{ prefix, suffix } = @buffer.prefixAndSuffixForRange(oldRange)
{lines, lineEndings} = @splitLines(newText)
lastLineIndex = lines.length - 1
if lines.length == 1
lines = [prefix + newText + suffix]
else
lines[0] = prefix + lines[0]
lines[lastLineIndex] += suffix
startRow = oldRange.start.row
endRow = oldRange.end.row
normalizeLineEndings = @options.normalizeLineEndings ? true
if normalizeLineEndings and suggestedLineEnding = @buffer.suggestedLineEndingForRow(startRow)
lineEndings[index] = suggestedLineEnding for index in [0..lastLineIndex]
_.spliceWithArray(@buffer.lines, startRow, endRow - startRow + 1, lines)
_.spliceWithArray(@buffer.lineEndings, startRow, endRow - startRow + 1, lineEndings)
@buffer.cachedMemoryContents = null
@buffer.conflict = false if @buffer.conflict and !@buffer.isModified()
event = { oldRange, newRange, oldText, newText }
@updateMarkers(event)
@buffer.trigger 'changed', event
@buffer.scheduleModifiedEvents()
newRange
calculateNewRange: (oldRange, newText) ->
newRange = new Range(oldRange.start.copy(), oldRange.start.copy())
{lines} = @splitLines(newText)
if lines.length == 1
newRange.end.column += newText.length
else
lastLineIndex = lines.length - 1
newRange.end.row += lastLineIndex
newRange.end.column = lines[lastLineIndex].length
newRange
invalidateMarkers: (oldRange) ->
@buffer.getMarkers().map (marker) -> marker.tryToInvalidate(oldRange)
pauseMarkerObservation: ->
marker.pauseEvents() for marker in @buffer.getMarkers(includeInvalid: true)
resumeMarkerObservation: ->
marker.resumeEvents() for marker in @buffer.getMarkers(includeInvalid: true)
@buffer.trigger 'markers-updated' if @oldRange?
updateMarkers: (bufferChange) ->
marker.handleBufferChange(bufferChange) for marker in @buffer.getMarkers()
restoreMarkers: (markersToRestore) ->
for [id, previousRange] in markersToRestore
if validMarker = @buffer.validMarkers[id]
validMarker.setRange(previousRange)
else if invalidMarker = @buffer.invalidMarkers[id]
invalidMarker.revalidate()