From b959d5aa374f130f0ffd1654205d80a1a48abcf7 Mon Sep 17 00:00:00 2001 From: Corey Johnson & Nathan Sobo Date: Wed, 18 Jul 2012 12:49:18 -0700 Subject: [PATCH] Buffers are memoized on project by path --- spec/app/buffer-spec.coffee | 35 ++++++++++++++++++----------------- spec/app/project-spec.coffee | 18 ++++++++++++++---- spec/spec-helper.coffee | 1 + src/app/buffer.coffee | 16 ++++++++++------ src/app/project.coffee | 18 +++++++++++------- 5 files changed, 54 insertions(+), 34 deletions(-) diff --git a/spec/app/buffer-spec.coffee b/spec/app/buffer-spec.coffee index 591870bfb..41f89ce83 100644 --- a/spec/app/buffer-spec.coffee +++ b/spec/app/buffer-spec.coffee @@ -11,11 +11,11 @@ describe 'Buffer', -> buffer = new Buffer(filePath) afterEach -> - buffer?.destroy() + buffer?.release() describe 'constructor', -> beforeEach -> - buffer.destroy() + buffer.release() describe "when given a path", -> describe "when a file exists for the path", -> @@ -56,8 +56,8 @@ describe 'Buffer', -> beforeEach -> path = "/tmp/tmp.txt" fs.write(path, "first") - buffer.destroy() - buffer = new Buffer(path) + buffer.release() + buffer = new Buffer(path).retain() afterEach -> fs.remove(path) @@ -99,7 +99,7 @@ describe 'Buffer', -> it "returns false after modified buffer is saved", -> filePath = "/tmp/atom-tmp-file" fs.write(filePath, '') - buffer.destroy() + buffer.release() buffer = new Buffer(filePath) expect(buffer.isModified()).toBe false @@ -243,7 +243,7 @@ describe 'Buffer', -> describe ".save()", -> beforeEach -> - buffer.destroy() + buffer.release() describe "when the buffer has a path", -> filePath = null @@ -283,33 +283,34 @@ describe 'Buffer', -> expect(-> buffer.save()).toThrow() describe ".saveAs(path)", -> - filePath = null + [filePath, saveAsBuffer] = [] - beforeEach -> - buffer.destroy() + afterEach -> + saveAsBuffer.release() it "saves the contents of the buffer to the path", -> filePath = '/tmp/temp.txt' fs.remove filePath if fs.exists(filePath) - buffer = new Buffer() + saveAsBuffer = new Buffer().retain() eventHandler = jasmine.createSpy('eventHandler') - buffer.on 'path-change', eventHandler + saveAsBuffer.on 'path-change', eventHandler - buffer.setText 'Buffer contents!' - buffer.saveAs(filePath) + saveAsBuffer.setText 'Buffer contents!' + saveAsBuffer.saveAs(filePath) expect(fs.read(filePath)).toEqual 'Buffer contents!' - expect(eventHandler).toHaveBeenCalledWith(buffer) + expect(eventHandler).toHaveBeenCalledWith(saveAsBuffer) it "stops listening to events on previous path and begins listening to events on new path", -> originalPath = "/tmp/original.txt" newPath = "/tmp/new.txt" fs.write(originalPath, "") - buffer = new Buffer(originalPath) + + saveAsBuffer = new Buffer(originalPath).retain() changeHandler = jasmine.createSpy('changeHandler') - buffer.on 'change', changeHandler - buffer.saveAs(newPath) + saveAsBuffer.on 'change', changeHandler + saveAsBuffer.saveAs(newPath) expect(changeHandler).not.toHaveBeenCalled() fs.write(originalPath, "should not trigger buffer event") diff --git a/spec/app/project-spec.coffee b/spec/app/project-spec.coffee index 19d0f97eb..0fa2045bc 100644 --- a/spec/app/project-spec.coffee +++ b/spec/app/project-spec.coffee @@ -13,18 +13,14 @@ describe "Project", -> it "removes edit session and calls destroy on buffer (if buffer is not referenced by other edit sessions)", -> editSession = project.buildEditSessionForPath("a") anotherEditSession = project.buildEditSessionForPath("a") - buffer = editSession.buffer - spyOn(buffer, 'destroy').andCallThrough() expect(project.editSessions.length).toBe 2 expect(editSession.buffer).toBe anotherEditSession.buffer editSession.destroy() - expect(buffer.destroy).not.toHaveBeenCalled() expect(project.editSessions.length).toBe 1 anotherEditSession.destroy() - expect(buffer.destroy).toHaveBeenCalled() expect(project.editSessions.length).toBe 0 describe ".buildEditSessionForPath(path)", -> @@ -66,6 +62,20 @@ describe "Project", -> expect(newBufferHandler).toHaveBeenCalledWith(editSession.buffer) expect(newEditSessionHandler).toHaveBeenCalledWith editSession + describe ".bufferForPath(path)", -> + describe "when opening a previously opened path", -> + it "does not create a new buffer", -> + buffer = project.bufferForPath("a").retain() + expect(project.bufferForPath("a")).toBe buffer + + alternativeBuffer = project.bufferForPath("b").retain().release() + expect(alternativeBuffer).not.toBe buffer + buffer.release() + + it "creates a new buffer if the previous buffer was destroyed", -> + buffer = project.bufferForPath("a").retain().release() + expect(project.bufferForPath("a").retain().release()).not.toBe buffer + describe ".resolve(path)", -> it "returns an absolute path based on the project's root", -> absolutePath = require.resolve('fixtures/dir/a') diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index eb82d2c3b..c559a1cce 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -26,6 +26,7 @@ afterEach -> $('#jasmine-content').empty() document.title = defaultTitle ensureNoPathSubscriptions() + window.fixturesProject.destroy() window.keymap.bindKeys '*', 'meta-w': 'close' $(document).on 'close', -> window.close() diff --git a/src/app/buffer.coffee b/src/app/buffer.coffee index 6914b835a..7a815549c 100644 --- a/src/app/buffer.coffee +++ b/src/app/buffer.coffee @@ -20,7 +20,7 @@ class Buffer anchorRanges: null refcount: 0 - constructor: (path) -> + constructor: (path, @project) -> @id = @constructor.idCounter++ @anchors = [] @anchorRanges = [] @@ -38,8 +38,9 @@ class Buffer destroy: -> throw new Error("Destroying buffer twice with path '#{@getPath()}'") if @destroyed - @destroyed = true @file?.off() + @destroyed = true + @project?.removeBuffer(this) retain: -> @refcount++ @@ -50,6 +51,12 @@ class Buffer @destroy() if @refcount <= 0 this + subscribeToFile: -> + @file?.on "contents-change", => + unless @isModified() + @setText(fs.read(@file.getPath())) + @modified = false + getPath: -> @file?.getPath() @@ -58,10 +65,7 @@ class Buffer @file?.off() @file = new File(path) - @file.on "contents-change", => - unless @isModified() - @setText(fs.read(@file.getPath())) - @modified = false + @subscribeToFile() @trigger "path-change", this getExtension: -> diff --git a/src/app/project.coffee b/src/app/project.coffee index 503458548..9098c7e26 100644 --- a/src/app/project.coffee +++ b/src/app/project.coffee @@ -21,7 +21,7 @@ class Project constructor: (path) -> @setPath(path) @editSessions = [] - @buffer = [] + @buffers = [] @setTabText(' ') @setAutoIndent(true) @setSoftTabs(true) @@ -30,6 +30,9 @@ class Project /(^|\/)\.git(\/|$)/ ] + destroy: -> + editSession.destroy() for editSession in @getEditSessions() + getPath: -> @rootDirectory?.path @@ -106,9 +109,6 @@ class Project getEditSessions: -> new Array(@editSessions...) - destroy: -> - editSession.destroy() for editSession in @getEditSessions() - removeEditSession: (editSession) -> _.remove(@editSessions, editSession) @@ -122,16 +122,20 @@ class Project bufferForPath: (filePath) -> if filePath? filePath = @resolve(filePath) - return editSession.buffer for editSession in @editSessions when editSession.buffer.getPath() == filePath - @buildBuffer(filePath) + buffer = _.find @buffers, (buffer) -> buffer.getPath() == filePath + buffer or @buildBuffer(filePath) else @buildBuffer() buildBuffer: (filePath) -> - buffer = new Buffer(filePath) + buffer = new Buffer(filePath, this) + @buffers.push buffer @trigger 'new-buffer', buffer buffer + removeBuffer: (buffer) -> + _.remove(@buffers, buffer) + scan: (regex, iterator) -> regex = new RegExp(regex.source, 'g') commands = [