From c596514d11f6d42e1ce6ac4ebe0ac577bc07b980 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki & Nathan Sobo Date: Wed, 26 Jun 2013 13:44:05 -0600 Subject: [PATCH] Accept documents in EditSession and replicate scroll position --- spec/app/edit-session-replication-spec.coffee | 26 ++++++ src/app/edit-session.coffee | 80 ++++++++++++------- src/app/editor.coffee | 6 ++ src/app/project.coffee | 1 - 4 files changed, 82 insertions(+), 31 deletions(-) create mode 100644 spec/app/edit-session-replication-spec.coffee diff --git a/spec/app/edit-session-replication-spec.coffee b/spec/app/edit-session-replication-spec.coffee new file mode 100644 index 000000000..6db80f82b --- /dev/null +++ b/spec/app/edit-session-replication-spec.coffee @@ -0,0 +1,26 @@ +{createSite} = require 'telepath' +Editor = require 'editor' + +describe "EditSession replication", -> + [editSession1, editSession2] = [] + beforeEach -> + editSession1 = project.open('sample.js') + doc1 = editSession1.getState() + doc2 = doc1.clone(createSite(2)) + doc1.connect(doc2) + editSession2 = deserialize(doc2) + + it "replicates the scroll position", -> + editor1 = new Editor(editSession1) + editor2 = new Editor(editSession2) + + editor1.attachToDom().width(50).height(50) + editor2.attachToDom().width(50).height(50) + + editor1.scrollTop(10) + expect(editor1.scrollTop()).toBe 10 + expect(editor2.scrollTop()).toBe 10 + + editor2.scrollLeft(20) + expect(editor2.scrollLeft()).toBe 20 + expect(editor1.scrollLeft()).toBe 20 diff --git a/src/app/edit-session.coffee b/src/app/edit-session.coffee index dac081069..411043da7 100644 --- a/src/app/edit-session.coffee +++ b/src/app/edit-session.coffee @@ -1,3 +1,7 @@ +_ = require 'underscore' +fsUtils = require 'fs-utils' +path = require 'path' +telepath = require 'telepath' Point = require 'point' Buffer = require 'text-buffer' LanguageMode = require 'language-mode' @@ -7,14 +11,13 @@ Selection = require 'selection' EventEmitter = require 'event-emitter' Subscriber = require 'subscriber' Range = require 'range' -_ = require 'underscore' -fsUtils = require 'fs-utils' -path = require 'path' TextMateScopeSelector = require 'text-mate-scope-selector' # An `EditSession` manages the states between {Editor}s, {Buffer}s, and the project as a whole. module.exports = class EditSession + @acceptsDocuments: true + registerDeserializer(this) ### Internal ### @@ -22,17 +25,8 @@ class EditSession @version: 1 @deserialize: (state) -> - session = project.buildEditSessionForBuffer(Buffer.deserialize(state.buffer)) - if !session? - console.warn "Could not build edit session for path '#{state.buffer}' because that file no longer exists" if state.buffer - session = project.open(null) - session.setScrollTop(state.scrollTop) - session.setScrollLeft(state.scrollLeft) - session.setCursorScreenPosition(state.cursorScreenPosition) - session + new EditSession(state) - scrollTop: 0 - scrollLeft: 0 languageMode: null displayBuffer: null cursors: null @@ -40,17 +34,32 @@ class EditSession softTabs: true softWrap: false - constructor: ({@project, @buffer, tabLength, softTabs, @softWrap}) -> + constructor: (optionsOrState) -> + if optionsOrState instanceof telepath.Document + project.editSessions.push(this) + @state = optionsOrState + {tabLength, softTabs, @softWrap} = @state.toObject() + @buffer = deserialize(@state.get('buffer')) + @setScrollTop(@state.get('scrollTop')) + @setScrollLeft(@state.get('scrollLeft')) + cursorScreenPosition = @state.getObject('cursorScreenPosition') + else + {@buffer, tabLength, softTabs, @softWrap} = optionsOrState + @state = telepath.Document.fromObject + deserializer: 'EditSession' + version: @constructor.version + cursorScreenPosition = [0, 0] + @softTabs = @buffer.usesSoftTabs() ? softTabs ? true @languageMode = new LanguageMode(this, @buffer.getExtension()) @displayBuffer = new DisplayBuffer(@buffer, { @languageMode, tabLength }) @cursors = [] @selections = [] - @addCursorAtScreenPosition([0, 0]) + @addCursorAtScreenPosition(cursorScreenPosition) @buffer.retain() @subscribe @buffer, "path-changed", => - @project.setPath(path.dirname(@getPath())) unless @project.getPath()? + project.setPath(path.dirname(@getPath())) unless project.getPath()? @trigger "title-changed" @trigger "path-changed" @subscribe @buffer, "contents-conflicted", => @trigger "contents-conflicted" @@ -64,6 +73,13 @@ class EditSession @displayBuffer.on 'grammar-changed', => @handleGrammarChange() + @state.observe ({key, value, site}) => + switch key + when 'scrollTop' + @trigger 'scroll-top-changed', value + when 'scrollLeft' + @trigger 'scroll-left-changed', value + getViewClass: -> require 'editor' @@ -75,23 +91,26 @@ class EditSession selection.destroy() for selection in @getSelections() @displayBuffer.destroy() @languageMode.destroy() - @project?.removeEditSession(this) + project?.removeEditSession(this) @trigger 'destroyed' @off() serialize: -> - deserializer: 'EditSession' - version: @constructor.version - buffer: @buffer.serialize() - scrollTop: @getScrollTop() - scrollLeft: @getScrollLeft() - cursorScreenPosition: @getCursorScreenPosition().serialize() + @state.set + buffer: @buffer.serialize() + scrollTop: @getScrollTop() + scrollLeft: @getScrollLeft() + tabLength: @getTabLength() + softTabs: @softTabs + softWrap: @softWrap + cursorScreenPosition: @getCursorScreenPosition().serialize() + @state getState: -> @serialize() # Creates a copy of the current {EditSession}.Returns an identical `EditSession`. copy: -> - EditSession.deserialize(@serialize(), @project) + EditSession.deserialize(@serialize()) ### Public ### @@ -131,8 +150,8 @@ class EditSession isEqual: (other) -> return false unless other instanceof EditSession @buffer == other.buffer and - @scrollTop == other.getScrollTop() and - @scrollLeft == other.getScrollLeft() and + @getScrollTop() == other.getScrollTop() and + @getScrollLeft() == other.getScrollLeft() and @getCursorScreenPosition().isEqual(other.getCursorScreenPosition()) setVisible: (visible) -> @displayBuffer.setVisible(visible) @@ -140,22 +159,23 @@ class EditSession # Defines the value of the `EditSession`'s `scrollTop` property. # # scrollTop - A {Number} defining the `scrollTop`, in pixels. - setScrollTop: (@scrollTop) -> + setScrollTop: (scrollTop) -> @state.set('scrollTop', scrollTop) # Gets the value of the `EditSession`'s `scrollTop` property. # # Returns a {Number} defining the `scrollTop`, in pixels. - getScrollTop: -> @scrollTop + getScrollTop: -> + @state.get('scrollTop') ? 0 # Defines the value of the `EditSession`'s `scrollLeft` property. # # scrollLeft - A {Number} defining the `scrollLeft`, in pixels. - setScrollLeft: (@scrollLeft) -> + setScrollLeft: (scrollLeft) -> @state.set('scrollLeft', scrollLeft) # Gets the value of the `EditSession`'s `scrollLeft` property. # # Returns a {Number} defining the `scrollLeft`, in pixels. - getScrollLeft: -> @scrollLeft + getScrollLeft: -> @state.get('scrollLeft') # Defines the limit at which the buffer begins to soft wrap text. # diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 656c382ec..441676bc9 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -728,6 +728,12 @@ class Editor extends View @activeEditSession.on 'screen-lines-changed.editor', (e) => @handleScreenLinesChange(e) + @activeEditSession.on 'scroll-top-changed.editor', (scrollTop) => + @scrollTop(scrollTop) + + @activeEditSession.on 'scroll-left-changed.editor', (scrollLeft) => + @scrollLeft(scrollLeft) + @trigger 'editor:path-changed' @resetDisplay() diff --git a/src/app/project.coffee b/src/app/project.coffee index 9c6c73dca..ed3a87db1 100644 --- a/src/app/project.coffee +++ b/src/app/project.coffee @@ -297,7 +297,6 @@ class Project buildEditSessionForBuffer: (buffer, editSessionOptions) -> options = _.extend(@defaultEditSessionOptions(), editSessionOptions) - options.project = this options.buffer = buffer editSession = new EditSession(options) @editSessions.push editSession