Merge pull request #1297 from atom/bo-diff-reload

Apply text to buffer via diff on reload
This commit is contained in:
Ben Ogle
2013-12-12 10:40:47 -08:00
3 changed files with 120 additions and 3 deletions

View File

@@ -23,6 +23,7 @@
"clear-cut": "0.2.0",
"coffee-script": "1.6.3",
"coffeestack": "0.6.0",
"diff": "git://github.com/benogle/jsdiff.git",
"emissary": "0.19.0",
"first-mate": "0.5.0",
"fs-plus": "0.11.0",

View File

@@ -113,10 +113,17 @@ describe 'TextBuffer', ->
runs ->
[event] = changeHandler.argsForCall[0]
expect(event.oldRange).toEqual [[0, 0], [0, 5]]
expect(event.oldRange).toEqual [[0, 0], [0, 0]]
expect(event.newRange).toEqual [[0, 0], [0, 6]]
expect(event.oldText).toBe "first"
expect(event.oldText).toBe ""
expect(event.newText).toBe "second"
[event] = changeHandler.argsForCall[1]
expect(event.oldRange).toEqual [[0, 6], [0, 11]]
expect(event.newRange).toEqual [[0, 6], [0, 6]]
expect(event.oldText).toBe "first"
expect(event.newText).toBe ""
expect(buffer.isModified()).toBeFalsy()
describe "when the buffer's memory contents differ from the *previous* disk contents", ->
@@ -454,6 +461,68 @@ describe 'TextBuffer', ->
expect(event.oldRange).toEqual expectedPreRange
expect(event.newRange).toEqual [[0, 0], [1, 14]]
describe ".setTextViaDiff(text)", ->
it "can change the entire contents of the buffer when there are no newlines", ->
buffer.setText('BUFFER CHANGE')
newText = 'DISK CHANGE'
buffer.setTextViaDiff(newText)
expect(buffer.getText()).toBe newText
describe "with standard newlines", ->
it "can change the entire contents of the buffer with no newline at the end", ->
newText = "I know you are.\nBut what am I?"
buffer.setTextViaDiff(newText)
expect(buffer.getText()).toBe newText
it "can change the entire contents of the buffer with a newline at the end", ->
newText = "I know you are.\nBut what am I?\n"
buffer.setTextViaDiff(newText)
expect(buffer.getText()).toBe newText
it "can change a few lines at the beginning in the buffer", ->
newText = buffer.getText().replace(/function/g, 'omgwow')
buffer.setTextViaDiff(newText)
expect(buffer.getText()).toBe newText
it "can change a few lines in the middle of the buffer", ->
newText = buffer.getText().replace(/shift/g, 'omgwow')
buffer.setTextViaDiff(newText)
expect(buffer.getText()).toBe newText
it "can adds a newline at the end", ->
newText = buffer.getText() + '\n'
buffer.setTextViaDiff(newText)
expect(buffer.getText()).toBe newText
describe "with windows newlines", ->
beforeEach ->
buffer.setText(buffer.getText().replace(/\n/g, '\r\n'))
it "adds a newline at the end", ->
newText = buffer.getText() + '\r\n'
buffer.setTextViaDiff(newText)
expect(buffer.getText()).toBe newText
it "changes the entire contents of the buffer with smaller content with no newline at the end", ->
newText = "I know you are.\r\nBut what am I?"
buffer.setTextViaDiff(newText)
expect(buffer.getText()).toBe newText
it "changes the entire contents of the buffer with smaller content with newline at the end", ->
newText = "I know you are.\r\nBut what am I?\r\n"
buffer.setTextViaDiff(newText)
expect(buffer.getText()).toBe newText
it "changes a few lines at the beginning in the buffer", ->
newText = buffer.getText().replace(/function/g, 'omgwow')
buffer.setTextViaDiff(newText)
expect(buffer.getText()).toBe newText
it "changes a few lines in the middle of the buffer", ->
newText = buffer.getText().replace(/shift/g, 'omgwow')
buffer.setTextViaDiff(newText)
expect(buffer.getText()).toBe newText
describe ".save()", ->
saveBuffer = null

View File

@@ -1,4 +1,5 @@
_ = require 'underscore-plus'
diff = require 'diff'
Q = require 'q'
{P} = require 'scandal'
telepath = require 'telepath'
@@ -133,7 +134,7 @@ class TextBuffer extends telepath.Model
# Sets the buffer's content to the cached disk contents
reload: ->
@emit 'will-reload'
@setText(@cachedDiskContents)
@setTextViaDiff(@cachedDiskContents)
@emitModifiedStatusChanged(false)
@emit 'reloaded'
@@ -198,6 +199,52 @@ class TextBuffer extends telepath.Model
setText: (text) ->
@change(@getRange(), text, normalizeLineEndings: false)
# Private: Replaces the current buffer contents. Only apply the differences.
#
# text - A {String} containing the new buffer contents.
setTextViaDiff: (text) ->
currentText = @getText()
return if currentText == text
endsWithNewline = (str) ->
/[\r\n]+$/g.test(str)
computeBufferColumn = (str) ->
newlineIndex = Math.max(str.lastIndexOf('\n'), str.lastIndexOf('\r'))
if endsWithNewline(str)
0
else if newlineIndex == -1
str.length
else
str.length - newlineIndex - 1
@transact =>
row = 0
column = 0
currentPosition = [0, 0]
lineDiff = diff.diffLines(currentText, text)
changeOptions = normalizeLineEndings: false
for change in lineDiff
lineCount = change.value.match(/\n/g)?.length ? 0
currentPosition[0] = row
currentPosition[1] = column
if change.added
@change([currentPosition, currentPosition], change.value, changeOptions)
row += lineCount
column = computeBufferColumn(change.value)
else if change.removed
endRow = row + lineCount
endColumn = column + computeBufferColumn(change.value)
@change([currentPosition, [endRow, endColumn]], '', changeOptions)
else
row += lineCount
column = computeBufferColumn(change.value)
# Gets the range of the buffer contents.
#
# Returns a new {Range}, from `[0, 0]` to the end of the buffer.