diff --git a/spec/atom/app-spec.coffee b/spec/atom/app-spec.coffee index 91f4da67c..61d7d01c7 100644 --- a/spec/atom/app-spec.coffee +++ b/spec/atom/app-spec.coffee @@ -14,30 +14,14 @@ describe "App", -> describe "open", -> describe "when opening a filePath", -> - it "displays it in a new window", -> + it "displays it in a new window with the contents of the file loaded", -> filePath = require.resolve 'fixtures/sample.txt' expect(app.windows().length).toBe 0 app.open filePath expect(app.windows().length).toBe 1 - - it "loads a buffer with filePath contents", -> - filePath = require.resolve 'fixtures/sample.txt' - - app.open filePath - newWindow = app.windows()[0] expect(newWindow.rootView.editor.buffer.url).toEqual filePath expect(newWindow.rootView.editor.buffer.getText()).toEqual fs.read(filePath) - describe "when opening a dirPath", -> - it "loads an empty buffer", -> - dirPath = require.resolve 'fixtures' - - app.open dirPath - - newWindow = app.windows()[0] - expect(newWindow.rootView.editor.buffer.url).toBeUndefined - expect(newWindow.rootView.editor.buffer.getText()).toBe "" - diff --git a/spec/atom/editor-spec.coffee b/spec/atom/editor-spec.coffee index 5e03e9f72..9f4f80611 100644 --- a/spec/atom/editor-spec.coffee +++ b/spec/atom/editor-spec.coffee @@ -1,3 +1,4 @@ +Buffer = require 'buffer' Editor = require 'editor' $ = require 'jquery' ck = require 'coffeekup' @@ -12,7 +13,6 @@ describe "Editor", -> beforeEach -> filePath = require.resolve 'fixtures/sample.txt' tempFilePath = '/tmp/temp.txt' - spyOn(Editor.prototype.viewProperties, 'open').andCallThrough() editor = Editor.build() afterEach -> @@ -29,41 +29,45 @@ describe "Editor", -> editor.destroy() expect(editor.aceEditor.destroy).toHaveBeenCalled() - describe "open(url)", -> - describe "when called with a url", -> - it "loads a buffer for the given url into the editor", -> - editor.open(filePath) - fileContents = fs.read(filePath) - expect(editor.getAceSession().getValue()).toBe fileContents - expect(editor.buffer.url).toBe(filePath) - expect(editor.buffer.getText()).toEqual fileContents + describe "setBuffer(buffer)", -> + it "sets the document on the aceSession", -> + buffer = new Buffer filePath + editor.setBuffer buffer - it "sets the mode on the session based on the file extension", -> - editor.open('something.js') - expect(editor.getAceSession().getMode().name).toBe 'javascript' + fileContents = fs.read(filePath) + expect(editor.getAceSession().getValue()).toBe fileContents - editor.open('something.text') - expect(editor.getAceSession().getMode().name).toBe 'text' + it "restores the ace edit session for a previously assigned buffer", -> + buffer = new Buffer filePath + editor.setBuffer buffer - describe "when called with null", -> - it "loads an empty buffer with no url", -> - editor.open() - expect(editor.getAceSession().getValue()).toBe "" - expect(editor.buffer.url).toBeUndefined() - expect(editor.buffer.getText()).toEqual "" + aceSession = editor.getAceSession() + + editor.setBuffer new Buffer(tempFilePath) + expect(editor.getAceSession()).not.toBe(aceSession) + + editor.setBuffer(buffer) + expect(editor.getAceSession()).toBe aceSession + + it "sets the language mode based on the file extension", -> + buffer = new Buffer "something.js" + editor.setBuffer buffer + + expect(editor.getAceSession().getMode().name).toBe 'javascript' describe "when the text is changed via the ace editor", -> it "updates the buffer text", -> - editor.open(filePath) - expect(editor.buffer.getText()).not.toMatch /^.ooo/ + buffer = new Buffer(filePath) + editor.setBuffer(buffer) + expect(buffer.getText()).not.toMatch /^.ooo/ editor.getAceSession().insert {row: 0, column: 1}, 'ooo' - expect(editor.buffer.getText()).toMatch /^.ooo/ + expect(buffer.getText()).toMatch /^.ooo/ describe "save", -> describe "when the current buffer has a url", -> beforeEach -> - editor.open tempFilePath - expect(editor.buffer.url).toBe tempFilePath + buffer = new Buffer(tempFilePath) + editor.setBuffer(buffer) it "saves the current buffer to disk", -> editor.buffer.setText 'Edited buffer!' diff --git a/spec/atom/project-spec.coffee b/spec/atom/project-spec.coffee index 39f6517a6..9d50de015 100644 --- a/spec/atom/project-spec.coffee +++ b/spec/atom/project-spec.coffee @@ -14,3 +14,28 @@ describe "Project", -> project.getFilePaths().done (result) -> expect(result).toEqual(expectedPaths) + describe ".open(path)", -> + absolutePath = null + beforeEach -> + absolutePath = require.resolve('fixtures/dir/a') + + it "always returns the same buffer for the same canonical path", -> + buffer = project.open(absolutePath) + expect(project.open(absolutePath)).toBe buffer + expect(project.open('a')).toBe buffer + + describe "when given an absolute path", -> + it "returns a buffer for the given path", -> + expect(project.open(absolutePath).url).toBe absolutePath + + describe "when given a relative path", -> + it "returns a buffer for the given path (relative to the project root)", -> + expect(project.open('a').url).toBe absolutePath + + describe ".resolve(path)", -> + it "returns an absolute path based on the project's root", -> + absolutePath = require.resolve('fixtures/dir/a') + expect(project.resolve('a')).toBe absolutePath + expect(project.resolve(absolutePath + '/../a')).toBe absolutePath + expect(project.resolve('a/../a')).toBe absolutePath + diff --git a/spec/atom/root-view-spec.coffee b/spec/atom/root-view-spec.coffee index 3ba05cfba..a2d3ee5a8 100644 --- a/spec/atom/root-view-spec.coffee +++ b/spec/atom/root-view-spec.coffee @@ -4,11 +4,13 @@ RootView = require 'root-view' describe "RootView", -> rootView = null + project = null url = null beforeEach -> url = require.resolve 'fixtures/dir/a' rootView = RootView.build {url} + project = rootView.project describe "initialize", -> describe "when called with a url that references a file", -> @@ -49,11 +51,17 @@ describe "RootView", -> rootView.toggleFileFinder() expect(rootView.find('.file-finder')).not.toExist() - it "shows all urls for the current project", -> + it "shows all relative file paths for the current project", -> waitsForPromise -> rootView.toggleFileFinder() - runs -> - expect(rootView.fileFinder.urlList.children('li').length).toBe 3 + + waitsForPromise -> + project.getFilePaths().done (paths) -> + expect(rootView.fileFinder.urlList.children('li').length).toBe paths.length + + for path in paths + relativePath = path.replace(project.url, '') + expect(rootView.fileFinder.urlList.find("li:contains(#{relativePath}):not(:contains(#{project.url}))")).toExist() describe "when there is no project", -> beforeEach -> @@ -65,3 +73,14 @@ describe "RootView", -> rootView.toggleFileFinder() expect(rootView.find('.file-finder')).not.toExist() + describe "when a path is selected in the file finder", -> + it "opens the file associated with that path in the editor", -> + waitsForPromise -> rootView.toggleFileFinder() + runs -> + firstLi = rootView.fileFinder.find('li:first') + rootView.fileFinder.select() + expect(rootView.editor.buffer.url).toBe(project.url + firstLi.text()) + + + + diff --git a/spec/stdlib/fs-spec.coffee b/spec/stdlib/fs-spec.coffee index 66ce34e1b..1e43de342 100644 --- a/spec/stdlib/fs-spec.coffee +++ b/spec/stdlib/fs-spec.coffee @@ -11,6 +11,12 @@ describe "fs", -> expect(fs.directory(require.resolve('fixtures/dir'))).toBe require.resolve('fixtures/dir/') expect(fs.directory(require.resolve('fixtures/dir/'))).toBe require.resolve('fixtures/dir/') + describe ".join(paths...)", -> + it "concatenates the given paths with the directory seperator", -> + expect(fs.join('a')).toBe 'a' + expect(fs.join('a', 'b', 'c')).toBe 'a/b/c' + expect(fs.join('/a/b/', 'c', 'd')).toBe '/a/b/c/d' + expect(fs.join('a', 'b/c/', 'd/')).toBe 'a/b/c/d/' describe ".async", -> describe ".listFiles(directoryPath, recursive)", -> @@ -19,15 +25,13 @@ describe "fs", -> describe "when recursive is true", -> it "returns a promise that resolves to the recursive contents of that directory that are files", -> - waitsFor (complete) -> + waitsForPromise -> fs.async.listFiles(directoryPath, true).done (result) -> expect(result).toEqual (path for path in fs.list(directoryPath, true) when fs.isFile(path)) - complete() describe "when recursive is false", -> it "returns a promise that resolves to the contents of that directory that are files", -> - waitsFor (complete) -> + waitsForPromise -> fs.async.listFiles(directoryPath).done (result) -> expect(result).toEqual (path for path in fs.list(directoryPath) when fs.isFile(path)) - complete() diff --git a/src/atom/editor.coffee b/src/atom/editor.coffee index 7d9a7a7dd..aafd81c5a 100644 --- a/src/atom/editor.coffee +++ b/src/atom/editor.coffee @@ -12,11 +12,11 @@ class Editor extends Template viewProperties: aceEditor: null buffer: null - editorElement: null initialize: () -> + @aceSessions = {} @buildAceEditor() - @open() + @setBuffer(new Buffer) shutdown: -> @destroy() @@ -24,10 +24,11 @@ class Editor extends Template destroy: -> @aceEditor.destroy() - open: (url) -> - @buffer = new Buffer(url) - session = new EditSession(@buffer.aceDocument, @buffer.getMode()) - @aceEditor.setSession(session) + setBuffer: (@buffer) -> + @aceEditor.setSession @getAceSessionForBuffer(buffer) + + getAceSessionForBuffer: (buffer) -> + @aceSessions[@buffer.url] ?= new EditSession(@buffer.aceDocument, @buffer.getMode()) buildAceEditor: -> @aceEditor = ace.edit this[0] diff --git a/src/atom/project.coffee b/src/atom/project.coffee index 87c501104..9fa61c654 100644 --- a/src/atom/project.coffee +++ b/src/atom/project.coffee @@ -1,9 +1,13 @@ fs = require 'fs' +Buffer = require 'buffer' module.exports = class Project + buffers: null + constructor: (@url) -> + @buffers = {} getFilePaths: -> projectUrl = @url @@ -11,3 +15,11 @@ class Project urls = (url.replace(projectUrl, "") for url in urls when fs.isFile(url)) urls + open: (filePath) -> + filePath = @resolve filePath + @buffers[filePath] ?= new Buffer(filePath) + + resolve: (filePath) -> + filePath = fs.join(@url, filePath) unless filePath[0] == '/' + fs.absolute filePath + diff --git a/src/atom/root-view.coffee b/src/atom/root-view.coffee index 69c5ce40f..eaf4a5bcc 100644 --- a/src/atom/root-view.coffee +++ b/src/atom/root-view.coffee @@ -2,6 +2,7 @@ $ = require 'jquery' fs = require 'fs' Template = require 'template' +Buffer = require 'buffer' Editor = require 'editor' FileFinder = require 'file-finder' Project = require 'project' @@ -23,7 +24,7 @@ class RootView extends Template if url @project = new Project(fs.directory(url)) - @editor.open(url) if fs.isFile(url) + @editor.setBuffer(@project.open(url)) if fs.isFile(url) addPane: (view) -> pane = $('
') @@ -37,7 +38,10 @@ class RootView extends Template @fileFinder.remove() @fileFinder = null else - @project.getFilePaths().done (urls) => - @fileFinder = FileFinder.build({urls, selected: (url) => @editor.open(url)}) - @addPane(@fileFinder) + @project.getFilePaths().done (paths) => + relativePaths = (path.replace(@project.url, "") for path in paths) + @fileFinder = FileFinder.build + urls: relativePaths + selected: (relativePath) => @editor.setBuffer(@project.open(relativePath)) + @addPane @fileFinder @fileFinder.input.focus() diff --git a/src/stdlib/fs.coffee b/src/stdlib/fs.coffee index 0950232e9..614da994f 100644 --- a/src/stdlib/fs.coffee +++ b/src/stdlib/fs.coffee @@ -35,6 +35,11 @@ module.exports = exists: (path) -> OSX.NSFileManager.defaultManager.fileExistsAtPath_isDirectory path, null + join: (paths...) -> + return paths[0] if paths.length == 1 + [first, rest...] = paths + first.replace(/\/?$/, "/") + @join(rest...) + # Returns true if the file specified by path exists and is a # directory. isDirectory: (path) ->