From 288abbc57b85c8379449feec9e55ffeb9ade7785 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 13 Nov 2015 10:51:31 +0100 Subject: [PATCH 001/137] Add OS X dock menu with 'New Window' option --- src/browser/atom-application.coffee | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 8bb44349e..56c4ea216 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -82,6 +82,7 @@ class AtomApplication @listenForArgumentsFromNewProcess() @setupJavaScriptArguments() @handleEvents() + @setupDockMenu() @storageFolder = new StorageFolder(process.env.ATOM_HOME) if options.pathsToOpen?.length > 0 or options.urlsToOpen?.length > 0 or options.test @@ -280,6 +281,13 @@ class AtomApplication ipc.on 'write-to-stderr', (event, output) -> process.stderr.write(output) + setupDockMenu: -> + if process.platform is 'darwin' + dockMenu = Menu.buildFromTemplate [ + {label: 'New Window', click: => @emit('application:new-window')} + ] + app.dock.setMenu dockMenu + # Public: Executes the given command. # # If it isn't handled globally, delegate to the currently focused window. From c8843b1b56e6bc61a483a0f99286981f657ca828 Mon Sep 17 00:00:00 2001 From: Wliu Date: Tue, 17 Nov 2015 22:58:55 -0500 Subject: [PATCH 002/137] :checkered_flag: Add --no-shortcut flag to disable creating a desktop shortcut --- build/Gruntfile.coffee | 3 ++- build/tasks/install-task.coffee | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index 8dd1c573b..cb6ff0c1e 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -37,6 +37,7 @@ module.exports = (grunt) -> buildDir ?= path.join(os.tmpdir(), 'atom-build') buildDir = path.resolve(buildDir) disableAutoUpdate = grunt.option('no-auto-update') ? false + disableShortcut = grunt.option('no-shortcut') ? false channel = grunt.option('channel') releasableBranches = ['stable', 'beta'] @@ -179,7 +180,7 @@ module.exports = (grunt) -> pkg: grunt.file.readJSON('package.json') atom: { - appName, channel, metadata, disableAutoUpdate, + appName, channel, metadata, disableAutoUpdate, disableShortcut, appFileName, apmFileName, appDir, buildDir, contentsDir, installDir, shellAppDir, symbolsDir, } diff --git a/build/tasks/install-task.coffee b/build/tasks/install-task.coffee index 54fd06022..ee38b1582 100644 --- a/build/tasks/install-task.coffee +++ b/build/tasks/install-task.coffee @@ -21,8 +21,9 @@ module.exports = (grunt) -> if runas('cmd', ['/c', copyFolder, shellAppDir, installDir], admin: true) isnt 0 grunt.log.error("Failed to copy #{shellAppDir} to #{installDir}") - createShortcut = path.resolve 'script', 'create-shortcut.cmd' - runas('cmd', ['/c', createShortcut, path.join(installDir, 'atom.exe'), appName]) + unless grunt.config.get('atom.disableShortcut') + createShortcut = path.resolve 'script', 'create-shortcut.cmd' + runas('cmd', ['/c', createShortcut, path.join(installDir, 'atom.exe'), appName]) else if process.platform is 'darwin' rm installDir mkdir path.dirname(installDir) From b4de9c6e871a0b52fa1053ff5ceca88e51e61507 Mon Sep 17 00:00:00 2001 From: Wliu Date: Tue, 17 Nov 2015 23:00:58 -0500 Subject: [PATCH 003/137] :memo: Document --no-shortcut --- docs/build-instructions/windows.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/build-instructions/windows.md b/docs/build-instructions/windows.md index debdd6570..fa7c32148 100644 --- a/docs/build-instructions/windows.md +++ b/docs/build-instructions/windows.md @@ -34,6 +34,7 @@ These instructions will assume the use of Git Shell. * `--install-dir` - Creates the final built application in this directory. * `--build-dir` - Build the application in this directory. * `--verbose` - Verbose mode. A lot more information output. + * `--no-shortcut` - Don't create a desktop shortcut. ## Why do I have to use GitHub Desktop? From ade1ef7a4cd275edd81e4ae3a58948891a7e16ef Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 18 Nov 2015 13:59:17 -0800 Subject: [PATCH 004/137] Load deserializers from files specified in package.json --- .../packages/package-with-deserializers/package.json | 7 +++++++ .../package-with-deserializers/the-deserializer.js | 6 ++++++ spec/package-manager-spec.coffee | 10 ++++++++++ src/package.coffee | 7 +++++++ 4 files changed, 30 insertions(+) create mode 100644 spec/fixtures/packages/package-with-deserializers/package.json create mode 100644 spec/fixtures/packages/package-with-deserializers/the-deserializer.js diff --git a/spec/fixtures/packages/package-with-deserializers/package.json b/spec/fixtures/packages/package-with-deserializers/package.json new file mode 100644 index 000000000..867457e0a --- /dev/null +++ b/spec/fixtures/packages/package-with-deserializers/package.json @@ -0,0 +1,7 @@ +{ + "name": "package-with-deserializers", + "version": "1.0.0", + "atom-deserializers": { + "TheDeserializerName": "./the-deserializer.js" + } +} diff --git a/spec/fixtures/packages/package-with-deserializers/the-deserializer.js b/spec/fixtures/packages/package-with-deserializers/the-deserializer.js new file mode 100644 index 000000000..d70e62bfd --- /dev/null +++ b/spec/fixtures/packages/package-with-deserializers/the-deserializer.js @@ -0,0 +1,6 @@ +module.exports = function (state) { + return { + wasDeserializedBy: 'TheDeserializer', + state: state + } +} diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 4b5f3c26d..59e076834 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -79,6 +79,16 @@ describe "PackageManager", -> expect(loadedPackage.name).toBe "package-with-main" + it "registers any deserializers specified in the package's package.json", -> + atom.packages.loadPackage("package-with-deserializers") + + state = {deserializer: 'TheDeserializerName', a: 'b'} + + expect(atom.deserializers.deserialize(state)).toEqual { + wasDeserializedBy: 'TheDeserializer' + state: state + } + describe "::unloadPackage(name)", -> describe "when the package is active", -> it "throws an error", -> diff --git a/src/package.coffee b/src/package.coffee index 4cd6a18fd..b40cabac3 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -84,6 +84,7 @@ class Package @loadKeymaps() @loadMenus() @loadStylesheets() + @loadDeserializers() @settingsPromise = @loadSettings() @requireMainModule() unless @mainModule? or @activationShouldBeDeferred() catch error @@ -253,6 +254,12 @@ class Package @stylesheets = @getStylesheetPaths().map (stylesheetPath) => [stylesheetPath, @themeManager.loadStylesheet(stylesheetPath, true)] + loadDeserializers: -> + for name, implementationPath of @metadata['atom-deserializers'] + deserialize = require(path.join(@path, implementationPath)) + atom.deserializers.add({name, deserialize}) + return + getStylesheetsPath: -> path.join(@path, 'styles') From 46272cd1927aac453a69397ffa6675c506ba3ac8 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 18 Nov 2015 14:31:16 -0800 Subject: [PATCH 005/137] Load deserializers lazily --- .../{the-deserializer.js => deserializer-1.js} | 2 +- .../package-with-deserializers/deserializer-2.js | 6 ++++++ .../package-with-deserializers/package.json | 3 ++- spec/package-manager-spec.coffee | 13 +++++++++---- src/package.coffee | 10 ++++++++-- 5 files changed, 26 insertions(+), 8 deletions(-) rename spec/fixtures/packages/package-with-deserializers/{the-deserializer.js => deserializer-1.js} (62%) create mode 100644 spec/fixtures/packages/package-with-deserializers/deserializer-2.js diff --git a/spec/fixtures/packages/package-with-deserializers/the-deserializer.js b/spec/fixtures/packages/package-with-deserializers/deserializer-1.js similarity index 62% rename from spec/fixtures/packages/package-with-deserializers/the-deserializer.js rename to spec/fixtures/packages/package-with-deserializers/deserializer-1.js index d70e62bfd..f4d7a1488 100644 --- a/spec/fixtures/packages/package-with-deserializers/the-deserializer.js +++ b/spec/fixtures/packages/package-with-deserializers/deserializer-1.js @@ -1,6 +1,6 @@ module.exports = function (state) { return { - wasDeserializedBy: 'TheDeserializer', + wasDeserializedBy: 'Deserializer1', state: state } } diff --git a/spec/fixtures/packages/package-with-deserializers/deserializer-2.js b/spec/fixtures/packages/package-with-deserializers/deserializer-2.js new file mode 100644 index 000000000..3099d2b15 --- /dev/null +++ b/spec/fixtures/packages/package-with-deserializers/deserializer-2.js @@ -0,0 +1,6 @@ +module.exports = function (state) { + return { + wasDeserializedBy: 'Deserializer2', + state: state + } +} diff --git a/spec/fixtures/packages/package-with-deserializers/package.json b/spec/fixtures/packages/package-with-deserializers/package.json index 867457e0a..377a5faf8 100644 --- a/spec/fixtures/packages/package-with-deserializers/package.json +++ b/spec/fixtures/packages/package-with-deserializers/package.json @@ -2,6 +2,7 @@ "name": "package-with-deserializers", "version": "1.0.0", "atom-deserializers": { - "TheDeserializerName": "./the-deserializer.js" + "Deserializer1": "./deserializer-1.js", + "Deserializer2": "./deserializer-2.js" } } diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 59e076834..843e9a932 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -82,11 +82,16 @@ describe "PackageManager", -> it "registers any deserializers specified in the package's package.json", -> atom.packages.loadPackage("package-with-deserializers") - state = {deserializer: 'TheDeserializerName', a: 'b'} + state1 = {deserializer: 'Deserializer1', a: 'b'} + expect(atom.deserializers.deserialize(state1)).toEqual { + wasDeserializedBy: 'Deserializer1' + state: state1 + } - expect(atom.deserializers.deserialize(state)).toEqual { - wasDeserializedBy: 'TheDeserializer' - state: state + state2 = {deserializer: 'Deserializer2', c: 'd'} + expect(atom.deserializers.deserialize(state2)).toEqual { + wasDeserializedBy: 'Deserializer2' + state: state2 } describe "::unloadPackage(name)", -> diff --git a/src/package.coffee b/src/package.coffee index b40cabac3..f933f93c3 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -256,8 +256,14 @@ class Package loadDeserializers: -> for name, implementationPath of @metadata['atom-deserializers'] - deserialize = require(path.join(@path, implementationPath)) - atom.deserializers.add({name, deserialize}) + do => + deserializePath = path.join(@path, implementationPath) + deserializeFunction = null + atom.deserializers.add + name: name, + deserialize: -> + deserializeFunction ?= require(deserializePath) + deserializeFunction.apply(this, arguments) return getStylesheetsPath: -> From a0a402c3f89be74fa90569f591a46708c41a6258 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 19 Nov 2015 14:12:03 -0800 Subject: [PATCH 006/137] Remove 'atom' prefix from deserializers package.json key --- spec/fixtures/packages/package-with-deserializers/package.json | 2 +- src/package.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/fixtures/packages/package-with-deserializers/package.json b/spec/fixtures/packages/package-with-deserializers/package.json index 377a5faf8..c55e1444a 100644 --- a/spec/fixtures/packages/package-with-deserializers/package.json +++ b/spec/fixtures/packages/package-with-deserializers/package.json @@ -1,7 +1,7 @@ { "name": "package-with-deserializers", "version": "1.0.0", - "atom-deserializers": { + "deserializers": { "Deserializer1": "./deserializer-1.js", "Deserializer2": "./deserializer-2.js" } diff --git a/src/package.coffee b/src/package.coffee index f933f93c3..a49c70868 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -255,7 +255,7 @@ class Package [stylesheetPath, @themeManager.loadStylesheet(stylesheetPath, true)] loadDeserializers: -> - for name, implementationPath of @metadata['atom-deserializers'] + for name, implementationPath of @metadata.deserializers do => deserializePath = path.join(@path, implementationPath) deserializeFunction = null From 91b651e86c52f48ed2911158369ea8b434ec987c Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 19 Nov 2015 15:54:47 -0800 Subject: [PATCH 007/137] Make model constructor argument to addViewProvider optional --- spec/view-registry-spec.coffee | 15 ++++++++ src/view-registry.coffee | 66 ++++++++++++++++++++++------------ 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/spec/view-registry-spec.coffee b/spec/view-registry-spec.coffee index a2b4965a5..16672b25d 100644 --- a/spec/view-registry-spec.coffee +++ b/spec/view-registry-spec.coffee @@ -47,6 +47,21 @@ describe "ViewRegistry", -> expect(view2 instanceof TestView).toBe true expect(view2.model).toBe subclassModel + describe "when a view provider is registered generically, and works with the object", -> + it "constructs a view element and assigns the model on it", -> + model = {a: 'b'} + + registry.addViewProvider (model) -> + if model.a is 'b' + element = document.createElement('div') + element.className = 'test-element' + element + + view = registry.getView({a: 'b'}) + expect(view.className).toBe 'test-element' + + expect(-> registry.getView({a: 'c'})).toThrow() + describe "when no view provider is registered for the object's constructor", -> it "throws an exception", -> expect(-> registry.getView(new Object)).toThrow() diff --git a/src/view-registry.coffee b/src/view-registry.coffee index 0f07600ae..e754a010b 100644 --- a/src/view-registry.coffee +++ b/src/view-registry.coffee @@ -3,6 +3,8 @@ Grim = require 'grim' {Disposable} = require 'event-kit' _ = require 'underscore-plus' +AnyConstructor = Symbol('any-constructor') + # Essential: `ViewRegistry` handles the association between model and view # types in Atom. We call this association a View Provider. As in, for a given # model, this class can provide a view via {::getView}, as long as the @@ -76,16 +78,27 @@ class ViewRegistry # textEditorElement # ``` # - # * `modelConstructor` Constructor {Function} for your model. + # * `modelConstructor` (optional) Constructor {Function} for your model. If + # a constructor is given, the `createView` function will only be used + # for model objects inheriting from that constructor. Otherwise, it will + # will be called for any object. # * `createView` Factory {Function} that is passed an instance of your model - # and must return a subclass of `HTMLElement` or `undefined`. + # and must return a subclass of `HTMLElement` or `undefined`. If it returns + # `undefined`, then the registry will continue to search for other view + # providers. # # Returns a {Disposable} on which `.dispose()` can be called to remove the # added provider. addViewProvider: (modelConstructor, createView) -> if arguments.length is 1 - Grim.deprecate("atom.views.addViewProvider now takes 2 arguments: a model constructor and a createView function. See docs for details.") - provider = modelConstructor + switch typeof modelConstructor + when 'function' + provider = {createView: modelConstructor, modelConstructor: AnyConstructor} + when 'object' + Grim.deprecate("atom.views.addViewProvider now takes 2 arguments: a model constructor and a createView function. See docs for details.") + provider = modelConstructor + else + throw new TypeError("Arguments to addViewProvider must be functions") else provider = {modelConstructor, createView} @@ -153,25 +166,34 @@ class ViewRegistry createView: (object) -> if object instanceof HTMLElement - object - else if object?.element instanceof HTMLElement - object.element - else if object?.jquery - object[0] - else if provider = @findProvider(object) - element = provider.createView?(object, @atomEnvironment) - unless element? - element = new provider.viewConstructor - element.initialize?(object) ? element.setModel?(object) - element - else if viewConstructor = object?.getViewClass?() - view = new viewConstructor(object) - view[0] - else - throw new Error("Can't create a view for #{object.constructor.name} instance. Please register a view provider.") + return object - findProvider: (object) -> - find @providers, ({modelConstructor}) -> object instanceof modelConstructor + if object?.element instanceof HTMLElement + return object.element + + if object?.jquery + return object[0] + + for provider in @providers + if provider.modelConstructor is AnyConstructor + if element = provider.createView(object, @atomEnvironment) + return element + continue + + if object instanceof provider.modelConstructor + if element = provider.createView?(object, @atomEnvironment) + return element + + if viewConstructor = provider.viewConstructor + element = new viewConstructor + element.initialize?(object) ? element.setModel?(object) + return element + + if viewConstructor = object?.getViewClass?() + view = new viewConstructor(object) + return view[0] + + throw new Error("Can't create a view for #{object.constructor.name} instance. Please register a view provider.") updateDocument: (fn) -> @documentWriters.push(fn) From cb2b068d779a7e182c50e0f9ed47998e46f0f992 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 19 Nov 2015 16:58:08 -0800 Subject: [PATCH 008/137] Load view providers from files specified in package.json --- .../package-with-view-providers/package.json | 8 ++++++++ .../package-with-view-providers/view-provider-1.js | 9 +++++++++ .../package-with-view-providers/view-provider-2.js | 9 +++++++++ spec/package-manager-spec.coffee | 13 +++++++++++++ spec/package-spec.coffee | 1 + src/atom-environment.coffee | 2 +- src/package-manager.coffee | 6 ++++-- src/package.coffee | 8 +++++++- 8 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 spec/fixtures/packages/package-with-view-providers/package.json create mode 100644 spec/fixtures/packages/package-with-view-providers/view-provider-1.js create mode 100644 spec/fixtures/packages/package-with-view-providers/view-provider-2.js diff --git a/spec/fixtures/packages/package-with-view-providers/package.json b/spec/fixtures/packages/package-with-view-providers/package.json new file mode 100644 index 000000000..7f7405c32 --- /dev/null +++ b/spec/fixtures/packages/package-with-view-providers/package.json @@ -0,0 +1,8 @@ +{ + "name": "package-with-view-providers", + "version": "1.0.0", + "viewProviders": [ + "./view-provider-1", + "./view-provider-2" + ] +} diff --git a/spec/fixtures/packages/package-with-view-providers/view-provider-1.js b/spec/fixtures/packages/package-with-view-providers/view-provider-1.js new file mode 100644 index 000000000..e4f0dcc0b --- /dev/null +++ b/spec/fixtures/packages/package-with-view-providers/view-provider-1.js @@ -0,0 +1,9 @@ +'use strict' + +module.exports = function (model) { + if (model.worksWithViewProvider1) { + let element = document.createElement('div') + element.dataset['createdBy'] = 'view-provider-1' + return element + } +} diff --git a/spec/fixtures/packages/package-with-view-providers/view-provider-2.js b/spec/fixtures/packages/package-with-view-providers/view-provider-2.js new file mode 100644 index 000000000..a3b58a3aa --- /dev/null +++ b/spec/fixtures/packages/package-with-view-providers/view-provider-2.js @@ -0,0 +1,9 @@ +'use strict' + +module.exports = function (model) { + if (model.worksWithViewProvider2) { + let element = document.createElement('div') + element.dataset['createdBy'] = 'view-provider-2' + return element + } +} diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 843e9a932..169e09b76 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -94,6 +94,19 @@ describe "PackageManager", -> state: state2 } + it "registers any view providers specified in the package's package.json", -> + atom.packages.loadPackage("package-with-view-providers") + + model1 = {worksWithViewProvider1: true} + element1 = atom.views.getView(model1) + expect(element1 instanceof HTMLDivElement).toBe true + expect(element1.dataset.createdBy).toBe 'view-provider-1' + + model2 = {worksWithViewProvider2: true} + element2 = atom.views.getView(model2) + expect(element2 instanceof HTMLDivElement).toBe true + expect(element2.dataset.createdBy).toBe 'view-provider-2' + describe "::unloadPackage(name)", -> describe "when the package is active", -> it "throws an error", -> diff --git a/spec/package-spec.coffee b/spec/package-spec.coffee index 63a80a7db..f49d2ed7c 100644 --- a/spec/package-spec.coffee +++ b/spec/package-spec.coffee @@ -10,6 +10,7 @@ describe "Package", -> keymapManager: atom.keymaps, commandRegistry: atom.command, grammarRegistry: atom.grammars, themeManager: atom.themes, menuManager: atom.menu, contextMenuManager: atom.contextMenu, + deserializerManager: atom.deserializers, viewRegistry: atom.views, devMode: false ) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index ac76daf04..c56bcb493 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -151,7 +151,7 @@ class AtomEnvironment extends Model @packages = new PackageManager({ devMode, configDirPath, resourcePath, safeMode, @config, styleManager: @styles, commandRegistry: @commands, keymapManager: @keymaps, notificationManager: @notifications, - grammarRegistry: @grammars + grammarRegistry: @grammars, deserializerManager: @deserializers, viewRegistry: @views }) @themes = new ThemeManager({ diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 789b2eae5..5b0264212 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -31,7 +31,8 @@ class PackageManager constructor: (params) -> { configDirPath, @devMode, safeMode, @resourcePath, @config, @styleManager, - @notificationManager, @keymapManager, @commandRegistry, @grammarRegistry + @notificationManager, @keymapManager, @commandRegistry, @grammarRegistry, + @deserializerManager, @viewRegistry } = params @emitter = new Emitter @@ -375,7 +376,8 @@ class PackageManager options = { path: packagePath, metadata, packageManager: this, @config, @styleManager, @commandRegistry, @keymapManager, @devMode, @notificationManager, - @grammarRegistry, @themeManager, @menuManager, @contextMenuManager + @grammarRegistry, @themeManager, @menuManager, @contextMenuManager, + @deserializerManager, @viewRegistry } if metadata.theme pack = new ThemePackage(options) diff --git a/src/package.coffee b/src/package.coffee index a49c70868..1d98c8161 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -33,7 +33,7 @@ class Package { @path, @metadata, @packageManager, @config, @styleManager, @commandRegistry, @keymapManager, @devMode, @notificationManager, @grammarRegistry, @themeManager, - @menuManager, @contextMenuManager + @menuManager, @contextMenuManager, @deserializerManager, @viewRegistry } = params @emitter = new Emitter @@ -85,6 +85,7 @@ class Package @loadMenus() @loadStylesheets() @loadDeserializers() + @loadViewProviders() @settingsPromise = @loadSettings() @requireMainModule() unless @mainModule? or @activationShouldBeDeferred() catch error @@ -266,6 +267,11 @@ class Package deserializeFunction.apply(this, arguments) return + loadViewProviders: -> + for implementationPath in @metadata.viewProviders + @viewRegistry.addViewProvider(require(path.join(@path, implementationPath))) + return + getStylesheetsPath: -> path.join(@path, 'styles') From 4e5912c5453cff723aa93b847569d9d2878d9204 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 20 Nov 2015 13:54:01 -0800 Subject: [PATCH 009/137] Upload to S3 as well. --- build/tasks/publish-build-task.coffee | 34 ++++++++++++++++++++++++--- package.json | 1 + 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/build/tasks/publish-build-task.coffee b/build/tasks/publish-build-task.coffee index fc96121ae..c8da8a895 100644 --- a/build/tasks/publish-build-task.coffee +++ b/build/tasks/publish-build-task.coffee @@ -6,6 +6,7 @@ async = require 'async' fs = require 'fs-plus' GitHub = require 'github-releases' request = require 'request' +AWS = require 'aws-sdk' grunt = null @@ -210,7 +211,7 @@ deleteExistingAssets = (release, assetNames, callback) -> async.parallel(tasks, callback) uploadAssets = (release, buildDir, assets, callback) -> - upload = (release, assetName, assetPath, callback) -> + uploadToReleases = (release, assetName, assetPath, callback) -> options = uri: release.upload_url.replace(/\{.*$/, "?name=#{assetName}") method: 'POST' @@ -221,15 +222,42 @@ uploadAssets = (release, buildDir, assets, callback) -> assetRequest = request options, (error, response, body='') -> if error? or response.statusCode >= 400 - logError("Upload release asset #{assetName} failed", error, body) + logError("Upload release asset #{assetName} to Releases failed", error, body) callback(error ? new Error(response.statusCode)) else callback(null, release) fs.createReadStream(assetPath).pipe(assetRequest) + uploadToS3 = (release, assetName, assetPath, callback) -> + s3Key = process.env.BUILD_ATOM_RELEASES_S3_KEY + s3Secret = process.env.BUILD_ATOM_RELEASES_S3_SECRET + s3Bucket = process.env.BUILD_ATOM_RELEASES_S3_BUCKET + + unless s3Key && s3Secret && s3Bucket + callback(new Error('BUILD_ATOM_RELEASES_S3_KEY, BUILD_ATOM_RELEASES_S3_SECRET, and BUILD_ATOM_RELEASES_S3_BUCKET environment variables must be set.')) + return + + s3Info = + accessKeyId: s3Key + secretAccessKey: s3Secret + s3 = new AWS.S3 s3Info + + uploadParams = + Bucket: s3Bucket + ACL: 'public-read' + Key: "releases/#{assetName}" + Body: fs.createReadStream(assetPath) + s3.upload uploadParams, (error, data) -> + if error? + console.log("Upload release asset #{assetName} to S3 failed", error) + callback(error) + else + callback(null, release) + tasks = [] for {assetName} in assets assetPath = path.join(buildDir, assetName) - tasks.push(upload.bind(this, release, assetName, assetPath)) + tasks.push(uploadToReleases.bind(this, release, assetName, assetPath)) + tasks.push(uploadToS3.bind(this, release, assetName, assetPath)) async.parallel(tasks, callback) diff --git a/package.json b/package.json index 9c9afc546..c11b3345e 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "dependencies": { "async": "0.2.6", "atom-keymap": "^6.1.1", + "aws-sdk": "^2.2.18", "babel-core": "^5.8.21", "bootstrap": "^3.3.4", "cached-run-in-this-context": "0.4.0", From ad7a67d8e4a07987a4602a0f01d77035cbb6c5c3 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 20 Nov 2015 14:05:05 -0800 Subject: [PATCH 010/137] Re-export the variables for the Linux builds. --- script/cibuild-atom-linux | 3 +++ script/cibuild-atom-rpm | 3 +++ 2 files changed, 6 insertions(+) diff --git a/script/cibuild-atom-linux b/script/cibuild-atom-linux index c4e957189..2c3395608 100755 --- a/script/cibuild-atom-linux +++ b/script/cibuild-atom-linux @@ -3,6 +3,9 @@ set -e export ATOM_ACCESS_TOKEN=$BUILD_ATOM_LINUX_ACCESS_TOKEN +export BUILD_ATOM_RELEASES_S3_KEY=$BUILD_ATOM_LINUX_RELEASES_S3_KEY +export BUILD_ATOM_RELEASES_S3_SECRET=$BUILD_ATOM_LINUX_RELEASES_S3_SECRET +export BUILD_ATOM_RELEASES_S3_BUCKET=$BUILD_ATOM_LINUX_RELEASES_S3_BUCKET if [ -d /usr/local/share/nodenv ]; then export NODENV_ROOT=/usr/local/share/nodenv diff --git a/script/cibuild-atom-rpm b/script/cibuild-atom-rpm index a861a068b..2faa89347 100755 --- a/script/cibuild-atom-rpm +++ b/script/cibuild-atom-rpm @@ -8,5 +8,8 @@ docker run \ --env JANKY_SHA1="$JANKY_SHA1" \ --env JANKY_BRANCH="$JANKY_BRANCH" \ --env ATOM_ACCESS_TOKEN="$BUILD_ATOM_RPM_ACCESS_TOKEN" \ + --env BUILD_ATOM_RELEASES_S3_KEY="$BUILD_ATOM_RPM_RELEASES_S3_KEY" \ + --env BUILD_ATOM_RELEASES_S3_SECRET="$BUILD_ATOM_RPM_RELEASES_S3_SECRET" \ + --env BUILD_ATOM_RELEASES_S3_BUCKET="$BUILD_ATOM_RPM_RELEASES_S3_BUCKET" \ atom-rpm /atom/script/rpmbuild docker rmi atom-rpm From 67b713ffb4013f5d60355be30ff10f91d359e951 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 20 Nov 2015 14:08:56 -0800 Subject: [PATCH 011/137] Re-export the variables for Windows too. --- script/cibuild.cmd | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/script/cibuild.cmd b/script/cibuild.cmd index 79197d1b1..a596b7eba 100644 --- a/script/cibuild.cmd +++ b/script/cibuild.cmd @@ -1,3 +1,7 @@ +SET BUILD_ATOM_RELEASES_S3_KEY=%BUILD_ATOM_WIN_RELEASES_S3_KEY% +SET BUILD_ATOM_RELEASES_S3_SECRET=%BUILD_ATOM_WIN_RELEASES_S3_SECRET% +SET BUILD_ATOM_RELEASES_S3_BUCKET=%BUILD_ATOM_WIN_RELEASES_S3_BUCKET% + @IF EXIST "%~dp0\node.exe" ( "%~dp0\node.exe" "%~dp0\cibuild" %* ) ELSE ( From 220b0e67e63b43145f42b1620591469503ae8341 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 20 Nov 2015 14:58:19 -0800 Subject: [PATCH 012/137] Hacks on hacks on hacks to test on test on test --- build/tasks/publish-build-task.coffee | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/build/tasks/publish-build-task.coffee b/build/tasks/publish-build-task.coffee index c8da8a895..910254360 100644 --- a/build/tasks/publish-build-task.coffee +++ b/build/tasks/publish-build-task.coffee @@ -37,8 +37,8 @@ module.exports = (gruntObject) -> isPrerelease = false when 'beta' isPrerelease = true - else - return + # else + # return doneCallback = @async() startTime = Date.now() @@ -55,12 +55,16 @@ module.exports = (gruntObject) -> zipAssets buildDir, assets, (error) -> return done(error) if error? - getAtomDraftRelease isPrerelease, channel, (error, release) -> - return done(error) if error? - assetNames = (asset.assetName for asset in assets) - deleteExistingAssets release, assetNames, (error) -> - return done(error) if error? - uploadAssets(release, buildDir, assets, done) + uploadAssets(null, buildDir, assets, done) + + # zipAssets buildDir, assets, (error) -> + # return done(error) if error? + # getAtomDraftRelease isPrerelease, channel, (error, release) -> + # return done(error) if error? + # assetNames = (asset.assetName for asset in assets) + # deleteExistingAssets release, assetNames, (error) -> + # return done(error) if error? + # uploadAssets(release, buildDir, assets, done) getAssets = -> {cp} = require('./task-helpers')(grunt) @@ -258,6 +262,6 @@ uploadAssets = (release, buildDir, assets, callback) -> tasks = [] for {assetName} in assets assetPath = path.join(buildDir, assetName) - tasks.push(uploadToReleases.bind(this, release, assetName, assetPath)) + # tasks.push(uploadToReleases.bind(this, release, assetName, assetPath)) tasks.push(uploadToS3.bind(this, release, assetName, assetPath)) async.parallel(tasks, callback) From 785da0aa6c5536754fe90732bac9575aba3e9ea1 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 20 Nov 2015 15:33:15 -0800 Subject: [PATCH 013/137] Linty --- build/tasks/publish-build-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/publish-build-task.coffee b/build/tasks/publish-build-task.coffee index 910254360..0a1042766 100644 --- a/build/tasks/publish-build-task.coffee +++ b/build/tasks/publish-build-task.coffee @@ -238,7 +238,7 @@ uploadAssets = (release, buildDir, assets, callback) -> s3Secret = process.env.BUILD_ATOM_RELEASES_S3_SECRET s3Bucket = process.env.BUILD_ATOM_RELEASES_S3_BUCKET - unless s3Key && s3Secret && s3Bucket + unless s3Key and s3Secret and s3Bucket callback(new Error('BUILD_ATOM_RELEASES_S3_KEY, BUILD_ATOM_RELEASES_S3_SECRET, and BUILD_ATOM_RELEASES_S3_BUCKET environment variables must be set.')) return From 46517af6dbeecafb7c896316d40b075293a76ce2 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Thu, 19 Nov 2015 21:46:54 -0500 Subject: [PATCH 014/137] :arrow_up: notifications@0.62.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d7787fe1e..1cff7c8ca 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "link": "0.31.0", "markdown-preview": "0.156.0", "metrics": "0.53.0", - "notifications": "0.61.0", + "notifications": "0.62.1", "open-on-github": "0.39.0", "package-generator": "0.41.0", "release-notes": "0.53.0", From 05ef4c0e853c123f372f4d13310a92ea47121930 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Thu, 19 Nov 2015 16:06:22 -0500 Subject: [PATCH 015/137] :arrow_up: language-coffee-script@0.45.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1cff7c8ca..bfbaadefd 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "wrap-guide": "0.38.1", "language-c": "0.49.0", "language-clojure": "0.18.0", - "language-coffee-script": "0.43.0", + "language-coffee-script": "0.45.0", "language-csharp": "0.11.0", "language-css": "0.34.0", "language-gfm": "0.81.0", From 00120ef4823e77d07b2bb65c64bdf3669f4d7566 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 20 Nov 2015 16:05:22 -0800 Subject: [PATCH 016/137] Namespace by tag name. --- build/tasks/publish-build-task.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/tasks/publish-build-task.coffee b/build/tasks/publish-build-task.coffee index 0a1042766..b0011f921 100644 --- a/build/tasks/publish-build-task.coffee +++ b/build/tasks/publish-build-task.coffee @@ -247,10 +247,11 @@ uploadAssets = (release, buildDir, assets, callback) -> secretAccessKey: s3Secret s3 = new AWS.S3 s3Info + key = "releases/#{release.tag_name}/#{assetName}" uploadParams = Bucket: s3Bucket ACL: 'public-read' - Key: "releases/#{assetName}" + Key: key Body: fs.createReadStream(assetPath) s3.upload uploadParams, (error, data) -> if error? From c08e408a718785c1f09dd8ec74ad5dec72844969 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 20 Nov 2015 16:09:55 -0800 Subject: [PATCH 017/137] Dummy out the tag name for now. --- build/tasks/publish-build-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/publish-build-task.coffee b/build/tasks/publish-build-task.coffee index b0011f921..58e8df9a1 100644 --- a/build/tasks/publish-build-task.coffee +++ b/build/tasks/publish-build-task.coffee @@ -55,7 +55,7 @@ module.exports = (gruntObject) -> zipAssets buildDir, assets, (error) -> return done(error) if error? - uploadAssets(null, buildDir, assets, done) + uploadAssets({tag_name: '1.1'}, buildDir, assets, done) # zipAssets buildDir, assets, (error) -> # return done(error) if error? From 35d9c3dfffa67a3bc3206e533f3b6ff8f35a6baa Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 20 Nov 2015 16:33:18 -0800 Subject: [PATCH 018/137] REMOVE ME hacks on hacks on hacks --- build/tasks/set-version-task.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/tasks/set-version-task.coffee b/build/tasks/set-version-task.coffee index 28abb6493..99c147c53 100644 --- a/build/tasks/set-version-task.coffee +++ b/build/tasks/set-version-task.coffee @@ -5,9 +5,9 @@ module.exports = (grunt) -> {spawn} = require('./task-helpers')(grunt) getVersion = (callback) -> - releasableBranches = ['stable', 'beta'] + releasableBranches = ['stable', 'beta', 'upload-to-s3'] channel = grunt.config.get('atom.channel') - shouldUseCommitHash = if channel in releasableBranches then false else true + shouldUseCommitHash = false # if channel in releasableBranches then false else true inRepository = fs.existsSync(path.resolve(__dirname, '..', '..', '.git')) {version} = require(path.join(grunt.config.get('atom.appDir'), 'package.json')) if shouldUseCommitHash and inRepository From 9cd5a0c31c2421aa5e045a6fa882b2d58d7e6e30 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 20 Nov 2015 16:42:37 -0800 Subject: [PATCH 019/137] aws-sdk is a build dependency. --- build/package.json | 1 + package.json | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package.json b/build/package.json index de9053006..40e5b309a 100644 --- a/build/package.json +++ b/build/package.json @@ -8,6 +8,7 @@ "dependencies": { "asar": "^0.8.0", "async": "~0.2.9", + "aws-sdk": "^2.2.18", "donna": "^1.0.13", "formidable": "~1.0.14", "fs-plus": "2.x", diff --git a/package.json b/package.json index c11b3345e..9c9afc546 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,6 @@ "dependencies": { "async": "0.2.6", "atom-keymap": "^6.1.1", - "aws-sdk": "^2.2.18", "babel-core": "^5.8.21", "bootstrap": "^3.3.4", "cached-run-in-this-context": "0.4.0", From f77699694e37b80c7196f4f8d5f8bd3dcdbaffa7 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 20 Nov 2015 17:15:10 -0800 Subject: [PATCH 020/137] Revert ":arrow_up: text-buffer :racehorse:" This reverts commit fcab30e822e25d2c1d6e0d85c3e9bcecd224b9a5. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cbd79970d..d141f8c71 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "service-hub": "^0.7.0", "source-map-support": "^0.3.2", "temp": "0.8.1", - "text-buffer": "^8.0.5", + "text-buffer": "^8.0.4", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "yargs": "^3.23.0" From 71bdeb5010bd1d40dd8fb1243fb2729353a429ec Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 20 Nov 2015 17:32:09 -0800 Subject: [PATCH 021/137] Try copying the Windows vars in cibuild. --- script/cibuild | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/script/cibuild b/script/cibuild index b3f0b3f83..c4fa533d0 100755 --- a/script/cibuild +++ b/script/cibuild @@ -41,6 +41,10 @@ function setEnvironmentVariables() { process.env.CXX = 'clang++'; process.env.npm_config_clang = '1'; } + + process.env.BUILD_ATOM_RELEASES_S3_KEY = process.env.BUILD_ATOM_WIN_RELEASES_S3_KEY + process.env.BUILD_ATOM_RELEASES_S3_SECRET = process.env.BUILD_ATOM_RELEASES_S3_SECRET + process.env.BUILD_ATOM_RELEASES_S3_BUCKET = process.env.BUILD_ATOM_RELEASES_S3_BUCKET } function removeNodeModules() { From 481cacb5d31d28251da8ee276dba6b203753e869 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 20 Nov 2015 17:32:15 -0800 Subject: [PATCH 022/137] Let's see if we get here. --- script/cibuild.cmd | 2 ++ 1 file changed, 2 insertions(+) diff --git a/script/cibuild.cmd b/script/cibuild.cmd index a596b7eba..9065be470 100644 --- a/script/cibuild.cmd +++ b/script/cibuild.cmd @@ -2,6 +2,8 @@ SET BUILD_ATOM_RELEASES_S3_KEY=%BUILD_ATOM_WIN_RELEASES_S3_KEY% SET BUILD_ATOM_RELEASES_S3_SECRET=%BUILD_ATOM_WIN_RELEASES_S3_SECRET% SET BUILD_ATOM_RELEASES_S3_BUCKET=%BUILD_ATOM_WIN_RELEASES_S3_BUCKET% +ECHO Here I go Windowsing again + @IF EXIST "%~dp0\node.exe" ( "%~dp0\node.exe" "%~dp0\cibuild" %* ) ELSE ( From fbf3265f5af7cbcc5d68f9b16b058e0ddf2292a7 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 20 Nov 2015 17:59:59 -0800 Subject: [PATCH 023/137] Revert "Let's see if we get here." This reverts commit 481cacb5d31d28251da8ee276dba6b203753e869. --- script/cibuild.cmd | 2 -- 1 file changed, 2 deletions(-) diff --git a/script/cibuild.cmd b/script/cibuild.cmd index 9065be470..a596b7eba 100644 --- a/script/cibuild.cmd +++ b/script/cibuild.cmd @@ -2,8 +2,6 @@ SET BUILD_ATOM_RELEASES_S3_KEY=%BUILD_ATOM_WIN_RELEASES_S3_KEY% SET BUILD_ATOM_RELEASES_S3_SECRET=%BUILD_ATOM_WIN_RELEASES_S3_SECRET% SET BUILD_ATOM_RELEASES_S3_BUCKET=%BUILD_ATOM_WIN_RELEASES_S3_BUCKET% -ECHO Here I go Windowsing again - @IF EXIST "%~dp0\node.exe" ( "%~dp0\node.exe" "%~dp0\cibuild" %* ) ELSE ( From 0f9cdbec775ccf69834464cedcc53289b0de4a69 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 20 Nov 2015 18:03:14 -0800 Subject: [PATCH 024/137] It helps if you get the names right. --- script/cibuild | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/script/cibuild b/script/cibuild index c4fa533d0..e562b0ea7 100755 --- a/script/cibuild +++ b/script/cibuild @@ -40,11 +40,10 @@ function setEnvironmentVariables() { process.env.CC = 'clang'; process.env.CXX = 'clang++'; process.env.npm_config_clang = '1'; + process.env.BUILD_ATOM_RELEASES_S3_KEY = process.env.BUILD_ATOM_WIN_RELEASES_S3_KEY + process.env.BUILD_ATOM_RELEASES_S3_SECRET = process.env.BUILD_ATOM_WIN_RELEASES_S3_SECRET + process.env.BUILD_ATOM_RELEASES_S3_BUCKET = process.env.BUILD_ATOM_WIN_RELEASES_S3_BUCKET } - - process.env.BUILD_ATOM_RELEASES_S3_KEY = process.env.BUILD_ATOM_WIN_RELEASES_S3_KEY - process.env.BUILD_ATOM_RELEASES_S3_SECRET = process.env.BUILD_ATOM_RELEASES_S3_SECRET - process.env.BUILD_ATOM_RELEASES_S3_BUCKET = process.env.BUILD_ATOM_RELEASES_S3_BUCKET } function removeNodeModules() { From 10628351ea365b42f5748afb031aa3bcefae6c8a Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 20 Nov 2015 18:03:21 -0800 Subject: [PATCH 025/137] Only do it on Windows. --- script/cibuild | 1 + 1 file changed, 1 insertion(+) diff --git a/script/cibuild b/script/cibuild index e562b0ea7..860e0a938 100755 --- a/script/cibuild +++ b/script/cibuild @@ -40,6 +40,7 @@ function setEnvironmentVariables() { process.env.CC = 'clang'; process.env.CXX = 'clang++'; process.env.npm_config_clang = '1'; + } else if (process.platform === 'win32') { process.env.BUILD_ATOM_RELEASES_S3_KEY = process.env.BUILD_ATOM_WIN_RELEASES_S3_KEY process.env.BUILD_ATOM_RELEASES_S3_SECRET = process.env.BUILD_ATOM_WIN_RELEASES_S3_SECRET process.env.BUILD_ATOM_RELEASES_S3_BUCKET = process.env.BUILD_ATOM_WIN_RELEASES_S3_BUCKET From b11d0c25851d9d784abccd7e9d0c96c2fa25eee3 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Mon, 16 Nov 2015 11:59:47 +0100 Subject: [PATCH 026/137] Use em-dash in window title and exclude app name on OS X --- spec/workspace-spec.coffee | 14 +++++++------- src/workspace.coffee | 19 +++++++++++++------ 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index e150761af..74e98e1e4 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -76,7 +76,7 @@ describe "Workspace", -> expect(editor4.getCursorScreenPosition()).toEqual [2, 4] expect(atom.workspace.getActiveTextEditor().getPath()).toBe editor3.getPath() - expect(document.title).toBe "#{path.basename(editor3.getLongTitle())} - #{atom.project.getPaths()[0]} - Atom" + expect(document.title).toMatch ///^#{path.basename(editor3.getLongTitle())}\ \u2014\ #{atom.project.getPaths()[0]}/// describe "where there are no open panes or editors", -> it "constructs the view with no open editors", -> @@ -732,7 +732,7 @@ describe "Workspace", -> describe "when the project has no path", -> it "sets the title to 'untitled'", -> atom.project.setPaths([]) - expect(document.title).toBe 'untitled - Atom' + expect(document.title).toMatch ///^untitled/// describe "when the project has a path", -> beforeEach -> @@ -742,25 +742,25 @@ describe "Workspace", -> describe "when there is an active pane item", -> it "sets the title to the pane item's title plus the project path", -> item = atom.workspace.getActivePaneItem() - expect(document.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]} - Atom" + expect(document.title).toMatch ///^#{item.getTitle()}\ \u2014\ #{atom.project.getPaths()[0]}/// describe "when the title of the active pane item changes", -> it "updates the window title based on the item's new title", -> editor = atom.workspace.getActivePaneItem() editor.buffer.setPath(path.join(temp.dir, 'hi')) - expect(document.title).toBe "#{editor.getTitle()} - #{atom.project.getPaths()[0]} - Atom" + expect(document.title).toMatch ///^#{editor.getTitle()}\ \u2014\ #{atom.project.getPaths()[0]}/// describe "when the active pane's item changes", -> it "updates the title to the new item's title plus the project path", -> atom.workspace.getActivePane().activateNextItem() item = atom.workspace.getActivePaneItem() - expect(document.title).toBe "#{item.getTitle()} - #{atom.project.getPaths()[0]} - Atom" + expect(document.title).toMatch ///^#{item.getTitle()}\ \u2014\ #{atom.project.getPaths()[0]}/// describe "when the last pane item is removed", -> it "updates the title to contain the project's path", -> atom.workspace.getActivePane().destroy() expect(atom.workspace.getActivePaneItem()).toBeUndefined() - expect(document.title).toBe "#{atom.project.getPaths()[0]} - Atom" + expect(document.title).toMatch ///^#{atom.project.getPaths()[0]}/// describe "when an inactive pane's item changes", -> it "does not update the title", -> @@ -784,7 +784,7 @@ describe "Workspace", -> }) workspace2.deserialize(atom.workspace.serialize(), atom.deserializers) item = workspace2.getActivePaneItem() - expect(document.title).toBe "#{item.getLongTitle()} - #{atom.project.getPaths()[0]} - Atom" + expect(document.title).toMatch ///^#{item.getLongTitle()}\ \u2014\ #{atom.project.getPaths()[0]}/// workspace2.destroy() describe "document edited status", -> diff --git a/src/workspace.coffee b/src/workspace.coffee index 04feef61e..f64f58ee0 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -161,15 +161,22 @@ class Workspace extends Model itemTitle ?= "untitled" projectPath ?= projectPaths[0] + titleParts = [] if item? and projectPath? - document.title = "#{itemTitle} - #{projectPath} - #{appName}" - @applicationDelegate.setRepresentedFilename(itemPath ? projectPath) + titleParts.push itemTitle, projectPath + representedPath = itemPath ? projectPath else if projectPath? - document.title = "#{projectPath} - #{appName}" - @applicationDelegate.setRepresentedFilename(projectPath) + titleParts.push projectPath + representedPath = projectPath else - document.title = "#{itemTitle} - #{appName}" - @applicationDelegate.setRepresentedFilename("") + titleParts.push itemTitle + representedPath = "" + + unless process.platform is 'darwin' + titleParts.push appName + + document.title = titleParts.join(" \u2014 ") + @applicationDelegate.setRepresentedFilename(representedPath) # On OS X, fades the application window's proxy icon when the current file # has been modified. From 6d20ffc06e31dc88211d49587587cdac7864bc12 Mon Sep 17 00:00:00 2001 From: joshaber Date: Sat, 21 Nov 2015 05:34:39 -0800 Subject: [PATCH 027/137] What you got. --- script/cibuild | 2 ++ 1 file changed, 2 insertions(+) diff --git a/script/cibuild b/script/cibuild index 860e0a938..ae3316cad 100755 --- a/script/cibuild +++ b/script/cibuild @@ -41,6 +41,8 @@ function setEnvironmentVariables() { process.env.CXX = 'clang++'; process.env.npm_config_clang = '1'; } else if (process.platform === 'win32') { + console.log("env:") + console.log(process.env) process.env.BUILD_ATOM_RELEASES_S3_KEY = process.env.BUILD_ATOM_WIN_RELEASES_S3_KEY process.env.BUILD_ATOM_RELEASES_S3_SECRET = process.env.BUILD_ATOM_WIN_RELEASES_S3_SECRET process.env.BUILD_ATOM_RELEASES_S3_BUCKET = process.env.BUILD_ATOM_WIN_RELEASES_S3_BUCKET From bb69ffe015df00d1e0bf01ebaafc518ce8f373fd Mon Sep 17 00:00:00 2001 From: joshaber Date: Sat, 21 Nov 2015 05:47:18 -0800 Subject: [PATCH 028/137] Revert "What you got." This reverts commit 6d20ffc06e31dc88211d49587587cdac7864bc12. --- script/cibuild | 2 -- 1 file changed, 2 deletions(-) diff --git a/script/cibuild b/script/cibuild index ae3316cad..860e0a938 100755 --- a/script/cibuild +++ b/script/cibuild @@ -41,8 +41,6 @@ function setEnvironmentVariables() { process.env.CXX = 'clang++'; process.env.npm_config_clang = '1'; } else if (process.platform === 'win32') { - console.log("env:") - console.log(process.env) process.env.BUILD_ATOM_RELEASES_S3_KEY = process.env.BUILD_ATOM_WIN_RELEASES_S3_KEY process.env.BUILD_ATOM_RELEASES_S3_SECRET = process.env.BUILD_ATOM_WIN_RELEASES_S3_SECRET process.env.BUILD_ATOM_RELEASES_S3_BUCKET = process.env.BUILD_ATOM_WIN_RELEASES_S3_BUCKET From 5648cd633e7f5b511cdc521d19abf34d928961bd Mon Sep 17 00:00:00 2001 From: joshaber Date: Sat, 21 Nov 2015 05:53:57 -0800 Subject: [PATCH 029/137] This is just used for Appveyor, which doesn't need these. --- script/cibuild.cmd | 4 ---- 1 file changed, 4 deletions(-) diff --git a/script/cibuild.cmd b/script/cibuild.cmd index a596b7eba..79197d1b1 100644 --- a/script/cibuild.cmd +++ b/script/cibuild.cmd @@ -1,7 +1,3 @@ -SET BUILD_ATOM_RELEASES_S3_KEY=%BUILD_ATOM_WIN_RELEASES_S3_KEY% -SET BUILD_ATOM_RELEASES_S3_SECRET=%BUILD_ATOM_WIN_RELEASES_S3_SECRET% -SET BUILD_ATOM_RELEASES_S3_BUCKET=%BUILD_ATOM_WIN_RELEASES_S3_BUCKET% - @IF EXIST "%~dp0\node.exe" ( "%~dp0\node.exe" "%~dp0\cibuild" %* ) ELSE ( From cc84246e4ddd0ba9547d1e7955be1f8ef176bb6f Mon Sep 17 00:00:00 2001 From: joshaber Date: Sat, 21 Nov 2015 06:08:13 -0800 Subject: [PATCH 030/137] Revert "REMOVE ME hacks on hacks on hacks" This reverts commit 35d9c3dfffa67a3bc3206e533f3b6ff8f35a6baa. --- build/tasks/set-version-task.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/tasks/set-version-task.coffee b/build/tasks/set-version-task.coffee index 99c147c53..28abb6493 100644 --- a/build/tasks/set-version-task.coffee +++ b/build/tasks/set-version-task.coffee @@ -5,9 +5,9 @@ module.exports = (grunt) -> {spawn} = require('./task-helpers')(grunt) getVersion = (callback) -> - releasableBranches = ['stable', 'beta', 'upload-to-s3'] + releasableBranches = ['stable', 'beta'] channel = grunt.config.get('atom.channel') - shouldUseCommitHash = false # if channel in releasableBranches then false else true + shouldUseCommitHash = if channel in releasableBranches then false else true inRepository = fs.existsSync(path.resolve(__dirname, '..', '..', '.git')) {version} = require(path.join(grunt.config.get('atom.appDir'), 'package.json')) if shouldUseCommitHash and inRepository From 8e79796f3cbbf92aa1615cee14c158a36b924272 Mon Sep 17 00:00:00 2001 From: joshaber Date: Sat, 21 Nov 2015 06:08:48 -0800 Subject: [PATCH 031/137] Revert "Hacks on hacks on hacks to test on test on test" This reverts commit 220b0e67e63b43145f42b1620591469503ae8341. --- build/tasks/publish-build-task.coffee | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/build/tasks/publish-build-task.coffee b/build/tasks/publish-build-task.coffee index 58e8df9a1..d8dffd1ea 100644 --- a/build/tasks/publish-build-task.coffee +++ b/build/tasks/publish-build-task.coffee @@ -37,8 +37,8 @@ module.exports = (gruntObject) -> isPrerelease = false when 'beta' isPrerelease = true - # else - # return + else + return doneCallback = @async() startTime = Date.now() @@ -55,16 +55,12 @@ module.exports = (gruntObject) -> zipAssets buildDir, assets, (error) -> return done(error) if error? - uploadAssets({tag_name: '1.1'}, buildDir, assets, done) - - # zipAssets buildDir, assets, (error) -> - # return done(error) if error? - # getAtomDraftRelease isPrerelease, channel, (error, release) -> - # return done(error) if error? - # assetNames = (asset.assetName for asset in assets) - # deleteExistingAssets release, assetNames, (error) -> - # return done(error) if error? - # uploadAssets(release, buildDir, assets, done) + getAtomDraftRelease isPrerelease, channel, (error, release) -> + return done(error) if error? + assetNames = (asset.assetName for asset in assets) + deleteExistingAssets release, assetNames, (error) -> + return done(error) if error? + uploadAssets(release, buildDir, assets, done) getAssets = -> {cp} = require('./task-helpers')(grunt) @@ -263,6 +259,6 @@ uploadAssets = (release, buildDir, assets, callback) -> tasks = [] for {assetName} in assets assetPath = path.join(buildDir, assetName) - # tasks.push(uploadToReleases.bind(this, release, assetName, assetPath)) + tasks.push(uploadToReleases.bind(this, release, assetName, assetPath)) tasks.push(uploadToS3.bind(this, release, assetName, assetPath)) async.parallel(tasks, callback) From 2d29fd6e79262bd5b8c902f86456ef5a21f224ae Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 20 Nov 2015 13:28:05 -0800 Subject: [PATCH 032/137] Load config schemas from packages' package.json files --- .../package-with-json-config-schema/package.json | 13 +++++++++++++ spec/package-manager-spec.coffee | 15 +++++++++++++++ src/package.coffee | 13 ++++++++----- 3 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 spec/fixtures/packages/package-with-json-config-schema/package.json diff --git a/spec/fixtures/packages/package-with-json-config-schema/package.json b/spec/fixtures/packages/package-with-json-config-schema/package.json new file mode 100644 index 000000000..960d87fc1 --- /dev/null +++ b/spec/fixtures/packages/package-with-json-config-schema/package.json @@ -0,0 +1,13 @@ +{ + "name": "package-with-json-config-schema", + "configSchema": { + "a": { + "type": "number", + "default": 5 + }, + "b": { + "type": "string", + "default": "five" + } + } +} diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 169e09b76..656b4b691 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -194,6 +194,21 @@ describe "PackageManager", -> expect(atom.config.set('package-with-config-schema.numbers.one', '10')).toBe true expect(atom.config.get('package-with-config-schema.numbers.one')).toBe 10 + it "assigns the config schema when the package contains a schema in its package.json", -> + expect(atom.config.get('package-with-json-config-schema')).toBeUndefined() + + waitsForPromise -> + atom.packages.activatePackage('package-with-json-config-schema') + + runs -> + expect(atom.config.getSchema('package-with-json-config-schema')).toEqual { + type: 'object' + properties: { + a: {type: 'number', default: 5} + b: {type: 'string', default: 'five'} + } + } + describe "when the package metadata includes `activationCommands`", -> [mainModule, promise, workspaceCommandListener, registration] = [] diff --git a/src/package.coffee b/src/package.coffee index 1d98c8161..d1354340f 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -133,11 +133,14 @@ class Package activateConfig: -> return if @configActivated - @requireMainModule() unless @mainModule? - if @mainModule? - if @mainModule.config? and typeof @mainModule.config is 'object' - @config.setSchema @name, {type: 'object', properties: @mainModule.config} - @mainModule.activateConfig?() + if configSchema = @metadata.configSchema + @config.setSchema @name, {type: 'object', properties: configSchema} + else + @requireMainModule() unless @mainModule? + if @mainModule? + if @mainModule.config? and typeof @mainModule.config is 'object' + @config.setSchema @name, {type: 'object', properties: @mainModule.config} + @mainModule.activateConfig?() @configActivated = true activateStylesheets: -> From 5f1947ef1f15393fd25b929914de5fcb6f40c37f Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 20 Nov 2015 13:42:17 -0800 Subject: [PATCH 033/137] Guard for undefined package.json fields --- src/package.coffee | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/package.coffee b/src/package.coffee index d1354340f..b2a87d1d8 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -259,21 +259,23 @@ class Package [stylesheetPath, @themeManager.loadStylesheet(stylesheetPath, true)] loadDeserializers: -> - for name, implementationPath of @metadata.deserializers - do => - deserializePath = path.join(@path, implementationPath) - deserializeFunction = null - atom.deserializers.add - name: name, - deserialize: -> - deserializeFunction ?= require(deserializePath) - deserializeFunction.apply(this, arguments) - return + if @metadata.deserializers? + for name, implementationPath of @metadata.deserializers + do => + deserializePath = path.join(@path, implementationPath) + deserializeFunction = null + atom.deserializers.add + name: name, + deserialize: -> + deserializeFunction ?= require(deserializePath) + deserializeFunction.apply(this, arguments) + return loadViewProviders: -> - for implementationPath in @metadata.viewProviders - @viewRegistry.addViewProvider(require(path.join(@path, implementationPath))) - return + if @metadata.viewProviders? + for implementationPath in @metadata.viewProviders + @viewRegistry.addViewProvider(require(path.join(@path, implementationPath))) + return getStylesheetsPath: -> path.join(@path, 'styles') From d6e5ea85642155cf28e224034a558254dd4922fe Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 23 Nov 2015 16:05:32 -0800 Subject: [PATCH 034/137] Defer requiring packages' main modules if they use new package.json fields --- .../package-with-deserializers/index.js | 3 ++ .../package-with-deserializers/package.json | 1 + .../package-with-view-providers/index.js | 3 ++ .../package-with-view-providers/package.json | 1 + spec/package-manager-spec.coffee | 36 ++++++++-------- src/package.coffee | 43 +++++++++++-------- 6 files changed, 53 insertions(+), 34 deletions(-) create mode 100644 spec/fixtures/packages/package-with-deserializers/index.js create mode 100644 spec/fixtures/packages/package-with-view-providers/index.js diff --git a/spec/fixtures/packages/package-with-deserializers/index.js b/spec/fixtures/packages/package-with-deserializers/index.js new file mode 100644 index 000000000..19bba5ecb --- /dev/null +++ b/spec/fixtures/packages/package-with-deserializers/index.js @@ -0,0 +1,3 @@ +module.exports = { + activate: function() {} +} diff --git a/spec/fixtures/packages/package-with-deserializers/package.json b/spec/fixtures/packages/package-with-deserializers/package.json index c55e1444a..daa5776bf 100644 --- a/spec/fixtures/packages/package-with-deserializers/package.json +++ b/spec/fixtures/packages/package-with-deserializers/package.json @@ -1,6 +1,7 @@ { "name": "package-with-deserializers", "version": "1.0.0", + "main": "./index", "deserializers": { "Deserializer1": "./deserializer-1.js", "Deserializer2": "./deserializer-2.js" diff --git a/spec/fixtures/packages/package-with-view-providers/index.js b/spec/fixtures/packages/package-with-view-providers/index.js new file mode 100644 index 000000000..19bba5ecb --- /dev/null +++ b/spec/fixtures/packages/package-with-view-providers/index.js @@ -0,0 +1,3 @@ +module.exports = { + activate: function() {} +} diff --git a/spec/fixtures/packages/package-with-view-providers/package.json b/spec/fixtures/packages/package-with-view-providers/package.json index 7f7405c32..989473f95 100644 --- a/spec/fixtures/packages/package-with-view-providers/package.json +++ b/spec/fixtures/packages/package-with-view-providers/package.json @@ -1,5 +1,6 @@ { "name": "package-with-view-providers", + "main": "./index", "version": "1.0.0", "viewProviders": [ "./view-provider-1", diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 656b4b691..94a6c43c5 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -80,7 +80,7 @@ describe "PackageManager", -> expect(loadedPackage.name).toBe "package-with-main" it "registers any deserializers specified in the package's package.json", -> - atom.packages.loadPackage("package-with-deserializers") + pack = atom.packages.loadPackage("package-with-deserializers") state1 = {deserializer: 'Deserializer1', a: 'b'} expect(atom.deserializers.deserialize(state1)).toEqual { @@ -94,8 +94,10 @@ describe "PackageManager", -> state: state2 } + expect(pack.mainModule).toBeNull() + it "registers any view providers specified in the package's package.json", -> - atom.packages.loadPackage("package-with-view-providers") + pack = atom.packages.loadPackage("package-with-view-providers") model1 = {worksWithViewProvider1: true} element1 = atom.views.getView(model1) @@ -107,6 +109,21 @@ describe "PackageManager", -> expect(element2 instanceof HTMLDivElement).toBe true expect(element2.dataset.createdBy).toBe 'view-provider-2' + expect(pack.mainModule).toBeNull() + + it "registers the config schema in the package's metadata, if present", -> + pack = atom.packages.loadPackage("package-with-json-config-schema") + + expect(atom.config.getSchema('package-with-json-config-schema')).toEqual { + type: 'object' + properties: { + a: {type: 'number', default: 5} + b: {type: 'string', default: 'five'} + } + } + + expect(pack.mainModule).toBeNull() + describe "::unloadPackage(name)", -> describe "when the package is active", -> it "throws an error", -> @@ -194,21 +211,6 @@ describe "PackageManager", -> expect(atom.config.set('package-with-config-schema.numbers.one', '10')).toBe true expect(atom.config.get('package-with-config-schema.numbers.one')).toBe 10 - it "assigns the config schema when the package contains a schema in its package.json", -> - expect(atom.config.get('package-with-json-config-schema')).toBeUndefined() - - waitsForPromise -> - atom.packages.activatePackage('package-with-json-config-schema') - - runs -> - expect(atom.config.getSchema('package-with-json-config-schema')).toEqual { - type: 'object' - properties: { - a: {type: 'number', default: 5} - b: {type: 'string', default: 'five'} - } - } - describe "when the package metadata includes `activationCommands`", -> [mainModule, promise, workspaceCommandListener, registration] = [] diff --git a/src/package.coffee b/src/package.coffee index b2a87d1d8..b97424d04 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -86,12 +86,22 @@ class Package @loadStylesheets() @loadDeserializers() @loadViewProviders() + @registerConfigSchemaFromMetadata() @settingsPromise = @loadSettings() - @requireMainModule() unless @mainModule? or @activationShouldBeDeferred() + if @shouldRequireMainModuleOnLoad() and not @mainModule? + @requireMainModule() catch error @handleError("Failed to load the #{@name} package", error) this + shouldRequireMainModuleOnLoad: -> + not ( + @metadata.deserializers? or + @metadata.viewProviders? or + @metadata.configSchema? or + @activationShouldBeDeferred() + ) + reset: -> @stylesheets = [] @keymaps = [] @@ -119,9 +129,11 @@ class Package activateNow: -> try - @activateConfig() + @requireMainModule() unless @mainModule? + @registerConfigSchemaFromMainModule() @activateStylesheets() if @mainModule? and not @mainActivated + @mainModule.activateConfig?() @mainModule.activate?(@packageManager.getPackageState(@name) ? {}) @mainActivated = true @activateServices() @@ -130,18 +142,19 @@ class Package @resolveActivationPromise?() - activateConfig: -> - return if @configActivated - + registerConfigSchemaFromMetadata: -> if configSchema = @metadata.configSchema @config.setSchema @name, {type: 'object', properties: configSchema} - else - @requireMainModule() unless @mainModule? - if @mainModule? - if @mainModule.config? and typeof @mainModule.config is 'object' - @config.setSchema @name, {type: 'object', properties: @mainModule.config} - @mainModule.activateConfig?() - @configActivated = true + @configSchemaRegistered = true + + registerConfigSchemaFromMainModule: -> + return if @configSchemaRegistered + + if @mainModule? + if @mainModule.config? and typeof @mainModule.config is 'object' + @config.setSchema @name, {type: 'object', properties: @mainModule.config} + + @configSchemaRegistered = true activateStylesheets: -> return if @stylesheetsActivated @@ -368,20 +381,16 @@ class Package @resolveActivationPromise = null @activationCommandSubscriptions?.dispose() @deactivateResources() - @deactivateConfig() @deactivateKeymaps() if @mainActivated try @mainModule?.deactivate?() + @mainModule?.deactivateConfig?() @mainActivated = false catch e console.error "Error deactivating package '#{@name}'", e.stack @emitter.emit 'did-deactivate' - deactivateConfig: -> - @mainModule?.deactivateConfig?() - @configActivated = false - deactivateResources: -> grammar.deactivate() for grammar in @grammars settings.deactivate() for settings in @settings From 24938c0361366be8715a1a1886e336dfd20dade5 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 23 Nov 2015 16:28:08 -0800 Subject: [PATCH 035/137] Defer loading view providers until activation or deserializer use Signed-off-by: Nathan Sobo --- .../deserializer.js | 3 + .../package-with-view-providers/package.json | 3 + spec/package-manager-spec.coffee | 59 +++++++++++++++---- src/package.coffee | 11 ++-- 4 files changed, 60 insertions(+), 16 deletions(-) create mode 100644 spec/fixtures/packages/package-with-view-providers/deserializer.js diff --git a/spec/fixtures/packages/package-with-view-providers/deserializer.js b/spec/fixtures/packages/package-with-view-providers/deserializer.js new file mode 100644 index 000000000..334e7b2ab --- /dev/null +++ b/spec/fixtures/packages/package-with-view-providers/deserializer.js @@ -0,0 +1,3 @@ +module.exports = function (state) { + return {state: state} +} diff --git a/spec/fixtures/packages/package-with-view-providers/package.json b/spec/fixtures/packages/package-with-view-providers/package.json index 989473f95..f67477280 100644 --- a/spec/fixtures/packages/package-with-view-providers/package.json +++ b/spec/fixtures/packages/package-with-view-providers/package.json @@ -2,6 +2,9 @@ "name": "package-with-view-providers", "main": "./index", "version": "1.0.0", + "deserializers": { + "DeserializerFromPackageWithViewProviders": "./deserializer" + }, "viewProviders": [ "./view-provider-1", "./view-provider-2" diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 94a6c43c5..d82f37acb 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -96,20 +96,57 @@ describe "PackageManager", -> expect(pack.mainModule).toBeNull() - it "registers any view providers specified in the package's package.json", -> - pack = atom.packages.loadPackage("package-with-view-providers") - + describe "when there are view providers specified in the package's package.json", -> model1 = {worksWithViewProvider1: true} - element1 = atom.views.getView(model1) - expect(element1 instanceof HTMLDivElement).toBe true - expect(element1.dataset.createdBy).toBe 'view-provider-1' - model2 = {worksWithViewProvider2: true} - element2 = atom.views.getView(model2) - expect(element2 instanceof HTMLDivElement).toBe true - expect(element2.dataset.createdBy).toBe 'view-provider-2' - expect(pack.mainModule).toBeNull() + afterEach -> + atom.packages.deactivatePackage('package-with-view-providers') + atom.packages.unloadPackage('package-with-view-providers') + + it "does not load the view providers immediately", -> + pack = atom.packages.loadPackage("package-with-view-providers") + expect(pack.mainModule).toBeNull() + + expect(-> atom.views.getView(model1)).toThrow() + expect(-> atom.views.getView(model2)).toThrow() + + it "registers the view providers when the package is activated", -> + pack = atom.packages.loadPackage("package-with-view-providers") + + waitsForPromise -> + atom.packages.activatePackage("package-with-view-providers").then -> + element1 = atom.views.getView(model1) + expect(element1 instanceof HTMLDivElement).toBe true + expect(element1.dataset.createdBy).toBe 'view-provider-1' + + element2 = atom.views.getView(model2) + expect(element2 instanceof HTMLDivElement).toBe true + expect(element2.dataset.createdBy).toBe 'view-provider-2' + + it "registers the view providers when any of the package's deserializers are used", -> + pack = atom.packages.loadPackage("package-with-view-providers") + + spyOn(atom.views, 'addViewProvider').andCallThrough() + atom.deserializers.deserialize({ + deserializer: 'DeserializerFromPackageWithViewProviders', + a: 'b' + }) + expect(atom.views.addViewProvider.callCount).toBe 2 + + atom.deserializers.deserialize({ + deserializer: 'DeserializerFromPackageWithViewProviders', + a: 'b' + }) + expect(atom.views.addViewProvider.callCount).toBe 2 + + element1 = atom.views.getView(model1) + expect(element1 instanceof HTMLDivElement).toBe true + expect(element1.dataset.createdBy).toBe 'view-provider-1' + + element2 = atom.views.getView(model2) + expect(element2 instanceof HTMLDivElement).toBe true + expect(element2.dataset.createdBy).toBe 'view-provider-2' it "registers the config schema in the package's metadata, if present", -> pack = atom.packages.loadPackage("package-with-json-config-schema") diff --git a/src/package.coffee b/src/package.coffee index b97424d04..f437d327a 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -85,7 +85,6 @@ class Package @loadMenus() @loadStylesheets() @loadDeserializers() - @loadViewProviders() @registerConfigSchemaFromMetadata() @settingsPromise = @loadSettings() if @shouldRequireMainModuleOnLoad() and not @mainModule? @@ -131,6 +130,7 @@ class Package try @requireMainModule() unless @mainModule? @registerConfigSchemaFromMainModule() + @registerViewProviders() @activateStylesheets() if @mainModule? and not @mainActivated @mainModule.activateConfig?() @@ -279,16 +279,17 @@ class Package deserializeFunction = null atom.deserializers.add name: name, - deserialize: -> + deserialize: => + @registerViewProviders() deserializeFunction ?= require(deserializePath) deserializeFunction.apply(this, arguments) return - loadViewProviders: -> - if @metadata.viewProviders? + registerViewProviders: -> + if @metadata.viewProviders? and not @registeredViewProviders for implementationPath in @metadata.viewProviders @viewRegistry.addViewProvider(require(path.join(@path, implementationPath))) - return + @registeredViewProviders = true getStylesheetsPath: -> path.join(@path, 'styles') From 327cf6997bbff1a058d47baa3cdf8ceab90489e5 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 23 Nov 2015 17:35:38 -0800 Subject: [PATCH 036/137] Remember which packages use atom APIs at main module load time Signed-off-by: Nathan Sobo --- .../package-with-eval-time-api-calls/index.js | 5 ++++ .../package.json | 5 ++++ .../packages/package-with-main/package.cson | 1 + spec/package-manager-spec.coffee | 24 +++++++++++++++++++ spec/package-spec.coffee | 11 +++------ spec/spec-helper.coffee | 6 +++++ src/deserializer-manager.coffee | 3 +++ src/package.coffee | 12 +++++++++- src/view-registry.coffee | 3 +++ 9 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 spec/fixtures/packages/package-with-eval-time-api-calls/index.js create mode 100644 spec/fixtures/packages/package-with-eval-time-api-calls/package.json diff --git a/spec/fixtures/packages/package-with-eval-time-api-calls/index.js b/spec/fixtures/packages/package-with-eval-time-api-calls/index.js new file mode 100644 index 000000000..e16db0743 --- /dev/null +++ b/spec/fixtures/packages/package-with-eval-time-api-calls/index.js @@ -0,0 +1,5 @@ +atom.deserializers.add('MyDeserializer', function (state) { + return {state: state, a: 'b'} +}) + +exports.activate = function () {} diff --git a/spec/fixtures/packages/package-with-eval-time-api-calls/package.json b/spec/fixtures/packages/package-with-eval-time-api-calls/package.json new file mode 100644 index 000000000..7a76abb5f --- /dev/null +++ b/spec/fixtures/packages/package-with-eval-time-api-calls/package.json @@ -0,0 +1,5 @@ +{ + "name": "package-with-eval-time-api-calls", + "version": "1.2.3", + "main": "./index" +} diff --git a/spec/fixtures/packages/package-with-main/package.cson b/spec/fixtures/packages/package-with-main/package.cson index e799f6ca8..75910bbcc 100644 --- a/spec/fixtures/packages/package-with-main/package.cson +++ b/spec/fixtures/packages/package-with-main/package.cson @@ -1 +1,2 @@ 'main': 'main-module.coffee' +'version': '2.3.4' diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index d82f37acb..4e88a1c2f 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -1,6 +1,7 @@ path = require 'path' Package = require '../src/package' {Disposable} = require 'atom' +{mockLocalStorage} = require './spec-helper' describe "PackageManager", -> workspaceElement = null @@ -161,6 +162,29 @@ describe "PackageManager", -> expect(pack.mainModule).toBeNull() + describe "when a package does not have deserializers, view providers or a config schema in its package.json", -> + beforeEach -> + atom.packages.unloadPackage('package-with-main') + mockLocalStorage() + + it "defers loading the package's main module if the package previously used no Atom APIs when its main module was required", -> + pack1 = atom.packages.loadPackage('package-with-main') + expect(pack1.mainModule).toBeDefined() + + atom.packages.unloadPackage('package-with-main') + + pack2 = atom.packages.loadPackage('package-with-main') + expect(pack2.mainModule).toBeNull() + + it "does not defer loading the package's main module if the package previously used Atom APIs when its main module was required", -> + pack1 = atom.packages.loadPackage('package-with-eval-time-api-calls') + expect(pack1.mainModule).toBeDefined() + + atom.packages.unloadPackage('package-with-eval-time-api-calls') + + pack2 = atom.packages.loadPackage('package-with-eval-time-api-calls') + expect(pack2.mainModule).not.toBeNull() + describe "::unloadPackage(name)", -> describe "when the package is active", -> it "throws an error", -> diff --git a/spec/package-spec.coffee b/spec/package-spec.coffee index f49d2ed7c..92218e749 100644 --- a/spec/package-spec.coffee +++ b/spec/package-spec.coffee @@ -1,6 +1,7 @@ path = require 'path' Package = require '../src/package' ThemePackage = require '../src/theme-package' +{mockLocalStorage} = require './spec-helper' describe "Package", -> build = (constructor, path) -> @@ -20,10 +21,7 @@ describe "Package", -> describe "when the package contains incompatible native modules", -> beforeEach -> - items = {} - spyOn(global.localStorage, 'setItem').andCallFake (key, item) -> items[key] = item; undefined - spyOn(global.localStorage, 'getItem').andCallFake (key) -> items[key] ? null - spyOn(global.localStorage, 'removeItem').andCallFake (key) -> delete items[key]; undefined + mockLocalStorage() it "does not activate it", -> packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-incompatible-native-module') @@ -55,10 +53,7 @@ describe "Package", -> describe "::rebuild()", -> beforeEach -> - items = {} - spyOn(global.localStorage, 'setItem').andCallFake (key, item) -> items[key] = item; undefined - spyOn(global.localStorage, 'getItem').andCallFake (key) -> items[key] ? null - spyOn(global.localStorage, 'removeItem').andCallFake (key) -> delete items[key]; undefined + mockLocalStorage() it "returns a promise resolving to the results of `apm rebuild`", -> packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-index') diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index f31c67298..67883511b 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -265,3 +265,9 @@ window.advanceClock = (delta=1) -> true callback() for callback in callbacks + +exports.mockLocalStorage = -> + items = {} + spyOn(global.localStorage, 'setItem').andCallFake (key, item) -> items[key] = item.toString(); undefined + spyOn(global.localStorage, 'getItem').andCallFake (key) -> items[key] ? null + spyOn(global.localStorage, 'removeItem').andCallFake (key) -> delete items[key]; undefined diff --git a/src/deserializer-manager.coffee b/src/deserializer-manager.coffee index 7f6cb0f65..3c73a0b02 100644 --- a/src/deserializer-manager.coffee +++ b/src/deserializer-manager.coffee @@ -39,6 +39,9 @@ class DeserializerManager delete @deserializers[deserializer.name] for deserializer in deserializers return + getDeserializerCount: -> + Object.keys(@deserializers).length + # Public: Deserialize the state and params. # # * `state` The state {Object} to deserialize. diff --git a/src/package.coffee b/src/package.coffee index f437d327a..5ff008ec7 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -98,7 +98,8 @@ class Package @metadata.deserializers? or @metadata.viewProviders? or @metadata.configSchema? or - @activationShouldBeDeferred() + @activationShouldBeDeferred() or + localStorage.getItem(@getCanDeferMainModuleRequireStorageKey()) is 'true' ) reset: -> @@ -426,7 +427,13 @@ class Package mainModulePath = @getMainModulePath() if fs.isFileSync(mainModulePath) @mainModuleRequired = true + + previousViewProviderCount = @viewRegistry.getViewProviderCount() + previousDeserializerCount = @deserializerManager.getDeserializerCount() @mainModule = require(mainModulePath) + if (@viewRegistry.getViewProviderCount() is previousViewProviderCount and + @deserializerManager.getDeserializerCount() is previousDeserializerCount) + localStorage.setItem(@getCanDeferMainModuleRequireStorageKey(), 'true') getMainModulePath: -> return @mainModulePath if @resolvedMainModulePath @@ -620,6 +627,9 @@ class Package electronVersion = process.versions['electron'] ? process.versions['atom-shell'] "installed-packages:#{@name}:#{@metadata.version}:electron-#{electronVersion}:incompatible-native-modules" + getCanDeferMainModuleRequireStorageKey: -> + "installed-packages:#{@name}:#{@metadata.version}:can-defer-main-module-require" + # Get the incompatible native modules that this package depends on. # This recurses through all dependencies and requires all modules that # contain a `.node` file. diff --git a/src/view-registry.coffee b/src/view-registry.coffee index e754a010b..ef7151353 100644 --- a/src/view-registry.coffee +++ b/src/view-registry.coffee @@ -106,6 +106,9 @@ class ViewRegistry new Disposable => @providers = @providers.filter (p) -> p isnt provider + getViewProviderCount: -> + @providers.length + # Essential: Get the view associated with an object in the workspace. # # If you're just *using* the workspace, you shouldn't need to access the view From f35dddee2f40a0a5edbd3c7afd0b1c19404ae3b6 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 23 Nov 2015 18:01:26 -0800 Subject: [PATCH 037/137] Reregister config schema when package is reactivated Signed-off-by: Nathan Sobo --- src/package.coffee | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/package.coffee b/src/package.coffee index 5ff008ec7..08b434583 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -85,7 +85,7 @@ class Package @loadMenus() @loadStylesheets() @loadDeserializers() - @registerConfigSchemaFromMetadata() + @configSchemaRegisteredOnLoad = @registerConfigSchemaFromMetadata() @settingsPromise = @loadSettings() if @shouldRequireMainModuleOnLoad() and not @mainModule? @requireMainModule() @@ -130,7 +130,7 @@ class Package activateNow: -> try @requireMainModule() unless @mainModule? - @registerConfigSchemaFromMainModule() + @configSchemaRegisteredOnActivate = @registerConfigSchemaFromMainModule() @registerViewProviders() @activateStylesheets() if @mainModule? and not @mainActivated @@ -146,16 +146,16 @@ class Package registerConfigSchemaFromMetadata: -> if configSchema = @metadata.configSchema @config.setSchema @name, {type: 'object', properties: configSchema} - @configSchemaRegistered = true + true + else + false registerConfigSchemaFromMainModule: -> - return if @configSchemaRegistered - - if @mainModule? + if @mainModule? and not @configSchemaRegisteredOnLoad if @mainModule.config? and typeof @mainModule.config is 'object' @config.setSchema @name, {type: 'object', properties: @mainModule.config} - - @configSchemaRegistered = true + return true + false activateStylesheets: -> return if @stylesheetsActivated @@ -382,6 +382,7 @@ class Package @activationPromise = null @resolveActivationPromise = null @activationCommandSubscriptions?.dispose() + @configSchemaRegisteredOnActivate = false @deactivateResources() @deactivateKeymaps() if @mainActivated From 7b976bc689e479995ca1ce40a5f2cc357aa5984a Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 24 Nov 2015 13:07:05 -0500 Subject: [PATCH 038/137] Don't cache me bro. --- build/tasks/publish-build-task.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/build/tasks/publish-build-task.coffee b/build/tasks/publish-build-task.coffee index d8dffd1ea..b375123d3 100644 --- a/build/tasks/publish-build-task.coffee +++ b/build/tasks/publish-build-task.coffee @@ -249,6 +249,7 @@ uploadAssets = (release, buildDir, assets, callback) -> ACL: 'public-read' Key: key Body: fs.createReadStream(assetPath) + CacheControl: 'max-age=0' s3.upload uploadParams, (error, data) -> if error? console.log("Upload release asset #{assetName} to S3 failed", error) From 338d429d48cc7491d507f4df2b7ac73dd79e3ee7 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 24 Nov 2015 15:41:28 -0500 Subject: [PATCH 039/137] REVERT ME: Hacks on hacks on hacks to test. --- build/tasks/publish-build-task.coffee | 22 +++++++++++++--------- build/tasks/set-version-task.coffee | 4 ++-- package.json | 2 +- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/build/tasks/publish-build-task.coffee b/build/tasks/publish-build-task.coffee index b375123d3..518ccc77e 100644 --- a/build/tasks/publish-build-task.coffee +++ b/build/tasks/publish-build-task.coffee @@ -37,8 +37,8 @@ module.exports = (gruntObject) -> isPrerelease = false when 'beta' isPrerelease = true - else - return + # else + # return doneCallback = @async() startTime = Date.now() @@ -55,12 +55,16 @@ module.exports = (gruntObject) -> zipAssets buildDir, assets, (error) -> return done(error) if error? - getAtomDraftRelease isPrerelease, channel, (error, release) -> - return done(error) if error? - assetNames = (asset.assetName for asset in assets) - deleteExistingAssets release, assetNames, (error) -> - return done(error) if error? - uploadAssets(release, buildDir, assets, done) + uploadAssets({tag_name: 'v1.1'}, buildDir, assets, done) + + # zipAssets buildDir, assets, (error) -> + # return done(error) if error? + # getAtomDraftRelease isPrerelease, channel, (error, release) -> + # return done(error) if error? + # assetNames = (asset.assetName for asset in assets) + # deleteExistingAssets release, assetNames, (error) -> + # return done(error) if error? + # uploadAssets(release, buildDir, assets, done) getAssets = -> {cp} = require('./task-helpers')(grunt) @@ -260,6 +264,6 @@ uploadAssets = (release, buildDir, assets, callback) -> tasks = [] for {assetName} in assets assetPath = path.join(buildDir, assetName) - tasks.push(uploadToReleases.bind(this, release, assetName, assetPath)) + # tasks.push(uploadToReleases.bind(this, release, assetName, assetPath)) tasks.push(uploadToS3.bind(this, release, assetName, assetPath)) async.parallel(tasks, callback) diff --git a/build/tasks/set-version-task.coffee b/build/tasks/set-version-task.coffee index 28abb6493..99c147c53 100644 --- a/build/tasks/set-version-task.coffee +++ b/build/tasks/set-version-task.coffee @@ -5,9 +5,9 @@ module.exports = (grunt) -> {spawn} = require('./task-helpers')(grunt) getVersion = (callback) -> - releasableBranches = ['stable', 'beta'] + releasableBranches = ['stable', 'beta', 'upload-to-s3'] channel = grunt.config.get('atom.channel') - shouldUseCommitHash = if channel in releasableBranches then false else true + shouldUseCommitHash = false # if channel in releasableBranches then false else true inRepository = fs.existsSync(path.resolve(__dirname, '..', '..', '.git')) {version} = require(path.join(grunt.config.get('atom.appDir'), 'package.json')) if shouldUseCommitHash and inRepository diff --git a/package.json b/package.json index 0ffc69221..2b563bf7c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "1.4.0-dev", + "version": "1.1.0-dev", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From cfcf397546081aaf5237d4a8b465c9252c54f20f Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Thu, 19 Nov 2015 21:46:54 -0500 Subject: [PATCH 040/137] :arrow_up: notifications@0.62.1 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index c2678a21a..9c469f3f5 100644 --- a/package.json +++ b/package.json @@ -97,9 +97,9 @@ "keybinding-resolver": "0.33.0", "line-ending-selector": "0.3.0", "link": "0.31.0", - "markdown-preview": "0.156.1", + "markdown-preview": "0.156.2", "metrics": "0.53.0", - "notifications": "0.61.0", + "notifications": "0.62.1", "open-on-github": "0.40.0", "package-generator": "0.41.0", "release-notes": "0.53.0", From ce60e07d7c65cada5c20e767e3e687b5d7e79ca4 Mon Sep 17 00:00:00 2001 From: Wliu Date: Tue, 24 Nov 2015 15:54:06 -0500 Subject: [PATCH 041/137] Revert ":arrow_up: notifications@0.62.1" This reverts commit cfcf397546081aaf5237d4a8b465c9252c54f20f. --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 9c469f3f5..c2678a21a 100644 --- a/package.json +++ b/package.json @@ -97,9 +97,9 @@ "keybinding-resolver": "0.33.0", "line-ending-selector": "0.3.0", "link": "0.31.0", - "markdown-preview": "0.156.2", + "markdown-preview": "0.156.1", "metrics": "0.53.0", - "notifications": "0.62.1", + "notifications": "0.61.0", "open-on-github": "0.40.0", "package-generator": "0.41.0", "release-notes": "0.53.0", From d1d0ca1355487d87829684b8823955af2de9485e Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Thu, 19 Nov 2015 21:46:54 -0500 Subject: [PATCH 042/137] :arrow_up: notifications@0.62.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c2678a21a..40ffe8b81 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "link": "0.31.0", "markdown-preview": "0.156.1", "metrics": "0.53.0", - "notifications": "0.61.0", + "notifications": "0.62.1", "open-on-github": "0.40.0", "package-generator": "0.41.0", "release-notes": "0.53.0", From b391671a188c472051382b507a81043153ff3581 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Thu, 19 Nov 2015 16:06:22 -0500 Subject: [PATCH 043/137] :arrow_up: language-coffee-script@0.45.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 40ffe8b81..008ea6b77 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "wrap-guide": "0.38.1", "language-c": "0.49.0", "language-clojure": "0.18.0", - "language-coffee-script": "0.43.0", + "language-coffee-script": "0.45.0", "language-csharp": "0.11.0", "language-css": "0.35.0", "language-gfm": "0.81.0", From 4d21f1418efaefea003161dd6010071ee0a3ac7d Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 24 Nov 2015 16:08:01 -0500 Subject: [PATCH 044/137] REVERT ME: Test again --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2b563bf7c..bc4359ae1 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "1.1.0-dev", + "version": "1.2.0-dev", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 212afba8b1ca6fd25034a0728376bb366a53a340 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 24 Nov 2015 17:07:05 -0500 Subject: [PATCH 045/137] Revert "REVERT ME: Test again" This reverts commit 4d21f1418efaefea003161dd6010071ee0a3ac7d. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bc4359ae1..2b563bf7c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "1.2.0-dev", + "version": "1.1.0-dev", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 233e6e47818ba740c6da3a0be26608313bd556c1 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 24 Nov 2015 17:07:09 -0500 Subject: [PATCH 046/137] Revert "REVERT ME: Hacks on hacks on hacks to test." This reverts commit 338d429d48cc7491d507f4df2b7ac73dd79e3ee7. --- build/tasks/publish-build-task.coffee | 22 +++++++++------------- build/tasks/set-version-task.coffee | 4 ++-- package.json | 2 +- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/build/tasks/publish-build-task.coffee b/build/tasks/publish-build-task.coffee index 518ccc77e..b375123d3 100644 --- a/build/tasks/publish-build-task.coffee +++ b/build/tasks/publish-build-task.coffee @@ -37,8 +37,8 @@ module.exports = (gruntObject) -> isPrerelease = false when 'beta' isPrerelease = true - # else - # return + else + return doneCallback = @async() startTime = Date.now() @@ -55,16 +55,12 @@ module.exports = (gruntObject) -> zipAssets buildDir, assets, (error) -> return done(error) if error? - uploadAssets({tag_name: 'v1.1'}, buildDir, assets, done) - - # zipAssets buildDir, assets, (error) -> - # return done(error) if error? - # getAtomDraftRelease isPrerelease, channel, (error, release) -> - # return done(error) if error? - # assetNames = (asset.assetName for asset in assets) - # deleteExistingAssets release, assetNames, (error) -> - # return done(error) if error? - # uploadAssets(release, buildDir, assets, done) + getAtomDraftRelease isPrerelease, channel, (error, release) -> + return done(error) if error? + assetNames = (asset.assetName for asset in assets) + deleteExistingAssets release, assetNames, (error) -> + return done(error) if error? + uploadAssets(release, buildDir, assets, done) getAssets = -> {cp} = require('./task-helpers')(grunt) @@ -264,6 +260,6 @@ uploadAssets = (release, buildDir, assets, callback) -> tasks = [] for {assetName} in assets assetPath = path.join(buildDir, assetName) - # tasks.push(uploadToReleases.bind(this, release, assetName, assetPath)) + tasks.push(uploadToReleases.bind(this, release, assetName, assetPath)) tasks.push(uploadToS3.bind(this, release, assetName, assetPath)) async.parallel(tasks, callback) diff --git a/build/tasks/set-version-task.coffee b/build/tasks/set-version-task.coffee index 99c147c53..28abb6493 100644 --- a/build/tasks/set-version-task.coffee +++ b/build/tasks/set-version-task.coffee @@ -5,9 +5,9 @@ module.exports = (grunt) -> {spawn} = require('./task-helpers')(grunt) getVersion = (callback) -> - releasableBranches = ['stable', 'beta', 'upload-to-s3'] + releasableBranches = ['stable', 'beta'] channel = grunt.config.get('atom.channel') - shouldUseCommitHash = false # if channel in releasableBranches then false else true + shouldUseCommitHash = if channel in releasableBranches then false else true inRepository = fs.existsSync(path.resolve(__dirname, '..', '..', '.git')) {version} = require(path.join(grunt.config.get('atom.appDir'), 'package.json')) if shouldUseCommitHash and inRepository diff --git a/package.json b/package.json index 2b563bf7c..0ffc69221 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "1.1.0-dev", + "version": "1.4.0-dev", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From aecc2598f9d3af978334df37df5badddc8b512d0 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 24 Nov 2015 15:14:39 -0800 Subject: [PATCH 047/137] Restore private activateConfig method to fix settings-view --- src/package.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/package.coffee b/src/package.coffee index 08b434583..b831b3c55 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -157,6 +157,9 @@ class Package return true false + # TODO: Remove. Settings view calls this method currently. + activateConfig: -> @registerConfigSchemaFromMainModule() + activateStylesheets: -> return if @stylesheetsActivated From aac52b70206ac4fc2b4224402a23b46c280f7d95 Mon Sep 17 00:00:00 2001 From: Ross Allen Date: Tue, 24 Nov 2015 15:45:11 -0800 Subject: [PATCH 048/137] Correct config.coffee doc references to `scope` The scope selector is referred to with the key `scope` on the options object, not `scopeDescriptor` as the current docs claim. Reference `scope` correctly. Mark `options` as optional for `::observe` because the arguments collection is checked for length, and a length of 2 assumes the second argument is `callback`. `options` is actually optional. --- src/config.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/config.coffee b/src/config.coffee index 489e16016..d2759fcb4 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -381,8 +381,8 @@ class Config # ``` # # * `keyPath` {String} name of the key to observe - # * `options` {Object} - # * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from + # * `options` (optional) {Object} + # * `scope` (optional) {ScopeDescriptor} describing a path from # the root of the syntax tree to a token. Get one by calling # {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples. # See [the scopes docs](https://atom.io/docs/latest/behind-atom-scoped-settings-scopes-and-scope-descriptors) @@ -412,8 +412,8 @@ class Config # # * `keyPath` (optional) {String} name of the key to observe. Must be # specified if `scopeDescriptor` is specified. - # * `optional` (optional) {Object} - # * `scopeDescriptor` (optional) {ScopeDescriptor} describing a path from + # * `options` (optional) {Object} + # * `scope` (optional) {ScopeDescriptor} describing a path from # the root of the syntax tree to a token. Get one by calling # {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples. # See [the scopes docs](https://atom.io/docs/latest/behind-atom-scoped-settings-scopes-and-scope-descriptors) From 5dfd765bcf6328f0edaa870ce0b59202ae95689b Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 26 Nov 2015 10:39:47 +0100 Subject: [PATCH 049/137] Do not override user-defined keymaps when reloading packages --- spec/package-manager-spec.coffee | 51 ++++++++++++++++++++++++++++++++ src/keymap-extensions.coffee | 2 +- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 4b5f3c26d..19f9b0648 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -1,6 +1,9 @@ path = require 'path' Package = require '../src/package' +temp = require 'temp' +fs = require 'fs-plus' {Disposable} = require 'atom' +{buildKeydownEvent} = require '../src/keymap-extensions' describe "PackageManager", -> workspaceElement = null @@ -456,6 +459,54 @@ describe "PackageManager", -> atom.config.set("core.packagesWithKeymapsDisabled", []) expect(atom.keymaps.findKeyBindings(keystrokes: 'ctrl-z', target: element1)[0].command).toBe 'keymap-1' + describe "when the package is de-activated and re-activated", -> + [element, events, userKeymapPath] = [] + + beforeEach -> + userKeymapPath = path.join(temp.path(), "user-keymaps.cson") + spyOn(atom.keymaps, "getUserKeymapPath").andReturn(userKeymapPath) + + element = createTestElement('test-1') + jasmine.attachToDOM(element) + + events = [] + element.addEventListener 'user-command', (e) -> events.push(e) + element.addEventListener 'test-1', (e) -> events.push(e) + + afterEach -> + element.remove() + + # Avoid leaking user keymap subscription + atom.keymaps.watchSubscriptions[userKeymapPath].dispose() + delete atom.keymaps.watchSubscriptions[userKeymapPath] + + it "doesn't override user-defined keymaps", -> + fs.writeFileSync userKeymapPath, """ + ".test-1": + "ctrl-z": "user-command" + """ + atom.keymaps.loadUserKeymap() + + waitsForPromise -> + atom.packages.activatePackage("package-with-keymaps") + + runs -> + atom.keymaps.handleKeyboardEvent(buildKeydownEvent("z", ctrl: true, target: element)) + + expect(events.length).toBe(1) + expect(events[0].type).toBe("user-command") + + atom.packages.deactivatePackage("package-with-keymaps") + + waitsForPromise -> + atom.packages.activatePackage("package-with-keymaps") + + runs -> + atom.keymaps.handleKeyboardEvent(buildKeydownEvent("z", ctrl: true, target: element)) + + expect(events.length).toBe(2) + expect(events[1].type).toBe("user-command") + describe "menu loading", -> beforeEach -> atom.contextMenu.definitions = [] diff --git a/src/keymap-extensions.coffee b/src/keymap-extensions.coffee index 82f2e8b99..b5c3964f9 100644 --- a/src/keymap-extensions.coffee +++ b/src/keymap-extensions.coffee @@ -32,7 +32,7 @@ KeymapManager::loadUserKeymap = -> return unless fs.isFileSync(userKeymapPath) try - @loadKeymap(userKeymapPath, watch: true, suppressErrors: true) + @loadKeymap(userKeymapPath, watch: true, suppressErrors: true, priority: 100) catch error if error.message.indexOf('Unable to watch path') > -1 message = """ From d23a28538497cc7b6bb40874f07633b6761efa5d Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Sun, 29 Nov 2015 11:03:59 -0500 Subject: [PATCH 050/137] :arrow_up: language-coffee-script@0.46.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 47521c4ea..4eb575535 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "wrap-guide": "0.38.1", "language-c": "0.50.1", "language-clojure": "0.18.0", - "language-coffee-script": "0.45.0", + "language-coffee-script": "0.46.0", "language-csharp": "0.11.0", "language-css": "0.35.1", "language-gfm": "0.81.0", From 9bd81d00e9d82e73c8a65d7ab29b217968cf4daf Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 30 Nov 2015 10:16:13 -0500 Subject: [PATCH 051/137] Don't use a zero max age anymore. --- build/tasks/publish-build-task.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/build/tasks/publish-build-task.coffee b/build/tasks/publish-build-task.coffee index b375123d3..d8dffd1ea 100644 --- a/build/tasks/publish-build-task.coffee +++ b/build/tasks/publish-build-task.coffee @@ -249,7 +249,6 @@ uploadAssets = (release, buildDir, assets, callback) -> ACL: 'public-read' Key: key Body: fs.createReadStream(assetPath) - CacheControl: 'max-age=0' s3.upload uploadParams, (error, data) -> if error? console.log("Upload release asset #{assetName} to S3 failed", error) From 1340597c5f78f1bdea7c0ba06a4090b8d3f13b04 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 30 Nov 2015 11:09:45 -0500 Subject: [PATCH 052/137] Revert "Revert "REVERT ME: Hacks on hacks on hacks to test."" This reverts commit 233e6e47818ba740c6da3a0be26608313bd556c1. --- build/tasks/publish-build-task.coffee | 22 +++++++++++++--------- build/tasks/set-version-task.coffee | 4 ++-- package.json | 2 +- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/build/tasks/publish-build-task.coffee b/build/tasks/publish-build-task.coffee index d8dffd1ea..ea1188350 100644 --- a/build/tasks/publish-build-task.coffee +++ b/build/tasks/publish-build-task.coffee @@ -37,8 +37,8 @@ module.exports = (gruntObject) -> isPrerelease = false when 'beta' isPrerelease = true - else - return + # else + # return doneCallback = @async() startTime = Date.now() @@ -55,12 +55,16 @@ module.exports = (gruntObject) -> zipAssets buildDir, assets, (error) -> return done(error) if error? - getAtomDraftRelease isPrerelease, channel, (error, release) -> - return done(error) if error? - assetNames = (asset.assetName for asset in assets) - deleteExistingAssets release, assetNames, (error) -> - return done(error) if error? - uploadAssets(release, buildDir, assets, done) + uploadAssets({tag_name: 'v1.1'}, buildDir, assets, done) + + # zipAssets buildDir, assets, (error) -> + # return done(error) if error? + # getAtomDraftRelease isPrerelease, channel, (error, release) -> + # return done(error) if error? + # assetNames = (asset.assetName for asset in assets) + # deleteExistingAssets release, assetNames, (error) -> + # return done(error) if error? + # uploadAssets(release, buildDir, assets, done) getAssets = -> {cp} = require('./task-helpers')(grunt) @@ -259,6 +263,6 @@ uploadAssets = (release, buildDir, assets, callback) -> tasks = [] for {assetName} in assets assetPath = path.join(buildDir, assetName) - tasks.push(uploadToReleases.bind(this, release, assetName, assetPath)) + # tasks.push(uploadToReleases.bind(this, release, assetName, assetPath)) tasks.push(uploadToS3.bind(this, release, assetName, assetPath)) async.parallel(tasks, callback) diff --git a/build/tasks/set-version-task.coffee b/build/tasks/set-version-task.coffee index 28abb6493..99c147c53 100644 --- a/build/tasks/set-version-task.coffee +++ b/build/tasks/set-version-task.coffee @@ -5,9 +5,9 @@ module.exports = (grunt) -> {spawn} = require('./task-helpers')(grunt) getVersion = (callback) -> - releasableBranches = ['stable', 'beta'] + releasableBranches = ['stable', 'beta', 'upload-to-s3'] channel = grunt.config.get('atom.channel') - shouldUseCommitHash = if channel in releasableBranches then false else true + shouldUseCommitHash = false # if channel in releasableBranches then false else true inRepository = fs.existsSync(path.resolve(__dirname, '..', '..', '.git')) {version} = require(path.join(grunt.config.get('atom.appDir'), 'package.json')) if shouldUseCommitHash and inRepository diff --git a/package.json b/package.json index 4eb575535..d24638a73 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "1.4.0-dev", + "version": "1.1.0-dev", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 1fd7267f10d693bdfd1260f5694069d8399f62f8 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 30 Nov 2015 11:34:08 -0500 Subject: [PATCH 053/137] REVERT ME: Tests gonna test --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d24638a73..ed33be9a6 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "1.1.0-dev", + "version": "1.2.0-dev", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 9fabac6fde4dd25357ed7998af530e2b77f44f59 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 30 Nov 2015 12:27:05 -0500 Subject: [PATCH 054/137] Revert "REVERT ME: Tests gonna test" This reverts commit 1fd7267f10d693bdfd1260f5694069d8399f62f8. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ed33be9a6..d24638a73 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "1.2.0-dev", + "version": "1.1.0-dev", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From d223e0738977e5071ba946fe8713151d9f02c4ed Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 30 Nov 2015 12:27:09 -0500 Subject: [PATCH 055/137] Revert "Revert "Revert "REVERT ME: Hacks on hacks on hacks to test.""" This reverts commit 1340597c5f78f1bdea7c0ba06a4090b8d3f13b04. --- build/tasks/publish-build-task.coffee | 22 +++++++++------------- build/tasks/set-version-task.coffee | 4 ++-- package.json | 2 +- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/build/tasks/publish-build-task.coffee b/build/tasks/publish-build-task.coffee index ea1188350..d8dffd1ea 100644 --- a/build/tasks/publish-build-task.coffee +++ b/build/tasks/publish-build-task.coffee @@ -37,8 +37,8 @@ module.exports = (gruntObject) -> isPrerelease = false when 'beta' isPrerelease = true - # else - # return + else + return doneCallback = @async() startTime = Date.now() @@ -55,16 +55,12 @@ module.exports = (gruntObject) -> zipAssets buildDir, assets, (error) -> return done(error) if error? - uploadAssets({tag_name: 'v1.1'}, buildDir, assets, done) - - # zipAssets buildDir, assets, (error) -> - # return done(error) if error? - # getAtomDraftRelease isPrerelease, channel, (error, release) -> - # return done(error) if error? - # assetNames = (asset.assetName for asset in assets) - # deleteExistingAssets release, assetNames, (error) -> - # return done(error) if error? - # uploadAssets(release, buildDir, assets, done) + getAtomDraftRelease isPrerelease, channel, (error, release) -> + return done(error) if error? + assetNames = (asset.assetName for asset in assets) + deleteExistingAssets release, assetNames, (error) -> + return done(error) if error? + uploadAssets(release, buildDir, assets, done) getAssets = -> {cp} = require('./task-helpers')(grunt) @@ -263,6 +259,6 @@ uploadAssets = (release, buildDir, assets, callback) -> tasks = [] for {assetName} in assets assetPath = path.join(buildDir, assetName) - # tasks.push(uploadToReleases.bind(this, release, assetName, assetPath)) + tasks.push(uploadToReleases.bind(this, release, assetName, assetPath)) tasks.push(uploadToS3.bind(this, release, assetName, assetPath)) async.parallel(tasks, callback) diff --git a/build/tasks/set-version-task.coffee b/build/tasks/set-version-task.coffee index 99c147c53..28abb6493 100644 --- a/build/tasks/set-version-task.coffee +++ b/build/tasks/set-version-task.coffee @@ -5,9 +5,9 @@ module.exports = (grunt) -> {spawn} = require('./task-helpers')(grunt) getVersion = (callback) -> - releasableBranches = ['stable', 'beta', 'upload-to-s3'] + releasableBranches = ['stable', 'beta'] channel = grunt.config.get('atom.channel') - shouldUseCommitHash = false # if channel in releasableBranches then false else true + shouldUseCommitHash = if channel in releasableBranches then false else true inRepository = fs.existsSync(path.resolve(__dirname, '..', '..', '.git')) {version} = require(path.join(grunt.config.get('atom.appDir'), 'package.json')) if shouldUseCommitHash and inRepository diff --git a/package.json b/package.json index d24638a73..4eb575535 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "1.1.0-dev", + "version": "1.4.0-dev", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From a2f14685fcdfa2970db7658e97f046c9493c2a0a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 30 Nov 2015 10:15:16 -0800 Subject: [PATCH 056/137] :arrow_up: autocomplete-snippets --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b488ba3ce..31086502b 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "autocomplete-css": "0.11.0", "autocomplete-html": "0.7.2", "autocomplete-plus": "2.23.0", - "autocomplete-snippets": "1.8.0", + "autocomplete-snippets": "1.9.0", "autoflow": "0.26.0", "autosave": "0.23.0", "background-tips": "0.26.0", From 6cd31f94e9a1f5cca8ea954954ad2f8df808b036 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 30 Nov 2015 13:21:25 -0500 Subject: [PATCH 057/137] Use logError instead of console.log. --- build/tasks/publish-build-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/publish-build-task.coffee b/build/tasks/publish-build-task.coffee index d8dffd1ea..4f8df6336 100644 --- a/build/tasks/publish-build-task.coffee +++ b/build/tasks/publish-build-task.coffee @@ -251,7 +251,7 @@ uploadAssets = (release, buildDir, assets, callback) -> Body: fs.createReadStream(assetPath) s3.upload uploadParams, (error, data) -> if error? - console.log("Upload release asset #{assetName} to S3 failed", error) + logError("Upload release asset #{assetName} to S3 failed", error) callback(error) else callback(null, release) From 228e67838c7705c9e1fca19d84ba8a6bf7000fbd Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 30 Nov 2015 10:51:03 -0800 Subject: [PATCH 058/137] Suppress false coffeelint error --- spec/workspace-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index e150761af..0587a2629 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -661,7 +661,7 @@ describe "Workspace", -> describe "::isTextEditor(obj)", -> it "returns true when the passed object is an instance of `TextEditor`", -> expect(workspace.isTextEditor(atom.workspace.buildTextEditor())).toBe(true) - expect(workspace.isTextEditor({getText: ->})).toBe(false) + expect(workspace.isTextEditor({getText: -> null})).toBe(false) expect(workspace.isTextEditor(null)).toBe(false) expect(workspace.isTextEditor(undefined)).toBe(false) From f139992585fddd88ffdea3513c64503db6be0516 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 30 Nov 2015 10:47:40 -0800 Subject: [PATCH 059/137] Avoid infinite recursion in Error.prepareStackTrace Previously, prepareStackTraceWithStackAssignment could end up calling itself when third-party code assigned Error.prepareStackTrace back to its original value. Now, we short-circuit this process if the rawStack property has already been assigned. Signed-off-by: Max Brunsfeld --- spec/compile-cache-spec.coffee | 23 ++++++++++++++++++++++- src/compile-cache.js | 8 ++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/spec/compile-cache-spec.coffee b/spec/compile-cache-spec.coffee index 8a6cc214e..848da6b49 100644 --- a/spec/compile-cache-spec.coffee +++ b/spec/compile-cache-spec.coffee @@ -81,6 +81,27 @@ describe 'CompileCache', -> waits(1) runs -> error = new Error("Oops again") - console.log error.stack expect(error.stack).toContain('compile-cache-spec.coffee') expect(Array.isArray(error.getRawStack())).toBe true + + it 'does not infinitely loop when the original prepareStackTrace value is reassigned', -> + originalPrepareStackTrace = Error.prepareStackTrace + + Error.prepareStackTrace = -> 'a-stack-trace' + Error.prepareStackTrace = originalPrepareStackTrace + + error = new Error('Oops') + expect(error.stack).toContain('compile-cache-spec.coffee') + expect(Array.isArray(error.getRawStack())).toBe true + + it 'does not infinitely loop when the assigned prepareStackTrace calls the original prepareStackTrace', -> + originalPrepareStackTrace = Error.prepareStackTrace + + Error.prepareStackTrace = (error, stack) -> + error.foo = 'bar' + originalPrepareStackTrace(error, stack) + + error = new Error('Oops') + expect(error.stack).toContain('compile-cache-spec.coffee') + expect(error.foo).toBe('bar') + expect(Array.isArray(error.getRawStack())).toBe true diff --git a/src/compile-cache.js b/src/compile-cache.js index bedbd2549..8da229a50 100644 --- a/src/compile-cache.js +++ b/src/compile-cache.js @@ -163,8 +163,12 @@ var prepareStackTraceWithSourceMapping = Error.prepareStackTrace let prepareStackTrace = prepareStackTraceWithSourceMapping function prepareStackTraceWithRawStackAssignment (error, frames) { - error.rawStack = frames - return prepareStackTrace(error, frames) + if (error.rawStack) { // avoid infinite recursion + return prepareStackTraceWithSourceMapping(error, frames) + } else { + error.rawStack = frames + return prepareStackTrace(error, frames) + } } Object.defineProperty(Error, 'prepareStackTrace', { From d34fec20d046dcde0201d5bd1260380390222b73 Mon Sep 17 00:00:00 2001 From: Josh Abernathy Date: Mon, 30 Nov 2015 16:00:30 -0500 Subject: [PATCH 060/137] Merge pull request #9729 from atom/upload-to-s3 Upload releases to s3 --- build/package.json | 1 + build/tasks/publish-build-task.coffee | 35 ++++++++++++++++++++++++--- script/cibuild | 4 +++ script/cibuild-atom-linux | 3 +++ script/cibuild-atom-rpm | 3 +++ 5 files changed, 43 insertions(+), 3 deletions(-) diff --git a/build/package.json b/build/package.json index 2ce92de17..3e97d57d1 100644 --- a/build/package.json +++ b/build/package.json @@ -8,6 +8,7 @@ "dependencies": { "asar": "^0.8.0", "async": "~0.2.9", + "aws-sdk": "^2.2.18", "donna": "^1.0.13", "formidable": "~1.0.14", "fs-plus": "2.x", diff --git a/build/tasks/publish-build-task.coffee b/build/tasks/publish-build-task.coffee index fc96121ae..4f8df6336 100644 --- a/build/tasks/publish-build-task.coffee +++ b/build/tasks/publish-build-task.coffee @@ -6,6 +6,7 @@ async = require 'async' fs = require 'fs-plus' GitHub = require 'github-releases' request = require 'request' +AWS = require 'aws-sdk' grunt = null @@ -210,7 +211,7 @@ deleteExistingAssets = (release, assetNames, callback) -> async.parallel(tasks, callback) uploadAssets = (release, buildDir, assets, callback) -> - upload = (release, assetName, assetPath, callback) -> + uploadToReleases = (release, assetName, assetPath, callback) -> options = uri: release.upload_url.replace(/\{.*$/, "?name=#{assetName}") method: 'POST' @@ -221,15 +222,43 @@ uploadAssets = (release, buildDir, assets, callback) -> assetRequest = request options, (error, response, body='') -> if error? or response.statusCode >= 400 - logError("Upload release asset #{assetName} failed", error, body) + logError("Upload release asset #{assetName} to Releases failed", error, body) callback(error ? new Error(response.statusCode)) else callback(null, release) fs.createReadStream(assetPath).pipe(assetRequest) + uploadToS3 = (release, assetName, assetPath, callback) -> + s3Key = process.env.BUILD_ATOM_RELEASES_S3_KEY + s3Secret = process.env.BUILD_ATOM_RELEASES_S3_SECRET + s3Bucket = process.env.BUILD_ATOM_RELEASES_S3_BUCKET + + unless s3Key and s3Secret and s3Bucket + callback(new Error('BUILD_ATOM_RELEASES_S3_KEY, BUILD_ATOM_RELEASES_S3_SECRET, and BUILD_ATOM_RELEASES_S3_BUCKET environment variables must be set.')) + return + + s3Info = + accessKeyId: s3Key + secretAccessKey: s3Secret + s3 = new AWS.S3 s3Info + + key = "releases/#{release.tag_name}/#{assetName}" + uploadParams = + Bucket: s3Bucket + ACL: 'public-read' + Key: key + Body: fs.createReadStream(assetPath) + s3.upload uploadParams, (error, data) -> + if error? + logError("Upload release asset #{assetName} to S3 failed", error) + callback(error) + else + callback(null, release) + tasks = [] for {assetName} in assets assetPath = path.join(buildDir, assetName) - tasks.push(upload.bind(this, release, assetName, assetPath)) + tasks.push(uploadToReleases.bind(this, release, assetName, assetPath)) + tasks.push(uploadToS3.bind(this, release, assetName, assetPath)) async.parallel(tasks, callback) diff --git a/script/cibuild b/script/cibuild index c1aedddc8..8b8e64c12 100755 --- a/script/cibuild +++ b/script/cibuild @@ -38,6 +38,10 @@ function setEnvironmentVariables() { process.env.CC = 'clang'; process.env.CXX = 'clang++'; process.env.npm_config_clang = '1'; + } else if (process.platform === 'win32') { + process.env.BUILD_ATOM_RELEASES_S3_KEY = process.env.BUILD_ATOM_WIN_RELEASES_S3_KEY + process.env.BUILD_ATOM_RELEASES_S3_SECRET = process.env.BUILD_ATOM_WIN_RELEASES_S3_SECRET + process.env.BUILD_ATOM_RELEASES_S3_BUCKET = process.env.BUILD_ATOM_WIN_RELEASES_S3_BUCKET } } diff --git a/script/cibuild-atom-linux b/script/cibuild-atom-linux index c4e957189..2c3395608 100755 --- a/script/cibuild-atom-linux +++ b/script/cibuild-atom-linux @@ -3,6 +3,9 @@ set -e export ATOM_ACCESS_TOKEN=$BUILD_ATOM_LINUX_ACCESS_TOKEN +export BUILD_ATOM_RELEASES_S3_KEY=$BUILD_ATOM_LINUX_RELEASES_S3_KEY +export BUILD_ATOM_RELEASES_S3_SECRET=$BUILD_ATOM_LINUX_RELEASES_S3_SECRET +export BUILD_ATOM_RELEASES_S3_BUCKET=$BUILD_ATOM_LINUX_RELEASES_S3_BUCKET if [ -d /usr/local/share/nodenv ]; then export NODENV_ROOT=/usr/local/share/nodenv diff --git a/script/cibuild-atom-rpm b/script/cibuild-atom-rpm index a861a068b..2faa89347 100755 --- a/script/cibuild-atom-rpm +++ b/script/cibuild-atom-rpm @@ -8,5 +8,8 @@ docker run \ --env JANKY_SHA1="$JANKY_SHA1" \ --env JANKY_BRANCH="$JANKY_BRANCH" \ --env ATOM_ACCESS_TOKEN="$BUILD_ATOM_RPM_ACCESS_TOKEN" \ + --env BUILD_ATOM_RELEASES_S3_KEY="$BUILD_ATOM_RPM_RELEASES_S3_KEY" \ + --env BUILD_ATOM_RELEASES_S3_SECRET="$BUILD_ATOM_RPM_RELEASES_S3_SECRET" \ + --env BUILD_ATOM_RELEASES_S3_BUCKET="$BUILD_ATOM_RPM_RELEASES_S3_BUCKET" \ atom-rpm /atom/script/rpmbuild docker rmi atom-rpm From 8697bdaf674885cdbe39a4cffdf6f71aca529b7a Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 30 Nov 2015 17:11:13 -0500 Subject: [PATCH 061/137] 1.3.0-beta7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 008ea6b77..66d85ffad 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "1.3.0-beta6", + "version": "1.3.0-beta7", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 3836b5cbaac4acb6251c402a178ee8018ccffa4b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Nov 2015 16:14:37 -0800 Subject: [PATCH 062/137] :arrow_up: language-make@0.21 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1a5aa9437..006984454 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,7 @@ "language-javascript": "0.102.2", "language-json": "0.17.1", "language-less": "0.29.0", - "language-make": "0.20.0", + "language-make": "0.21.0", "language-mustache": "0.13.0", "language-objective-c": "0.15.0", "language-perl": "0.31.0", From c26d2be959a1941f51895330cac28b6328370a2e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Nov 2015 16:43:33 -0800 Subject: [PATCH 063/137] :arrow_up: markdown-preview@0.157 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 006984454..cf099f2d3 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "keybinding-resolver": "0.33.0", "line-ending-selector": "0.3.0", "link": "0.31.0", - "markdown-preview": "0.156.2", + "markdown-preview": "0.157.0", "metrics": "0.53.1", "notifications": "0.62.1", "open-on-github": "0.40.0", From a69f5d54683c3dc86d09dea046016d52d9959c17 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Nov 2015 16:46:00 -0800 Subject: [PATCH 064/137] :arrow_up: language-shellscript@0.21 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cf099f2d3..67a51bbc3 100644 --- a/package.json +++ b/package.json @@ -140,7 +140,7 @@ "language-ruby": "0.64.1", "language-ruby-on-rails": "0.24.0", "language-sass": "0.44.1", - "language-shellscript": "0.20.0", + "language-shellscript": "0.21.0", "language-source": "0.9.0", "language-sql": "0.19.0", "language-text": "0.7.0", From d0cbcdf0703ff570332f32363502c266c1741faa Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Nov 2015 17:03:10 -0800 Subject: [PATCH 065/137] :arrow_up: language-javascript@0.103.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 67a51bbc3..05f14ceaf 100644 --- a/package.json +++ b/package.json @@ -127,7 +127,7 @@ "language-html": "0.42.0", "language-hyperlink": "0.15.0", "language-java": "0.17.0", - "language-javascript": "0.102.2", + "language-javascript": "0.103.0", "language-json": "0.17.1", "language-less": "0.29.0", "language-make": "0.21.0", From 73e83e83ac77b56afc066380dee057691da2f537 Mon Sep 17 00:00:00 2001 From: Wliu Date: Mon, 30 Nov 2015 20:12:16 -0500 Subject: [PATCH 066/137] Entirely :fire: shortcut creation --- build/Gruntfile.coffee | 3 +-- build/tasks/install-task.coffee | 4 ---- docs/build-instructions/windows.md | 1 - script/create-shortcut.cmd | 23 ----------------------- 4 files changed, 1 insertion(+), 30 deletions(-) delete mode 100644 script/create-shortcut.cmd diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index cb6ff0c1e..8dd1c573b 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -37,7 +37,6 @@ module.exports = (grunt) -> buildDir ?= path.join(os.tmpdir(), 'atom-build') buildDir = path.resolve(buildDir) disableAutoUpdate = grunt.option('no-auto-update') ? false - disableShortcut = grunt.option('no-shortcut') ? false channel = grunt.option('channel') releasableBranches = ['stable', 'beta'] @@ -180,7 +179,7 @@ module.exports = (grunt) -> pkg: grunt.file.readJSON('package.json') atom: { - appName, channel, metadata, disableAutoUpdate, disableShortcut, + appName, channel, metadata, disableAutoUpdate, appFileName, apmFileName, appDir, buildDir, contentsDir, installDir, shellAppDir, symbolsDir, } diff --git a/build/tasks/install-task.coffee b/build/tasks/install-task.coffee index ee38b1582..2d9054385 100644 --- a/build/tasks/install-task.coffee +++ b/build/tasks/install-task.coffee @@ -20,10 +20,6 @@ module.exports = (grunt) -> copyFolder = path.resolve 'script', 'copy-folder.cmd' if runas('cmd', ['/c', copyFolder, shellAppDir, installDir], admin: true) isnt 0 grunt.log.error("Failed to copy #{shellAppDir} to #{installDir}") - - unless grunt.config.get('atom.disableShortcut') - createShortcut = path.resolve 'script', 'create-shortcut.cmd' - runas('cmd', ['/c', createShortcut, path.join(installDir, 'atom.exe'), appName]) else if process.platform is 'darwin' rm installDir mkdir path.dirname(installDir) diff --git a/docs/build-instructions/windows.md b/docs/build-instructions/windows.md index fa7c32148..debdd6570 100644 --- a/docs/build-instructions/windows.md +++ b/docs/build-instructions/windows.md @@ -34,7 +34,6 @@ These instructions will assume the use of Git Shell. * `--install-dir` - Creates the final built application in this directory. * `--build-dir` - Build the application in this directory. * `--verbose` - Verbose mode. A lot more information output. - * `--no-shortcut` - Don't create a desktop shortcut. ## Why do I have to use GitHub Desktop? diff --git a/script/create-shortcut.cmd b/script/create-shortcut.cmd deleted file mode 100644 index ca295d434..000000000 --- a/script/create-shortcut.cmd +++ /dev/null @@ -1,23 +0,0 @@ -@echo off - -set USAGE=Usage: %0 source name-on-desktop - -if [%1] == [] ( - echo %USAGE% - exit 1 -) -if [%2] == [] ( - echo %USAGE% - exit 2 -) - -set SCRIPT="%TEMP%\%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%.vbs" - -echo Set oWS = WScript.CreateObject("WScript.Shell") >> %SCRIPT% -echo sLinkFile = "%USERPROFILE%\Desktop\%2.lnk" >> %SCRIPT% -echo Set oLink = oWS.CreateShortcut(sLinkFile) >> %SCRIPT% -echo oLink.TargetPath = %1 >> %SCRIPT% -echo oLink.Save >> %SCRIPT% - -cscript /nologo %SCRIPT% -del %SCRIPT% From 7c9d32d8d62abbcd8a24bc2a3a1ae9690c2693d9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 30 Nov 2015 17:26:23 -0800 Subject: [PATCH 067/137] :arrow_up: language-html@0.43 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 05f14ceaf..23d7aa55e 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "language-gfm": "0.81.0", "language-git": "0.10.0", "language-go": "0.40.0", - "language-html": "0.42.0", + "language-html": "0.43.0", "language-hyperlink": "0.15.0", "language-java": "0.17.0", "language-javascript": "0.103.0", From 948aaa0652c55a793af6acdb2766ae0b1c9f2cfc Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Sun, 15 Nov 2015 20:51:07 +0100 Subject: [PATCH 068/137] Add opened files and folders to recent documents menu --- src/application-delegate.coffee | 3 +++ src/atom-environment.coffee | 4 +++- src/browser/atom-application.coffee | 3 +++ src/workspace.coffee | 3 +++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/application-delegate.coffee b/src/application-delegate.coffee index d6937f2d3..59259d223 100644 --- a/src/application-delegate.coffee +++ b/src/application-delegate.coffee @@ -109,6 +109,9 @@ class ApplicationDelegate setRepresentedFilename: (filename) -> ipc.send("call-window-method", "setRepresentedFilename", filename) + addRecentDocument: (filename) -> + ipc.send("add-recent-document", filename) + setRepresentedDirectoryPaths: (paths) -> loadSettings = getWindowLoadSettings() loadSettings['initialPaths'] = paths diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index e8d656a43..bd3d88fc8 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -885,7 +885,9 @@ class AtomEnvironment extends Model else @project.addPath(pathToOpen) - unless fs.isDirectorySync(pathToOpen) + if fs.isDirectorySync(pathToOpen) + @applicationDelegate.addRecentDocument(pathToOpen) + else @workspace?.open(pathToOpen, {initialLine, initialColumn}) return diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 1987f9dec..e720597e3 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -281,6 +281,9 @@ class AtomApplication ipc.on 'write-to-stderr', (event, output) -> process.stderr.write(output) + ipc.on 'add-recent-document', (event, filename) -> + app.addRecentDocument(filename) + setupDockMenu: -> if process.platform is 'darwin' dockMenu = Menu.buildFromTemplate [ diff --git a/src/workspace.coffee b/src/workspace.coffee index 04feef61e..3057a9047 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -488,6 +488,9 @@ class Workspace extends Model if initialLine >= 0 or initialColumn >= 0 item.setCursorBufferPosition?([initialLine, initialColumn]) + path = item.getPath?() + @applicationDelegate.addRecentDocument(path) if path? + index = pane.getActiveItemIndex() @emitter.emit 'did-open', {uri, pane, item, index} item From 2f78a274a124245442264e95bf9b55d45a2277fd Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Sun, 15 Nov 2015 22:47:50 +0100 Subject: [PATCH 069/137] Only add explicitly opened files/folders as recent documents --- src/atom-environment.coffee | 6 +++--- src/workspace.coffee | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index bd3d88fc8..de52fe55c 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -885,9 +885,9 @@ class AtomEnvironment extends Model else @project.addPath(pathToOpen) - if fs.isDirectorySync(pathToOpen) - @applicationDelegate.addRecentDocument(pathToOpen) - else + @applicationDelegate.addRecentDocument(pathToOpen) + + unless fs.isDirectorySync(pathToOpen) @workspace?.open(pathToOpen, {initialLine, initialColumn}) return diff --git a/src/workspace.coffee b/src/workspace.coffee index 3057a9047..04feef61e 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -488,9 +488,6 @@ class Workspace extends Model if initialLine >= 0 or initialColumn >= 0 item.setCursorBufferPosition?([initialLine, initialColumn]) - path = item.getPath?() - @applicationDelegate.addRecentDocument(path) if path? - index = pane.getActiveItemIndex() @emitter.emit 'did-open', {uri, pane, item, index} item From b74d11b998126891ac801f84c2cfb07a724553da Mon Sep 17 00:00:00 2001 From: Josh Abernathy Date: Mon, 30 Nov 2015 16:00:30 -0500 Subject: [PATCH 070/137] Merge pull request #9729 from atom/upload-to-s3 Upload releases to s3 --- build/package.json | 1 + build/tasks/publish-build-task.coffee | 35 ++++++++++++++++++++++++--- script/cibuild | 4 +++ script/cibuild-atom-linux | 3 +++ script/cibuild-atom-rpm | 3 +++ 5 files changed, 43 insertions(+), 3 deletions(-) diff --git a/build/package.json b/build/package.json index 2ce92de17..3e97d57d1 100644 --- a/build/package.json +++ b/build/package.json @@ -8,6 +8,7 @@ "dependencies": { "asar": "^0.8.0", "async": "~0.2.9", + "aws-sdk": "^2.2.18", "donna": "^1.0.13", "formidable": "~1.0.14", "fs-plus": "2.x", diff --git a/build/tasks/publish-build-task.coffee b/build/tasks/publish-build-task.coffee index d1640a42b..c2c41d8ab 100644 --- a/build/tasks/publish-build-task.coffee +++ b/build/tasks/publish-build-task.coffee @@ -6,6 +6,7 @@ async = require 'async' fs = require 'fs-plus' GitHub = require 'github-releases' request = require 'request' +AWS = require 'aws-sdk' grunt = null @@ -211,7 +212,7 @@ deleteExistingAssets = (release, assetNames, callback) -> async.parallel(tasks, callback) uploadAssets = (release, buildDir, assets, callback) -> - upload = (release, assetName, assetPath, callback) -> + uploadToReleases = (release, assetName, assetPath, callback) -> options = uri: release.upload_url.replace(/\{.*$/, "?name=#{assetName}") method: 'POST' @@ -222,15 +223,43 @@ uploadAssets = (release, buildDir, assets, callback) -> assetRequest = request options, (error, response, body='') -> if error? or response.statusCode >= 400 - logError("Upload release asset #{assetName} failed", error, body) + logError("Upload release asset #{assetName} to Releases failed", error, body) callback(error ? new Error(response.statusCode)) else callback(null, release) fs.createReadStream(assetPath).pipe(assetRequest) + uploadToS3 = (release, assetName, assetPath, callback) -> + s3Key = process.env.BUILD_ATOM_RELEASES_S3_KEY + s3Secret = process.env.BUILD_ATOM_RELEASES_S3_SECRET + s3Bucket = process.env.BUILD_ATOM_RELEASES_S3_BUCKET + + unless s3Key and s3Secret and s3Bucket + callback(new Error('BUILD_ATOM_RELEASES_S3_KEY, BUILD_ATOM_RELEASES_S3_SECRET, and BUILD_ATOM_RELEASES_S3_BUCKET environment variables must be set.')) + return + + s3Info = + accessKeyId: s3Key + secretAccessKey: s3Secret + s3 = new AWS.S3 s3Info + + key = "releases/#{release.tag_name}/#{assetName}" + uploadParams = + Bucket: s3Bucket + ACL: 'public-read' + Key: key + Body: fs.createReadStream(assetPath) + s3.upload uploadParams, (error, data) -> + if error? + logError("Upload release asset #{assetName} to S3 failed", error) + callback(error) + else + callback(null, release) + tasks = [] for {assetName} in assets assetPath = path.join(buildDir, assetName) - tasks.push(upload.bind(this, release, assetName, assetPath)) + tasks.push(uploadToReleases.bind(this, release, assetName, assetPath)) + tasks.push(uploadToS3.bind(this, release, assetName, assetPath)) async.parallel(tasks, callback) diff --git a/script/cibuild b/script/cibuild index d366af79a..41cfbdbdf 100755 --- a/script/cibuild +++ b/script/cibuild @@ -32,6 +32,10 @@ function readEnvironmentVariables() { process.env.CC = 'clang'; process.env.CXX = 'clang++'; process.env.npm_config_clang = '1'; + } else if (process.platform === 'win32') { + process.env.BUILD_ATOM_RELEASES_S3_KEY = process.env.BUILD_ATOM_WIN_RELEASES_S3_KEY + process.env.BUILD_ATOM_RELEASES_S3_SECRET = process.env.BUILD_ATOM_WIN_RELEASES_S3_SECRET + process.env.BUILD_ATOM_RELEASES_S3_BUCKET = process.env.BUILD_ATOM_WIN_RELEASES_S3_BUCKET } } diff --git a/script/cibuild-atom-linux b/script/cibuild-atom-linux index c4e957189..2c3395608 100755 --- a/script/cibuild-atom-linux +++ b/script/cibuild-atom-linux @@ -3,6 +3,9 @@ set -e export ATOM_ACCESS_TOKEN=$BUILD_ATOM_LINUX_ACCESS_TOKEN +export BUILD_ATOM_RELEASES_S3_KEY=$BUILD_ATOM_LINUX_RELEASES_S3_KEY +export BUILD_ATOM_RELEASES_S3_SECRET=$BUILD_ATOM_LINUX_RELEASES_S3_SECRET +export BUILD_ATOM_RELEASES_S3_BUCKET=$BUILD_ATOM_LINUX_RELEASES_S3_BUCKET if [ -d /usr/local/share/nodenv ]; then export NODENV_ROOT=/usr/local/share/nodenv diff --git a/script/cibuild-atom-rpm b/script/cibuild-atom-rpm index a861a068b..2faa89347 100755 --- a/script/cibuild-atom-rpm +++ b/script/cibuild-atom-rpm @@ -8,5 +8,8 @@ docker run \ --env JANKY_SHA1="$JANKY_SHA1" \ --env JANKY_BRANCH="$JANKY_BRANCH" \ --env ATOM_ACCESS_TOKEN="$BUILD_ATOM_RPM_ACCESS_TOKEN" \ + --env BUILD_ATOM_RELEASES_S3_KEY="$BUILD_ATOM_RPM_RELEASES_S3_KEY" \ + --env BUILD_ATOM_RELEASES_S3_SECRET="$BUILD_ATOM_RPM_RELEASES_S3_SECRET" \ + --env BUILD_ATOM_RELEASES_S3_BUCKET="$BUILD_ATOM_RPM_RELEASES_S3_BUCKET" \ atom-rpm /atom/script/rpmbuild docker rmi atom-rpm From 3da93a10458122f06ddb0a0bcb0eb1868220d54b Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Tue, 1 Dec 2015 17:17:41 -0500 Subject: [PATCH 071/137] :arrow_up: language-ruby@0.65.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 23d7aa55e..6cda226fd 100644 --- a/package.json +++ b/package.json @@ -137,7 +137,7 @@ "language-php": "0.34.0", "language-property-list": "0.8.0", "language-python": "0.42.1", - "language-ruby": "0.64.1", + "language-ruby": "0.65.0", "language-ruby-on-rails": "0.24.0", "language-sass": "0.44.1", "language-shellscript": "0.21.0", From 5b81f11711bd7f44cc1de87ad241fe9076e2b7b9 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Tue, 1 Dec 2015 22:40:33 -0500 Subject: [PATCH 072/137] :arrow_up: language-objective-c@0.15.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6cda226fd..0e2c0f997 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "language-less": "0.29.0", "language-make": "0.21.0", "language-mustache": "0.13.0", - "language-objective-c": "0.15.0", + "language-objective-c": "0.15.1", "language-perl": "0.31.0", "language-php": "0.34.0", "language-property-list": "0.8.0", From ed7a80b5aade6422822e5bc6429a62eef6bee36c Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Fri, 20 Nov 2015 21:59:48 -0600 Subject: [PATCH 073/137] bump Contributor Covenant version to 1.3 --- CONTRIBUTING.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 36de7b46c..6e0a1fede 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,7 +30,7 @@ These are just guidelines, not rules, use your best judgment and feel free to pr ### Code of Conduct -This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0). +This project adheres to the [Contributor Covenant 1.3](http://contributor-covenant.org/version/1/3/0). By participating, you are expected to uphold this code. Please report unacceptable behavior to [atom@github.com](mailto:atom@github.com). diff --git a/README.md b/README.md index 168124ac5..6d1d8a385 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Visit [atom.io](https://atom.io) to learn more or visit the [Atom forum](https:/ Follow [@AtomEditor](https://twitter.com/atomeditor) on Twitter for important announcements. -This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0). +This project adheres to the [Contributor Covenant 1.3](http://contributor-covenant.org/version/1/3/0). By participating, you are expected to uphold this code. Please report unacceptable behavior to atom@github.com. ## Documentation From df34bd8b3f2c22457ab7a9dadcdb850a5e666a95 Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Wed, 2 Dec 2015 16:15:34 -0600 Subject: [PATCH 074/137] add CODE_OF_CONDUCT.md with atom@github.com email address --- CODE_OF_CONDUCT.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..444ce0b4c --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,24 @@ +# Contributor Code of Conduct + +As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. + +We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery +- Personal attacks +- Trolling or insulting/derogatory comments +- Public or private harassment +- Publishing other's private information, such as physical or electronic addresses, without explicit permission +- Other unethical or unprofessional conduct + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a project maintainer at [atom@github.com](mailto:atom@github.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Maintainers are obligated to maintain confidentiality with regard to the reporter of an incident. + +This Code of Conduct is adapted from the Contributor Covenant, version 1.3.0, available from http://contributor-covenant.org/version/1/3/0/ From effb01c7e6ac65b29ca8abed90c40ef271499085 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Wed, 2 Dec 2015 18:18:16 -0500 Subject: [PATCH 075/137] :arrow_up: language-css@0.36.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0e2c0f997..fe0d9c811 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "language-clojure": "0.18.0", "language-coffee-script": "0.46.0", "language-csharp": "0.11.0", - "language-css": "0.35.1", + "language-css": "0.36.0", "language-gfm": "0.81.0", "language-git": "0.10.0", "language-go": "0.40.0", From bb2278e8cd3eb09a2b2a6e1aad139ad2e806de91 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Wed, 2 Dec 2015 18:19:32 -0500 Subject: [PATCH 076/137] :arrow_up: language-sass@0.45.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fe0d9c811..f8dcd822e 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "language-python": "0.42.1", "language-ruby": "0.65.0", "language-ruby-on-rails": "0.24.0", - "language-sass": "0.44.1", + "language-sass": "0.45.0", "language-shellscript": "0.21.0", "language-source": "0.9.0", "language-sql": "0.19.0", From db93dd46e2ed9356e353e15e441d8d9e288197aa Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Wed, 2 Dec 2015 18:22:18 -0500 Subject: [PATCH 077/137] :arrow_up: language-c@0.51.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f8dcd822e..3678a1b3a 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "welcome": "0.33.0", "whitespace": "0.32.1", "wrap-guide": "0.38.1", - "language-c": "0.50.1", + "language-c": "0.51.0", "language-clojure": "0.18.0", "language-coffee-script": "0.46.0", "language-csharp": "0.11.0", From 63c7f1cf9aac3899e2796360ac1628c6d450d52b Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Wed, 2 Dec 2015 18:22:59 -0500 Subject: [PATCH 078/137] :arrow_up: language-json@0.17.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3678a1b3a..85ba0be29 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "language-hyperlink": "0.15.0", "language-java": "0.17.0", "language-javascript": "0.103.0", - "language-json": "0.17.1", + "language-json": "0.17.2", "language-less": "0.29.0", "language-make": "0.21.0", "language-mustache": "0.13.0", From 2bec69fcc2cf7e63fece0212fa75350d28d59190 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Wed, 2 Dec 2015 18:26:20 -0500 Subject: [PATCH 079/137] :arrow_up: language-yaml@0.24.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 85ba0be29..e7cfc5c8c 100644 --- a/package.json +++ b/package.json @@ -147,7 +147,7 @@ "language-todo": "0.27.0", "language-toml": "0.17.0", "language-xml": "0.34.1", - "language-yaml": "0.24.0" + "language-yaml": "0.24.1" }, "private": true, "scripts": { From 837b003e0027824ac777632c4b816c67cbc93f33 Mon Sep 17 00:00:00 2001 From: Wliu Date: Wed, 2 Dec 2015 20:47:06 -0500 Subject: [PATCH 080/137] :arrow_up: language-javascript@0.104.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e7cfc5c8c..265e046dc 100644 --- a/package.json +++ b/package.json @@ -127,7 +127,7 @@ "language-html": "0.43.0", "language-hyperlink": "0.15.0", "language-java": "0.17.0", - "language-javascript": "0.103.0", + "language-javascript": "0.104.0", "language-json": "0.17.2", "language-less": "0.29.0", "language-make": "0.21.0", From ecd14f33902bd542d525506fc4c45c3b8e1eed52 Mon Sep 17 00:00:00 2001 From: Wliu Date: Wed, 2 Dec 2015 20:47:27 -0500 Subject: [PATCH 081/137] :green_heart: let and var are now storage.type.var.js Refs atom/language-javascript#277 --- spec/text-editor-component-spec.js | 2 +- spec/text-editor-presenter-spec.coffee | 2 +- spec/tokenized-buffer-spec.coffee | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index 609d20291..d5e9f5425 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -484,7 +484,7 @@ describe('TextEditorComponent', function () { it('displays newlines as their own token outside of the other tokens\' scopeDescriptor', async function () { editor.setText('let\n') await nextViewUpdatePromise() - expect(component.lineNodeForScreenRow(0).innerHTML).toBe('let' + invisibles.eol + '') + expect(component.lineNodeForScreenRow(0).innerHTML).toBe('let' + invisibles.eol + '') }) it('displays trailing carriage returns using a visible, non-empty value', async function () { diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 8dd34fde8..f3800220e 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -611,7 +611,7 @@ describe "TextEditorPresenter", -> expect(presenter.getState().hiddenInput.width).toBe 15 expectStateUpdate presenter, -> - presenter.getLinesYardstick().setScopedCharacterWidth(['source.js', 'storage.modifier.js'], 'r', 20) + presenter.getLinesYardstick().setScopedCharacterWidth(['source.js', 'storage.type.var.js'], 'r', 20) presenter.characterWidthsChanged() expect(presenter.getState().hiddenInput.width).toBe 20 diff --git a/spec/tokenized-buffer-spec.coffee b/spec/tokenized-buffer-spec.coffee index 5d6d3cfdc..692e758a9 100644 --- a/spec/tokenized-buffer-spec.coffee +++ b/spec/tokenized-buffer-spec.coffee @@ -198,7 +198,7 @@ describe "TokenizedBuffer", -> buffer.setTextInRange([[1, 0], [3, 0]], "foo()") # previous line 0 remains - expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[0]).toEqual(value: 'var', scopes: ['source.js', 'storage.modifier.js']) + expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[0]).toEqual(value: 'var', scopes: ['source.js', 'storage.type.var.js']) # previous line 3 should be combined with input to form line 1 expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[0]).toEqual(value: 'foo', scopes: ['source.js', 'meta.function-call.js', 'entity.name.function.js']) @@ -242,7 +242,7 @@ describe "TokenizedBuffer", -> buffer.setTextInRange([[1, 0], [2, 0]], "foo()\nbar()\nbaz()\nquux()") # previous line 0 remains - expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[0]).toEqual( value: 'var', scopes: ['source.js', 'storage.modifier.js']) + expect(tokenizedBuffer.tokenizedLineForRow(0).tokens[0]).toEqual( value: 'var', scopes: ['source.js', 'storage.type.var.js']) # 3 new lines inserted expect(tokenizedBuffer.tokenizedLineForRow(1).tokens[0]).toEqual(value: 'foo', scopes: ['source.js', 'meta.function-call.js', 'entity.name.function.js']) @@ -582,7 +582,7 @@ describe "TokenizedBuffer", -> fullyTokenize(tokenizedBuffer) expect(tokenizedBuffer.tokenForPosition([1, 0]).scopes).toEqual ["source.js"] expect(tokenizedBuffer.tokenForPosition([1, 1]).scopes).toEqual ["source.js"] - expect(tokenizedBuffer.tokenForPosition([1, 2]).scopes).toEqual ["source.js", "storage.modifier.js"] + expect(tokenizedBuffer.tokenForPosition([1, 2]).scopes).toEqual ["source.js", "storage.type.var.js"] describe ".bufferRangeForScopeAtPosition(selector, position)", -> beforeEach -> @@ -599,8 +599,8 @@ describe "TokenizedBuffer", -> describe "when the selector matches a single token at the position", -> it "returns the range covered by the token", -> - expect(tokenizedBuffer.bufferRangeForScopeAtPosition('.storage.modifier.js', [0, 1])).toEqual [[0, 0], [0, 3]] - expect(tokenizedBuffer.bufferRangeForScopeAtPosition('.storage.modifier.js', [0, 3])).toEqual [[0, 0], [0, 3]] + expect(tokenizedBuffer.bufferRangeForScopeAtPosition('.storage.type.var.js', [0, 1])).toEqual [[0, 0], [0, 3]] + expect(tokenizedBuffer.bufferRangeForScopeAtPosition('.storage.type.var.js', [0, 3])).toEqual [[0, 0], [0, 3]] describe "when the selector matches a run of multiple tokens at the position", -> it "returns the range covered by all contigous tokens (within a single line)", -> From d85af0d3f40ecce205bf36ecea9d345ee23ce0e2 Mon Sep 17 00:00:00 2001 From: Wliu Date: Wed, 2 Dec 2015 21:39:12 -0500 Subject: [PATCH 082/137] :green_heart: again --- spec/text-editor-presenter-spec.coffee | 4 ++-- spec/text-editor-spec.coffee | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index f3800220e..2aeb8822e 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -1449,12 +1449,12 @@ describe "TextEditorPresenter", -> presenter = buildPresenter(explicitHeight: 20) expectStateUpdate presenter, -> - presenter.getLinesYardstick().setScopedCharacterWidth(['source.js', 'storage.modifier.js'], 'v', 20) + presenter.getLinesYardstick().setScopedCharacterWidth(['source.js', 'storage.type.var.js'], 'v', 20) presenter.characterWidthsChanged() expect(stateForCursor(presenter, 0)).toEqual {top: 1 * 10, left: (3 * 10) + 20, width: 10, height: 10} expectStateUpdate presenter, -> - presenter.getLinesYardstick().setScopedCharacterWidth(['source.js', 'storage.modifier.js'], 'r', 20) + presenter.getLinesYardstick().setScopedCharacterWidth(['source.js', 'storage.type.var.js'], 'r', 20) presenter.characterWidthsChanged() expect(stateForCursor(presenter, 0)).toEqual {top: 1 * 10, left: (3 * 10) + 20, width: 20, height: 10} diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 0cee8215a..1797e25bf 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5337,7 +5337,7 @@ describe "TextEditor", -> tokens = atom.grammars.decodeTokens(line, tags) expect(tokens[0].value).toBe "var" - expect(tokens[0].scopes).toEqual ["source.js", "storage.modifier.js"] + expect(tokens[0].scopes).toEqual ["source.js", "storage.type.var.js"] expect(tokens[6].value).toBe "http://github.com" expect(tokens[6].scopes).toEqual ["source.js", "comment.line.double-slash.js", "markup.underline.link.http.hyperlink"] From 26929810a0f4ded720245b3b7f9c504334f542ab Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Wed, 2 Dec 2015 22:10:55 -0500 Subject: [PATCH 083/137] :arrow_up: language-html@0.43.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 265e046dc..fadb21d55 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "language-gfm": "0.81.0", "language-git": "0.10.0", "language-go": "0.40.0", - "language-html": "0.43.0", + "language-html": "0.43.1", "language-hyperlink": "0.15.0", "language-java": "0.17.0", "language-javascript": "0.104.0", From e047741ff362f43b3f35bf10a9f9d938f6ed1983 Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Wed, 2 Dec 2015 23:36:29 -0600 Subject: [PATCH 084/137] link to CoC from README and CONTRIBUTING docs [ci skip] --- CONTRIBUTING.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6e0a1fede..0fdf8b43d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,7 +30,7 @@ These are just guidelines, not rules, use your best judgment and feel free to pr ### Code of Conduct -This project adheres to the [Contributor Covenant 1.3](http://contributor-covenant.org/version/1/3/0). +This project adheres to the [Contributor Covenant 1.3](http://contributor-covenant.org/version/1/3/0) (see [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)). By participating, you are expected to uphold this code. Please report unacceptable behavior to [atom@github.com](mailto:atom@github.com). diff --git a/README.md b/README.md index 6d1d8a385..fdca068ab 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Visit [atom.io](https://atom.io) to learn more or visit the [Atom forum](https:/ Follow [@AtomEditor](https://twitter.com/atomeditor) on Twitter for important announcements. -This project adheres to the [Contributor Covenant 1.3](http://contributor-covenant.org/version/1/3/0). +This project adheres to the [Contributor Covenant 1.3](http://contributor-covenant.org/version/1/3/0) (see [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)). By participating, you are expected to uphold this code. Please report unacceptable behavior to atom@github.com. ## Documentation From c6cca659abc32c500a10efbd536072dc5ec2b869 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Thu, 3 Dec 2015 10:33:14 -0500 Subject: [PATCH 085/137] :arrow_up: language-clojure@0.19.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e7cfc5c8c..00fcadf25 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "whitespace": "0.32.1", "wrap-guide": "0.38.1", "language-c": "0.51.0", - "language-clojure": "0.18.0", + "language-clojure": "0.19.0", "language-coffee-script": "0.46.0", "language-csharp": "0.11.0", "language-css": "0.36.0", From d81e2a23b9f45927e73a60a2f7eb194ed195e9ab Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Thu, 3 Dec 2015 10:08:03 -0600 Subject: [PATCH 086/137] remove links to Contributor Covenant CoC --- CONTRIBUTING.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0fdf8b43d..ada420a40 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,7 +30,7 @@ These are just guidelines, not rules, use your best judgment and feel free to pr ### Code of Conduct -This project adheres to the [Contributor Covenant 1.3](http://contributor-covenant.org/version/1/3/0) (see [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)). +This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [atom@github.com](mailto:atom@github.com). diff --git a/README.md b/README.md index fdca068ab..7f7acb5fe 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Visit [atom.io](https://atom.io) to learn more or visit the [Atom forum](https:/ Follow [@AtomEditor](https://twitter.com/atomeditor) on Twitter for important announcements. -This project adheres to the [Contributor Covenant 1.3](http://contributor-covenant.org/version/1/3/0) (see [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)). +This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to atom@github.com. ## Documentation From 71d2761c1ad1f0a2128a3a716b97118634ba21e0 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 3 Dec 2015 10:30:09 -0800 Subject: [PATCH 087/137] Merge pull request #9763 from dranzerashi/patch-1 --- spec/text-editor-spec.coffee | 27 +++++++++++++++++++++++++++ src/cursor.coffee | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 0cee8215a..dbc5289f7 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -767,6 +767,20 @@ describe "TextEditor", -> editor.moveToBeginningOfWord() expect(editor.getCursorBufferPosition()).toEqual [9, 2] + it "treats lines with only whitespace as a word (CRLF line ending)", -> + editor.buffer.setText(buffer.getText().replace(/\n/g, "\r\n")) + editor.setCursorBufferPosition([11, 0]) + editor.moveToBeginningOfWord() + expect(editor.getCursorBufferPosition()).toEqual [10, 0] + editor.buffer.setText(buffer.getText().replace(/\r\n/g, "\n")) + + it "works when the current line is blank (CRLF line ending)", -> + editor.buffer.setText(buffer.getText().replace(/\n/g, "\r\n")) + editor.setCursorBufferPosition([10, 0]) + editor.moveToBeginningOfWord() + expect(editor.getCursorBufferPosition()).toEqual [9, 2] + editor.buffer.setText(buffer.getText().replace(/\r\n/g, "\n")) + describe ".moveToPreviousWordBoundary()", -> it "moves the cursor to the previous word boundary", -> editor.setCursorBufferPosition [0, 8] @@ -826,6 +840,19 @@ describe "TextEditor", -> editor.moveToEndOfWord() expect(editor.getCursorBufferPosition()).toEqual [11, 8] + it "treats lines with only whitespace as a word (CRLF line ending)", -> + editor.buffer.setText(buffer.getText().replace(/\n/g, "\r\n")) + editor.setCursorBufferPosition([9, 4]) + editor.moveToEndOfWord() + expect(editor.getCursorBufferPosition()).toEqual [10, 0] + + it "works when the current line is blank (CRLF line ending)", -> + editor.buffer.setText(buffer.getText().replace(/\n/g, "\r\n")) + editor.setCursorBufferPosition([10, 0]) + editor.moveToEndOfWord() + expect(editor.getCursorBufferPosition()).toEqual [11, 8] + editor.buffer.setText(buffer.getText().replace(/\r\n/g, "\n")) + describe ".moveToBeginningOfNextWord()", -> it "moves the cursor before the first character of the next word", -> editor.setCursorBufferPosition [0, 6] diff --git a/src/cursor.coffee b/src/cursor.coffee index 0f87c2760..9368a5a9c 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -606,7 +606,7 @@ class Cursor extends Model wordRegExp: ({includeNonWordCharacters}={}) -> includeNonWordCharacters ?= true nonWordCharacters = @config.get('editor.nonWordCharacters', scope: @getScopeDescriptor()) - segments = ["^[\t ]*$"] + segments = ["\\r?\\n[\\t\\s]*\\r?\\n"] segments.push("[^\\s#{_.escapeRegExp(nonWordCharacters)}]+") if includeNonWordCharacters segments.push("[#{_.escapeRegExp(nonWordCharacters)}]+") From 76b6ca5043a83cffa5c4c44fb9cd3691b5fcffaa Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 3 Dec 2015 11:52:45 -0800 Subject: [PATCH 088/137] Make CRLF word-movement tests pass --- spec/text-editor-spec.coffee | 22 +++++++++----------- src/cursor.coffee | 40 +++++++++++++++++++----------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index dbc5289f7..23312ca2b 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -762,17 +762,16 @@ describe "TextEditor", -> editor.moveToBeginningOfWord() expect(editor.getCursorBufferPosition()).toEqual [10, 0] - it "works when the current line is blank", -> - editor.setCursorBufferPosition([10, 0]) - editor.moveToBeginningOfWord() - expect(editor.getCursorBufferPosition()).toEqual [9, 2] - it "treats lines with only whitespace as a word (CRLF line ending)", -> editor.buffer.setText(buffer.getText().replace(/\n/g, "\r\n")) editor.setCursorBufferPosition([11, 0]) editor.moveToBeginningOfWord() expect(editor.getCursorBufferPosition()).toEqual [10, 0] - editor.buffer.setText(buffer.getText().replace(/\r\n/g, "\n")) + + it "works when the current line is blank", -> + editor.setCursorBufferPosition([10, 0]) + editor.moveToBeginningOfWord() + expect(editor.getCursorBufferPosition()).toEqual [9, 2] it "works when the current line is blank (CRLF line ending)", -> editor.buffer.setText(buffer.getText().replace(/\n/g, "\r\n")) @@ -835,23 +834,22 @@ describe "TextEditor", -> editor.moveToEndOfWord() expect(editor.getCursorBufferPosition()).toEqual [10, 0] - it "works when the current line is blank", -> - editor.setCursorBufferPosition([10, 0]) - editor.moveToEndOfWord() - expect(editor.getCursorBufferPosition()).toEqual [11, 8] - it "treats lines with only whitespace as a word (CRLF line ending)", -> editor.buffer.setText(buffer.getText().replace(/\n/g, "\r\n")) editor.setCursorBufferPosition([9, 4]) editor.moveToEndOfWord() expect(editor.getCursorBufferPosition()).toEqual [10, 0] + it "works when the current line is blank", -> + editor.setCursorBufferPosition([10, 0]) + editor.moveToEndOfWord() + expect(editor.getCursorBufferPosition()).toEqual [11, 8] + it "works when the current line is blank (CRLF line ending)", -> editor.buffer.setText(buffer.getText().replace(/\n/g, "\r\n")) editor.setCursorBufferPosition([10, 0]) editor.moveToEndOfWord() expect(editor.getCursorBufferPosition()).toEqual [11, 8] - editor.buffer.setText(buffer.getText().replace(/\r\n/g, "\n")) describe ".moveToBeginningOfNextWord()", -> it "moves the cursor before the first character of the next word", -> diff --git a/src/cursor.coffee b/src/cursor.coffee index 9368a5a9c..c63485fd2 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -467,10 +467,13 @@ class Cursor extends Model scanRange = [[previousNonBlankRow, 0], currentBufferPosition] beginningOfWordPosition = null - @editor.backwardsScanInBufferRange (options.wordRegex ? @wordRegExp(options)), scanRange, ({range, stop}) -> - if range.end.isGreaterThanOrEqual(currentBufferPosition) or allowPrevious - beginningOfWordPosition = range.start - if not beginningOfWordPosition?.isEqual(currentBufferPosition) + @editor.backwardsScanInBufferRange (options.wordRegex ? @wordRegExp(options)), scanRange, ({range, matchText, stop}) -> + # Ignore 'empty line' matches between '\r' and '\n' + return if matchText is '' and range.start.column isnt 0 + + if range.start.isLessThan(currentBufferPosition) + if range.end.isGreaterThanOrEqual(currentBufferPosition) or allowPrevious + beginningOfWordPosition = range.start stop() if beginningOfWordPosition? @@ -496,13 +499,12 @@ class Cursor extends Model scanRange = [currentBufferPosition, @editor.getEofBufferPosition()] endOfWordPosition = null - @editor.scanInBufferRange (options.wordRegex ? @wordRegExp(options)), scanRange, ({range, stop}) -> - if allowNext - if range.end.isGreaterThan(currentBufferPosition) - endOfWordPosition = range.end - stop() - else - if range.start.isLessThanOrEqual(currentBufferPosition) + @editor.scanInBufferRange (options.wordRegex ? @wordRegExp(options)), scanRange, ({range, matchText, stop}) -> + # Ignore 'empty line' matches between '\r' and '\n' + return if matchText is '' and range.start.column isnt 0 + + if range.end.isGreaterThan(currentBufferPosition) + if allowNext or range.start.isLessThanOrEqual(currentBufferPosition) endOfWordPosition = range.end stop() @@ -603,14 +605,14 @@ class Cursor extends Model # non-word characters in the regex. (default: true) # # Returns a {RegExp}. - wordRegExp: ({includeNonWordCharacters}={}) -> - includeNonWordCharacters ?= true - nonWordCharacters = @config.get('editor.nonWordCharacters', scope: @getScopeDescriptor()) - segments = ["\\r?\\n[\\t\\s]*\\r?\\n"] - segments.push("[^\\s#{_.escapeRegExp(nonWordCharacters)}]+") - if includeNonWordCharacters - segments.push("[#{_.escapeRegExp(nonWordCharacters)}]+") - new RegExp(segments.join("|"), "g") + wordRegExp: (options) -> + scope = @getScopeDescriptor() + nonWordCharacters = _.escapeRegExp(@config.get('editor.nonWordCharacters', {scope})) + + source = "^[\t ]*$|[^\\s#{nonWordCharacters}]+" + if options?.includeNonWordCharacters ? true + source += "|" + "[#{nonWordCharacters}]+" + new RegExp(source, "g") # Public: Get the RegExp used by the cursor to determine what a "subword" is. # From fe5b1b70e8b0b85a3d7fa2a06fee625aca3e70ca Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 3 Dec 2015 12:07:15 -0800 Subject: [PATCH 089/137] Fix paragraph motions in the presence of CRLF line endings --- spec/text-editor-spec.coffee | 30 +++++++++++++++++++++++++++++- src/cursor.coffee | 16 ++++++++-------- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 23312ca2b..a646457fc 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -1080,8 +1080,36 @@ describe "TextEditor", -> editor.moveToBeginningOfNextParagraph() expect(editor.getCursorBufferPosition()).toEqual [0, 0] + it "moves the cursor before the first line of the next paragraph (CRLF line endings)", -> + editor.setText(editor.getText().replace(/\n/g, '\r\n')) + + editor.setCursorBufferPosition [0, 6] + editor.foldBufferRow(4) + + editor.moveToBeginningOfNextParagraph() + expect(editor.getCursorBufferPosition()).toEqual [10, 0] + + editor.setText("") + editor.setCursorBufferPosition [0, 0] + editor.moveToBeginningOfNextParagraph() + expect(editor.getCursorBufferPosition()).toEqual [0, 0] + describe ".moveToBeginningOfPreviousParagraph()", -> - it "moves the cursor before the first line of the pevious paragraph", -> + it "moves the cursor before the first line of the previous paragraph", -> + editor.setCursorBufferPosition [10, 0] + editor.foldBufferRow(4) + + editor.moveToBeginningOfPreviousParagraph() + expect(editor.getCursorBufferPosition()).toEqual [0, 0] + + editor.setText("") + editor.setCursorBufferPosition [0, 0] + editor.moveToBeginningOfPreviousParagraph() + expect(editor.getCursorBufferPosition()).toEqual [0, 0] + + it "moves the cursor before the first line of the previous paragraph (CRLF line endings)", -> + editor.setText(editor.getText().replace(/\n/g, '\r\n')) + editor.setCursorBufferPosition [10, 0] editor.foldBufferRow(4) diff --git a/src/cursor.coffee b/src/cursor.coffee index c63485fd2..5b3b23b73 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -3,6 +3,8 @@ _ = require 'underscore-plus' Model = require './model' +EmptyLineRegExp = /(\r\n[\t ]*\r\n)|(\n[\t ]*\n)/g + # Extended: The `Cursor` class represents the little blinking line identifying # where text can be inserted. # @@ -668,10 +670,9 @@ class Cursor extends Model {row, column} = eof position = new Point(row, column - 1) - @editor.scanInBufferRange /^\n*$/g, scanRange, ({range, stop}) -> - unless range.start.isEqual(start) - position = range.start - stop() + @editor.scanInBufferRange EmptyLineRegExp, scanRange, ({range, stop}) -> + position = range.start.traverse(Point(1, 0)) + stop() unless position.isEqual(start) position getBeginningOfPreviousParagraphBufferPosition: -> @@ -681,8 +682,7 @@ class Cursor extends Model scanRange = [[row-1, column], [0, 0]] position = new Point(0, 0) zero = new Point(0, 0) - @editor.backwardsScanInBufferRange /^\n*$/g, scanRange, ({range, stop}) -> - unless range.start.isEqual(zero) - position = range.start - stop() + @editor.backwardsScanInBufferRange EmptyLineRegExp, scanRange, ({range, stop}) -> + position = range.start.traverse(Point(1, 0)) + stop() unless position.isEqual(start) position From 33ea4f55f5e7077b132dc2590000a365f77b763c Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 3 Dec 2015 13:46:44 -0800 Subject: [PATCH 090/137] :arrow_up: autocomplete-plus --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 00fcadf25..60efc39fc 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "autocomplete-atom-api": "0.9.2", "autocomplete-css": "0.11.0", "autocomplete-html": "0.7.2", - "autocomplete-plus": "2.23.1", + "autocomplete-plus": "2.24.0", "autocomplete-snippets": "1.9.0", "autoflow": "0.26.0", "autosave": "0.23.0", From 4fc88264e314e9bcc336637ba0680ec97e0ae0ff Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 3 Dec 2015 15:34:00 -0800 Subject: [PATCH 091/137] :arrow_up: language-hyperlink@0.16 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 693263b6f..66650e710 100644 --- a/package.json +++ b/package.json @@ -125,7 +125,7 @@ "language-git": "0.10.0", "language-go": "0.40.0", "language-html": "0.43.1", - "language-hyperlink": "0.15.0", + "language-hyperlink": "0.16.0", "language-java": "0.17.0", "language-javascript": "0.104.0", "language-json": "0.17.2", From e58ea27e911e306bc358c90dfb23876ca9c9330f Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Thu, 3 Dec 2015 15:52:13 -0800 Subject: [PATCH 092/137] :arrow_up: find-and-replace@0.192.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 66650e710..9910ad884 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "dev-live-reload": "0.47.0", "encoding-selector": "0.21.0", "exception-reporting": "0.37.0", - "find-and-replace": "0.191.0", + "find-and-replace": "0.192.0", "fuzzy-finder": "0.93.0", "git-diff": "0.57.0", "go-to-line": "0.30.0", From a90fa150e5694f29d5b6dcd8fab4fea49e86b538 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 3 Dec 2015 15:47:38 -0800 Subject: [PATCH 093/137] :arrow_up: language-toml@0.18 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9910ad884..b5cefa506 100644 --- a/package.json +++ b/package.json @@ -145,7 +145,7 @@ "language-sql": "0.19.0", "language-text": "0.7.0", "language-todo": "0.27.0", - "language-toml": "0.17.0", + "language-toml": "0.18.0", "language-xml": "0.34.1", "language-yaml": "0.24.1" }, From b43036c323c6d01c0937ae4c39683a23ffcb7920 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 3 Dec 2015 16:10:53 -0800 Subject: [PATCH 094/137] :arrow_up: language-git@0.11 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b5cefa506..733221e53 100644 --- a/package.json +++ b/package.json @@ -122,7 +122,7 @@ "language-csharp": "0.11.0", "language-css": "0.36.0", "language-gfm": "0.81.0", - "language-git": "0.10.0", + "language-git": "0.11.0", "language-go": "0.40.0", "language-html": "0.43.1", "language-hyperlink": "0.16.0", From 834115bb073d13c8ddf1790fda73380d017faf1e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 3 Dec 2015 16:11:22 -0800 Subject: [PATCH 095/137] :arrow_up: language-yaml@0.25 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 733221e53..26dbed649 100644 --- a/package.json +++ b/package.json @@ -147,7 +147,7 @@ "language-todo": "0.27.0", "language-toml": "0.18.0", "language-xml": "0.34.1", - "language-yaml": "0.24.1" + "language-yaml": "0.25.0" }, "private": true, "scripts": { From 65464225e84d25acb998a8bf2b94b645eb62144f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 3 Dec 2015 16:17:46 -0800 Subject: [PATCH 096/137] :arrow_up: language-perl@0.32 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 26dbed649..b141397a2 100644 --- a/package.json +++ b/package.json @@ -133,7 +133,7 @@ "language-make": "0.21.0", "language-mustache": "0.13.0", "language-objective-c": "0.15.1", - "language-perl": "0.31.0", + "language-perl": "0.32.0", "language-php": "0.34.0", "language-property-list": "0.8.0", "language-python": "0.42.1", From 5c6375d9de319a871d560d76eba06c0aa85b6b60 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 3 Dec 2015 16:34:10 -0800 Subject: [PATCH 097/137] :arrow_up: language-sql@0.20 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b141397a2..6ba1a2d53 100644 --- a/package.json +++ b/package.json @@ -142,7 +142,7 @@ "language-sass": "0.45.0", "language-shellscript": "0.21.0", "language-source": "0.9.0", - "language-sql": "0.19.0", + "language-sql": "0.20.0", "language-text": "0.7.0", "language-todo": "0.27.0", "language-toml": "0.18.0", From d377e725e091371331bccfb05882eda0125e6b98 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 3 Dec 2015 16:36:37 -0800 Subject: [PATCH 098/137] :arrow_up: language-gfm@0.82 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6ba1a2d53..5ca330287 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,7 @@ "language-coffee-script": "0.46.0", "language-csharp": "0.11.0", "language-css": "0.36.0", - "language-gfm": "0.81.0", + "language-gfm": "0.82.0", "language-git": "0.11.0", "language-go": "0.40.0", "language-html": "0.43.1", From 7c657b08cc175041245885576c64a5cc72d54d91 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 4 Dec 2015 18:42:43 +0100 Subject: [PATCH 099/137] :arrow_up: atom-keymap --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5ca330287..b4dcdc9f6 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "electronVersion": "0.34.5", "dependencies": { "async": "0.2.6", - "atom-keymap": "^6.1.1", + "atom-keymap": "^6.2.0", "babel-core": "^5.8.21", "bootstrap": "^3.3.4", "cached-run-in-this-context": "0.4.0", From 96e0deb3c2bbbaef72768ca2fb1bc561a1125db1 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 4 Dec 2015 09:47:05 -0800 Subject: [PATCH 100/137] :arrow_up: github-releases --- build/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package.json b/build/package.json index 40e5b309a..fd7d29d80 100644 --- a/build/package.json +++ b/build/package.json @@ -12,7 +12,7 @@ "donna": "^1.0.13", "formidable": "~1.0.14", "fs-plus": "2.x", - "github-releases": "~0.3.0", + "github-releases": "~0.3.1", "glob": "^5.0.14", "grunt": "~0.4.1", "grunt-babel": "^5.0.1", From 6e2061c0760b9015cd5285d53cba174d763494c2 Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Sun, 6 Dec 2015 17:15:13 -0800 Subject: [PATCH 101/137] :white_check_mark: add spec for ordered config.cson --- spec/config-spec.coffee | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/spec/config-spec.coffee b/spec/config-spec.coffee index e00cee789..eab2f6f04 100644 --- a/spec/config-spec.coffee +++ b/spec/config-spec.coffee @@ -679,6 +679,26 @@ describe "Config", -> writtenConfig = CSON.writeFileSync.argsForCall[0][1] expect(writtenConfig).toEqual '*': atom.config.settings + it 'writes properties in alphabetical order', -> + atom.config.set('foo', 1) + atom.config.set('bar', 2) + atom.config.set('baz.foo', 3) + atom.config.set('baz.bar', 4) + + CSON.writeFileSync.reset() + atom.config.save() + + expect(CSON.writeFileSync.argsForCall[0][0]).toBe atom.config.configFilePath + writtenConfig = CSON.writeFileSync.argsForCall[0][1] + expect(writtenConfig).toEqual '*': atom.config.settings + + expectedKeys = ['bar', 'baz', 'foo'] + foundKeys = (key for key of writtenConfig['*'] when key in expectedKeys) + expect(foundKeys).toEqual expectedKeys + expectedKeys = ['bar', 'foo'] + foundKeys = (key for key of writtenConfig['*']['baz'] when key in expectedKeys) + expect(foundKeys).toEqual expectedKeys + describe "when ~/.atom/config.json doesn't exist", -> it "writes any non-default properties to ~/.atom/config.cson", -> atom.config.set("a.b.c", 1) From f7a4ef4a844085077118102f344c3d1e77b20473 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 7 Dec 2015 14:47:23 +0100 Subject: [PATCH 102/137] Deserialize also untitled buffers --- spec/tokenized-buffer-spec.coffee | 28 ++++++++++++++++++++++++++++ src/project.coffee | 8 ++++++++ src/tokenized-buffer.coffee | 6 +++++- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/spec/tokenized-buffer-spec.coffee b/spec/tokenized-buffer-spec.coffee index 692e758a9..1d53cc6bd 100644 --- a/spec/tokenized-buffer-spec.coffee +++ b/spec/tokenized-buffer-spec.coffee @@ -24,6 +24,34 @@ describe "TokenizedBuffer", -> advanceClock() while tokenizedBuffer.firstInvalidRow()? changeHandler?.reset() + describe "serialization", -> + describe "when the underlying buffer has a path", -> + it "deserializes it searching for its path in the current project", -> + buffer = atom.project.bufferForPathSync('sample.js') + tokenizedBufferA = new TokenizedBuffer({ + buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert + }) + tokenizedBufferB = TokenizedBuffer.deserialize( + JSON.parse(JSON.stringify(tokenizedBufferA.serialize())), + atom + ) + + expect(tokenizedBufferB.buffer).toBe(tokenizedBufferA.buffer) + + describe "when the underlying buffer has no path", -> + it "deserializes it searching for its id in the current project", -> + buffer = atom.project.bufferForPathSync(null) + + tokenizedBufferA = new TokenizedBuffer({ + buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert + }) + tokenizedBufferB = TokenizedBuffer.deserialize( + JSON.parse(JSON.stringify(tokenizedBufferA.serialize())), + atom + ) + + expect(tokenizedBufferB.buffer).toBe(tokenizedBufferA.buffer) + describe "when the buffer is destroyed", -> beforeEach -> buffer = atom.project.bufferForPathSync('sample.js') diff --git a/src/project.coffee b/src/project.coffee index bb9c8be80..badca3cce 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -308,12 +308,20 @@ class Project extends Model findBufferForPath: (filePath) -> _.find @buffers, (buffer) -> buffer.getPath() is filePath + findBufferForId: (id) -> + _.find @buffers, (buffer) -> buffer.getId() is id + # Only to be used in specs bufferForPathSync: (filePath) -> absoluteFilePath = @resolvePath(filePath) existingBuffer = @findBufferForPath(absoluteFilePath) if filePath existingBuffer ? @buildBufferSync(absoluteFilePath) + # Only to be used when deserializing + bufferForIdSync: (id) -> + existingBuffer = @findBufferForId(id) if id + existingBuffer ? @buildBufferSync(absoluteFilePath) + # Given a file path, this retrieves or creates a new {TextBuffer}. # # If the `filePath` already has a `buffer`, that value is used instead. Otherwise, diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 2df29a31c..31a19cbad 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -22,7 +22,10 @@ class TokenizedBuffer extends Model changeCount: 0 @deserialize: (state, atomEnvironment) -> - state.buffer = atomEnvironment.project.bufferForPathSync(state.bufferPath) + if state.bufferPath + state.buffer = atomEnvironment.project.bufferForPathSync(state.bufferPath) + else + state.buffer = atomEnvironment.project.bufferForIdSync(state.bufferId) state.config = atomEnvironment.config state.grammarRegistry = atomEnvironment.grammars state.packageManager = atomEnvironment.packages @@ -53,6 +56,7 @@ class TokenizedBuffer extends Model serialize: -> deserializer: 'TokenizedBuffer' bufferPath: @buffer.getPath() + bufferId: @buffer.getId() tabLength: @tabLength ignoreInvisibles: @ignoreInvisibles largeFileMode: @largeFileMode From afd05f391f7917c570fe4100fb4d7c115630be31 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 7 Dec 2015 14:50:34 +0100 Subject: [PATCH 103/137] Don't prompt to save when a window close is requested Fixes #942 --- src/text-editor.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index a151c9dba..1435aef19 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -677,7 +677,7 @@ class TextEditor extends Model # this editor. shouldPromptToSave: ({windowCloseRequested}={}) -> if windowCloseRequested - @isModified() + false else @isModified() and not @buffer.hasMultipleEditors() From 08f48a8a9d556bd713d0651f3daae5ee4608ec82 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 7 Dec 2015 15:20:20 +0100 Subject: [PATCH 104/137] :fire: --- src/project.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/project.coffee b/src/project.coffee index badca3cce..f97331bd4 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -320,7 +320,7 @@ class Project extends Model # Only to be used when deserializing bufferForIdSync: (id) -> existingBuffer = @findBufferForId(id) if id - existingBuffer ? @buildBufferSync(absoluteFilePath) + existingBuffer ? @buildBufferSync() # Given a file path, this retrieves or creates a new {TextBuffer}. # From e0bb800dd32c5664c2b5384399dcaf10ec326e0a Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 7 Dec 2015 15:54:22 +0100 Subject: [PATCH 105/137] :white_check_mark: Write integration spec --- spec/workspace-spec.coffee | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index e06a3e598..35585479b 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -43,6 +43,9 @@ describe "Workspace", -> pane3 = pane2.splitRight(copyActiveItem: true) pane4 = null + waitsForPromise -> + atom.workspace.open(null).then (editor) -> editor.setText("An untitled editor.") + waitsForPromise -> atom.workspace.open('b').then (editor) -> pane2.activateItem(editor.copy()) @@ -65,15 +68,16 @@ describe "Workspace", -> simulateReload() - expect(atom.workspace.getTextEditors().length).toBe 4 - [editor1, editor2, editor3, editor4] = atom.workspace.getTextEditors() - + expect(atom.workspace.getTextEditors().length).toBe 5 + [editor1, editor2, untitledEditor, editor3, editor4] = atom.workspace.getTextEditors() expect(editor1.getPath()).toBe atom.project.getDirectories()[0]?.resolve('b') expect(editor2.getPath()).toBe atom.project.getDirectories()[0]?.resolve('../sample.txt') expect(editor2.getCursorScreenPosition()).toEqual [0, 2] expect(editor3.getPath()).toBe atom.project.getDirectories()[0]?.resolve('b') expect(editor4.getPath()).toBe atom.project.getDirectories()[0]?.resolve('../sample.js') expect(editor4.getCursorScreenPosition()).toEqual [2, 4] + expect(untitledEditor.getPath()).toBeUndefined() + expect(untitledEditor.getText()).toBe("An untitled editor.") expect(atom.workspace.getActiveTextEditor().getPath()).toBe editor3.getPath() expect(document.title).toMatch ///^#{path.basename(editor3.getLongTitle())}\ \u2014\ #{atom.project.getPaths()[0]}/// From 80fdfb9280e94ca4ecbe8a5c02fa946dd54389d5 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 7 Dec 2015 09:34:34 -0800 Subject: [PATCH 106/137] :arrow_up: find-and-replace --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b4dcdc9f6..6beba336d 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "dev-live-reload": "0.47.0", "encoding-selector": "0.21.0", "exception-reporting": "0.37.0", - "find-and-replace": "0.192.0", + "find-and-replace": "0.193.0", "fuzzy-finder": "0.93.0", "git-diff": "0.57.0", "go-to-line": "0.30.0", From fbbcdbf5185f2a08dd1705d7a11767920e662f71 Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Sun, 6 Dec 2015 17:20:06 -0800 Subject: [PATCH 107/137] order keys in config.cson alphabetically --- src/config.coffee | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/config.coffee b/src/config.coffee index d2759fcb4..2e4387732 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -827,6 +827,7 @@ class Config allSettings = {'*': @settings} allSettings = _.extend allSettings, @scopedSettingsStore.propertiesForSource(@getUserConfigPath()) + allSettings = sortObject(allSettings) try CSON.writeFileSync(@configFilePath, allSettings) catch error @@ -1190,6 +1191,13 @@ Config.addSchemaEnforcers isPlainObject = (value) -> _.isObject(value) and not _.isArray(value) and not _.isFunction(value) and not _.isString(value) and not (value instanceof Color) +sortObject = (value) -> + return value unless isPlainObject(value) + result = {} + for key in Object.keys(value).sort() + result[key] = sortObject(value[key]) + result + withoutEmptyObjects = (object) -> resultObject = undefined if isPlainObject(object) From 0fa62d23ede8191b43afd1271de33cc0bd0efa1a Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 7 Dec 2015 19:29:51 +0100 Subject: [PATCH 108/137] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5ca330287..0f82c0435 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "service-hub": "^0.7.0", "source-map-support": "^0.3.2", "temp": "0.8.1", - "text-buffer": "8.0.9", + "text-buffer": "8.1.0", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "yargs": "^3.23.0" From a8a9581ef469d96152d00123f1836c90945f14d5 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 7 Dec 2015 19:01:54 +0100 Subject: [PATCH 109/137] :art: Use only id --- spec/tokenized-buffer-spec.coffee | 4 ++-- src/project.coffee | 3 --- src/tokenized-buffer.coffee | 7 ++++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/spec/tokenized-buffer-spec.coffee b/spec/tokenized-buffer-spec.coffee index 1d53cc6bd..76314681c 100644 --- a/spec/tokenized-buffer-spec.coffee +++ b/spec/tokenized-buffer-spec.coffee @@ -26,7 +26,7 @@ describe "TokenizedBuffer", -> describe "serialization", -> describe "when the underlying buffer has a path", -> - it "deserializes it searching for its path in the current project", -> + it "deserializes it searching among the buffers in the current project", -> buffer = atom.project.bufferForPathSync('sample.js') tokenizedBufferA = new TokenizedBuffer({ buffer, config: atom.config, grammarRegistry: atom.grammars, packageManager: atom.packages, assert: atom.assert @@ -39,7 +39,7 @@ describe "TokenizedBuffer", -> expect(tokenizedBufferB.buffer).toBe(tokenizedBufferA.buffer) describe "when the underlying buffer has no path", -> - it "deserializes it searching for its id in the current project", -> + it "deserializes it searching among the buffers in the current project", -> buffer = atom.project.bufferForPathSync(null) tokenizedBufferA = new TokenizedBuffer({ diff --git a/src/project.coffee b/src/project.coffee index f97331bd4..d59c041cb 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -337,9 +337,6 @@ class Project extends Model else @buildBuffer(absoluteFilePath) - bufferForId: (id) -> - _.find @buffers, (buffer) -> buffer.id is id - # Still needed when deserializing a tokenized buffer buildBufferSync: (absoluteFilePath) -> buffer = new TextBuffer({filePath: absoluteFilePath}) diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 31a19cbad..cdafc2869 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -22,10 +22,11 @@ class TokenizedBuffer extends Model changeCount: 0 @deserialize: (state, atomEnvironment) -> - if state.bufferPath - state.buffer = atomEnvironment.project.bufferForPathSync(state.bufferPath) - else + if state.bufferId state.buffer = atomEnvironment.project.bufferForIdSync(state.bufferId) + else + # TODO: remove this fallback after everyone transitions to the latest version. + state.buffer = atomEnvironment.project.bufferForPathSync(state.bufferPath) state.config = atomEnvironment.config state.grammarRegistry = atomEnvironment.grammars state.packageManager = atomEnvironment.packages From 1f955f0aab2c247cac24dcc12b32e1d5bf221e7a Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 7 Dec 2015 22:03:20 +0100 Subject: [PATCH 110/137] :fire: :green_heart: Remove outdated spec This made the build fail because we were checking that a TextEditor couldn't have been serialized when the path didn't exist. This is exactly the opposite we want to do for restoring untitled editors, therefore I think it's safe to delete this test. /cc: @nathansobo for extra :eyes: --- spec/text-editor-spec.coffee | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 43265c58d..02d2e4a96 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -22,17 +22,6 @@ describe "TextEditor", -> atom.packages.activatePackage('language-javascript') describe "when the editor is deserialized", -> - it "returns undefined when the path cannot be read", -> - pathToOpen = path.join(temp.mkdirSync(), 'file.txt') - editor1 = null - - waitsForPromise -> - atom.workspace.open(pathToOpen).then (o) -> editor1 = o - - runs -> - fs.mkdirSync(pathToOpen) - expect(TextEditor.deserialize(editor1.serialize(), atom)).toBeUndefined() - it "restores selections and folds based on markers in the buffer", -> editor.setSelectedBufferRange([[1, 2], [3, 4]]) editor.addSelectionForBufferRange([[5, 6], [7, 5]], reversed: true) From 4f9e1a8ca3939f887a0c516c1ebe384247faed1e Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 7 Dec 2015 14:25:11 -0700 Subject: [PATCH 111/137] Increase stack trace size limit to 30 --- src/compile-cache.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/compile-cache.js b/src/compile-cache.js index f7726b4b3..f11856a47 100644 --- a/src/compile-cache.js +++ b/src/compile-cache.js @@ -158,6 +158,8 @@ require('source-map-support').install({ } }) +Error.stackTraceLimit = 30 + var sourceMapPrepareStackTrace = Error.prepareStackTrace var prepareStackTrace = sourceMapPrepareStackTrace From ec759f1322fab123da8785616f290e3623a03661 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 7 Dec 2015 16:49:55 -0800 Subject: [PATCH 112/137] Clear out loaded packages in PackageManager.prototype.reset This way, when the AtomEnvironment is reset, packages will have .load() called on them again, so their config schemas will be registered again. --- src/package-manager.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 5b0264212..5ef0d2a46 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -62,6 +62,7 @@ class PackageManager reset: -> @serviceHub.clear() @deactivatePackages() + @loadedPackages = {} @packageStates = {} ### From 05e10bfaeb9d22c2d871148f75158ad22d7c156a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 7 Dec 2015 16:52:33 -0800 Subject: [PATCH 113/137] Register config schemas from package.json in theme packages --- src/theme-package.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/theme-package.coffee b/src/theme-package.coffee index 084728869..502fbd52b 100644 --- a/src/theme-package.coffee +++ b/src/theme-package.coffee @@ -14,6 +14,7 @@ class ThemePackage extends Package load: -> @loadTime = 0 + @configSchemaRegisteredOnLoad = @registerConfigSchemaFromMetadata() this activate: -> From 03a2846eb5b741ffe0b6900ee1a41acc1f12bebb Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 7 Dec 2015 17:24:34 -0800 Subject: [PATCH 114/137] Remove redundant unloadPackage call in spec --- spec/package-manager-spec.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index b504f676f..e7f4214a9 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -167,7 +167,6 @@ describe "PackageManager", -> describe "when a package does not have deserializers, view providers or a config schema in its package.json", -> beforeEach -> - atom.packages.unloadPackage('package-with-main') mockLocalStorage() it "defers loading the package's main module if the package previously used no Atom APIs when its main module was required", -> From 665e855911b632ed0e8ab9c6386fca55e4c2c685 Mon Sep 17 00:00:00 2001 From: Sander van Harmelen Date: Thu, 5 Nov 2015 10:47:23 +0100 Subject: [PATCH 115/137] :arrow_up: language-go@0.40.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bfbaadefd..d6e774150 100644 --- a/package.json +++ b/package.json @@ -122,7 +122,7 @@ "language-css": "0.34.0", "language-gfm": "0.81.0", "language-git": "0.10.0", - "language-go": "0.39.0", + "language-go": "0.40.0", "language-html": "0.42.0", "language-hyperlink": "0.15.0", "language-java": "0.16.0", From 82c27e896e8fd0437c05538ff6d749253ef5a34a Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Tue, 8 Dec 2015 09:35:14 -0500 Subject: [PATCH 116/137] :arrow_up: language-xml@0.34.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6beba336d..2a6582d4b 100644 --- a/package.json +++ b/package.json @@ -146,7 +146,7 @@ "language-text": "0.7.0", "language-todo": "0.27.0", "language-toml": "0.18.0", - "language-xml": "0.34.1", + "language-xml": "0.34.2", "language-yaml": "0.25.0" }, "private": true, From 314a1234f498ca4945b80a36c1f44f880c82e2aa Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 8 Dec 2015 11:09:52 -0800 Subject: [PATCH 117/137] Track which packages are in the process of activating This fixes a race condition where a package's activation promise resolves asynchronously after it has been deactivated, causing it to stay in the package manager's @activePackages object. --- src/package-manager.coffee | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 5ef0d2a46..6772178af 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -47,6 +47,7 @@ class PackageManager @packagesCache = require('../package.json')?._atomPackages ? {} @loadedPackages = {} @activePackages = {} + @activatingPackages = {} @packageStates = {} @serviceHub = new ServiceHub @@ -437,9 +438,12 @@ class PackageManager if pack = @getActivePackage(name) Promise.resolve(pack) else if pack = @loadPackage(name) + @activatingPackages[pack.name] = pack pack.activate().then => - @activePackages[pack.name] = pack - @emitter.emit 'did-activate-package', pack + if @activatingPackages[pack.name]? + delete @activatingPackages[pack.name] + @activePackages[pack.name] = pack + @emitter.emit 'did-activate-package', pack pack else Promise.reject(new Error("Failed to load package '#{name}'")) @@ -475,6 +479,7 @@ class PackageManager @setPackageState(pack.name, state) if state = pack.serialize?() pack.deactivate() delete @activePackages[pack.name] + delete @activatingPackages[pack.name] @emitter.emit 'did-deactivate-package', pack handleMetadataError: (error, packagePath) -> From d835ac0ac849a398d63ec0beaac1361aec2cd248 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 8 Dec 2015 11:27:20 -0800 Subject: [PATCH 118/137] Add spec for re-registering schema after unloading package --- spec/package-manager-spec.coffee | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index e7f4214a9..e6848ef03 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -154,7 +154,6 @@ describe "PackageManager", -> it "registers the config schema in the package's metadata, if present", -> pack = atom.packages.loadPackage("package-with-json-config-schema") - expect(atom.config.getSchema('package-with-json-config-schema')).toEqual { type: 'object' properties: { @@ -165,6 +164,18 @@ describe "PackageManager", -> expect(pack.mainModule).toBeNull() + atom.packages.unloadPackage('package-with-json-config-schema') + atom.config.clear() + + pack = atom.packages.loadPackage("package-with-json-config-schema") + expect(atom.config.getSchema('package-with-json-config-schema')).toEqual { + type: 'object' + properties: { + a: {type: 'number', default: 5} + b: {type: 'string', default: 'five'} + } + } + describe "when a package does not have deserializers, view providers or a config schema in its package.json", -> beforeEach -> mockLocalStorage() From 916da68ee5b71204e71aa77659759d95bdf60de2 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Dec 2015 14:11:14 -0700 Subject: [PATCH 119/137] :arrow_up: find-and-replace for layer service --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 66d85ffad..48a1431f6 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "dev-live-reload": "0.47.0", "encoding-selector": "0.21.0", "exception-reporting": "0.37.0", - "find-and-replace": "0.191.0", + "find-and-replace": "0.194.0", "fuzzy-finder": "0.93.0", "git-diff": "0.57.0", "go-to-line": "0.30.0", From 54169b53a8ccbe69a37baa4d4f765a2b34739f4a Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Dec 2015 14:11:39 -0700 Subject: [PATCH 120/137] 1.3.0-beta8 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 48a1431f6..29a0c59a2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "1.3.0-beta7", + "version": "1.3.0-beta8", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 7718d5cb56692a7eb102a2e158e5d7aa9a8e77e4 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 24 Nov 2015 11:59:53 -0700 Subject: [PATCH 121/137] Merge pull request #9773 from atom/mb-ns-prepare-stack-trace-fixes Allow Error.prepareStackTrace to be temporarily reassigned --- spec/compile-cache-spec.coffee | 15 ++++++++++++++ src/compile-cache.js | 38 ++++++++++++++++++++-------------- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/spec/compile-cache-spec.coffee b/spec/compile-cache-spec.coffee index d80e05fc5..8a6cc214e 100644 --- a/spec/compile-cache-spec.coffee +++ b/spec/compile-cache-spec.coffee @@ -69,3 +69,18 @@ describe 'CompileCache', -> CompileCache.addPathToCache(path.join(fixtures, 'cson.cson'), atomHome) expect(CSONParser.parse.callCount).toBe 1 + + describe 'overriding Error.prepareStackTrace', -> + it 'removes the override on the next tick, and always assigns the raw stack', -> + Error.prepareStackTrace = -> 'a-stack-trace' + + error = new Error("Oops") + expect(error.stack).toBe 'a-stack-trace' + expect(Array.isArray(error.getRawStack())).toBe true + + waits(1) + runs -> + error = new Error("Oops again") + console.log error.stack + expect(error.stack).toContain('compile-cache-spec.coffee') + expect(Array.isArray(error.getRawStack())).toBe true diff --git a/src/compile-cache.js b/src/compile-cache.js index f11856a47..aed72ee36 100644 --- a/src/compile-cache.js +++ b/src/compile-cache.js @@ -160,25 +160,33 @@ require('source-map-support').install({ Error.stackTraceLimit = 30 -var sourceMapPrepareStackTrace = Error.prepareStackTrace -var prepareStackTrace = sourceMapPrepareStackTrace +var prepareStackTraceWithSourceMapping = Error.prepareStackTrace -// Prevent coffee-script from reassigning Error.prepareStackTrace -Object.defineProperty(Error, 'prepareStackTrace', { - get: function () { return prepareStackTrace }, - set: function (newValue) {} -}) +let prepareStackTrace = prepareStackTraceWithSourceMapping -// Enable Grim to access the raw stack without reassigning Error.prepareStackTrace -Error.prototype.getRawStack = function () { // eslint-disable-line no-extend-native - prepareStackTrace = getRawStack - var result = this.stack - prepareStackTrace = sourceMapPrepareStackTrace - return result +function prepareStackTraceWithRawStackAssignment (error, frames) { + error.rawStack = frames + return prepareStackTrace(error, frames) } -function getRawStack (_, stack) { - return stack +Object.defineProperty(Error, 'prepareStackTrace', { + get: function () { + return prepareStackTraceWithRawStackAssignment + }, + + set: function (newValue) { + prepareStackTrace = newValue + process.nextTick(function () { + prepareStackTrace = prepareStackTraceWithSourceMapping + }) + } +}) + +Error.prototype.getRawStack = function () { // eslint-disable-line no-extend-native + // Access this.stack to ensure prepareStackTrace has been run on this error + // because it assigns this.rawStack as a side-effect + this.stack + return this.rawStack } Object.keys(COMPILERS).forEach(function (extension) { From 3567d477903d837ad68d8f828696d8a93fc7a356 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 30 Nov 2015 12:32:06 -0800 Subject: [PATCH 122/137] Merge pull request #9878 from atom/ns-mb-fix-prepare-stack-trace-recursion Avoid infinite recursion in Error.prepareStackTrace --- spec/compile-cache-spec.coffee | 23 ++++++++++++++++++++++- src/compile-cache.js | 8 ++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/spec/compile-cache-spec.coffee b/spec/compile-cache-spec.coffee index 8a6cc214e..848da6b49 100644 --- a/spec/compile-cache-spec.coffee +++ b/spec/compile-cache-spec.coffee @@ -81,6 +81,27 @@ describe 'CompileCache', -> waits(1) runs -> error = new Error("Oops again") - console.log error.stack expect(error.stack).toContain('compile-cache-spec.coffee') expect(Array.isArray(error.getRawStack())).toBe true + + it 'does not infinitely loop when the original prepareStackTrace value is reassigned', -> + originalPrepareStackTrace = Error.prepareStackTrace + + Error.prepareStackTrace = -> 'a-stack-trace' + Error.prepareStackTrace = originalPrepareStackTrace + + error = new Error('Oops') + expect(error.stack).toContain('compile-cache-spec.coffee') + expect(Array.isArray(error.getRawStack())).toBe true + + it 'does not infinitely loop when the assigned prepareStackTrace calls the original prepareStackTrace', -> + originalPrepareStackTrace = Error.prepareStackTrace + + Error.prepareStackTrace = (error, stack) -> + error.foo = 'bar' + originalPrepareStackTrace(error, stack) + + error = new Error('Oops') + expect(error.stack).toContain('compile-cache-spec.coffee') + expect(error.foo).toBe('bar') + expect(Array.isArray(error.getRawStack())).toBe true diff --git a/src/compile-cache.js b/src/compile-cache.js index aed72ee36..fde04a2f4 100644 --- a/src/compile-cache.js +++ b/src/compile-cache.js @@ -165,8 +165,12 @@ var prepareStackTraceWithSourceMapping = Error.prepareStackTrace let prepareStackTrace = prepareStackTraceWithSourceMapping function prepareStackTraceWithRawStackAssignment (error, frames) { - error.rawStack = frames - return prepareStackTrace(error, frames) + if (error.rawStack) { // avoid infinite recursion + return prepareStackTraceWithSourceMapping(error, frames) + } else { + error.rawStack = frames + return prepareStackTrace(error, frames) + } } Object.defineProperty(Error, 'prepareStackTrace', { From cd9bf67d988bc988a7ff90562762f11c19c91a66 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Dec 2015 14:32:32 -0700 Subject: [PATCH 123/137] Fix bad merge. Oops. --- package.json | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/package.json b/package.json index 4904554c4..da93467d6 100644 --- a/package.json +++ b/package.json @@ -87,11 +87,7 @@ "dev-live-reload": "0.47.0", "encoding-selector": "0.21.0", "exception-reporting": "0.37.0", -<<<<<<< HEAD - "find-and-replace": "0.193.0", -======= "find-and-replace": "0.194.0", ->>>>>>> beta "fuzzy-finder": "0.93.0", "git-diff": "0.57.0", "go-to-line": "0.30.0", @@ -101,13 +97,8 @@ "keybinding-resolver": "0.33.0", "line-ending-selector": "0.3.0", "link": "0.31.0", -<<<<<<< HEAD "markdown-preview": "0.157.0", "metrics": "0.53.1", -======= - "markdown-preview": "0.156.1", - "metrics": "0.53.0", ->>>>>>> beta "notifications": "0.62.1", "open-on-github": "0.40.0", "package-generator": "0.41.0", @@ -125,15 +116,9 @@ "welcome": "0.33.0", "whitespace": "0.32.1", "wrap-guide": "0.38.1", -<<<<<<< HEAD "language-c": "0.51.0", "language-clojure": "0.19.0", "language-coffee-script": "0.46.0", -======= - "language-c": "0.49.0", - "language-clojure": "0.18.0", - "language-coffee-script": "0.45.0", ->>>>>>> beta "language-csharp": "0.11.0", "language-css": "0.36.0", "language-gfm": "0.82.0", From 14a440e0f1f43d3b174d3192d29e9f764ff6fc0f Mon Sep 17 00:00:00 2001 From: simurai Date: Tue, 8 Dec 2015 13:57:33 -0800 Subject: [PATCH 124/137] :arrow_up: one-dark/light-ui@v1.1.8 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index da93467d6..b002b05fd 100644 --- a/package.json +++ b/package.json @@ -64,10 +64,10 @@ "atom-light-ui": "0.43.0", "base16-tomorrow-dark-theme": "1.0.0", "base16-tomorrow-light-theme": "1.0.0", - "one-dark-ui": "1.1.7", + "one-dark-ui": "1.1.8", "one-dark-syntax": "1.1.1", "one-light-syntax": "1.1.1", - "one-light-ui": "1.1.7", + "one-light-ui": "1.1.8", "solarized-dark-syntax": "0.39.0", "solarized-light-syntax": "0.23.0", "about": "1.1.0", From bef0e5c99457811f0aa14349683cf24f093820d9 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 8 Dec 2015 14:39:14 -0800 Subject: [PATCH 125/137] Set mac version properly on beta --- build/tasks/set-version-task.coffee | 3 ++- script/set-version | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/build/tasks/set-version-task.coffee b/build/tasks/set-version-task.coffee index 28abb6493..fc2382476 100644 --- a/build/tasks/set-version-task.coffee +++ b/build/tasks/set-version-task.coffee @@ -29,6 +29,7 @@ module.exports = (grunt) -> return appDir = grunt.config.get('atom.appDir') + shellAppDir = grunt.config.get('atom.shellAppDir') # Replace version field of package.json. packageJsonPath = path.join(appDir, 'package.json') @@ -39,7 +40,7 @@ module.exports = (grunt) -> if process.platform is 'darwin' cmd = 'script/set-version' - args = [grunt.config.get('atom.buildDir'), version] + args = [shellAppDir, version] spawn {cmd, args}, (error, result, code) -> done(error) else if process.platform is 'win32' shellAppDir = grunt.config.get('atom.shellAppDir') diff --git a/script/set-version b/script/set-version index 7cad26799..33dec9d77 100755 --- a/script/set-version +++ b/script/set-version @@ -2,10 +2,11 @@ set -e -BUILT_PRODUCTS_DIR=$1 +SHELL_APP_DIR=$1 VERSION=$2 -PLIST_PATH="$BUILT_PRODUCTS_DIR/Atom.app/Contents/Info.plist" -HELPER_PLIST_PATH="$BUILT_PRODUCTS_DIR/Atom.app/Contents/Frameworks/Atom Helper.app/Contents/Info.plist" + +PLIST_PATH="$SHELL_APP_DIR/Contents/Info.plist" +HELPER_PLIST_PATH="$SHELL_APP_DIR/Contents/Frameworks/Atom Helper.app/Contents/Info.plist" # Update version /usr/libexec/PlistBuddy -c "Set CFBundleShortVersionString $VERSION" "$PLIST_PATH" From efe33d69fd2be94f5bbff22d4700e6a59c8781b9 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Dec 2015 16:09:58 -0700 Subject: [PATCH 126/137] Back to 1.3.0-beta7 because it wasn't published --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 29a0c59a2..48a1431f6 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "1.3.0-beta8", + "version": "1.3.0-beta7", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 80faae4add608029a79edf8df5f9c277420f4c13 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Tue, 8 Dec 2015 22:30:28 -0500 Subject: [PATCH 127/137] :arrow_up: language-c@0.51.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b002b05fd..30452701a 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "welcome": "0.33.0", "whitespace": "0.32.1", "wrap-guide": "0.38.1", - "language-c": "0.51.0", + "language-c": "0.51.1", "language-clojure": "0.19.0", "language-coffee-script": "0.46.0", "language-csharp": "0.11.0", From b3b8b8d5639bb88eac296a0a29a7ae02c4b1d55e Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 9 Dec 2015 08:31:31 +0100 Subject: [PATCH 128/137] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 30452701a..50e4d4d09 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "service-hub": "^0.7.0", "source-map-support": "^0.3.2", "temp": "0.8.1", - "text-buffer": "8.0.9", + "text-buffer": "8.1.1", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "yargs": "^3.23.0" From 9dd61ca7e6466eae22f434a26389eb3c6bd98238 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 9 Dec 2015 08:37:54 +0100 Subject: [PATCH 129/137] :memo: Mention switching encoding speedup --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 057b8bcf3..f983b699c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,3 +10,4 @@ See https://atom.io/releases * Fixed an issue where characters were inserted when toggling the settings view on some keyboard layouts. * Modules can now temporarily override `Error.prepareStackTrace`. There is also an `Error.prototype.getRawStack()` method if you just need access to the raw v8 trace structure. * Fixed a problem that caused blurry fonts on monitors that have a slightly higher resolution than 96 DPI. +* Switching encoding is now fast also with large files. From 02b2f06ae1006c98572431ff2f6a719acf7ec63d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 9 Dec 2015 08:38:35 +0100 Subject: [PATCH 130/137] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f983b699c..68113c1ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,4 +10,7 @@ See https://atom.io/releases * Fixed an issue where characters were inserted when toggling the settings view on some keyboard layouts. * Modules can now temporarily override `Error.prepareStackTrace`. There is also an `Error.prototype.getRawStack()` method if you just need access to the raw v8 trace structure. * Fixed a problem that caused blurry fonts on monitors that have a slightly higher resolution than 96 DPI. + +## 1.4.0 + * Switching encoding is now fast also with large files. From f709c43159df2702d0763b7ab631b8d05c8ceb49 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 9 Dec 2015 08:40:06 +0100 Subject: [PATCH 131/137] Reorder changelog --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68113c1ec..b841c0e78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ See https://atom.io/releases +## 1.4.0 + +* Switching encoding is now fast also with large files. + ## 1.3.0 * The tree-view now sorts directory entries more naturally, in a locale-sensitive way. @@ -10,7 +14,3 @@ See https://atom.io/releases * Fixed an issue where characters were inserted when toggling the settings view on some keyboard layouts. * Modules can now temporarily override `Error.prepareStackTrace`. There is also an `Error.prototype.getRawStack()` method if you just need access to the raw v8 trace structure. * Fixed a problem that caused blurry fonts on monitors that have a slightly higher resolution than 96 DPI. - -## 1.4.0 - -* Switching encoding is now fast also with large files. From 38b72dc156112eb5d836f94ec924abbd3a09e553 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 9 Dec 2015 08:41:34 +0100 Subject: [PATCH 132/137] :memo: Mention reloading keymaps fix --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b841c0e78..e00c92c86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ See https://atom.io/releases ## 1.4.0 * Switching encoding is now fast also with large files. +* Fixed an issue where disabling and re-enabling a package caused custom keymaps to be overridden. ## 1.3.0 From d7f1f7bb62694b7245ca051bc8a44f1856156bec Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 9 Dec 2015 12:05:13 +0100 Subject: [PATCH 133/137] :memo: Mention the fix for untitled editors [ci skip] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e00c92c86..e36b3f59e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ See https://atom.io/releases * Switching encoding is now fast also with large files. * Fixed an issue where disabling and re-enabling a package caused custom keymaps to be overridden. +* Fixed restoring untitled editors on restart. The new behavior never prompts to save new/changed files when closing a window or quitting Atom. ## 1.3.0 From f3e257cad899b225800533e558e60f163ce99fa9 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 9 Dec 2015 14:18:27 -0800 Subject: [PATCH 134/137] 1.5.0-dev --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 50e4d4d09..e0b4904ca 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "1.4.0-dev", + "version": "1.5.0-dev", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From 255864fc9d2620aec693424a6b827d231582c41b Mon Sep 17 00:00:00 2001 From: Sander van Harmelen Date: Thu, 10 Dec 2015 13:52:10 +0100 Subject: [PATCH 135/137] :arrow_up: language-go@0.41.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e0b4904ca..e61892fc3 100644 --- a/package.json +++ b/package.json @@ -123,7 +123,7 @@ "language-css": "0.36.0", "language-gfm": "0.82.0", "language-git": "0.11.0", - "language-go": "0.40.0", + "language-go": "0.41.0", "language-html": "0.43.1", "language-hyperlink": "0.16.0", "language-java": "0.17.0", From 50dc9b6bb4de32f3a3b2ed2e5e83e64fc1f3422d Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 11 Dec 2015 06:17:15 +0900 Subject: [PATCH 136/137] :arrow_up: one-dark/light-ui@v1.1.9 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e61892fc3..36ffb2dcb 100644 --- a/package.json +++ b/package.json @@ -64,10 +64,10 @@ "atom-light-ui": "0.43.0", "base16-tomorrow-dark-theme": "1.0.0", "base16-tomorrow-light-theme": "1.0.0", - "one-dark-ui": "1.1.8", + "one-dark-ui": "1.1.9", "one-dark-syntax": "1.1.1", "one-light-syntax": "1.1.1", - "one-light-ui": "1.1.8", + "one-light-ui": "1.1.9", "solarized-dark-syntax": "0.39.0", "solarized-light-syntax": "0.23.0", "about": "1.1.0", From 85c61395798240c80a6816d8abee54aa7519af76 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 4 Dec 2015 19:02:24 -0700 Subject: [PATCH 137/137] =?UTF-8?q?Don=E2=80=99t=20force=20DOM=20updates?= =?UTF-8?q?=20in=20LinesYardstick?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead, determine the need for a DOM update in the component before measuring with the lines yardstick, and break `updateSync` into two explicit pre- and post-measurement phases. --- spec/fake-lines-yardstick.coffee | 23 +- spec/lines-yardstick-spec.coffee | 42 +-- spec/text-editor-presenter-spec.coffee | 492 +++++++++++++------------ src/lines-yardstick.coffee | 47 +-- src/text-editor-component.coffee | 49 ++- src/text-editor-presenter.coffee | 30 +- 6 files changed, 323 insertions(+), 360 deletions(-) diff --git a/spec/fake-lines-yardstick.coffee b/spec/fake-lines-yardstick.coffee index 1872b8c65..da5f8327e 100644 --- a/spec/fake-lines-yardstick.coffee +++ b/spec/fake-lines-yardstick.coffee @@ -2,13 +2,9 @@ module.exports = class FakeLinesYardstick - constructor: (@model, @presenter) -> + constructor: (@model) -> @characterWidthsByScope = {} - prepareScreenRowsForMeasurement: -> - @presenter.getPreMeasurementState() - @screenRows = new Set(@presenter.getScreenRows()) - getScopedCharacterWidth: (scopeNames, char) -> @getScopedCharacterWidths(scopeNames)[char] @@ -35,8 +31,6 @@ class FakeLinesYardstick left = 0 column = 0 - return {top, left: 0} unless @screenRows.has(screenPosition.row) - iterator = @model.tokenizedLineForScreenRow(targetRow).getTokenIterator() while iterator.next() characterWidths = @getScopedCharacterWidths(iterator.getScopes()) @@ -59,18 +53,3 @@ class FakeLinesYardstick column += charLength {top, left} - - pixelRectForScreenRange: (screenRange) -> - lineHeight = @model.getLineHeightInPixels() - - if screenRange.end.row > screenRange.start.row - top = @pixelPositionForScreenPosition(screenRange.start).top - left = 0 - height = (screenRange.end.row - screenRange.start.row + 1) * lineHeight - width = @presenter.getScrollWidth() - else - {top, left} = @pixelPositionForScreenPosition(screenRange.start, false) - height = lineHeight - width = @pixelPositionForScreenPosition(screenRange.end, false).left - left - - {top, left, width, height} diff --git a/spec/lines-yardstick-spec.coffee b/spec/lines-yardstick-spec.coffee index ae85a0e9d..74f5fca6a 100644 --- a/spec/lines-yardstick-spec.coffee +++ b/spec/lines-yardstick-spec.coffee @@ -2,7 +2,7 @@ LinesYardstick = require "../src/lines-yardstick" {toArray} = require 'underscore-plus' describe "LinesYardstick", -> - [editor, mockPresenter, mockLineNodesProvider, createdLineNodes, linesYardstick, buildLineNode] = [] + [editor, mockLineNodesProvider, createdLineNodes, linesYardstick, buildLineNode] = [] beforeEach -> waitsForPromise -> @@ -31,22 +31,10 @@ describe "LinesYardstick", -> createdLineNodes.push(lineNode) lineNode - mockPresenter = - setScreenRowsToMeasure: (screenRows) -> screenRowsToMeasure = screenRows - clearScreenRowsToMeasure: -> setScreenRowsToMeasure = [] - getPreMeasurementState: -> - state = {} - for screenRow in screenRowsToMeasure - tokenizedLine = editor.tokenizedLineForScreenRow(screenRow) - state[tokenizedLine.id] = screenRow - state - mockLineNodesProvider = - updateSync: (state) -> availableScreenRows = state lineNodeForLineIdAndScreenRow: (lineId, screenRow) -> - return if availableScreenRows[lineId] isnt screenRow - buildLineNode(screenRow) + textNodesForLineIdAndScreenRow: (lineId, screenRow) -> lineNode = @lineNodeForLineIdAndScreenRow(lineId, screenRow) iterator = document.createNodeIterator(lineNode, NodeFilter.SHOW_TEXT) @@ -56,7 +44,7 @@ describe "LinesYardstick", -> textNodes editor.setLineHeightInPixels(14) - linesYardstick = new LinesYardstick(editor, mockPresenter, mockLineNodesProvider, atom.grammars) + linesYardstick = new LinesYardstick(editor, mockLineNodesProvider, atom.grammars) afterEach -> lineNode.remove() for lineNode in createdLineNodes @@ -153,18 +141,6 @@ describe "LinesYardstick", -> expect(linesYardstick.pixelPositionForScreenPosition([0, 36]).left).toBe 237.5 expect(linesYardstick.pixelPositionForScreenPosition([0, 37]).left).toBe 244.09375 - it "doesn't measure invisible lines if it is explicitly told so", -> - atom.styles.addStyleSheet """ - * { - font-size: 12px; - font-family: monospace; - } - """ - - expect(linesYardstick.pixelPositionForScreenPosition([0, 0], true, true)).toEqual({left: 0, top: 0}) - expect(linesYardstick.pixelPositionForScreenPosition([0, 1], true, true)).toEqual({left: 0, top: 0}) - expect(linesYardstick.pixelPositionForScreenPosition([0, 5], true, true)).toEqual({left: 0, top: 0}) - describe "::screenPositionForPixelPosition(pixelPosition)", -> it "converts pixel positions to screen positions", -> atom.styles.addStyleSheet """ @@ -197,15 +173,3 @@ describe "LinesYardstick", -> expect(linesYardstick.screenPositionForPixelPosition(top: Infinity, left: Infinity)).toEqual [12, 2] expect(linesYardstick.screenPositionForPixelPosition(top: (editor.getLastScreenRow() + 1) * 14, left: 0)).toEqual [12, 2] expect(linesYardstick.screenPositionForPixelPosition(top: editor.getLastScreenRow() * 14, left: 0)).toEqual [12, 0] - - it "doesn't measure invisible lines if it is explicitly told so", -> - atom.styles.addStyleSheet """ - * { - font-size: 12px; - font-family: monospace; - } - """ - - expect(linesYardstick.screenPositionForPixelPosition({top: 0, left: 13}, true)).toEqual([0, 0]) - expect(linesYardstick.screenPositionForPixelPosition({top: 14, left: 20}, true)).toEqual([1, 0]) - expect(linesYardstick.screenPositionForPixelPosition({top: 28, left: 100}, true)).toEqual([2, 0]) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 2aeb8822e..effa579b1 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -9,7 +9,7 @@ FakeLinesYardstick = require './fake-lines-yardstick' describe "TextEditorPresenter", -> # These `describe` and `it` blocks mirror the structure of the ::state object. # Please maintain this structure when adding specs for new state fields. - describe "::getState()", -> + describe "::get(Pre|Post)MeasurementState()", -> [buffer, editor] = [] beforeEach -> @@ -25,6 +25,10 @@ describe "TextEditorPresenter", -> editor.destroy() buffer.destroy() + getState = (presenter) -> + presenter.getPreMeasurementState() + presenter.getPostMeasurementState() + buildPresenterWithoutMeasurements = (params={}) -> _.defaults params, model: editor @@ -279,7 +283,7 @@ describe "TextEditorPresenter", -> describe "during state retrieval", -> it "does not trigger onDidUpdateState events", -> presenter = buildPresenter() - expectNoStateUpdate presenter, -> presenter.getState() + expectNoStateUpdate presenter, -> getState(presenter) describe ".horizontalScrollbar", -> describe ".visible", -> @@ -292,19 +296,19 @@ describe "TextEditorPresenter", -> horizontalScrollbarHeight: 10 verticalScrollbarWidth: 10 - expect(presenter.getState().horizontalScrollbar.visible).toBe false + expect(getState(presenter).horizontalScrollbar.visible).toBe false # ::contentFrameWidth itself is smaller than scrollWidth presenter.setContentFrameWidth(editor.getMaxScreenLineLength() * 10) - expect(presenter.getState().horizontalScrollbar.visible).toBe true + expect(getState(presenter).horizontalScrollbar.visible).toBe true # restore... presenter.setContentFrameWidth(editor.getMaxScreenLineLength() * 10 + 1) - expect(presenter.getState().horizontalScrollbar.visible).toBe false + expect(getState(presenter).horizontalScrollbar.visible).toBe false # visible vertical scrollbar makes the clientWidth smaller than the scrollWidth presenter.setExplicitHeight((editor.getLineCount() * 10) - 1) - expect(presenter.getState().horizontalScrollbar.visible).toBe true + expect(getState(presenter).horizontalScrollbar.visible).toBe true it "is false if the editor is mini", -> presenter = buildPresenter @@ -312,18 +316,18 @@ describe "TextEditorPresenter", -> contentFrameWidth: editor.getMaxScreenLineLength() * 10 - 10 baseCharacterWidth: 10 - expect(presenter.getState().horizontalScrollbar.visible).toBe true + expect(getState(presenter).horizontalScrollbar.visible).toBe true editor.setMini(true) - expect(presenter.getState().horizontalScrollbar.visible).toBe false + expect(getState(presenter).horizontalScrollbar.visible).toBe false editor.setMini(false) - expect(presenter.getState().horizontalScrollbar.visible).toBe true + expect(getState(presenter).horizontalScrollbar.visible).toBe true describe ".height", -> it "tracks the value of ::horizontalScrollbarHeight", -> presenter = buildPresenter(horizontalScrollbarHeight: 10) - expect(presenter.getState().horizontalScrollbar.height).toBe 10 + expect(getState(presenter).horizontalScrollbar.height).toBe 10 expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(20) - expect(presenter.getState().horizontalScrollbar.height).toBe 20 + expect(getState(presenter).horizontalScrollbar.height).toBe 20 describe ".right", -> it "is ::verticalScrollbarWidth if the vertical scrollbar is visible and 0 otherwise", -> @@ -335,27 +339,27 @@ describe "TextEditorPresenter", -> horizontalScrollbarHeight: 10 verticalScrollbarWidth: 10 - expect(presenter.getState().horizontalScrollbar.right).toBe 0 + expect(getState(presenter).horizontalScrollbar.right).toBe 0 presenter.setExplicitHeight((editor.getLineCount() * 10) - 1) - expect(presenter.getState().horizontalScrollbar.right).toBe 10 + expect(getState(presenter).horizontalScrollbar.right).toBe 10 describe ".scrollWidth", -> it "is initialized as the max of the ::contentFrameWidth and the width of the longest line", -> maxLineLength = editor.getMaxScreenLineLength() presenter = buildPresenter(contentFrameWidth: 50, baseCharacterWidth: 10) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1 + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1 presenter = buildPresenter(contentFrameWidth: 10 * maxLineLength + 20, baseCharacterWidth: 10) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 20 + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 20 it "updates when the ::contentFrameWidth changes", -> maxLineLength = editor.getMaxScreenLineLength() presenter = buildPresenter(contentFrameWidth: 50, baseCharacterWidth: 10) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1 + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1 expectStateUpdate presenter, -> presenter.setContentFrameWidth(10 * maxLineLength + 20) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 20 + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 20 it "updates when character widths change", -> waitsForPromise -> atom.packages.activatePackage('language-javascript') @@ -364,72 +368,72 @@ describe "TextEditorPresenter", -> maxLineLength = editor.getMaxScreenLineLength() presenter = buildPresenter(contentFrameWidth: 50, baseCharacterWidth: 10) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1 + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1 expectStateUpdate presenter, -> presenter.getLinesYardstick().setScopedCharacterWidth(['source.js', 'support.function.js'], 'p', 20) presenter.characterWidthsChanged() - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe (10 * (maxLineLength - 2)) + (20 * 2) + 1 # 2 of the characters are 20px wide now instead of 10px wide + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe (10 * (maxLineLength - 2)) + (20 * 2) + 1 # 2 of the characters are 20px wide now instead of 10px wide it "updates when ::softWrapped changes on the editor", -> presenter = buildPresenter(contentFrameWidth: 470, baseCharacterWidth: 10) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 expectStateUpdate presenter, -> editor.setSoftWrapped(true) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe presenter.clientWidth + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe presenter.clientWidth expectStateUpdate presenter, -> editor.setSoftWrapped(false) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 it "updates when the longest line changes", -> presenter = buildPresenter(contentFrameWidth: 50, baseCharacterWidth: 10) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 expectStateUpdate presenter, -> editor.setCursorBufferPosition([editor.getLongestScreenRow(), 0]) expectStateUpdate presenter, -> editor.insertText('xyz') - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 describe ".scrollLeft", -> it "tracks the value of ::scrollLeft", -> presenter = buildPresenter(scrollLeft: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500) - expect(presenter.getState().horizontalScrollbar.scrollLeft).toBe 10 + expect(getState(presenter).horizontalScrollbar.scrollLeft).toBe 10 expectStateUpdate presenter, -> presenter.setScrollLeft(50) - expect(presenter.getState().horizontalScrollbar.scrollLeft).toBe 50 + expect(getState(presenter).horizontalScrollbar.scrollLeft).toBe 50 it "never exceeds the computed scrollWidth minus the computed clientWidth", -> presenter = buildPresenter(scrollLeft: 10, verticalScrollbarWidth: 10, explicitHeight: 100, contentFrameWidth: 500) expectStateUpdate presenter, -> presenter.setScrollLeft(300) - expect(presenter.getState().horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth + expect(getState(presenter).horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expectStateUpdate presenter, -> presenter.setContentFrameWidth(600) - expect(presenter.getState().horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth + expect(getState(presenter).horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expectStateUpdate presenter, -> presenter.setVerticalScrollbarWidth(5) - expect(presenter.getState().horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth + expect(getState(presenter).horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expectStateUpdate presenter, -> editor.getBuffer().delete([[6, 0], [6, Infinity]]) - expect(presenter.getState().horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth + expect(getState(presenter).horizontalScrollbar.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth # Scroll top only gets smaller when needed as dimensions change, never bigger - scrollLeftBefore = presenter.getState().horizontalScrollbar.scrollLeft + scrollLeftBefore = getState(presenter).horizontalScrollbar.scrollLeft expectStateUpdate presenter, -> editor.getBuffer().insert([6, 0], new Array(100).join('x')) - expect(presenter.getState().horizontalScrollbar.scrollLeft).toBe scrollLeftBefore + expect(getState(presenter).horizontalScrollbar.scrollLeft).toBe scrollLeftBefore it "never goes negative", -> presenter = buildPresenter(scrollLeft: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500) expectStateUpdate presenter, -> presenter.setScrollLeft(-300) - expect(presenter.getState().horizontalScrollbar.scrollLeft).toBe 0 + expect(getState(presenter).horizontalScrollbar.scrollLeft).toBe 0 it "is always 0 when soft wrapping is enabled", -> presenter = buildPresenter(scrollLeft: 0, verticalScrollbarWidth: 0, contentFrameWidth: 85, baseCharacterWidth: 10) editor.setSoftWrapped(false) presenter.setScrollLeft(Infinity) - expect(presenter.getState().content.scrollLeft).toBeGreaterThan 0 + expect(getState(presenter).content.scrollLeft).toBeGreaterThan 0 editor.setSoftWrapped(true) - expect(presenter.getState().content.scrollLeft).toBe 0 + expect(getState(presenter).content.scrollLeft).toBe 0 presenter.setScrollLeft(10) - expect(presenter.getState().content.scrollLeft).toBe 0 + expect(getState(presenter).content.scrollLeft).toBe 0 describe ".verticalScrollbar", -> describe ".visible", -> @@ -443,26 +447,26 @@ describe "TextEditorPresenter", -> horizontalScrollbarHeight: 10 verticalScrollbarWidth: 10 - expect(presenter.getState().verticalScrollbar.visible).toBe false + expect(getState(presenter).verticalScrollbar.visible).toBe false # ::explicitHeight itself is smaller than scrollWidth presenter.setExplicitHeight(editor.getLineCount() * 10 - 1) - expect(presenter.getState().verticalScrollbar.visible).toBe true + expect(getState(presenter).verticalScrollbar.visible).toBe true # restore... presenter.setExplicitHeight(editor.getLineCount() * 10) - expect(presenter.getState().verticalScrollbar.visible).toBe false + expect(getState(presenter).verticalScrollbar.visible).toBe false # visible horizontal scrollbar makes the clientHeight smaller than the scrollHeight presenter.setContentFrameWidth(editor.getMaxScreenLineLength() * 10) - expect(presenter.getState().verticalScrollbar.visible).toBe true + expect(getState(presenter).verticalScrollbar.visible).toBe true describe ".width", -> it "is assigned based on ::verticalScrollbarWidth", -> presenter = buildPresenter(verticalScrollbarWidth: 10) - expect(presenter.getState().verticalScrollbar.width).toBe 10 + expect(getState(presenter).verticalScrollbar.width).toBe 10 expectStateUpdate presenter, -> presenter.setVerticalScrollbarWidth(20) - expect(presenter.getState().verticalScrollbar.width).toBe 20 + expect(getState(presenter).verticalScrollbar.width).toBe 20 describe ".bottom", -> it "is ::horizontalScrollbarHeight if the horizontal scrollbar is visible and 0 otherwise", -> @@ -474,129 +478,129 @@ describe "TextEditorPresenter", -> horizontalScrollbarHeight: 10 verticalScrollbarWidth: 10 - expect(presenter.getState().verticalScrollbar.bottom).toBe 0 + expect(getState(presenter).verticalScrollbar.bottom).toBe 0 presenter.setContentFrameWidth(editor.getMaxScreenLineLength() * 10) - expect(presenter.getState().verticalScrollbar.bottom).toBe 10 + expect(getState(presenter).verticalScrollbar.bottom).toBe 10 describe ".scrollHeight", -> it "is initialized based on the lineHeight, the number of lines, and the height", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10) - expect(presenter.getState().verticalScrollbar.scrollHeight).toBe editor.getScreenLineCount() * 10 + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe editor.getScreenLineCount() * 10 presenter = buildPresenter(scrollTop: 0, lineHeight: 10, explicitHeight: 500) - expect(presenter.getState().verticalScrollbar.scrollHeight).toBe 500 + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe 500 it "updates when the ::lineHeight changes", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10) expectStateUpdate presenter, -> presenter.setLineHeight(20) - expect(presenter.getState().verticalScrollbar.scrollHeight).toBe editor.getScreenLineCount() * 20 + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe editor.getScreenLineCount() * 20 it "updates when the line count changes", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10) expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n") - expect(presenter.getState().verticalScrollbar.scrollHeight).toBe editor.getScreenLineCount() * 10 + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe editor.getScreenLineCount() * 10 it "updates when ::explicitHeight changes", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10) expectStateUpdate presenter, -> presenter.setExplicitHeight(500) - expect(presenter.getState().verticalScrollbar.scrollHeight).toBe 500 + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe 500 it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().verticalScrollbar.scrollHeight).toBe presenter.contentHeight + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) - expect(presenter.getState().verticalScrollbar.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.getState().verticalScrollbar.scrollHeight).toBe presenter.contentHeight + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight describe ".scrollTop", -> it "tracks the value of ::scrollTop", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 20, horizontalScrollbarHeight: 10) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe 10 + expect(getState(presenter).verticalScrollbar.scrollTop).toBe 10 expectStateUpdate presenter, -> presenter.setScrollTop(50) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe 50 + expect(getState(presenter).verticalScrollbar.scrollTop).toBe 50 it "never exceeds the computed scrollHeight minus the computed clientHeight", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(100) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getState(presenter).verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expectStateUpdate presenter, -> presenter.setExplicitHeight(60) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getState(presenter).verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(5) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getState(presenter).verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expectStateUpdate presenter, -> editor.getBuffer().delete([[8, 0], [12, 0]]) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getState(presenter).verticalScrollbar.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight # Scroll top only gets smaller when needed as dimensions change, never bigger - scrollTopBefore = presenter.getState().verticalScrollbar.scrollTop + scrollTopBefore = getState(presenter).verticalScrollbar.scrollTop expectStateUpdate presenter, -> editor.getBuffer().insert([9, Infinity], '\n\n\n') - expect(presenter.getState().verticalScrollbar.scrollTop).toBe scrollTopBefore + expect(getState(presenter).verticalScrollbar.scrollTop).toBe scrollTopBefore it "never goes negative", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(-100) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe 0 + expect(getState(presenter).verticalScrollbar.scrollTop).toBe 0 it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe presenter.contentHeight - presenter.clientHeight + expect(getState(presenter).verticalScrollbar.scrollTop).toBe presenter.contentHeight - presenter.clientHeight atom.config.set("editor.scrollPastEnd", true) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) + expect(getState(presenter).verticalScrollbar.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.getState().verticalScrollbar.scrollTop).toBe presenter.contentHeight - presenter.clientHeight + expect(getState(presenter).verticalScrollbar.scrollTop).toBe presenter.contentHeight - presenter.clientHeight describe ".hiddenInput", -> describe ".top/.left", -> it "is positioned over the last cursor it is in view and the editor is focused", -> editor.setCursorBufferPosition([3, 6]) presenter = buildPresenter(focused: false, explicitHeight: 50, contentFrameWidth: 300, horizontalScrollbarHeight: 0, verticalScrollbarWidth: 0) - expectValues presenter.getState().hiddenInput, {top: 0, left: 0} + expectValues getState(presenter).hiddenInput, {top: 0, left: 0} expectStateUpdate presenter, -> presenter.setFocused(true) - expectValues presenter.getState().hiddenInput, {top: 3 * 10, left: 6 * 10} + expectValues getState(presenter).hiddenInput, {top: 3 * 10, left: 6 * 10} expectStateUpdate presenter, -> presenter.setScrollTop(15) - expectValues presenter.getState().hiddenInput, {top: (3 * 10) - 15, left: 6 * 10} + expectValues getState(presenter).hiddenInput, {top: (3 * 10) - 15, left: 6 * 10} expectStateUpdate presenter, -> presenter.setScrollLeft(35) - expectValues presenter.getState().hiddenInput, {top: (3 * 10) - 15, left: (6 * 10) - 35} + expectValues getState(presenter).hiddenInput, {top: (3 * 10) - 15, left: (6 * 10) - 35} expectStateUpdate presenter, -> presenter.setScrollTop(40) - expectValues presenter.getState().hiddenInput, {top: 0, left: (6 * 10) - 35} + expectValues getState(presenter).hiddenInput, {top: 0, left: (6 * 10) - 35} expectStateUpdate presenter, -> presenter.setScrollLeft(70) - expectValues presenter.getState().hiddenInput, {top: 0, left: 0} + expectValues getState(presenter).hiddenInput, {top: 0, left: 0} expectStateUpdate presenter, -> editor.setCursorBufferPosition([11, 43]) - expectValues presenter.getState().hiddenInput, {top: 11 * 10 - presenter.getScrollTop(), left: 43 * 10 - presenter.getScrollLeft()} + expectValues getState(presenter).hiddenInput, {top: 11 * 10 - presenter.getScrollTop(), left: 43 * 10 - presenter.getScrollLeft()} newCursor = null expectStateUpdate presenter, -> newCursor = editor.addCursorAtBufferPosition([6, 10]) - expectValues presenter.getState().hiddenInput, {top: (6 * 10) - presenter.getScrollTop(), left: (10 * 10) - presenter.getScrollLeft()} + expectValues getState(presenter).hiddenInput, {top: (6 * 10) - presenter.getScrollTop(), left: (10 * 10) - presenter.getScrollLeft()} expectStateUpdate presenter, -> newCursor.destroy() - expectValues presenter.getState().hiddenInput, {top: 50 - 10, left: 300 - 10} + expectValues getState(presenter).hiddenInput, {top: 50 - 10, left: 300 - 10} expectStateUpdate presenter, -> presenter.setFocused(false) - expectValues presenter.getState().hiddenInput, {top: 0, left: 0} + expectValues getState(presenter).hiddenInput, {top: 0, left: 0} describe ".height", -> it "is assigned based on the line height", -> presenter = buildPresenter() - expect(presenter.getState().hiddenInput.height).toBe 10 + expect(getState(presenter).hiddenInput.height).toBe 10 expectStateUpdate presenter, -> presenter.setLineHeight(20) - expect(presenter.getState().hiddenInput.height).toBe 20 + expect(getState(presenter).hiddenInput.height).toBe 20 describe ".width", -> it "is assigned based on the width of the character following the cursor", -> @@ -605,38 +609,38 @@ describe "TextEditorPresenter", -> runs -> editor.setCursorBufferPosition([3, 6]) presenter = buildPresenter() - expect(presenter.getState().hiddenInput.width).toBe 10 + expect(getState(presenter).hiddenInput.width).toBe 10 expectStateUpdate presenter, -> presenter.setBaseCharacterWidth(15) - expect(presenter.getState().hiddenInput.width).toBe 15 + expect(getState(presenter).hiddenInput.width).toBe 15 expectStateUpdate presenter, -> presenter.getLinesYardstick().setScopedCharacterWidth(['source.js', 'storage.type.var.js'], 'r', 20) presenter.characterWidthsChanged() - expect(presenter.getState().hiddenInput.width).toBe 20 + expect(getState(presenter).hiddenInput.width).toBe 20 it "is 2px at the end of lines", -> presenter = buildPresenter() editor.setCursorBufferPosition([3, Infinity]) - expect(presenter.getState().hiddenInput.width).toBe 2 + expect(getState(presenter).hiddenInput.width).toBe 2 describe ".content", -> describe ".scrollingVertically", -> it "is true for ::stoppedScrollingDelay milliseconds following a changes to ::scrollTop", -> presenter = buildPresenter(scrollTop: 10, stoppedScrollingDelay: 200, explicitHeight: 100) - expect(presenter.getState().content.scrollingVertically).toBe true + expect(getState(presenter).content.scrollingVertically).toBe true advanceClock(300) - expect(presenter.getState().content.scrollingVertically).toBe false + expect(getState(presenter).content.scrollingVertically).toBe false expectStateUpdate presenter, -> presenter.setScrollTop(0) - expect(presenter.getState().content.scrollingVertically).toBe true + expect(getState(presenter).content.scrollingVertically).toBe true advanceClock(100) - expect(presenter.getState().content.scrollingVertically).toBe true + expect(getState(presenter).content.scrollingVertically).toBe true presenter.setScrollTop(10) - presenter.getState() # commits scroll position + getState(presenter) # commits scroll position advanceClock(100) - expect(presenter.getState().content.scrollingVertically).toBe true + expect(getState(presenter).content.scrollingVertically).toBe true expectStateUpdate presenter, -> advanceClock(100) - expect(presenter.getState().content.scrollingVertically).toBe false + expect(getState(presenter).content.scrollingVertically).toBe false describe ".maxHeight", -> it "changes based on boundingClientRect", -> @@ -644,55 +648,55 @@ describe "TextEditorPresenter", -> expectStateUpdate presenter, -> presenter.setBoundingClientRect(left: 0, top: 0, height: 20, width: 0) - expect(presenter.getState().content.maxHeight).toBe(20) + expect(getState(presenter).content.maxHeight).toBe(20) expectStateUpdate presenter, -> presenter.setBoundingClientRect(left: 0, top: 0, height: 50, width: 0) - expect(presenter.getState().content.maxHeight).toBe(50) + expect(getState(presenter).content.maxHeight).toBe(50) describe ".scrollHeight", -> it "is initialized based on the lineHeight, the number of lines, and the height", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10) - expect(presenter.getState().content.scrollHeight).toBe editor.getScreenLineCount() * 10 + expect(getState(presenter).content.scrollHeight).toBe editor.getScreenLineCount() * 10 presenter = buildPresenter(scrollTop: 0, lineHeight: 10, explicitHeight: 500) - expect(presenter.getState().content.scrollHeight).toBe 500 + expect(getState(presenter).content.scrollHeight).toBe 500 it "updates when the ::lineHeight changes", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10) expectStateUpdate presenter, -> presenter.setLineHeight(20) - expect(presenter.getState().content.scrollHeight).toBe editor.getScreenLineCount() * 20 + expect(getState(presenter).content.scrollHeight).toBe editor.getScreenLineCount() * 20 it "updates when the line count changes", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10) expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n") - expect(presenter.getState().content.scrollHeight).toBe editor.getScreenLineCount() * 10 + expect(getState(presenter).content.scrollHeight).toBe editor.getScreenLineCount() * 10 it "updates when ::explicitHeight changes", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10) expectStateUpdate presenter, -> presenter.setExplicitHeight(500) - expect(presenter.getState().content.scrollHeight).toBe 500 + expect(getState(presenter).content.scrollHeight).toBe 500 it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().content.scrollHeight).toBe presenter.contentHeight + expect(getState(presenter).content.scrollHeight).toBe presenter.contentHeight expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) - expect(presenter.getState().content.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) + expect(getState(presenter).content.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.getState().content.scrollHeight).toBe presenter.contentHeight + expect(getState(presenter).content.scrollHeight).toBe presenter.contentHeight describe ".scrollWidth", -> it "is initialized as the max of the computed clientWidth and the width of the longest line", -> maxLineLength = editor.getMaxScreenLineLength() presenter = buildPresenter(explicitHeight: 100, contentFrameWidth: 50, baseCharacterWidth: 10, verticalScrollbarWidth: 10) - expect(presenter.getState().content.scrollWidth).toBe 10 * maxLineLength + 1 + expect(getState(presenter).content.scrollWidth).toBe 10 * maxLineLength + 1 presenter = buildPresenter(explicitHeight: 100, contentFrameWidth: 10 * maxLineLength + 20, baseCharacterWidth: 10, verticalScrollbarWidth: 10) - expect(presenter.getState().content.scrollWidth).toBe 10 * maxLineLength + 20 - 10 # subtract vertical scrollbar width + expect(getState(presenter).content.scrollWidth).toBe 10 * maxLineLength + 20 - 10 # subtract vertical scrollbar width describe "when the longest screen row is the first one and it's hidden", -> it "doesn't compute an invalid value (regression)", -> @@ -706,15 +710,15 @@ describe "TextEditorPresenter", -> """ expectStateUpdate presenter, -> presenter.setScrollTop(40) - expect(presenter.getState().content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 it "updates when the ::contentFrameWidth changes", -> maxLineLength = editor.getMaxScreenLineLength() presenter = buildPresenter(contentFrameWidth: 50, baseCharacterWidth: 10) - expect(presenter.getState().content.scrollWidth).toBe 10 * maxLineLength + 1 + expect(getState(presenter).content.scrollWidth).toBe 10 * maxLineLength + 1 expectStateUpdate presenter, -> presenter.setContentFrameWidth(10 * maxLineLength + 20) - expect(presenter.getState().content.scrollWidth).toBe 10 * maxLineLength + 20 + expect(getState(presenter).content.scrollWidth).toBe 10 * maxLineLength + 20 it "updates when character widths change", -> waitsForPromise -> atom.packages.activatePackage('language-javascript') @@ -723,109 +727,109 @@ describe "TextEditorPresenter", -> maxLineLength = editor.getMaxScreenLineLength() presenter = buildPresenter(contentFrameWidth: 50, baseCharacterWidth: 10) - expect(presenter.getState().content.scrollWidth).toBe 10 * maxLineLength + 1 + expect(getState(presenter).content.scrollWidth).toBe 10 * maxLineLength + 1 expectStateUpdate presenter, -> presenter.getLinesYardstick().setScopedCharacterWidth(['source.js', 'support.function.js'], 'p', 20) presenter.characterWidthsChanged() - expect(presenter.getState().content.scrollWidth).toBe (10 * (maxLineLength - 2)) + (20 * 2) + 1 # 2 of the characters are 20px wide now instead of 10px wide + expect(getState(presenter).content.scrollWidth).toBe (10 * (maxLineLength - 2)) + (20 * 2) + 1 # 2 of the characters are 20px wide now instead of 10px wide it "updates when ::softWrapped changes on the editor", -> presenter = buildPresenter(contentFrameWidth: 470, baseCharacterWidth: 10) - expect(presenter.getState().content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 expectStateUpdate presenter, -> editor.setSoftWrapped(true) - expect(presenter.getState().horizontalScrollbar.scrollWidth).toBe presenter.clientWidth + expect(getState(presenter).horizontalScrollbar.scrollWidth).toBe presenter.clientWidth expectStateUpdate presenter, -> editor.setSoftWrapped(false) - expect(presenter.getState().content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 it "updates when the longest line changes", -> presenter = buildPresenter(contentFrameWidth: 50, baseCharacterWidth: 10) - expect(presenter.getState().content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 expectStateUpdate presenter, -> editor.setCursorBufferPosition([editor.getLongestScreenRow(), 0]) expectStateUpdate presenter, -> editor.insertText('xyz') - expect(presenter.getState().content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 it "isn't clipped to 0 when the longest line is folded (regression)", -> presenter = buildPresenter(contentFrameWidth: 50, baseCharacterWidth: 10) editor.foldBufferRow(0) - expect(presenter.getState().content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 + expect(getState(presenter).content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1 describe ".scrollTop", -> it "doesn't get stuck when repeatedly setting the same non-integer position in a scroll event listener", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10, explicitHeight: 20) - expect(presenter.getState().content.scrollTop).toBe(0) + expect(getState(presenter).content.scrollTop).toBe(0) presenter.onDidChangeScrollTop -> presenter.setScrollTop(1.5) - presenter.getState() # trigger scroll update + getState(presenter) # trigger scroll update presenter.setScrollTop(1.5) - presenter.getState() # trigger scroll update + getState(presenter) # trigger scroll update expect(presenter.getScrollTop()).toBe(2) expect(presenter.getRealScrollTop()).toBe(1.5) it "changes based on the scroll operation that was performed last", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10, explicitHeight: 20) - expect(presenter.getState().content.scrollTop).toBe(0) + expect(getState(presenter).content.scrollTop).toBe(0) presenter.setScrollTop(20) editor.setCursorBufferPosition([5, 0]) - expect(presenter.getState().content.scrollTop).toBe(50) + expect(getState(presenter).content.scrollTop).toBe(50) editor.setCursorBufferPosition([8, 0]) presenter.setScrollTop(10) - expect(presenter.getState().content.scrollTop).toBe(10) + expect(getState(presenter).content.scrollTop).toBe(10) it "corresponds to the passed logical coordinates when building the presenter", -> editor.setFirstVisibleScreenRow(4) presenter = buildPresenter(lineHeight: 10, explicitHeight: 20) - expect(presenter.getState().content.scrollTop).toBe(40) + expect(getState(presenter).content.scrollTop).toBe(40) it "tracks the value of ::scrollTop", -> presenter = buildPresenter(scrollTop: 10, lineHeight: 10, explicitHeight: 20) - expect(presenter.getState().content.scrollTop).toBe 10 + expect(getState(presenter).content.scrollTop).toBe 10 expectStateUpdate presenter, -> presenter.setScrollTop(50) - expect(presenter.getState().content.scrollTop).toBe 50 + expect(getState(presenter).content.scrollTop).toBe 50 it "keeps the model up to date with the corresponding logical coordinates", -> presenter = buildPresenter(scrollTop: 0, explicitHeight: 20, horizontalScrollbarHeight: 10, lineHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(50) - presenter.getState() # commits scroll position + getState(presenter) # commits scroll position expect(editor.getFirstVisibleScreenRow()).toBe 5 expectStateUpdate presenter, -> presenter.setScrollTop(57) - presenter.getState() # commits scroll position + getState(presenter) # commits scroll position expect(editor.getFirstVisibleScreenRow()).toBe 6 it "reassigns the scrollTop if it exceeds the max possible value after lines are removed", -> presenter = buildPresenter(scrollTop: 80, lineHeight: 10, explicitHeight: 50, horizontalScrollbarHeight: 0) - expect(presenter.getState().content.scrollTop).toBe(80) + expect(getState(presenter).content.scrollTop).toBe(80) buffer.deleteRows(10, 9, 8) - expect(presenter.getState().content.scrollTop).toBe(60) + expect(getState(presenter).content.scrollTop).toBe(60) it "is always rounded to the nearest integer", -> presenter = buildPresenter(scrollTop: 10, lineHeight: 10, explicitHeight: 20) - expect(presenter.getState().content.scrollTop).toBe 10 + expect(getState(presenter).content.scrollTop).toBe 10 expectStateUpdate presenter, -> presenter.setScrollTop(11.4) - expect(presenter.getState().content.scrollTop).toBe 11 + expect(getState(presenter).content.scrollTop).toBe 11 expectStateUpdate presenter, -> presenter.setScrollTop(12.6) - expect(presenter.getState().content.scrollTop).toBe 13 + expect(getState(presenter).content.scrollTop).toBe 13 it "scrolls down automatically when the model is changed", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10, explicitHeight: 20) editor.setText("") editor.insertNewline() - expect(presenter.getState().content.scrollTop).toBe(0) + expect(getState(presenter).content.scrollTop).toBe(0) editor.insertNewline() - expect(presenter.getState().content.scrollTop).toBe(10) + expect(getState(presenter).content.scrollTop).toBe(10) it "never exceeds the computed scroll height minus the computed client height", -> didChangeScrollTopSpy = jasmine.createSpy() @@ -833,111 +837,111 @@ describe "TextEditorPresenter", -> presenter.onDidChangeScrollTop(didChangeScrollTopSpy) expectStateUpdate presenter, -> presenter.setScrollTop(100) - expect(presenter.getState().content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getState(presenter).content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expect(presenter.getRealScrollTop()).toBe presenter.scrollHeight - presenter.clientHeight expect(didChangeScrollTopSpy).toHaveBeenCalledWith presenter.scrollHeight - presenter.clientHeight didChangeScrollTopSpy.reset() expectStateUpdate presenter, -> presenter.setExplicitHeight(60) - expect(presenter.getState().content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getState(presenter).content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expect(presenter.getRealScrollTop()).toBe presenter.scrollHeight - presenter.clientHeight expect(didChangeScrollTopSpy).toHaveBeenCalledWith presenter.scrollHeight - presenter.clientHeight didChangeScrollTopSpy.reset() expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(5) - expect(presenter.getState().content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getState(presenter).content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expect(presenter.getRealScrollTop()).toBe presenter.scrollHeight - presenter.clientHeight expect(didChangeScrollTopSpy).toHaveBeenCalledWith presenter.scrollHeight - presenter.clientHeight didChangeScrollTopSpy.reset() expectStateUpdate presenter, -> editor.getBuffer().delete([[8, 0], [12, 0]]) - expect(presenter.getState().content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + expect(getState(presenter).content.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight expect(presenter.getRealScrollTop()).toBe presenter.scrollHeight - presenter.clientHeight expect(didChangeScrollTopSpy).toHaveBeenCalledWith presenter.scrollHeight - presenter.clientHeight # Scroll top only gets smaller when needed as dimensions change, never bigger - scrollTopBefore = presenter.getState().verticalScrollbar.scrollTop + scrollTopBefore = getState(presenter).verticalScrollbar.scrollTop didChangeScrollTopSpy.reset() expectStateUpdate presenter, -> editor.getBuffer().insert([9, Infinity], '\n\n\n') - expect(presenter.getState().content.scrollTop).toBe scrollTopBefore + expect(getState(presenter).content.scrollTop).toBe scrollTopBefore expect(presenter.getRealScrollTop()).toBe scrollTopBefore expect(didChangeScrollTopSpy).not.toHaveBeenCalled() it "never goes negative", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(-100) - expect(presenter.getState().content.scrollTop).toBe 0 + expect(getState(presenter).content.scrollTop).toBe 0 it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().content.scrollTop).toBe presenter.contentHeight - presenter.clientHeight + expect(getState(presenter).content.scrollTop).toBe presenter.contentHeight - presenter.clientHeight atom.config.set("editor.scrollPastEnd", true) expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().content.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) + expect(getState(presenter).content.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.getState().content.scrollTop).toBe presenter.contentHeight - presenter.clientHeight + expect(getState(presenter).content.scrollTop).toBe presenter.contentHeight - presenter.clientHeight describe ".scrollLeft", -> it "doesn't get stuck when repeatedly setting the same non-integer position in a scroll event listener", -> presenter = buildPresenter(scrollLeft: 0, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 10) - expect(presenter.getState().content.scrollLeft).toBe(0) + expect(getState(presenter).content.scrollLeft).toBe(0) presenter.onDidChangeScrollLeft -> presenter.setScrollLeft(1.5) - presenter.getState() # trigger scroll update + getState(presenter) # trigger scroll update presenter.setScrollLeft(1.5) - presenter.getState() # trigger scroll update + getState(presenter) # trigger scroll update expect(presenter.getScrollLeft()).toBe(2) expect(presenter.getRealScrollLeft()).toBe(1.5) it "changes based on the scroll operation that was performed last", -> presenter = buildPresenter(scrollLeft: 0, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 10) - expect(presenter.getState().content.scrollLeft).toBe(0) + expect(getState(presenter).content.scrollLeft).toBe(0) presenter.setScrollLeft(20) editor.setCursorBufferPosition([0, 9]) - expect(presenter.getState().content.scrollLeft).toBe(90) + expect(getState(presenter).content.scrollLeft).toBe(90) editor.setCursorBufferPosition([0, 18]) presenter.setScrollLeft(50) - expect(presenter.getState().content.scrollLeft).toBe(50) + expect(getState(presenter).content.scrollLeft).toBe(50) it "corresponds to the passed logical coordinates when building the presenter", -> editor.setFirstVisibleScreenColumn(3) presenter = buildPresenter(lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500) - expect(presenter.getState().content.scrollLeft).toBe(30) + expect(getState(presenter).content.scrollLeft).toBe(30) it "tracks the value of ::scrollLeft", -> presenter = buildPresenter(scrollLeft: 10, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500) - expect(presenter.getState().content.scrollLeft).toBe 10 + expect(getState(presenter).content.scrollLeft).toBe 10 expectStateUpdate presenter, -> presenter.setScrollLeft(50) - expect(presenter.getState().content.scrollLeft).toBe 50 + expect(getState(presenter).content.scrollLeft).toBe 50 it "keeps the model up to date with the corresponding logical coordinates", -> presenter = buildPresenter(scrollLeft: 0, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500) expectStateUpdate presenter, -> presenter.setScrollLeft(50) - presenter.getState() # commits scroll position + getState(presenter) # commits scroll position expect(editor.getFirstVisibleScreenColumn()).toBe 5 expectStateUpdate presenter, -> presenter.setScrollLeft(57) - presenter.getState() # commits scroll position + getState(presenter) # commits scroll position expect(editor.getFirstVisibleScreenColumn()).toBe 6 it "is always rounded to the nearest integer", -> presenter = buildPresenter(scrollLeft: 10, lineHeight: 10, baseCharacterWidth: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500) - expect(presenter.getState().content.scrollLeft).toBe 10 + expect(getState(presenter).content.scrollLeft).toBe 10 expectStateUpdate presenter, -> presenter.setScrollLeft(11.4) - expect(presenter.getState().content.scrollLeft).toBe 11 + expect(getState(presenter).content.scrollLeft).toBe 11 expectStateUpdate presenter, -> presenter.setScrollLeft(12.6) - expect(presenter.getState().content.scrollLeft).toBe 13 + expect(getState(presenter).content.scrollLeft).toBe 13 it "never exceeds the computed scrollWidth minus the computed clientWidth", -> didChangeScrollLeftSpy = jasmine.createSpy() @@ -945,65 +949,65 @@ describe "TextEditorPresenter", -> presenter.onDidChangeScrollLeft(didChangeScrollLeftSpy) expectStateUpdate presenter, -> presenter.setScrollLeft(300) - expect(presenter.getState().content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth + expect(getState(presenter).content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expect(presenter.getRealScrollLeft()).toBe presenter.scrollWidth - presenter.clientWidth expect(didChangeScrollLeftSpy).toHaveBeenCalledWith presenter.scrollWidth - presenter.clientWidth didChangeScrollLeftSpy.reset() expectStateUpdate presenter, -> presenter.setContentFrameWidth(600) - expect(presenter.getState().content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth + expect(getState(presenter).content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expect(presenter.getRealScrollLeft()).toBe presenter.scrollWidth - presenter.clientWidth expect(didChangeScrollLeftSpy).toHaveBeenCalledWith presenter.scrollWidth - presenter.clientWidth didChangeScrollLeftSpy.reset() expectStateUpdate presenter, -> presenter.setVerticalScrollbarWidth(5) - expect(presenter.getState().content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth + expect(getState(presenter).content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expect(presenter.getRealScrollLeft()).toBe presenter.scrollWidth - presenter.clientWidth expect(didChangeScrollLeftSpy).toHaveBeenCalledWith presenter.scrollWidth - presenter.clientWidth didChangeScrollLeftSpy.reset() expectStateUpdate presenter, -> editor.getBuffer().delete([[6, 0], [6, Infinity]]) - expect(presenter.getState().content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth + expect(getState(presenter).content.scrollLeft).toBe presenter.scrollWidth - presenter.clientWidth expect(presenter.getRealScrollLeft()).toBe presenter.scrollWidth - presenter.clientWidth expect(didChangeScrollLeftSpy).toHaveBeenCalledWith presenter.scrollWidth - presenter.clientWidth # Scroll top only gets smaller when needed as dimensions change, never bigger - scrollLeftBefore = presenter.getState().content.scrollLeft + scrollLeftBefore = getState(presenter).content.scrollLeft didChangeScrollLeftSpy.reset() expectStateUpdate presenter, -> editor.getBuffer().insert([6, 0], new Array(100).join('x')) - expect(presenter.getState().content.scrollLeft).toBe scrollLeftBefore + expect(getState(presenter).content.scrollLeft).toBe scrollLeftBefore expect(presenter.getRealScrollLeft()).toBe scrollLeftBefore expect(didChangeScrollLeftSpy).not.toHaveBeenCalled() it "never goes negative", -> presenter = buildPresenter(scrollLeft: 10, verticalScrollbarWidth: 10, contentFrameWidth: 500) expectStateUpdate presenter, -> presenter.setScrollLeft(-300) - expect(presenter.getState().content.scrollLeft).toBe 0 + expect(getState(presenter).content.scrollLeft).toBe 0 describe ".indentGuidesVisible", -> it "is initialized based on the editor.showIndentGuide config setting", -> presenter = buildPresenter() - expect(presenter.getState().content.indentGuidesVisible).toBe false + expect(getState(presenter).content.indentGuidesVisible).toBe false atom.config.set('editor.showIndentGuide', true) presenter = buildPresenter() - expect(presenter.getState().content.indentGuidesVisible).toBe true + expect(getState(presenter).content.indentGuidesVisible).toBe true it "updates when the editor.showIndentGuide config setting changes", -> presenter = buildPresenter() - expect(presenter.getState().content.indentGuidesVisible).toBe false + expect(getState(presenter).content.indentGuidesVisible).toBe false expectStateUpdate presenter, -> atom.config.set('editor.showIndentGuide', true) - expect(presenter.getState().content.indentGuidesVisible).toBe true + expect(getState(presenter).content.indentGuidesVisible).toBe true expectStateUpdate presenter, -> atom.config.set('editor.showIndentGuide', false) - expect(presenter.getState().content.indentGuidesVisible).toBe false + expect(getState(presenter).content.indentGuidesVisible).toBe false it "updates when the editor's grammar changes", -> atom.config.set('editor.showIndentGuide', true, scopeSelector: ".source.js") presenter = buildPresenter() - expect(presenter.getState().content.indentGuidesVisible).toBe false + expect(getState(presenter).content.indentGuidesVisible).toBe false stateUpdated = false presenter.onDidUpdateState -> stateUpdated = true @@ -1012,65 +1016,65 @@ describe "TextEditorPresenter", -> runs -> expect(stateUpdated).toBe true - expect(presenter.getState().content.indentGuidesVisible).toBe true + expect(getState(presenter).content.indentGuidesVisible).toBe true expectStateUpdate presenter, -> editor.setGrammar(atom.grammars.selectGrammar('.txt')) - expect(presenter.getState().content.indentGuidesVisible).toBe false + expect(getState(presenter).content.indentGuidesVisible).toBe false it "is always false when the editor is mini", -> atom.config.set('editor.showIndentGuide', true) editor.setMini(true) presenter = buildPresenter() - expect(presenter.getState().content.indentGuidesVisible).toBe false + expect(getState(presenter).content.indentGuidesVisible).toBe false editor.setMini(false) - expect(presenter.getState().content.indentGuidesVisible).toBe true + expect(getState(presenter).content.indentGuidesVisible).toBe true editor.setMini(true) - expect(presenter.getState().content.indentGuidesVisible).toBe false + expect(getState(presenter).content.indentGuidesVisible).toBe false describe ".backgroundColor", -> it "is assigned to ::backgroundColor unless the editor is mini", -> presenter = buildPresenter() presenter.setBackgroundColor('rgba(255, 0, 0, 0)') - expect(presenter.getState().content.backgroundColor).toBe 'rgba(255, 0, 0, 0)' + expect(getState(presenter).content.backgroundColor).toBe 'rgba(255, 0, 0, 0)' editor.setMini(true) presenter = buildPresenter() presenter.setBackgroundColor('rgba(255, 0, 0, 0)') - expect(presenter.getState().content.backgroundColor).toBeNull() + expect(getState(presenter).content.backgroundColor).toBeNull() it "updates when ::backgroundColor changes", -> presenter = buildPresenter() presenter.setBackgroundColor('rgba(255, 0, 0, 0)') - expect(presenter.getState().content.backgroundColor).toBe 'rgba(255, 0, 0, 0)' + expect(getState(presenter).content.backgroundColor).toBe 'rgba(255, 0, 0, 0)' expectStateUpdate presenter, -> presenter.setBackgroundColor('rgba(0, 0, 255, 0)') - expect(presenter.getState().content.backgroundColor).toBe 'rgba(0, 0, 255, 0)' + expect(getState(presenter).content.backgroundColor).toBe 'rgba(0, 0, 255, 0)' it "updates when ::mini changes", -> presenter = buildPresenter() presenter.setBackgroundColor('rgba(255, 0, 0, 0)') - expect(presenter.getState().content.backgroundColor).toBe 'rgba(255, 0, 0, 0)' + expect(getState(presenter).content.backgroundColor).toBe 'rgba(255, 0, 0, 0)' expectStateUpdate presenter, -> editor.setMini(true) - expect(presenter.getState().content.backgroundColor).toBeNull() + expect(getState(presenter).content.backgroundColor).toBeNull() describe ".placeholderText", -> it "is present when the editor has no text", -> editor.setPlaceholderText("the-placeholder-text") presenter = buildPresenter() - expect(presenter.getState().content.placeholderText).toBeNull() + expect(getState(presenter).content.placeholderText).toBeNull() expectStateUpdate presenter, -> editor.setText("") - expect(presenter.getState().content.placeholderText).toBe "the-placeholder-text" + expect(getState(presenter).content.placeholderText).toBe "the-placeholder-text" expectStateUpdate presenter, -> editor.setPlaceholderText("new-placeholder-text") - expect(presenter.getState().content.placeholderText).toBe "new-placeholder-text" + expect(getState(presenter).content.placeholderText).toBe "new-placeholder-text" describe ".tiles", -> lineStateForScreenRow = (presenter, row) -> lineId = presenter.model.tokenizedLineForScreenRow(row).id tileRow = presenter.tileForRow(row) - presenter.getState().content.tiles[tileRow]?.lines[lineId] + getState(presenter).content.tiles[tileRow]?.lines[lineId] - tiledContentContract (presenter) -> presenter.getState().content + tiledContentContract (presenter) -> getState(presenter).content describe "[tileId].lines[lineId]", -> # line state objects it "includes the state for visible lines in a tile", -> @@ -1330,7 +1334,7 @@ describe "TextEditorPresenter", -> describe ".cursors", -> stateForCursor = (presenter, cursorIndex) -> - presenter.getState().content.cursors[presenter.model.getCursors()[cursorIndex].id] + getState(presenter).content.cursors[presenter.model.getCursors()[cursorIndex].id] it "contains pixelRects for empty selections that are visible on screen", -> editor.setSelectedBufferRanges([ @@ -1350,31 +1354,31 @@ describe "TextEditorPresenter", -> it "is empty until all of the required measurements are assigned", -> presenter = buildPresenterWithoutMeasurements() - expect(presenter.getState().content.cursors).toEqual({}) + expect(getState(presenter).content.cursors).toEqual({}) presenter.setExplicitHeight(25) - expect(presenter.getState().content.cursors).toEqual({}) + expect(getState(presenter).content.cursors).toEqual({}) presenter.setLineHeight(10) - expect(presenter.getState().content.cursors).toEqual({}) + expect(getState(presenter).content.cursors).toEqual({}) presenter.setScrollTop(0) - expect(presenter.getState().content.cursors).toEqual({}) + expect(getState(presenter).content.cursors).toEqual({}) presenter.setBaseCharacterWidth(8) - expect(presenter.getState().content.cursors).toEqual({}) + expect(getState(presenter).content.cursors).toEqual({}) presenter.setBoundingClientRect(top: 0, left: 0, width: 500, height: 130) - expect(presenter.getState().content.cursors).toEqual({}) + expect(getState(presenter).content.cursors).toEqual({}) presenter.setWindowSize(500, 130) - expect(presenter.getState().content.cursors).toEqual({}) + expect(getState(presenter).content.cursors).toEqual({}) presenter.setVerticalScrollbarWidth(10) - expect(presenter.getState().content.cursors).toEqual({}) + expect(getState(presenter).content.cursors).toEqual({}) presenter.setHorizontalScrollbarHeight(10) - expect(presenter.getState().content.cursors).not.toEqual({}) + expect(getState(presenter).content.cursors).not.toEqual({}) it "updates when ::scrollTop changes", -> editor.setSelectedBufferRanges([ @@ -1493,7 +1497,7 @@ describe "TextEditorPresenter", -> # destroying destroyedCursor = editor.getCursors()[2] expectStateUpdate presenter, -> destroyedCursor.destroy() - expect(presenter.getState().content.cursors[destroyedCursor.id]).toBeUndefined() + expect(getState(presenter).content.cursors[destroyedCursor.id]).toBeUndefined() it "makes cursors as wide as the ::baseCharacterWidth if they're at the end of a line", -> editor.setCursorBufferPosition([1, Infinity]) @@ -1507,27 +1511,27 @@ describe "TextEditorPresenter", -> presenter = buildPresenter({cursorBlinkPeriod, cursorBlinkResumeDelay}) presenter.setFocused(true) - expect(presenter.getState().content.cursorsVisible).toBe true + expect(getState(presenter).content.cursorsVisible).toBe true expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe true + expect(getState(presenter).content.cursorsVisible).toBe true expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe true + expect(getState(presenter).content.cursorsVisible).toBe true expectStateUpdate presenter, -> presenter.setFocused(false) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false expectStateUpdate presenter, -> presenter.setFocused(true) - expect(presenter.getState().content.cursorsVisible).toBe true + expect(getState(presenter).content.cursorsVisible).toBe true expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false it "stops alternating for ::cursorBlinkResumeDelay when a cursor moves or a cursor is added", -> cursorBlinkPeriod = 100 @@ -1535,46 +1539,46 @@ describe "TextEditorPresenter", -> presenter = buildPresenter({cursorBlinkPeriod, cursorBlinkResumeDelay}) presenter.setFocused(true) - expect(presenter.getState().content.cursorsVisible).toBe true + expect(getState(presenter).content.cursorsVisible).toBe true expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false expectStateUpdate presenter, -> editor.moveRight() - expect(presenter.getState().content.cursorsVisible).toBe true + expect(getState(presenter).content.cursorsVisible).toBe true expectStateUpdate presenter, -> advanceClock(cursorBlinkResumeDelay) advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe true + expect(getState(presenter).content.cursorsVisible).toBe true expectStateUpdate presenter, -> advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false expectStateUpdate presenter, -> editor.addCursorAtBufferPosition([1, 0]) - expect(presenter.getState().content.cursorsVisible).toBe true + expect(getState(presenter).content.cursorsVisible).toBe true expectStateUpdate presenter, -> advanceClock(cursorBlinkResumeDelay) advanceClock(cursorBlinkPeriod / 2) - expect(presenter.getState().content.cursorsVisible).toBe false + expect(getState(presenter).content.cursorsVisible).toBe false describe ".highlights", -> expectUndefinedStateForHighlight = (presenter, decoration) -> - for tileId, tileState of presenter.getState().content.tiles + for tileId, tileState of getState(presenter).content.tiles state = stateForHighlightInTile(presenter, decoration, tileId) expect(state).toBeUndefined() stateForHighlightInTile = (presenter, decoration, tile) -> - presenter.getState().content.tiles[tile]?.highlights[decoration.id] + getState(presenter).content.tiles[tile]?.highlights[decoration.id] stateForSelectionInTile = (presenter, selectionIndex, tile) -> selection = presenter.model.getSelections()[selectionIndex] stateForHighlightInTile(presenter, selection.decoration, tile) expectUndefinedStateForSelection = (presenter, selectionIndex) -> - for tileId, tileState of presenter.getState().content.tiles + for tileId, tileState of getState(presenter).content.tiles state = stateForSelectionInTile(presenter, selectionIndex, tileId) expect(state).toBeUndefined() @@ -1684,24 +1688,24 @@ describe "TextEditorPresenter", -> ]) presenter = buildPresenterWithoutMeasurements(tileSize: 2) - for tileId, tileState of presenter.getState().content.tiles + for tileId, tileState of getState(presenter).content.tiles expect(tileState.highlights).toEqual({}) presenter.setExplicitHeight(25) - for tileId, tileState of presenter.getState().content.tiles + for tileId, tileState of getState(presenter).content.tiles expect(tileState.highlights).toEqual({}) presenter.setLineHeight(10) - for tileId, tileState of presenter.getState().content.tiles + for tileId, tileState of getState(presenter).content.tiles expect(tileState.highlights).toEqual({}) presenter.setScrollTop(0) - for tileId, tileState of presenter.getState().content.tiles + for tileId, tileState of getState(presenter).content.tiles expect(tileState.highlights).toEqual({}) presenter.setBaseCharacterWidth(8) assignedAnyHighlight = false - for tileId, tileState of presenter.getState().content.tiles + for tileId, tileState of getState(presenter).content.tiles assignedAnyHighlight ||= _.isEqual(tileState.highlights, {}) expect(assignedAnyHighlight).toBe(true) @@ -1916,7 +1920,7 @@ describe "TextEditorPresenter", -> describe ".overlays", -> [item] = [] stateForOverlay = (presenter, decoration) -> - presenter.getState().content.overlays[decoration.id] + getState(presenter).content.overlays[decoration.id] it "contains state for overlay decorations both initially and when their markers move", -> marker = editor.addMarkerLayer(maintainHistory: true).markBufferPosition([2, 13], invalidate: 'touch') @@ -2023,25 +2027,25 @@ describe "TextEditorPresenter", -> decoration = editor.decorateMarker(marker, {type: 'overlay', position: 'tail', item}) presenter = buildPresenterWithoutMeasurements() - expect(presenter.getState().content.overlays).toEqual({}) + expect(getState(presenter).content.overlays).toEqual({}) presenter.setBaseCharacterWidth(10) - expect(presenter.getState().content.overlays).toEqual({}) + expect(getState(presenter).content.overlays).toEqual({}) presenter.setLineHeight(10) - expect(presenter.getState().content.overlays).toEqual({}) + expect(getState(presenter).content.overlays).toEqual({}) presenter.setWindowSize(500, 100) - expect(presenter.getState().content.overlays).toEqual({}) + expect(getState(presenter).content.overlays).toEqual({}) presenter.setVerticalScrollbarWidth(10) - expect(presenter.getState().content.overlays).toEqual({}) + expect(getState(presenter).content.overlays).toEqual({}) presenter.setHorizontalScrollbarHeight(10) - expect(presenter.getState().content.overlays).toEqual({}) + expect(getState(presenter).content.overlays).toEqual({}) presenter.setBoundingClientRect({top: 0, left: 0, height: 100, width: 500}) - expect(presenter.getState().content.overlays).not.toEqual({}) + expect(getState(presenter).content.overlays).not.toEqual({}) describe "when the overlay has been measured", -> [gutterWidth, windowWidth, windowHeight, itemWidth, itemHeight, contentMargin, boundingClientRect, contentFrameWidth] = [] @@ -2210,52 +2214,52 @@ describe "TextEditorPresenter", -> it "updates model's rows per page when it changes", -> presenter = buildPresenter(explicitHeight: 50, lineHeightInPixels: 10, horizontalScrollbarHeight: 10) - presenter.getState() # trigger state update + getState(presenter) # trigger state update expect(editor.getRowsPerPage()).toBe(4) presenter.setExplicitHeight(100) - presenter.getState() # trigger state update + getState(presenter) # trigger state update expect(editor.getRowsPerPage()).toBe(9) presenter.setHorizontalScrollbarHeight(0) - presenter.getState() # trigger state update + getState(presenter) # trigger state update expect(editor.getRowsPerPage()).toBe(10) presenter.setLineHeight(5) - presenter.getState() # trigger state update + getState(presenter) # trigger state update expect(editor.getRowsPerPage()).toBe(20) it "tracks the computed content height if ::autoHeight is true so the editor auto-expands vertically", -> presenter = buildPresenter(explicitHeight: null) presenter.setAutoHeight(true) - expect(presenter.getState().height).toBe editor.getScreenLineCount() * 10 + expect(getState(presenter).height).toBe editor.getScreenLineCount() * 10 expectStateUpdate presenter, -> presenter.setAutoHeight(false) - expect(presenter.getState().height).toBe null + expect(getState(presenter).height).toBe null expectStateUpdate presenter, -> presenter.setAutoHeight(true) - expect(presenter.getState().height).toBe editor.getScreenLineCount() * 10 + expect(getState(presenter).height).toBe editor.getScreenLineCount() * 10 expectStateUpdate presenter, -> presenter.setLineHeight(20) - expect(presenter.getState().height).toBe editor.getScreenLineCount() * 20 + expect(getState(presenter).height).toBe editor.getScreenLineCount() * 20 expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n") - expect(presenter.getState().height).toBe editor.getScreenLineCount() * 20 + expect(getState(presenter).height).toBe editor.getScreenLineCount() * 20 describe ".focused", -> it "tracks the value of ::focused", -> presenter = buildPresenter() presenter.setFocused(false) - expect(presenter.getState().focused).toBe false + expect(getState(presenter).focused).toBe false expectStateUpdate presenter, -> presenter.setFocused(true) - expect(presenter.getState().focused).toBe true + expect(getState(presenter).focused).toBe true expectStateUpdate presenter, -> presenter.setFocused(false) - expect(presenter.getState().focused).toBe false + expect(getState(presenter).focused).toBe false describe ".gutters", -> getStateForGutterWithName = (presenter, gutterName) -> - gutterDescriptions = presenter.getState().gutters + gutterDescriptions = getState(presenter).gutters for description in gutterDescriptions gutter = description.gutter return description if gutter.name is gutterName @@ -2267,7 +2271,7 @@ describe "TextEditorPresenter", -> gutter2 = editor.addGutter({name: 'test-gutter-2', priority: 100, visible: false}) expectedGutterOrder = [gutter1, editor.gutterWithName('line-number'), gutter2] - for gutterDescription, index in presenter.getState().gutters + for gutterDescription, index in getState(presenter).gutters expect(gutterDescription.gutter).toEqual expectedGutterOrder[index] it "updates when the visibility of a gutter changes", -> @@ -2286,7 +2290,7 @@ describe "TextEditorPresenter", -> describe "for a gutter description that corresponds to the line-number gutter", -> getLineNumberGutterState = (presenter) -> - gutterDescriptions = presenter.getState().gutters + gutterDescriptions = getState(presenter).gutters for description in gutterDescriptions gutter = description.gutter return description if gutter.name is 'line-number' @@ -2614,7 +2618,7 @@ describe "TextEditorPresenter", -> decoration3 = editor.decorateMarker(marker3, decorationParams) # Clear any batched state updates. - presenter.getState() + getState(presenter) it "contains all decorations within the visible buffer range", -> decorationState = getContentForGutterWithName(presenter, 'test-gutter') @@ -2915,7 +2919,7 @@ describe "TextEditorPresenter", -> expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollTop).toBe presenter.scrollHeight - presenter.clientHeight # Scroll top only gets smaller when needed as dimensions change, never bigger - scrollTopBefore = presenter.getState().verticalScrollbar.scrollTop + scrollTopBefore = getState(presenter).verticalScrollbar.scrollTop expectStateUpdate presenter, -> editor.getBuffer().insert([9, Infinity], '\n\n\n') expect(getStylesForGutterWithName(presenter, 'line-number').scrollTop).toBe scrollTopBefore expect(getStylesForGutterWithName(presenter, 'test-gutter').scrollTop).toBe scrollTopBefore @@ -3016,7 +3020,7 @@ describe "TextEditorPresenter", -> expectValidState = -> presenterParams.scrollTop = presenter.scrollTop presenterParams.scrollLeft = presenter.scrollLeft - actualState = presenter.getState() + actualState = getState(presenter) expectedState = new TextEditorPresenter(presenterParams).state delete actualState.content.scrollingVertically delete expectedState.content.scrollingVertically diff --git a/src/lines-yardstick.coffee b/src/lines-yardstick.coffee index 54ba6cf57..bd8219e81 100644 --- a/src/lines-yardstick.coffee +++ b/src/lines-yardstick.coffee @@ -3,7 +3,7 @@ TokenIterator = require './token-iterator' module.exports = class LinesYardstick - constructor: (@model, @presenter, @lineNodesProvider, grammarRegistry) -> + constructor: (@model, @lineNodesProvider, grammarRegistry) -> @tokenIterator = new TokenIterator({grammarRegistry}) @rangeForMeasurement = document.createRange() @invalidateCache() @@ -11,14 +11,12 @@ class LinesYardstick invalidateCache: -> @pixelPositionsByLineIdAndColumn = {} - prepareScreenRowsForMeasurement: (screenRows) -> - @presenter.setScreenRowsToMeasure(screenRows) - @lineNodesProvider.updateSync(@presenter.getPreMeasurementState()) + measuredRowForPixelPosition: (pixelPosition) -> + targetTop = pixelPosition.top + row = Math.floor(targetTop / @model.getLineHeightInPixels()) + row if 0 <= row <= @model.getLastScreenRow() - clearScreenRowsForMeasurement: -> - @presenter.clearScreenRowsToMeasure() - - screenPositionForPixelPosition: (pixelPosition, measureVisibleLinesOnly) -> + screenPositionForPixelPosition: (pixelPosition) -> targetTop = pixelPosition.top targetLeft = pixelPosition.left defaultCharWidth = @model.getDefaultCharWidth() @@ -28,12 +26,10 @@ class LinesYardstick row = Math.min(row, @model.getLastScreenRow()) row = Math.max(0, row) - @prepareScreenRowsForMeasurement([row]) unless measureVisibleLinesOnly - line = @model.tokenizedLineForScreenRow(row) lineNode = @lineNodesProvider.lineNodeForLineIdAndScreenRow(line?.id, row) - return new Point(row, 0) unless lineNode? and line? + return Point(row, 0) unless lineNode? and line? textNodes = @lineNodesProvider.textNodesForLineIdAndScreenRow(line.id, row) column = 0 @@ -70,33 +66,27 @@ class LinesYardstick left = @leftPixelPositionForCharInTextNode(lineNode, textNode, indexWithinTextNode) charWidth = left - previousLeft - return new Point(row, previousColumn) if targetLeft <= previousLeft + (charWidth / 2) + return Point(row, previousColumn) if targetLeft <= previousLeft + (charWidth / 2) previousLeft = left previousColumn = column column += charLength - @clearScreenRowsForMeasurement() unless measureVisibleLinesOnly - if targetLeft <= previousLeft + (charWidth / 2) - new Point(row, previousColumn) + Point(row, previousColumn) else - new Point(row, column) + Point(row, column) - pixelPositionForScreenPosition: (screenPosition, clip=true, measureVisibleLinesOnly) -> + pixelPositionForScreenPosition: (screenPosition, clip=true) -> screenPosition = Point.fromObject(screenPosition) screenPosition = @model.clipScreenPosition(screenPosition) if clip targetRow = screenPosition.row targetColumn = screenPosition.column - @prepareScreenRowsForMeasurement([targetRow]) unless measureVisibleLinesOnly - top = targetRow * @model.getLineHeightInPixels() left = @leftPixelPositionForScreenPosition(targetRow, targetColumn) - @clearScreenRowsForMeasurement() unless measureVisibleLinesOnly - {top, left} leftPixelPositionForScreenPosition: (row, column) -> @@ -173,18 +163,3 @@ class LinesYardstick offset = lineNode.getBoundingClientRect().left left + width - offset - - pixelRectForScreenRange: (screenRange, measureVisibleLinesOnly) -> - lineHeight = @model.getLineHeightInPixels() - - if screenRange.end.row > screenRange.start.row - top = @pixelPositionForScreenPosition(screenRange.start, true, measureVisibleLinesOnly).top - left = 0 - height = (screenRange.end.row - screenRange.start.row + 1) * lineHeight - width = @presenter.getScrollWidth() - else - {top, left} = @pixelPositionForScreenPosition(screenRange.start, false, measureVisibleLinesOnly) - height = lineHeight - width = @pixelPositionForScreenPosition(screenRange.end, false, measureVisibleLinesOnly).left - left - - {top, left, width, height} diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 430b0c0fd..6a84c8dac 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -82,7 +82,7 @@ class TextEditorComponent @linesComponent = new LinesComponent({@presenter, @hostElement, @useShadowDOM, @domElementPool, @assert, @grammars}) @scrollViewNode.appendChild(@linesComponent.getDomNode()) - @linesYardstick = new LinesYardstick(@editor, @presenter, @linesComponent, @grammars) + @linesYardstick = new LinesYardstick(@editor, @linesComponent, @grammars) @presenter.setLinesYardstick(@linesYardstick) @horizontalScrollbarComponent = new ScrollbarComponent({orientation: 'horizontal', onScroll: @onHorizontalScroll}) @@ -127,8 +127,10 @@ class TextEditorComponent @domNode updateSync: -> + @updateSyncPreMeasurement() + @oldState ?= {} - @newState = @presenter.getState() + @newState = @presenter.getPostMeasurementState() if @editor.getLastSelection()? and not @editor.getLastSelection().isEmpty() @domNode.classList.add('has-selection') @@ -170,6 +172,9 @@ class TextEditorComponent @updateParentViewFocusedClassIfNeeded() @updateParentViewMiniClass() + updateSyncPreMeasurement: -> + @linesComponent.updateSync(@presenter.getPreMeasurementState()) + readAfterUpdateSync: => @overlayManager?.measureOverlays() @@ -429,14 +434,42 @@ class TextEditorComponent getVisibleRowRange: -> @presenter.getVisibleRowRange() - pixelPositionForScreenPosition: -> - @linesYardstick.pixelPositionForScreenPosition(arguments...) + pixelPositionForScreenPosition: (screenPosition, clip) -> + unless @presenter.isRowVisible(screenPosition.row) + @presenter.setScreenRowsToMeasure([screenPosition.row]) + @updateSyncPreMeasurement() - screenPositionForPixelPosition: -> - @linesYardstick.screenPositionForPixelPosition(arguments...) + pixelPosition = @linesYardstick.pixelPositionForScreenPosition(screenPosition, clip) + @presenter.clearScreenRowsToMeasure() + pixelPosition - pixelRectForScreenRange: -> - @linesYardstick.pixelRectForScreenRange(arguments...) + screenPositionForPixelPosition: (pixelPosition) -> + row = @linesYardstick.measuredRowForPixelPosition(pixelPosition) + if row? and not @presenter.isRowVisible(row) + @presenter.setScreenRowsToMeasure([row]) + @updateSyncPreMeasurement() + + position = @linesYardstick.screenPositionForPixelPosition(pixelPosition) + @presenter.clearScreenRowsToMeasure() + position + + pixelRectForScreenRange: (screenRange) -> + rowsToMeasure = [] + unless @presenter.isRowVisible(screenRange.start.row) + rowsToMeasure.push(screenRange.start.row) + unless @presenter.isRowVisible(screenRange.end.row) + rowsToMeasure.push(screenRange.end.row) + + if rowsToMeasure.length > 0 + @presenter.setScreenRowsToMeasure(rowsToMeasure) + @updateSyncPreMeasurement() + + rect = @presenter.absolutePixelRectForScreenRange(screenRange) + + if rowsToMeasure.length > 0 + @presenter.clearScreenRowsToMeasure() + + rect pixelRangeForScreenRange: (screenRange, clip=true) -> {start, end} = Range.fromObject(screenRange) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 405e34548..5cfaeebcf 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -121,14 +121,6 @@ class TextEditorPresenter @updating = false @resetTrackedUpdates() - - # Public: Gets this presenter's state, updating it just in time before returning from this function. - # Returns a state {Object}, useful for rendering to screen. - getState: -> - @linesYardstick.prepareScreenRowsForMeasurement() - - @getPostMeasurementState() - @state resetTrackedUpdates: -> @@ -1155,16 +1147,29 @@ class TextEditorPresenter hasOverlayPositionRequirements: -> @hasPixelRectRequirements() and @boundingClientRect? and @windowWidth and @windowHeight + absolutePixelRectForScreenRange: (screenRange) -> + lineHeight = @model.getLineHeightInPixels() + + if screenRange.end.row > screenRange.start.row + top = @linesYardstick.pixelPositionForScreenPosition(screenRange.start, true).top + left = 0 + height = (screenRange.end.row - screenRange.start.row + 1) * lineHeight + width = @getScrollWidth() + else + {top, left} = @linesYardstick.pixelPositionForScreenPosition(screenRange.start, false) + height = lineHeight + width = @linesYardstick.pixelPositionForScreenPosition(screenRange.end, false).left - left + + {top, left, width, height} + pixelRectForScreenRange: (screenRange) -> - rect = @linesYardstick.pixelRectForScreenRange(screenRange, true) + rect = @absolutePixelRectForScreenRange(screenRange) rect.top -= @getScrollTop() rect.left -= @getScrollLeft() - rect.top = Math.round(rect.top) rect.left = Math.round(rect.left) rect.width = Math.round(rect.width) rect.height = Math.round(rect.height) - rect fetchDecorations: -> @@ -1550,3 +1555,6 @@ class TextEditorPresenter getVisibleRowRange: -> [@startRow, @endRow] + + isRowVisible: (row) -> + @startRow <= row < @endRow