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/atom-spec.coffee b/spec/atom-spec.coffee index a5643443e..26ceea45c 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", -> @@ -298,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", -> @@ -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/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/spec-bootstrap.coffee b/spec/spec-bootstrap.coffee index 97a4d8471..d4df9c3cd 100644 --- a/spec/spec-bootstrap.coffee +++ b/spec/spec-bootstrap.coffee @@ -1,7 +1,8 @@ try - require '../src/atom' require '../src/window' - atom.show() + Atom = require '../src/atom' + window.atom = new Atom() + window.atom.show() {runSpecSuite} = require './jasmine-helper' document.title = "Spec Suite" diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 74155a915..38db81e8c 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -14,12 +14,11 @@ 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) -keymap.loadBundledKeymaps() +atom.keymap.loadBundledKeymaps() [bindingSetsToRestore, bindingSetsByFirstKeystrokeToRestore] = [] $(window).on 'core:close', -> window.close() @@ -36,20 +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.packageStates = {} + 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() + 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() 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..a536d0ca6 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() @@ -156,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 = @@ -206,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'] @@ -214,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/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..3206081c3 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -10,155 +10,140 @@ path = require 'path' dialog = remote.require 'dialog' app = remote.require 'app' {Document} = require 'telepath' -ThemeManager = require './theme-manager' -ContextMenuManager = require './context-menu-manager' +DeserializerManager = require './deserializer-manager' +Subscriber = require './subscriber' -window.atom = - loadedPackages: {} - activePackages: {} - packageStates: {} - themes: new ThemeManager() - contextMenu: new ContextMenuManager(remote.getCurrentWindow().loadSettings.devMode) +# 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 - getLoadSettings: -> - @getCurrentWindow().loadSettings + constructor: -> + @rootViewParentSelector = 'body' + @deserializers = new DeserializerManager() + + 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() + + #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) + @config = new Config() + @pasteboard = new Pasteboard() + @keymap = new Keymap() + @syntax = deserialize(@getWindowState('syntax')) ? new Syntax() getCurrentWindow: -> remote.getCurrentWindow() - getPackageState: (name) -> - @packageStates[name] + # 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} - 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] + # 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. + # + y: + # The new y coordinate. + # + width: + # The new width. + # + height: + # The new height. + setDimensions: ({x, y, width, height}) -> + browserWindow = @getCurrentWindow() + browserWindow.setSize(width, height) + if x? and y? + browserWindow.setPosition(x, y) else - throw new Error("No active package for name '#{name}'") + browserWindow.center() - getActivePackage: (name) -> - @activePackages[name] + restoreDimensions: (defaultDimensions={width: 800, height: 600})-> + dimensions = @getWindowState().getObject('dimensions') + dimensions = defaultDimensions unless dimensions?.width and dimensions?.height + @setDimensions(dimensions) - isPackageActive: (name) -> - @getActivePackage(name)? + getLoadSettings: -> + @getCurrentWindow().loadSettings - getActivePackages: -> - _.values(@activePackages) + deserializeProject: -> + Project = require './project' + state = @getWindowState() + @project = deserialize(state.get('project')) + unless @project? + @project = new Project(@getLoadSettings().initialPath) + state.set('project', @project.getState()) - 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' + 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) - @loadPackage(name) for name in @getAvailablePackageNames() when not @isPackageDisabled(name) - @watchThemes() + deserializePackageStates: -> + state = @getWindowState() + @packages.packageStates = state.getObject('packageStates') ? {} + state.remove('packageStates') - 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.deactivatePackages(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() watchThemes: -> @themes.on 'reloaded', => - @reloadBaseStylesheets() - pack.reloadStylesheets?() for name, pack of @loadedPackages + pack.reloadStylesheets?() for name, pack of @getLoadedPackages() 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) @@ -210,8 +195,7 @@ window.atom = close: -> @getCurrentWindow().close() - exit: (status) -> - app.exit(status) + exit: (status) -> app.exit(status) toggleFullScreen: -> @setFullScreen(!@isFullScreen()) @@ -236,7 +220,7 @@ window.atom = filename = "editor-#{sha1}" if filename - path.join(config.userStoragePath, filename) + path.join(@config.userStoragePath, filename) else null @@ -289,8 +273,22 @@ window.atom = 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 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/config.coffee b/src/config.coffee index ffcd24809..1b2466381 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,26 @@ 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")) + @userPackageDirPaths = _.clone(@packageDirPaths) + @userStoragePath = path.join(configDirPath, "storage") + @defaultSettings = core: _.clone(require('./root-view').configDefaults) editor: _.clone(require('./editor').configDefaults) 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/package-manager.coffee b/src/package-manager.coffee new file mode 100644 index 000000000..cc08c6f56 --- /dev/null +++ b/src/package-manager.coffee @@ -0,0 +1,129 @@ +EventEmitter = require './event-emitter' +fsUtils = require './fs-utils' +_ = require './underscore-extensions' +Package = require './package' +path = require 'path' + +module.exports = +class PackageManager + _.extend @prototype, EventEmitter + + constructor: -> + @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) + @trigger 'loaded' + + 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 + atom.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 diff --git a/src/theme-manager.coffee b/src/theme-manager.coffee index 5ae6ff6f7..3c4b71e48 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. @@ -15,6 +15,7 @@ class ThemeManager constructor: -> @loadedThemes = [] @activeThemes = [] + @lessCache = null # Internal-only: register: (theme) -> @@ -33,9 +34,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 +127,7 @@ class ThemeManager @activateTheme(themeName) for themeName in themeNames @loadUserStylesheet() - + @reloadBaseStylesheets() @trigger('reloaded') # Private: @@ -118,5 +195,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-bootstrap.coffee b/src/window-bootstrap.coffee index bccf2ee92..15da3237e 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' require './window' +Atom = require './atom' +window.atom = new Atom() window.setUpEnvironment('editor') window.startEditorWindow() console.log "Window load time: #{new Date().getTime() - startTime}ms" diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee index 33b6f2cd5..60e157b6d 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' @@ -20,27 +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}) -> - 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', -> + 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', keymap.handleKeyEvent + @subscribe $(document), 'keydown', atom.keymap.handleKeyEvent + + @subscribe $(document), 'drop', (e) -> + e.preventDefault() + e.stopPropagation() + pathsToOpen = _.pluck(e.originalEvent.dataTransfer.files, 'path') + atom.open({pathsToOpen}) if pathsToOpen.length > 0 - @subscribe $(document), 'drop', onDrop @subscribe $(document), 'dragover', (e) -> e.preventDefault() e.stopPropagation() @@ -54,7 +70,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) -> diff --git a/src/window.coffee b/src/window.coffee index 337a3704b..72c29d1ec 100644 --- a/src/window.coffee +++ b/src/window.coffee @@ -1,17 +1,9 @@ -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' -deserializers = {} -deferredDeserializers = {} -defaultWindowDimensions = {width: 800, height: 600} -lessCache = null - ### Internal ### windowEventHandler = null @@ -28,19 +20,13 @@ 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 - - Config = require './config' - Syntax = require './syntax' - Pasteboard = require './pasteboard' - Keymap = require './keymap' - - window.rootViewParentSelector = 'body' - window.config = new Config - window.syntax = deserialize(atom.getWindowState('syntax')) ? new Syntax - window.pasteboard = new Pasteboard - window.keymap = new Keymap() - + 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 + window.keymap = atom.keymap # Set up the default event handlers and menus for a non-editor windows. # @@ -50,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 = -> @@ -60,16 +46,16 @@ window.startEditorWindow = -> windowEventHandler = new WindowEventHandler restoreDimensions() - config.load() - keymap.loadBundledKeymaps() - atom.loadBaseStylesheets() - atom.loadPackages() - atom.loadThemes() + atom.config.load() + atom.keymap.loadBundledKeymaps() + atom.themes.loadBaseStylesheets() + 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() @@ -78,188 +64,58 @@ 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', project.serialize()) - windowState.set('syntax', syntax.serialize()) - windowState.set('rootView', rootView.serialize()) - atom.deactivatePackages() - windowState.set('packageStates', atom.packageStates) + 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 -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) -window.onDrop = (e) -> - e.preventDefault() - e.stopPropagation() - pathsToOpen = _.pluck(e.originalEvent.dataTransfer.files, 'path') - atom.open({pathsToOpen}) if pathsToOpen.length > 0 - window.deserializeEditorWindow = -> - RootView = require './root-view' - Project = require './project' + atom.deserializePackageStates() + atom.deserializeProject() + window.project = atom.project + atom.deserializeRootView() + window.rootView = atom.rootView - windowState = atom.getWindowState() +window.getDimensions = -> atom.getDimensions() - atom.packageStates = windowState.getObject('packageStates') ? {} - windowState.remove('packageStates') +window.setDimensions = (args...) -> atom.setDimensions(args...) - 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 - -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() - [width, height] = browserWindow.getSize() - {x, y, width, height} - -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.restoreDimensions = (args...) -> atom.restoreDimensions(args...) 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] - -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 + 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 = (args...) -> + atom.requireWithGlobals(args...) window.measure = (description, fn) -> start = new Date().getTime()