From 72f9af4d002ef097fa82141dd5699457ad88b91f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki & Nathan Sobo Date: Mon, 1 Jul 2013 18:25:38 -0600 Subject: [PATCH] Replicate buffer changes Still some failures due to line endings --- spec/app/text-buffer-replication-spec.coffee | 23 ++++++++- spec/app/text-buffer-spec.coffee | 52 +++++++++++--------- src/app/buffer-change-operation.coffee | 12 ----- src/app/text-buffer.coffee | 30 +++++++---- vendor/telepath | 2 +- 5 files changed, 74 insertions(+), 45 deletions(-) diff --git a/spec/app/text-buffer-replication-spec.coffee b/spec/app/text-buffer-replication-spec.coffee index 00045c66a..b8a0ca800 100644 --- a/spec/app/text-buffer-replication-spec.coffee +++ b/spec/app/text-buffer-replication-spec.coffee @@ -16,6 +16,27 @@ describe "TextBuffer replication", -> buffer1.destroy() buffer2.destroy() - it "replicates the initial path and text of the buffer", -> + it "replicates the initial path and text", -> expect(buffer2.getPath()).toBe buffer1.getPath() expect(buffer2.getText()).toBe buffer1.getText() + + it "replicates changes to the text and emits 'change' events on all replicas", -> + buffer1.on 'changed', handler1 = jasmine.createSpy("buffer1 change handler") + buffer2.on 'changed', handler2 = jasmine.createSpy("buffer2 change handler") + + buffer1.change([[1, 4], [1, 6]], 'h') + expect(buffer1.lineForRow(1)).toBe 'var hicksort = function () {' + expect(buffer2.lineForRow(1)).toBe 'var hicksort = function () {' + + expect(buffer1.isModified()).toBeTruthy() + expect(buffer2.isModified()).toBeTruthy() + + expectedEvent = + oldRange: [[1, 4], [1, 6]] + oldText: "qu" + newRange: [[1, 4], [1, 5]] + newText: "h" + expect(handler1).toHaveBeenCalledWith(expectedEvent) + expect(handler2).toHaveBeenCalledWith(expectedEvent) + expect(handler1.callCount).toBe 1 + expect(handler2.callCount).toBe 1 diff --git a/spec/app/text-buffer-spec.coffee b/spec/app/text-buffer-spec.coffee index 4e81a5087..8806d3c7c 100644 --- a/spec/app/text-buffer-spec.coffee +++ b/spec/app/text-buffer-spec.coffee @@ -1316,39 +1316,47 @@ describe 'TextBuffer', -> expect(buffer.clipPosition([10,Infinity])).toEqual [0,9] describe "serialization", -> - serializedState = null + buffer2 = null - reloadBuffer = -> - serializedState = buffer.serialize() - buffer.release() - buffer = Buffer.deserialize(serializedState) + afterEach -> + buffer2.release() describe "when the serialized buffer had no unsaved changes", -> it "loads the current contents of the file at the serialized path", -> - path = buffer.getPath() - text = buffer.getText() - reloadBuffer() - expect(serializedState.text).toBeUndefined() - expect(buffer.getPath()).toBe(path) - expect(buffer.getText()).toBe(text) + expect(buffer.isModified()).toBeFalsy() + + state = buffer.serialize() + expect(state.get('text')).toBeUndefined() + + buffer2 = deserialize(state) + expect(buffer2.isModified()).toBeFalsy() + expect(buffer2.getPath()).toBe(buffer.getPath()) + expect(buffer2.getText()).toBe(buffer.getText()) describe "when the serialized buffer had unsaved changes", -> it "restores the previous unsaved state of the buffer", -> - path = buffer.getPath() previousText = buffer.getText() buffer.setText("abc") - reloadBuffer() - expect(serializedState.text).toBe "abc" - expect(buffer.getPath()).toBe(path) - expect(buffer.getText()).toBe("abc") - buffer.setText(previousText) - expect(buffer.isModified()).toBeFalsy() + + state = buffer.serialize() + expect(state.getObject('text')).toBe 'abc' + + buffer2 = deserialize(state) + expect(buffer2.getPath()).toBe(buffer.getPath()) + expect(buffer2.getText()).toBe(buffer.getText()) + expect(buffer2.isModified()).toBeTruthy() + buffer2.setText(previousText) + expect(buffer2.isModified()).toBeFalsy() describe "when the serialized buffer was unsaved and had no path", -> it "restores the previous unsaved state of the buffer", -> buffer.setPath(undefined) buffer.setText("abc") - reloadBuffer() - expect(serializedState.path).toBeUndefined() - expect(buffer.getPath()).toBeUndefined() - expect(buffer.getText()).toBe("abc") + + state = buffer.serialize() + expect(state.get('path')).toBeUndefined() + expect(state.getObject('text')).toBe 'abc' + + buffer2 = deserialize(state) + expect(buffer2.getPath()).toBeUndefined() + expect(buffer2.getText()).toBe("abc") diff --git a/src/app/buffer-change-operation.coffee b/src/app/buffer-change-operation.coffee index 7517a0d86..703ed8537 100644 --- a/src/app/buffer-change-operation.coffee +++ b/src/app/buffer-change-operation.coffee @@ -49,15 +49,6 @@ class BufferChangeOperation changeBuffer: ({ oldRange, newRange, newText, oldText }) -> @buffer.text.change(oldRange, newText) - - @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 invalidateMarkers: (oldRange) -> @@ -70,9 +61,6 @@ class BufferChangeOperation 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] diff --git a/src/app/text-buffer.coffee b/src/app/text-buffer.coffee index bc404f48d..36b8aa36e 100644 --- a/src/app/text-buffer.coffee +++ b/src/app/text-buffer.coffee @@ -49,25 +49,33 @@ class TextBuffer path = @state.get('path') else [path, initialText] = args - @text = telepath.Document.create('', shareStrings: true) - @state = telepath.Document.create(deserializer: @constructor.name, text: @text) + @text = telepath.Document.create(initialText, shareStrings: true) if initialText + @state = telepath.Document.create(deserializer: @constructor.name) if path @setPath(path) - if initialText? - @setText(initialText) + if @text @updateCachedDiskContents() - else if fsUtils.exists(path) - @reload() else - @setText('') + @text = telepath.Document.create('', shareStrings: true) + @reload() if fsUtils.exists(path) else - @setText(initialText ? '') + @text ?= telepath.Document.create('', shareStrings: true) + @state.set('text', @text) + @text.observe(@handleTextChange) @undoManager = new UndoManager(this) ### Internal ### + handleTextChange: (event) => + event = _.pick(event, 'oldRange', 'newRange', 'oldText', 'newText') + @cachedMemoryContents = null + @conflict = false if @conflict and !@isModified() + marker.handleBufferChange(event) for marker in @getMarkers() + @trigger 'changed', event + @scheduleModifiedEvents() + destroy: -> throw new Error("Destroying buffer twice with path '#{@getPath()}'") if @destroyed @file?.off() @@ -83,7 +91,11 @@ class TextBuffer @destroy() if @refcount <= 0 this - serialize: -> @state + serialize: -> + state = @state.clone() + state.remove('text') unless @isModified() + state + getState: -> @state subscribeToFile: -> diff --git a/vendor/telepath b/vendor/telepath index 6e7b12255..6b7634edc 160000 --- a/vendor/telepath +++ b/vendor/telepath @@ -1 +1 @@ -Subproject commit 6e7b122559024b32156e11cf8bb53cf810228a19 +Subproject commit 6b7634edceb809a08c27aee11bf3bfd3b89a3c33