From c808630ba1e9293049e2db227123c5f4f6a3ff66 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Sep 2013 08:39:16 -0700 Subject: [PATCH 01/40] Move all stylesheet globals to ThemeManager --- spec/atom-spec.coffee | 53 ++++++--------------- spec/spec-helper.coffee | 4 +- spec/theme-manager-spec.coffee | 81 +++++++++++++++++++++++++++++++- spec/window-spec.coffee | 60 ------------------------ src/atom-package.coffee | 12 +++-- src/atom.coffee | 10 ---- src/theme-manager.coffee | 86 ++++++++++++++++++++++++++++++++-- src/window.coffee | 61 +----------------------- 8 files changed, 186 insertions(+), 181 deletions(-) diff --git a/spec/atom-spec.coffee b/spec/atom-spec.coffee index a5643443e..2384920df 100644 --- a/spec/atom-spec.coffee +++ b/spec/atom-spec.coffee @@ -6,29 +6,6 @@ describe "the `atom` global", -> beforeEach -> window.rootView = new RootView - describe "base stylesheet loading", -> - beforeEach -> - rootView.append $$ -> @div class: 'editor' - rootView.attachToDom() - atom.themes.load() - atom.watchThemes() - - afterEach -> - atom.themes.unload() - config.set('core.themes', []) - atom.reloadBaseStylesheets() - - it "loads the correct values from the theme's ui-variables file", -> - config.set('core.themes', ['theme-with-ui-variables']) - - # an override loaded in the base css - expect(rootView.css("background-color")).toBe "rgb(0, 0, 255)" - - # from within the theme itself - expect($(".editor").css("padding-top")).toBe "150px" - expect($(".editor").css("padding-right")).toBe "150px" - expect($(".editor").css("padding-bottom")).toBe "150px" - describe "package lifecycle methods", -> describe ".loadPackage(name)", -> describe "when the package has deferred deserializers", -> @@ -205,15 +182,15 @@ describe "the `atom` global", -> one = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/1.css") two = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/2.less") three = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/3.css") - expect(stylesheetElementForId(one)).not.toExist() - expect(stylesheetElementForId(two)).not.toExist() - expect(stylesheetElementForId(three)).not.toExist() + expect(atom.themes.stylesheetElementForId(one)).not.toExist() + expect(atom.themes.stylesheetElementForId(two)).not.toExist() + expect(atom.themes.stylesheetElementForId(three)).not.toExist() atom.activatePackage("package-with-stylesheets-manifest") - expect(stylesheetElementForId(one)).toExist() - expect(stylesheetElementForId(two)).toExist() - expect(stylesheetElementForId(three)).not.toExist() + expect(atom.themes.stylesheetElementForId(one)).toExist() + expect(atom.themes.stylesheetElementForId(two)).toExist() + expect(atom.themes.stylesheetElementForId(three)).not.toExist() expect($('#jasmine-content').css('font-size')).toBe '1px' describe "when the metadata does not contain a 'stylesheets' manifest", -> @@ -221,14 +198,14 @@ describe "the `atom` global", -> one = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/1.css") two = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/2.less") three = require.resolve("./fixtures/packages/package-with-stylesheets/stylesheets/3.css") - expect(stylesheetElementForId(one)).not.toExist() - expect(stylesheetElementForId(two)).not.toExist() - expect(stylesheetElementForId(three)).not.toExist() + expect(atom.themes.stylesheetElementForId(one)).not.toExist() + expect(atom.themes.stylesheetElementForId(two)).not.toExist() + expect(atom.themes.stylesheetElementForId(three)).not.toExist() atom.activatePackage("package-with-stylesheets") - expect(stylesheetElementForId(one)).toExist() - expect(stylesheetElementForId(two)).toExist() - expect(stylesheetElementForId(three)).toExist() + expect(atom.themes.stylesheetElementForId(one)).toExist() + expect(atom.themes.stylesheetElementForId(two)).toExist() + expect(atom.themes.stylesheetElementForId(three)).toExist() expect($('#jasmine-content').css('font-size')).toBe '3px' describe "grammar loading", -> @@ -320,9 +297,9 @@ describe "the `atom` global", -> one = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/1.css") two = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/2.less") three = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/3.css") - expect(stylesheetElementForId(one)).not.toExist() - expect(stylesheetElementForId(two)).not.toExist() - expect(stylesheetElementForId(three)).not.toExist() + expect(atom.themes.stylesheetElementForId(one)).not.toExist() + expect(atom.themes.stylesheetElementForId(two)).not.toExist() + expect(atom.themes.stylesheetElementForId(three)).not.toExist() it "removes the package's scoped-properties", -> atom.activatePackage("package-with-scoped-properties") diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 74155a915..51853d666 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -14,8 +14,8 @@ TokenizedBuffer = require '../src/tokenized-buffer' pathwatcher = require 'pathwatcher' clipboard = require 'clipboard' -atom.loadBaseStylesheets() -requireStylesheet '../static/jasmine' +atom.themes.loadBaseStylesheets() +atom.themes.requireStylesheet '../static/jasmine' fixturePackagesPath = path.resolve(__dirname, './fixtures/packages') config.packageDirPaths.unshift(fixturePackagesPath) diff --git a/spec/theme-manager-spec.coffee b/spec/theme-manager-spec.coffee index 43f8185e6..d5d5cc1b3 100644 --- a/spec/theme-manager-spec.coffee +++ b/spec/theme-manager-spec.coffee @@ -1,4 +1,5 @@ -{$} = require 'atom' +path = require 'path' +{$, $$, fs, RootView} = require 'atom' ThemeManager = require '../src/theme-manager' AtomPackage = require '../src/atom-package' @@ -73,3 +74,81 @@ describe "ThemeManager", -> expect(loadHandler).toHaveBeenCalled() expect(loadHandler.mostRecentCall.args[0]).toBeInstanceOf AtomPackage + + describe "requireStylesheet(path)", -> + it "synchronously loads css at the given path and installs a style tag for it in the head", -> + cssPath = project.resolve('css.css') + lengthBefore = $('head style').length + + themeManager.requireStylesheet(cssPath) + expect($('head style').length).toBe lengthBefore + 1 + + element = $('head style[id*="css.css"]') + expect(element.attr('id')).toBe cssPath + expect(element.text()).toBe fs.read(cssPath) + + # doesn't append twice + themeManager.requireStylesheet(cssPath) + expect($('head style').length).toBe lengthBefore + 1 + + $('head style[id*="css.css"]').remove() + + it "synchronously loads and parses less files at the given path and installs a style tag for it in the head", -> + lessPath = project.resolve('sample.less') + lengthBefore = $('head style').length + themeManager.requireStylesheet(lessPath) + expect($('head style').length).toBe lengthBefore + 1 + + element = $('head style[id*="sample.less"]') + expect(element.attr('id')).toBe lessPath + expect(element.text()).toBe """ + #header { + color: #4d926f; + } + h2 { + color: #4d926f; + } + + """ + + # doesn't append twice + themeManager.requireStylesheet(lessPath) + expect($('head style').length).toBe lengthBefore + 1 + $('head style[id*="sample.less"]').remove() + + it "supports requiring css and less stylesheets without an explicit extension", -> + themeManager.requireStylesheet path.join(__dirname, 'fixtures', 'css') + expect($('head style[id*="css.css"]').attr('id')).toBe project.resolve('css.css') + themeManager.requireStylesheet path.join(__dirname, 'fixtures', 'sample') + expect($('head style[id*="sample.less"]').attr('id')).toBe project.resolve('sample.less') + + $('head style[id*="css.css"]').remove() + $('head style[id*="sample.less"]').remove() + + describe ".removeStylesheet(path)", -> + it "removes styling applied by given stylesheet path", -> + cssPath = require.resolve('./fixtures/css.css') + + expect($(document.body).css('font-weight')).not.toBe("bold") + themeManager.requireStylesheet(cssPath) + expect($(document.body).css('font-weight')).toBe("bold") + themeManager.removeStylesheet(cssPath) + expect($(document.body).css('font-weight')).not.toBe("bold") + + describe "base stylesheet loading", -> + beforeEach -> + window.rootView = new RootView + rootView.append $$ -> @div class: 'editor' + rootView.attachToDom() + themeManager.load() + + it "loads the correct values from the theme's ui-variables file", -> + config.set('core.themes', ['theme-with-ui-variables']) + + # an override loaded in the base css + expect(rootView.css("background-color")).toBe "rgb(0, 0, 255)" + + # from within the theme itself + expect($(".editor").css("padding-top")).toBe "150px" + expect($(".editor").css("padding-right")).toBe "150px" + expect($(".editor").css("padding-bottom")).toBe "150px" diff --git a/spec/window-spec.coffee b/spec/window-spec.coffee index 1522d6ec4..fe00aa17b 100644 --- a/spec/window-spec.coffee +++ b/spec/window-spec.coffee @@ -75,66 +75,6 @@ describe "Window", -> expect(window.onbeforeunload(new Event('beforeunload'))).toBeFalsy() expect(atom.confirmSync).toHaveBeenCalled() - describe "requireStylesheet(path)", -> - it "synchronously loads css at the given path and installs a style tag for it in the head", -> - cssPath = project.resolve('css.css') - lengthBefore = $('head style').length - - requireStylesheet(cssPath) - expect($('head style').length).toBe lengthBefore + 1 - - element = $('head style[id*="css.css"]') - expect(element.attr('id')).toBe cssPath - expect(element.text()).toBe fs.read(cssPath) - - # doesn't append twice - requireStylesheet(cssPath) - expect($('head style').length).toBe lengthBefore + 1 - - $('head style[id*="css.css"]').remove() - - it "synchronously loads and parses less files at the given path and installs a style tag for it in the head", -> - lessPath = project.resolve('sample.less') - lengthBefore = $('head style').length - requireStylesheet(lessPath) - expect($('head style').length).toBe lengthBefore + 1 - - element = $('head style[id*="sample.less"]') - expect(element.attr('id')).toBe lessPath - expect(element.text()).toBe """ - #header { - color: #4d926f; - } - h2 { - color: #4d926f; - } - - """ - - # doesn't append twice - requireStylesheet(lessPath) - expect($('head style').length).toBe lengthBefore + 1 - $('head style[id*="sample.less"]').remove() - - it "supports requiring css and less stylesheets without an explicit extension", -> - requireStylesheet path.join(__dirname, 'fixtures', 'css') - expect($('head style[id*="css.css"]').attr('id')).toBe project.resolve('css.css') - requireStylesheet path.join(__dirname, 'fixtures', 'sample') - expect($('head style[id*="sample.less"]').attr('id')).toBe project.resolve('sample.less') - - $('head style[id*="css.css"]').remove() - $('head style[id*="sample.less"]').remove() - - describe ".removeStylesheet(path)", -> - it "removes styling applied by given stylesheet path", -> - cssPath = require.resolve('./fixtures/css.css') - - expect($(document.body).css('font-weight')).not.toBe("bold") - requireStylesheet(cssPath) - expect($(document.body).css('font-weight')).toBe("bold") - removeStylesheet(cssPath) - expect($(document.body).css('font-weight')).not.toBe("bold") - describe ".unloadEditorWindow()", -> it "saves the serialized state of the window so it can be deserialized after reload", -> rootViewState = rootView.serialize() diff --git a/src/atom-package.coffee b/src/atom-package.coffee index 1074eca48..641f67b39 100644 --- a/src/atom-package.coffee +++ b/src/atom-package.coffee @@ -83,7 +83,8 @@ class AtomPackage extends Package activateStylesheets: -> type = if @metadata.theme then 'theme' else 'bundled' - applyStylesheet(stylesheetPath, content, type) for [stylesheetPath, content] in @stylesheets + for [stylesheetPath, content] in @stylesheets + atom.themes.applyStylesheet(stylesheetPath, content, type) activateResources: -> keymap.add(keymapPath, map) for [keymapPath, map] in @keymaps @@ -113,7 +114,8 @@ class AtomPackage extends Package fsUtils.listSync(menusDirPath, ['cson', 'json']) loadStylesheets: -> - @stylesheets = @getStylesheetPaths().map (stylesheetPath) -> [stylesheetPath, loadStylesheet(stylesheetPath)] + @stylesheets = @getStylesheetPaths().map (stylesheetPath) -> + [stylesheetPath, atom.themes.loadStylesheet(stylesheetPath)] getStylesheetsPath: -> path.join(@path, @constructor.stylesheetsDir) @@ -165,17 +167,17 @@ class AtomPackage extends Package syntax.removeGrammar(grammar) for grammar in @grammars syntax.removeProperties(scopedPropertiesPath) for [scopedPropertiesPath] in @scopedProperties keymap.remove(keymapPath) for [keymapPath] in @keymaps - removeStylesheet(stylesheetPath) for [stylesheetPath] in @stylesheets + atom.themes.removeStylesheet(stylesheetPath) for [stylesheetPath] in @stylesheets reloadStylesheets: -> oldSheets = _.clone(@stylesheets) @loadStylesheets() - removeStylesheet(stylesheetPath) for [stylesheetPath] in oldSheets + atom.themes.removeStylesheet(stylesheetPath) for [stylesheetPath] in oldSheets @reloadStylesheet(stylesheetPath, content) for [stylesheetPath, content] in @stylesheets reloadStylesheet: (stylesheetPath, content) -> type = if @metadata.theme then 'theme' else 'bundled' - window.applyStylesheet(stylesheetPath, content, type) + atom.themes.applyStylesheet(stylesheetPath, content, type) requireMainModule: -> return @mainModule if @mainModule? diff --git a/src/atom.coffee b/src/atom.coffee index 723f9a7f4..81e0e5842 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -146,19 +146,9 @@ window.atom = watchThemes: -> @themes.on 'reloaded', => - @reloadBaseStylesheets() pack.reloadStylesheets?() for name, pack of @loadedPackages null - loadBaseStylesheets: -> - requireStylesheet('bootstrap/less/bootstrap') - @reloadBaseStylesheets() - - reloadBaseStylesheets: -> - requireStylesheet('../static/atom') - if nativeStylesheetPath = fsUtils.resolveOnLoadPath(process.platform, ['css', 'less']) - requireStylesheet(nativeStylesheetPath) - open: (options) -> ipc.sendChannel('open', options) diff --git a/src/theme-manager.coffee b/src/theme-manager.coffee index 5ae6ff6f7..487669479 100644 --- a/src/theme-manager.coffee +++ b/src/theme-manager.coffee @@ -4,7 +4,7 @@ Package = require './package' AtomPackage = require './atom-package' _ = require './underscore-extensions' - +$ = require './jquery-extensions' fsUtils = require './fs-utils' # Private: Handles discovering and loading available themes. @@ -33,9 +33,85 @@ class ThemeManager getLoadedThemes: -> _.clone(@loadedThemes) + # Internal-only: + loadBaseStylesheets: -> + @requireStylesheet('bootstrap/less/bootstrap') + @reloadBaseStylesheets() + + # Internal-only: + reloadBaseStylesheets: -> + @requireStylesheet('../static/atom') + if nativeStylesheetPath = fsUtils.resolveOnLoadPath(process.platform, ['css', 'less']) + @requireStylesheet(nativeStylesheetPath) + + # Internal-only: + stylesheetElementForId: (id) -> + $("""head style[id="#{id}"]""") + + # Internal-only: + resolveStylesheet: (stylesheetPath) -> + if path.extname(stylesheetPath).length > 0 + fsUtils.resolveOnLoadPath(stylesheetPath) + else + fsUtils.resolveOnLoadPath(stylesheetPath, ['css', 'less']) + + # Public: resolves and applies the stylesheet specified by the path. + # + # * stylesheetPath: String. Can be an absolute path or the name of a CSS or + # LESS file in the stylesheets path. + # + # Returns the absolute path to the stylesheet + requireStylesheet: (stylesheetPath) -> + if fullPath = @resolveStylesheet(stylesheetPath) + content = @loadStylesheet(fullPath) + @applyStylesheet(fullPath, content) + else + throw new Error("Could not find a file at path '#{stylesheetPath}'") + + fullPath + + # Internal-only: + loadStylesheet: (stylesheetPath) -> + if path.extname(stylesheetPath) is '.less' + @loadLessStylesheet(stylesheetPath) + else + fsUtils.read(stylesheetPath) + + # Internal-only: + loadLessStylesheet: (lessStylesheetPath) -> + unless lessCache? + LessCompileCache = require './less-compile-cache' + lessCache = new LessCompileCache() + + try + lessCache.read(lessStylesheetPath) + catch e + console.error """ + Error compiling less stylesheet: #{lessStylesheetPath} + Line number: #{e.line} + #{e.message} + """ + + # Internal-only: + removeStylesheet: (stylesheetPath) -> + unless fullPath = @resolveStylesheet(stylesheetPath) + throw new Error("Could not find a file at path '#{stylesheetPath}'") + @stylesheetElementForId(fullPath).remove() + + # Internal-only: + applyStylesheet: (id, text, ttype = 'bundled') -> + styleElement = @stylesheetElementForId(id) + if styleElement.length + styleElement.text(text) + else + if $("head style.#{ttype}").length + $("head style.#{ttype}:last").after "" + else + $("head").append "" + # Internal-only: unload: -> - removeStylesheet(@userStylesheetPath) if @userStylesheetPath? + @removeStylesheet(@userStylesheetPath) if @userStylesheetPath? theme.deactivate() while theme = @activeThemes.pop() # Internal-only: @@ -50,7 +126,7 @@ class ThemeManager @activateTheme(themeName) for themeName in themeNames @loadUserStylesheet() - + @reloadBaseStylesheets() @trigger('reloaded') # Private: @@ -118,5 +194,5 @@ class ThemeManager loadUserStylesheet: -> if userStylesheetPath = @getUserStylesheetPath() @userStylesheetPath = userStylesheetPath - userStylesheetContents = loadStylesheet(userStylesheetPath) - applyStylesheet(userStylesheetPath, userStylesheetContents, 'userTheme') + userStylesheetContents = @loadStylesheet(userStylesheetPath) + @applyStylesheet(userStylesheetPath, userStylesheetContents, 'userTheme') diff --git a/src/window.coffee b/src/window.coffee index 337a3704b..0867e6a08 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -62,7 +62,7 @@ window.startEditorWindow = -> restoreDimensions() config.load() keymap.loadBundledKeymaps() - atom.loadBaseStylesheets() + atom.themes.loadBaseStylesheets() atom.loadPackages() atom.loadThemes() deserializeEditorWindow() @@ -132,65 +132,6 @@ window.deserializeEditorWindow = -> projectPath = project.getPath() atom.getLoadSettings().initialPath = projectPath -window.stylesheetElementForId = (id) -> - $("""head style[id="#{id}"]""") - -window.resolveStylesheet = (stylesheetPath) -> - if path.extname(stylesheetPath).length > 0 - fsUtils.resolveOnLoadPath(stylesheetPath) - else - fsUtils.resolveOnLoadPath(stylesheetPath, ['css', 'less']) - -# Public: resolves and applies the stylesheet specified by the path. -# -# * stylesheetPath: String. Can be an absolute path or the name of a CSS or -# LESS file in the stylesheets path. -# -# Returns the absolute path to the stylesheet -window.requireStylesheet = (stylesheetPath) -> - if fullPath = window.resolveStylesheet(stylesheetPath) - content = window.loadStylesheet(fullPath) - window.applyStylesheet(fullPath, content) - else - throw new Error("Could not find a file at path '#{stylesheetPath}'") - - fullPath - -window.loadStylesheet = (stylesheetPath) -> - if path.extname(stylesheetPath) is '.less' - loadLessStylesheet(stylesheetPath) - else - fsUtils.read(stylesheetPath) - -window.loadLessStylesheet = (lessStylesheetPath) -> - unless lessCache? - LessCompileCache = require './less-compile-cache' - lessCache = new LessCompileCache() - - try - lessCache.read(lessStylesheetPath) - catch e - console.error """ - Error compiling less stylesheet: #{lessStylesheetPath} - Line number: #{e.line} - #{e.message} - """ - -window.removeStylesheet = (stylesheetPath) -> - unless fullPath = window.resolveStylesheet(stylesheetPath) - throw new Error("Could not find a file at path '#{stylesheetPath}'") - window.stylesheetElementForId(fullPath).remove() - -window.applyStylesheet = (id, text, ttype = 'bundled') -> - styleElement = window.stylesheetElementForId(id) - if styleElement.length - styleElement.text(text) - else - if $("head style.#{ttype}").length - $("head style.#{ttype}:last").after "" - else - $("head").append "" - window.getDimensions = -> browserWindow = remote.getCurrentWindow() [x, y] = browserWindow.getPosition() From 862220adf2c789e59bf23edc02f8522c6d813784 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Sep 2013 09:00:18 -0700 Subject: [PATCH 02/40] Store less cache as an ivar on ThemeManager --- src/theme-manager.coffee | 5 +++-- src/window.coffee | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/theme-manager.coffee b/src/theme-manager.coffee index 487669479..3c4b71e48 100644 --- a/src/theme-manager.coffee +++ b/src/theme-manager.coffee @@ -15,6 +15,7 @@ class ThemeManager constructor: -> @loadedThemes = [] @activeThemes = [] + @lessCache = null # Internal-only: register: (theme) -> @@ -81,10 +82,10 @@ class ThemeManager loadLessStylesheet: (lessStylesheetPath) -> unless lessCache? LessCompileCache = require './less-compile-cache' - lessCache = new LessCompileCache() + @lessCache = new LessCompileCache() try - lessCache.read(lessStylesheetPath) + @lessCache.read(lessStylesheetPath) catch e console.error """ Error compiling less stylesheet: #{lessStylesheetPath} diff --git a/src/window.coffee b/src/window.coffee index 0867e6a08..887ccf62f 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -10,7 +10,6 @@ WindowEventHandler = require './window-event-handler' deserializers = {} deferredDeserializers = {} defaultWindowDimensions = {width: 800, height: 600} -lessCache = null ### Internal ### From fc3dcd9749b0095bc85bb286f8372c679792dde5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Sep 2013 09:14:13 -0700 Subject: [PATCH 03/40] Add PackageManager class accessible from atom.packages --- src/atom.coffee | 141 +++++++------------------------------ src/package-manager.coffee | 125 ++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 117 deletions(-) create mode 100644 src/package-manager.coffee diff --git a/src/atom.coffee b/src/atom.coffee index 81e0e5842..6f3f9e2c0 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -10,13 +10,12 @@ path = require 'path' dialog = remote.require 'dialog' app = remote.require 'app' {Document} = require 'telepath' +PackageManager = require './package-manager' ThemeManager = require './theme-manager' ContextMenuManager = require './context-menu-manager' window.atom = - loadedPackages: {} - activePackages: {} - packageStates: {} + packages: new PackageManager() themes: new ThemeManager() contextMenu: new ContextMenuManager(remote.getCurrentWindow().loadSettings.devMode) @@ -26,120 +25,28 @@ window.atom = getCurrentWindow: -> remote.getCurrentWindow() - getPackageState: (name) -> - @packageStates[name] - - setPackageState: (name, state) -> - @packageStates[name] = state - - activatePackages: -> - @activatePackage(pack.name) for pack in @getLoadedPackages() - - activatePackage: (name, options) -> - if pack = @loadPackage(name, options) - @activePackages[pack.name] = pack - pack.activate(options) - pack - - deactivatePackages: -> - @deactivatePackage(pack.name) for pack in @getActivePackages() - - deactivatePackage: (name) -> - if pack = @getActivePackage(name) - @setPackageState(pack.name, state) if state = pack.serialize?() - pack.deactivate() - delete @activePackages[pack.name] - else - throw new Error("No active package for name '#{name}'") - - getActivePackage: (name) -> - @activePackages[name] - - isPackageActive: (name) -> - @getActivePackage(name)? - - getActivePackages: -> - _.values(@activePackages) - - loadPackages: -> - # Ensure atom exports is already in the require cache so the load time - # of the first package isn't skewed by being the first to require atom - require '../exports/atom' - - @loadPackage(name) for name in @getAvailablePackageNames() when not @isPackageDisabled(name) - @watchThemes() - - loadPackage: (name, options) -> - if @isPackageDisabled(name) - return console.warn("Tried to load disabled package '#{name}'") - - if packagePath = @resolvePackagePath(name) - return pack if pack = @getLoadedPackage(name) - pack = Package.load(packagePath, options) - if pack.metadata.theme - @themes.register(pack) - else - @loadedPackages[pack.name] = pack - pack - else - throw new Error("Could not resolve '#{name}' to a package path") - - unloadPackage: (name) -> - if @isPackageActive(name) - throw new Error("Tried to unload active package '#{name}'") - - if pack = @getLoadedPackage(name) - delete @loadedPackages[pack.name] - else - throw new Error("No loaded package for name '#{name}'") - - resolvePackagePath: (name) -> - return name if fsUtils.isDirectorySync(name) - - packagePath = fsUtils.resolve(config.packageDirPaths..., name) - return packagePath if fsUtils.isDirectorySync(packagePath) - - packagePath = path.join(window.resourcePath, 'node_modules', name) - return packagePath if @isInternalPackage(packagePath) - - isInternalPackage: (packagePath) -> - {engines} = Package.loadMetadata(packagePath, true) - engines?.atom? - - getLoadedPackage: (name) -> - @loadedPackages[name] - - isPackageLoaded: (name) -> - @getLoadedPackage(name)? - - getLoadedPackages: -> - _.values(@loadedPackages) - - isPackageDisabled: (name) -> - _.include(config.get('core.disabledPackages') ? [], name) - - getAvailablePackagePaths: -> - packagePaths = [] - - for packageDirPath in config.packageDirPaths - for packagePath in fsUtils.listSync(packageDirPath) - packagePaths.push(packagePath) if fsUtils.isDirectorySync(packagePath) - - for packagePath in fsUtils.listSync(path.join(window.resourcePath, 'node_modules')) - packagePaths.push(packagePath) if @isInternalPackage(packagePath) - - _.uniq(packagePaths) - - getAvailablePackageNames: -> - _.uniq _.map @getAvailablePackagePaths(), (packagePath) -> path.basename(packagePath) - - getAvailablePackageMetadata: -> - packages = [] - for packagePath in atom.getAvailablePackagePaths() - name = path.basename(packagePath) - metadata = atom.getLoadedPackage(name)?.metadata ? Package.loadMetadata(packagePath, true) - packages.push(metadata) - packages + #TODO Remove theses once packages have been migrated + getPackageState: (args...) -> @packages.getPackageState(args...) + setPackageState: (args...) -> @packages.setPackageState(args...) + activatePackages: (args...) -> @packages.activatePackages(args...) + activatePackage: (args...) -> @packages.activatePackage(args...) + deactivatePackages: (args...) -> @packages.deactivatePackage(args...) + deactivatePackage: (args...) -> @packages.deactivatePackage(args...) + getActivePackage: (args...) -> @packages.getActivePackage(args...) + isPackageActive: (args...) -> @packages.isPackageActive(args...) + getActivePackages: (args...) -> @packages.getActivePackages(args...) + loadPackages: (args...) -> @packages.loadPackages(args...) + loadPackage: (args...) -> @packages.loadPackage(args...) + unloadPackage: (args...) -> @packages.unloadPackage(args...) + resolvePackagePath: (args...) -> @packages.resolvePackagePath(args...) + isInternalPackage: (args...) -> @packages.isInternalPackage(args...) + getLoadedPackage: (args...) -> @packages.getLoadedPackage(args...) + isPackageLoaded: (args...) -> @packages.isPackageLoaded(args...) + getLoadedPackages: (args...) -> @packages.getLoadedPackages(args...) + isPackageDisabled: (args...) -> @packages.isPackageDisabled(args...) + getAvailablePackagePaths: (args...) -> @packages.getAvailablePackagePaths(args...) + getAvailablePackageNames: (args...) -> @packages.getAvailablePackageNames(args...) + getAvailablePackageMetadata: (args...)-> @packages.getAvailablePackageMetadata(args...) loadThemes: -> @themes.load() diff --git a/src/package-manager.coffee b/src/package-manager.coffee new file mode 100644 index 000000000..9b34b1a89 --- /dev/null +++ b/src/package-manager.coffee @@ -0,0 +1,125 @@ +fsUtils = require './fs-utils' +_ = require './underscore-extensions' +Package = require './package' +path = require 'path' + +module.exports = +class PackageManager + loadedPackages: {} + activePackages: {} + packageStates: {} + + getPackageState: (name) -> + @packageStates[name] + + setPackageState: (name, state) -> + @packageStates[name] = state + + activatePackages: -> + @activatePackage(pack.name) for pack in @getLoadedPackages() + + activatePackage: (name, options) -> + if pack = @loadPackage(name, options) + @activePackages[pack.name] = pack + pack.activate(options) + pack + + deactivatePackages: -> + @deactivatePackage(pack.name) for pack in @getActivePackages() + + deactivatePackage: (name) -> + if pack = @getActivePackage(name) + @setPackageState(pack.name, state) if state = pack.serialize?() + pack.deactivate() + delete @activePackages[pack.name] + else + throw new Error("No active package for name '#{name}'") + + getActivePackage: (name) -> + @activePackages[name] + + isPackageActive: (name) -> + @getActivePackage(name)? + + getActivePackages: -> + _.values(@activePackages) + + loadPackages: -> + # Ensure atom exports is already in the require cache so the load time + # of the first package isn't skewed by being the first to require atom + require '../exports/atom' + + @loadPackage(name) for name in @getAvailablePackageNames() when not @isPackageDisabled(name) + @watchThemes() + + loadPackage: (name, options) -> + if @isPackageDisabled(name) + return console.warn("Tried to load disabled package '#{name}'") + + if packagePath = @resolvePackagePath(name) + return pack if pack = @getLoadedPackage(name) + pack = Package.load(packagePath, options) + if pack.metadata.theme + @themes.register(pack) + else + @loadedPackages[pack.name] = pack + pack + else + throw new Error("Could not resolve '#{name}' to a package path") + + unloadPackage: (name) -> + if @isPackageActive(name) + throw new Error("Tried to unload active package '#{name}'") + + if pack = @getLoadedPackage(name) + delete @loadedPackages[pack.name] + else + throw new Error("No loaded package for name '#{name}'") + + resolvePackagePath: (name) -> + return name if fsUtils.isDirectorySync(name) + + packagePath = fsUtils.resolve(config.packageDirPaths..., name) + return packagePath if fsUtils.isDirectorySync(packagePath) + + packagePath = path.join(window.resourcePath, 'node_modules', name) + return packagePath if @isInternalPackage(packagePath) + + isInternalPackage: (packagePath) -> + {engines} = Package.loadMetadata(packagePath, true) + engines?.atom? + + getLoadedPackage: (name) -> + @loadedPackages[name] + + isPackageLoaded: (name) -> + @getLoadedPackage(name)? + + getLoadedPackages: -> + _.values(@loadedPackages) + + isPackageDisabled: (name) -> + _.include(config.get('core.disabledPackages') ? [], name) + + getAvailablePackagePaths: -> + packagePaths = [] + + for packageDirPath in config.packageDirPaths + for packagePath in fsUtils.listSync(packageDirPath) + packagePaths.push(packagePath) if fsUtils.isDirectorySync(packagePath) + + for packagePath in fsUtils.listSync(path.join(window.resourcePath, 'node_modules')) + packagePaths.push(packagePath) if @isInternalPackage(packagePath) + + _.uniq(packagePaths) + + getAvailablePackageNames: -> + _.uniq _.map @getAvailablePackagePaths(), (packagePath) -> path.basename(packagePath) + + getAvailablePackageMetadata: -> + packages = [] + for packagePath in atom.getAvailablePackagePaths() + name = path.basename(packagePath) + metadata = atom.getLoadedPackage(name)?.metadata ? Package.loadMetadata(packagePath, true) + packages.push(metadata) + packages From 44d6bf9bf0568c9abadbdc66c6de847d3e4319a7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 25 Sep 2013 09:15:18 -0700 Subject: [PATCH 04/40] Call getLoadPackages() instead of referencing ivar --- src/atom.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atom.coffee b/src/atom.coffee index 6f3f9e2c0..a40e44764 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -53,7 +53,7 @@ window.atom = watchThemes: -> @themes.on 'reloaded', => - pack.reloadStylesheets?() for name, pack of @loadedPackages + pack.reloadStylesheets?() for name, pack of @getLoadedPackages() null open: (options) -> From 7f4ccf6a42ff54e6ba613d586e36106016a28a47 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 08:30:45 -0700 Subject: [PATCH 05/40] Export an Atom class from atom.coffee --- src/atom.coffee | 10 ++++++---- src/window-bootstrap.coffee | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index a40e44764..342399dec 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -14,10 +14,12 @@ PackageManager = require './package-manager' ThemeManager = require './theme-manager' ContextMenuManager = require './context-menu-manager' -window.atom = - packages: new PackageManager() - themes: new ThemeManager() - contextMenu: new ContextMenuManager(remote.getCurrentWindow().loadSettings.devMode) +module.exports = +class Atom + constructor: -> + @packages = new PackageManager() + @themes = new ThemeManager() + @contextMenu = new ContextMenuManager(@getLoadSettings().devMode) getLoadSettings: -> @getCurrentWindow().loadSettings diff --git a/src/window-bootstrap.coffee b/src/window-bootstrap.coffee index bccf2ee92..26760e9f5 100644 --- a/src/window-bootstrap.coffee +++ b/src/window-bootstrap.coffee @@ -1,9 +1,10 @@ # Like sands through the hourglass, so are the days of our lives. startTime = new Date().getTime() -require './atom' +Atom = require './atom' require './window' +window.atom = new Atom() window.setUpEnvironment('editor') window.startEditorWindow() console.log "Window load time: #{new Date().getTime() - startTime}ms" From 3f5875e5db3c734783bb31d10e468bf84cebc064 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 08:33:22 -0700 Subject: [PATCH 06/40] :lipstick: Add getCurrentWindow() helper --- src/atom.coffee | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index 342399dec..247d64249 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -21,12 +21,12 @@ class Atom @themes = new ThemeManager() @contextMenu = new ContextMenuManager(@getLoadSettings().devMode) - getLoadSettings: -> - @getCurrentWindow().loadSettings - getCurrentWindow: -> remote.getCurrentWindow() + getLoadSettings: -> + @getCurrentWindow().loadSettings + #TODO Remove theses once packages have been migrated getPackageState: (args...) -> @packages.getPackageState(args...) setPackageState: (args...) -> @packages.setPackageState(args...) @@ -109,8 +109,7 @@ class Atom close: -> @getCurrentWindow().close() - exit: (status) -> - app.exit(status) + exit: (status) -> app.exit(status) toggleFullScreen: -> @setFullScreen(!@isFullScreen()) From 8660a46facae0678cefc1fb46279c52a435e0e70 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 08:34:45 -0700 Subject: [PATCH 07/40] :memo: Mark Atom class as public --- src/atom.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/atom.coffee b/src/atom.coffee index 247d64249..47cd56af1 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -14,6 +14,7 @@ PackageManager = require './package-manager' ThemeManager = require './theme-manager' ContextMenuManager = require './context-menu-manager' +# Public: Atom global for dealing with packages, themes, menus, and the window. module.exports = class Atom constructor: -> From 62278d91371173716c0172f7586f8ce4772682f7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 08:41:05 -0700 Subject: [PATCH 08/40] Create config, pasteboard, and keymap in Atom --- src/atom.coffee | 6 ++++++ src/window.coffee | 9 +++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index 47cd56af1..0df8ff830 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -10,7 +10,10 @@ path = require 'path' dialog = remote.require 'dialog' app = remote.require 'app' {Document} = require 'telepath' +Config = require './config' +Keymap = require './keymap' PackageManager = require './package-manager' +Pasteboard = require './pasteboard' ThemeManager = require './theme-manager' ContextMenuManager = require './context-menu-manager' @@ -21,6 +24,9 @@ class Atom @packages = new PackageManager() @themes = new ThemeManager() @contextMenu = new ContextMenuManager(@getLoadSettings().devMode) + @config = new Config() + @pasteboard = new Pasteboard() + @keymap = new KeyMap() getCurrentWindow: -> remote.getCurrentWindow() diff --git a/src/window.coffee b/src/window.coffee index 887ccf62f..4835f6cf7 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -29,16 +29,13 @@ window.setUpEnvironment = (windowMode) -> atom.windowMode = windowMode window.resourcePath = remote.getCurrentWindow().loadSettings.resourcePath - Config = require './config' Syntax = require './syntax' - Pasteboard = require './pasteboard' - Keymap = require './keymap' window.rootViewParentSelector = 'body' - window.config = new Config + window.config = atom.config window.syntax = deserialize(atom.getWindowState('syntax')) ? new Syntax - window.pasteboard = new Pasteboard - window.keymap = new Keymap() + window.pasteboard = atom.pasteboard + window.keymap = atom.keymap # Set up the default event handlers and menus for a non-editor windows. From 6a65aad2746d5cdd55fc55e49189848d1b71a98f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 08:41:43 -0700 Subject: [PATCH 09/40] :lipstick: Use atom.getLoadSettings() --- src/window.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window.coffee b/src/window.coffee index 4835f6cf7..9bf54ebed 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -27,7 +27,7 @@ displayWindow = -> # This method is called in any window needing a general environment, including specs window.setUpEnvironment = (windowMode) -> atom.windowMode = windowMode - window.resourcePath = remote.getCurrentWindow().loadSettings.resourcePath + window.resourcePath = atom.getLoadSettings().resourcePath Syntax = require './syntax' From 4e3c5d2abaa34b30510a80065a197c4584618ee2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 08:45:54 -0700 Subject: [PATCH 10/40] Keep command install functions local --- src/window.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/window.coffee b/src/window.coffee index 9bf54ebed..4be27cdc4 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -89,11 +89,11 @@ window.unloadEditorWindow = -> window.rootView = null window.project = null -window.installAtomCommand = (callback) -> +installAtomCommand = (callback) -> commandPath = path.join(window.resourcePath, 'atom.sh') require('./command-installer').install(commandPath, callback) -window.installApmCommand = (callback) -> +installApmCommand = (callback) -> commandPath = path.join(window.resourcePath, 'node_modules', '.bin', 'apm') require('./command-installer').install(commandPath, callback) From 4be4868959a8537d9a52cf010ffdeac593c7d42d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 08:50:01 -0700 Subject: [PATCH 11/40] Move dimension helpers from window to Atom class --- src/atom.coffee | 19 +++++++++++++++++++ src/window-event-handler.coffee | 2 ++ src/window.coffee | 21 ++------------------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index 0df8ff830..84d07ba44 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -31,6 +31,25 @@ class Atom getCurrentWindow: -> remote.getCurrentWindow() + getDimensions: -> + browserWindow = @getCurrentWindow() + [x, y] = browserWindow.getPosition() + [width, height] = browserWindow.getSize() + {x, y, width, height} + + setDimensions: ({x, y, width, height}) -> + browserWindow = @getCurrentWindow() + browserWindow.setSize(width, height) + if x? and y? + browserWindow.setPosition(x, y) + else + browserWindow.center() + + restoreDimensions: (defaultDimensions={width: 800, height: 600})-> + dimensions = @getWindowState().getObject('dimensions') + dimensions = defaultDimensions unless dimensions?.width and dimensions?.height + @setDimensions(dimensions) + getLoadSettings: -> @getCurrentWindow().loadSettings diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee index 33b6f2cd5..fe3a97820 100644 --- a/src/window-event-handler.coffee +++ b/src/window-event-handler.coffee @@ -28,6 +28,8 @@ class WindowEventHandler atom.hide() if confirmed and not @reloadRequested and remote.getCurrentWindow().isWebViewFocused() @reloadRequested = false confirmed + @subscribe $(window), 'unload', -> + atom.getWindowState().set('dimensions', atom.getDimensions()) @subscribeToCommand $(window), 'window:toggle-full-screen', => atom.toggleFullScreen() @subscribeToCommand $(window), 'window:close', => atom.close() @subscribeToCommand $(window), 'window:reload', => diff --git a/src/window.coffee b/src/window.coffee index 4be27cdc4..3158878e5 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -9,7 +9,6 @@ WindowEventHandler = require './window-event-handler' deserializers = {} deferredDeserializers = {} -defaultWindowDimensions = {width: 800, height: 600} ### Internal ### @@ -128,25 +127,9 @@ window.deserializeEditorWindow = -> projectPath = project.getPath() atom.getLoadSettings().initialPath = projectPath -window.getDimensions = -> - browserWindow = remote.getCurrentWindow() - [x, y] = browserWindow.getPosition() - [width, height] = browserWindow.getSize() - {x, y, width, height} +window.getDimensions = -> atom.getDimensions() -window.setDimensions = ({x, y, width, height}) -> - browserWindow = remote.getCurrentWindow() - browserWindow.setSize(width, height) - if x? and y? - browserWindow.setPosition(x, y) - else - browserWindow.center() - -window.restoreDimensions = -> - dimensions = atom.getWindowState().getObject('dimensions') - dimensions = defaultWindowDimensions unless dimensions?.width and dimensions?.height - window.setDimensions(dimensions) - $(window).on 'unload', -> atom.getWindowState().set('dimensions', window.getDimensions()) +window.setDimensions = (args...) -> atom.setDimensions(args...) window.onerror = -> atom.openDevTools() From 5c4a8f55c810ec1251230b5c339569c354c1ba74 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 08:58:43 -0700 Subject: [PATCH 12/40] Add deserializeEditorWindow to Atom class --- src/atom.coffee | 27 ++++++++++++++++++++++++++- src/window.coffee | 28 +++++----------------------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index 84d07ba44..a840628e5 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -14,12 +14,15 @@ Config = require './config' Keymap = require './keymap' PackageManager = require './package-manager' Pasteboard = require './pasteboard' +Project = require './project' +RootView = require './root-view' +Subscriber = require './subscriber' ThemeManager = require './theme-manager' ContextMenuManager = require './context-menu-manager' # Public: Atom global for dealing with packages, themes, menus, and the window. module.exports = -class Atom +class Atom extends Subscriber constructor: -> @packages = new PackageManager() @themes = new ThemeManager() @@ -53,6 +56,28 @@ class Atom getLoadSettings: -> @getCurrentWindow().loadSettings + deserializeEditorWindow: -> + state = @getWindowState() + + @packages.packageStates = state.getObject('packageStates') ? {} + state.remove('packageStates') + + @project = deserialize(state.get('project')) + unless @project? + @project = new Project(@getLoadSettings().initialPath) + state.set('project', @project.getState()) + + @rootView = deserialize(state.get('rootView')) + unless @rootView? + @rootView = new RootView() + state.set('rootView', @rootView.getState()) + + $(rootViewParentSelector).append(rootView) + + @subscribe @project, 'path-changed', -> + projectPath = project.getPath() + @getLoadSettings().initialPath = projectPath + #TODO Remove theses once packages have been migrated getPackageState: (args...) -> @packages.getPackageState(args...) setPackageState: (args...) -> @packages.setPackageState(args...) diff --git a/src/window.coffee b/src/window.coffee index 3158878e5..96458bede 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -31,6 +31,7 @@ window.setUpEnvironment = (windowMode) -> Syntax = require './syntax' window.rootViewParentSelector = 'body' + #TODO remove once all packages use the atom globa window.config = atom.config window.syntax = deserialize(atom.getWindowState('syntax')) ? new Syntax window.pasteboard = atom.pasteboard @@ -103,29 +104,10 @@ window.onDrop = (e) -> atom.open({pathsToOpen}) if pathsToOpen.length > 0 window.deserializeEditorWindow = -> - RootView = require './root-view' - Project = require './project' - - windowState = atom.getWindowState() - - atom.packageStates = windowState.getObject('packageStates') ? {} - windowState.remove('packageStates') - - window.project = deserialize(windowState.get('project')) - unless window.project? - window.project = new Project(atom.getLoadSettings().initialPath) - windowState.set('project', window.project.getState()) - - window.rootView = deserialize(windowState.get('rootView')) - unless window.rootView? - window.rootView = new RootView() - windowState.set('rootView', window.rootView.getState()) - - $(rootViewParentSelector).append(rootView) - - project.on 'path-changed', -> - projectPath = project.getPath() - atom.getLoadSettings().initialPath = projectPath + atom.deserializeEditorWindow() + #TODO remove once all packages use the atom globa + window.project = atom.project + window.rootView = atom.rootView window.getDimensions = -> atom.getDimensions() From e2d727f8387984fd103fe6a034df15df7ebceb4c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 09:00:39 -0700 Subject: [PATCH 13/40] Move Syntax global to Atom class --- src/atom.coffee | 5 ++++- src/window.coffee | 10 +++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index a840628e5..fcda9fe66 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -16,6 +16,7 @@ PackageManager = require './package-manager' Pasteboard = require './pasteboard' Project = require './project' RootView = require './root-view' +Syntax = require './syntax' Subscriber = require './subscriber' ThemeManager = require './theme-manager' ContextMenuManager = require './context-menu-manager' @@ -24,12 +25,14 @@ ContextMenuManager = require './context-menu-manager' module.exports = class Atom extends Subscriber constructor: -> + @rootViewParentSelector = 'body' @packages = new PackageManager() @themes = new ThemeManager() @contextMenu = new ContextMenuManager(@getLoadSettings().devMode) @config = new Config() @pasteboard = new Pasteboard() @keymap = new KeyMap() + @syntax = deserialize(@getWindowState('syntax')) ? new Syntax() getCurrentWindow: -> remote.getCurrentWindow() @@ -72,7 +75,7 @@ class Atom extends Subscriber @rootView = new RootView() state.set('rootView', @rootView.getState()) - $(rootViewParentSelector).append(rootView) + $(@rootViewParentSelector).append(rootView) @subscribe @project, 'path-changed', -> projectPath = project.getPath() diff --git a/src/window.coffee b/src/window.coffee index 96458bede..52d242363 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -26,14 +26,10 @@ displayWindow = -> # This method is called in any window needing a general environment, including specs window.setUpEnvironment = (windowMode) -> atom.windowMode = windowMode + #TODO remove once all packages use the atom global window.resourcePath = atom.getLoadSettings().resourcePath - - Syntax = require './syntax' - - window.rootViewParentSelector = 'body' - #TODO remove once all packages use the atom globa window.config = atom.config - window.syntax = deserialize(atom.getWindowState('syntax')) ? new Syntax + window.syntax = atom.syntax window.pasteboard = atom.pasteboard window.keymap = atom.keymap @@ -105,7 +101,7 @@ window.onDrop = (e) -> window.deserializeEditorWindow = -> atom.deserializeEditorWindow() - #TODO remove once all packages use the atom globa + #TODO remove once all packages use the atom global window.project = atom.project window.rootView = atom.rootView From dc8fae12b60bbd05a02e23b8c946bda401f1597e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 09:25:14 -0700 Subject: [PATCH 14/40] Create new Atom class in spec/benchmark bootstraps --- benchmark/benchmark-bootstrap.coffee | 3 ++- spec/spec-bootstrap.coffee | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/benchmark/benchmark-bootstrap.coffee b/benchmark/benchmark-bootstrap.coffee index 18d030e62..5d74df7de 100644 --- a/benchmark/benchmark-bootstrap.coffee +++ b/benchmark/benchmark-bootstrap.coffee @@ -1,4 +1,5 @@ -require '../src/atom' +Atom = require '../src/atom' +window.atom = new Atom() {runSpecSuite} = require '../spec/jasmine-helper' atom.openDevTools() diff --git a/spec/spec-bootstrap.coffee b/spec/spec-bootstrap.coffee index 97a4d8471..ac84f6675 100644 --- a/spec/spec-bootstrap.coffee +++ b/spec/spec-bootstrap.coffee @@ -1,7 +1,8 @@ try - require '../src/atom' + Atom = require '../src/atom' require '../src/window' - atom.show() + window.atom = new Atom() + window.atom.show() {runSpecSuite} = require './jasmine-helper' document.title = "Spec Suite" From 901b128572f5a0e862d832f1f0f64c6bfee5afc6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 09:40:09 -0700 Subject: [PATCH 15/40] :lipstick: Remove extra newline --- src/window.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/window.coffee b/src/window.coffee index 52d242363..dcf0a595e 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -33,7 +33,6 @@ window.setUpEnvironment = (windowMode) -> window.pasteboard = atom.pasteboard window.keymap = atom.keymap - # Set up the default event handlers and menus for a non-editor windows. # # This can be used by packages to have a minimum level of keybindings and From 8150263f52c7d22938247569d4ddb66c8f0c68b5 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 10:10:23 -0700 Subject: [PATCH 16/40] Initialize paths in constructor Previously this was done at eval time which required globals to be set before the class could be required. --- src/config.coffee | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/config.coffee b/src/config.coffee index ffcd24809..ae7901177 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -8,12 +8,6 @@ async = require 'async' pathWatcher = require 'pathwatcher' configDirPath = fsUtils.absolute("~/.atom") -nodeModulesDirPath = path.join(resourcePath, "node_modules") -bundledKeymapsDirPath = path.join(resourcePath, "keymaps") -userPackagesDirPath = path.join(configDirPath, "packages") -userPackageDirPaths = [userPackagesDirPath] -userPackageDirPaths.unshift(path.join(configDirPath, "dev", "packages")) if atom.getLoadSettings().devMode -userStoragePath = path.join(configDirPath, "storage") # Public: Used to access all of Atom's configuration details. # @@ -36,23 +30,25 @@ module.exports = class Config _.extend @prototype, EventEmitter - configDirPath: configDirPath - bundledPackageDirPaths: [nodeModulesDirPath] - bundledKeymapsDirPath: bundledKeymapsDirPath - nodeModulesDirPath: nodeModulesDirPath - packageDirPaths: _.clone(userPackageDirPaths) - userPackageDirPaths: userPackageDirPaths - userStoragePath: userStoragePath - lessSearchPaths: [ - path.join(resourcePath, 'static', 'variables') - path.join(resourcePath, 'static') - ] defaultSettings: null settings: null configFileHasErrors: null # Private: Created during initialization, available as `global.config` constructor: -> + @configDirPath = configDirPath + @bundledKeymapsDirPath = path.join(resourcePath, "keymaps") + @nodeModulesDirPath = path.join(resourcePath, "node_modules") + @bundledPackageDirPaths = [@nodeModulesDirPath] + @lessSearchPaths = [ + path.join(resourcePath, 'static', 'variables') + path.join(resourcePath, 'static') + ] + @packageDirPaths = [path.join(configDirPath, "packages")] + if atom.getLoadSettings().devMode + @packageDirPaths.unshift(path.join(configDirPath, "dev", "packages")) + @userStoragePath = path.join(configDirPath, "storage") + @defaultSettings = core: _.clone(require('./root-view').configDefaults) editor: _.clone(require('./editor').configDefaults) From f56758acd2440d16e7ff0ffdaa5ae7dca896fa4c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 10:10:40 -0700 Subject: [PATCH 17/40] Shim window.restoreDimensions to atom --- src/window.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/window.coffee b/src/window.coffee index dcf0a595e..bfb52524a 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -108,6 +108,8 @@ window.getDimensions = -> atom.getDimensions() window.setDimensions = (args...) -> atom.setDimensions(args...) +window.restoreDimensions = (args...) -> atom.restoreDimensions(args...) + window.onerror = -> atom.openDevTools() From 45a1334c754057eeaaa5d3bfe865ee4d86a32a3b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 10:10:59 -0700 Subject: [PATCH 18/40] Require atom after window is required --- src/window-bootstrap.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window-bootstrap.coffee b/src/window-bootstrap.coffee index 26760e9f5..15da3237e 100644 --- a/src/window-bootstrap.coffee +++ b/src/window-bootstrap.coffee @@ -1,9 +1,9 @@ # Like sands through the hourglass, so are the days of our lives. startTime = new Date().getTime() -Atom = require './atom' require './window' +Atom = require './atom' window.atom = new Atom() window.setUpEnvironment('editor') window.startEditorWindow() From 52ef2db198b0486cee777f22999622ef0daccbd6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 10:11:28 -0700 Subject: [PATCH 19/40] Separate construction vs. initialization --- src/atom.coffee | 53 +++++++++++++++++++++++++++-------------------- src/window.coffee | 8 ++++--- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index fcda9fe66..cf38c2d24 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -10,28 +10,34 @@ path = require 'path' dialog = remote.require 'dialog' app = remote.require 'app' {Document} = require 'telepath' -Config = require './config' -Keymap = require './keymap' -PackageManager = require './package-manager' -Pasteboard = require './pasteboard' -Project = require './project' -RootView = require './root-view' -Syntax = require './syntax' Subscriber = require './subscriber' -ThemeManager = require './theme-manager' -ContextMenuManager = require './context-menu-manager' # Public: Atom global for dealing with packages, themes, menus, and the window. module.exports = -class Atom extends Subscriber +class Atom + _.extend @prototype, Subscriber + constructor: -> @rootViewParentSelector = 'body' + + initialize: -> + @unsubscribe() + + Config = require './config' + Keymap = require './keymap' + PackageManager = require './package-manager' + Pasteboard = require './pasteboard' + Syntax = require './syntax' + ThemeManager = require './theme-manager' + ContextMenuManager = require './context-menu-manager' + @packages = new PackageManager() + @packages.on 'loaded', => @watchThemes() @themes = new ThemeManager() @contextMenu = new ContextMenuManager(@getLoadSettings().devMode) @config = new Config() @pasteboard = new Pasteboard() - @keymap = new KeyMap() + @keymap = new Keymap() @syntax = deserialize(@getWindowState('syntax')) ? new Syntax() getCurrentWindow: -> @@ -59,27 +65,27 @@ class Atom extends Subscriber getLoadSettings: -> @getCurrentWindow().loadSettings - deserializeEditorWindow: -> + deserializeProject: -> + Project = require './project' state = @getWindowState() - - @packages.packageStates = state.getObject('packageStates') ? {} - state.remove('packageStates') - @project = deserialize(state.get('project')) unless @project? @project = new Project(@getLoadSettings().initialPath) state.set('project', @project.getState()) + deserializeRootView: -> + RootView = require './root-view' + state = @getWindowState() @rootView = deserialize(state.get('rootView')) unless @rootView? @rootView = new RootView() state.set('rootView', @rootView.getState()) + $(@rootViewParentSelector).append(@rootView) - $(@rootViewParentSelector).append(rootView) - - @subscribe @project, 'path-changed', -> - projectPath = project.getPath() - @getLoadSettings().initialPath = projectPath + deserializePackageStates: -> + state = @getWindowState() + @packages.packageStates = state.getObject('packageStates') ? {} + state.remove('packageStates') #TODO Remove theses once packages have been migrated getPackageState: (args...) -> @packages.getPackageState(args...) @@ -92,6 +98,7 @@ class Atom extends Subscriber isPackageActive: (args...) -> @packages.isPackageActive(args...) getActivePackages: (args...) -> @packages.getActivePackages(args...) loadPackages: (args...) -> @packages.loadPackages(args...) + loadPackage: (args...) -> @packages.loadPackage(args...) unloadPackage: (args...) -> @packages.unloadPackage(args...) resolvePackagePath: (args...) -> @packages.resolvePackagePath(args...) @@ -188,7 +195,7 @@ class Atom extends Subscriber filename = "editor-#{sha1}" if filename - path.join(config.userStoragePath, filename) + path.join(@config.userStoragePath, filename) else null @@ -241,7 +248,7 @@ class Atom extends Subscriber shell.beep() requireUserInitScript: -> - userInitScriptPath = path.join(config.configDirPath, "user.coffee") + userInitScriptPath = path.join(@config.configDirPath, "user.coffee") try require userInitScriptPath if fsUtils.isFileSync(userInitScriptPath) catch error diff --git a/src/window.coffee b/src/window.coffee index bfb52524a..63a21ebe9 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -26,8 +26,9 @@ displayWindow = -> # This method is called in any window needing a general environment, including specs window.setUpEnvironment = (windowMode) -> atom.windowMode = windowMode - #TODO remove once all packages use the atom global window.resourcePath = atom.getLoadSettings().resourcePath + atom.initialize() + #TODO remove once all packages use the atom global window.config = atom.config window.syntax = atom.syntax window.pasteboard = atom.pasteboard @@ -99,9 +100,10 @@ window.onDrop = (e) -> atom.open({pathsToOpen}) if pathsToOpen.length > 0 window.deserializeEditorWindow = -> - atom.deserializeEditorWindow() - #TODO remove once all packages use the atom global + atom.deserializePackageStates() + atom.deserializeProject() window.project = atom.project + atom.deserializeRootView() window.rootView = atom.rootView window.getDimensions = -> atom.getDimensions() From ed5dbe983e08637751794c9673fe42648619e93b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 10:11:48 -0700 Subject: [PATCH 20/40] Trigger event when packages are loaded --- src/package-manager.coffee | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 9b34b1a89..9fcff1ee3 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -1,3 +1,4 @@ +EventEmitter = require './event-emitter' fsUtils = require './fs-utils' _ = require './underscore-extensions' Package = require './package' @@ -5,6 +6,7 @@ path = require 'path' module.exports = class PackageManager + _.extend @prototype, EventEmitter loadedPackages: {} activePackages: {} packageStates: {} @@ -50,7 +52,7 @@ class PackageManager require '../exports/atom' @loadPackage(name) for name in @getAvailablePackageNames() when not @isPackageDisabled(name) - @watchThemes() + @trigger 'loaded' loadPackage: (name, options) -> if @isPackageDisabled(name) @@ -60,7 +62,7 @@ class PackageManager return pack if pack = @getLoadedPackage(name) pack = Package.load(packagePath, options) if pack.metadata.theme - @themes.register(pack) + atom.themes.register(pack) else @loadedPackages[pack.name] = pack pack From bdddb4eb52f920856488fe81fe0195f65330aefd Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 10:13:16 -0700 Subject: [PATCH 21/40] Require atom after window --- spec/spec-bootstrap.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/spec-bootstrap.coffee b/spec/spec-bootstrap.coffee index ac84f6675..d4df9c3cd 100644 --- a/spec/spec-bootstrap.coffee +++ b/spec/spec-bootstrap.coffee @@ -1,6 +1,6 @@ try - Atom = require '../src/atom' require '../src/window' + Atom = require '../src/atom' window.atom = new Atom() window.atom.show() {runSpecSuite} = require './jasmine-helper' From c3e462db00aead17ab0469e68de856f1355c5304 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 10:14:49 -0700 Subject: [PATCH 22/40] Use subscribe instead of on --- src/atom.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atom.coffee b/src/atom.coffee index cf38c2d24..7dc26878b 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -32,7 +32,7 @@ class Atom ContextMenuManager = require './context-menu-manager' @packages = new PackageManager() - @packages.on 'loaded', => @watchThemes() + @subscribe @packages, 'loaded', => @watchThemes() @themes = new ThemeManager() @contextMenu = new ContextMenuManager(@getLoadSettings().devMode) @config = new Config() From 22f2d4c1c57f014c87e88330f5e7bf4683f9eb5c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 10:17:50 -0700 Subject: [PATCH 23/40] Update packageDirPaths on new config instance --- spec/spec-helper.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 51853d666..799c76e7e 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -18,7 +18,6 @@ atom.themes.loadBaseStylesheets() atom.themes.requireStylesheet '../static/jasmine' fixturePackagesPath = path.resolve(__dirname, './fixtures/packages') -config.packageDirPaths.unshift(fixturePackagesPath) keymap.loadBundledKeymaps() [bindingSetsToRestore, bindingSetsByFirstKeystrokeToRestore] = [] @@ -50,6 +49,7 @@ beforeEach -> # reset config before each spec; don't load or save from/to `config.json` window.config = new Config() + window.config.packageDirPaths.unshift(fixturePackagesPath) spyOn(config, 'load') spyOn(config, 'save') config.set "editor.fontFamily", "Courier" From ebe1598a71bee29f463a40a9b8857d217854aa76 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 10:18:02 -0700 Subject: [PATCH 24/40] Correctly passthrough call to deactivatePackages --- src/atom.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atom.coffee b/src/atom.coffee index 7dc26878b..eab55f5c3 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -92,7 +92,7 @@ class Atom setPackageState: (args...) -> @packages.setPackageState(args...) activatePackages: (args...) -> @packages.activatePackages(args...) activatePackage: (args...) -> @packages.activatePackage(args...) - deactivatePackages: (args...) -> @packages.deactivatePackage(args...) + deactivatePackages: (args...) -> @packages.deactivatePackages(args...) deactivatePackage: (args...) -> @packages.deactivatePackage(args...) getActivePackage: (args...) -> @packages.getActivePackage(args...) isPackageActive: (args...) -> @packages.isPackageActive(args...) From 7cae014d09a89d932ad064006f43fe18b0428624 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 10:18:42 -0700 Subject: [PATCH 25/40] :lipstick: Initialize ivars in constructor --- src/package-manager.coffee | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 9fcff1ee3..cc08c6f56 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -7,9 +7,11 @@ path = require 'path' module.exports = class PackageManager _.extend @prototype, EventEmitter - loadedPackages: {} - activePackages: {} - packageStates: {} + + constructor: -> + @loadedPackages = {} + @activePackages = {} + @packageStates = {} getPackageState: (name) -> @packageStates[name] From 0c532b62fff66c17491837d02bc8fe4eed3c75b9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 26 Sep 2013 10:20:17 -0700 Subject: [PATCH 26/40] Reference package states on packages ivar --- spec/atom-spec.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/atom-spec.coffee b/spec/atom-spec.coffee index 2384920df..26ceea45c 100644 --- a/spec/atom-spec.coffee +++ b/spec/atom-spec.coffee @@ -275,8 +275,8 @@ describe "the `atom` global", -> atom.activatePackage('package-with-serialize-error', immediate: true) atom.activatePackage('package-with-serialization', immediate: true) atom.deactivatePackages() - expect(atom.packageStates['package-with-serialize-error']).toBeUndefined() - expect(atom.packageStates['package-with-serialization']).toEqual someNumber: 1 + expect(atom.packages.packageStates['package-with-serialize-error']).toBeUndefined() + expect(atom.packages.packageStates['package-with-serialization']).toEqual someNumber: 1 expect(console.error).toHaveBeenCalled() it "removes the package's grammars", -> From 1e108aa0d1d134b034f3ddde1398f456382f8b9b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Sep 2013 12:14:30 -0700 Subject: [PATCH 27/40] Reference packageStates via atom.packages --- spec/spec-helper.coffee | 2 +- src/window.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 799c76e7e..461217c8f 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -38,7 +38,7 @@ beforeEach -> window.project = new Project(specProjectPath) window.resetTimeouts() - atom.packageStates = {} + atom.packages.packageStates = {} spyOn(atom, 'saveWindowState') syntax.clearGrammarOverrides() syntax.clearProperties() diff --git a/src/window.coffee b/src/window.coffee index 63a21ebe9..323b8bf3e 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -76,7 +76,7 @@ window.unloadEditorWindow = -> windowState.set('syntax', syntax.serialize()) windowState.set('rootView', rootView.serialize()) atom.deactivatePackages() - windowState.set('packageStates', atom.packageStates) + windowState.set('packageStates', atom.packages.packageStates) atom.saveWindowState() rootView.remove() project.destroy() From 1d7861677a9fc5b205a920f0b295e509d58b6d51 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Sep 2013 12:41:55 -0700 Subject: [PATCH 28/40] :memo: doc dimension getter/setter --- src/atom.coffee | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/atom.coffee b/src/atom.coffee index eab55f5c3..aaf5710cc 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -13,6 +13,8 @@ app = remote.require 'app' Subscriber = require './subscriber' # Public: Atom global for dealing with packages, themes, menus, and the window. +# +# An instance of this class is always available as the `atom` global. module.exports = class Atom _.extend @prototype, Subscriber @@ -43,12 +45,26 @@ class Atom getCurrentWindow: -> remote.getCurrentWindow() + # Public: Get the dimensions of this window. + # + # Returns an object with x, y, width, and height keys. getDimensions: -> browserWindow = @getCurrentWindow() [x, y] = browserWindow.getPosition() [width, height] = browserWindow.getSize() {x, y, width, height} + # Public: Set the dimensions of the window. + # + # * dimensions: + # + x: + # The new x coordinate. + # + y: + # The new y coordinate. + # + width: + # The new width. + # + height: + # The new height. setDimensions: ({x, y, width, height}) -> browserWindow = @getCurrentWindow() browserWindow.setSize(width, height) From cad2c9c7af700498b38a7f5295cad8390e817a5c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Sep 2013 12:46:12 -0700 Subject: [PATCH 29/40] :memo: Mention centering behavior --- src/atom.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/atom.coffee b/src/atom.coffee index aaf5710cc..1668b2451 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -56,6 +56,9 @@ class Atom # Public: Set the dimensions of the window. # + # The window will be centered if either the x or y coordinate is not set + # in the dimensions parameter. + # # * dimensions: # + x: # The new x coordinate. @@ -114,7 +117,6 @@ class Atom isPackageActive: (args...) -> @packages.isPackageActive(args...) getActivePackages: (args...) -> @packages.getActivePackages(args...) loadPackages: (args...) -> @packages.loadPackages(args...) - loadPackage: (args...) -> @packages.loadPackage(args...) unloadPackage: (args...) -> @packages.unloadPackage(args...) resolvePackagePath: (args...) -> @packages.resolvePackagePath(args...) From 068a10b2db3c18d1510e15d680bee4e43f966d3d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Sep 2013 13:02:05 -0700 Subject: [PATCH 30/40] Extract deserializer management into class --- spec/deserializer-manager-spec.coffee | 33 ++++++++++++++++++++ spec/window-spec.coffee | 32 ------------------- src/atom.coffee | 2 ++ src/deserializer-manager.coffee | 38 ++++++++++++++++++++++ src/window.coffee | 45 +++++++-------------------- 5 files changed, 84 insertions(+), 66 deletions(-) create mode 100644 spec/deserializer-manager-spec.coffee create mode 100644 src/deserializer-manager.coffee diff --git a/spec/deserializer-manager-spec.coffee b/spec/deserializer-manager-spec.coffee new file mode 100644 index 000000000..84bc4b9d0 --- /dev/null +++ b/spec/deserializer-manager-spec.coffee @@ -0,0 +1,33 @@ +DeserializerManager = require '../src/deserializer-manager' + +describe ".deserialize(state)", -> + deserializer = null + + class Foo + @deserialize: ({name}) -> new Foo(name) + constructor: (@name) -> + + beforeEach -> + deserializer = new DeserializerManager() + deserializer.registerDeserializer(Foo) + + it "calls deserialize on the deserializer for the given state object, or returns undefined if one can't be found", -> + spyOn(console, 'warn') + object = deserializer.deserialize({ deserializer: 'Foo', name: 'Bar' }) + expect(object.name).toBe 'Bar' + expect(deserializer.deserialize({ deserializer: 'Bogus' })).toBeUndefined() + + describe "when the deserializer has a version", -> + beforeEach -> + Foo.version = 2 + + describe "when the deserialized state has a matching version", -> + it "attempts to deserialize the state", -> + object = deserializer.deserialize({ deserializer: 'Foo', version: 2, name: 'Bar' }) + expect(object.name).toBe 'Bar' + + describe "when the deserialized state has a non-matching version", -> + it "returns undefined", -> + expect(deserializer.deserialize({ deserializer: 'Foo', version: 3, name: 'Bar' })).toBeUndefined() + expect(deserializer.deserialize({ deserializer: 'Foo', version: 1, name: 'Bar' })).toBeUndefined() + expect(deserializer.deserialize({ deserializer: 'Foo', name: 'Bar' })).toBeUndefined() diff --git a/spec/window-spec.coffee b/spec/window-spec.coffee index fe00aa17b..187ddcfcf 100644 --- a/spec/window-spec.coffee +++ b/spec/window-spec.coffee @@ -96,38 +96,6 @@ describe "Window", -> expect(buffer.subscriptionCount()).toBe 0 - describe ".deserialize(state)", -> - class Foo - @deserialize: ({name}) -> new Foo(name) - constructor: (@name) -> - - beforeEach -> - registerDeserializer(Foo) - - afterEach -> - unregisterDeserializer(Foo) - - it "calls deserialize on the deserializer for the given state object, or returns undefined if one can't be found", -> - spyOn(console, 'warn') - object = deserialize({ deserializer: 'Foo', name: 'Bar' }) - expect(object.name).toBe 'Bar' - expect(deserialize({ deserializer: 'Bogus' })).toBeUndefined() - - describe "when the deserializer has a version", -> - beforeEach -> - Foo.version = 2 - - describe "when the deserialized state has a matching version", -> - it "attempts to deserialize the state", -> - object = deserialize({ deserializer: 'Foo', version: 2, name: 'Bar' }) - expect(object.name).toBe 'Bar' - - describe "when the deserialized state has a non-matching version", -> - it "returns undefined", -> - expect(deserialize({ deserializer: 'Foo', version: 3, name: 'Bar' })).toBeUndefined() - expect(deserialize({ deserializer: 'Foo', version: 1, name: 'Bar' })).toBeUndefined() - expect(deserialize({ deserializer: 'Foo', name: 'Bar' })).toBeUndefined() - describe "drag and drop", -> buildDragEvent = (type, files) -> dataTransfer = diff --git a/src/atom.coffee b/src/atom.coffee index 1668b2451..74459a619 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -10,6 +10,7 @@ path = require 'path' dialog = remote.require 'dialog' app = remote.require 'app' {Document} = require 'telepath' +DeserializerManager = require './deserializer-manager' Subscriber = require './subscriber' # Public: Atom global for dealing with packages, themes, menus, and the window. @@ -21,6 +22,7 @@ class Atom constructor: -> @rootViewParentSelector = 'body' + @deserializers = new DeserializerManager() initialize: -> @unsubscribe() diff --git a/src/deserializer-manager.coffee b/src/deserializer-manager.coffee new file mode 100644 index 000000000..8fd3bec19 --- /dev/null +++ b/src/deserializer-manager.coffee @@ -0,0 +1,38 @@ +{Document} = require 'telepath' + +module.exports = +class DeserializerManager + constructor: -> + @deserializers = {} + @deferredDeserializers = {} + + registerDeserializer: (klasses...) -> + @deserializers[klass.name] = klass for klass in klasses + + registerDeferredDeserializer: (name, fn) -> + @deferredDeserializers[name] = fn + + unregisterDeserializer: (klasses...) -> + delete @deserializers[klass.name] for klass in klasses + + deserialize: (state, params) -> + return unless state? + + if deserializer = @getDeserializer(state) + stateVersion = state.get?('version') ? state.version + return if deserializer.version? and deserializer.version isnt stateVersion + if (state instanceof Document) and not deserializer.acceptsDocuments + state = state.toObject() + deserializer.deserialize(state, params) + else + console.warn "No deserializer found for", state + + getDeserializer: (state) -> + return unless state? + + name = state.get?('deserializer') ? state.deserializer + if @deferredDeserializers[name] + @deferredDeserializers[name]() + delete @deferredDeserializers[name] + + @deserializers[name] diff --git a/src/window.coffee b/src/window.coffee index 323b8bf3e..738431186 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -7,9 +7,6 @@ remote = require 'remote' ipc = require 'ipc' WindowEventHandler = require './window-event-handler' -deserializers = {} -deferredDeserializers = {} - ### Internal ### windowEventHandler = null @@ -116,37 +113,17 @@ window.onerror = -> atom.openDevTools() window.registerDeserializers = (args...) -> - registerDeserializer(arg) for arg in args - -window.registerDeserializer = (klass) -> - deserializers[klass.name] = klass - -window.registerDeferredDeserializer = (name, fn) -> - deferredDeserializers[name] = fn - -window.unregisterDeserializer = (klass) -> - delete deserializers[klass.name] - -window.deserialize = (state, params) -> - return unless state? - if deserializer = getDeserializer(state) - stateVersion = state.get?('version') ? state.version - return if deserializer.version? and deserializer.version isnt stateVersion - if (state instanceof telepath.Document) and not deserializer.acceptsDocuments - state = state.toObject() - deserializer.deserialize(state, params) - else - console.warn "No deserializer found for", state - -window.getDeserializer = (state) -> - return unless state? - - name = state.get?('deserializer') ? state.deserializer - if deferredDeserializers[name] - deferredDeserializers[name]() - delete deferredDeserializers[name] - - deserializers[name] + atom.deserializers.registerDeserializer(args...) +window.registerDeserializer = (args...) -> + atom.deserializers.registerDeserializer(args...) +window.registerDeferredDeserializer = (args...) -> + atom.deserializers.registerDeferredDeserializer(args...) +window.unregisterDeserializer = (args...) -> + atom.deserializers.unregisterDeserializer(args...) +window.deserialize = (args...) -> + atom.deserializers.deserialize(args...) +window.getDeserializer = (args...) -> + atom.deserializer.getDeserializer(args...) window.requireWithGlobals = (id, globals={}) -> existingGlobals = {} From dc9c59f0b30b347a6898170b397b364f6b26598b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Sep 2013 13:08:19 -0700 Subject: [PATCH 31/40] Add atom prefix to globals --- src/window.coffee | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/window.coffee b/src/window.coffee index 738431186..344ae23c4 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -49,16 +49,16 @@ window.startEditorWindow = -> windowEventHandler = new WindowEventHandler restoreDimensions() - config.load() - keymap.loadBundledKeymaps() + atom.config.load() + atom.keymap.loadBundledKeymaps() atom.themes.loadBaseStylesheets() - atom.loadPackages() - atom.loadThemes() + atom.packages.loadPackages() + atom.themes.load() deserializeEditorWindow() - atom.activatePackages() - keymap.loadUserKeymaps() + atom.packages.activatePackages() + atom.keymap.loadUserKeymaps() atom.requireUserInitScript() - ipc.sendChannel 'update-application-menu', keymap.keystrokesByCommandForSelector('body') + ipc.sendChannel 'update-application-menu', atom.keymap.keystrokesByCommandForSelector('body') $(window).on 'unload', -> $(document.body).hide() unloadEditorWindow() @@ -69,16 +69,15 @@ window.startEditorWindow = -> window.unloadEditorWindow = -> return if not project and not rootView windowState = atom.getWindowState() - windowState.set('project', project.serialize()) - windowState.set('syntax', syntax.serialize()) - windowState.set('rootView', rootView.serialize()) - atom.deactivatePackages() + windowState.set('project', atom.project.serialize()) + windowState.set('syntax', atom.syntax.serialize()) + windowState.set('rootView', atom.rootView.serialize()) + atom.packages.deactivatePackages() windowState.set('packageStates', atom.packages.packageStates) atom.saveWindowState() - rootView.remove() - project.destroy() + atom.rootView.remove() + atom.project.destroy() windowEventHandler?.unsubscribe() - lessCache?.destroy() window.rootView = null window.project = null From 333c5a0db2dff9fd4e4cf498e5ab1522e5a281e4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Sep 2013 13:09:22 -0700 Subject: [PATCH 32/40] Add requireWithGlobals() to atom global --- src/atom.coffee | 14 ++++++++++++++ src/window.coffee | 16 ++-------------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/atom.coffee b/src/atom.coffee index 74459a619..2f8713a10 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -273,3 +273,17 @@ class Atom require userInitScriptPath if fsUtils.isFileSync(userInitScriptPath) catch error console.error "Failed to load `#{userInitScriptPath}`", error.stack, error + + requireWithGlobals: (id, globals={}) -> + existingGlobals = {} + for key, value of globals + existingGlobals[key] = window[key] + window[key] = value + + require(id) + + for key, value of existingGlobals + if value is undefined + delete window[key] + else + window[key] = value diff --git a/src/window.coffee b/src/window.coffee index 344ae23c4..98601fd72 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -123,20 +123,8 @@ window.deserialize = (args...) -> atom.deserializers.deserialize(args...) window.getDeserializer = (args...) -> atom.deserializer.getDeserializer(args...) - -window.requireWithGlobals = (id, globals={}) -> - existingGlobals = {} - for key, value of globals - existingGlobals[key] = window[key] - window[key] = value - - require(id) - - for key, value of existingGlobals - if value is undefined - delete window[key] - else - window[key] = value +window.requireWithGlobals = (args...) -> + atom.requireWithGlobals(args...) window.measure = (description, fn) -> start = new Date().getTime() From 550f112be8ffaa048096aa16b8362c5357a3d328 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Sep 2013 13:12:18 -0700 Subject: [PATCH 33/40] Remove unused requires --- src/window.coffee | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/window.coffee b/src/window.coffee index 98601fd72..5e9e5bfc9 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -1,9 +1,6 @@ -fsUtils = require './fs-utils' path = require 'path' -telepath = require 'telepath' $ = require './jquery-extensions' _ = require './underscore-extensions' -remote = require 'remote' ipc = require 'ipc' WindowEventHandler = require './window-event-handler' From 2a9ceb42b23d21c42b1b84f920f77c73632478af Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Sep 2013 13:12:38 -0700 Subject: [PATCH 34/40] Reference project and rootView using atom global --- src/window.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window.coffee b/src/window.coffee index 5e9e5bfc9..bd7d761ed 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -64,7 +64,7 @@ window.startEditorWindow = -> displayWindow() window.unloadEditorWindow = -> - return if not project and not rootView + return if not atom.project and not atom.rootView windowState = atom.getWindowState() windowState.set('project', atom.project.serialize()) windowState.set('syntax', atom.syntax.serialize()) From c7bc92f6e70e20ff937eb0a26735d5435d1a42c0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Sep 2013 13:33:57 -0700 Subject: [PATCH 35/40] Access rootView through atom global --- src/window-event-handler.coffee | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee index fe3a97820..0460f55be 100644 --- a/src/window-event-handler.coffee +++ b/src/window-event-handler.coffee @@ -1,7 +1,7 @@ $ = require './jquery-extensions' _ = require './underscore-extensions' ipc = require 'ipc' -remote = require 'remote' +shell = require 'shell' Subscriber = require './subscriber' fsUtils = require './fs-utils' @@ -22,10 +22,10 @@ class WindowEventHandler @subscribe $(window), 'focus', -> $("body").removeClass('is-blurred') @subscribe $(window), 'blur', -> $("body").addClass('is-blurred') @subscribe $(window), 'window:open-path', (event, {pathToOpen, initialLine}) -> - rootView?.open(pathToOpen, {initialLine}) unless fsUtils.isDirectorySync(pathToOpen) + atom.rootView?.open(pathToOpen, {initialLine}) unless fsUtils.isDirectorySync(pathToOpen) @subscribe $(window), 'beforeunload', => - confirmed = rootView?.confirmClose() - atom.hide() if confirmed and not @reloadRequested and remote.getCurrentWindow().isWebViewFocused() + confirmed = atom.rootView?.confirmClose() + atom.hide() if confirmed and not @reloadRequested and atom.getCurrentWindow().isWebViewFocused() @reloadRequested = false confirmed @subscribe $(window), 'unload', -> @@ -40,7 +40,7 @@ class WindowEventHandler @subscribeToCommand $(document), 'core:focus-next', @focusNext @subscribeToCommand $(document), 'core:focus-previous', @focusPrevious - @subscribe $(document), 'keydown', keymap.handleKeyEvent + @subscribe $(document), 'keydown', atom.keymap.handleKeyEvent @subscribe $(document), 'drop', onDrop @subscribe $(document), 'dragover', (e) -> @@ -56,7 +56,7 @@ class WindowEventHandler openLink: (event) => location = $(event.target).attr('href') if location and location[0] isnt '#' and /^https?:\/\//.test(location) - require('shell').openExternal(location) + shell.openExternal(location) false eachTabIndexedElement: (callback) -> From dde7ccadd43bed9d8a73481e8a88cdcc186ecab6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Sep 2013 13:40:35 -0700 Subject: [PATCH 36/40] Move onDrop global to WindowEventHandler --- spec/window-spec.coffee | 4 ++-- src/window-event-handler.coffee | 16 +++++++++++++++- src/window.coffee | 6 ------ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/spec/window-spec.coffee b/spec/window-spec.coffee index 187ddcfcf..a536d0ca6 100644 --- a/spec/window-spec.coffee +++ b/spec/window-spec.coffee @@ -114,7 +114,7 @@ describe "Window", -> it "opens it", -> spyOn(atom, "open") event = buildDragEvent("drop", [ {path: "/fake1"}, {path: "/fake2"} ]) - window.onDrop(event) + $(document).trigger(event) expect(atom.open.callCount).toBe 1 expect(atom.open.argsForCall[0][0]).toEqual pathsToOpen: ['/fake1', '/fake2'] @@ -122,7 +122,7 @@ describe "Window", -> it "does nothing", -> spyOn(atom, "open") event = buildDragEvent("drop", []) - window.onDrop(event) + $(document).trigger(event) expect(atom.open).not.toHaveBeenCalled() describe "when a link is clicked", -> diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee index 0460f55be..60e157b6d 100644 --- a/src/window-event-handler.coffee +++ b/src/window-event-handler.coffee @@ -20,29 +20,43 @@ class WindowEventHandler $(atom.contextMenu.activeElement).trigger(command, args...) @subscribe $(window), 'focus', -> $("body").removeClass('is-blurred') + @subscribe $(window), 'blur', -> $("body").addClass('is-blurred') + @subscribe $(window), 'window:open-path', (event, {pathToOpen, initialLine}) -> atom.rootView?.open(pathToOpen, {initialLine}) unless fsUtils.isDirectorySync(pathToOpen) + @subscribe $(window), 'beforeunload', => confirmed = atom.rootView?.confirmClose() atom.hide() if confirmed and not @reloadRequested and atom.getCurrentWindow().isWebViewFocused() @reloadRequested = false confirmed + @subscribe $(window), 'unload', -> atom.getWindowState().set('dimensions', atom.getDimensions()) + @subscribeToCommand $(window), 'window:toggle-full-screen', => atom.toggleFullScreen() + @subscribeToCommand $(window), 'window:close', => atom.close() + @subscribeToCommand $(window), 'window:reload', => @reloadRequested = true atom.reload() + @subscribeToCommand $(window), 'window:toggle-dev-tools', => atom.toggleDevTools() @subscribeToCommand $(document), 'core:focus-next', @focusNext + @subscribeToCommand $(document), 'core:focus-previous', @focusPrevious @subscribe $(document), 'keydown', atom.keymap.handleKeyEvent - @subscribe $(document), 'drop', onDrop + @subscribe $(document), 'drop', (e) -> + e.preventDefault() + e.stopPropagation() + pathsToOpen = _.pluck(e.originalEvent.dataTransfer.files, 'path') + atom.open({pathsToOpen}) if pathsToOpen.length > 0 + @subscribe $(document), 'dragover', (e) -> e.preventDefault() e.stopPropagation() diff --git a/src/window.coffee b/src/window.coffee index bd7d761ed..f54d8fd44 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -86,12 +86,6 @@ installApmCommand = (callback) -> commandPath = path.join(window.resourcePath, 'node_modules', '.bin', 'apm') require('./command-installer').install(commandPath, callback) -window.onDrop = (e) -> - e.preventDefault() - e.stopPropagation() - pathsToOpen = _.pluck(e.originalEvent.dataTransfer.files, 'path') - atom.open({pathsToOpen}) if pathsToOpen.length > 0 - window.deserializeEditorWindow = -> atom.deserializePackageStates() atom.deserializeProject() From 022db0fc44e9f05bc204a7cc302a1c3c1ac372e7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Sep 2013 13:45:27 -0700 Subject: [PATCH 37/40] Access keymap via atom global --- src/window.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/window.coffee b/src/window.coffee index f54d8fd44..72c29d1ec 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -36,8 +36,8 @@ window.setUpEnvironment = (windowMode) -> # This should only be called after setUpEnvironment() has been called. window.setUpDefaultEvents = -> windowEventHandler = new WindowEventHandler - keymap.loadBundledKeymaps() - ipc.sendChannel 'update-application-menu', keymap.keystrokesByCommandForSelector('body') + atom.keymap.loadBundledKeymaps() + ipc.sendChannel 'update-application-menu', atom.keymap.keystrokesByCommandForSelector('body') # This method is only called when opening a real application window window.startEditorWindow = -> From 63b79a1d045fadac0c65a93f7e1b2aa5c4790b8d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 1 Oct 2013 15:42:28 -0700 Subject: [PATCH 38/40] Bring back userPackageDirPaths for backwards-compatibility --- src/config.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/config.coffee b/src/config.coffee index ae7901177..1b2466381 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -47,6 +47,7 @@ class Config @packageDirPaths = [path.join(configDirPath, "packages")] if atom.getLoadSettings().devMode @packageDirPaths.unshift(path.join(configDirPath, "dev", "packages")) + @userPackageDirPaths = _.clone(@packageDirPaths) @userStoragePath = path.join(configDirPath, "storage") @defaultSettings = From a85817369e34b1d599e54c49b2eb87ce4b4802f1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 1 Oct 2013 15:58:39 -0700 Subject: [PATCH 39/40] Add shim for packages accessing atom.packageStates --- src/atom.coffee | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/atom.coffee b/src/atom.coffee index 2f8713a10..3206081c3 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -36,6 +36,11 @@ class Atom ContextMenuManager = require './context-menu-manager' @packages = new PackageManager() + + #TODO Remove once packages have been updated to not touch atom.packageStates directly + @__defineGetter__ 'packageStates', => @packages.packageStates + @__defineSetter__ 'packageStates', (packageStates) => @packages.packageStates = packageStates + @subscribe @packages, 'loaded', => @watchThemes() @themes = new ThemeManager() @contextMenu = new ContextMenuManager(@getLoadSettings().devMode) From 3591b921fd37d900c5916f8b882433df4ce2b0df Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 1 Oct 2013 16:11:08 -0700 Subject: [PATCH 40/40] Update atom and window globals in beforEach --- spec/spec-helper.coffee | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 461217c8f..38db81e8c 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -18,7 +18,7 @@ atom.themes.loadBaseStylesheets() atom.themes.requireStylesheet '../static/jasmine' fixturePackagesPath = path.resolve(__dirname, './fixtures/packages') -keymap.loadBundledKeymaps() +atom.keymap.loadBundledKeymaps() [bindingSetsToRestore, bindingSetsByFirstKeystrokeToRestore] = [] $(window).on 'core:close', -> window.close() @@ -35,21 +35,22 @@ specProjectPath = path.join(specDirectory, 'fixtures') beforeEach -> $.fx.off = true - window.project = new Project(specProjectPath) + atom.project = new Project(specProjectPath) + window.project = atom.project window.resetTimeouts() atom.packages.packageStates = {} spyOn(atom, 'saveWindowState') - syntax.clearGrammarOverrides() - syntax.clearProperties() + atom.syntax.clearGrammarOverrides() + atom.syntax.clearProperties() # used to reset keymap after each spec bindingSetsToRestore = _.clone(keymap.bindingSets) bindingSetsByFirstKeystrokeToRestore = _.clone(keymap.bindingSetsByFirstKeystroke) # reset config before each spec; don't load or save from/to `config.json` - window.config = new Config() - window.config.packageDirPaths.unshift(fixturePackagesPath) + config = new Config() + config.packageDirPaths.unshift(fixturePackagesPath) spyOn(config, 'load') spyOn(config, 'save') config.set "editor.fontFamily", "Courier" @@ -57,6 +58,8 @@ beforeEach -> config.set "editor.autoIndent", false config.set "core.disabledPackages", ["package-that-throws-an-exception"] config.save.reset() + atom.config = config + window.config = config # make editor display updates synchronous spyOn(Editor.prototype, 'requestDisplayUpdate').andCallFake -> @updateDisplay()