From f672f8ea925b804e49b623ef4b9acddd6827928b Mon Sep 17 00:00:00 2001 From: Giuseppe Piscopo Date: Tue, 15 Sep 2015 11:44:38 +0200 Subject: [PATCH 001/273] squirrel-update test on desktop shortcut groups too many assertions Every test on desktop shortcut now tends to have 1 assertion. They have been rearranged to show more clearly what is the actual test intent. Expectation already checked somewhere else have been removed. --- spec/squirrel-update-spec.coffee | 91 +++++++++++++++++++++----------- 1 file changed, 59 insertions(+), 32 deletions(-) diff --git a/spec/squirrel-update-spec.coffee b/spec/squirrel-update-spec.coffee index b71a9b0c4..e3891ed1c 100644 --- a/spec/squirrel-update-spec.coffee +++ b/spec/squirrel-update-spec.coffee @@ -5,25 +5,25 @@ path = require 'path' temp = require 'temp' SquirrelUpdate = require '../src/browser/squirrel-update' -describe "Windows squirrel updates", -> +describe "Windows Squirrel Update", -> tempHomeDirectory = null + originalSpawn = ChildProcess.spawn + + harmlessSpawn = -> + # Just spawn something that won't actually modify the host + if process.platform is 'win32' + originalSpawn('dir') + else + originalSpawn('ls') beforeEach -> - # Prevent the actually home directory from being manipulated + # Prevent the actual home directory from being manipulated tempHomeDirectory = temp.mkdirSync('atom-temp-home-') spyOn(fs, 'getHomeDirectory').andReturn(tempHomeDirectory) # Prevent any commands from actually running and affecting the host - originalSpawn = ChildProcess.spawn spyOn(ChildProcess, 'spawn').andCallFake (command, args) -> - if path.basename(command) is 'Update.exe' and args?[0] is '--createShortcut' - fs.writeFileSync(path.join(tempHomeDirectory, 'Desktop', 'Atom.lnk'), '') - - # Just spawn something that won't actually modify the host - if process.platform is 'win32' - originalSpawn('dir') - else - originalSpawn('ls') + harmlessSpawn() it "ignores errors spawning Squirrel", -> jasmine.unspy(ChildProcess, 'spawn') @@ -67,28 +67,55 @@ describe "Windows squirrel updates", -> runs -> expect(SquirrelUpdate.handleStartupEvent(app, '--not-squirrel')).toBe false - it "keeps the desktop shortcut deleted on updates if it was previously deleted after install", -> - desktopShortcutPath = path.join(tempHomeDirectory, 'Desktop', 'Atom.lnk') - expect(fs.existsSync(desktopShortcutPath)).toBe false - - app = quit: jasmine.createSpy('quit') - expect(SquirrelUpdate.handleStartupEvent(app, '--squirrel-install')).toBe true - - waitsFor -> - app.quit.callCount is 1 - - runs -> - app.quit.reset() - expect(fs.existsSync(desktopShortcutPath)).toBe true - fs.removeSync(desktopShortcutPath) - expect(fs.existsSync(desktopShortcutPath)).toBe false - expect(SquirrelUpdate.handleStartupEvent(app, '--squirrel-updated')).toBe true - - waitsFor -> - app.quit.callCount is 1 - - runs -> + describe "Desktop shortcut", -> + desktopShortcutPath = '/non/existing/path' + + beforeEach -> + desktopShortcutPath = path.join(tempHomeDirectory, 'Desktop', 'Atom.lnk') + + jasmine.unspy(ChildProcess, 'spawn') + spyOn(ChildProcess, 'spawn').andCallFake (command, args) -> + if path.basename(command) is 'Update.exe' and args?[0] is '--createShortcut' + fs.writeFileSync(path.join(tempHomeDirectory, 'Desktop', 'Atom.lnk'), '') + harmlessSpawn() + else + throw new Error("API not mocked") + + it "does not exist before install", -> expect(fs.existsSync(desktopShortcutPath)).toBe false + + describe "on install", -> + beforeEach -> + app = quit: jasmine.createSpy('quit') + SquirrelUpdate.handleStartupEvent(app, '--squirrel-install') + waitsFor -> + app.quit.callCount is 1 + + it "creates desktop shortcut", -> + expect(fs.existsSync(desktopShortcutPath)).toBe true + + describe "when shortcut is deleted and then app is updated", -> + beforeEach -> + fs.removeSync(desktopShortcutPath) + expect(fs.existsSync(desktopShortcutPath)).toBe false + + app = quit: jasmine.createSpy('quit') + SquirrelUpdate.handleStartupEvent(app, '--squirrel-updated') + waitsFor -> + app.quit.callCount is 1 + + it "does not recreate shortcut", -> + expect(fs.existsSync(desktopShortcutPath)).toBe false + + describe "when shortcut is kept and app is updated", -> + beforeEach -> + app = quit: jasmine.createSpy('quit') + SquirrelUpdate.handleStartupEvent(app, '--squirrel-updated') + waitsFor -> + app.quit.callCount is 1 + + it "still has desktop shortcut", -> + expect(fs.existsSync(desktopShortcutPath)).toBe true describe ".restartAtom", -> it "quits the app and spawns a new one", -> From 538500042c7d3878aa0afb7060343ff1e05bf400 Mon Sep 17 00:00:00 2001 From: Collin Donahue-Oponski Date: Mon, 16 Nov 2015 22:05:23 -0700 Subject: [PATCH 002/273] :bug: Autoscroll to cursor after clearing multi-cursor selection. --- src/text-editor.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index e5b3bd481..501c52a43 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -2445,6 +2445,7 @@ class TextEditor extends Model selections = @getSelections() if selections.length > 1 selection.destroy() for selection in selections[1...(selections.length)] + selections[0].autoscroll() true else false From e4e200317abcd6c484ba834e4bac32ad27463452 Mon Sep 17 00:00:00 2001 From: Collin Donahue-Oponski Date: Fri, 11 Dec 2015 15:32:29 -0700 Subject: [PATCH 003/273] :white_check_mark: Autoscroll to cursor after clearing multi-cursor selection. --- spec/text-editor-spec.coffee | 32 +++++++++++++++++++++++++++----- src/text-editor.coffee | 2 +- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 02d2e4a96..a99e95ee6 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -2119,20 +2119,42 @@ describe "TextEditor", -> editor.splitSelectionsIntoLines() expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [0, 3]]] - describe ".consolidateSelections()", -> - it "destroys all selections but the least recent, returning true if any selections were destroyed", -> - editor.setSelectedBufferRange([[3, 16], [3, 21]]) - selection1 = editor.getLastSelection() + describe "::consolidateSelections()", -> + makeMultipleSelections = -> + selection.setBufferRange [[3, 16], [3, 21]] selection2 = editor.addSelectionForBufferRange([[3, 25], [3, 34]]) selection3 = editor.addSelectionForBufferRange([[8, 4], [8, 10]]) + selection4 = editor.addSelectionForBufferRange([[1, 6], [1, 10]]) + expect(editor.getSelections()).toEqual [selection, selection2, selection3, selection4] + [selection, selection2, selection3, selection4] + + it "destroys all selections but the least recent, returning true if any selections were destroyed", -> + [selection1] = makeMultipleSelections() - expect(editor.getSelections()).toEqual [selection1, selection2, selection3] expect(editor.consolidateSelections()).toBeTruthy() expect(editor.getSelections()).toEqual [selection1] expect(selection1.isEmpty()).toBeFalsy() expect(editor.consolidateSelections()).toBeFalsy() expect(editor.getSelections()).toEqual [selection1] + it "scrolls to the remaining selection", -> + [selection1] = makeMultipleSelections() + + atom.config.set('editor.scrollPastEnd', true) + editor.setHeight(100, true) + editor.setLineHeightInPixels(10) + editor.setFirstVisibleScreenRow(10) + expect(editor.getVisibleRowRange()[0]).toBeGreaterThan(selection1.getBufferRowRange()[1]) + + editor.consolidateSelections() + + waitsForPromise -> + new Promise((resolve) -> window.requestAnimationFrame(resolve)) + + runs -> + expect(editor.getVisibleRowRange()[0]).not.toBeGreaterThan(selection1.getBufferRowRange()[0]) + expect(editor.getVisibleRowRange()[1]).not.toBeLessThan(selection1.getBufferRowRange()[0]) + describe "when the cursor is moved while there is a selection", -> makeSelection = -> selection.setBufferRange [[1, 2], [1, 5]] diff --git a/src/text-editor.coffee b/src/text-editor.coffee index ba54b9cd4..d4d0737e2 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -2437,7 +2437,7 @@ class TextEditor extends Model selections = @getSelections() if selections.length > 1 selection.destroy() for selection in selections[1...(selections.length)] - selections[0].autoscroll() + selections[0].autoscroll(center: true) true else false From 3a14fa2a2e4b1d34e4c90c7a33da620c1d0acaa5 Mon Sep 17 00:00:00 2001 From: Joe Fitzgerald Date: Tue, 19 Jan 2016 17:41:27 -0800 Subject: [PATCH 004/273] Use ELECTRON_RUN_AS_NODE Variable Key - https://github.com/atom/electron/pull/3594 --- src/buffered-node-process.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/buffered-node-process.coffee b/src/buffered-node-process.coffee index bb1a1c655..3b4916b24 100644 --- a/src/buffered-node-process.coffee +++ b/src/buffered-node-process.coffee @@ -46,7 +46,7 @@ class BufferedNodeProcess extends BufferedProcess options ?= {} options.env ?= Object.create(process.env) - options.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE'] = 1 + options.env['ELECTRON_RUN_AS_NODE'] = 1 args = args?.slice() ? [] args.unshift(command) From b3e8ba350ab372ea45f9e1826176c886ef43ed10 Mon Sep 17 00:00:00 2001 From: Paul Aikman Date: Tue, 16 Feb 2016 22:04:33 +0000 Subject: [PATCH 005/273] Fix for directory provider on Windows. Checks for presence of host in URL passed in instead of protocol (false positive). --- src/default-directory-provider.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/default-directory-provider.coffee b/src/default-directory-provider.coffee index 6b05a582f..094522980 100644 --- a/src/default-directory-provider.coffee +++ b/src/default-directory-provider.coffee @@ -16,8 +16,8 @@ class DefaultDirectoryProvider # * `null` if the given URI is not compatibile with this provider. directoryForURISync: (uri) -> normalizedPath = path.normalize(uri) - {protocol} = url.parse(uri) - directoryPath = if protocol? + host = url.parse(uri).host; + directoryPath = if host uri else if not fs.isDirectorySync(normalizedPath) and fs.isDirectorySync(path.dirname(normalizedPath)) path.dirname(normalizedPath) @@ -26,7 +26,7 @@ class DefaultDirectoryProvider # TODO: Stop normalizing the path in pathwatcher's Directory. directory = new Directory(directoryPath) - if protocol? + if host directory.path = directoryPath if fs.isCaseInsensitive() directory.lowerCasePath = directoryPath.toLowerCase() From 17a2bec3966b2614f4574795d24aecd21f0e696c Mon Sep 17 00:00:00 2001 From: Paul Aikman Date: Wed, 17 Feb 2016 16:20:45 +0000 Subject: [PATCH 006/273] Fix for linter error on CI build. --- src/default-directory-provider.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/default-directory-provider.coffee b/src/default-directory-provider.coffee index 094522980..ed4e9ba36 100644 --- a/src/default-directory-provider.coffee +++ b/src/default-directory-provider.coffee @@ -16,7 +16,7 @@ class DefaultDirectoryProvider # * `null` if the given URI is not compatibile with this provider. directoryForURISync: (uri) -> normalizedPath = path.normalize(uri) - host = url.parse(uri).host; + {host} = url.parse(uri) directoryPath = if host uri else if not fs.isDirectorySync(normalizedPath) and fs.isDirectorySync(path.dirname(normalizedPath)) From 2d4474eb8b31af3c952bcb68543bb0540d849c5d Mon Sep 17 00:00:00 2001 From: Carl Henderson Date: Mon, 22 Feb 2016 15:13:38 -0500 Subject: [PATCH 007/273] search only new data for new lines rather than entire buffer --- src/buffered-process.coffee | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/buffered-process.coffee b/src/buffered-process.coffee index c7097d711..183a1d99a 100644 --- a/src/buffered-process.coffee +++ b/src/buffered-process.coffee @@ -111,11 +111,12 @@ class BufferedProcess stream.on 'data', (data) => return if @killed + bufferedLength = buffered.length buffered += data - lastNewlineIndex = buffered.lastIndexOf('\n') + lastNewlineIndex = data.lastIndexOf('\n') if lastNewlineIndex isnt -1 - onLines(buffered.substring(0, lastNewlineIndex + 1)) - buffered = buffered.substring(lastNewlineIndex + 1) + onLines(buffered.substring(0, lastNewlineIndex + bufferedLength + 1)) + buffered = buffered.substring(lastNewlineIndex + bufferedLength + 1) stream.on 'close', => return if @killed From a62965dc62336f8b344eefc20c8a0440edf69435 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 25 Feb 2016 09:25:13 -0800 Subject: [PATCH 008/273] Default the channel based on the package.json, not the branch --- build/Gruntfile.coffee | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index a34e1fbd4..2340f8823 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -35,22 +35,8 @@ module.exports = (grunt) -> # Options installDir = grunt.option('install-dir') - buildDir = grunt.option('build-dir') - buildDir ?= 'out' - buildDir = path.resolve(buildDir) - - channel = grunt.option('channel') - releasableBranches = ['stable', 'beta'] - if process.env.APPVEYOR and not process.env.APPVEYOR_PULL_REQUEST_NUMBER - channel ?= process.env.APPVEYOR_REPO_BRANCH if process.env.APPVEYOR_REPO_BRANCH in releasableBranches - - if process.env.TRAVIS and not process.env.TRAVIS_PULL_REQUEST - channel ?= process.env.TRAVIS_BRANCH if process.env.TRAVIS_BRANCH in releasableBranches - - if process.env.JANKY_BRANCH - channel ?= process.env.JANKY_BRANCH if process.env.JANKY_BRANCH in releasableBranches - - channel ?= 'dev' + buildDir = path.resolve(grunt.option('build-dir') ? 'out') + channel = grunt.option('channel') ? getDefaultReleaseChannel() metadata = packageJson appName = packageJson.productName @@ -310,3 +296,15 @@ module.exports = (grunt) -> unless process.platform is 'linux' or grunt.option('no-install') defaultTasks.push 'install' grunt.registerTask('default', defaultTasks) + +getDefaultReleaseChannel = -> + {version} = packageJson + if version.match(/dev/) or isBuildingPR() + 'dev' + else if version.match(/beta/) + 'beta' + else + 'stable' + +isBuildingPR = -> + process.env.APPVEYOR_PULL_REQUEST_NUMBER? or process.env.TRAVIS_PULL_REQUEST? From 77bae0fad1df9be04d2f98ad05e49bf099a6dcbb Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 25 Feb 2016 10:24:41 -0800 Subject: [PATCH 009/273] When creating draft releases, choose release branch based on version number --- build/Gruntfile.coffee | 22 ++++++++++++++-------- build/tasks/publish-build-task.coffee | 13 ++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index 2340f8823..d9375d05c 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -34,9 +34,10 @@ module.exports = (grunt) -> grunt.file.setBase(path.resolve('..')) # Options + [defaultChannel, releaseBranch] = getDefaultChannelAndReleaseBranch(packageJson.version) installDir = grunt.option('install-dir') buildDir = path.resolve(grunt.option('build-dir') ? 'out') - channel = grunt.option('channel') ? getDefaultReleaseChannel() + channel = grunt.option('channel') ? defaultChannel metadata = packageJson appName = packageJson.productName @@ -175,7 +176,7 @@ module.exports = (grunt) -> pkg: grunt.file.readJSON('package.json') atom: { - appName, channel, metadata, + appName, channel, metadata, releaseBranch, appFileName, apmFileName, appDir, buildDir, contentsDir, installDir, shellAppDir, symbolsDir, } @@ -297,14 +298,19 @@ module.exports = (grunt) -> defaultTasks.push 'install' grunt.registerTask('default', defaultTasks) -getDefaultReleaseChannel = -> - {version} = packageJson +getDefaultChannelAndReleaseBranch = (version) -> if version.match(/dev/) or isBuildingPR() - 'dev' - else if version.match(/beta/) - 'beta' + channel = 'dev' + releaseBranch = null else - 'stable' + if version.match(/beta/) + channel = 'beta' + else + channel = 'stable' + + minorVersion = version.match(/^\d\.\d/)[0] + releaseBranch = "#{minorVersion}-releases" + [channel, releaseBranch] isBuildingPR = -> process.env.APPVEYOR_PULL_REQUEST_NUMBER? or process.env.TRAVIS_PULL_REQUEST? diff --git a/build/tasks/publish-build-task.coffee b/build/tasks/publish-build-task.coffee index 4f8df6336..de46eb4fe 100644 --- a/build/tasks/publish-build-task.coffee +++ b/build/tasks/publish-build-task.coffee @@ -31,14 +31,9 @@ module.exports = (gruntObject) -> cp path.join(docsOutputDir, 'api.json'), path.join(buildDir, 'atom-api.json') grunt.registerTask 'upload-assets', 'Upload the assets to a GitHub release', -> - channel = grunt.config.get('atom.channel') - switch channel - when 'stable' - isPrerelease = false - when 'beta' - isPrerelease = true - else - return + releaseBranch = grunt.config.get('atom.releaseBranch') + isPrerelease = grunt.config.get('atom.channel') is 'beta' + return unless releaseBranch? doneCallback = @async() startTime = Date.now() @@ -55,7 +50,7 @@ module.exports = (gruntObject) -> zipAssets buildDir, assets, (error) -> return done(error) if error? - getAtomDraftRelease isPrerelease, channel, (error, release) -> + getAtomDraftRelease isPrerelease, releaseBranch, (error, release) -> return done(error) if error? assetNames = (asset.assetName for asset in assets) deleteExistingAssets release, assetNames, (error) -> From 9c5c171eb59b9d7a17668c6b9bf25477523b09da Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 25 Feb 2016 10:28:03 -0800 Subject: [PATCH 010/273] Don't refer to stable and beta as branches --- build/tasks/set-version-task.coffee | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build/tasks/set-version-task.coffee b/build/tasks/set-version-task.coffee index fc2382476..c7a29b584 100644 --- a/build/tasks/set-version-task.coffee +++ b/build/tasks/set-version-task.coffee @@ -5,9 +5,7 @@ module.exports = (grunt) -> {spawn} = require('./task-helpers')(grunt) getVersion = (callback) -> - releasableBranches = ['stable', 'beta'] - channel = grunt.config.get('atom.channel') - shouldUseCommitHash = if channel in releasableBranches then false else true + shouldUseCommitHash = grunt.config.get('atom.channel') is 'dev' inRepository = fs.existsSync(path.resolve(__dirname, '..', '..', '.git')) {version} = require(path.join(grunt.config.get('atom.appDir'), 'package.json')) if shouldUseCommitHash and inRepository From 44dabf1e2fb6f058d7d2e024063f036bf75bc73b Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 10:22:10 -0500 Subject: [PATCH 011/273] Added .getElement to TextEditor. --- src/text-editor.coffee | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index c0a6f2057..d1c092598 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -11,6 +11,7 @@ Selection = require './selection' TextMateScopeSelector = require('first-mate').ScopeSelector {Directory} = require "pathwatcher" GutterContainer = require './gutter-container' +TextEditorElement = require './text-editor-element' # Essential: This class represents all essential editing state for a single # {TextBuffer}, including cursor and selection positions, folds, and soft wraps. @@ -61,6 +62,10 @@ class TextEditor extends Model suppressSelectionMerging: false selectionFlashDuration: 500 gutterContainer: null + editorElement: null + + Object.defineProperty @prototype, "element", + get: -> @getElement() @deserialize: (state, atomEnvironment) -> try @@ -3142,6 +3147,10 @@ class TextEditor extends Model Section: TextEditor Rendering ### + # Get the Element for the editor. + getElement: -> + @editorElement ?= new TextEditorElement().initialize(this, atom) + # Essential: Retrieves the greyed out placeholder of a mini editor. # # Returns a {String}. From 10f0064a63c93b36511ce265453e6394f4e594e4 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 10:24:31 -0500 Subject: [PATCH 012/273] Call .getElement if the model has it. --- src/view-registry.coffee | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/view-registry.coffee b/src/view-registry.coffee index ef7151353..5fbfba729 100644 --- a/src/view-registry.coffee +++ b/src/view-registry.coffee @@ -171,6 +171,11 @@ class ViewRegistry if object instanceof HTMLElement return object + if typeof object?.getElement is 'function' + element = object.getElement() + if element instanceof HTMLElement + return element + if object?.element instanceof HTMLElement return object.element From 02c7bb3ddd8ef2980e5c7be69c2dfb0e78967370 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 10:24:38 -0500 Subject: [PATCH 013/273] Don't need this view provider anymore. --- src/atom-environment.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index c42bf05aa..dc1bef7d4 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -254,8 +254,6 @@ class AtomEnvironment extends Model new PaneAxisElement().initialize(model, env) @views.addViewProvider Pane, (model, env) -> new PaneElement().initialize(model, env) - @views.addViewProvider TextEditor, (model, env) -> - new TextEditorElement().initialize(model, env) @views.addViewProvider(Gutter, createGutterView) registerDefaultOpeners: -> From dfb1d1d62d091bfc6e87fb3e56bd2c9b81d36d89 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 10:24:51 -0500 Subject: [PATCH 014/273] Expose a bound buildTextEditor. --- src/workspace.coffee | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index 0bfff7e0f..e0a913f94 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -43,6 +43,12 @@ class Workspace extends Model @defaultDirectorySearcher = new DefaultDirectorySearcher() @consumeServices(@packageManager) + # One cannot simply .bind here since it could be used as a component with + # Etch, which means it'd be `new`d in which case `this` would the new + # object. + realThis = this + @buildTextEditor = (params) -> realThis.buildTextEditor_(params) + @panelContainers = top: new PanelContainer({location: 'top'}) left: new PanelContainer({location: 'left'}) @@ -550,7 +556,7 @@ class Workspace extends Model # Extended: Create a new text editor. # # Returns a {TextEditor}. - buildTextEditor: (params) -> + buildTextEditor_: (params) -> params = _.extend({ @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, @project, @assert, @applicationDelegate From 768f5ee5ca1c9eb2a896e668661c54e6dbc1541f Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 14:00:49 -0500 Subject: [PATCH 015/273] Maybe a better comment? --- src/workspace.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index e0a913f94..15ffc6e6a 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -44,8 +44,8 @@ class Workspace extends Model @consumeServices(@packageManager) # One cannot simply .bind here since it could be used as a component with - # Etch, which means it'd be `new`d in which case `this` would the new - # object. + # Etch, in which case it'd be `new`d. And when it's `new`d, `this` is always + # the newly created object. realThis = this @buildTextEditor = (params) -> realThis.buildTextEditor_(params) From 55e1496b96b93d9cec2a48dd261081165b09632e Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 14:49:07 -0500 Subject: [PATCH 016/273] Call the prototype method directly. h/t @maxbrunsfeld --- src/workspace.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index 15ffc6e6a..31c381428 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -47,7 +47,7 @@ class Workspace extends Model # Etch, in which case it'd be `new`d. And when it's `new`d, `this` is always # the newly created object. realThis = this - @buildTextEditor = (params) -> realThis.buildTextEditor_(params) + @buildTextEditor = -> Workspace.prototype.buildTextEditor.apply(realThis, arguments) @panelContainers = top: new PanelContainer({location: 'top'}) @@ -556,7 +556,7 @@ class Workspace extends Model # Extended: Create a new text editor. # # Returns a {TextEditor}. - buildTextEditor_: (params) -> + buildTextEditor: (params) -> params = _.extend({ @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, @project, @assert, @applicationDelegate From f3ce468a7068a09c26e2f76078ad5a820253cf9b Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 15:01:40 -0500 Subject: [PATCH 017/273] Support specifying whether to ignore invisibles and the grammar. --- src/text-editor.coffee | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index d1c092598..e1706d5f1 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -97,7 +97,7 @@ class TextEditor extends Model softWrapped, @displayBuffer, @selectionsMarkerLayer, buffer, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode, @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, - @project, @assert, @applicationDelegate, @pending + @project, @assert, @applicationDelegate, @pending, grammarName, ignoreInvisibles } = params throw new Error("Must pass a config parameter when constructing TextEditors") unless @config? @@ -119,7 +119,7 @@ class TextEditor extends Model buffer ?= new TextBuffer @displayBuffer ?= new DisplayBuffer({ - buffer, tabLength, softWrapped, ignoreInvisibles: @mini, largeFileMode, + buffer, tabLength, softWrapped, ignoreInvisibles: @mini || ignoreInvisibles, largeFileMode, @config, @assert, @grammarRegistry, @packageManager }) @buffer = @displayBuffer.buffer @@ -148,6 +148,9 @@ class TextEditor extends Model priority: 0 visible: lineNumberGutterVisible + if grammarName? + @setGrammar(@grammarRegistry.grammarForScopeName(grammarName)) + serialize: -> deserializer: 'TextEditor' id: @id From 822cd780555278b615e0da32020115b0d5fe7295 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 15:18:29 -0500 Subject: [PATCH 018/273] Use the computed style to find the height --- src/text-editor-component.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index bdd0befcd..d5103c1fb 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -731,8 +731,7 @@ class TextEditorComponent measureDimensions: -> return unless @mounted - {position} = getComputedStyle(@hostElement) - {height} = @hostElement.style + {position, height} = getComputedStyle(@hostElement) if position is 'absolute' or height @presenter.setAutoHeight(false) From 2af53231f16c602423f223fe99fb834a730d5f9f Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 15:21:56 -0500 Subject: [PATCH 019/273] Less lint. --- 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 e1706d5f1..19b7e8c86 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -119,7 +119,7 @@ class TextEditor extends Model buffer ?= new TextBuffer @displayBuffer ?= new DisplayBuffer({ - buffer, tabLength, softWrapped, ignoreInvisibles: @mini || ignoreInvisibles, largeFileMode, + buffer, tabLength, softWrapped, ignoreInvisibles: @mini or ignoreInvisibles, largeFileMode, @config, @assert, @grammarRegistry, @packageManager }) @buffer = @displayBuffer.buffer From dd780a7c5a415f513acae6d501df1f4f23c1cf93 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 15:41:55 -0500 Subject: [PATCH 020/273] Revert "Use the computed style to find the height" This reverts commit 822cd780555278b615e0da32020115b0d5fe7295. --- src/text-editor-component.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index d5103c1fb..bdd0befcd 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -731,7 +731,8 @@ class TextEditorComponent measureDimensions: -> return unless @mounted - {position, height} = getComputedStyle(@hostElement) + {position} = getComputedStyle(@hostElement) + {height} = @hostElement.style if position is 'absolute' or height @presenter.setAutoHeight(false) From dd83619c45a8fc0e4decf0127bfa38d0f46a128d Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 16:05:57 -0500 Subject: [PATCH 021/273] Add autoHeight setting. --- src/text-editor-element.coffee | 4 ++++ src/text-editor.coffee | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 380417163..554f73cef 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -344,6 +344,10 @@ class TextEditorElement extends HTMLElement @style.height = height + "px" @component.measureDimensions() + disableAutoHeight: -> + @style.height = "100%" + @component.measureDimensions() + getHeight: -> @offsetHeight diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 19b7e8c86..06e58aa1e 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -97,7 +97,7 @@ class TextEditor extends Model softWrapped, @displayBuffer, @selectionsMarkerLayer, buffer, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode, @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, - @project, @assert, @applicationDelegate, @pending, grammarName, ignoreInvisibles + @project, @assert, @applicationDelegate, @pending, grammarName, ignoreInvisibles, @autoHeight } = params throw new Error("Must pass a config parameter when constructing TextEditors") unless @config? @@ -116,6 +116,7 @@ class TextEditor extends Model @cursors = [] @cursorsByMarkerId = new Map @selections = [] + @autoHeight ?= true buffer ?= new TextBuffer @displayBuffer ?= new DisplayBuffer({ @@ -3152,7 +3153,11 @@ class TextEditor extends Model # Get the Element for the editor. getElement: -> - @editorElement ?= new TextEditorElement().initialize(this, atom) + if not @editorElement? + @editorElement = new TextEditorElement().initialize(this, atom) + if not @autoHeight + @editorElement.disableAutoHeight() + @editorElement # Essential: Retrieves the greyed out placeholder of a mini editor. # From ff0b9e30a9bea281bfad8ab55e57bce4daf5e386 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 16:59:58 -0500 Subject: [PATCH 022/273] Add ignoreScrollPastEnd --- src/text-editor-component.coffee | 3 ++- src/text-editor-element.coffee | 4 +++- src/text-editor-presenter.coffee | 4 ++-- src/text-editor.coffee | 11 ++++++----- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index bdd0befcd..5a4097fc5 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -43,7 +43,7 @@ class TextEditorComponent @assert domNode?, "TextEditorComponent::domNode was set to null." @domNodeValue = domNode - constructor: ({@editor, @hostElement, @rootElement, @stylesElement, @useShadowDOM, tileSize, @views, @themes, @config, @workspace, @assert, @grammars}) -> + constructor: ({@editor, @hostElement, @rootElement, @stylesElement, @useShadowDOM, tileSize, @views, @themes, @config, @workspace, @assert, @grammars, ignoreScrollPastEnd}) -> @tileSize = tileSize if tileSize? @disposables = new CompositeDisposable @@ -61,6 +61,7 @@ class TextEditorComponent stoppedScrollingDelay: 200 config: @config lineTopIndex: lineTopIndex + ignoreScrollPastEnd: ignoreScrollPastEnd @presenter.onDidUpdateState(@requestUpdate) diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 554f73cef..6fad33dc3 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -17,6 +17,7 @@ class TextEditorElement extends HTMLElement focusOnAttach: false hasTiledRendering: true logicalDisplayBuffer: true + ignoreScrollPastEnd: false createdCallback: -> # Use globals when the following instance variables aren't set. @@ -86,7 +87,7 @@ class TextEditorElement extends HTMLElement @subscriptions.add @component.onDidChangeScrollLeft => @emitter.emit("did-change-scroll-left", arguments...) - initialize: (model, {@views, @config, @themes, @workspace, @assert, @styles, @grammars}) -> + initialize: (model, {@views, @config, @themes, @workspace, @assert, @styles, @grammars}, @ignoreScrollPastEnd = false) -> throw new Error("Must pass a config parameter when initializing TextEditorElements") unless @views? throw new Error("Must pass a config parameter when initializing TextEditorElements") unless @config? throw new Error("Must pass a themes parameter when initializing TextEditorElements") unless @themes? @@ -143,6 +144,7 @@ class TextEditorElement extends HTMLElement workspace: @workspace assert: @assert grammars: @grammars + ignoreScrollPastEnd: @ignoreScrollPastEnd ) @rootElement.appendChild(@component.getDomNode()) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index a3504caa8..0db175c2b 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -13,7 +13,7 @@ class TextEditorPresenter minimumReflowInterval: 200 constructor: (params) -> - {@model, @config, @lineTopIndex} = params + {@model, @config, @lineTopIndex, @ignoreScrollPastEnd} = params {@cursorBlinkPeriod, @cursorBlinkResumeDelay, @stoppedScrollingDelay, @tileSize} = params {@contentFrameWidth} = params @@ -661,7 +661,7 @@ class TextEditorPresenter return unless @contentHeight? and @clientHeight? contentHeight = @contentHeight - if @scrollPastEnd + if @scrollPastEnd and not @ignoreScrollPastEnd extraScrollHeight = @clientHeight - (@lineHeight * 3) contentHeight += extraScrollHeight if extraScrollHeight > 0 scrollHeight = Math.max(contentHeight, @height) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index c1a4150e9..c22a1a73f 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -97,7 +97,7 @@ class TextEditor extends Model softWrapped, @displayBuffer, @selectionsMarkerLayer, buffer, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode, @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, - @project, @assert, @applicationDelegate, @pending, grammarName, ignoreInvisibles, @autoHeight + @project, @assert, @applicationDelegate, @pending, grammarName, ignoreInvisibles, @autoHeight, @ignoreScrollPastEnd } = params throw new Error("Must pass a config parameter when constructing TextEditors") unless @config? @@ -117,6 +117,7 @@ class TextEditor extends Model @cursorsByMarkerId = new Map @selections = [] @autoHeight ?= true + @ignoreScrollPastEnd ?= false buffer ?= new TextBuffer @displayBuffer ?= new DisplayBuffer({ @@ -3153,9 +3154,9 @@ class TextEditor extends Model # Get the Element for the editor. getElement: -> - if not @editorElement? - @editorElement = new TextEditorElement().initialize(this, atom) - if not @autoHeight + unless @editorElement? + @editorElement = new TextEditorElement().initialize(this, atom, @ignoreScrollPastEnd) + unless @autoHeight @editorElement.disableAutoHeight() @editorElement @@ -3233,7 +3234,7 @@ class TextEditor extends Model setFirstVisibleScreenRow: (screenRow, fromView) -> unless fromView maxScreenRow = @getScreenLineCount() - 1 - unless @config.get('editor.scrollPastEnd') + unless @config.get('editor.scrollPastEnd') and not @ignoreScrollPastEnd height = @displayBuffer.getHeight() lineHeightInPixels = @displayBuffer.getLineHeightInPixels() if height? and lineHeightInPixels? From dfd3e1b94840de8eecd89aa9793bc32f4260037c Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 17:11:04 -0500 Subject: [PATCH 023/273] Take autoHeight as an argument. --- src/text-editor-element.coffee | 9 ++++----- src/text-editor.coffee | 6 +----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 6fad33dc3..02f688e2c 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -39,6 +39,9 @@ class TextEditorElement extends HTMLElement @setAttribute('tabindex', -1) initializeContent: (attributes) -> + unless @autoHeight + @style.height = "100%" + if @config.get('editor.useShadowDOM') @useShadowDOM = true @@ -87,7 +90,7 @@ class TextEditorElement extends HTMLElement @subscriptions.add @component.onDidChangeScrollLeft => @emitter.emit("did-change-scroll-left", arguments...) - initialize: (model, {@views, @config, @themes, @workspace, @assert, @styles, @grammars}, @ignoreScrollPastEnd = false) -> + initialize: (model, {@views, @config, @themes, @workspace, @assert, @styles, @grammars}, @autoHeight = true, @ignoreScrollPastEnd = false) -> throw new Error("Must pass a config parameter when initializing TextEditorElements") unless @views? throw new Error("Must pass a config parameter when initializing TextEditorElements") unless @config? throw new Error("Must pass a themes parameter when initializing TextEditorElements") unless @themes? @@ -346,10 +349,6 @@ class TextEditorElement extends HTMLElement @style.height = height + "px" @component.measureDimensions() - disableAutoHeight: -> - @style.height = "100%" - @component.measureDimensions() - getHeight: -> @offsetHeight diff --git a/src/text-editor.coffee b/src/text-editor.coffee index c22a1a73f..2823b993e 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -3154,11 +3154,7 @@ class TextEditor extends Model # Get the Element for the editor. getElement: -> - unless @editorElement? - @editorElement = new TextEditorElement().initialize(this, atom, @ignoreScrollPastEnd) - unless @autoHeight - @editorElement.disableAutoHeight() - @editorElement + @editorElement ?= new TextEditorElement().initialize(this, atom, @autoHeight, @ignoreScrollPastEnd) # Essential: Retrieves the greyed out placeholder of a mini editor. # From 5dfd0c9102e683b00212bbfea89d775ea6b7c457 Mon Sep 17 00:00:00 2001 From: Johnston Jiaa Date: Sun, 28 Feb 2016 11:48:27 -0500 Subject: [PATCH 024/273] Show tooltip immediately if the tooltip trigger is manual --- spec/tooltip-manager-spec.coffee | 4 ++++ src/tooltip-manager.coffee | 2 ++ src/tooltip.js | 4 +++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/spec/tooltip-manager-spec.coffee b/spec/tooltip-manager-spec.coffee index 87082504a..264d1a3bb 100644 --- a/spec/tooltip-manager-spec.coffee +++ b/spec/tooltip-manager-spec.coffee @@ -28,6 +28,10 @@ describe "TooltipManager", -> hover element, -> expect(document.body.querySelector(".tooltip")).toHaveText("Title") + it "creates a tooltip immediately if the trigger type is manual", -> + manager.add element, title: "Title", trigger: "manual" + expect(document.body.querySelector(".tooltip")).toHaveText("Title") + it "allows jQuery elements to be passed as the target", -> element2 = document.createElement('div') jasmine.attachToDOM(element2) diff --git a/src/tooltip-manager.coffee b/src/tooltip-manager.coffee index 247437535..90f0ab8e6 100644 --- a/src/tooltip-manager.coffee +++ b/src/tooltip-manager.coffee @@ -63,6 +63,8 @@ class TooltipManager # full list of options. You can also supply the following additional options: # * `title` A {String} or {Function} to use for the text in the tip. If # given a function, `this` will be set to the `target` element. + # * `trigger` A {String} that's the same as Bootstrap 'click | hover | focus + # | manual', except 'manual' will show the tooltip immediately. # * `keyBindingCommand` A {String} containing a command name. If you specify # this option and a key binding exists that matches the command, it will # be appended to the title or rendered alone if no title is specified. diff --git a/src/tooltip.js b/src/tooltip.js index 4ea952a64..ad5ce0cdd 100644 --- a/src/tooltip.js +++ b/src/tooltip.js @@ -64,7 +64,9 @@ Tooltip.prototype.init = function (element, options) { if (trigger === 'click') { this.disposables.add(listen(this.element, 'click', this.options.selector, this.toggle.bind(this))) - } else if (trigger !== 'manual') { + } else if (trigger === 'manual') { + this.show() + } else { var eventIn, eventOut if (trigger === 'hover') { From 92bbbf064508d50f75b84e4e2195f194dfd9facc Mon Sep 17 00:00:00 2001 From: Damien Guard Date: Sun, 28 Feb 2016 15:05:07 -0800 Subject: [PATCH 025/273] Windows command line does not allow ELSE on separate line, fixes #10934 --- resources/win/atom.cmd | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/resources/win/atom.cmd b/resources/win/atom.cmd index c9bfdd5ba..8d5e6f97a 100644 --- a/resources/win/atom.cmd +++ b/resources/win/atom.cmd @@ -35,8 +35,7 @@ IF "%EXPECT_OUTPUT%"=="YES" ( "%~dp0\..\..\atom.exe" --pid=%PID% %* rem If the wait flag is set, don't exit this process until Atom tells it to. goto waitLoop - ) - ELSE ( + ) ELSE ( "%~dp0\..\..\atom.exe" %* ) ) ELSE ( From 2dad38a7826522455feb56bd33f276f6b8eeeb49 Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Sun, 28 Feb 2016 17:57:59 -0800 Subject: [PATCH 026/273] onDidTerminatePendingState :arrow_right: onItemDidTerminatePendingState Signed-off-by: Katrina Uychaco --- src/pane.coffee | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/pane.coffee b/src/pane.coffee index 12abc5448..9905680bd 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -441,8 +441,10 @@ class Pane extends Model item setPendingItem: (item) => - @pendingItem = item if @pendingItem isnt item - @emitter.emit 'did-terminate-pending-state' if not item + if @pendingItem isnt item + mostRecentPendingItem = @pendingItem + @pendingItem = item + @emitter.emit 'item-did-terminate-pending-state', mostRecentPendingItem getPendingItem: => @pendingItem or null @@ -450,8 +452,8 @@ class Pane extends Model clearPendingItem: => @setPendingItem(null) - onDidTerminatePendingState: (callback) => - @emitter.on 'did-terminate-pending-state', callback + onItemDidTerminatePendingState: (callback) => + @emitter.on 'item-did-terminate-pending-state', callback # Public: Add the given items to the pane. # From 92dea0379a041d0c43f37df8c8068485aef02eb6 Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Sun, 28 Feb 2016 18:32:19 -0800 Subject: [PATCH 027/273] :arrow_up: tree-view Signed-off-by: Katrina Uychaco --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5dc94cda9..8830a3f98 100644 --- a/package.json +++ b/package.json @@ -112,7 +112,7 @@ "symbols-view": "0.111.1", "tabs": "0.90.2", "timecop": "0.33.1", - "tree-view": "0.201.4", + "tree-view": "0.201.5", "update-package-dependencies": "0.10.0", "welcome": "0.34.0", "whitespace": "0.32.2", From d39418ad7c61626753ffc9ed4536341ef0fc0b12 Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Sun, 28 Feb 2016 18:15:52 -0800 Subject: [PATCH 028/273] Add specs for Pane::setPendingItem and ::onItemDidTerminatePendingState Signed-off-by: Katrina Uychaco --- spec/pane-spec.coffee | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/spec/pane-spec.coffee b/spec/pane-spec.coffee index e5cbee1a6..b4785e113 100644 --- a/spec/pane-spec.coffee +++ b/spec/pane-spec.coffee @@ -183,6 +183,41 @@ describe "Pane", -> pane.activateItem(itemD, true) expect(pane.getItems().map (item) -> item.name).toEqual ['A', 'B', 'D'] + describe "::setPendingItem", -> + pane = null + + beforeEach -> + pane = atom.workspace.getActivePane() + + it "changes the pending item", -> + expect(pane.getPendingItem()).toBeNull() + pane.setPendingItem("fake item") + expect(pane.getPendingItem()).toEqual "fake item" + + describe "::onItemDidTerminatePendingState callback", -> + pane = null + callbackCalled = false + + beforeEach -> + pane = atom.workspace.getActivePane() + callbackCalled = false + + it "is called when the pending item changes", -> + pane.setPendingItem("fake item one") + pane.onItemDidTerminatePendingState (item) -> + callbackCalled = true + expect(item).toEqual "fake item one" + pane.setPendingItem("fake item two") + expect(callbackCalled).toBeTruthy() + + it "has access to the new pending item via ::getPendingItem", -> + pane.setPendingItem("fake item one") + pane.onItemDidTerminatePendingState (item) -> + callbackCalled = true + expect(pane.getPendingItem()).toEqual "fake item two" + pane.setPendingItem("fake item two") + expect(callbackCalled).toBeTruthy() + describe "::activateNextRecentlyUsedItem() and ::activatePreviousRecentlyUsedItem()", -> it "sets the active item to the next/previous item in the itemStack, looping around at either end", -> pane = new Pane(paneParams(items: [new Item("A"), new Item("B"), new Item("C"), new Item("D"), new Item("E")])) From 4769e601bf9e3e0595789a276a29f0cd2e1e5b5a Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Mon, 29 Feb 2016 11:27:38 -0800 Subject: [PATCH 029/273] Move spec from tabs package See https://github.com/atom/tabs/pull/274#issuecomment-190064071 Signed-off-by: Katrina Uychaco --- spec/workspace-spec.coffee | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 78bbf2fdb..2e15431b2 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -604,6 +604,25 @@ describe "Workspace", -> runs -> expect(pane.getPendingItem()).toBeNull() + describe "when opening will switch from a pending tab to a permanent tab", -> + it "keeps the pending tab open", -> + editor1 = null + editor2 = null + + waitsForPromise -> + atom.workspace.open('sample.txt').then (o) -> + editor1 = o + + waitsForPromise -> + atom.workspace.open('sample2.txt', pending: true).then (o) -> + editor2 = o + + runs -> + pane = atom.workspace.getActivePane() + pane.activateItem(editor1) + expect(pane.getItems().length).toBe 2 + expect(pane.getItems()).toEqual [editor1, editor2] + describe "::reopenItem()", -> it "opens the uri associated with the last closed pane that isn't currently open", -> pane = workspace.getActivePane() From 920d348014ac2ddf42e54e0bed6bb2cd71465146 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 29 Feb 2016 11:32:28 -0800 Subject: [PATCH 030/273] Only move legit items to the top of the stack Fixes #11002 cc @natalieogle --- spec/pane-spec.coffee | 4 ++++ src/pane.coffee | 1 + 2 files changed, 5 insertions(+) diff --git a/spec/pane-spec.coffee b/spec/pane-spec.coffee index b4785e113..888ccf6e2 100644 --- a/spec/pane-spec.coffee +++ b/spec/pane-spec.coffee @@ -337,6 +337,10 @@ describe "Pane", -> expect(pane.itemStack).toEqual [item2] expect(pane.getActiveItem()).toBe item2 + pane.destroyItem(item2) + expect(pane.itemStack).toEqual [] + expect(pane.getActiveItem()).toBeUndefined() + it "invokes ::onWillDestroyItem() observers before destroying the item", -> events = [] pane.onWillDestroyItem (event) -> diff --git a/src/pane.coffee b/src/pane.coffee index 9905680bd..25f421934 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -307,6 +307,7 @@ class Pane extends Model # Add item (or move item) to the end of the itemStack addItemToStack: (newItem) -> + return unless newItem? index = @itemStack.indexOf(newItem) @itemStack.splice(index, 1) unless index is -1 @itemStack.push(newItem) From c849216084d248402c3d9a81fe7d55cacc0b7545 Mon Sep 17 00:00:00 2001 From: Jonathan Willis Date: Mon, 29 Feb 2016 14:49:19 -0500 Subject: [PATCH 031/273] Config: Added documentation for order key in config. --- src/config.coffee | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/config.coffee b/src/config.coffee index 348b7b94f..66f07516e 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -319,6 +319,23 @@ ScopeDescriptor = require './scope-descriptor' # * line breaks - `line breaks
` # * ~~strikethrough~~ - `~~strikethrough~~` # +# #### order +# +# The settings view orders your settings alphabetically. You can override this +# ordering with the order key. +# +# ```coffee +# config: +# zSetting: +# type: 'integer' +# default: 4 +# order: 1 +# aSetting: +# type: 'integer' +# default: 4 +# order: 2 +# ``` +# # ## Best practices # # * Don't depend on (or write to) configuration keys outside of your keypath. From c99260bce75b852f60581782630813ccd5ab4e39 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 29 Feb 2016 15:04:36 -0500 Subject: [PATCH 032/273] Disable EOL diffs for diff stats too. --- src/git-repository-async.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/git-repository-async.js b/src/git-repository-async.js index 894b1216a..91b78e0c5 100644 --- a/src/git-repository-async.js +++ b/src/git-repository-async.js @@ -596,7 +596,15 @@ export default class GitRepositoryAsync { .then(([repo, headCommit]) => Promise.all([repo, headCommit.getTree()])) .then(([repo, tree]) => { const options = new Git.DiffOptions() + options.contextLines = 0 + options.flags = Git.Diff.OPTION.DISABLE_PATHSPEC_MATCH options.pathspec = this.relativize(_path, repo.workdir()) + if (process.platform === 'win32') { + // Ignore eol of line differences on windows so that files checked in + // as LF don't report every line modified when the text contains CRLF + // endings. + options.flags |= Git.Diff.OPTION.IGNORE_WHITESPACE_EOL + } return Git.Diff.treeToWorkdir(repo, tree, options) }) .then(diff => this._getDiffLines(diff)) From 9a938064cb72ecce7ebed2a795fd53727591a3f0 Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Mon, 29 Feb 2016 14:09:01 -0800 Subject: [PATCH 033/273] :arrow_up: tabs@0.91.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8830a3f98..42cf22f8b 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "status-bar": "1.1.0", "styleguide": "0.45.2", "symbols-view": "0.111.1", - "tabs": "0.90.2", + "tabs": "0.91.0", "timecop": "0.33.1", "tree-view": "0.201.5", "update-package-dependencies": "0.10.0", From 26cf7f081fe84ad8d08000f4b605d6dbd11c5906 Mon Sep 17 00:00:00 2001 From: Willem Van Lint Date: Fri, 26 Feb 2016 16:20:39 -0500 Subject: [PATCH 034/273] Registry for editors --- spec/text-editor-registry-spec.coffee | 38 +++++++++++++++++++++++++++ src/atom-environment.coffee | 6 +++++ src/text-editor-registry.coffee | 33 +++++++++++++++++++++++ src/text-editor.coffee | 5 +++- src/workspace.coffee | 5 +++- 5 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 spec/text-editor-registry-spec.coffee create mode 100644 src/text-editor-registry.coffee diff --git a/spec/text-editor-registry-spec.coffee b/spec/text-editor-registry-spec.coffee new file mode 100644 index 000000000..04665bef2 --- /dev/null +++ b/spec/text-editor-registry-spec.coffee @@ -0,0 +1,38 @@ +TextEditorRegistry = require '../src/text-editor-registry' + +describe "TextEditorRegistry", -> + [registry, editor] = [] + + beforeEach -> + registry = new TextEditorRegistry + + describe "when a TextEditor is added", -> + it "gets added to the list of registered editors", -> + editor = {} + registry.add(editor) + expect(registry.editors.size).toBe 1 + expect(registry.editors.has(editor)).toBe(true) + + it "returns a Disposable that can unregister the editor", -> + editor = {} + disposable = registry.add(editor) + expect(registry.editors.size).toBe 1 + disposable.dispose() + expect(registry.editors.size).toBe 0 + + describe "when the registry is observed", -> + it "calls the callback for current and future editors until unsubscribed", -> + [editor1, editor2, editor3] = [{}, {}, {}] + + registry.add(editor1) + subscription = registry.observe spy = jasmine.createSpy() + expect(spy.calls.length).toBe 1 + + registry.add(editor2) + expect(spy.calls.length).toBe 2 + expect(spy.argsForCall[0][0]).toBe editor1 + expect(spy.argsForCall[1][0]).toBe editor2 + + subscription.dispose() + registry.add(editor3) + expect(spy.calls.length).toBe 2 diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index c42bf05aa..0ee12fe93 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -40,6 +40,7 @@ Project = require './project' TextEditor = require './text-editor' TextBuffer = require 'text-buffer' Gutter = require './gutter' +TextEditorRegistry = require './text-editor-registry' WorkspaceElement = require './workspace-element' PanelContainerElement = require './panel-container-element' @@ -111,6 +112,9 @@ class AtomEnvironment extends Model # Public: A {Workspace} instance workspace: null + # Public: A {TextEditorRegistry} instance + textEditors: null + saveStateDebounceInterval: 1000 ### @@ -183,6 +187,8 @@ class AtomEnvironment extends Model }) @themes.workspace = @workspace + @textEditors = new TextEditorRegistry + @config.load() @themes.loadBaseStylesheets() diff --git a/src/text-editor-registry.coffee b/src/text-editor-registry.coffee new file mode 100644 index 000000000..fc95f9cd7 --- /dev/null +++ b/src/text-editor-registry.coffee @@ -0,0 +1,33 @@ +{Emitter, Disposable} = require 'event-kit' + +# This global registry tracks registered `TextEditors`. +# +# Packages that provide extra functionality to `TextEditors`, such as +# autocompletion, can observe this registry to find applicable editors. +module.exports = +class TextEditorRegistry + constructor: -> + @editors = new Set + @emitter = new Emitter + + # Register a `TextEditor`. + # + # * `editor` The editor to register. + # + # Returns a {Disposable} on which `.dispose()` can be called to remove the + # added editor. To avoid any memory leaks this should be called when the + # editor is destroyed. + add: (editor) -> + @editors.add(editor) + @emitter.emit 'did-add-editor', editor + new Disposable => @editors.delete(editor) + + # Invoke the given callback with all the current and future registered + # `TextEditors`. + # + # * `callback` {Function} to be called with current and future text editors. + # + # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. + observe: (callback) -> + @editors.forEach (editor) -> callback(editor) + @emitter.on 'did-add-editor', callback diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 5d55e0e48..d7fae17b3 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -82,7 +82,10 @@ class TextEditor extends Model state.project = atomEnvironment.project state.assert = atomEnvironment.assert.bind(atomEnvironment) state.applicationDelegate = atomEnvironment.applicationDelegate - new this(state) + editor = new this(state) + disposable = atomEnvironment.textEditors.add(editor) + editor.onDidDestroy -> disposable.dispose() + editor constructor: (params={}) -> super diff --git a/src/workspace.coffee b/src/workspace.coffee index 636ebfd69..c925a495a 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -558,7 +558,10 @@ class Workspace extends Model @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, @project, @assert, @applicationDelegate }, params) - new TextEditor(params) + editor = new TextEditor(params) + disposable = atom.textEditors.add(editor) + editor.onDidDestroy -> disposable.dispose() + editor # Public: Asynchronously reopens the last-closed item's URI if it hasn't already been # reopened. From 8959e414a63aea30f9fc3f7b776a4444caf93212 Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Mon, 29 Feb 2016 15:54:47 -0800 Subject: [PATCH 035/273] :arrow_up: tabs Signed-off-by: Katrina Uychaco --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 42cf22f8b..e6e63d31b 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "status-bar": "1.1.0", "styleguide": "0.45.2", "symbols-view": "0.111.1", - "tabs": "0.91.0", + "tabs": "0.91.1", "timecop": "0.33.1", "tree-view": "0.201.5", "update-package-dependencies": "0.10.0", From 98516150788b9b5022019179ce0bf1b5c8db3448 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Mon, 29 Feb 2016 16:24:22 -0800 Subject: [PATCH 036/273] :arrow_up: find-and-replace Signed-off-by: Michelle Tilley --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e6e63d31b..9ba72dc83 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "dev-live-reload": "0.47.0", "encoding-selector": "0.21.0", "exception-reporting": "0.37.0", - "find-and-replace": "0.197.2", + "find-and-replace": "0.197.3", "fuzzy-finder": "1.0.2", "git-diff": "1.0.0", "go-to-line": "0.30.0", From 6292484c971827c2137b3ce2fc02e33979cd664a Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 29 Feb 2016 17:30:03 -0700 Subject: [PATCH 037/273] Always strip git+ prefix and .git suffix from package repository URLs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, a guard based on the presence of the _id field (which is inserted by npm during installation) prevented a regex replacement of the git+ prefix on URLs. Now we always do this. Since the .git suffix also causes problems and we’re removing that in packages, I now remove that as well. --- .../package.json | 8 ++++++++ spec/package-manager-spec.coffee | 7 ++++++- src/package-manager.coffee | 5 +++-- 3 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 spec/fixtures/packages/package-with-prefixed-and-suffixed-repo-url/package.json diff --git a/spec/fixtures/packages/package-with-prefixed-and-suffixed-repo-url/package.json b/spec/fixtures/packages/package-with-prefixed-and-suffixed-repo-url/package.json new file mode 100644 index 000000000..ce57f7501 --- /dev/null +++ b/spec/fixtures/packages/package-with-prefixed-and-suffixed-repo-url/package.json @@ -0,0 +1,8 @@ +{ + "name": "package-with-a-git-prefixed-git-repo-url", + "repository": { + "type": "git", + "url": "git+https://github.com/example/repo.git" + }, + "_id": "this is here to simulate the URL being already normalized by npm. we still need to stript git+ from the beginning and .git from the end." +} diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 0a2d614b3..3b54691b2 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -55,12 +55,17 @@ describe "PackageManager", -> it "normalizes short repository urls in package.json", -> {metadata} = atom.packages.loadPackage("package-with-short-url-package-json") expect(metadata.repository.type).toBe "git" - expect(metadata.repository.url).toBe "https://github.com/example/repo.git" + expect(metadata.repository.url).toBe "https://github.com/example/repo" {metadata} = atom.packages.loadPackage("package-with-invalid-url-package-json") expect(metadata.repository.type).toBe "git" expect(metadata.repository.url).toBe "foo" + it "trims git+ from the beginning and .git from the end of repository URLs, even if npm already normalized them ", -> + {metadata} = atom.packages.loadPackage("package-with-prefixed-and-suffixed-repo-url") + expect(metadata.repository.type).toBe "git" + expect(metadata.repository.url).toBe "https://github.com/example/repo" + it "returns null if the package is not found in any package directory", -> spyOn(console, 'warn') expect(atom.packages.loadPackage("this-package-cannot-be-found")).toBeNull() diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 33f8f86a3..94b55a793 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -541,11 +541,12 @@ class PackageManager unless typeof metadata.name is 'string' and metadata.name.length > 0 metadata.name = packageName + if metadata.repository?.type is 'git' and typeof metadata.repository.url is 'string' + metadata.repository.url = metadata.repository.url.replace(/(^git\+)|(\.git$)/g, '') + metadata normalizePackageMetadata: (metadata) -> unless metadata?._id normalizePackageData ?= require 'normalize-package-data' normalizePackageData(metadata) - if metadata.repository?.type is 'git' and typeof metadata.repository.url is 'string' - metadata.repository.url = metadata.repository.url.replace(/^git\+/, '') From b95fd26cce2ced1a5b4d28f92bde8fd3a1a28f88 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 29 Feb 2016 17:38:47 -0700 Subject: [PATCH 038/273] Adjust TextEditorRegistry docs /cc @wvanlint --- src/text-editor-registry.coffee | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/text-editor-registry.coffee b/src/text-editor-registry.coffee index fc95f9cd7..943a0d31a 100644 --- a/src/text-editor-registry.coffee +++ b/src/text-editor-registry.coffee @@ -1,9 +1,16 @@ {Emitter, Disposable} = require 'event-kit' -# This global registry tracks registered `TextEditors`. +# Experimental: This global registry tracks registered `TextEditors`. # -# Packages that provide extra functionality to `TextEditors`, such as -# autocompletion, can observe this registry to find applicable editors. +# If you want to add functionality to a wider set of text editors than just +# those appearing within workspace panes, use `atom.textEditors.observe` to +# invoke a callback for all current and future registered text editors. +# +# If you want packages to be able to add functionality to your non-pane text +# editors (such as a search field in a custom user interface element), register +# them for observation via `atom.textEditors.add`. **Important:** When you're +# done using your editor, be sure to call `dispose` on the returned disposable +# to avoid leaking editors. module.exports = class TextEditorRegistry constructor: -> From 7600c4bdf47cd17e0e54e8d620ed33ed89f21bd4 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 29 Feb 2016 17:39:11 -0700 Subject: [PATCH 039/273] Avoid wrapper closure by passing callback to forEach directly /cc @wvanlint --- src/text-editor-registry.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text-editor-registry.coffee b/src/text-editor-registry.coffee index 943a0d31a..8a17335d4 100644 --- a/src/text-editor-registry.coffee +++ b/src/text-editor-registry.coffee @@ -36,5 +36,5 @@ class TextEditorRegistry # # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. observe: (callback) -> - @editors.forEach (editor) -> callback(editor) + @editors.forEach(callback) @emitter.on 'did-add-editor', callback From b7f0f794f850aff4e1e32a18ff977002a3b365db Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Mon, 29 Feb 2016 12:57:03 -0800 Subject: [PATCH 040/273] Don't destroy pane if replacing last pending item Signed-off-by: Michelle Tilley --- spec/workspace-spec.coffee | 28 ++++++++++++++++++++++++++++ src/pane.coffee | 8 ++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 2e15431b2..b39a07a6c 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -623,6 +623,34 @@ describe "Workspace", -> expect(pane.getItems().length).toBe 2 expect(pane.getItems()).toEqual [editor1, editor2] + describe "when replacing a pending item which is the last item in a second pane", -> + it "does not destory the pane even if core.destroyEmptyPanes is on", -> + atom.config.set('core.destroyEmptyPanes', true) + editor1 = null + editor2 = null + leftPane = atom.workspace.getActivePane() + rightPane = null + + waitsForPromise -> + atom.workspace.open('sample.js', pending: true, split: 'right').then (o) -> + editor1 = o + rightPane = atom.workspace.getActivePane() + spyOn rightPane, "destroyed" + + runs -> + expect(leftPane).not.toBe rightPane + expect(atom.workspace.getActivePane()).toBe rightPane + expect(atom.workspace.getActivePane().getItems().length).toBe 1 + expect(rightPane.getPendingItem()).toBe editor1 + + waitsForPromise -> + atom.workspace.open('sample.txt', pending: true).then (o) -> + editor2 = o + + runs -> + expect(rightPane.getPendingItem()).toBe editor2 + expect(rightPane.destroyed.callCount).toBe 0 + describe "::reopenItem()", -> it "opens the uri associated with the last closed pane that isn't currently open", -> pane = workspace.getActivePane() diff --git a/src/pane.coffee b/src/pane.coffee index 25f421934..b944f763c 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -423,10 +423,6 @@ class Pane extends Model return if item in @items - pendingItem = @getPendingItem() - @destroyItem(pendingItem) if pendingItem? - @setPendingItem(item) if pending - if typeof item.onDidDestroy is 'function' itemSubscriptions = new CompositeDisposable itemSubscriptions.add item.onDidDestroy => @removeItem(item, false) @@ -437,6 +433,10 @@ class Pane extends Model @subscriptionsPerItem.set item, itemSubscriptions @items.splice(index, 0, item) + pendingItem = @getPendingItem() + @destroyItem(pendingItem) if pendingItem? + @setPendingItem(item) if pending + @emitter.emit 'did-add-item', {item, index, moved} @setActiveItem(item) unless @getActiveItem()? item From a55ad00ac1cf3995447cfed0c7ad12269fcfe7ee Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 29 Feb 2016 18:51:12 -0700 Subject: [PATCH 041/273] Fix option pass-through in Selection:: and Cursor::autoscroll --- src/selection.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/selection.coffee b/src/selection.coffee index c4046677b..e208ea55a 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -810,11 +810,11 @@ class Selection extends Model @wordwise = false @linewise = false - autoscroll: -> + autoscroll: (options) -> if @marker.hasTail() - @editor.scrollToScreenRange(@getScreenRange(), reversed: @isReversed()) + @editor.scrollToScreenRange(@getScreenRange(), Object.assign({reversed: @isReversed()}, options)) else - @cursor.autoscroll() + @cursor.autoscroll(options) clearAutoscroll: -> From 7f744681c3c792e0bb01beca71ad5eedc3fddcb7 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 29 Feb 2016 18:51:36 -0700 Subject: [PATCH 042/273] Simplify consolidateSelections spec to test autoscroll with events --- spec/text-editor-spec.coffee | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 74875a7f5..1c0d3ad02 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -2141,32 +2141,21 @@ describe "TextEditor", -> expect(editor.getSelections()).toEqual [selection, selection2, selection3, selection4] [selection, selection2, selection3, selection4] - it "destroys all selections but the least recent, returning true if any selections were destroyed", -> + it "destroys all selections but the oldest selection and autoscrolls to it, returning true if any selections were destroyed", -> [selection1] = makeMultipleSelections() + autoscrollEvents = [] + editor.onDidRequestAutoscroll (event) -> autoscrollEvents.push(event) + expect(editor.consolidateSelections()).toBeTruthy() expect(editor.getSelections()).toEqual [selection1] expect(selection1.isEmpty()).toBeFalsy() expect(editor.consolidateSelections()).toBeFalsy() expect(editor.getSelections()).toEqual [selection1] - it "scrolls to the remaining selection", -> - [selection1] = makeMultipleSelections() - - atom.config.set('editor.scrollPastEnd', true) - editor.setHeight(100, true) - editor.setLineHeightInPixels(10) - editor.setFirstVisibleScreenRow(10) - expect(editor.getVisibleRowRange()[0]).toBeGreaterThan(selection1.getBufferRowRange()[1]) - - editor.consolidateSelections() - - waitsForPromise -> - new Promise((resolve) -> window.requestAnimationFrame(resolve)) - - runs -> - expect(editor.getVisibleRowRange()[0]).not.toBeGreaterThan(selection1.getBufferRowRange()[0]) - expect(editor.getVisibleRowRange()[1]).not.toBeLessThan(selection1.getBufferRowRange()[0]) + expect(autoscrollEvents).toEqual([ + {screenRange: selection1.getScreenRange(), options: {center: true, reversed: false}} + ]) describe "when the cursor is moved while there is a selection", -> makeSelection = -> selection.setBufferRange [[1, 2], [1, 5]] From 4e409ef44ae2d406e9e7449014aa3a8d7fc84f9e Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 29 Feb 2016 19:43:59 -0700 Subject: [PATCH 043/273] :arrow_up: image-view --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9ba72dc83..da7c700e5 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "git-diff": "1.0.0", "go-to-line": "0.30.0", "grammar-selector": "0.48.1", - "image-view": "0.56.0", + "image-view": "0.57.0", "incompatible-packages": "0.25.1", "keybinding-resolver": "0.35.0", "line-ending-selector": "0.3.1", From fdac1e466369c11fb72a331b645da50b9975b52b Mon Sep 17 00:00:00 2001 From: Koki Takahashi Date: Thu, 8 Jan 2015 02:07:44 +0900 Subject: [PATCH 044/273] :bug: Treat empty comment line as comment and add tests (Fix #4140) --- spec/fixtures/sample-with-comments.js | 13 +++++++- spec/language-mode-spec.coffee | 45 ++++++++++++++++++++++++--- src/language-mode.coffee | 2 -- src/tokenized-line.coffee | 1 - 4 files changed, 53 insertions(+), 8 deletions(-) diff --git a/spec/fixtures/sample-with-comments.js b/spec/fixtures/sample-with-comments.js index c10d42232..b40ddc890 100644 --- a/spec/fixtures/sample-with-comments.js +++ b/spec/fixtures/sample-with-comments.js @@ -9,12 +9,23 @@ var quicksort = function () { // Wowza if (items.length <= 1) return items; var pivot = items.shift(), current, left = [], right = []; + /* + This is a multiline comment block with + an empty line inside of it. + + Awesome. + */ while(items.length > 0) { current = items.shift(); current < pivot ? left.push(current) : right.push(current); } + // This is a collection of + // single line comments + + // ...with an empty line + // among it, geez! return sort(left).concat(pivot).concat(sort(right)); }; // this is a single-line comment return sort(Array.apply(this, arguments)); -}; \ No newline at end of file +}; diff --git a/spec/language-mode-spec.coffee b/spec/language-mode-spec.coffee index cd32e29c7..d4d97d2de 100644 --- a/spec/language-mode-spec.coffee +++ b/spec/language-mode-spec.coffee @@ -1,4 +1,4 @@ -describe "LanguageMode", -> +fdescribe "LanguageMode", -> [editor, buffer, languageMode] = [] afterEach -> @@ -430,7 +430,7 @@ describe "LanguageMode", -> languageMode.foldAll() fold1 = editor.tokenizedLineForScreenRow(0).fold - expect([fold1.getStartRow(), fold1.getEndRow()]).toEqual [0, 19] + expect([fold1.getStartRow(), fold1.getEndRow()]).toEqual [0, 30] fold1.destroy() fold2 = editor.tokenizedLineForScreenRow(1).fold @@ -441,6 +441,14 @@ describe "LanguageMode", -> fold4 = editor.tokenizedLineForScreenRow(3).fold expect([fold4.getStartRow(), fold4.getEndRow()]).toEqual [6, 8] + fold5 = editor.tokenizedLineForScreenRow(6).fold + expect([fold5.getStartRow(), fold5.getEndRow()]).toEqual [11, 16] + fold5.destroy(); + + fold6 = editor.tokenizedLineForScreenRow(13).fold + expect([fold6.getStartRow(), fold6.getEndRow()]).toEqual [21, 22] + fold6.destroy(); + describe ".foldAllAtIndentLevel()", -> it "folds every foldable range at a given indentLevel", -> languageMode.foldAllAtIndentLevel(2) @@ -450,19 +458,48 @@ describe "LanguageMode", -> fold1.destroy() fold2 = editor.tokenizedLineForScreenRow(11).fold - expect([fold2.getStartRow(), fold2.getEndRow()]).toEqual [11, 14] + expect([fold2.getStartRow(), fold2.getEndRow()]).toEqual [11, 16] fold2.destroy() + fold3 = editor.tokenizedLineForScreenRow(17).fold + expect([fold3.getStartRow(), fold3.getEndRow()]).toEqual [17, 20] + fold3.destroy() + + fold4 = editor.tokenizedLineForScreenRow(21).fold + expect([fold4.getStartRow(), fold4.getEndRow()]).toEqual [21, 22] + fold4.destroy() + + fold5 = editor.tokenizedLineForScreenRow(24).fold + expect([fold5.getStartRow(), fold5.getEndRow()]).toEqual [24, 25] + fold5.destroy() + it "does not fold anything but the indentLevel", -> languageMode.foldAllAtIndentLevel(0) fold1 = editor.tokenizedLineForScreenRow(0).fold - expect([fold1.getStartRow(), fold1.getEndRow()]).toEqual [0, 19] + expect([fold1.getStartRow(), fold1.getEndRow()]).toEqual [0, 30] fold1.destroy() fold2 = editor.tokenizedLineForScreenRow(5).fold expect(fold2).toBeFalsy() + describe ".isFoldableAtBufferRow(bufferRow)", -> + it "returns true if the line starts a multi-line comment", -> + expect(languageMode.isFoldableAtBufferRow(1)).toBe true + expect(languageMode.isFoldableAtBufferRow(6)).toBe true + expect(languageMode.isFoldableAtBufferRow(8)).toBe false + expect(languageMode.isFoldableAtBufferRow(11)).toBe true + expect(languageMode.isFoldableAtBufferRow(15)).toBe false + expect(languageMode.isFoldableAtBufferRow(17)).toBe true + expect(languageMode.isFoldableAtBufferRow(21)).toBe true + expect(languageMode.isFoldableAtBufferRow(24)).toBe true + expect(languageMode.isFoldableAtBufferRow(28)).toBe false + + it "does not return true for a line in the middle of a comment that's followed by an indented line", -> + expect(languageMode.isFoldableAtBufferRow(7)).toBe false + editor.buffer.insert([8, 0], ' ') + expect(languageMode.isFoldableAtBufferRow(7)).toBe false + describe "css", -> beforeEach -> waitsForPromise -> diff --git a/src/language-mode.coffee b/src/language-mode.coffee index dc5003cac..4824431bf 100644 --- a/src/language-mode.coffee +++ b/src/language-mode.coffee @@ -147,13 +147,11 @@ class LanguageMode if bufferRow > 0 for currentRow in [bufferRow-1..0] by -1 - break if @buffer.isRowBlank(currentRow) break unless @editor.displayBuffer.tokenizedBuffer.tokenizedLineForRow(currentRow).isComment() startRow = currentRow if bufferRow < @buffer.getLastRow() for currentRow in [bufferRow+1..@buffer.getLastRow()] by 1 - break if @buffer.isRowBlank(currentRow) break unless @editor.displayBuffer.tokenizedBuffer.tokenizedLineForRow(currentRow).isComment() endRow = currentRow diff --git a/src/tokenized-line.coffee b/src/tokenized-line.coffee index bf6a6dd2b..c1ac4caff 100644 --- a/src/tokenized-line.coffee +++ b/src/tokenized-line.coffee @@ -498,7 +498,6 @@ class TokenizedLine while iterator.next() scopes = iterator.getScopes() continue if scopes.length is 1 - continue unless NonWhitespaceRegex.test(iterator.getText()) for scope in scopes if CommentScopeRegex.test(scope) @isCommentLine = true From 6d00d5e9798e0f1e08cf2af04036f1455e15923c Mon Sep 17 00:00:00 2001 From: Koki Takahashi Date: Thu, 8 Jan 2015 02:18:23 +0900 Subject: [PATCH 045/273] Revert focus on language-mode-spec.coffee --- spec/language-mode-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/language-mode-spec.coffee b/spec/language-mode-spec.coffee index d4d97d2de..6ae21a8e6 100644 --- a/spec/language-mode-spec.coffee +++ b/spec/language-mode-spec.coffee @@ -1,4 +1,4 @@ -fdescribe "LanguageMode", -> +describe "LanguageMode", -> [editor, buffer, languageMode] = [] afterEach -> From a59ee5dec89fadbd469bbdd0595293564fd16751 Mon Sep 17 00:00:00 2001 From: Koki Takahashi Date: Wed, 3 Jun 2015 02:12:40 +0900 Subject: [PATCH 046/273] Remove trailing semicolon --- spec/language-mode-spec.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/language-mode-spec.coffee b/spec/language-mode-spec.coffee index 6ae21a8e6..26bb19b0e 100644 --- a/spec/language-mode-spec.coffee +++ b/spec/language-mode-spec.coffee @@ -443,11 +443,11 @@ describe "LanguageMode", -> fold5 = editor.tokenizedLineForScreenRow(6).fold expect([fold5.getStartRow(), fold5.getEndRow()]).toEqual [11, 16] - fold5.destroy(); + fold5.destroy() fold6 = editor.tokenizedLineForScreenRow(13).fold expect([fold6.getStartRow(), fold6.getEndRow()]).toEqual [21, 22] - fold6.destroy(); + fold6.destroy() describe ".foldAllAtIndentLevel()", -> it "folds every foldable range at a given indentLevel", -> From 3b135c5b7f4456319847d5af89806496bdfe1b38 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 1 Mar 2016 09:43:25 +0100 Subject: [PATCH 047/273] :arrow_up: autocomplete-plus --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index da7c700e5..1c55268dd 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "autocomplete-atom-api": "0.10.0", "autocomplete-css": "0.11.0", "autocomplete-html": "0.7.2", - "autocomplete-plus": "2.29.0", + "autocomplete-plus": "2.29.1", "autocomplete-snippets": "1.10.0", "autoflow": "0.27.0", "autosave": "0.23.1", From 4cd7cbda021b8673a6a93eb31e9e8c5e1106b74d Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 1 Mar 2016 10:53:31 -0500 Subject: [PATCH 048/273] Test ignoreScrollPastEnd. --- spec/text-editor-presenter-spec.coffee | 28 ++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 05ac87c0c..62d1e4747 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -635,16 +635,28 @@ describe "TextEditorPresenter", -> expectStateUpdate presenter, -> presenter.setExplicitHeight(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(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight + describe "scrollPastEnd", -> + 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(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight - expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) - expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) + expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) - expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight + expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight + + it "doesn't add the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true but ignoreScrollPastEnd is true", -> + presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10, ignoreScrollPastEnd: true) + expectStateUpdate presenter, -> presenter.setScrollTop(300) + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight + + expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight + + expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight describe ".scrollTop", -> it "tracks the value of ::scrollTop", -> From d929543aa2c9d8a0d2e8a771247059ebd90b5326 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 1 Mar 2016 10:56:03 -0500 Subject: [PATCH 049/273] Test for getElement. --- spec/view-registry-spec.coffee | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spec/view-registry-spec.coffee b/spec/view-registry-spec.coffee index 16672b25d..68a482b48 100644 --- a/spec/view-registry-spec.coffee +++ b/spec/view-registry-spec.coffee @@ -23,6 +23,15 @@ describe "ViewRegistry", -> component = new TestComponent expect(registry.getView(component)).toBe component.element + describe "when passed an object with a getElement function", -> + it "returns the return value of getElement if it's an instance of HTMLElement", -> + class TestComponent + getElement: -> + @myElement ?= document.createElement('div') + + component = new TestComponent + expect(registry.getView(component)).toBe component.myElement + describe "when passed a model object", -> describe "when a view provider is registered matching the object's constructor", -> it "constructs a view element and assigns the model on it", -> From e0d44aad5df4abd92082e3f99dc1ae66001a7a00 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 1 Mar 2016 11:07:55 -0500 Subject: [PATCH 050/273] Test getElement. --- spec/text-editor-spec.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 1c0d3ad02..ae8ec54a9 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5828,3 +5828,7 @@ describe "TextEditor", -> screenRange: marker1.getRange(), rangeIsReversed: false } + + describe "::getElement", -> + it "returns an element", -> + expect(editor.getElement() instanceof HTMLElement).toBe(true) From e1c5aad0a6972ce9950363770db6af30d56677c9 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 1 Mar 2016 11:43:38 -0500 Subject: [PATCH 051/273] Test ignoreInvisibles and grammarName. --- spec/text-editor-spec.coffee | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index ae8ec54a9..c75084fd5 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5829,6 +5829,29 @@ describe "TextEditor", -> rangeIsReversed: false } + describe "when the editor is constructed with the ignoreInvisibles option set to true", -> + beforeEach -> + atom.workspace.destroyActivePane() + waitsForPromise -> + atom.workspace.open('sample.js', ignoreInvisibles: true).then (o) -> editor = o + + it "ignores invisibles even if editor.showInvisibles is true", -> + atom.config.set('editor.showInvisibles', true) + invisibles = editor.tokenizedLineForScreenRow(0).invisibles + expect(invisibles).toBe(null) + + describe "when the editor is constructed with the grammarName option set", -> + beforeEach -> + atom.workspace.destroyActivePane() + waitsForPromise -> + atom.packages.activatePackage('language-coffee-script') + + waitsForPromise -> + atom.workspace.open('sample.js', grammarName: 'source.coffee').then (o) -> editor = o + + it "sets the grammar", -> + expect(editor.getGrammar().name).toBe 'CoffeeScript' + describe "::getElement", -> it "returns an element", -> expect(editor.getElement() instanceof HTMLElement).toBe(true) From da0ce2a7bde9003b0b432247a13e9d4673729f80 Mon Sep 17 00:00:00 2001 From: Thomas Johansen Date: Tue, 1 Mar 2016 18:54:11 +0100 Subject: [PATCH 052/273] :arrow_up: language-xml --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1c55268dd..7ff3df275 100644 --- a/package.json +++ b/package.json @@ -147,7 +147,7 @@ "language-text": "0.7.0", "language-todo": "0.27.0", "language-toml": "0.18.0", - "language-xml": "0.34.3", + "language-xml": "0.34.4", "language-yaml": "0.25.1" }, "private": true, From e1f7dd92238026f43bf7c4c98b29091c9e9b6260 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 1 Mar 2016 15:43:45 -0500 Subject: [PATCH 053/273] :arrow_up: nodegit@0.11.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8830a3f98..5df436fb5 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "less-cache": "0.23", "line-top-index": "0.2.0", "marked": "^0.3.4", - "nodegit": "0.11.5", + "nodegit": "0.11.6", "normalize-package-data": "^2.0.0", "nslog": "^3", "oniguruma": "^5", From 3716aaf00bc080ba91a2743c69fc4bbf72e23c83 Mon Sep 17 00:00:00 2001 From: Daniel Hengeveld Date: Tue, 2 Feb 2016 11:56:05 -0800 Subject: [PATCH 054/273] Spike out an update wrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can expose just a few event subscription methods on atom.update to take care of what most packages (e.g. About) would be interested in. Of course the updater runs on the main thread so we’re proxying them through IPC. It’s fine. --- src/application-delegate.coffee | 28 +++++++++++++ src/atom-environment.coffee | 3 ++ src/browser/auto-update-manager.coffee | 14 +++++++ src/update.js | 56 ++++++++++++++++++++++++++ 4 files changed, 101 insertions(+) create mode 100644 src/update.js diff --git a/src/application-delegate.coffee b/src/application-delegate.coffee index cc1f4c946..a4262965f 100644 --- a/src/application-delegate.coffee +++ b/src/application-delegate.coffee @@ -182,6 +182,34 @@ class ApplicationDelegate new Disposable -> ipcRenderer.removeListener('message', outerCallback) + onDidBeginCheckingForUpdate: (callback) -> + outerCallback = (message, detail) -> + if message is 'checking-for-update' + callback(detail) + + ipc.on('message', outerCallback) + new Disposable -> + ipc.removeListener('message', outerCallback) + + onDidCompleteDownloadingUpdate: (callback) -> + outerCallback = (message, detail) -> + if message is 'update-downloaded' + callback(detail) + + ipc.on('message', outerCallback) + new Disposable -> + ipc.removeListener('message', outerCallback) + + onUpdateNotAvailable: (callback) -> + outerCallback = (message, detail) -> + if message is 'update-not-available' + callback(detail) + + ipc.on('message', outerCallback) + new Disposable -> + ipc.removeListener('message', outerCallback) + + onApplicationMenuCommand: (callback) -> outerCallback = (event, args...) -> callback(args...) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 0ee12fe93..e6830ceaa 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -115,6 +115,9 @@ class AtomEnvironment extends Model # Public: A {TextEditorRegistry} instance textEditors: null + # Public: An {Update} instance + update: null + saveStateDebounceInterval: 1000 ### diff --git a/src/browser/auto-update-manager.coffee b/src/browser/auto-update-manager.coffee index 2df338761..c58d317cb 100644 --- a/src/browser/auto-update-manager.coffee +++ b/src/browser/auto-update-manager.coffee @@ -39,12 +39,19 @@ class AutoUpdateManager autoUpdater.on 'checking-for-update', => @setState(CheckingState) + @emitWindowEvent('checking-for-update') autoUpdater.on 'update-not-available', => @setState(NoUpdateAvailableState) autoUpdater.on 'update-available', => @setState(DownladingState) + # We use sendMessage to send an event called 'update-available' below + # once the update download is complete. This mismatch between the electron + # autoUpdater events is unfortunate but in the interest of not changing the + # one existing event handled by applicationDelegate + @emitWindowEvent('did-begin-downloading-update') + @emit('did-begin-download') autoUpdater.on 'update-downloaded', (event, releaseNotes, @releaseVersion) => @setState(UpdateAvailableState) @@ -66,10 +73,16 @@ class AutoUpdateManager emitUpdateAvailableEvent: (windows...) -> return unless @releaseVersion? + @emitWindowEvent('update-available', {@releaseVersion}) for atomWindow in windows atomWindow.sendMessage('update-available', {@releaseVersion}) return + emitWindowEvent: (eventName, windows, payload) -> + for atomWindow in windows + atomWindow.sendMessage(eventName, payload) + return + setState: (state) -> return if @state is state @state = state @@ -93,6 +106,7 @@ class AutoUpdateManager @checkForUpdatesIntervalID = null check: ({hidePopups}={}) -> + console.log 'checking for update' unless hidePopups autoUpdater.once 'update-not-available', @onUpdateNotAvailable autoUpdater.once 'error', @onUpdateError diff --git a/src/update.js b/src/update.js new file mode 100644 index 000000000..fcadbc21c --- /dev/null +++ b/src/update.js @@ -0,0 +1,56 @@ +'use babel' + +import {Emitter} from 'event-kit' + +export default class Update { + constructor () { + this.subscriptions = new CompositeDisposable() + this.emitter = new Emitter() + } + + initialize () { + atom.applicationDelegate.onDidBeginDownloadingUpdate(() => { + this.emitter.emit('did-begin-downloading-update') + }) + atom.applicationDelegate.onDidBeginCheckingForUpdate(() => { + this.emitter.emit('did-begin-checking-for-update') + }) + atom.applicationDelegate.onUpdateAvailable(() => { + this.emitter.emit('did-complete-downloading-update') + }) + } + + dispose () { + this.subscriptions.dispose() + } + + onDidBeginCheckingForUpdate (callback) { + this.subscriptions.add( + this.emitter.on('did-begin-checking-for-update', callback) + ) + } + + onDidBeginDownload (callback) { + this.subscriptions.add( + this.emitter.on('did-begin-downloading-update', callback) + ) + } + + onDidCompleteDownload (callback) { + this.subscriptions.add( + this.emitter.on('did-complete-downloading-update', callback) + ) + } + + onUpdateNotAvailable (callback) { + this.subscriptions.add() + } + + check () { + // TODO + } + + getState () { + // TODO + } +} From 1eaf30fae979ecda2b6cd6e5df99d31069e01f22 Mon Sep 17 00:00:00 2001 From: Daniel Hengeveld Date: Tue, 2 Feb 2016 22:34:11 -0800 Subject: [PATCH 055/273] Add a few more things before stepping aside to work on another issue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …maybe rebase this away… --- spec/update-spec.js | 37 ++++++++++++++++++++++++++ src/application-delegate.coffee | 4 +-- src/browser/auto-update-manager.coffee | 11 ++++---- src/update.js | 12 +++++++-- 4 files changed, 54 insertions(+), 10 deletions(-) create mode 100644 spec/update-spec.js diff --git a/spec/update-spec.js b/spec/update-spec.js new file mode 100644 index 000000000..9e12bab48 --- /dev/null +++ b/spec/update-spec.js @@ -0,0 +1,37 @@ +'use babel' + +import Update from '../src/update' +import remote from 'remote' + +fdescribe('Update', () => { + describe('::initialize', () => { + it('subscribes to appropriate applicationDelegate events', () => { + const update = new Update() + update.initialize() + + const downloadingSpy = jasmine.createSpy('downloadingSpy') + const checkingSpy = jasmine.createSpy('checkingSpy') + const noUpdateSpy = jasmine.createSpy('noUpdateSpy') + + update.onDidBeginCheckingForUpdate(checkingSpy) + update.onDidBeginDownload(downloadingSpy) + update.onUpdateNotAvailable(noUpdateSpy) + + const webContents = remote.getCurrentWebContents() + // AutoUpdateManager sends these from main process land + webContents.send('update-available', {releaseVersion: '1.2.3'}) + webContents.send('did-begin-downloading-update') + webContents.send('checking-for-update') + webContents.send('update-not-available') + + waitsFor(() => { + noUpdateSpy.callCount > 0 + }) + runs(() => { + expect(downloadingSpy.callCount).toBe(1) + expect(checkingSpy.callCount).toBe(1) + expect(noUpdateSpy.callCount).toBe(1) + }) + }) + }) +}) diff --git a/src/application-delegate.coffee b/src/application-delegate.coffee index a4262965f..8368e10ec 100644 --- a/src/application-delegate.coffee +++ b/src/application-delegate.coffee @@ -175,7 +175,7 @@ class ApplicationDelegate onUpdateAvailable: (callback) -> outerCallback = (event, message, detail) -> - if message is 'update-available' + if message is 'did-begin-downloading-update' callback(detail) ipcRenderer.on('message', outerCallback) @@ -193,7 +193,7 @@ class ApplicationDelegate onDidCompleteDownloadingUpdate: (callback) -> outerCallback = (message, detail) -> - if message is 'update-downloaded' + if message is 'update-available' callback(detail) ipc.on('message', outerCallback) diff --git a/src/browser/auto-update-manager.coffee b/src/browser/auto-update-manager.coffee index c58d317cb..064ccf27c 100644 --- a/src/browser/auto-update-manager.coffee +++ b/src/browser/auto-update-manager.coffee @@ -43,6 +43,7 @@ class AutoUpdateManager autoUpdater.on 'update-not-available', => @setState(NoUpdateAvailableState) + @emitWindowEvent('update-not-available') autoUpdater.on 'update-available', => @setState(DownladingState) @@ -55,7 +56,7 @@ class AutoUpdateManager autoUpdater.on 'update-downloaded', (event, releaseNotes, @releaseVersion) => @setState(UpdateAvailableState) - @emitUpdateAvailableEvent(@getWindows()...) + @emitUpdateAvailableEvent() @config.onDidChange 'core.automaticallyUpdate', ({newValue}) => if newValue @@ -71,15 +72,13 @@ class AutoUpdateManager when 'linux' @setState(UnsupportedState) - emitUpdateAvailableEvent: (windows...) -> + emitUpdateAvailableEvent: -> return unless @releaseVersion? @emitWindowEvent('update-available', {@releaseVersion}) - for atomWindow in windows - atomWindow.sendMessage('update-available', {@releaseVersion}) return - emitWindowEvent: (eventName, windows, payload) -> - for atomWindow in windows + emitWindowEvent: (eventName, payload) -> + for atomWindow in @getWindows() atomWindow.sendMessage(eventName, payload) return diff --git a/src/update.js b/src/update.js index fcadbc21c..4abffc0b0 100644 --- a/src/update.js +++ b/src/update.js @@ -1,6 +1,6 @@ 'use babel' -import {Emitter} from 'event-kit' +import {Emitter, CompositeDisposable} from 'event-kit' export default class Update { constructor () { @@ -42,8 +42,16 @@ export default class Update { ) } + onUpdateAvailable (callback) { + this.subscriptions.add( + this.emitter.on('update-available', callback) + ) + } + onUpdateNotAvailable (callback) { - this.subscriptions.add() + this.subscriptions.add( + this.emitter.on('update-not-available', callback) + ) } check () { From 6505c650089a9d63b0529000603fcf4e4a4d3473 Mon Sep 17 00:00:00 2001 From: Daniel Hengeveld Date: Wed, 3 Feb 2016 14:20:24 -0800 Subject: [PATCH 056/273] add out/ to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6eec21c2a..bce6c56d3 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ debug.log docs/output docs/includes spec/fixtures/evil-files/ +out/ From 44d78327458bf65b0be90c7ec4c9bccf5ee3a385 Mon Sep 17 00:00:00 2001 From: Daniel Hengeveld Date: Wed, 3 Feb 2016 14:20:56 -0800 Subject: [PATCH 057/273] add @update to AtomEnvironment --- src/atom-environment.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index e6830ceaa..31562a392 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -41,6 +41,7 @@ TextEditor = require './text-editor' TextBuffer = require 'text-buffer' Gutter = require './gutter' TextEditorRegistry = require './text-editor-registry' +Update = require './update' WorkspaceElement = require './workspace-element' PanelContainerElement = require './panel-container-element' @@ -191,6 +192,7 @@ class AtomEnvironment extends Model @themes.workspace = @workspace @textEditors = new TextEditorRegistry + @update = new Update() @config.load() From 6fce680a2890b698eea10a056f85dc63ae0e67a3 Mon Sep 17 00:00:00 2001 From: Daniel Hengeveld Date: Wed, 3 Feb 2016 14:21:46 -0800 Subject: [PATCH 058/273] Send check-for-update message over ipc --- src/browser/atom-application.coffee | 3 +++ src/browser/auto-update-manager.coffee | 3 ++- src/update.js | 7 ++----- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 40b04c3a1..ebcc9717b 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -304,6 +304,9 @@ class AtomApplication ipcMain.on 'execute-javascript-in-dev-tools', (event, code) -> event.sender.devToolsWebContents?.executeJavaScript(code) + ipcMain.on 'check-for-update', => + @autoUpdateManager.check() + setupDockMenu: -> if process.platform is 'darwin' dockMenu = Menu.buildFromTemplate [ diff --git a/src/browser/auto-update-manager.coffee b/src/browser/auto-update-manager.coffee index 064ccf27c..c17d9aead 100644 --- a/src/browser/auto-update-manager.coffee +++ b/src/browser/auto-update-manager.coffee @@ -3,6 +3,7 @@ _ = require 'underscore-plus' Config = require '../config' {EventEmitter} = require 'events' path = require 'path' +ipc = require 'ipc' IdleState = 'idle' CheckingState = 'checking' @@ -47,7 +48,7 @@ class AutoUpdateManager autoUpdater.on 'update-available', => @setState(DownladingState) - # We use sendMessage to send an event called 'update-available' below + # We use sendMessage to send an event called 'update-available' in 'update-downloaded' # once the update download is complete. This mismatch between the electron # autoUpdater events is unfortunate but in the interest of not changing the # one existing event handled by applicationDelegate diff --git a/src/update.js b/src/update.js index 4abffc0b0..452a3647f 100644 --- a/src/update.js +++ b/src/update.js @@ -1,6 +1,7 @@ 'use babel' import {Emitter, CompositeDisposable} from 'event-kit' +import ipc from 'ipc' export default class Update { constructor () { @@ -55,10 +56,6 @@ export default class Update { } check () { - // TODO - } - - getState () { - // TODO + ipc.send('check-for-update') } } From a8a5006950c61863ad784bbf8f0a01a98b9ea1d9 Mon Sep 17 00:00:00 2001 From: Daniel Hengeveld Date: Wed, 3 Feb 2016 14:21:56 -0800 Subject: [PATCH 059/273] Add missing subscription event --- src/application-delegate.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/application-delegate.coffee b/src/application-delegate.coffee index 8368e10ec..f70bd7d0c 100644 --- a/src/application-delegate.coffee +++ b/src/application-delegate.coffee @@ -182,6 +182,9 @@ class ApplicationDelegate new Disposable -> ipcRenderer.removeListener('message', outerCallback) + onDidBeginDownloadingUpdate: (callback) -> + @onUpdateAvailable(callback) + onDidBeginCheckingForUpdate: (callback) -> outerCallback = (message, detail) -> if message is 'checking-for-update' From bdb9866ff1a1b1fa9411e261a43357c15159e351 Mon Sep 17 00:00:00 2001 From: Daniel Hengeveld Date: Wed, 3 Feb 2016 17:15:05 -0800 Subject: [PATCH 060/273] remove errant log statement --- src/browser/auto-update-manager.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/browser/auto-update-manager.coffee b/src/browser/auto-update-manager.coffee index c17d9aead..2b6539bd8 100644 --- a/src/browser/auto-update-manager.coffee +++ b/src/browser/auto-update-manager.coffee @@ -106,7 +106,6 @@ class AutoUpdateManager @checkForUpdatesIntervalID = null check: ({hidePopups}={}) -> - console.log 'checking for update' unless hidePopups autoUpdater.once 'update-not-available', @onUpdateNotAvailable autoUpdater.once 'error', @onUpdateError From 6d77e97901e7b304a75afacd59fec05e75c0bb14 Mon Sep 17 00:00:00 2001 From: Daniel Hengeveld Date: Wed, 3 Feb 2016 17:32:54 -0800 Subject: [PATCH 061/273] The app delegate uses the `message` channel here. --- spec/update-spec.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/spec/update-spec.js b/spec/update-spec.js index 9e12bab48..8c8247538 100644 --- a/spec/update-spec.js +++ b/spec/update-spec.js @@ -18,11 +18,10 @@ fdescribe('Update', () => { update.onUpdateNotAvailable(noUpdateSpy) const webContents = remote.getCurrentWebContents() - // AutoUpdateManager sends these from main process land - webContents.send('update-available', {releaseVersion: '1.2.3'}) - webContents.send('did-begin-downloading-update') - webContents.send('checking-for-update') - webContents.send('update-not-available') + webContents.send('message', 'update-available', {releaseVersion: '1.2.3'}) + webContents.send('message', 'did-begin-downloading-update') + webContents.send('message', 'checking-for-update') + webContents.send('message', 'update-not-available') waitsFor(() => { noUpdateSpy.callCount > 0 From e6a86d38d1d9a841fb7d7fffedab344fe8c4e5d2 Mon Sep 17 00:00:00 2001 From: Daniel Hengeveld Date: Fri, 5 Feb 2016 12:11:18 -0800 Subject: [PATCH 062/273] this doesn't work --- spec/update-spec.js | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/update-spec.js b/spec/update-spec.js index 8c8247538..4d66da666 100644 --- a/spec/update-spec.js +++ b/spec/update-spec.js @@ -17,6 +17,7 @@ fdescribe('Update', () => { update.onDidBeginDownload(downloadingSpy) update.onUpdateNotAvailable(noUpdateSpy) + // This doesn't work const webContents = remote.getCurrentWebContents() webContents.send('message', 'update-available', {releaseVersion: '1.2.3'}) webContents.send('message', 'did-begin-downloading-update') From 004a0e870d83b3b067964890c280e1118844b5c2 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 18 Feb 2016 23:40:18 -0800 Subject: [PATCH 063/273] Add ApplicationDelegate listener disposables to subscriptions --- src/update.js | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/update.js b/src/update.js index 452a3647f..b4699fbec 100644 --- a/src/update.js +++ b/src/update.js @@ -10,15 +10,26 @@ export default class Update { } initialize () { - atom.applicationDelegate.onDidBeginDownloadingUpdate(() => { - this.emitter.emit('did-begin-downloading-update') - }) - atom.applicationDelegate.onDidBeginCheckingForUpdate(() => { - this.emitter.emit('did-begin-checking-for-update') - }) - atom.applicationDelegate.onUpdateAvailable(() => { - this.emitter.emit('did-complete-downloading-update') - }) + this.subscriptions.add( + atom.applicationDelegate.onDidBeginDownloadingUpdate(() => { + this.emitter.emit('did-begin-downloading-update') + }) + ) + this.subscriptions.add( + atom.applicationDelegate.onDidBeginCheckingForUpdate(() => { + this.emitter.emit('did-begin-checking-for-update') + }) + ) + this.subscriptions.add( + atom.applicationDelegate.onDidCompleteDownloadingUpdate(() => { + this.emitter.emit('did-complete-downloading-update') + }) + ) + this.subscriptions.add( + atom.applicationDelegate.onUpdateNotAvailable(() => { + this.emitter.emit('update-not-available') + }) + ) } dispose () { From adc086d4859ed63ef031bb25caa2ec19bdfe69a8 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 18 Feb 2016 23:41:23 -0800 Subject: [PATCH 064/273] Add specs for Update methods (::check left TODO) --- spec/update-spec.js | 102 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 93 insertions(+), 9 deletions(-) diff --git a/spec/update-spec.js b/spec/update-spec.js index 4d66da666..0f2f66289 100644 --- a/spec/update-spec.js +++ b/spec/update-spec.js @@ -2,36 +2,120 @@ import Update from '../src/update' import remote from 'remote' +import ipc from 'ipc' fdescribe('Update', () => { + let update + + afterEach(() => { + update.dispose() + }) + describe('::initialize', () => { it('subscribes to appropriate applicationDelegate events', () => { - const update = new Update() - update.initialize() + update = new Update() const downloadingSpy = jasmine.createSpy('downloadingSpy') const checkingSpy = jasmine.createSpy('checkingSpy') const noUpdateSpy = jasmine.createSpy('noUpdateSpy') + const completedDownloadSpy = jasmine.createSpy('completedDownloadSpy') - update.onDidBeginCheckingForUpdate(checkingSpy) - update.onDidBeginDownload(downloadingSpy) - update.onUpdateNotAvailable(noUpdateSpy) + update.emitter.on('did-begin-checking-for-update', checkingSpy) + update.emitter.on('did-begin-downloading-update', downloadingSpy) + update.emitter.on('did-complete-downloading-update', completedDownloadSpy) + update.emitter.on('update-not-available', noUpdateSpy) + + update.initialize() - // This doesn't work const webContents = remote.getCurrentWebContents() - webContents.send('message', 'update-available', {releaseVersion: '1.2.3'}) - webContents.send('message', 'did-begin-downloading-update') webContents.send('message', 'checking-for-update') + webContents.send('message', 'did-begin-downloading-update') + webContents.send('message', 'update-available', {releaseVersion: '1.2.3'}) webContents.send('message', 'update-not-available') waitsFor(() => { - noUpdateSpy.callCount > 0 + return noUpdateSpy.callCount > 0 }) + runs(() => { expect(downloadingSpy.callCount).toBe(1) expect(checkingSpy.callCount).toBe(1) expect(noUpdateSpy.callCount).toBe(1) + expect(completedDownloadSpy.callCount).toBe(1) }) }) }) + + beforeEach(() => { + update = new Update() + update.initialize() + }) + + describe('::onDidBeginCheckingForUpdate', () => { + it('subscribes to "did-begin-checking-for-update" event', () => { + const spy = jasmine.createSpy('spy') + update.onDidBeginCheckingForUpdate(spy) + update.emitter.emit('did-begin-checking-for-update') + expect(spy.callCount).toBe(1) + }) + }) + + describe('::onDidBeginDownload', () => { + it('subscribes to "did-begin-downloading-update" event', () => { + const spy = jasmine.createSpy('spy') + update.onDidBeginDownload(spy) + update.emitter.emit('did-begin-downloading-update') + expect(spy.callCount).toBe(1) + }) + }) + + describe('::onDidCompleteDownload', () => { + it('subscribes to "did-complete-downloading-update" event', () => { + const spy = jasmine.createSpy('spy') + update.onDidCompleteDownload(spy) + update.emitter.emit('did-complete-downloading-update') + expect(spy.callCount).toBe(1) + }) + }) + + describe('::onUpdateNotAvailable', () => { + it('subscribes to "update-not-available" event', () => { + const spy = jasmine.createSpy('spy') + update.onUpdateNotAvailable(spy) + update.emitter.emit('update-not-available') + expect(spy.callCount).toBe(1) + }) + }) + + describe('::onUpdateAvailable', () => { + it('subscribes to "update-available" event', () => { + const spy = jasmine.createSpy('spy') + update.onUpdateAvailable(spy) + update.emitter.emit('update-available') + expect(spy.callCount).toBe(1) + }) + }) + + // TODO: spec is timing out. spy is not called + // describe('::check', () => { + // it('sends "check-for-update" event', () => { + // const spy = jasmine.createSpy('spy') + // ipc.on('check-for-update', () => { + // spy() + // }) + // update.check() + // waitsFor(() => { + // return spy.callCount > 0 + // }) + // }) + // }) + + describe('::dispose', () => { + it('disposes of subscriptions', () => { + expect(update.subscriptions.disposables).not.toBeNull() + update.dispose() + expect(update.subscriptions.disposables).toBeNull() + }) + }) + }) From 3e29cd57626945827d6930bfea5d31760184fa8a Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 18 Feb 2016 23:50:27 -0800 Subject: [PATCH 065/273] Merge branch 'master' into dh-expose-updates --- src/application-delegate.coffee | 18 +++++++++--------- src/browser/atom-application.coffee | 3 +++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/application-delegate.coffee b/src/application-delegate.coffee index f70bd7d0c..2aaeb35ff 100644 --- a/src/application-delegate.coffee +++ b/src/application-delegate.coffee @@ -186,31 +186,31 @@ class ApplicationDelegate @onUpdateAvailable(callback) onDidBeginCheckingForUpdate: (callback) -> - outerCallback = (message, detail) -> + outerCallback = (event, message, detail) -> if message is 'checking-for-update' callback(detail) - ipc.on('message', outerCallback) + ipcRenderer.on('message', outerCallback) new Disposable -> - ipc.removeListener('message', outerCallback) + ipcRenderer.removeListener('message', outerCallback) onDidCompleteDownloadingUpdate: (callback) -> - outerCallback = (message, detail) -> + outerCallback = (event, message, detail) -> if message is 'update-available' callback(detail) - ipc.on('message', outerCallback) + ipcRenderer.on('message', outerCallback) new Disposable -> - ipc.removeListener('message', outerCallback) + ipcRenderer.removeListener('message', outerCallback) onUpdateNotAvailable: (callback) -> - outerCallback = (message, detail) -> + outerCallback = (event, message, detail) -> if message is 'update-not-available' callback(detail) - ipc.on('message', outerCallback) + ipcRenderer.on('message', outerCallback) new Disposable -> - ipc.removeListener('message', outerCallback) + ipcRenderer.removeListener('message', outerCallback) onApplicationMenuCommand: (callback) -> diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index ebcc9717b..fad69b967 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -307,6 +307,9 @@ class AtomApplication ipcMain.on 'check-for-update', => @autoUpdateManager.check() + ipcMain.on 'execute-javascript-in-dev-tools', (event, code) -> + event.sender.devToolsWebContents?.executeJavaScript(code) + setupDockMenu: -> if process.platform is 'darwin' dockMenu = Menu.buildFromTemplate [ From 5cda45b5c73b893e1352d099aa7e3f9e3ecb611d Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 19 Feb 2016 12:36:09 -0800 Subject: [PATCH 066/273] =?UTF-8?q?Use=20ipcRenderer=20from=20=E2=80=98ele?= =?UTF-8?q?ctron=E2=80=99=20rather=20than=20=E2=80=98pic=E2=80=99=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/update.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/update.js b/src/update.js index b4699fbec..5389c35e8 100644 --- a/src/update.js +++ b/src/update.js @@ -1,7 +1,7 @@ 'use babel' import {Emitter, CompositeDisposable} from 'event-kit' -import ipc from 'ipc' +import {ipcRenderer} from 'electron' export default class Update { constructor () { @@ -67,6 +67,6 @@ export default class Update { } check () { - ipc.send('check-for-update') + ipcRenderer.send('check-for-update') } } From 16ebefca3f2a7c4fa23ac0106009ca413c7541b3 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 19 Feb 2016 12:36:38 -0800 Subject: [PATCH 067/273] =?UTF-8?q?Remove=20unnecessary=20=E2=80=98ipc'=20?= =?UTF-8?q?module=20import?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/browser/auto-update-manager.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/browser/auto-update-manager.coffee b/src/browser/auto-update-manager.coffee index 2b6539bd8..c8c57cb01 100644 --- a/src/browser/auto-update-manager.coffee +++ b/src/browser/auto-update-manager.coffee @@ -3,7 +3,6 @@ _ = require 'underscore-plus' Config = require '../config' {EventEmitter} = require 'events' path = require 'path' -ipc = require 'ipc' IdleState = 'idle' CheckingState = 'checking' From 19d30c7dc955b557927571fbf60038fc446e4a6d Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 19 Feb 2016 12:40:51 -0800 Subject: [PATCH 068/273] Improve specs for `Update` class --- spec/update-spec.js | 104 ++++++++++---------------------------------- 1 file changed, 23 insertions(+), 81 deletions(-) diff --git a/spec/update-spec.js b/spec/update-spec.js index 0f2f66289..bd50113c2 100644 --- a/spec/update-spec.js +++ b/spec/update-spec.js @@ -1,62 +1,29 @@ 'use babel' import Update from '../src/update' -import remote from 'remote' -import ipc from 'ipc' +import {remote} from 'electron' +const electronAutoUpdater = remote.require('electron').autoUpdater -fdescribe('Update', () => { +describe('Update', () => { let update - afterEach(() => { - update.dispose() - }) - - describe('::initialize', () => { - it('subscribes to appropriate applicationDelegate events', () => { - update = new Update() - - const downloadingSpy = jasmine.createSpy('downloadingSpy') - const checkingSpy = jasmine.createSpy('checkingSpy') - const noUpdateSpy = jasmine.createSpy('noUpdateSpy') - const completedDownloadSpy = jasmine.createSpy('completedDownloadSpy') - - update.emitter.on('did-begin-checking-for-update', checkingSpy) - update.emitter.on('did-begin-downloading-update', downloadingSpy) - update.emitter.on('did-complete-downloading-update', completedDownloadSpy) - update.emitter.on('update-not-available', noUpdateSpy) - - update.initialize() - - const webContents = remote.getCurrentWebContents() - webContents.send('message', 'checking-for-update') - webContents.send('message', 'did-begin-downloading-update') - webContents.send('message', 'update-available', {releaseVersion: '1.2.3'}) - webContents.send('message', 'update-not-available') - - waitsFor(() => { - return noUpdateSpy.callCount > 0 - }) - - runs(() => { - expect(downloadingSpy.callCount).toBe(1) - expect(checkingSpy.callCount).toBe(1) - expect(noUpdateSpy.callCount).toBe(1) - expect(completedDownloadSpy.callCount).toBe(1) - }) - }) - }) - beforeEach(() => { update = new Update() update.initialize() }) + afterEach(() => { + update.dispose() + }) + describe('::onDidBeginCheckingForUpdate', () => { it('subscribes to "did-begin-checking-for-update" event', () => { const spy = jasmine.createSpy('spy') update.onDidBeginCheckingForUpdate(spy) - update.emitter.emit('did-begin-checking-for-update') - expect(spy.callCount).toBe(1) + electronAutoUpdater.emit('checking-for-update') + waitsFor(() => { + return spy.callCount === 1 + }) }) }) @@ -64,8 +31,10 @@ fdescribe('Update', () => { it('subscribes to "did-begin-downloading-update" event', () => { const spy = jasmine.createSpy('spy') update.onDidBeginDownload(spy) - update.emitter.emit('did-begin-downloading-update') - expect(spy.callCount).toBe(1) + electronAutoUpdater.emit('update-available') + waitsFor(() => { + return spy.callCount === 1 + }) }) }) @@ -73,8 +42,10 @@ fdescribe('Update', () => { it('subscribes to "did-complete-downloading-update" event', () => { const spy = jasmine.createSpy('spy') update.onDidCompleteDownload(spy) - update.emitter.emit('did-complete-downloading-update') - expect(spy.callCount).toBe(1) + electronAutoUpdater.emit('update-downloaded', null, null, {releaseVersion: '1.2.3'}) + waitsFor(() => { + return spy.callCount === 1 + }) }) }) @@ -82,39 +53,10 @@ fdescribe('Update', () => { it('subscribes to "update-not-available" event', () => { const spy = jasmine.createSpy('spy') update.onUpdateNotAvailable(spy) - update.emitter.emit('update-not-available') - expect(spy.callCount).toBe(1) - }) - }) - - describe('::onUpdateAvailable', () => { - it('subscribes to "update-available" event', () => { - const spy = jasmine.createSpy('spy') - update.onUpdateAvailable(spy) - update.emitter.emit('update-available') - expect(spy.callCount).toBe(1) - }) - }) - - // TODO: spec is timing out. spy is not called - // describe('::check', () => { - // it('sends "check-for-update" event', () => { - // const spy = jasmine.createSpy('spy') - // ipc.on('check-for-update', () => { - // spy() - // }) - // update.check() - // waitsFor(() => { - // return spy.callCount > 0 - // }) - // }) - // }) - - describe('::dispose', () => { - it('disposes of subscriptions', () => { - expect(update.subscriptions.disposables).not.toBeNull() - update.dispose() - expect(update.subscriptions.disposables).toBeNull() + electronAutoUpdater.emit('update-not-available') + waitsFor(() => { + return spy.callCount === 1 + }) }) }) From dd53c6f85644701cd0c6b61e7cfca5c69d098df0 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 19 Feb 2016 15:35:42 -0800 Subject: [PATCH 069/273] Use `onDidCompleteDownloadingUpdate` in `listenForUpdates` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This gets a bit confusing… It was formerly `@applicationDelegate.onUpdateAvailable`, but `::onUpdateAvailable` listens for the `did-begin-downloading-update` event and `::onDidCompleteDownloadingUpdate` listens for the `update-available` event. Note that ‘available’ here means successfully downloaded and ready to be used and NOT available to be downloaded. --- src/atom-environment.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 31562a392..b9527b947 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -891,7 +891,8 @@ class AtomEnvironment extends Model @emitter.emit 'update-available', details listenForUpdates: -> - @disposables.add(@applicationDelegate.onUpdateAvailable(@updateAvailable.bind(this))) + # listen for updates available locally (that have been successfully downloaded) + @disposables.add(@applicationDelegate.onDidCompleteDownloadingUpdate(@updateAvailable.bind(this))) setBodyPlatformClass: -> @document.body.classList.add("platform-#{process.platform}") From 342f72b6a14a8bd7280133e034ab8fc07e1b3257 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 23 Feb 2016 17:07:11 -0800 Subject: [PATCH 070/273] Rename `Update` `AutoUpdateManager` --- ...te-spec.js => auto-update-manager-spec.js} | 21 +++++++++---------- src/atom-environment.coffee | 8 +++---- src/{update.js => auto-update-manager.js} | 2 +- 3 files changed, 15 insertions(+), 16 deletions(-) rename spec/{update-spec.js => auto-update-manager-spec.js} (75%) rename src/{update.js => auto-update-manager.js} (97%) diff --git a/spec/update-spec.js b/spec/auto-update-manager-spec.js similarity index 75% rename from spec/update-spec.js rename to spec/auto-update-manager-spec.js index bd50113c2..b78830c33 100644 --- a/spec/update-spec.js +++ b/spec/auto-update-manager-spec.js @@ -1,25 +1,25 @@ 'use babel' -import Update from '../src/update' +import AutoUpdateManager from '../src/auto-update-manager' import {remote} from 'electron' const electronAutoUpdater = remote.require('electron').autoUpdater -describe('Update', () => { - let update +fdescribe('AutoUpdateManager (renderer)', () => { + let autoUpdateManager beforeEach(() => { - update = new Update() - update.initialize() + autoUpdateManager = new AutoUpdateManager() + autoUpdateManager.initialize() }) afterEach(() => { - update.dispose() + autoUpdateManager.dispose() }) describe('::onDidBeginCheckingForUpdate', () => { it('subscribes to "did-begin-checking-for-update" event', () => { const spy = jasmine.createSpy('spy') - update.onDidBeginCheckingForUpdate(spy) + autoUpdateManager.onDidBeginCheckingForUpdate(spy) electronAutoUpdater.emit('checking-for-update') waitsFor(() => { return spy.callCount === 1 @@ -30,7 +30,7 @@ describe('Update', () => { describe('::onDidBeginDownload', () => { it('subscribes to "did-begin-downloading-update" event', () => { const spy = jasmine.createSpy('spy') - update.onDidBeginDownload(spy) + autoUpdateManager.onDidBeginDownload(spy) electronAutoUpdater.emit('update-available') waitsFor(() => { return spy.callCount === 1 @@ -41,7 +41,7 @@ describe('Update', () => { describe('::onDidCompleteDownload', () => { it('subscribes to "did-complete-downloading-update" event', () => { const spy = jasmine.createSpy('spy') - update.onDidCompleteDownload(spy) + autoUpdateManager.onDidCompleteDownload(spy) electronAutoUpdater.emit('update-downloaded', null, null, {releaseVersion: '1.2.3'}) waitsFor(() => { return spy.callCount === 1 @@ -52,12 +52,11 @@ describe('Update', () => { describe('::onUpdateNotAvailable', () => { it('subscribes to "update-not-available" event', () => { const spy = jasmine.createSpy('spy') - update.onUpdateNotAvailable(spy) + autoUpdateManager.onUpdateNotAvailable(spy) electronAutoUpdater.emit('update-not-available') waitsFor(() => { return spy.callCount === 1 }) }) }) - }) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index b9527b947..4fead0da9 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -41,7 +41,7 @@ TextEditor = require './text-editor' TextBuffer = require 'text-buffer' Gutter = require './gutter' TextEditorRegistry = require './text-editor-registry' -Update = require './update' +AutoUpdateManager = require './auto-update-manager' WorkspaceElement = require './workspace-element' PanelContainerElement = require './panel-container-element' @@ -116,8 +116,8 @@ class AtomEnvironment extends Model # Public: A {TextEditorRegistry} instance textEditors: null - # Public: An {Update} instance - update: null + # Public: An {AutoUpdateManager} instance + autoUpdater: null saveStateDebounceInterval: 1000 @@ -192,7 +192,7 @@ class AtomEnvironment extends Model @themes.workspace = @workspace @textEditors = new TextEditorRegistry - @update = new Update() + @autoUpdater = new AutoUpdateManager @config.load() diff --git a/src/update.js b/src/auto-update-manager.js similarity index 97% rename from src/update.js rename to src/auto-update-manager.js index 5389c35e8..1f0f39f29 100644 --- a/src/update.js +++ b/src/auto-update-manager.js @@ -3,7 +3,7 @@ import {Emitter, CompositeDisposable} from 'event-kit' import {ipcRenderer} from 'electron' -export default class Update { +export default class AutoUpdateManager { constructor () { this.subscriptions = new CompositeDisposable() this.emitter = new Emitter() From e40c91d3538e512004e058b8c21bd53994a36a69 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 23 Feb 2016 17:08:59 -0800 Subject: [PATCH 071/273] All subscriptions can be in one call --- src/auto-update-manager.js | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index 1f0f39f29..006eadf9e 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -13,19 +13,13 @@ export default class AutoUpdateManager { this.subscriptions.add( atom.applicationDelegate.onDidBeginDownloadingUpdate(() => { this.emitter.emit('did-begin-downloading-update') - }) - ) - this.subscriptions.add( + }), atom.applicationDelegate.onDidBeginCheckingForUpdate(() => { this.emitter.emit('did-begin-checking-for-update') - }) - ) - this.subscriptions.add( + }), atom.applicationDelegate.onDidCompleteDownloadingUpdate(() => { this.emitter.emit('did-complete-downloading-update') - }) - ) - this.subscriptions.add( + }), atom.applicationDelegate.onUpdateNotAvailable(() => { this.emitter.emit('update-not-available') }) From ddff53bfc56b373c479c4c50c1f4dde6a04c80d7 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 23 Feb 2016 17:10:56 -0800 Subject: [PATCH 072/273] Postfix ifs --- src/application-delegate.coffee | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/application-delegate.coffee b/src/application-delegate.coffee index 2aaeb35ff..a853cd8ea 100644 --- a/src/application-delegate.coffee +++ b/src/application-delegate.coffee @@ -166,8 +166,7 @@ class ApplicationDelegate onDidOpenLocations: (callback) -> outerCallback = (event, message, detail) -> - if message is 'open-locations' - callback(detail) + callback(detail) if message is 'open-locations' ipcRenderer.on('message', outerCallback) new Disposable -> @@ -175,8 +174,7 @@ class ApplicationDelegate onUpdateAvailable: (callback) -> outerCallback = (event, message, detail) -> - if message is 'did-begin-downloading-update' - callback(detail) + callback(detail) if message is 'did-begin-downloading-update' ipcRenderer.on('message', outerCallback) new Disposable -> @@ -187,8 +185,7 @@ class ApplicationDelegate onDidBeginCheckingForUpdate: (callback) -> outerCallback = (event, message, detail) -> - if message is 'checking-for-update' - callback(detail) + callback(detail) if message is 'checking-for-update' ipcRenderer.on('message', outerCallback) new Disposable -> @@ -196,8 +193,7 @@ class ApplicationDelegate onDidCompleteDownloadingUpdate: (callback) -> outerCallback = (event, message, detail) -> - if message is 'update-available' - callback(detail) + callback(detail) if message is 'update-available' ipcRenderer.on('message', outerCallback) new Disposable -> @@ -205,14 +201,12 @@ class ApplicationDelegate onUpdateNotAvailable: (callback) -> outerCallback = (event, message, detail) -> - if message is 'update-not-available' - callback(detail) + callback(detail) if message is 'update-not-available' ipcRenderer.on('message', outerCallback) new Disposable -> ipcRenderer.removeListener('message', outerCallback) - onApplicationMenuCommand: (callback) -> outerCallback = (event, args...) -> callback(args...) From b481a06cbfb7628d31c3690e9429961da2867e9a Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 23 Feb 2016 17:14:05 -0800 Subject: [PATCH 073/273] Pass the app delegate into AutoUpdateManager --- spec/auto-update-manager-spec.js | 2 +- src/atom-environment.coffee | 1 + src/auto-update-manager.js | 10 +++++----- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/spec/auto-update-manager-spec.js b/spec/auto-update-manager-spec.js index b78830c33..93df903de 100644 --- a/spec/auto-update-manager-spec.js +++ b/spec/auto-update-manager-spec.js @@ -9,7 +9,7 @@ fdescribe('AutoUpdateManager (renderer)', () => { beforeEach(() => { autoUpdateManager = new AutoUpdateManager() - autoUpdateManager.initialize() + autoUpdateManager.initialize(atom.applicationDelegate) }) afterEach(() => { diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 4fead0da9..e492c7067 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -193,6 +193,7 @@ class AtomEnvironment extends Model @textEditors = new TextEditorRegistry @autoUpdater = new AutoUpdateManager + @autoUpdater.initialize(@applicationDelegate) @config.load() diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index 006eadf9e..c0f0b39bb 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -9,18 +9,18 @@ export default class AutoUpdateManager { this.emitter = new Emitter() } - initialize () { + initialize (updateEventEmitter) { this.subscriptions.add( - atom.applicationDelegate.onDidBeginDownloadingUpdate(() => { + updateEventEmitter.onDidBeginDownloadingUpdate(() => { this.emitter.emit('did-begin-downloading-update') }), - atom.applicationDelegate.onDidBeginCheckingForUpdate(() => { + updateEventEmitter.onDidBeginCheckingForUpdate(() => { this.emitter.emit('did-begin-checking-for-update') }), - atom.applicationDelegate.onDidCompleteDownloadingUpdate(() => { + updateEventEmitter.onDidCompleteDownloadingUpdate(() => { this.emitter.emit('did-complete-downloading-update') }), - atom.applicationDelegate.onUpdateNotAvailable(() => { + updateEventEmitter.onUpdateNotAvailable(() => { this.emitter.emit('update-not-available') }) ) From a876e85899cd2ebb4056d356ae5dc22866f561b8 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 23 Feb 2016 17:14:52 -0800 Subject: [PATCH 074/273] check -> checkForUpdate --- src/auto-update-manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index c0f0b39bb..05de08a3a 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -60,7 +60,7 @@ export default class AutoUpdateManager { ) } - check () { + checkForUpdate () { ipcRenderer.send('check-for-update') } } From eaba6943194153c55ad753e5e6137f8f64a254bd Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 23 Feb 2016 17:14:59 -0800 Subject: [PATCH 075/273] =?UTF-8?q?Let=E2=80=99s=20make=20this=20private?= =?UTF-8?q?=20for=20now?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/atom-environment.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index e492c7067..481e762ca 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -116,7 +116,7 @@ class AtomEnvironment extends Model # Public: A {TextEditorRegistry} instance textEditors: null - # Public: An {AutoUpdateManager} instance + # Private: An {AutoUpdateManager} instance autoUpdater: null saveStateDebounceInterval: 1000 From 3a5c8271629f6ebd9d4b03779f3b019d1bad5bc9 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 23 Feb 2016 17:23:11 -0800 Subject: [PATCH 076/273] Add dispose spec --- spec/auto-update-manager-spec.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/spec/auto-update-manager-spec.js b/spec/auto-update-manager-spec.js index 93df903de..6aa791373 100644 --- a/spec/auto-update-manager-spec.js +++ b/spec/auto-update-manager-spec.js @@ -59,4 +59,29 @@ fdescribe('AutoUpdateManager (renderer)', () => { }) }) }) + + describe('::dispose', () => { + it('subscribes to "update-not-available" event', () => { + const spy = jasmine.createSpy('spy') + const doneIndicator = jasmine.createSpy('spy') + atom.applicationDelegate.onUpdateNotAvailable(doneIndicator) + autoUpdateManager.dispose() + autoUpdateManager.onDidBeginCheckingForUpdate(spy) + autoUpdateManager.onDidBeginDownload(spy) + autoUpdateManager.onDidCompleteDownload(spy) + autoUpdateManager.onUpdateNotAvailable(spy) + electronAutoUpdater.emit('checking-for-update') + electronAutoUpdater.emit('update-available') + electronAutoUpdater.emit('update-downloaded', null, null, {releaseVersion: '1.2.3'}) + electronAutoUpdater.emit('update-not-available') + + waitsFor(() => { + return doneIndicator.callCount === 1 + }) + + runs(() => { + expect(spy.callCount).toBe(0) + }) + }) + }) }) From c9293e7733502c0551438a41633031c902ab43c6 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 23 Feb 2016 17:34:31 -0800 Subject: [PATCH 077/273] Pass the version info through the event --- spec/auto-update-manager-spec.js | 7 +++++-- src/auto-update-manager.js | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/spec/auto-update-manager-spec.js b/spec/auto-update-manager-spec.js index 6aa791373..e23c1911d 100644 --- a/spec/auto-update-manager-spec.js +++ b/spec/auto-update-manager-spec.js @@ -42,10 +42,13 @@ fdescribe('AutoUpdateManager (renderer)', () => { it('subscribes to "did-complete-downloading-update" event', () => { const spy = jasmine.createSpy('spy') autoUpdateManager.onDidCompleteDownload(spy) - electronAutoUpdater.emit('update-downloaded', null, null, {releaseVersion: '1.2.3'}) + electronAutoUpdater.emit('update-downloaded', null, null, '1.2.3') waitsFor(() => { return spy.callCount === 1 }) + runs(() => { + expect(spy.mostRecentCall.args[0].releaseVersion).toBe('1.2.3') + }) }) }) @@ -72,7 +75,7 @@ fdescribe('AutoUpdateManager (renderer)', () => { autoUpdateManager.onUpdateNotAvailable(spy) electronAutoUpdater.emit('checking-for-update') electronAutoUpdater.emit('update-available') - electronAutoUpdater.emit('update-downloaded', null, null, {releaseVersion: '1.2.3'}) + electronAutoUpdater.emit('update-downloaded', null, null, '1.2.3') electronAutoUpdater.emit('update-not-available') waitsFor(() => { diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index 05de08a3a..f46197f8d 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -17,8 +17,8 @@ export default class AutoUpdateManager { updateEventEmitter.onDidBeginCheckingForUpdate(() => { this.emitter.emit('did-begin-checking-for-update') }), - updateEventEmitter.onDidCompleteDownloadingUpdate(() => { - this.emitter.emit('did-complete-downloading-update') + updateEventEmitter.onDidCompleteDownloadingUpdate((details) => { + this.emitter.emit('did-complete-downloading-update', details) }), updateEventEmitter.onUpdateNotAvailable(() => { this.emitter.emit('update-not-available') From fa0f6f35258b5cbb9fb347c2858ee0ab258d1df5 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 23 Feb 2016 17:35:35 -0800 Subject: [PATCH 078/273] =?UTF-8?q?Use=20the=20renderer=20AutoUpdateManage?= =?UTF-8?q?r=20in=20atom-environment=E2=80=99s=20update=20events?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/atom-environment.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 481e762ca..f1fe1b459 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -893,7 +893,7 @@ class AtomEnvironment extends Model listenForUpdates: -> # listen for updates available locally (that have been successfully downloaded) - @disposables.add(@applicationDelegate.onDidCompleteDownloadingUpdate(@updateAvailable.bind(this))) + @disposables.add(@autoUpdater.onDidCompleteDownload(@updateAvailable.bind(this))) setBodyPlatformClass: -> @document.body.classList.add("platform-#{process.platform}") From 341abbfc261d2b9206cf2d85cdd7bf147d4760cd Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 23 Feb 2016 17:35:50 -0800 Subject: [PATCH 079/273] Nof. Nope. --- spec/auto-update-manager-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/auto-update-manager-spec.js b/spec/auto-update-manager-spec.js index e23c1911d..ff2fc0682 100644 --- a/spec/auto-update-manager-spec.js +++ b/spec/auto-update-manager-spec.js @@ -4,7 +4,7 @@ import AutoUpdateManager from '../src/auto-update-manager' import {remote} from 'electron' const electronAutoUpdater = remote.require('electron').autoUpdater -fdescribe('AutoUpdateManager (renderer)', () => { +describe('AutoUpdateManager (renderer)', () => { let autoUpdateManager beforeEach(() => { From e9e372b69e42d0ab8659bc3e446e6df57ce987a0 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 23 Feb 2016 17:48:15 -0800 Subject: [PATCH 080/273] Dispose emitter --- spec/auto-update-manager-spec.js | 2 +- src/auto-update-manager.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/auto-update-manager-spec.js b/spec/auto-update-manager-spec.js index ff2fc0682..f4e7622b2 100644 --- a/spec/auto-update-manager-spec.js +++ b/spec/auto-update-manager-spec.js @@ -68,11 +68,11 @@ describe('AutoUpdateManager (renderer)', () => { const spy = jasmine.createSpy('spy') const doneIndicator = jasmine.createSpy('spy') atom.applicationDelegate.onUpdateNotAvailable(doneIndicator) - autoUpdateManager.dispose() autoUpdateManager.onDidBeginCheckingForUpdate(spy) autoUpdateManager.onDidBeginDownload(spy) autoUpdateManager.onDidCompleteDownload(spy) autoUpdateManager.onUpdateNotAvailable(spy) + autoUpdateManager.dispose() electronAutoUpdater.emit('checking-for-update') electronAutoUpdater.emit('update-available') electronAutoUpdater.emit('update-downloaded', null, null, '1.2.3') diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index f46197f8d..681978cb6 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -28,6 +28,7 @@ export default class AutoUpdateManager { dispose () { this.subscriptions.dispose() + this.emitter.dispose() } onDidBeginCheckingForUpdate (callback) { From 4afe6df2c4edc8a4bfc8b5db07ee27a88f7df908 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 23 Feb 2016 17:48:26 -0800 Subject: [PATCH 081/273] Reorder for consistency --- src/auto-update-manager.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index 681978cb6..5f37196ed 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -11,12 +11,12 @@ export default class AutoUpdateManager { initialize (updateEventEmitter) { this.subscriptions.add( - updateEventEmitter.onDidBeginDownloadingUpdate(() => { - this.emitter.emit('did-begin-downloading-update') - }), updateEventEmitter.onDidBeginCheckingForUpdate(() => { this.emitter.emit('did-begin-checking-for-update') }), + updateEventEmitter.onDidBeginDownloadingUpdate(() => { + this.emitter.emit('did-begin-downloading-update') + }), updateEventEmitter.onDidCompleteDownloadingUpdate((details) => { this.emitter.emit('did-complete-downloading-update', details) }), From b60e1957a88c0a9c2585434f94cbeadc9a51f3b6 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 23 Feb 2016 17:48:43 -0800 Subject: [PATCH 082/273] Return the disposables! --- src/auto-update-manager.js | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index 5f37196ed..0bb793b44 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -32,33 +32,23 @@ export default class AutoUpdateManager { } onDidBeginCheckingForUpdate (callback) { - this.subscriptions.add( - this.emitter.on('did-begin-checking-for-update', callback) - ) + return this.emitter.on('did-begin-checking-for-update', callback) } onDidBeginDownload (callback) { - this.subscriptions.add( - this.emitter.on('did-begin-downloading-update', callback) - ) + return this.emitter.on('did-begin-downloading-update', callback) } onDidCompleteDownload (callback) { - this.subscriptions.add( - this.emitter.on('did-complete-downloading-update', callback) - ) + return this.emitter.on('did-complete-downloading-update', callback) } onUpdateAvailable (callback) { - this.subscriptions.add( - this.emitter.on('update-available', callback) - ) + return this.emitter.on('update-available', callback) } onUpdateNotAvailable (callback) { - this.subscriptions.add( - this.emitter.on('update-not-available', callback) - ) + return this.emitter.on('update-not-available', callback) } checkForUpdate () { From d3340d070f456c6e181da7e38624cc5af9d3f062 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 23 Feb 2016 18:12:04 -0800 Subject: [PATCH 083/273] =?UTF-8?q?UpdateAvailable=20isn=E2=80=99t=20reall?= =?UTF-8?q?y=20a=20thing=20in=20this=20world?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/auto-update-manager.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index 0bb793b44..cc3035fdf 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -43,10 +43,6 @@ export default class AutoUpdateManager { return this.emitter.on('did-complete-downloading-update', callback) } - onUpdateAvailable (callback) { - return this.emitter.on('update-available', callback) - } - onUpdateNotAvailable (callback) { return this.emitter.on('update-not-available', callback) } From e477751c1986743882d551d54fa3d2b99bd189a0 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Thu, 25 Feb 2016 16:00:48 -0800 Subject: [PATCH 084/273] Make the autoupdater functions consistently names --- spec/auto-update-manager-spec.js | 12 ++++++------ src/auto-update-manager.js | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/auto-update-manager-spec.js b/spec/auto-update-manager-spec.js index f4e7622b2..499e2cb3b 100644 --- a/spec/auto-update-manager-spec.js +++ b/spec/auto-update-manager-spec.js @@ -27,10 +27,10 @@ describe('AutoUpdateManager (renderer)', () => { }) }) - describe('::onDidBeginDownload', () => { + describe('::onDidBeginDownloadingUpdate', () => { it('subscribes to "did-begin-downloading-update" event', () => { const spy = jasmine.createSpy('spy') - autoUpdateManager.onDidBeginDownload(spy) + autoUpdateManager.onDidBeginDownloadingUpdate(spy) electronAutoUpdater.emit('update-available') waitsFor(() => { return spy.callCount === 1 @@ -38,10 +38,10 @@ describe('AutoUpdateManager (renderer)', () => { }) }) - describe('::onDidCompleteDownload', () => { + describe('::onDidCompleteDownloadingUpdate', () => { it('subscribes to "did-complete-downloading-update" event', () => { const spy = jasmine.createSpy('spy') - autoUpdateManager.onDidCompleteDownload(spy) + autoUpdateManager.onDidCompleteDownloadingUpdate(spy) electronAutoUpdater.emit('update-downloaded', null, null, '1.2.3') waitsFor(() => { return spy.callCount === 1 @@ -69,8 +69,8 @@ describe('AutoUpdateManager (renderer)', () => { const doneIndicator = jasmine.createSpy('spy') atom.applicationDelegate.onUpdateNotAvailable(doneIndicator) autoUpdateManager.onDidBeginCheckingForUpdate(spy) - autoUpdateManager.onDidBeginDownload(spy) - autoUpdateManager.onDidCompleteDownload(spy) + autoUpdateManager.onDidBeginDownloadingUpdate(spy) + autoUpdateManager.onDidCompleteDownloadingUpdate(spy) autoUpdateManager.onUpdateNotAvailable(spy) autoUpdateManager.dispose() electronAutoUpdater.emit('checking-for-update') diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index cc3035fdf..e7852f2d9 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -35,11 +35,11 @@ export default class AutoUpdateManager { return this.emitter.on('did-begin-checking-for-update', callback) } - onDidBeginDownload (callback) { + onDidBeginDownloadingUpdate (callback) { return this.emitter.on('did-begin-downloading-update', callback) } - onDidCompleteDownload (callback) { + onDidCompleteDownloadingUpdate (callback) { return this.emitter.on('did-complete-downloading-update', callback) } From c19296efb753167619a66532ecb6481339415b9d Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Thu, 25 Feb 2016 16:01:23 -0800 Subject: [PATCH 085/273] Add isEnabled function to AutoUpdateManager --- spec/auto-update-manager-spec.js | 32 ++++++++++++++++++++++++++++++++ src/auto-update-manager.js | 27 +++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/spec/auto-update-manager-spec.js b/spec/auto-update-manager-spec.js index 499e2cb3b..6e3c037ef 100644 --- a/spec/auto-update-manager-spec.js +++ b/spec/auto-update-manager-spec.js @@ -63,6 +63,38 @@ describe('AutoUpdateManager (renderer)', () => { }) }) + describe('::isEnabled', () => { + let platform, releaseChannel + it('returns true on OS X and Windows, when in stable', () => { + spyOn(autoUpdateManager, 'getPlatform').andCallFake(() => platform) + spyOn(autoUpdateManager, 'getReleaseChannel').andCallFake(() => releaseChannel) + + platform = 'win32' + releaseChannel = 'stable' + expect(autoUpdateManager.isEnabled()).toBe(true) + + platform = 'win32' + releaseChannel = 'dev' + expect(autoUpdateManager.isEnabled()).toBe(false) + + platform = 'darwin' + releaseChannel = 'stable' + expect(autoUpdateManager.isEnabled()).toBe(true) + + platform = 'darwin' + releaseChannel = 'dev' + expect(autoUpdateManager.isEnabled()).toBe(false) + + platform = 'linux' + releaseChannel = 'stable' + expect(autoUpdateManager.isEnabled()).toBe(false) + + platform = 'linux' + releaseChannel = 'dev' + expect(autoUpdateManager.isEnabled()).toBe(false) + }) + }) + describe('::dispose', () => { it('subscribes to "update-not-available" event', () => { const spy = jasmine.createSpy('spy') diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index e7852f2d9..e99ce83d9 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -31,6 +31,18 @@ export default class AutoUpdateManager { this.emitter.dispose() } + checkForUpdate () { + ipcRenderer.send('check-for-update') + } + + quitAndInstallUpdate () { + ipcRenderer.send('install-update') + } + + isEnabled () { + return this.getReleaseChannel() == 'stable' && (this.getPlatform() === 'darwin' || this.getPlatform() === 'win32') + } + onDidBeginCheckingForUpdate (callback) { return this.emitter.on('did-begin-checking-for-update', callback) } @@ -47,7 +59,18 @@ export default class AutoUpdateManager { return this.emitter.on('update-not-available', callback) } - checkForUpdate () { - ipcRenderer.send('check-for-update') + getPlatform () { + return process.platform + } + + // TODO: We should move this into atom env or something. + getReleaseChannel () { + let version = atom.getVersion() + if (version.indexOf('beta') > -1) { + return 'beta' + } else if (version.indexOf('dev') > -1) { + return 'dev' + } + return 'stable' } } From 1cd530cdf06e4865a91f159fffc0e687ff78610c Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Thu, 25 Feb 2016 16:01:44 -0800 Subject: [PATCH 086/273] Add some todo code --- src/auto-update-manager.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index e99ce83d9..06b437c3b 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -55,6 +55,12 @@ export default class AutoUpdateManager { return this.emitter.on('did-complete-downloading-update', callback) } + // TODO: When https://github.com/atom/electron/issues/4587 is closed, we can + // add an update-available event. + // onUpdateAvailable (callback) { + // return this.emitter.on('update-available', callback) + // } + onUpdateNotAvailable (callback) { return this.emitter.on('update-not-available', callback) } From 418b1bd8f1bb95c79620d9847518aa33abdb4142 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Thu, 25 Feb 2016 16:33:39 -0800 Subject: [PATCH 087/273] Get rid of the initialize method --- spec/auto-update-manager-spec.js | 5 +++-- src/atom-environment.coffee | 3 +-- src/auto-update-manager.js | 12 +++++------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/spec/auto-update-manager-spec.js b/spec/auto-update-manager-spec.js index 6e3c037ef..2b51ed658 100644 --- a/spec/auto-update-manager-spec.js +++ b/spec/auto-update-manager-spec.js @@ -8,8 +8,9 @@ describe('AutoUpdateManager (renderer)', () => { let autoUpdateManager beforeEach(() => { - autoUpdateManager = new AutoUpdateManager() - autoUpdateManager.initialize(atom.applicationDelegate) + autoUpdateManager = new AutoUpdateManager({ + applicationDelegate: atom.applicationDelegate + }) }) afterEach(() => { diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index f1fe1b459..04074cfcb 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -192,8 +192,7 @@ class AtomEnvironment extends Model @themes.workspace = @workspace @textEditors = new TextEditorRegistry - @autoUpdater = new AutoUpdateManager - @autoUpdater.initialize(@applicationDelegate) + @autoUpdater = new AutoUpdateManager({@applicationDelegate}) @config.load() diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index 06b437c3b..d811996c1 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -4,23 +4,21 @@ import {Emitter, CompositeDisposable} from 'event-kit' import {ipcRenderer} from 'electron' export default class AutoUpdateManager { - constructor () { + constructor ({applicationDelegate}) { this.subscriptions = new CompositeDisposable() this.emitter = new Emitter() - } - initialize (updateEventEmitter) { this.subscriptions.add( - updateEventEmitter.onDidBeginCheckingForUpdate(() => { + applicationDelegate.onDidBeginCheckingForUpdate(() => { this.emitter.emit('did-begin-checking-for-update') }), - updateEventEmitter.onDidBeginDownloadingUpdate(() => { + applicationDelegate.onDidBeginDownloadingUpdate(() => { this.emitter.emit('did-begin-downloading-update') }), - updateEventEmitter.onDidCompleteDownloadingUpdate((details) => { + applicationDelegate.onDidCompleteDownloadingUpdate((details) => { this.emitter.emit('did-complete-downloading-update', details) }), - updateEventEmitter.onUpdateNotAvailable(() => { + applicationDelegate.onUpdateNotAvailable(() => { this.emitter.emit('update-not-available') }) ) From bc138f727e1af484f0110661eafafae6f4861e95 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Thu, 25 Feb 2016 16:33:51 -0800 Subject: [PATCH 088/273] Fix usage of the onDidCompleteDownload() method --- src/atom-environment.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 04074cfcb..2122abbbe 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -892,7 +892,7 @@ class AtomEnvironment extends Model listenForUpdates: -> # listen for updates available locally (that have been successfully downloaded) - @disposables.add(@autoUpdater.onDidCompleteDownload(@updateAvailable.bind(this))) + @disposables.add(@autoUpdater.onDidCompleteDownloadingUpdate(@updateAvailable.bind(this))) setBodyPlatformClass: -> @document.body.classList.add("platform-#{process.platform}") From 68951494d2e6c4becfa44be38d90a49f79f7c3b9 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Thu, 25 Feb 2016 17:32:02 -0800 Subject: [PATCH 089/273] isEnabled -> platformSupportsUpdates --- spec/auto-update-manager-spec.js | 14 +++++++------- src/auto-update-manager.js | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/auto-update-manager-spec.js b/spec/auto-update-manager-spec.js index 2b51ed658..e12f85c5b 100644 --- a/spec/auto-update-manager-spec.js +++ b/spec/auto-update-manager-spec.js @@ -64,7 +64,7 @@ describe('AutoUpdateManager (renderer)', () => { }) }) - describe('::isEnabled', () => { + describe('::platformSupportsUpdates', () => { let platform, releaseChannel it('returns true on OS X and Windows, when in stable', () => { spyOn(autoUpdateManager, 'getPlatform').andCallFake(() => platform) @@ -72,27 +72,27 @@ describe('AutoUpdateManager (renderer)', () => { platform = 'win32' releaseChannel = 'stable' - expect(autoUpdateManager.isEnabled()).toBe(true) + expect(autoUpdateManager.platformSupportsUpdates()).toBe(true) platform = 'win32' releaseChannel = 'dev' - expect(autoUpdateManager.isEnabled()).toBe(false) + expect(autoUpdateManager.platformSupportsUpdates()).toBe(false) platform = 'darwin' releaseChannel = 'stable' - expect(autoUpdateManager.isEnabled()).toBe(true) + expect(autoUpdateManager.platformSupportsUpdates()).toBe(true) platform = 'darwin' releaseChannel = 'dev' - expect(autoUpdateManager.isEnabled()).toBe(false) + expect(autoUpdateManager.platformSupportsUpdates()).toBe(false) platform = 'linux' releaseChannel = 'stable' - expect(autoUpdateManager.isEnabled()).toBe(false) + expect(autoUpdateManager.platformSupportsUpdates()).toBe(false) platform = 'linux' releaseChannel = 'dev' - expect(autoUpdateManager.isEnabled()).toBe(false) + expect(autoUpdateManager.platformSupportsUpdates()).toBe(false) }) }) diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index d811996c1..497097864 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -37,7 +37,7 @@ export default class AutoUpdateManager { ipcRenderer.send('install-update') } - isEnabled () { + platformSupportsUpdates () { return this.getReleaseChannel() == 'stable' && (this.getPlatform() === 'darwin' || this.getPlatform() === 'win32') } From 7a1ad8263aa63438df16247663cf99e5073d4d72 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Fri, 26 Feb 2016 16:37:59 -0800 Subject: [PATCH 090/273] Rename `quitAndInstallUpdate` to `restartAndInstallUpdate` --- src/auto-update-manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index 497097864..eae979d9d 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -33,7 +33,7 @@ export default class AutoUpdateManager { ipcRenderer.send('check-for-update') } - quitAndInstallUpdate () { + restartAndInstallUpdate () { ipcRenderer.send('install-update') } From 3a32b30d5a98f704a310c96fa1d7bc8309d7d412 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Fri, 26 Feb 2016 16:38:56 -0800 Subject: [PATCH 091/273] Add mechanism to get the AutoUpdateManager's state --- src/auto-update-manager.js | 4 ++++ src/browser/atom-application.coffee | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index eae979d9d..14ec44c29 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -37,6 +37,10 @@ export default class AutoUpdateManager { ipcRenderer.send('install-update') } + getState () { + return ipcRenderer.sendSync('get-auto-update-manager-state') + } + platformSupportsUpdates () { return this.getReleaseChannel() == 'stable' && (this.getPlatform() === 'darwin' || this.getPlatform() === 'win32') } diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index fad69b967..fdfea5474 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -307,6 +307,9 @@ class AtomApplication ipcMain.on 'check-for-update', => @autoUpdateManager.check() + ipcMain.on 'get-auto-update-manager-state', (event) => + event.returnValue = @autoUpdateManager.getState() + ipcMain.on 'execute-javascript-in-dev-tools', (event, code) -> event.sender.devToolsWebContents?.executeJavaScript(code) From 8307fb84265509bcaaed99f9c6b8b452f9a56bfb Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Fri, 26 Feb 2016 16:39:42 -0800 Subject: [PATCH 092/273] Change logic for `platformSupportsUpdates --- src/auto-update-manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index 14ec44c29..c1446ed5d 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -42,7 +42,7 @@ export default class AutoUpdateManager { } platformSupportsUpdates () { - return this.getReleaseChannel() == 'stable' && (this.getPlatform() === 'darwin' || this.getPlatform() === 'win32') + return this.getReleaseChannel() !== 'dev' && this.getState() !== 'unsupported' } onDidBeginCheckingForUpdate (callback) { From d831ec73ed6adeccc1b355f96167daf1630031af Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 29 Feb 2016 16:42:25 -0800 Subject: [PATCH 093/273] Fix platformSupportsUpdates() specs --- spec/auto-update-manager-spec.js | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/spec/auto-update-manager-spec.js b/spec/auto-update-manager-spec.js index e12f85c5b..2b65d09e5 100644 --- a/spec/auto-update-manager-spec.js +++ b/spec/auto-update-manager-spec.js @@ -65,32 +65,24 @@ describe('AutoUpdateManager (renderer)', () => { }) describe('::platformSupportsUpdates', () => { - let platform, releaseChannel + let state, releaseChannel it('returns true on OS X and Windows, when in stable', () => { - spyOn(autoUpdateManager, 'getPlatform').andCallFake(() => platform) + spyOn(autoUpdateManager, 'getState').andCallFake(() => state) spyOn(autoUpdateManager, 'getReleaseChannel').andCallFake(() => releaseChannel) - platform = 'win32' + state = 'idle' releaseChannel = 'stable' expect(autoUpdateManager.platformSupportsUpdates()).toBe(true) - platform = 'win32' + state = 'idle' releaseChannel = 'dev' expect(autoUpdateManager.platformSupportsUpdates()).toBe(false) - platform = 'darwin' - releaseChannel = 'stable' - expect(autoUpdateManager.platformSupportsUpdates()).toBe(true) - - platform = 'darwin' - releaseChannel = 'dev' - expect(autoUpdateManager.platformSupportsUpdates()).toBe(false) - - platform = 'linux' + state = 'unsupported' releaseChannel = 'stable' expect(autoUpdateManager.platformSupportsUpdates()).toBe(false) - platform = 'linux' + state = 'unsupported' releaseChannel = 'dev' expect(autoUpdateManager.platformSupportsUpdates()).toBe(false) }) From 8eb1326d4c7170768cb0d71908803220c28aab0f Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 29 Feb 2016 16:42:37 -0800 Subject: [PATCH 094/273] Add some TODOs --- src/application-delegate.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/application-delegate.coffee b/src/application-delegate.coffee index a853cd8ea..dff496fdd 100644 --- a/src/application-delegate.coffee +++ b/src/application-delegate.coffee @@ -174,6 +174,9 @@ class ApplicationDelegate onUpdateAvailable: (callback) -> outerCallback = (event, message, detail) -> + # TODO: Yes, this is strange that `onUpdateAvailable` is listening for + # `did-begin-downloading-update`. We currently have no mechanism to know + # if there is an update, so begin of downloading is a good proxy. callback(detail) if message is 'did-begin-downloading-update' ipcRenderer.on('message', outerCallback) @@ -193,6 +196,7 @@ class ApplicationDelegate onDidCompleteDownloadingUpdate: (callback) -> outerCallback = (event, message, detail) -> + # TODO: We could rename this event to `did-complete-downloading-update` callback(detail) if message is 'update-available' ipcRenderer.on('message', outerCallback) From 75aca7ee0c9e1a61349114f5d3d78b676d58b2b2 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 29 Feb 2016 16:47:53 -0800 Subject: [PATCH 095/273] Add a deprecation TODO --- src/atom-environment.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 2122abbbe..df9130453 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -884,6 +884,7 @@ class AtomEnvironment extends Model detail: error.message dismissable: true + # TODO: We should deprecate the update events here, and use `atom.autoUpdater` instead onUpdateAvailable: (callback) -> @emitter.on 'update-available', callback From 58bf090724bd9b0f5917d9ce1dde2746c53e38d4 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 1 Mar 2016 14:41:38 -0800 Subject: [PATCH 096/273] Rename `dispose` -> `destroy` --- spec/auto-update-manager-spec.js | 8 ++++---- src/atom-environment.coffee | 1 + src/auto-update-manager.js | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/spec/auto-update-manager-spec.js b/spec/auto-update-manager-spec.js index 2b65d09e5..9c82400ef 100644 --- a/spec/auto-update-manager-spec.js +++ b/spec/auto-update-manager-spec.js @@ -14,7 +14,7 @@ describe('AutoUpdateManager (renderer)', () => { }) afterEach(() => { - autoUpdateManager.dispose() + autoUpdateManager.destroy() }) describe('::onDidBeginCheckingForUpdate', () => { @@ -88,8 +88,8 @@ describe('AutoUpdateManager (renderer)', () => { }) }) - describe('::dispose', () => { - it('subscribes to "update-not-available" event', () => { + describe('::destroy', () => { + it('unsubscribes from all events', () => { const spy = jasmine.createSpy('spy') const doneIndicator = jasmine.createSpy('spy') atom.applicationDelegate.onUpdateNotAvailable(doneIndicator) @@ -97,7 +97,7 @@ describe('AutoUpdateManager (renderer)', () => { autoUpdateManager.onDidBeginDownloadingUpdate(spy) autoUpdateManager.onDidCompleteDownloadingUpdate(spy) autoUpdateManager.onUpdateNotAvailable(spy) - autoUpdateManager.dispose() + autoUpdateManager.destroy() electronAutoUpdater.emit('checking-for-update') electronAutoUpdater.emit('update-available') electronAutoUpdater.emit('update-downloaded', null, null, '1.2.3') diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index df9130453..4fecd01aa 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -338,6 +338,7 @@ class AtomEnvironment extends Model @commands.clear() @stylesElement.remove() @config.unobserveUserConfig() + @autoUpdater.destroy() @uninstallWindowEventHandler() diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index c1446ed5d..3b2d27439 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -24,7 +24,7 @@ export default class AutoUpdateManager { ) } - dispose () { + destroy () { this.subscriptions.dispose() this.emitter.dispose() } From 81c07a2af9322e32b758c088663887b233db1808 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 1 Mar 2016 14:42:53 -0800 Subject: [PATCH 097/273] :art: Cleanup spec desc --- spec/auto-update-manager-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/auto-update-manager-spec.js b/spec/auto-update-manager-spec.js index 9c82400ef..7436be291 100644 --- a/spec/auto-update-manager-spec.js +++ b/spec/auto-update-manager-spec.js @@ -66,7 +66,7 @@ describe('AutoUpdateManager (renderer)', () => { describe('::platformSupportsUpdates', () => { let state, releaseChannel - it('returns true on OS X and Windows, when in stable', () => { + it('returns true on OS X and Windows when in stable', () => { spyOn(autoUpdateManager, 'getState').andCallFake(() => state) spyOn(autoUpdateManager, 'getReleaseChannel').andCallFake(() => releaseChannel) From 02368a9fc680f658dacbd0b06e1531959dd6c340 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 1 Mar 2016 14:51:45 -0800 Subject: [PATCH 098/273] Add `atom.getReleaseChannel` --- spec/atom-environment-spec.coffee | 15 +++++++++++++++ src/atom-environment.coffee | 10 ++++++++++ 2 files changed, 25 insertions(+) diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index 1f8eb08e7..6685d4060 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -328,3 +328,18 @@ describe "AtomEnvironment", -> runs -> {releaseVersion} = updateAvailableHandler.mostRecentCall.args[0] expect(releaseVersion).toBe 'version' + + describe "::getReleaseChannel()", -> + [version] = [] + beforeEach -> + spyOn(atom, 'getVersion').andCallFake -> version + + it "returns the correct channel based on the version number", -> + version = '1.5.6' + expect(atom.getReleaseChannel()).toBe 'stable' + + version = '1.5.0-beta10' + expect(atom.getReleaseChannel()).toBe 'beta' + + version = '1.7.0-dev-5340c91' + expect(atom.getReleaseChannel()).toBe 'dev' diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 4fecd01aa..14d3f78c9 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -417,6 +417,16 @@ class AtomEnvironment extends Model getVersion: -> @appVersion ?= @getLoadSettings().appVersion + # Returns the release channel as a {String}. Will return one of `'dev', 'beta', 'stable'` + getReleaseChannel: -> + version = @getVersion() + if version.indexOf('beta') > -1 + 'beta' + else if version.indexOf('dev') > -1 + 'dev' + else + 'stable' + # Public: Returns a {Boolean} that is `true` if the current version is an official release. isReleasedVersion: -> not /\w{7}/.test(@getVersion()) # Check if the release is a 7-character SHA prefix From 0b36d85bdac5679097f48cefa3f0bd44fe367b4c Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 1 Mar 2016 14:51:57 -0800 Subject: [PATCH 099/273] :art: Remove whitespace --- src/atom-environment.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 14d3f78c9..06296fbaf 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -846,7 +846,6 @@ class AtomEnvironment extends Model @applicationDelegate.setTemporaryWindowState(state) savePromise.catch(reject).then(resolve) - loadState: -> if @enablePersistence if stateKey = @getStateKey(@getLoadSettings().initialPaths) From 4d11ff25d0953c1debdacaef1b05f9a736b164f4 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 1 Mar 2016 14:59:02 -0800 Subject: [PATCH 100/273] Use atom.getReleaseChannel() --- spec/auto-update-manager-spec.js | 2 +- src/auto-update-manager.js | 13 +------------ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/spec/auto-update-manager-spec.js b/spec/auto-update-manager-spec.js index 7436be291..6f7dbbb1a 100644 --- a/spec/auto-update-manager-spec.js +++ b/spec/auto-update-manager-spec.js @@ -68,7 +68,7 @@ describe('AutoUpdateManager (renderer)', () => { let state, releaseChannel it('returns true on OS X and Windows when in stable', () => { spyOn(autoUpdateManager, 'getState').andCallFake(() => state) - spyOn(autoUpdateManager, 'getReleaseChannel').andCallFake(() => releaseChannel) + spyOn(atom, 'getReleaseChannel').andCallFake(() => releaseChannel) state = 'idle' releaseChannel = 'stable' diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index 3b2d27439..4a184faf8 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -42,7 +42,7 @@ export default class AutoUpdateManager { } platformSupportsUpdates () { - return this.getReleaseChannel() !== 'dev' && this.getState() !== 'unsupported' + return atom.getReleaseChannel() !== 'dev' && this.getState() !== 'unsupported' } onDidBeginCheckingForUpdate (callback) { @@ -70,15 +70,4 @@ export default class AutoUpdateManager { getPlatform () { return process.platform } - - // TODO: We should move this into atom env or something. - getReleaseChannel () { - let version = atom.getVersion() - if (version.indexOf('beta') > -1) { - return 'beta' - } else if (version.indexOf('dev') > -1) { - return 'dev' - } - return 'stable' - } } From 492e89c8fff3d9fa96634a8510eab1f3222dfe42 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 1 Mar 2016 14:59:41 -0800 Subject: [PATCH 101/273] Move raw ipc calls into the applicationDelegate --- src/application-delegate.coffee | 9 +++++++++ src/auto-update-manager.js | 7 ++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/application-delegate.coffee b/src/application-delegate.coffee index dff496fdd..3aff9e457 100644 --- a/src/application-delegate.coffee +++ b/src/application-delegate.coffee @@ -235,3 +235,12 @@ class ApplicationDelegate disablePinchToZoom: -> webFrame.setZoomLevelLimits(1, 1) + + checkForUpdate: -> + ipcRenderer.send('check-for-update') + + restartAndInstallUpdate: -> + ipcRenderer.send('install-update') + + getAutoUpdateManagerState: -> + ipcRenderer.sendSync('get-auto-update-manager-state') diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index 4a184faf8..01ead9bbe 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -5,6 +5,7 @@ import {ipcRenderer} from 'electron' export default class AutoUpdateManager { constructor ({applicationDelegate}) { + this.applicationDelegate = applicationDelegate this.subscriptions = new CompositeDisposable() this.emitter = new Emitter() @@ -30,15 +31,15 @@ export default class AutoUpdateManager { } checkForUpdate () { - ipcRenderer.send('check-for-update') + this.applicationDelegate.checkForUpdate() } restartAndInstallUpdate () { - ipcRenderer.send('install-update') + this.applicationDelegate.restartAndInstallUpdate() } getState () { - return ipcRenderer.sendSync('get-auto-update-manager-state') + return this.applicationDelegate.getAutoUpdateManagerState() } platformSupportsUpdates () { From f884c987e29acef83a40164b681950a7fd8bf047 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 1 Mar 2016 15:12:38 -0800 Subject: [PATCH 102/273] Remove unnecessary import --- src/auto-update-manager.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/auto-update-manager.js b/src/auto-update-manager.js index 01ead9bbe..62cc03f85 100644 --- a/src/auto-update-manager.js +++ b/src/auto-update-manager.js @@ -1,7 +1,6 @@ 'use babel' import {Emitter, CompositeDisposable} from 'event-kit' -import {ipcRenderer} from 'electron' export default class AutoUpdateManager { constructor ({applicationDelegate}) { From f26c0c0b15231f853f82a8fc6c7e527a27154d89 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 1 Mar 2016 18:03:50 -0700 Subject: [PATCH 103/273] Bump timeouts as a possible workaround for flaky specs --- spec/async-spec-helpers.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/async-spec-helpers.coffee b/spec/async-spec-helpers.coffee index 5f8e03ca3..6ed8a5a2b 100644 --- a/spec/async-spec-helpers.coffee +++ b/spec/async-spec-helpers.coffee @@ -19,7 +19,9 @@ exports.afterEach = (fn) -> waitsForPromise = (fn) -> promise = fn() - waitsFor 'spec promise to resolve', 30000, (done) -> + # This timeout is 3 minutes. We need to bump it back down once we fix backgrounding + # of the renderer process on CI. See https://github.com/atom/electron/issues/4317 + waitsFor 'spec promise to resolve', 3 * 60 * 1000, (done) -> promise.then( done, (error) -> From 47a348f557bce3c6518e572d9ad45f181c3ffde9 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 1 Mar 2016 18:22:43 -0700 Subject: [PATCH 104/273] Filter out non-directory project paths when deserializing Project Closes #10628 --- spec/project-spec.coffee | 8 ++++++++ src/project.coffee | 1 + 2 files changed, 9 insertions(+) diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 9d42f9a7e..70022426a 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -21,6 +21,14 @@ describe "Project", -> afterEach -> deserializedProject?.destroy() + it "does not deserialize paths to non directories", -> + deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) + state = atom.project.serialize() + state.paths.push('/directory/that/does/not/exist') + state.paths.push(path.join(__dirname, 'fixtures', 'sample.js')) + deserializedProject.deserialize(state, atom.deserializers) + expect(deserializedProject.getPaths()).toEqual(atom.project.getPaths()) + it "does not include unretained buffers in the serialized state", -> waitsForPromise -> atom.project.bufferForPath('a') diff --git a/src/project.coffee b/src/project.coffee index 008d81e3e..24a634cb1 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -56,6 +56,7 @@ class Project extends Model deserialize: (state, deserializerManager) -> state.paths = [state.path] if state.path? # backward compatibility + state.paths = state.paths.filter (directoryPath) -> fs.isDirectorySync(directoryPath) @buffers = _.compact state.buffers.map (bufferState) -> # Check that buffer's file path is accessible From ea2d72f314e24f1aee8c336064986520e1877895 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 1 Mar 2016 18:13:53 -0800 Subject: [PATCH 105/273] :arrow_up: about@1.4.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7ff3df275..005b066ee 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "one-light-syntax": "1.2.0", "solarized-dark-syntax": "1.0.0", "solarized-light-syntax": "1.0.0", - "about": "1.3.1", + "about": "1.4.0", "archive-view": "0.61.1", "autocomplete-atom-api": "0.10.0", "autocomplete-css": "0.11.0", From f6908f80cdfa8699c98d808d8c22fc4e2dd4b077 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 2 Mar 2016 15:38:29 -0700 Subject: [PATCH 106/273] Rename watchProjectPath to watchProjectPaths --- src/atom-environment.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 06296fbaf..661201125 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -676,7 +676,7 @@ class AtomEnvironment extends Model @document.body.appendChild(@views.getView(@workspace)) @backgroundStylesheet?.remove() - @watchProjectPath() + @watchProjectPaths() @packages.activate() @keymaps.loadUserKeymap() @@ -808,7 +808,7 @@ class AtomEnvironment extends Model @themes.load() # Notify the browser project of the window's current project path - watchProjectPath: -> + watchProjectPaths: -> @disposables.add @project.onDidChangePaths => @applicationDelegate.setRepresentedDirectoryPaths(@project.getPaths()) From 51a2609bc90a937507b7e226dad67a3a7ea6b8c6 Mon Sep 17 00:00:00 2001 From: Jason Koenig Date: Sat, 30 Jan 2016 23:28:43 -0800 Subject: [PATCH 107/273] Properly restore initialPaths so project paths are not loaded as files If project folders no longer exist or are not mounted, then Atom would open them as buffers, which were empty because the corresponding file did not exist. This threads the right state through the startup sequence so that "initialPaths", which actually are project roots, is restored correctly. --- src/browser/atom-application.coffee | 16 ++++++++-------- src/browser/atom-window.coffee | 13 ++++--------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index fdfea5474..b2d66af87 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -85,16 +85,16 @@ class AtomApplication else @loadState(options) or @openPath(options) - openWithOptions: ({pathsToOpen, executedFrom, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, newWindow, logFile, profileStartup, timeout, clearWindowState, addToLastWindow}) -> + openWithOptions: ({initialPaths, pathsToOpen, executedFrom, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, newWindow, logFile, profileStartup, timeout, clearWindowState, addToLastWindow}) -> if test @runTests({headless: true, devMode, @resourcePath, executedFrom, pathsToOpen, logFile, timeout}) else if pathsToOpen.length > 0 - @openPaths({pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, clearWindowState, addToLastWindow}) + @openPaths({initialPaths, pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, clearWindowState, addToLastWindow}) else if urlsToOpen.length > 0 @openUrl({urlToOpen, devMode, safeMode}) for urlToOpen in urlsToOpen else # Always open a editor window if this is the first instance of Atom. - @openPath({pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, clearWindowState, addToLastWindow}) + @openPath({initialPaths, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, clearWindowState, addToLastWindow}) # Public: Removes the {AtomWindow} from the global window list. removeWindow: (window) -> @@ -418,8 +418,8 @@ class AtomApplication # :profileStartup - Boolean to control creating a profile of the startup time. # :window - {AtomWindow} to open file paths in. # :addToLastWindow - Boolean of whether this should be opened in last focused window. - openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window, clearWindowState, addToLastWindow} = {}) -> - @openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window, clearWindowState, addToLastWindow}) + openPath: ({initialPaths, pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window, clearWindowState, addToLastWindow} = {}) -> + @openPaths({initialPaths, pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window, clearWindowState, addToLastWindow}) # Public: Opens multiple paths, in existing windows if possible. # @@ -432,7 +432,7 @@ class AtomApplication # :windowDimensions - Object with height and width keys. # :window - {AtomWindow} to open file paths in. # :addToLastWindow - Boolean of whether this should be opened in last focused window. - openPaths: ({pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, profileStartup, window, clearWindowState, addToLastWindow}={}) -> + openPaths: ({initialPaths, pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, profileStartup, window, clearWindowState, addToLastWindow}={}) -> devMode = Boolean(devMode) safeMode = Boolean(safeMode) clearWindowState = Boolean(clearWindowState) @@ -469,7 +469,7 @@ class AtomApplication windowInitializationScript ?= require.resolve('../initialize-application-window') resourcePath ?= @resourcePath windowDimensions ?= @getDimensionsForNewWindow() - openedWindow = new AtomWindow({locationsToOpen, windowInitializationScript, resourcePath, devMode, safeMode, windowDimensions, profileStartup, clearWindowState}) + openedWindow = new AtomWindow({initialPaths, locationsToOpen, windowInitializationScript, resourcePath, devMode, safeMode, windowDimensions, profileStartup, clearWindowState}) if pidToKillWhenClosed? @pidsToOpenWindows[pidToKillWhenClosed] = openedWindow @@ -512,7 +512,7 @@ class AtomApplication if (states = @storageFolder.load('application.json'))?.length > 0 for state in states @openWithOptions(_.extend(options, { - pathsToOpen: state.initialPaths + initialPaths: state.initialPaths urlsToOpen: [] devMode: @devMode safeMode: @safeMode diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index 634242e0d..24730c944 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -17,7 +17,7 @@ class AtomWindow isSpec: null constructor: (settings={}) -> - {@resourcePath, pathToOpen, locationsToOpen, @isSpec, @headless, @safeMode, @devMode} = settings + {@resourcePath, initialPaths, pathToOpen, locationsToOpen, @isSpec, @headless, @safeMode, @devMode} = settings locationsToOpen ?= [{pathToOpen}] if pathToOpen locationsToOpen ?= [] @@ -47,20 +47,15 @@ class AtomWindow loadSettings.safeMode ?= false loadSettings.atomHome = process.env.ATOM_HOME loadSettings.clearWindowState ?= false + loadSettings.initialPaths ?= [] + loadSettings.initialPaths.sort() # Only send to the first non-spec window created if @constructor.includeShellLoadTime and not @isSpec @constructor.includeShellLoadTime = false loadSettings.shellLoadTime ?= Date.now() - global.shellStartTime - loadSettings.initialPaths = - for {pathToOpen} in locationsToOpen when pathToOpen - if fs.statSyncNoException(pathToOpen).isFile?() - path.dirname(pathToOpen) - else - pathToOpen - - loadSettings.initialPaths.sort() + @browserWindow.loadSettings = loadSettings @browserWindow.once 'window:loaded', => @emit 'window:loaded' From 64ed1a0e43aa30f03504755739b8c10d6f6fbbc8 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 2 Mar 2016 17:00:27 -0700 Subject: [PATCH 108/273] Populate initialPaths based on pathsToOpen if not specified This ensures that we deserialize projects correctly when specifying command line arguments. --- src/browser/atom-window.coffee | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index 24730c944..33c64da7d 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -47,7 +47,13 @@ class AtomWindow loadSettings.safeMode ?= false loadSettings.atomHome = process.env.ATOM_HOME loadSettings.clearWindowState ?= false - loadSettings.initialPaths ?= [] + loadSettings.initialPaths ?= + for {pathToOpen} in locationsToOpen when pathToOpen + if fs.statSyncNoException(pathToOpen).isFile?() + path.dirname(pathToOpen) + else + pathToOpen + loadSettings.initialPaths.sort() # Only send to the first non-spec window created From 2bdf4be904ceecbb974d13930285fa4eb6a87db4 Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Wed, 2 Mar 2016 16:56:06 -0800 Subject: [PATCH 109/273] :arrow_up: atom-package-manager Signed-off-by: Katrina Uychaco --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 2e6b0b8ea..4b599bc39 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "1.6.0" + "atom-package-manager": "1.7.1" } } From db20cecfc08b262aad2ca01e98d7e5943007d2ec Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 3 Mar 2016 09:59:45 -0500 Subject: [PATCH 110/273] s/ignoreInvisibles/showInvisibles --- spec/text-editor-spec.coffee | 4 ++-- src/text-editor.coffee | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index c75084fd5..637244964 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5829,11 +5829,11 @@ describe "TextEditor", -> rangeIsReversed: false } - describe "when the editor is constructed with the ignoreInvisibles option set to true", -> + describe "when the editor is constructed with the showInvisibles option set to false", -> beforeEach -> atom.workspace.destroyActivePane() waitsForPromise -> - atom.workspace.open('sample.js', ignoreInvisibles: true).then (o) -> editor = o + atom.workspace.open('sample.js', showInvisibles: false).then (o) -> editor = o it "ignores invisibles even if editor.showInvisibles is true", -> atom.config.set('editor.showInvisibles', true) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 6ce96088b..6eeb2cff5 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -100,7 +100,7 @@ class TextEditor extends Model softWrapped, @displayBuffer, @selectionsMarkerLayer, buffer, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode, @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, - @project, @assert, @applicationDelegate, grammarName, ignoreInvisibles, @autoHeight, @ignoreScrollPastEnd + @project, @assert, @applicationDelegate, grammarName, showInvisibles, @autoHeight, @ignoreScrollPastEnd } = params throw new Error("Must pass a config parameter when constructing TextEditors") unless @config? @@ -123,9 +123,11 @@ class TextEditor extends Model @ignoreScrollPastEnd ?= false @hasTerminatedPendingState = false + showInvisibles ?= true + buffer ?= new TextBuffer @displayBuffer ?= new DisplayBuffer({ - buffer, tabLength, softWrapped, ignoreInvisibles: @mini or ignoreInvisibles, largeFileMode, + buffer, tabLength, softWrapped, ignoreInvisibles: @mini or !showInvisibles, largeFileMode, @config, @assert, @grammarRegistry, @packageManager }) @buffer = @displayBuffer.buffer From 98c8a08ac3837dc59c00e77a913af5f1358f6a14 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 3 Mar 2016 10:06:15 -0500 Subject: [PATCH 111/273] s/ignoreScrollPastEnd/scrollPastEnd --- spec/text-editor-presenter-spec.coffee | 4 ++-- src/text-editor-component.coffee | 4 ++-- src/text-editor-element.coffee | 6 +++--- src/text-editor-presenter.coffee | 6 ++++-- src/text-editor.coffee | 8 ++++---- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 62d1e4747..f8117af09 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -647,8 +647,8 @@ describe "TextEditorPresenter", -> expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight - it "doesn't add the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true but ignoreScrollPastEnd is true", -> - presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10, ignoreScrollPastEnd: true) + it "doesn't add the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true but the presenter is created with scrollPastEnd as false", -> + presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10, scrollPastEnd: false) expectStateUpdate presenter, -> presenter.setScrollTop(300) expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 5a4097fc5..9b091100d 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -43,7 +43,7 @@ class TextEditorComponent @assert domNode?, "TextEditorComponent::domNode was set to null." @domNodeValue = domNode - constructor: ({@editor, @hostElement, @rootElement, @stylesElement, @useShadowDOM, tileSize, @views, @themes, @config, @workspace, @assert, @grammars, ignoreScrollPastEnd}) -> + constructor: ({@editor, @hostElement, @rootElement, @stylesElement, @useShadowDOM, tileSize, @views, @themes, @config, @workspace, @assert, @grammars, scrollPastEnd}) -> @tileSize = tileSize if tileSize? @disposables = new CompositeDisposable @@ -61,7 +61,7 @@ class TextEditorComponent stoppedScrollingDelay: 200 config: @config lineTopIndex: lineTopIndex - ignoreScrollPastEnd: ignoreScrollPastEnd + scrollPastEnd: scrollPastEnd @presenter.onDidUpdateState(@requestUpdate) diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 02f688e2c..df13f2a15 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -17,7 +17,7 @@ class TextEditorElement extends HTMLElement focusOnAttach: false hasTiledRendering: true logicalDisplayBuffer: true - ignoreScrollPastEnd: false + scrollPastEnd: true createdCallback: -> # Use globals when the following instance variables aren't set. @@ -90,7 +90,7 @@ class TextEditorElement extends HTMLElement @subscriptions.add @component.onDidChangeScrollLeft => @emitter.emit("did-change-scroll-left", arguments...) - initialize: (model, {@views, @config, @themes, @workspace, @assert, @styles, @grammars}, @autoHeight = true, @ignoreScrollPastEnd = false) -> + initialize: (model, {@views, @config, @themes, @workspace, @assert, @styles, @grammars}, @autoHeight = true, @scrollPastEnd = true) -> throw new Error("Must pass a config parameter when initializing TextEditorElements") unless @views? throw new Error("Must pass a config parameter when initializing TextEditorElements") unless @config? throw new Error("Must pass a themes parameter when initializing TextEditorElements") unless @themes? @@ -147,7 +147,7 @@ class TextEditorElement extends HTMLElement workspace: @workspace assert: @assert grammars: @grammars - ignoreScrollPastEnd: @ignoreScrollPastEnd + scrollPastEnd: @scrollPastEnd ) @rootElement.appendChild(@component.getDomNode()) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 0db175c2b..1fa662c59 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -13,7 +13,7 @@ class TextEditorPresenter minimumReflowInterval: 200 constructor: (params) -> - {@model, @config, @lineTopIndex, @ignoreScrollPastEnd} = params + {@model, @config, @lineTopIndex, scrollPastEnd} = params {@cursorBlinkPeriod, @cursorBlinkResumeDelay, @stoppedScrollingDelay, @tileSize} = params {@contentFrameWidth} = params @@ -42,6 +42,8 @@ class TextEditorPresenter @startReflowing() if @continuousReflow @updating = false + @scrollPastEndOverride = scrollPastEnd || true + setLinesYardstick: (@linesYardstick) -> getLinesYardstick: -> @linesYardstick @@ -661,7 +663,7 @@ class TextEditorPresenter return unless @contentHeight? and @clientHeight? contentHeight = @contentHeight - if @scrollPastEnd and not @ignoreScrollPastEnd + if @scrollPastEnd and @scrollPastEndOverride extraScrollHeight = @clientHeight - (@lineHeight * 3) contentHeight += extraScrollHeight if extraScrollHeight > 0 scrollHeight = Math.max(contentHeight, @height) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 6eeb2cff5..54ea283e9 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -100,7 +100,7 @@ class TextEditor extends Model softWrapped, @displayBuffer, @selectionsMarkerLayer, buffer, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode, @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, - @project, @assert, @applicationDelegate, grammarName, showInvisibles, @autoHeight, @ignoreScrollPastEnd + @project, @assert, @applicationDelegate, grammarName, showInvisibles, @autoHeight, @scrollPastEnd } = params throw new Error("Must pass a config parameter when constructing TextEditors") unless @config? @@ -120,7 +120,7 @@ class TextEditor extends Model @cursorsByMarkerId = new Map @selections = [] @autoHeight ?= true - @ignoreScrollPastEnd ?= false + @scrollPastEnd ?= true @hasTerminatedPendingState = false showInvisibles ?= true @@ -3156,7 +3156,7 @@ class TextEditor extends Model # Get the Element for the editor. getElement: -> - @editorElement ?= new TextEditorElement().initialize(this, atom, @autoHeight, @ignoreScrollPastEnd) + @editorElement ?= new TextEditorElement().initialize(this, atom, @autoHeight, @scrollPastEnd) # Essential: Retrieves the greyed out placeholder of a mini editor. # @@ -3232,7 +3232,7 @@ class TextEditor extends Model setFirstVisibleScreenRow: (screenRow, fromView) -> unless fromView maxScreenRow = @getScreenLineCount() - 1 - unless @config.get('editor.scrollPastEnd') and not @ignoreScrollPastEnd + unless @config.get('editor.scrollPastEnd') and @scrollPastEnd height = @displayBuffer.getHeight() lineHeightInPixels = @displayBuffer.getLineHeightInPixels() if height? and lineHeightInPixels? From 928205a44ae7b18d7257a6853e34e33d5ed562c9 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 3 Mar 2016 10:09:18 -0500 Subject: [PATCH 112/273] s/grammarName/grammar --- spec/text-editor-spec.coffee | 4 ++-- src/text-editor.coffee | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 637244964..9d2a2a58c 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5840,14 +5840,14 @@ describe "TextEditor", -> invisibles = editor.tokenizedLineForScreenRow(0).invisibles expect(invisibles).toBe(null) - describe "when the editor is constructed with the grammarName option set", -> + describe "when the editor is constructed with the grammar option set", -> beforeEach -> atom.workspace.destroyActivePane() waitsForPromise -> atom.packages.activatePackage('language-coffee-script') waitsForPromise -> - atom.workspace.open('sample.js', grammarName: 'source.coffee').then (o) -> editor = o + atom.workspace.open('sample.js', grammar: atom.grammars.grammarForScopeName('source.coffee')).then (o) -> editor = o it "sets the grammar", -> expect(editor.getGrammar().name).toBe 'CoffeeScript' diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 54ea283e9..b981dcbb2 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -100,7 +100,7 @@ class TextEditor extends Model softWrapped, @displayBuffer, @selectionsMarkerLayer, buffer, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode, @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, - @project, @assert, @applicationDelegate, grammarName, showInvisibles, @autoHeight, @scrollPastEnd + @project, @assert, @applicationDelegate, grammar, showInvisibles, @autoHeight, @scrollPastEnd } = params throw new Error("Must pass a config parameter when constructing TextEditors") unless @config? @@ -156,8 +156,8 @@ class TextEditor extends Model priority: 0 visible: lineNumberGutterVisible - if grammarName? - @setGrammar(@grammarRegistry.grammarForScopeName(grammarName)) + if grammar? + @setGrammar(grammar) serialize: -> deserializer: 'TextEditor' From 10acfd057fbf994fe2ddd5dd12d66b7dba5cee94 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 3 Mar 2016 10:13:26 -0500 Subject: [PATCH 113/273] Err, yeah, we care about undefined, not false. --- src/text-editor-presenter.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 1fa662c59..ef1b403c3 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -42,7 +42,7 @@ class TextEditorPresenter @startReflowing() if @continuousReflow @updating = false - @scrollPastEndOverride = scrollPastEnd || true + @scrollPastEndOverride = scrollPastEnd ? true setLinesYardstick: (@linesYardstick) -> From dba1fbd40845304960b447bf0fc3c15a3ad2ef71 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 3 Mar 2016 10:15:13 -0500 Subject: [PATCH 114/273] De-lint. --- 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 b981dcbb2..d5937d307 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -127,7 +127,7 @@ class TextEditor extends Model buffer ?= new TextBuffer @displayBuffer ?= new DisplayBuffer({ - buffer, tabLength, softWrapped, ignoreInvisibles: @mini or !showInvisibles, largeFileMode, + buffer, tabLength, softWrapped, ignoreInvisibles: @mini or not showInvisibles, largeFileMode, @config, @assert, @grammarRegistry, @packageManager }) @buffer = @displayBuffer.buffer From a218582aeb3186d4237bd3a4341e5b621b5d2c3b Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 3 Mar 2016 18:02:08 -0700 Subject: [PATCH 115/273] =?UTF-8?q?Supply=20pathsToOpen=20in=20case=20ther?= =?UTF-8?q?e=E2=80=99s=20no=20window=20state?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/browser/atom-application.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index b2d66af87..230e1bb9f 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -513,6 +513,7 @@ class AtomApplication for state in states @openWithOptions(_.extend(options, { initialPaths: state.initialPaths + pathsToOpen: state.initialPaths.filter (directoryPath) -> fs.isDirectorySync(directoryPath) urlsToOpen: [] devMode: @devMode safeMode: @safeMode From e620232d355b81afcf2c9607314c3600198bab0b Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 3 Mar 2016 17:46:02 -0800 Subject: [PATCH 116/273] Add new item before destroying pending item Fixes atom/tabs#278 Signed-off-by: Michelle Tilley --- spec/pane-spec.coffee | 30 +++++++++++++++++++++++++++--- src/pane.coffee | 4 ++-- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/spec/pane-spec.coffee b/spec/pane-spec.coffee index 888ccf6e2..873749a19 100644 --- a/spec/pane-spec.coffee +++ b/spec/pane-spec.coffee @@ -132,13 +132,37 @@ describe "Pane", -> expect(-> pane.addItem('foo')).toThrow() expect(-> pane.addItem(1)).toThrow() - it "destroys any existing pending item if the new item is pending", -> + it "destroys any existing pending item", -> + pane = new Pane(paneParams(items: [])) + itemA = new Item("A") + itemB = new Item("B") + itemC = new Item("C") + pane.addItem(itemA, undefined, false, false) + pane.addItem(itemB, undefined, false, true) + pane.addItem(itemC, undefined, false, false) + expect(itemB.isDestroyed()).toBe true + + it "adds the new item before destroying any existing pending item", -> + eventOrder = [] + pane = new Pane(paneParams(items: [])) itemA = new Item("A") itemB = new Item("B") pane.addItem(itemA, undefined, false, true) - pane.addItem(itemB, undefined, false, true) - expect(itemA.isDestroyed()).toBe true + + pane.onDidAddItem ({item}) -> + eventOrder.push("add") if item is itemB + + pane.onDidRemoveItem ({item}) -> + eventOrder.push("remove") if item is itemA + + pane.addItem(itemB) + + waitsFor -> + eventOrder.length is 2 + + runs -> + expect(eventOrder).toEqual ["add", "remove"] describe "::activateItem(item)", -> pane = null diff --git a/src/pane.coffee b/src/pane.coffee index b944f763c..70f8b4bab 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -433,11 +433,11 @@ class Pane extends Model @subscriptionsPerItem.set item, itemSubscriptions @items.splice(index, 0, item) - pendingItem = @getPendingItem() - @destroyItem(pendingItem) if pendingItem? + lastPendingItem = @getPendingItem() @setPendingItem(item) if pending @emitter.emit 'did-add-item', {item, index, moved} + @destroyItem(lastPendingItem) if lastPendingItem? @setActiveItem(item) unless @getActiveItem()? item From 4d9e2b865b1f136bd1400eb3c67cb98dfc7571f2 Mon Sep 17 00:00:00 2001 From: Damien Guard Date: Thu, 3 Mar 2016 20:03:44 -0800 Subject: [PATCH 117/273] Ensure atom.cmd --wait correctly waits in Windows cmd & powershell --- resources/win/atom.cmd | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/resources/win/atom.cmd b/resources/win/atom.cmd index 8d5e6f97a..a1af5cd53 100644 --- a/resources/win/atom.cmd +++ b/resources/win/atom.cmd @@ -22,30 +22,13 @@ FOR %%a IN (%*) DO ( ) ) -rem Getting the process ID in cmd of the current cmd process: http://superuser.com/questions/881789/identify-and-kill-batch-script-started-before -set T=%TEMP%\atomCmdProcessId-%time::=%.tmp -wmic process where (Name="WMIC.exe" AND CommandLine LIKE "%%%TIME%%%") get ParentProcessId /value | find "ParentProcessId" >%T% -set /P A=<%T% -set PID=%A:~16% -del %T% - IF "%EXPECT_OUTPUT%"=="YES" ( SET ELECTRON_ENABLE_LOGGING=YES IF "%WAIT%"=="YES" ( - "%~dp0\..\..\atom.exe" --pid=%PID% %* - rem If the wait flag is set, don't exit this process until Atom tells it to. - goto waitLoop + powershell -noexit "%~dp0\..\..\atom.exe" --pid=$pid %* ; wait-event ) ELSE ( "%~dp0\..\..\atom.exe" %* ) ) ELSE ( "%~dp0\..\app\apm\bin\node.exe" "%~dp0\atom.js" %* ) - -goto end - -:waitLoop - sleep 1 - goto waitLoop - -:end From 1043dc083982c63a23d8d13f7653e34bd4453c50 Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Thu, 3 Mar 2016 22:43:19 -0800 Subject: [PATCH 118/273] :arrow_up: bracket-matcher@0.81.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8907f16b9..f4c6475be 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "autosave": "0.23.1", "background-tips": "0.26.0", "bookmarks": "0.38.2", - "bracket-matcher": "0.80.1", + "bracket-matcher": "0.81.0", "command-palette": "0.38.0", "deprecation-cop": "0.54.1", "dev-live-reload": "0.47.0", From 7176da7614fb3b457497e639908795948df5dc64 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 4 Mar 2016 15:17:10 +0100 Subject: [PATCH 119/273] Use structured cloning --- src/state-store.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/state-store.js b/src/state-store.js index 13c9a0462..a2d3b476b 100644 --- a/src/state-store.js +++ b/src/state-store.js @@ -24,16 +24,13 @@ class StateStore { } save (key, value) { - // Serialize values using JSON.stringify, as it seems way faster than IndexedDB structured clone. - // (Ref.: https://bugs.chromium.org/p/chromium/issues/detail?id=536620) - let jsonValue = JSON.stringify(value) return new Promise((resolve, reject) => { this.dbPromise.then(db => { if (db == null) resolve() var request = db.transaction(['states'], 'readwrite') .objectStore('states') - .put({value: jsonValue, storedAt: new Date().toString(), isJSON: true}, key) + .put({value: value, storedAt: new Date().toString()}, key) request.onsuccess = resolve request.onerror = reject @@ -52,9 +49,8 @@ class StateStore { request.onsuccess = (event) => { let result = event.target.result - if (result) { - // TODO: remove this when state will be serialized only via JSON. - resolve(result.isJSON ? JSON.parse(result.value) : result.value) + if (result && !result.isJSON) { + resolve(result.value) } else { resolve(null) } From 011fe380e9727a0f0d49230e15da25fa506835a3 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 4 Mar 2016 16:57:02 +0100 Subject: [PATCH 120/273] Pass markerLayer: false to buffer.serialize when not quitting --- spec/project-spec.coffee | 25 +++++++++++++++++++++---- src/project.coffee | 8 ++++---- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 9d42f9a7e..cecfe4bd4 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -29,7 +29,7 @@ describe "Project", -> expect(atom.project.getBuffers().length).toBe 1 deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) - deserializedProject.deserialize(atom.project.serialize(), atom.deserializers) + deserializedProject.deserialize(atom.project.serialize()) expect(deserializedProject.getBuffers().length).toBe 0 it "listens for destroyed events on deserialized buffers and removes them when they are destroyed", -> @@ -39,7 +39,7 @@ describe "Project", -> runs -> expect(atom.project.getBuffers().length).toBe 1 deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) - deserializedProject.deserialize(atom.project.serialize(), atom.deserializers) + deserializedProject.deserialize(atom.project.serialize()) expect(deserializedProject.getBuffers().length).toBe 1 deserializedProject.getBuffers()[0].destroy() @@ -56,7 +56,7 @@ describe "Project", -> expect(atom.project.getBuffers().length).toBe 1 fs.mkdirSync(pathToOpen) deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) - deserializedProject.deserialize(atom.project.serialize(), atom.deserializers) + deserializedProject.deserialize(atom.project.serialize()) expect(deserializedProject.getBuffers().length).toBe 0 it "does not deserialize buffers when their path is inaccessible", -> @@ -70,9 +70,26 @@ describe "Project", -> expect(atom.project.getBuffers().length).toBe 1 fs.chmodSync(pathToOpen, '000') deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) - deserializedProject.deserialize(atom.project.serialize(), atom.deserializers) + deserializedProject.deserialize(atom.project.serialize()) expect(deserializedProject.getBuffers().length).toBe 0 + it "serializes marker / marker only if Atom is quitting", -> + waitsForPromise -> + atom.workspace.open('a') + + runs -> + bufferA = atom.project.getBuffers()[0] + layerA = bufferA.addMarkerLayer(maintainHistory: true) + markerA = layerA.markPosition([0, 3]) + + notQuittingProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) + notQuittingProject.deserialize(atom.project.serialize({isQuitting: false})) + expect(notQuittingProject.getBuffers()[0].getMarkerLayer(layerA.id)?.getMarker(markerA.id)).toBeUndefined() + + quittingProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) + quittingProject.deserialize(atom.project.serialize({isQuitting: true})) + expect(quittingProject.getBuffers()[0].getMarkerLayer(layerA.id)?.getMarker(markerA.id)).not.toBeUndefined() + describe "when an editor is saved and the project has no path", -> it "sets the project's path to the saved file's parent directory", -> tempFile = temp.openSync().path diff --git a/src/project.coffee b/src/project.coffee index 008d81e3e..538c4acb4 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -54,7 +54,7 @@ class Project extends Model Section: Serialization ### - deserialize: (state, deserializerManager) -> + deserialize: (state) -> state.paths = [state.path] if state.path? # backward compatibility @buffers = _.compact state.buffers.map (bufferState) -> @@ -65,15 +65,15 @@ class Project extends Model fs.closeSync(fs.openSync(bufferState.filePath, 'r')) catch error return unless error.code is 'ENOENT' - deserializerManager.deserialize(bufferState) + TextBuffer.deserialize(bufferState) @subscribeToBuffer(buffer) for buffer in @buffers @setPaths(state.paths) - serialize: -> + serialize: (options) -> deserializer: 'Project' paths: @getPaths() - buffers: _.compact(@buffers.map (buffer) -> buffer.serialize() if buffer.isRetained()) + buffers: _.compact(@buffers.map (buffer) -> buffer.serialize({markerLayers: options.isQuitting is true}) if buffer.isRetained()) ### Section: Event Subscription From 311cde36c963ee85c9bc011baf38061cd7b01212 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 4 Mar 2016 17:06:53 +0100 Subject: [PATCH 121/273] Call saveState(isQuitting: true) on beforeUnload --- spec/window-event-handler-spec.coffee | 5 +++++ src/window-event-handler.coffee | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/spec/window-event-handler-spec.coffee b/spec/window-event-handler-spec.coffee index bb7e1665b..b9f102c3f 100644 --- a/spec/window-event-handler-spec.coffee +++ b/spec/window-event-handler-spec.coffee @@ -55,6 +55,11 @@ describe "WindowEventHandler", -> jasmine.unspy(TextEditor.prototype, "shouldPromptToSave") spyOn(ipcRenderer, 'send') + it "saves AtomEnvironment's state with the {isQuitting: true} option", -> + spyOn(atom, 'saveState') + window.dispatchEvent(new CustomEvent('beforeunload')) + expect(atom.saveState).toHaveBeenCalledWith({isQuitting: true}) + describe "when pane items are modified", -> editor = null beforeEach -> diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee index ce08344c6..10bebbf1e 100644 --- a/src/window-event-handler.coffee +++ b/src/window-event-handler.coffee @@ -143,7 +143,7 @@ class WindowEventHandler @reloadRequested = false @atomEnvironment.storeWindowDimensions() - @atomEnvironment.saveState() + @atomEnvironment.saveState({isQuitting: true}) if confirmed @atomEnvironment.unloadEditorWindow() else From 0fdc19098936aed7597425352f19e8a1726ae046 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 4 Mar 2016 17:08:32 +0100 Subject: [PATCH 122/273] Use isQuitting: false when saving state on key/mouse down --- spec/atom-environment-spec.coffee | 4 ++-- src/atom-environment.coffee | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index 1f8eb08e7..d8d700dd7 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -185,12 +185,12 @@ describe "AtomEnvironment", -> keydown = new KeyboardEvent('keydown') atom.document.dispatchEvent(keydown) advanceClock atom.saveStateDebounceInterval - expect(atom.saveState).toHaveBeenCalled() + expect(atom.saveState).toHaveBeenCalledWith({isQuitting: false}) mousedown = new MouseEvent('mousedown') atom.document.dispatchEvent(mousedown) advanceClock atom.saveStateDebounceInterval - expect(atom.saveState).toHaveBeenCalled() + expect(atom.saveState).toHaveBeenCalledWith({isQuitting: false}) describe "openInitialEmptyEditorIfNecessary", -> describe "when there are no paths set", -> diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 0ee12fe93..983148ca4 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -225,7 +225,7 @@ class AtomEnvironment extends Model checkPortableHomeWritable() attachSaveStateListeners: -> - debouncedSaveState = _.debounce((=> @saveState()), @saveStateDebounceInterval) + debouncedSaveState = _.debounce((=> @saveState({isQuitting: false})), @saveStateDebounceInterval) @document.addEventListener('mousedown', debouncedSaveState, true) @document.addEventListener('keydown', debouncedSaveState, true) @disposables.add new Disposable => From 3bdb83f97ec1018749695313e3c8a38da1f6a5af Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 4 Mar 2016 17:11:34 +0100 Subject: [PATCH 123/273] Pass saveState options to project.serialize --- src/atom-environment.coffee | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 983148ca4..748e73ef9 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -670,9 +670,9 @@ class AtomEnvironment extends Model @openInitialEmptyEditorIfNecessary() - serialize: -> + serialize: (options) -> version: @constructor.version - project: @project.serialize() + project: @project.serialize(options) workspace: @workspace.serialize() packageStates: @packages.serialize() grammars: {grammarOverridesByPath: @grammars.grammarOverridesByPath} @@ -817,9 +817,12 @@ class AtomEnvironment extends Model @blobStore.save() - saveState: -> + saveState: (options) -> return Promise.resolve() unless @enablePersistence + options ?= {} + options.isQuitting ?= false + new Promise (resolve, reject) => window.requestIdleCallback => state = @serialize() From 41c293ef9d79e5ae1d1268e8cf932d59c5664f9d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 4 Mar 2016 17:23:19 +0100 Subject: [PATCH 124/273] Always pass {isQuitting} in tests --- spec/git-repository-async-spec.js | 2 +- spec/git-spec.coffee | 2 +- spec/project-spec.coffee | 8 ++++---- spec/workspace-spec.coffee | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/git-repository-async-spec.js b/spec/git-repository-async-spec.js index fa5b0d711..80ba2ebb1 100644 --- a/spec/git-repository-async-spec.js +++ b/spec/git-repository-async-spec.js @@ -541,7 +541,7 @@ describe('GitRepositoryAsync', () => { await atom.workspace.open('file.txt') project2 = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) - project2.deserialize(atom.project.serialize(), atom.deserializers) + project2.deserialize(atom.project.serialize({isQuitting: true})) const repo = project2.getRepositories()[0].async waitsForPromise(() => repo.refreshStatus()) diff --git a/spec/git-spec.coffee b/spec/git-spec.coffee index 22c40c19a..9124f78cc 100644 --- a/spec/git-spec.coffee +++ b/spec/git-spec.coffee @@ -347,7 +347,7 @@ describe "GitRepository", -> runs -> project2 = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) - project2.deserialize(atom.project.serialize(), atom.deserializers) + project2.deserialize(atom.project.serialize({isQuitting: false})) buffer = project2.getBuffers()[0] waitsFor -> diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index cecfe4bd4..9a392dd62 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -29,7 +29,7 @@ describe "Project", -> expect(atom.project.getBuffers().length).toBe 1 deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) - deserializedProject.deserialize(atom.project.serialize()) + deserializedProject.deserialize(atom.project.serialize({isQuitting: false})) expect(deserializedProject.getBuffers().length).toBe 0 it "listens for destroyed events on deserialized buffers and removes them when they are destroyed", -> @@ -39,7 +39,7 @@ describe "Project", -> runs -> expect(atom.project.getBuffers().length).toBe 1 deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) - deserializedProject.deserialize(atom.project.serialize()) + deserializedProject.deserialize(atom.project.serialize({isQuitting: false})) expect(deserializedProject.getBuffers().length).toBe 1 deserializedProject.getBuffers()[0].destroy() @@ -56,7 +56,7 @@ describe "Project", -> expect(atom.project.getBuffers().length).toBe 1 fs.mkdirSync(pathToOpen) deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) - deserializedProject.deserialize(atom.project.serialize()) + deserializedProject.deserialize(atom.project.serialize({isQuitting: false})) expect(deserializedProject.getBuffers().length).toBe 0 it "does not deserialize buffers when their path is inaccessible", -> @@ -70,7 +70,7 @@ describe "Project", -> expect(atom.project.getBuffers().length).toBe 1 fs.chmodSync(pathToOpen, '000') deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) - deserializedProject.deserialize(atom.project.serialize()) + deserializedProject.deserialize(atom.project.serialize({isQuitting: false})) expect(deserializedProject.getBuffers().length).toBe 0 it "serializes marker / marker only if Atom is quitting", -> diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 2e15431b2..214fc477f 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -22,11 +22,11 @@ describe "Workspace", -> describe "serialization", -> simulateReload = -> workspaceState = atom.workspace.serialize() - projectState = atom.project.serialize() + projectState = atom.project.serialize({isQuitting: true}) atom.workspace.destroy() atom.project.destroy() atom.project = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm.bind(atom)}) - atom.project.deserialize(projectState, atom.deserializers) + atom.project.deserialize(projectState) atom.workspace = new Workspace({ config: atom.config, project: atom.project, packageManager: atom.packages, grammarRegistry: atom.grammars, deserializerManager: atom.deserializers, From 575065f3e92aadc944d3c749ae834bd8f22fa5c2 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 4 Mar 2016 17:37:53 +0100 Subject: [PATCH 125/273] Don't forget to pass the option during saveState --- src/atom-environment.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 748e73ef9..40cbe0089 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -825,7 +825,7 @@ class AtomEnvironment extends Model new Promise (resolve, reject) => window.requestIdleCallback => - state = @serialize() + state = @serialize(options) savePromise = if storageKey = @getStateKey(@project?.getPaths()) @stateStore.save(storageKey, state) From 046cdddefe58db79c7deafdc180ce40697a6bfe4 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 4 Mar 2016 17:53:14 +0100 Subject: [PATCH 126/273] :memo: --- spec/project-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 9a392dd62..0c76ad9bb 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -73,7 +73,7 @@ describe "Project", -> deserializedProject.deserialize(atom.project.serialize({isQuitting: false})) expect(deserializedProject.getBuffers().length).toBe 0 - it "serializes marker / marker only if Atom is quitting", -> + it "serializes marker layers only if Atom is quitting", -> waitsForPromise -> atom.workspace.open('a') From d9ee94031f31abccfdda23d528f8f42ded48fbf0 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 4 Mar 2016 13:40:16 -0700 Subject: [PATCH 127/273] Test disposal of manually-created tooltips This also prevents subsequent tests from failing due to the manual tooltip never being removed from document.body. --- spec/tooltip-manager-spec.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/tooltip-manager-spec.coffee b/spec/tooltip-manager-spec.coffee index 264d1a3bb..d4bfc1bd6 100644 --- a/spec/tooltip-manager-spec.coffee +++ b/spec/tooltip-manager-spec.coffee @@ -29,8 +29,10 @@ describe "TooltipManager", -> expect(document.body.querySelector(".tooltip")).toHaveText("Title") it "creates a tooltip immediately if the trigger type is manual", -> - manager.add element, title: "Title", trigger: "manual" + disposable = manager.add element, title: "Title", trigger: "manual" expect(document.body.querySelector(".tooltip")).toHaveText("Title") + disposable.dispose() + expect(document.body.querySelector(".tooltip")).toBeNull() it "allows jQuery elements to be passed as the target", -> element2 = document.createElement('div') From 6cc80e05ff4a98512f0882912c446dfdb7d4027b Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 4 Mar 2016 16:36:47 -0500 Subject: [PATCH 128/273] Default to auto height being true. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise TextEditorElements created through the tag wouldn’t have a setting and be wrong. --- src/text-editor-element.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index df13f2a15..2a9b5e262 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -18,6 +18,7 @@ class TextEditorElement extends HTMLElement hasTiledRendering: true logicalDisplayBuffer: true scrollPastEnd: true + autoHeight: true createdCallback: -> # Use globals when the following instance variables aren't set. From b4f335d9a18ceb719fa47e1c2c54a43993e6d5aa Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 4 Mar 2016 17:01:26 -0700 Subject: [PATCH 129/273] :arrow_up: tree-view --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f4c6475be..6a5f47479 100644 --- a/package.json +++ b/package.json @@ -112,7 +112,7 @@ "symbols-view": "0.111.1", "tabs": "0.91.1", "timecop": "0.33.1", - "tree-view": "0.201.5", + "tree-view": "0.202.0", "update-package-dependencies": "0.10.0", "welcome": "0.34.0", "whitespace": "0.32.2", From 341afed0ab7e5c9fbccd69030dce6e77a4bb4e75 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Fri, 4 Mar 2016 19:40:00 -0500 Subject: [PATCH 130/273] :arrow_up: language-json@0.17.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6a5f47479..3a6d0910c 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "language-hyperlink": "0.16.0", "language-java": "0.17.0", "language-javascript": "0.110.0", - "language-json": "0.17.4", + "language-json": "0.17.5", "language-less": "0.29.0", "language-make": "0.21.0", "language-mustache": "0.13.0", From 42a696cf28f00b9cfe33107ea57e33c4e38ea3f4 Mon Sep 17 00:00:00 2001 From: Rodrigo Espinosa Curbelo Date: Sat, 5 Mar 2016 21:28:06 -0300 Subject: [PATCH 131/273] :bug: Scroll to cursor when unfold all Fixes #11066 --- src/text-editor.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index d5937d307..e858d8c80 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -2936,6 +2936,7 @@ class TextEditor extends Model # Extended: Unfold all existing folds. unfoldAll: -> @languageMode.unfoldAll() + @scrollToCursorPosition() # Extended: Fold all foldable lines at the given indent level. # From f88051e5e624f5519932a626d135e23dfa7449bd Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Sun, 6 Mar 2016 00:56:35 -0800 Subject: [PATCH 132/273] :arrow_up: find-and-replace (cherry picked from commit 2d5d0d21bde88fcc04b6b28ded6ad84b5a85fe39) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3a6d0910c..3a36478bd 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "dev-live-reload": "0.47.0", "encoding-selector": "0.21.0", "exception-reporting": "0.37.0", - "find-and-replace": "0.197.3", + "find-and-replace": "0.197.4", "fuzzy-finder": "1.0.2", "git-diff": "1.0.0", "go-to-line": "0.30.0", From 95dbbea8f536753c7952f231fe479f3cc7e74d20 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 7 Mar 2016 10:32:19 +0100 Subject: [PATCH 133/273] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1c55268dd..aa74e94f2 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "service-hub": "^0.7.0", "source-map-support": "^0.3.2", "temp": "0.8.1", - "text-buffer": "8.3.2", + "text-buffer": "8.4.0", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "yargs": "^3.23.0" From 12587073d2eca35079c860c8c42fcb9b2065f6e7 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 7 Mar 2016 10:52:16 +0100 Subject: [PATCH 134/273] :art: isQuitting -> isUnloading --- spec/atom-environment-spec.coffee | 4 ++-- spec/git-repository-async-spec.js | 2 +- spec/git-spec.coffee | 2 +- spec/project-spec.coffee | 12 ++++++------ spec/window-event-handler-spec.coffee | 4 ++-- spec/workspace-spec.coffee | 2 +- src/atom-environment.coffee | 4 ++-- src/project.coffee | 2 +- src/window-event-handler.coffee | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index 82a38942c..556312082 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -185,12 +185,12 @@ describe "AtomEnvironment", -> keydown = new KeyboardEvent('keydown') atom.document.dispatchEvent(keydown) advanceClock atom.saveStateDebounceInterval - expect(atom.saveState).toHaveBeenCalledWith({isQuitting: false}) + expect(atom.saveState).toHaveBeenCalledWith({isUnloading: false}) mousedown = new MouseEvent('mousedown') atom.document.dispatchEvent(mousedown) advanceClock atom.saveStateDebounceInterval - expect(atom.saveState).toHaveBeenCalledWith({isQuitting: false}) + expect(atom.saveState).toHaveBeenCalledWith({isUnloading: false}) describe "openInitialEmptyEditorIfNecessary", -> describe "when there are no paths set", -> diff --git a/spec/git-repository-async-spec.js b/spec/git-repository-async-spec.js index 80ba2ebb1..e7bffad3a 100644 --- a/spec/git-repository-async-spec.js +++ b/spec/git-repository-async-spec.js @@ -541,7 +541,7 @@ describe('GitRepositoryAsync', () => { await atom.workspace.open('file.txt') project2 = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) - project2.deserialize(atom.project.serialize({isQuitting: true})) + project2.deserialize(atom.project.serialize({isUnloading: true})) const repo = project2.getRepositories()[0].async waitsForPromise(() => repo.refreshStatus()) diff --git a/spec/git-spec.coffee b/spec/git-spec.coffee index 9124f78cc..3afd4da75 100644 --- a/spec/git-spec.coffee +++ b/spec/git-spec.coffee @@ -347,7 +347,7 @@ describe "GitRepository", -> runs -> project2 = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) - project2.deserialize(atom.project.serialize({isQuitting: false})) + project2.deserialize(atom.project.serialize({isUnloading: false})) buffer = project2.getBuffers()[0] waitsFor -> diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 7f13cda40..499efd017 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -37,7 +37,7 @@ describe "Project", -> expect(atom.project.getBuffers().length).toBe 1 deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) - deserializedProject.deserialize(atom.project.serialize({isQuitting: false})) + deserializedProject.deserialize(atom.project.serialize({isUnloading: false})) expect(deserializedProject.getBuffers().length).toBe 0 it "listens for destroyed events on deserialized buffers and removes them when they are destroyed", -> @@ -47,7 +47,7 @@ describe "Project", -> runs -> expect(atom.project.getBuffers().length).toBe 1 deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) - deserializedProject.deserialize(atom.project.serialize({isQuitting: false})) + deserializedProject.deserialize(atom.project.serialize({isUnloading: false})) expect(deserializedProject.getBuffers().length).toBe 1 deserializedProject.getBuffers()[0].destroy() @@ -64,7 +64,7 @@ describe "Project", -> expect(atom.project.getBuffers().length).toBe 1 fs.mkdirSync(pathToOpen) deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) - deserializedProject.deserialize(atom.project.serialize({isQuitting: false})) + deserializedProject.deserialize(atom.project.serialize({isUnloading: false})) expect(deserializedProject.getBuffers().length).toBe 0 it "does not deserialize buffers when their path is inaccessible", -> @@ -78,7 +78,7 @@ describe "Project", -> expect(atom.project.getBuffers().length).toBe 1 fs.chmodSync(pathToOpen, '000') deserializedProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) - deserializedProject.deserialize(atom.project.serialize({isQuitting: false})) + deserializedProject.deserialize(atom.project.serialize({isUnloading: false})) expect(deserializedProject.getBuffers().length).toBe 0 it "serializes marker layers only if Atom is quitting", -> @@ -91,11 +91,11 @@ describe "Project", -> markerA = layerA.markPosition([0, 3]) notQuittingProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) - notQuittingProject.deserialize(atom.project.serialize({isQuitting: false})) + notQuittingProject.deserialize(atom.project.serialize({isUnloading: false})) expect(notQuittingProject.getBuffers()[0].getMarkerLayer(layerA.id)?.getMarker(markerA.id)).toBeUndefined() quittingProject = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm}) - quittingProject.deserialize(atom.project.serialize({isQuitting: true})) + quittingProject.deserialize(atom.project.serialize({isUnloading: true})) expect(quittingProject.getBuffers()[0].getMarkerLayer(layerA.id)?.getMarker(markerA.id)).not.toBeUndefined() describe "when an editor is saved and the project has no path", -> diff --git a/spec/window-event-handler-spec.coffee b/spec/window-event-handler-spec.coffee index b9f102c3f..7f093aeff 100644 --- a/spec/window-event-handler-spec.coffee +++ b/spec/window-event-handler-spec.coffee @@ -55,10 +55,10 @@ describe "WindowEventHandler", -> jasmine.unspy(TextEditor.prototype, "shouldPromptToSave") spyOn(ipcRenderer, 'send') - it "saves AtomEnvironment's state with the {isQuitting: true} option", -> + it "saves AtomEnvironment's state with the {isUnloading: true} option", -> spyOn(atom, 'saveState') window.dispatchEvent(new CustomEvent('beforeunload')) - expect(atom.saveState).toHaveBeenCalledWith({isQuitting: true}) + expect(atom.saveState).toHaveBeenCalledWith({isUnloading: true}) describe "when pane items are modified", -> editor = null diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index bf24f25cf..38d4839b0 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -22,7 +22,7 @@ describe "Workspace", -> describe "serialization", -> simulateReload = -> workspaceState = atom.workspace.serialize() - projectState = atom.project.serialize({isQuitting: true}) + projectState = atom.project.serialize({isUnloading: true}) atom.workspace.destroy() atom.project.destroy() atom.project = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm.bind(atom)}) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 2db72270c..f546fd63d 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -230,7 +230,7 @@ class AtomEnvironment extends Model checkPortableHomeWritable() attachSaveStateListeners: -> - debouncedSaveState = _.debounce((=> @saveState({isQuitting: false})), @saveStateDebounceInterval) + debouncedSaveState = _.debounce((=> @saveState({isUnloading: false})), @saveStateDebounceInterval) @document.addEventListener('mousedown', debouncedSaveState, true) @document.addEventListener('keydown', debouncedSaveState, true) @disposables.add new Disposable => @@ -835,7 +835,7 @@ class AtomEnvironment extends Model return Promise.resolve() unless @enablePersistence options ?= {} - options.isQuitting ?= false + options.isUnloading ?= false new Promise (resolve, reject) => window.requestIdleCallback => diff --git a/src/project.coffee b/src/project.coffee index d6d36e644..5f3420b08 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -74,7 +74,7 @@ class Project extends Model serialize: (options) -> deserializer: 'Project' paths: @getPaths() - buffers: _.compact(@buffers.map (buffer) -> buffer.serialize({markerLayers: options.isQuitting is true}) if buffer.isRetained()) + buffers: _.compact(@buffers.map (buffer) -> buffer.serialize({markerLayers: options.isUnloading is true}) if buffer.isRetained()) ### Section: Event Subscription diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee index 10bebbf1e..490b2b416 100644 --- a/src/window-event-handler.coffee +++ b/src/window-event-handler.coffee @@ -143,7 +143,7 @@ class WindowEventHandler @reloadRequested = false @atomEnvironment.storeWindowDimensions() - @atomEnvironment.saveState({isQuitting: true}) + @atomEnvironment.saveState({isUnloading: true}) if confirmed @atomEnvironment.unloadEditorWindow() else From 914015e4ebf9ba6fff1bbac816662fd46c71dc99 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 7 Mar 2016 10:52:28 +0100 Subject: [PATCH 135/273] :fire: Remove default parameters --- src/atom-environment.coffee | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index f546fd63d..f99ec3bcc 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -834,9 +834,6 @@ class AtomEnvironment extends Model saveState: (options) -> return Promise.resolve() unless @enablePersistence - options ?= {} - options.isUnloading ?= false - new Promise (resolve, reject) => window.requestIdleCallback => state = @serialize(options) From 4f9bc0c06ba7bc115b09a4ed0899e407bf0206bd Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 7 Mar 2016 11:45:54 +0100 Subject: [PATCH 136/273] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2c517fedd..ff30c0d07 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "service-hub": "^0.7.0", "source-map-support": "^0.3.2", "temp": "0.8.1", - "text-buffer": "8.4.0", + "text-buffer": "8.4.1", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "yargs": "^3.23.0" From a3bed908d7ca5b58bf61c8b9c3381d7f04c62a24 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 7 Mar 2016 16:58:03 +0100 Subject: [PATCH 137/273] Don't partially serialize after unloading editor window --- spec/atom-environment-spec.coffee | 11 ++++++++++- spec/window-event-handler-spec.coffee | 5 ----- src/atom-environment.coffee | 8 +++++++- src/window-event-handler.coffee | 1 - 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index 556312082..8e7af40d5 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -179,7 +179,7 @@ describe "AtomEnvironment", -> atom.loadState().then (state) -> expect(state).toEqual({stuff: 'cool'}) - it "saves state on keydown and mousedown events", -> + it "saves state on keydown and mousedown events when the editor window hasn't been unloaded", -> spyOn(atom, 'saveState') keydown = new KeyboardEvent('keydown') @@ -187,11 +187,20 @@ describe "AtomEnvironment", -> advanceClock atom.saveStateDebounceInterval expect(atom.saveState).toHaveBeenCalledWith({isUnloading: false}) + atom.saveState.reset() mousedown = new MouseEvent('mousedown') atom.document.dispatchEvent(mousedown) advanceClock atom.saveStateDebounceInterval expect(atom.saveState).toHaveBeenCalledWith({isUnloading: false}) + atom.saveState.reset() + atom.unloadEditorWindow() + mousedown = new MouseEvent('mousedown') + atom.document.dispatchEvent(mousedown) + advanceClock atom.saveStateDebounceInterval + expect(atom.saveState).toHaveBeenCalledWith({isUnloading: true}) + expect(atom.saveState).not.toHaveBeenCalledWith({isUnloading: false}) + describe "openInitialEmptyEditorIfNecessary", -> describe "when there are no paths set", -> beforeEach -> diff --git a/spec/window-event-handler-spec.coffee b/spec/window-event-handler-spec.coffee index 7f093aeff..bb7e1665b 100644 --- a/spec/window-event-handler-spec.coffee +++ b/spec/window-event-handler-spec.coffee @@ -55,11 +55,6 @@ describe "WindowEventHandler", -> jasmine.unspy(TextEditor.prototype, "shouldPromptToSave") spyOn(ipcRenderer, 'send') - it "saves AtomEnvironment's state with the {isUnloading: true} option", -> - spyOn(atom, 'saveState') - window.dispatchEvent(new CustomEvent('beforeunload')) - expect(atom.saveState).toHaveBeenCalledWith({isUnloading: true}) - describe "when pane items are modified", -> editor = null beforeEach -> diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index f99ec3bcc..8c79d66f6 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -129,6 +129,7 @@ class AtomEnvironment extends Model constructor: (params={}) -> {@blobStore, @applicationDelegate, @window, @document, configDirPath, @enablePersistence, onlyLoadBaseStyleSheets} = params + @unloaded = false @loadTime = null {devMode, safeMode, resourcePath, clearWindowState} = @getLoadSettings() @@ -230,7 +231,8 @@ class AtomEnvironment extends Model checkPortableHomeWritable() attachSaveStateListeners: -> - debouncedSaveState = _.debounce((=> @saveState({isUnloading: false})), @saveStateDebounceInterval) + saveState = => @saveState({isUnloading: false}) unless @unloaded + debouncedSaveState = _.debounce(saveState, @saveStateDebounceInterval) @document.addEventListener('mousedown', debouncedSaveState, true) @document.addEventListener('keydown', debouncedSaveState, true) @disposables.add new Disposable => @@ -696,9 +698,11 @@ class AtomEnvironment extends Model unloadEditorWindow: -> return if not @project + @saveState({isUnloading: true}) @storeWindowBackground() @packages.deactivatePackages() @saveBlobStoreSync() + @unloaded = true openInitialEmptyEditorIfNecessary: -> return unless @config.get('core.openEmptyEditorOnStart') @@ -836,6 +840,8 @@ class AtomEnvironment extends Model new Promise (resolve, reject) => window.requestIdleCallback => + return if not @project + state = @serialize(options) savePromise = if storageKey = @getStateKey(@project?.getPaths()) diff --git a/src/window-event-handler.coffee b/src/window-event-handler.coffee index 490b2b416..6c338320d 100644 --- a/src/window-event-handler.coffee +++ b/src/window-event-handler.coffee @@ -143,7 +143,6 @@ class WindowEventHandler @reloadRequested = false @atomEnvironment.storeWindowDimensions() - @atomEnvironment.saveState({isUnloading: true}) if confirmed @atomEnvironment.unloadEditorWindow() else From 8caa9d0a9571d48d812c5290abe97b56d154f750 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 7 Mar 2016 17:21:09 +0100 Subject: [PATCH 138/273] :art: Better wording on specs --- spec/atom-environment-spec.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index 8e7af40d5..7488c8e05 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -179,19 +179,21 @@ describe "AtomEnvironment", -> atom.loadState().then (state) -> expect(state).toEqual({stuff: 'cool'}) - it "saves state on keydown and mousedown events when the editor window hasn't been unloaded", -> + it "saves state on keydown, mousedown, and when the editor window unloads", -> spyOn(atom, 'saveState') keydown = new KeyboardEvent('keydown') atom.document.dispatchEvent(keydown) advanceClock atom.saveStateDebounceInterval expect(atom.saveState).toHaveBeenCalledWith({isUnloading: false}) + expect(atom.saveState).not.toHaveBeenCalledWith({isUnloading: true}) atom.saveState.reset() mousedown = new MouseEvent('mousedown') atom.document.dispatchEvent(mousedown) advanceClock atom.saveStateDebounceInterval expect(atom.saveState).toHaveBeenCalledWith({isUnloading: false}) + expect(atom.saveState).not.toHaveBeenCalledWith({isUnloading: true}) atom.saveState.reset() atom.unloadEditorWindow() From f6d419c2f4563dae446592eb928d4540bb841af7 Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Mon, 7 Mar 2016 10:01:28 -0800 Subject: [PATCH 139/273] Merge pull request #11057 from atom/mkt-improve-pane-add-item-options Move Pane::addItem 'pending' option to options object (cherry picked from commit 53a9c22554177c787751e20c7e7b38bd4eb8e69b) --- package.json | 2 +- spec/pane-spec.coffee | 57 +++++++++++++++++++++++++++++++++++-------- src/pane.coffee | 41 ++++++++++++++++++++----------- src/workspace.coffee | 2 +- 4 files changed, 76 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index ff30c0d07..5cd1367fa 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "status-bar": "1.1.0", "styleguide": "0.45.2", "symbols-view": "0.111.1", - "tabs": "0.91.1", + "tabs": "0.91.3", "timecop": "0.33.1", "tree-view": "0.202.0", "update-package-dependencies": "0.10.0", diff --git a/spec/pane-spec.coffee b/spec/pane-spec.coffee index 873749a19..d0b191f38 100644 --- a/spec/pane-spec.coffee +++ b/spec/pane-spec.coffee @@ -1,5 +1,6 @@ {extend} = require 'underscore-plus' {Emitter} = require 'event-kit' +Grim = require 'grim' Pane = require '../src/pane' PaneAxis = require '../src/pane-axis' PaneContainer = require '../src/pane-container' @@ -92,7 +93,7 @@ describe "Pane", -> pane = new Pane(paneParams(items: [new Item("A"), new Item("B")])) [item1, item2] = pane.getItems() item3 = new Item("C") - pane.addItem(item3, 1) + pane.addItem(item3, index: 1) expect(pane.getItems()).toEqual [item1, item3, item2] it "adds the item after the active item if no index is provided", -> @@ -115,7 +116,7 @@ describe "Pane", -> pane.onDidAddItem (event) -> events.push(event) item = new Item("C") - pane.addItem(item, 1) + pane.addItem(item, index: 1) expect(events).toEqual [{item, index: 1, moved: false}] it "throws an exception if the item is already present on a pane", -> @@ -137,9 +138,9 @@ describe "Pane", -> itemA = new Item("A") itemB = new Item("B") itemC = new Item("C") - pane.addItem(itemA, undefined, false, false) - pane.addItem(itemB, undefined, false, true) - pane.addItem(itemC, undefined, false, false) + pane.addItem(itemA, pending: false) + pane.addItem(itemB, pending: true) + pane.addItem(itemC, pending: false) expect(itemB.isDestroyed()).toBe true it "adds the new item before destroying any existing pending item", -> @@ -148,7 +149,7 @@ describe "Pane", -> pane = new Pane(paneParams(items: [])) itemA = new Item("A") itemB = new Item("B") - pane.addItem(itemA, undefined, false, true) + pane.addItem(itemA, pending: true) pane.onDidAddItem ({item}) -> eventOrder.push("add") if item is itemB @@ -164,6 +165,25 @@ describe "Pane", -> runs -> expect(eventOrder).toEqual ["add", "remove"] + describe "when using the old API of ::addItem(item, index)", -> + beforeEach -> + spyOn Grim, "deprecate" + + it "supports the older public API", -> + pane = new Pane(paneParams(items: [])) + itemA = new Item("A") + itemB = new Item("B") + itemC = new Item("C") + pane.addItem(itemA, 0) + pane.addItem(itemB, 0) + pane.addItem(itemC, 0) + expect(pane.getItems()).toEqual [itemC, itemB, itemA] + + it "shows a deprecation warning", -> + pane = new Pane(paneParams(items: [])) + pane.addItem(new Item(), 2) + expect(Grim.deprecate).toHaveBeenCalledWith "Pane::addItem(item, 2) is deprecated in favor of Pane::addItem(item, {index: 2})" + describe "::activateItem(item)", -> pane = null @@ -196,15 +216,15 @@ describe "Pane", -> itemD = new Item("D") it "replaces the active item if it is pending", -> - pane.activateItem(itemC, true) + pane.activateItem(itemC, pending: true) expect(pane.getItems().map (item) -> item.name).toEqual ['A', 'C', 'B'] - pane.activateItem(itemD, true) + pane.activateItem(itemD, pending: true) expect(pane.getItems().map (item) -> item.name).toEqual ['A', 'D', 'B'] it "adds the item after the active item if it is not pending", -> - pane.activateItem(itemC, true) + pane.activateItem(itemC, pending: true) pane.activateItemAtIndex(2) - pane.activateItem(itemD, true) + pane.activateItem(itemD, pending: true) expect(pane.getItems().map (item) -> item.name).toEqual ['A', 'B', 'D'] describe "::setPendingItem", -> @@ -706,6 +726,23 @@ describe "Pane", -> expect(pane2.isDestroyed()).toBe true expect(item4.isDestroyed()).toBe false + describe "when the item being moved is pending", -> + it "is made permanent in the new pane", -> + item6 = new Item("F") + pane1.addItem(item6, pending: true) + expect(pane1.getPendingItem()).toEqual item6 + pane1.moveItemToPane(item6, pane2, 0) + expect(pane2.getPendingItem()).not.toEqual item6 + + describe "when the target pane has a pending item", -> + it "does not destroy the pending item", -> + item6 = new Item("F") + pane1.addItem(item6, pending: true) + expect(pane1.getPendingItem()).toEqual item6 + pane2.moveItemToPane(item5, pane1, 0) + expect(pane1.getPendingItem()).toEqual item6 + + describe "split methods", -> [pane1, item1, container] = [] diff --git a/src/pane.coffee b/src/pane.coffee index 70f8b4bab..3ff62993c 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -1,3 +1,4 @@ +Grim = require 'grim' {find, compact, extend, last} = require 'underscore-plus' {CompositeDisposable, Emitter} = require 'event-kit' Model = require './model' @@ -394,30 +395,42 @@ class Pane extends Model # Public: Make the given item *active*, causing it to be displayed by # the pane's view. # - # * `pending` (optional) {Boolean} indicating that the item should be added - # in a pending state if it does not yet exist in the pane. Existing pending - # items in a pane are replaced with new pending items when they are opened. - activateItem: (item, pending=false) -> + # * `options` (optional) {Object} + # * `pending` (optional) {Boolean} indicating that the item should be added + # in a pending state if it does not yet exist in the pane. Existing pending + # items in a pane are replaced with new pending items when they are opened. + activateItem: (item, options={}) -> if item? if @getPendingItem() is @activeItem index = @getActiveItemIndex() else index = @getActiveItemIndex() + 1 - @addItem(item, index, false, pending) + @addItem(item, extend({}, options, {index: index})) @setActiveItem(item) # Public: Add the given item to the pane. # # * `item` The item to add. It can be a model with an associated view or a # view. - # * `index` (optional) {Number} indicating the index at which to add the item. - # If omitted, the item is added after the current active item. - # * `pending` (optional) {Boolean} indicating that the item should be - # added in a pending state. Existing pending items in a pane are replaced with - # new pending items when they are opened. + # * `options` (optional) {Object} + # * `index` (optional) {Number} indicating the index at which to add the item. + # If omitted, the item is added after the current active item. + # * `pending` (optional) {Boolean} indicating that the item should be + # added in a pending state. Existing pending items in a pane are replaced with + # new pending items when they are opened. # # Returns the added item. - addItem: (item, index=@getActiveItemIndex() + 1, moved=false, pending=false) -> + addItem: (item, options={}) -> + # Backward compat with old API: + # addItem(item, index=@getActiveItemIndex() + 1) + if typeof options is "number" + Grim.deprecate("Pane::addItem(item, #{options}) is deprecated in favor of Pane::addItem(item, {index: #{options}})") + options = index: options + + index = options.index ? @getActiveItemIndex() + 1 + moved = options.moved ? false + pending = options.pending ? false + throw new Error("Pane items must be objects. Attempted to add item #{item}.") unless item? and typeof item is 'object' throw new Error("Adding a pane item with URI '#{item.getURI?()}' that has already been destroyed") if item.isDestroyed?() @@ -437,7 +450,7 @@ class Pane extends Model @setPendingItem(item) if pending @emitter.emit 'did-add-item', {item, index, moved} - @destroyItem(lastPendingItem) if lastPendingItem? + @destroyItem(lastPendingItem) if lastPendingItem? and not moved @setActiveItem(item) unless @getActiveItem()? item @@ -467,7 +480,7 @@ class Pane extends Model # Returns an {Array} of added items. addItems: (items, index=@getActiveItemIndex() + 1) -> items = items.filter (item) => not (item in @items) - @addItem(item, index + i, false) for item, i in items + @addItem(item, {index: index + i}) for item, i in items items removeItem: (item, moved) -> @@ -516,7 +529,7 @@ class Pane extends Model # given pane. moveItemToPane: (item, pane, index) -> @removeItem(item, true) - pane.addItem(item, index, true) + pane.addItem(item, {index: index, moved: true}) # Public: Destroy the active item and activate the next item. destroyActiveItem: -> diff --git a/src/workspace.coffee b/src/workspace.coffee index 873d90370..9b1bf14fc 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -509,7 +509,7 @@ class Workspace extends Model return item if pane.isDestroyed() @itemOpened(item) - pane.activateItem(item, options.pending) if activateItem + pane.activateItem(item, {pending: options.pending}) if activateItem pane.activate() if activatePane initialLine = initialColumn = 0 From 56d82ccac28467c6c7c5f1114af09ac420bccb24 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 7 Mar 2016 14:44:51 -0500 Subject: [PATCH 140/273] :arrow_up: nodegit@0.11.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5cd1367fa..83864702d 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "less-cache": "0.23", "line-top-index": "0.2.0", "marked": "^0.3.4", - "nodegit": "0.11.6", + "nodegit": "0.11.7", "normalize-package-data": "^2.0.0", "nslog": "^3", "oniguruma": "^5", From 56b23a4a10b01a97497b08c9909f98dbf15867f9 Mon Sep 17 00:00:00 2001 From: Damien Guard Date: Mon, 7 Mar 2016 14:01:05 -0800 Subject: [PATCH 141/273] Make cli atom --wait work on Cygwin --- atom.sh | 2 -- resources/win/atom.sh | 19 ++++++++----------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/atom.sh b/atom.sh index ef8dbcdc4..b68716bf4 100755 --- a/atom.sh +++ b/atom.sh @@ -4,8 +4,6 @@ if [ "$(uname)" == 'Darwin' ]; then OS='Mac' elif [ "$(expr substr $(uname -s) 1 5)" == 'Linux' ]; then OS='Linux' -elif [ "$(expr substr $(uname -s) 1 10)" == 'MINGW32_NT' ]; then - OS='Cygwin' else echo "Your platform ($(uname -a)) is not supported." exit 1 diff --git a/resources/win/atom.sh b/resources/win/atom.sh index 0eaf193c0..7f1b1e093 100644 --- a/resources/win/atom.sh +++ b/resources/win/atom.sh @@ -6,6 +6,7 @@ while getopts ":fhtvw-:" opt; do case "${OPTARG}" in wait) WAIT=1 + EXPECT_OUTPUT=1 ;; help|version) REDIRECT_STDERR=1 @@ -18,6 +19,7 @@ while getopts ":fhtvw-:" opt; do ;; w) WAIT=1 + EXPECT_OUTPUT=1 ;; h|v) REDIRECT_STDERR=1 @@ -31,19 +33,14 @@ done directory=$(dirname "$0") -WINPS=`ps | grep -i $$` -PID=`echo $WINPS | cut -d' ' -f 4` - if [ $EXPECT_OUTPUT ]; then export ELECTRON_ENABLE_LOGGING=1 - "$directory/../../atom.exe" --executed-from="$(pwd)" --pid=$PID "$@" + if [ $WAIT == 'YES' ]; then + powershell -noexit "%~dp0\..\..\atom.exe" --pid=$pid "$@" ; +wait-event + else + "$directory/../../atom.exe" "$@" + fi else "$directory/../app/apm/bin/node.exe" "$directory/atom.js" "$@" fi - -# If the wait flag is set, don't exit this process until Atom tells it to. -if [ $WAIT ]; then - while true; do - sleep 1 - done -fi From b53c5a10d00db421abf84116d824addbd9a7c9ee Mon Sep 17 00:00:00 2001 From: Rowan Bottema Date: Tue, 8 Mar 2016 10:18:43 +0100 Subject: [PATCH 142/273] Add zero to hexadecimal numbers below F (16) --- spec/config-spec.coffee | 10 ++++++++++ src/color.coffee | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/spec/config-spec.coffee b/spec/config-spec.coffee index c7485ea65..acd9b112b 100644 --- a/spec/config-spec.coffee +++ b/spec/config-spec.coffee @@ -1621,6 +1621,16 @@ describe "Config", -> expect(color.toHexString()).toBe '#ff0000' expect(color.toRGBAString()).toBe 'rgba(255, 0, 0, 1)' + color.red = 11 + color.green = 11 + color.blue = 124 + color.alpha = 1 + atom.config.set('foo.bar.aColor', color) + + color = atom.config.get('foo.bar.aColor') + expect(color.toHexString()).toBe '#0b0b7c' + expect(color.toRGBAString()).toBe 'rgba(11, 11, 124, 1)' + it 'coerces various types to a color object', -> atom.config.set('foo.bar.aColor', 'red') expect(atom.config.get('foo.bar.aColor')).toEqual {red: 255, green: 0, blue: 0, alpha: 1} diff --git a/src/color.coffee b/src/color.coffee index fc751ce42..b413b9e2c 100644 --- a/src/color.coffee +++ b/src/color.coffee @@ -85,5 +85,5 @@ parseAlpha = (alpha) -> numberToHexString = (number) -> hex = number.toString(16) - hex = "0#{hex}" if number < 10 + hex = "0#{hex}" if number < 16 hex From 2f401c7116ee7103adbdc39c0968c1328e9e81e5 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 8 Mar 2016 12:14:26 -0500 Subject: [PATCH 143/273] We should emit changes when anything changes. --- spec/git-repository-async-spec.js | 38 +++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/spec/git-repository-async-spec.js b/spec/git-repository-async-spec.js index e7bffad3a..9144f8611 100644 --- a/spec/git-repository-async-spec.js +++ b/spec/git-repository-async-spec.js @@ -422,6 +422,44 @@ describe('GitRepositoryAsync', () => { expect(repo.isStatusModified(status)).toBe(true) expect(repo.isStatusNew(status)).toBe(false) }) + + it('emits did-change-statuses if the status changes', async () => { + const someNewPath = path.join(workingDirectory, 'MyNewJSFramework.md') + fs.writeFileSync(someNewPath, '') + + const statusHandler = jasmine.createSpy('statusHandler') + repo.onDidChangeStatuses(statusHandler) + + await repo.refreshStatus() + + waitsFor('the onDidChangeStatuses handler to be called', () => statusHandler.callCount > 0) + }) + + it('emits did-change-statuses if the branch changes', async () => { + const statusHandler = jasmine.createSpy('statusHandler') + repo.onDidChangeStatuses(statusHandler) + + repo._refreshBranch = jasmine.createSpy('_refreshBranch').andCallFake(() => { + return Promise.resolve(true) + }) + + await repo.refreshStatus() + + waitsFor('the onDidChangeStatuses handler to be called', () => statusHandler.callCount > 0) + }) + + it('emits did-change-statuses if the ahead/behind changes', async () => { + const statusHandler = jasmine.createSpy('statusHandler') + repo.onDidChangeStatuses(statusHandler) + + repo._refreshAheadBehindCount = jasmine.createSpy('_refreshAheadBehindCount').andCallFake(() => { + return Promise.resolve(true) + }) + + await repo.refreshStatus() + + waitsFor('the onDidChangeStatuses handler to be called', () => statusHandler.callCount > 0) + }) }) describe('.isProjectAtRoot()', () => { From f2be54bf299355142b4a9d79a3ea8fda19964986 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 8 Mar 2016 12:14:42 -0500 Subject: [PATCH 144/273] But actually do it tho. --- src/git-repository-async.js | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/git-repository-async.js b/src/git-repository-async.js index 91b78e0c5..642ed5a98 100644 --- a/src/git-repository-async.js +++ b/src/git-repository-async.js @@ -783,12 +783,17 @@ export default class GitRepositoryAsync { // Get the current branch and update this.branch. // - // Returns a {Promise} which resolves to the {String} branch name. + // Returns a {Promise} which resolves to a {boolean} indicating whether the + // branch name changed. _refreshBranch () { return this.getRepo() .then(repo => repo.getCurrentBranch()) .then(ref => ref.name()) - .then(branchName => this.branch = branchName) + .then(branchName => { + const changed = branchName !== this.branch + this.branch = branchName + return changed + }) } // Refresh the cached ahead/behind count with the given branch. @@ -796,10 +801,15 @@ export default class GitRepositoryAsync { // * `branchName` The {String} name of the branch whose ahead/behind should be // used for the refresh. // - // Returns a {Promise} which will resolve to {null}. + // Returns a {Promise} which will resolve to a {boolean} indicating whether + // the ahead/behind count changed. _refreshAheadBehindCount (branchName) { return this.getAheadBehindCount(branchName) - .then(counts => this.upstream = counts) + .then(counts => { + const changed = !_.isEqual(counts, this.upstream) + this.upstream = counts + return changed + }) } // Get the status for this repository. @@ -905,15 +915,15 @@ export default class GitRepositoryAsync { // Refresh the cached status. // - // Returns a {Promise} which will resolve to {null}. + // Returns a {Promise} which will resolve to a {boolean} indicating whether + // any statuses changed. _refreshStatus () { return Promise.all([this._getRepositoryStatus(), this._getSubmoduleStatuses()]) .then(([repositoryStatus, submoduleStatus]) => { const statusesByPath = _.extend({}, repositoryStatus, submoduleStatus) - if (!_.isEqual(this.pathStatusCache, statusesByPath) && this.emitter != null) { - this.emitter.emit('did-change-statuses') - } + const changed = !_.isEqual(this.pathStatusCache, statusesByPath) this.pathStatusCache = statusesByPath + return changed }) } @@ -927,7 +937,13 @@ export default class GitRepositoryAsync { this._refreshingPromise = this._refreshingPromise.then(_ => { return Promise.all([status, branch, aheadBehind]) - .then(_ => null) + .then(([statusChanged, branchChanged, aheadBehindChanged]) => { + if (this.emitter && (statusChanged || branchChanged || aheadBehindChanged)) { + this.emitter.emit('did-change-statuses') + } + + return null + }) // Because all these refresh steps happen asynchronously, it's entirely // possible the repository was destroyed while we were working. In which // case we should just swallow the error. From cb44450e923ec6040c4b7151d0106fd2dbd52f41 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 8 Mar 2016 12:40:29 -0500 Subject: [PATCH 145/273] Correct the spec name. --- spec/git-repository-async-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/git-repository-async-spec.js b/spec/git-repository-async-spec.js index 9144f8611..900d81bfb 100644 --- a/spec/git-repository-async-spec.js +++ b/spec/git-repository-async-spec.js @@ -714,7 +714,7 @@ describe('GitRepositoryAsync', () => { repo = GitRepositoryAsync.open(workingDirectory) }) - it('returns 0, 0 for a branch with no upstream', async () => { + it('returns 1, 0 for a branch which is ahead by 1', async () => { await repo.refreshStatus() const {ahead, behind} = await repo.getCachedUpstreamAheadBehindCount('You-Dont-Need-jQuery') From fc62398d62b950c6d84f5a6836a5e781a868d9f7 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 8 Mar 2016 12:40:38 -0500 Subject: [PATCH 146/273] Use the new branch name. --- src/git-repository-async.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/git-repository-async.js b/src/git-repository-async.js index 642ed5a98..f80f46a13 100644 --- a/src/git-repository-async.js +++ b/src/git-repository-async.js @@ -933,7 +933,7 @@ export default class GitRepositoryAsync { refreshStatus () { const status = this._refreshStatus() const branch = this._refreshBranch() - const aheadBehind = branch.then(branchName => this._refreshAheadBehindCount(branchName)) + const aheadBehind = branch.then(() => this._refreshAheadBehindCount(this.branch)) this._refreshingPromise = this._refreshingPromise.then(_ => { return Promise.all([status, branch, aheadBehind]) From 42c6d5c2bcb3c6b1d91a03bf92dd015b0b2cd4f6 Mon Sep 17 00:00:00 2001 From: Daniel Hengeveld Date: Tue, 8 Mar 2016 18:47:42 +0100 Subject: [PATCH 147/273] :arrow_up:symbols-view@0.112.0 - adds es7 async functions to js --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 83864702d..0353c9957 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "spell-check": "0.67.0", "status-bar": "1.1.0", "styleguide": "0.45.2", - "symbols-view": "0.111.1", + "symbols-view": "0.112.0", "tabs": "0.91.3", "timecop": "0.33.1", "tree-view": "0.202.0", From 52d6fbde1b9a4f869c8063972357ea19abce060f Mon Sep 17 00:00:00 2001 From: Damien Guard Date: Tue, 8 Mar 2016 12:12:52 -0800 Subject: [PATCH 148/273] More reliable to just call atom.cmd for Cygwin --- resources/win/atom.sh | 46 +------------------------------------------ 1 file changed, 1 insertion(+), 45 deletions(-) diff --git a/resources/win/atom.sh b/resources/win/atom.sh index 7f1b1e093..7380bf122 100644 --- a/resources/win/atom.sh +++ b/resources/win/atom.sh @@ -1,46 +1,2 @@ #!/bin/sh - -while getopts ":fhtvw-:" opt; do - case "$opt" in - -) - case "${OPTARG}" in - wait) - WAIT=1 - EXPECT_OUTPUT=1 - ;; - help|version) - REDIRECT_STDERR=1 - EXPECT_OUTPUT=1 - ;; - foreground|test) - EXPECT_OUTPUT=1 - ;; - esac - ;; - w) - WAIT=1 - EXPECT_OUTPUT=1 - ;; - h|v) - REDIRECT_STDERR=1 - EXPECT_OUTPUT=1 - ;; - f|t) - EXPECT_OUTPUT=1 - ;; - esac -done - -directory=$(dirname "$0") - -if [ $EXPECT_OUTPUT ]; then - export ELECTRON_ENABLE_LOGGING=1 - if [ $WAIT == 'YES' ]; then - powershell -noexit "%~dp0\..\..\atom.exe" --pid=$pid "$@" ; -wait-event - else - "$directory/../../atom.exe" "$@" - fi -else - "$directory/../app/apm/bin/node.exe" "$directory/atom.js" "$@" -fi +$(dirname "$0")/atom.cmd "$@" From bf5dea0a27953beafa40c12943b1fff6d7c2b09f Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Mar 2016 19:25:52 -0700 Subject: [PATCH 149/273] :arrow_up: fuzzy-finder --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0353c9957..59264c3a5 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "encoding-selector": "0.21.0", "exception-reporting": "0.37.0", "find-and-replace": "0.197.4", - "fuzzy-finder": "1.0.2", + "fuzzy-finder": "1.0.3", "git-diff": "1.0.0", "go-to-line": "0.30.0", "grammar-selector": "0.48.1", From 152e370a15e65a09039ddf82f1528563d9eb94c4 Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Wed, 9 Mar 2016 02:16:10 -0800 Subject: [PATCH 150/273] Default the options parameter to an empty object --- src/project.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/project.coffee b/src/project.coffee index 5f3420b08..93a3ed496 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -71,7 +71,7 @@ class Project extends Model @subscribeToBuffer(buffer) for buffer in @buffers @setPaths(state.paths) - serialize: (options) -> + serialize: (options={}) -> deserializer: 'Project' paths: @getPaths() buffers: _.compact(@buffers.map (buffer) -> buffer.serialize({markerLayers: options.isUnloading is true}) if buffer.isRetained()) From 129139f03a2846506d87dfa393d9d0b525e75757 Mon Sep 17 00:00:00 2001 From: joshaber Date: Wed, 9 Mar 2016 12:43:28 -0500 Subject: [PATCH 151/273] :arrow_up: nodegit@0.11.9 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 59264c3a5..a1fa3e820 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "less-cache": "0.23", "line-top-index": "0.2.0", "marked": "^0.3.4", - "nodegit": "0.11.7", + "nodegit": "0.11.9", "normalize-package-data": "^2.0.0", "nslog": "^3", "oniguruma": "^5", From a04c552fb710c3b147a55d824f260beac6cb3e34 Mon Sep 17 00:00:00 2001 From: Thomas Johansen Date: Wed, 9 Mar 2016 19:22:23 +0100 Subject: [PATCH 152/273] :arrow_up: language-text --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 59264c3a5..c96d52b72 100644 --- a/package.json +++ b/package.json @@ -144,7 +144,7 @@ "language-shellscript": "0.21.0", "language-source": "0.9.0", "language-sql": "0.20.0", - "language-text": "0.7.0", + "language-text": "0.7.1", "language-todo": "0.27.0", "language-toml": "0.18.0", "language-xml": "0.34.4", From ac35fec0cd882394d0ba22a98d1d7280e96a1f5d Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Wed, 9 Mar 2016 17:26:47 -0800 Subject: [PATCH 153/273] :arrow_up: tree-view@0.203.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8bae63604..6b449d0de 100644 --- a/package.json +++ b/package.json @@ -112,7 +112,7 @@ "symbols-view": "0.112.0", "tabs": "0.91.3", "timecop": "0.33.1", - "tree-view": "0.202.0", + "tree-view": "0.203.0", "update-package-dependencies": "0.10.0", "welcome": "0.34.0", "whitespace": "0.32.2", From 4b017759c9b053595e056d9ca409efee8dc81ff9 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 10 Mar 2016 09:40:26 +0100 Subject: [PATCH 154/273] Ensure project.serialize is called with atom.saveState options This is because we have made the `project.serialize(options)` parameter optional for backwards compatibility (i.e. #11111), and we want to make sure we don't make the mistake of not passing it internally. --- spec/atom-environment-spec.coffee | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index 7488c8e05..3283b63d6 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -203,6 +203,14 @@ describe "AtomEnvironment", -> expect(atom.saveState).toHaveBeenCalledWith({isUnloading: true}) expect(atom.saveState).not.toHaveBeenCalledWith({isUnloading: false}) + it "serializes the project state with all the options supplied in saveState", -> + spyOn(atom.project, 'serialize').andReturn({foo: 42}) + + waitsForPromise -> atom.saveState({anyOption: 'any option'}) + runs -> + expect(atom.project.serialize.calls.length).toBe(1) + expect(atom.project.serialize.mostRecentCall.args[0]).toEqual({anyOption: 'any option'}) + describe "openInitialEmptyEditorIfNecessary", -> describe "when there are no paths set", -> beforeEach -> From 0d7b182c2dba7daedc605ee4a65ba2c892842c5a Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 10 Mar 2016 10:31:24 -0500 Subject: [PATCH 155/273] :arrow_up: status-bar@1.1.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6b449d0de..353e470be 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "settings-view": "0.232.4", "snippets": "1.0.1", "spell-check": "0.67.0", - "status-bar": "1.1.0", + "status-bar": "1.1.1", "styleguide": "0.45.2", "symbols-view": "0.112.0", "tabs": "0.91.3", From 501eadccca0c8aaad9f7b027c596a87e2bcd873a Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Thu, 10 Mar 2016 11:00:48 -0800 Subject: [PATCH 156/273] :arrow_up: notifications@0.62.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 353e470be..d2cb82195 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "link": "0.31.0", "markdown-preview": "0.157.3", "metrics": "0.53.1", - "notifications": "0.62.3", + "notifications": "0.62.4", "open-on-github": "1.0.0", "package-generator": "0.41.1", "settings-view": "0.232.4", From 3201d7f7469811f7ca7d38810e0bf2900dd90cd6 Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Thu, 3 Mar 2016 21:15:52 -0800 Subject: [PATCH 157/273] Add basic atom.project.getEnv API --- spec/fixtures/sample.txt | 2 +- spec/project-spec.coffee | 53 ++++++++++++++++++++++++++++++++++++++++ src/project.coffee | 39 +++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/spec/fixtures/sample.txt b/spec/fixtures/sample.txt index 9701a96c5..0a2b6a502 100644 --- a/spec/fixtures/sample.txt +++ b/spec/fixtures/sample.txt @@ -1 +1 @@ -Some textSome textSome text. +Some textSome textSome textSome text. diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 499efd017..61dd244e8 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -537,3 +537,56 @@ describe "Project", -> randomPath = path.join("some", "random", "path") expect(atom.project.contains(randomPath)).toBe false + + describe ".getEnv", -> + afterEach -> + delete atom.project.env + + it "returns a copy of the environment", -> + env = atom.project.getEnv() + + env.PROJECT_GET_ENV_TESTING = "foo" + expect(process.env.PROJECT_GET_ENV_TESTING).not.toEqual "foo" + expect(atom.project.getEnv().PROJECT_GET_ENV_TESTING).not.toEqual "foo" + + describe "on platforms other than OS X", -> + beforeEach -> + spyOn(process, "platform").andReturn("foo") + + describe "when TERM is not set", -> + it "returns the PATH unchanged", -> + spyOn(process.env, "TERM").andReturn(undefined) + + expect(atom.project.getEnv().PATH).toEqual process.env.PATH + + describe "when TERM is set", -> + it "returns the PATH unchanged", -> + spyOn(process.env, "TERM").andReturn("foo") + + expect(atom.project.getEnv().PATH).toEqual process.env.PATH + + describe "on OS X", -> + beforeEach -> + spyOn(process, "platform").andReturn("darwin") + + describe "when TERM is not set", -> + it "replaces the PATH with the one obtained from the shell", -> + env = _.clone(process.env) + delete env.TERM + + spyOn(process, "env").andReturn(env) + + spyOn(atom.project, "getShellEnv").andReturn """ + FOO=BAR + TERM=xterm-something + PATH=/usr/bin:/bin:/usr/sbin:/sbin:/some/crazy/path/entry/that/should/not/exist + """ + + expect(atom.project.getShellPath()).toEqual "/usr/bin:/bin:/usr/sbin:/sbin:/some/crazy/path/entry/that/should/not/exist" + expect(atom.project.getEnv().PATH).toEqual "/usr/bin:/bin:/usr/sbin:/sbin:/some/crazy/path/entry/that/should/not/exist" + + describe "when TERM is set", -> + it "returns the PATH unchanged", -> + spyOn(process.env, "TERM").andReturn("foo") + + expect(atom.project.getEnv().PATH).toEqual process.env.PATH diff --git a/src/project.coffee b/src/project.coffee index 93a3ed496..f2ace97e2 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -12,6 +12,9 @@ TextEditor = require './text-editor' Task = require './task' GitRepositoryProvider = require './git-repository-provider' +child_process = require 'child_process' +os = require 'os' + # Extended: Represents a project that's opened in Atom. # # An instance of this class is always available as the `atom.project` global. @@ -271,6 +274,42 @@ class Project extends Model contains: (pathToCheck) -> @rootDirectories.some (dir) -> dir.contains(pathToCheck) + ### + Section: Environment + ### + + getEnv: -> + unless @env? + @env = _.clone(process.env) + if process.platform is "darwin" and not process.env.TERM? + @env.PATH = @getShellPath() + + _.clone(@env) + + getShellPath: -> + shellEnvText = @getShellEnv() + env = {} + + for line in shellEnvText.split(os.EOL) + if line.includes("=") + components = line.split("=") + if components.length is 2 + env[components[0]] = components[1] + else + k = components.shift() + v = components.join("=") + env[k] = v + + env.PATH + + getShellEnv: -> + shell = process.env.SHELL ? "/bin/bash" + results = child_process.spawnSync shell, ["--login"], input: "env", encoding: "utf8" + return if results.error? + return unless results.stdout and results.stdout.length > 0 + + results.stdout + ### Section: Private ### From a46740522d06ee9aa2af5ebde920c09a6871aa9a Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Thu, 3 Mar 2016 21:21:26 -0800 Subject: [PATCH 158/273] :memo: Add documentation for atom.project.getEnv --- src/project.coffee | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/project.coffee b/src/project.coffee index f2ace97e2..4f5dc37bc 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -278,6 +278,12 @@ class Project extends Model Section: Environment ### + # Public: Retrieves a normalized copy of the environment. + # + # On OS X, the `PATH` can be different depending on whether Atom is launched + # from the Dock, Spotlight or the terminal. This detects how Atom was started + # and corrects the `PATH` environment variable before returning a copy of the + # environment. getEnv: -> unless @env? @env = _.clone(process.env) From 2e64be6b000e7aecba237763baf69147c71441a5 Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Thu, 3 Mar 2016 22:18:39 -0800 Subject: [PATCH 159/273] Move new functions to private section --- src/project.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/project.coffee b/src/project.coffee index 4f5dc37bc..d91ec3a39 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -292,6 +292,10 @@ class Project extends Model _.clone(@env) + ### + Section: Private + ### + getShellPath: -> shellEnvText = @getShellEnv() env = {} @@ -316,10 +320,6 @@ class Project extends Model results.stdout - ### - Section: Private - ### - consumeServices: ({serviceHub}) -> serviceHub.consume( 'atom.directory-provider', From 7f6fd92c7a859b573677b8fbacc907ba63c76c1d Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Mon, 7 Mar 2016 14:19:32 -0800 Subject: [PATCH 160/273] :fire: Revert change to test fixture --- spec/fixtures/sample.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/fixtures/sample.txt b/spec/fixtures/sample.txt index 0a2b6a502..9701a96c5 100644 --- a/spec/fixtures/sample.txt +++ b/spec/fixtures/sample.txt @@ -1 +1 @@ -Some textSome textSome textSome text. +Some textSome textSome text. From 9916c78ce23ffb8dde835517d9b37c2e20f38259 Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Mon, 7 Mar 2016 14:27:19 -0800 Subject: [PATCH 161/273] Add --interactive option to get the user's full PATH with all the trimmings --- src/project.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/project.coffee b/src/project.coffee index d91ec3a39..e13942f28 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -314,7 +314,7 @@ class Project extends Model getShellEnv: -> shell = process.env.SHELL ? "/bin/bash" - results = child_process.spawnSync shell, ["--login"], input: "env", encoding: "utf8" + results = child_process.spawnSync shell, ["--login", "--interactive"], input: "env", encoding: "utf8" return if results.error? return unless results.stdout and results.stdout.length > 0 From 96b8f0ce38d4870672f89276450ae27da82dd043 Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Mon, 7 Mar 2016 14:28:30 -0800 Subject: [PATCH 162/273] :memo: Add Finder to the list of ways an app can be launched --- src/project.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/project.coffee b/src/project.coffee index e13942f28..5d5448dc7 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -281,9 +281,9 @@ class Project extends Model # Public: Retrieves a normalized copy of the environment. # # On OS X, the `PATH` can be different depending on whether Atom is launched - # from the Dock, Spotlight or the terminal. This detects how Atom was started - # and corrects the `PATH` environment variable before returning a copy of the - # environment. + # from the Dock, Finder, Spotlight or the terminal. This detects how Atom was + # started and corrects the `PATH` environment variable before returning a copy + # of the environment. getEnv: -> unless @env? @env = _.clone(process.env) From 6bf785faa0b5f795e33d53b76eeec93b504f7c72 Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Mon, 7 Mar 2016 15:42:11 -0800 Subject: [PATCH 163/273] :white_check_mark: Add test for error handling --- spec/project-spec.coffee | 37 ++++++++++++++++++++++++++----------- src/project.coffee | 19 +++++++++++++++++-- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 61dd244e8..35cd0157f 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -539,7 +539,13 @@ describe "Project", -> expect(atom.project.contains(randomPath)).toBe false describe ".getEnv", -> + [originalTerm] = [] + + beforeEach -> + originalTerm = process.env.TERM + afterEach -> + process.env.TERM = originalTerm delete atom.project.env it "returns a copy of the environment", -> @@ -554,15 +560,17 @@ describe "Project", -> spyOn(process, "platform").andReturn("foo") describe "when TERM is not set", -> - it "returns the PATH unchanged", -> - spyOn(process.env, "TERM").andReturn(undefined) + beforeEach -> + delete process.env.TERM + it "returns the PATH unchanged", -> expect(atom.project.getEnv().PATH).toEqual process.env.PATH describe "when TERM is set", -> - it "returns the PATH unchanged", -> - spyOn(process.env, "TERM").andReturn("foo") + beforeEach -> + process.env.TERM = "foo" + it "returns the PATH unchanged", -> expect(atom.project.getEnv().PATH).toEqual process.env.PATH describe "on OS X", -> @@ -570,12 +578,10 @@ describe "Project", -> spyOn(process, "platform").andReturn("darwin") describe "when TERM is not set", -> + beforeEach -> + delete process.env.TERM + it "replaces the PATH with the one obtained from the shell", -> - env = _.clone(process.env) - delete env.TERM - - spyOn(process, "env").andReturn(env) - spyOn(atom.project, "getShellEnv").andReturn """ FOO=BAR TERM=xterm-something @@ -584,9 +590,18 @@ describe "Project", -> expect(atom.project.getShellPath()).toEqual "/usr/bin:/bin:/usr/sbin:/sbin:/some/crazy/path/entry/that/should/not/exist" expect(atom.project.getEnv().PATH).toEqual "/usr/bin:/bin:/usr/sbin:/sbin:/some/crazy/path/entry/that/should/not/exist" + expect(atom.project.getEnv().FOO).not.toEqual "BAR" + + it "does the best it can when there is an error retrieving the shell environment", -> + spyOn(atom.project, "getShellEnv").andReturn(undefined) + + expect(atom.project.getShellPath()).toBeUndefined() + expect(atom.project.getEnv().PATH).not.toBeUndefined() + expect(atom.project.getEnv().PATH).toEqual process.env.PATH describe "when TERM is set", -> - it "returns the PATH unchanged", -> - spyOn(process.env, "TERM").andReturn("foo") + beforeEach -> + process.env.TERM = "foo" + it "returns the PATH unchanged", -> expect(atom.project.getEnv().PATH).toEqual process.env.PATH diff --git a/src/project.coffee b/src/project.coffee index 5d5448dc7..c8fd3ddbe 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -288,7 +288,8 @@ class Project extends Model unless @env? @env = _.clone(process.env) if process.platform is "darwin" and not process.env.TERM? - @env.PATH = @getShellPath() + shellPath = @getShellPath() + @env.PATH = shellPath if shellPath? _.clone(@env) @@ -296,8 +297,13 @@ class Project extends Model Section: Private ### + # Gets the user's configured shell `PATH`. + # + # Returns the value of `PATH` or `undefined` if there was an error. getShellPath: -> shellEnvText = @getShellEnv() + return unless shellEnvText? + env = {} for line in shellEnvText.split(os.EOL) @@ -312,9 +318,18 @@ class Project extends Model env.PATH + # Gets a dump of the user's configured shell environment. + # + # Returns the output of the `env` command or `undefined` if there was an error. getShellEnv: -> shell = process.env.SHELL ? "/bin/bash" - results = child_process.spawnSync shell, ["--login", "--interactive"], input: "env", encoding: "utf8" + + # The `-ilc` set of options was tested to work with the OS X v10.11 + # default-installed versions of bash, zsh, sh, and ksh. It *does not* + # work with csh or tcsh. Given that bash and zsh should cover the + # vast majority of users and it gracefully falls back to prior behavior, + # this should be safe. + results = child_process.spawnSync shell, ["-ilc"], input: "env", encoding: "utf8" return if results.error? return unless results.stdout and results.stdout.length > 0 From 8c53e25f802f7e5e6311a61087f78bbf4e246b20 Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Mon, 7 Mar 2016 16:43:20 -0800 Subject: [PATCH 164/273] Patch process.env on startup --- spec/atom-environment-spec.coffee | 13 +++++++++++++ src/atom-environment.coffee | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index 3283b63d6..6271ea5d4 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -362,3 +362,16 @@ describe "AtomEnvironment", -> version = '1.7.0-dev-5340c91' expect(atom.getReleaseChannel()).toBe 'dev' + + describe "environment patching", -> + it "patches process.env on startup", -> + configDirPath = temp.mkdirSync() + fakeDocument = { + addEventListener: -> + removeEventListener: -> + head: document.createElement('head') + body: document.createElement('body') + } + atomEnvironment = new AtomEnvironment({applicationDelegate: atom.applicationDelegate, window, document: fakeDocument}) + + expect(process.env).toEqual atomEnvironment.project.getEnv() diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 8c79d66f6..d1e921d54 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -230,6 +230,10 @@ class AtomEnvironment extends Model checkPortableHomeWritable() + # Patch the `process.env` on startup to fix the problem first documented + # in #4126 + process.env = @project.getEnv() + attachSaveStateListeners: -> saveState = => @saveState({isUnloading: false}) unless @unloaded debouncedSaveState = _.debounce(saveState, @saveStateDebounceInterval) From c7465f5f7e747b5d0b182a3c66f0bd0f67bf052d Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Tue, 8 Mar 2016 15:29:48 -0800 Subject: [PATCH 165/273] Add environment module for getting environment info --- spec/environment-spec.coffee | 27 ++++++++++++++++++++++++ src/environment.coffee | 41 ++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 spec/environment-spec.coffee create mode 100644 src/environment.coffee diff --git a/spec/environment-spec.coffee b/spec/environment-spec.coffee new file mode 100644 index 000000000..484bdcc1a --- /dev/null +++ b/spec/environment-spec.coffee @@ -0,0 +1,27 @@ +child_process = require('child_process') +{getShellEnv} = require("../src/environment") + +describe "Environment handling", -> + describe "when things are configured properly", -> + beforeEach -> + spyOn(child_process, "spawnSync").andReturn + stdout: """ + FOO=BAR + TERM=xterm-something + PATH=/usr/bin:/bin:/usr/sbin:/sbin:/some/crazy/path/entry/that/should/not/exist + """ + + it "returns an object containing the information from the user's shell environment", -> + env = getShellEnv() + + expect(env.FOO).toEqual "BAR" + expect(env.TERM).toEqual "xterm-something" + expect(env.PATH).toEqual "/usr/bin:/bin:/usr/sbin:/sbin:/some/crazy/path/entry/that/should/not/exist" + + describe "when an error occurs", -> + beforeEach -> + spyOn(child_process, "spawnSync").andReturn + error: new Error + + it "returns undefined", -> + expect(getShellEnv()).toBeUndefined() diff --git a/src/environment.coffee b/src/environment.coffee new file mode 100644 index 000000000..f2b9bbf47 --- /dev/null +++ b/src/environment.coffee @@ -0,0 +1,41 @@ +child_process = require('child_process') +os = require('os') + +# Gets a dump of the user's configured shell environment. +# +# Returns the output of the `env` command or `undefined` if there was an error. +getRawShellEnv = -> + shell = process.env.SHELL ? "/bin/bash" + + # The `-ilc` set of options was tested to work with the OS X v10.11 + # default-installed versions of bash, zsh, sh, and ksh. It *does not* + # work with csh or tcsh. Given that bash and zsh should cover the + # vast majority of users and it gracefully falls back to prior behavior, + # this should be safe. + results = child_process.spawnSync shell, ["-ilc"], input: "env", encoding: "utf8" + return if results.error? + return unless results.stdout and results.stdout.length > 0 + + results.stdout + +module.exports = + # Gets the user's configured shell environment. + # + # Returns a copy of the user's shell enviroment. + getShellEnv: -> + shellEnvText = getRawShellEnv() + return unless shellEnvText? + + env = {} + + for line in shellEnvText.split(os.EOL) + if line.includes("=") + components = line.split("=") + if components.length is 2 + env[components[0]] = components[1] + else + k = components.shift() + v = components.join("=") + env[k] = v + + env From a3ba15c8a13c5cc61155df9b33abdf6c5c58ddbf Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Tue, 8 Mar 2016 15:50:53 -0800 Subject: [PATCH 166/273] Update Project to use new environment module --- spec/project-spec.coffee | 20 +++++++++---------- src/project.coffee | 43 +++------------------------------------- 2 files changed, 13 insertions(+), 50 deletions(-) diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 35cd0157f..f5fcad8e3 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -8,6 +8,8 @@ BufferedProcess = require '../src/buffered-process' {Directory} = require 'pathwatcher' GitRepository = require '../src/git-repository' +environment = require '../src/environment' + describe "Project", -> beforeEach -> atom.project.setPaths([atom.project.getDirectories()[0]?.resolve('dir')]) @@ -581,21 +583,19 @@ describe "Project", -> beforeEach -> delete process.env.TERM - it "replaces the PATH with the one obtained from the shell", -> - spyOn(atom.project, "getShellEnv").andReturn """ - FOO=BAR - TERM=xterm-something - PATH=/usr/bin:/bin:/usr/sbin:/sbin:/some/crazy/path/entry/that/should/not/exist - """ + it "replaces the environment with the one obtained from the shell", -> + spyOn(environment, "getShellEnv").andReturn + FOO: "BAR" + TERM: "xterm-something" + PATH: "/usr/bin:/bin:/usr/sbin:/sbin:/some/crazy/path/entry/that/should/not/exist" - expect(atom.project.getShellPath()).toEqual "/usr/bin:/bin:/usr/sbin:/sbin:/some/crazy/path/entry/that/should/not/exist" + expect(atom.project.getEnv().TERM).toEqual "xterm-something" expect(atom.project.getEnv().PATH).toEqual "/usr/bin:/bin:/usr/sbin:/sbin:/some/crazy/path/entry/that/should/not/exist" - expect(atom.project.getEnv().FOO).not.toEqual "BAR" + expect(atom.project.getEnv().FOO).toEqual "BAR" it "does the best it can when there is an error retrieving the shell environment", -> - spyOn(atom.project, "getShellEnv").andReturn(undefined) + spyOn(environment, "getShellEnv").andReturn(undefined) - expect(atom.project.getShellPath()).toBeUndefined() expect(atom.project.getEnv().PATH).not.toBeUndefined() expect(atom.project.getEnv().PATH).toEqual process.env.PATH diff --git a/src/project.coffee b/src/project.coffee index c8fd3ddbe..2a21aa2d8 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -288,8 +288,9 @@ class Project extends Model unless @env? @env = _.clone(process.env) if process.platform is "darwin" and not process.env.TERM? - shellPath = @getShellPath() - @env.PATH = shellPath if shellPath? + {getShellEnv} = require("../src/environment") + shellEnv = getShellEnv() + @env = shellEnv if shellEnv? _.clone(@env) @@ -297,44 +298,6 @@ class Project extends Model Section: Private ### - # Gets the user's configured shell `PATH`. - # - # Returns the value of `PATH` or `undefined` if there was an error. - getShellPath: -> - shellEnvText = @getShellEnv() - return unless shellEnvText? - - env = {} - - for line in shellEnvText.split(os.EOL) - if line.includes("=") - components = line.split("=") - if components.length is 2 - env[components[0]] = components[1] - else - k = components.shift() - v = components.join("=") - env[k] = v - - env.PATH - - # Gets a dump of the user's configured shell environment. - # - # Returns the output of the `env` command or `undefined` if there was an error. - getShellEnv: -> - shell = process.env.SHELL ? "/bin/bash" - - # The `-ilc` set of options was tested to work with the OS X v10.11 - # default-installed versions of bash, zsh, sh, and ksh. It *does not* - # work with csh or tcsh. Given that bash and zsh should cover the - # vast majority of users and it gracefully falls back to prior behavior, - # this should be safe. - results = child_process.spawnSync shell, ["-ilc"], input: "env", encoding: "utf8" - return if results.error? - return unless results.stdout and results.stdout.length > 0 - - results.stdout - consumeServices: ({serviceHub}) -> serviceHub.consume( 'atom.directory-provider', From b98388fa762e27c357613b9f8f8e2f2b0e74bd95 Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Tue, 8 Mar 2016 16:23:48 -0800 Subject: [PATCH 167/273] Fix broken command parameter --- spec/environment-spec.coffee | 4 ++-- src/atom-environment.coffee | 3 ++- src/environment.coffee | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/spec/environment-spec.coffee b/spec/environment-spec.coffee index 484bdcc1a..9eac5b071 100644 --- a/spec/environment-spec.coffee +++ b/spec/environment-spec.coffee @@ -1,7 +1,7 @@ child_process = require('child_process') {getShellEnv} = require("../src/environment") -describe "Environment handling", -> +fdescribe "Environment handling", -> describe "when things are configured properly", -> beforeEach -> spyOn(child_process, "spawnSync").andReturn @@ -21,7 +21,7 @@ describe "Environment handling", -> describe "when an error occurs", -> beforeEach -> spyOn(child_process, "spawnSync").andReturn - error: new Error + error: new Error("testing when an error occurs") it "returns undefined", -> expect(getShellEnv()).toBeUndefined() diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index d1e921d54..e43051571 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -231,7 +231,8 @@ class AtomEnvironment extends Model checkPortableHomeWritable() # Patch the `process.env` on startup to fix the problem first documented - # in #4126 + # in #4126. Retain the original in case someone needs it. + process._originalEnv = process.env process.env = @project.getEnv() attachSaveStateListeners: -> diff --git a/src/environment.coffee b/src/environment.coffee index f2b9bbf47..56de0c194 100644 --- a/src/environment.coffee +++ b/src/environment.coffee @@ -12,7 +12,7 @@ getRawShellEnv = -> # work with csh or tcsh. Given that bash and zsh should cover the # vast majority of users and it gracefully falls back to prior behavior, # this should be safe. - results = child_process.spawnSync shell, ["-ilc"], input: "env", encoding: "utf8" + results = child_process.spawnSync(shell, ["-ilc", "env"], encoding: "utf8") return if results.error? return unless results.stdout and results.stdout.length > 0 From 6b38049b8d10deb9abf66fbdb19d2280e04075f2 Mon Sep 17 00:00:00 2001 From: Joe Fitzgerald Date: Thu, 10 Mar 2016 15:16:41 -0700 Subject: [PATCH 168/273] Remove Project API, Work With process.env Directly - Convert environment.coffee and environment-spec.coffee to JavaScript - Pass the process's environment across the wire when launching atom multiple times from the command line --- spec/atom-environment-spec.coffee | 13 -- spec/environment-spec.coffee | 27 ---- spec/environment-spec.js | 161 +++++++++++++++++++++++ spec/project-spec.coffee | 68 ---------- src/atom-environment.coffee | 7 +- src/browser/atom-application.coffee | 29 ++-- src/browser/main.coffee | 1 + src/environment.coffee | 41 ------ src/environment.js | 94 +++++++++++++ src/initialize-application-window.coffee | 3 +- src/project.coffee | 20 --- 11 files changed, 275 insertions(+), 189 deletions(-) delete mode 100644 spec/environment-spec.coffee create mode 100644 spec/environment-spec.js delete mode 100644 src/environment.coffee create mode 100644 src/environment.js diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index 6271ea5d4..3283b63d6 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -362,16 +362,3 @@ describe "AtomEnvironment", -> version = '1.7.0-dev-5340c91' expect(atom.getReleaseChannel()).toBe 'dev' - - describe "environment patching", -> - it "patches process.env on startup", -> - configDirPath = temp.mkdirSync() - fakeDocument = { - addEventListener: -> - removeEventListener: -> - head: document.createElement('head') - body: document.createElement('body') - } - atomEnvironment = new AtomEnvironment({applicationDelegate: atom.applicationDelegate, window, document: fakeDocument}) - - expect(process.env).toEqual atomEnvironment.project.getEnv() diff --git a/spec/environment-spec.coffee b/spec/environment-spec.coffee deleted file mode 100644 index 9eac5b071..000000000 --- a/spec/environment-spec.coffee +++ /dev/null @@ -1,27 +0,0 @@ -child_process = require('child_process') -{getShellEnv} = require("../src/environment") - -fdescribe "Environment handling", -> - describe "when things are configured properly", -> - beforeEach -> - spyOn(child_process, "spawnSync").andReturn - stdout: """ - FOO=BAR - TERM=xterm-something - PATH=/usr/bin:/bin:/usr/sbin:/sbin:/some/crazy/path/entry/that/should/not/exist - """ - - it "returns an object containing the information from the user's shell environment", -> - env = getShellEnv() - - expect(env.FOO).toEqual "BAR" - expect(env.TERM).toEqual "xterm-something" - expect(env.PATH).toEqual "/usr/bin:/bin:/usr/sbin:/sbin:/some/crazy/path/entry/that/should/not/exist" - - describe "when an error occurs", -> - beforeEach -> - spyOn(child_process, "spawnSync").andReturn - error: new Error("testing when an error occurs") - - it "returns undefined", -> - expect(getShellEnv()).toBeUndefined() diff --git a/spec/environment-spec.js b/spec/environment-spec.js new file mode 100644 index 000000000..ae36d7d2c --- /dev/null +++ b/spec/environment-spec.js @@ -0,0 +1,161 @@ +'use babel' +/* eslint-env jasmine */ + +import child_process from 'child_process' +import environment from '../src/environment' +import os from 'os' +import _ from 'underscore-plus' + +fdescribe('Environment handling', () => { + let originalEnv + let options + + beforeEach(() => { + originalEnv = process.env + delete process._originalEnv + options = { + platform: process.platform, + env: _.clone(process.env) + } + }) + + afterEach(() => { + process.env = originalEnv + delete process._originalEnv + }) + + describe('on OSX, when PWD is not set', () => { + beforeEach(() => { + options.platform = 'darwin' + }) + + describe('needsPatching', () => { + it('returns true if PWD is unset', () => { + delete options.env.PWD + expect(environment.needsPatching(options)).toBe(true) + options.env.PWD = undefined + expect(environment.needsPatching(options)).toBe(true) + options.env.PWD = null + expect(environment.needsPatching(options)).toBe(true) + options.env.PWD = false + expect(environment.needsPatching(options)).toBe(true) + }) + + it('returns false if PWD is set', () => { + options.env.PWD = 'xterm' + expect(environment.needsPatching(options)).toBe(false) + }) + }) + + describe('normalize', () => { + it('changes process.env if PWD is unset', () => { + if (process.platform === 'win32') { + return + } + delete options.env.PWD + environment.normalize(options) + expect(process._originalEnv).toBeDefined() + expect(process._originalEnv).toBeTruthy() + expect(process.env).toBeDefined() + expect(process.env).toBeTruthy() + expect(process.env.PWD).toBeDefined() + expect(process.env.PWD).toBeTruthy() + expect(process.env.PATH).toBeDefined() + expect(process.env.PATH).toBeTruthy() + expect(process.env.ATOM_HOME).toBeDefined() + expect(process.env.ATOM_HOME).toBeTruthy() + }) + }) + }) + + describe('on a platform other than OSX', () => { + beforeEach(() => { + options.platform = 'penguin' + }) + + describe('needsPatching', () => { + it('returns false if PWD is set or unset', () => { + delete options.env.PWD + expect(environment.needsPatching(options)).toBe(false) + options.env.PWD = undefined + expect(environment.needsPatching(options)).toBe(false) + options.env.PWD = null + expect(environment.needsPatching(options)).toBe(false) + options.env.PWD = false + expect(environment.needsPatching(options)).toBe(false) + options.env.PWD = '/' + expect(environment.needsPatching(options)).toBe(false) + }) + + it('returns false for linux', () => { + options.platform = 'linux' + options.PWD = '/' + expect(environment.needsPatching(options)).toBe(false) + }) + + it('returns false for windows', () => { + options.platform = 'win32' + options.PWD = 'c:\\' + expect(environment.needsPatching(options)).toBe(false) + }) + }) + + describe('normalize', () => { + it('does not change the environment', () => { + if (process.platform === 'win32') { + return + } + delete options.env.PWD + environment.normalize(options) + expect(process._originalEnv).toBeUndefined() + expect(process.env).toBeDefined() + expect(process.env).toBeTruthy() + expect(process.env.PATH).toBeDefined() + expect(process.env.PATH).toBeTruthy() + expect(process.env.PWD).toBeUndefined() + expect(process.env.PATH).toBe(originalEnv.PATH) + expect(process.env.ATOM_HOME).toBeDefined() + expect(process.env.ATOM_HOME).toBeTruthy() + }) + }) + }) + + describe('getFromShell', () => { + describe('when things are configured properly', () => { + beforeEach(() => { + spyOn(child_process, 'spawnSync').andReturn({ + stdout: 'FOO=BAR' + os.EOL + 'TERM=xterm-something' + os.EOL + + 'PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path' + }) + }) + + it('returns an object containing the information from the user\'s shell environment', () => { + let env = environment.getFromShell() + expect(env.FOO).toEqual('BAR') + expect(env.TERM).toEqual('xterm-something') + expect(env.PATH).toEqual('/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path') + }) + }) + + describe('when an error occurs launching the shell', () => { + beforeEach(() => { + spyOn(child_process, 'spawnSync').andReturn({ + error: new Error('testing when an error occurs') + }) + }) + + it('returns undefined', () => { + expect(environment.getFromShell()).toBeUndefined() + }) + + it('leaves the environment as-is when normalize() is called', () => { + options.platform = 'darwin' + delete options.env.PWD + expect(environment.needsPatching(options)).toBe(true) + environment.normalize(options) + expect(process.env).toBeDefined() + expect(process._originalEnv).toBeUndefined() + }) + }) + }) +}) diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index f5fcad8e3..499efd017 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -8,8 +8,6 @@ BufferedProcess = require '../src/buffered-process' {Directory} = require 'pathwatcher' GitRepository = require '../src/git-repository' -environment = require '../src/environment' - describe "Project", -> beforeEach -> atom.project.setPaths([atom.project.getDirectories()[0]?.resolve('dir')]) @@ -539,69 +537,3 @@ describe "Project", -> randomPath = path.join("some", "random", "path") expect(atom.project.contains(randomPath)).toBe false - - describe ".getEnv", -> - [originalTerm] = [] - - beforeEach -> - originalTerm = process.env.TERM - - afterEach -> - process.env.TERM = originalTerm - delete atom.project.env - - it "returns a copy of the environment", -> - env = atom.project.getEnv() - - env.PROJECT_GET_ENV_TESTING = "foo" - expect(process.env.PROJECT_GET_ENV_TESTING).not.toEqual "foo" - expect(atom.project.getEnv().PROJECT_GET_ENV_TESTING).not.toEqual "foo" - - describe "on platforms other than OS X", -> - beforeEach -> - spyOn(process, "platform").andReturn("foo") - - describe "when TERM is not set", -> - beforeEach -> - delete process.env.TERM - - it "returns the PATH unchanged", -> - expect(atom.project.getEnv().PATH).toEqual process.env.PATH - - describe "when TERM is set", -> - beforeEach -> - process.env.TERM = "foo" - - it "returns the PATH unchanged", -> - expect(atom.project.getEnv().PATH).toEqual process.env.PATH - - describe "on OS X", -> - beforeEach -> - spyOn(process, "platform").andReturn("darwin") - - describe "when TERM is not set", -> - beforeEach -> - delete process.env.TERM - - it "replaces the environment with the one obtained from the shell", -> - spyOn(environment, "getShellEnv").andReturn - FOO: "BAR" - TERM: "xterm-something" - PATH: "/usr/bin:/bin:/usr/sbin:/sbin:/some/crazy/path/entry/that/should/not/exist" - - expect(atom.project.getEnv().TERM).toEqual "xterm-something" - expect(atom.project.getEnv().PATH).toEqual "/usr/bin:/bin:/usr/sbin:/sbin:/some/crazy/path/entry/that/should/not/exist" - expect(atom.project.getEnv().FOO).toEqual "BAR" - - it "does the best it can when there is an error retrieving the shell environment", -> - spyOn(environment, "getShellEnv").andReturn(undefined) - - expect(atom.project.getEnv().PATH).not.toBeUndefined() - expect(atom.project.getEnv().PATH).toEqual process.env.PATH - - describe "when TERM is set", -> - beforeEach -> - process.env.TERM = "foo" - - it "returns the PATH unchanged", -> - expect(atom.project.getEnv().PATH).toEqual process.env.PATH diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index e43051571..97ec3c5d4 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -4,6 +4,7 @@ path = require 'path' _ = require 'underscore-plus' {deprecate} = require 'grim' +environment = require('./environment') {CompositeDisposable, Disposable, Emitter} = require 'event-kit' fs = require 'fs-plus' {mapSourcePosition} = require 'source-map-support' @@ -127,6 +128,7 @@ class AtomEnvironment extends Model # Call .loadOrCreate instead constructor: (params={}) -> + environment.normalize(params) {@blobStore, @applicationDelegate, @window, @document, configDirPath, @enablePersistence, onlyLoadBaseStyleSheets} = params @unloaded = false @@ -230,11 +232,6 @@ class AtomEnvironment extends Model checkPortableHomeWritable() - # Patch the `process.env` on startup to fix the problem first documented - # in #4126. Retain the original in case someone needs it. - process._originalEnv = process.env - process.env = @project.getEnv() - attachSaveStateListeners: -> saveState = => @saveState({isUnloading: false}) unless @unloaded debouncedSaveState = _.debounce(saveState, @saveStateDebounceInterval) diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index 230e1bb9f..4767c9065 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -85,16 +85,16 @@ class AtomApplication else @loadState(options) or @openPath(options) - openWithOptions: ({initialPaths, pathsToOpen, executedFrom, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, newWindow, logFile, profileStartup, timeout, clearWindowState, addToLastWindow}) -> + openWithOptions: ({initialPaths, pathsToOpen, executedFrom, urlsToOpen, test, pidToKillWhenClosed, devMode, safeMode, newWindow, logFile, profileStartup, timeout, clearWindowState, addToLastWindow, env}) -> if test - @runTests({headless: true, devMode, @resourcePath, executedFrom, pathsToOpen, logFile, timeout}) + @runTests({headless: true, devMode, @resourcePath, executedFrom, pathsToOpen, logFile, timeout, env}) else if pathsToOpen.length > 0 - @openPaths({initialPaths, pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, clearWindowState, addToLastWindow}) + @openPaths({initialPaths, pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, clearWindowState, addToLastWindow, env}) else if urlsToOpen.length > 0 - @openUrl({urlToOpen, devMode, safeMode}) for urlToOpen in urlsToOpen + @openUrl({urlToOpen, devMode, safeMode, env}) for urlToOpen in urlsToOpen else # Always open a editor window if this is the first instance of Atom. - @openPath({initialPaths, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, clearWindowState, addToLastWindow}) + @openPath({initialPaths, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, clearWindowState, addToLastWindow, env}) # Public: Removes the {AtomWindow} from the global window list. removeWindow: (window) -> @@ -134,7 +134,8 @@ class AtomApplication @deleteSocketFile() server = net.createServer (connection) => connection.on 'data', (data) => - @openWithOptions(JSON.parse(data)) + options = JSON.parse(data) + @openWithOptions(options) server.listen @socketPath server.on 'error', (error) -> console.error 'Application server failed', error @@ -418,8 +419,8 @@ class AtomApplication # :profileStartup - Boolean to control creating a profile of the startup time. # :window - {AtomWindow} to open file paths in. # :addToLastWindow - Boolean of whether this should be opened in last focused window. - openPath: ({initialPaths, pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window, clearWindowState, addToLastWindow} = {}) -> - @openPaths({initialPaths, pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window, clearWindowState, addToLastWindow}) + openPath: ({initialPaths, pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window, clearWindowState, addToLastWindow, env} = {}) -> + @openPaths({initialPaths, pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window, clearWindowState, addToLastWindow, env}) # Public: Opens multiple paths, in existing windows if possible. # @@ -432,7 +433,7 @@ class AtomApplication # :windowDimensions - Object with height and width keys. # :window - {AtomWindow} to open file paths in. # :addToLastWindow - Boolean of whether this should be opened in last focused window. - openPaths: ({initialPaths, pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, profileStartup, window, clearWindowState, addToLastWindow}={}) -> + openPaths: ({initialPaths, pathsToOpen, executedFrom, pidToKillWhenClosed, newWindow, devMode, safeMode, windowDimensions, profileStartup, window, clearWindowState, addToLastWindow, env}={}) -> devMode = Boolean(devMode) safeMode = Boolean(safeMode) clearWindowState = Boolean(clearWindowState) @@ -469,7 +470,7 @@ class AtomApplication windowInitializationScript ?= require.resolve('../initialize-application-window') resourcePath ?= @resourcePath windowDimensions ?= @getDimensionsForNewWindow() - openedWindow = new AtomWindow({initialPaths, locationsToOpen, windowInitializationScript, resourcePath, devMode, safeMode, windowDimensions, profileStartup, clearWindowState}) + openedWindow = new AtomWindow({initialPaths, locationsToOpen, windowInitializationScript, resourcePath, devMode, safeMode, windowDimensions, profileStartup, clearWindowState, env}) if pidToKillWhenClosed? @pidsToOpenWindows[pidToKillWhenClosed] = openedWindow @@ -532,7 +533,7 @@ class AtomApplication # :urlToOpen - The atom:// url to open. # :devMode - Boolean to control the opened window's dev mode. # :safeMode - Boolean to control the opened window's safe mode. - openUrl: ({urlToOpen, devMode, safeMode}) -> + openUrl: ({urlToOpen, devMode, safeMode, env}) -> unless @packages? PackageManager = require '../package-manager' @packages = new PackageManager @@ -547,7 +548,7 @@ class AtomApplication packagePath = @packages.resolvePackagePath(packageName) windowInitializationScript = path.resolve(packagePath, pack.urlMain) windowDimensions = @getDimensionsForNewWindow() - new AtomWindow({windowInitializationScript, @resourcePath, devMode, safeMode, urlToOpen, windowDimensions}) + new AtomWindow({windowInitializationScript, @resourcePath, devMode, safeMode, urlToOpen, windowDimensions, env}) else console.log "Package '#{pack.name}' does not have a url main: #{urlToOpen}" else @@ -562,7 +563,7 @@ class AtomApplication # :specPath - The directory to load specs from. # :safeMode - A Boolean that, if true, won't run specs from ~/.atom/packages # and ~/.atom/dev/packages, defaults to false. - runTests: ({headless, resourcePath, executedFrom, pathsToOpen, logFile, safeMode, timeout}) -> + runTests: ({headless, resourcePath, executedFrom, pathsToOpen, logFile, safeMode, timeout, env}) -> if resourcePath isnt @resourcePath and not fs.existsSync(resourcePath) resourcePath = @resourcePath @@ -592,7 +593,7 @@ class AtomApplication devMode = true isSpec = true safeMode ?= false - new AtomWindow({windowInitializationScript, resourcePath, headless, isSpec, devMode, testRunnerPath, legacyTestRunnerPath, testPaths, logFile, safeMode}) + new AtomWindow({windowInitializationScript, resourcePath, headless, isSpec, devMode, testRunnerPath, legacyTestRunnerPath, testPaths, logFile, safeMode, env}) resolveTestRunnerPath: (testPath) -> FindParentDir ?= require 'find-parent-dir' diff --git a/src/browser/main.coffee b/src/browser/main.coffee index b4df62bd6..6bf8817f9 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -13,6 +13,7 @@ console.log = require 'nslog' start = -> args = parseCommandLine() + args.env = process.env setupAtomHome(args) setupCompileCache() return if handleStartupEventWithSquirrel() diff --git a/src/environment.coffee b/src/environment.coffee deleted file mode 100644 index 56de0c194..000000000 --- a/src/environment.coffee +++ /dev/null @@ -1,41 +0,0 @@ -child_process = require('child_process') -os = require('os') - -# Gets a dump of the user's configured shell environment. -# -# Returns the output of the `env` command or `undefined` if there was an error. -getRawShellEnv = -> - shell = process.env.SHELL ? "/bin/bash" - - # The `-ilc` set of options was tested to work with the OS X v10.11 - # default-installed versions of bash, zsh, sh, and ksh. It *does not* - # work with csh or tcsh. Given that bash and zsh should cover the - # vast majority of users and it gracefully falls back to prior behavior, - # this should be safe. - results = child_process.spawnSync(shell, ["-ilc", "env"], encoding: "utf8") - return if results.error? - return unless results.stdout and results.stdout.length > 0 - - results.stdout - -module.exports = - # Gets the user's configured shell environment. - # - # Returns a copy of the user's shell enviroment. - getShellEnv: -> - shellEnvText = getRawShellEnv() - return unless shellEnvText? - - env = {} - - for line in shellEnvText.split(os.EOL) - if line.includes("=") - components = line.split("=") - if components.length is 2 - env[components[0]] = components[1] - else - k = components.shift() - v = components.join("=") - env[k] = v - - env diff --git a/src/environment.js b/src/environment.js new file mode 100644 index 000000000..00c112bda --- /dev/null +++ b/src/environment.js @@ -0,0 +1,94 @@ +'use babel' + +import {spawnSync} from 'child_process' +import os from 'os' + +// Gets a dump of the user's configured shell environment. +// +// Returns the output of the `env` command or `undefined` if there was an error. +function getRawShellEnv () { + let shell = getUserShell() + + // The `-ilc` set of options was tested to work with the OS X v10.11 + // default-installed versions of bash, zsh, sh, and ksh. It *does not* + // work with csh or tcsh. + let results = spawnSync(shell, ['-ilc', 'env'], {encoding: 'utf8'}) + if (results.error || !results.stdout || results.stdout.length <= 0) { + return + } + + return results.stdout +} + +function getUserShell () { + if (process.env.SHELL) { + return process.env.SHELL + } + + return '/bin/bash' +} + +// Gets the user's configured shell environment. +// +// Returns a copy of the user's shell enviroment. +function getFromShell () { + let shellEnvText = getRawShellEnv() + if (!shellEnvText) { + return + } + + let env = {} + + for (let line of shellEnvText.split(os.EOL)) { + if (line.includes('=')) { + let components = line.split('=') + if (components.length === 2) { + env[components[0]] = components[1] + } else { + let k = components.shift() + let v = components.join('=') + env[k] = v + } + } + } + + return env +} + +function needsPatching (options = { platform: process.platform, env: process.env }) { + if (options.platform === 'darwin' && !options.env.PWD) { + let shell = getUserShell() + if (shell.endsWith('csh') || shell.endsWith('tcsh')) { + return false + } + return true + } + + return false +} + +function normalize (options = {}) { + if (options && options.env) { + process.env = options.env + } + + if (!options.env) { + options.env = process.env + } + + if (!options.platform) { + options.platform = process.platform + } + + if (needsPatching(options)) { + // Patch the `process.env` on startup to fix the problem first documented + // in #4126. Retain the original in case someone needs it. + let shellEnv = getFromShell() + if (shellEnv && shellEnv.PATH) { + process._originalEnv = process.env + process.env = shellEnv + } + } +} + +export default { getFromShell, needsPatching, normalize } diff --git a/src/initialize-application-window.coffee b/src/initialize-application-window.coffee index cea4e1c3c..10f321ded 100644 --- a/src/initialize-application-window.coffee +++ b/src/initialize-application-window.coffee @@ -4,7 +4,7 @@ module.exports = ({blobStore}) -> require './window' {getWindowLoadSettings} = require './window-load-settings-helpers' - {resourcePath, isSpec, devMode} = getWindowLoadSettings() + {resourcePath, isSpec, devMode, env} = getWindowLoadSettings() # Add application-specific exports to module search path. exportsPath = path.join(resourcePath, 'exports') @@ -21,6 +21,7 @@ module.exports = ({blobStore}) -> applicationDelegate: new ApplicationDelegate, configDirPath: process.env.ATOM_HOME enablePersistence: true + env: env }) atom.startEditorWindow().then -> diff --git a/src/project.coffee b/src/project.coffee index 2a21aa2d8..340075a1b 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -274,26 +274,6 @@ class Project extends Model contains: (pathToCheck) -> @rootDirectories.some (dir) -> dir.contains(pathToCheck) - ### - Section: Environment - ### - - # Public: Retrieves a normalized copy of the environment. - # - # On OS X, the `PATH` can be different depending on whether Atom is launched - # from the Dock, Finder, Spotlight or the terminal. This detects how Atom was - # started and corrects the `PATH` environment variable before returning a copy - # of the environment. - getEnv: -> - unless @env? - @env = _.clone(process.env) - if process.platform is "darwin" and not process.env.TERM? - {getShellEnv} = require("../src/environment") - shellEnv = getShellEnv() - @env = shellEnv if shellEnv? - - _.clone(@env) - ### Section: Private ### From 87c20bd0958f410ac0a7b05e4ad48a77043edd8b Mon Sep 17 00:00:00 2001 From: Joe Fitzgerald Date: Thu, 10 Mar 2016 15:46:25 -0700 Subject: [PATCH 169/273] Remove Cruft --- src/project.coffee | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/project.coffee b/src/project.coffee index 340075a1b..93a3ed496 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -12,9 +12,6 @@ TextEditor = require './text-editor' Task = require './task' GitRepositoryProvider = require './git-repository-provider' -child_process = require 'child_process' -os = require 'os' - # Extended: Represents a project that's opened in Atom. # # An instance of this class is always available as the `atom.project` global. From 4e2db07dd96c13c966f84a86c01ec3ca9d7048cd Mon Sep 17 00:00:00 2001 From: simurai Date: Fri, 11 Mar 2016 10:13:31 +0900 Subject: [PATCH 170/273] :arrow_up: markdown-preview@v0.158.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d2cb82195..0194a5ad4 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "keybinding-resolver": "0.35.0", "line-ending-selector": "0.3.1", "link": "0.31.0", - "markdown-preview": "0.157.3", + "markdown-preview": "0.158.0", "metrics": "0.53.1", "notifications": "0.62.4", "open-on-github": "1.0.0", From 61fb12bf9aae6729c6eb2220b3f689382777a4e5 Mon Sep 17 00:00:00 2001 From: Joe Fitzgerald Date: Thu, 10 Mar 2016 19:59:26 -0700 Subject: [PATCH 171/273] Unfocus Spec --- spec/environment-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/environment-spec.js b/spec/environment-spec.js index ae36d7d2c..8d845a3f8 100644 --- a/spec/environment-spec.js +++ b/spec/environment-spec.js @@ -6,7 +6,7 @@ import environment from '../src/environment' import os from 'os' import _ from 'underscore-plus' -fdescribe('Environment handling', () => { +describe('Environment handling', () => { let originalEnv let options From bd4ef0a44381a6445d17063ff944bc91fd54a1ce Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Thu, 10 Mar 2016 20:17:19 -0800 Subject: [PATCH 172/273] :arrow_up: tabs@0.92.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d2cb82195..0b823926b 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "status-bar": "1.1.1", "styleguide": "0.45.2", "symbols-view": "0.112.0", - "tabs": "0.91.3", + "tabs": "0.92.0", "timecop": "0.33.1", "tree-view": "0.203.0", "update-package-dependencies": "0.10.0", From 383174d3803ef5e5ce658be1a94529516836b0b6 Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Thu, 10 Mar 2016 21:27:10 -0800 Subject: [PATCH 173/273] Load apm path from config Signed-off-by: Katrina Uychaco --- spec/package-manager-spec.coffee | 14 ++++++++++++++ src/package-manager.coffee | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index 3b54691b2..6a1610a8a 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -17,6 +17,20 @@ describe "PackageManager", -> beforeEach -> workspaceElement = atom.views.getView(atom.workspace) + describe "::getApmPath()", -> + it "returns the path to the apm command", -> + apmPath = path.join(process.resourcesPath, "app", "apm", "bin", "apm") + if process.platform is 'win32' + apmPath += ".cmd" + expect(atom.packages.getApmPath()).toBe apmPath + + describe "when the core.apmPath setting is set", -> + beforeEach -> + atom.config.set("core.apmPath", "/path/to/apm") + + it "returns the value of the core.apmPath config setting", -> + expect(atom.packages.getApmPath()).toBe "/path/to/apm" + describe "::loadPackage(name)", -> beforeEach -> atom.config.set("core.disabledPackages", []) diff --git a/src/package-manager.coffee b/src/package-manager.coffee index 94b55a793..0e76a762f 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -128,8 +128,12 @@ class PackageManager # Public: Get the path to the apm command. # + # Uses the value of the `core.apmPath` config setting if it exists. + # # Return a {String} file path to apm. getApmPath: -> + configPath = atom.config.get('core.apmPath') + return configPath if configPath return @apmPath if @apmPath? commandName = 'apm' From 466e554ee19cb90e3b0eb5f23924721b6ac4bb9f Mon Sep 17 00:00:00 2001 From: Willem Van Lint Date: Wed, 2 Mar 2016 22:35:33 -0800 Subject: [PATCH 174/273] Add TextEditors to the registry on opt-in only --- src/text-editor.coffee | 6 ++++-- src/workspace.coffee | 10 +++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 5e384fde1..8b503f16e 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -83,8 +83,9 @@ class TextEditor extends Model state.assert = atomEnvironment.assert.bind(atomEnvironment) state.applicationDelegate = atomEnvironment.applicationDelegate editor = new this(state) - disposable = atomEnvironment.textEditors.add(editor) - editor.onDidDestroy -> disposable.dispose() + if state.registered + disposable = atomEnvironment.textEditors.add(editor) + editor.onDidDestroy -> disposable.dispose() editor constructor: (params={}) -> @@ -155,6 +156,7 @@ class TextEditor extends Model firstVisibleScreenColumn: @getFirstVisibleScreenColumn() displayBuffer: @displayBuffer.serialize() selectionsMarkerLayerId: @selectionsMarkerLayer.id + registered: atom.textEditors.editors.has this subscribeToBuffer: -> @buffer.retain() diff --git a/src/workspace.coffee b/src/workspace.coffee index c925a495a..bdaf19eee 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -542,7 +542,10 @@ class Workspace extends Model throw error @project.bufferForPath(filePath, options).then (buffer) => - @buildTextEditor(_.extend({buffer, largeFileMode}, options)) + editor = @buildTextEditor(_.extend({buffer, largeFileMode}, options)) + disposable = atom.textEditors.add(editor) + editor.onDidDestroy -> disposable.dispose() + editor # Public: Returns a {Boolean} that is `true` if `object` is a `TextEditor`. # @@ -558,10 +561,7 @@ class Workspace extends Model @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, @project, @assert, @applicationDelegate }, params) - editor = new TextEditor(params) - disposable = atom.textEditors.add(editor) - editor.onDidDestroy -> disposable.dispose() - editor + new TextEditor(params) # Public: Asynchronously reopens the last-closed item's URI if it hasn't already been # reopened. From edd91839a86dd9498a32a1ad2991a8f925f19685 Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Fri, 11 Mar 2016 13:34:03 -0800 Subject: [PATCH 175/273] :arrow_up: language-ruby@0.68.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 417a46c76..77f54798b 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "language-php": "0.37.0", "language-property-list": "0.8.0", "language-python": "0.43.0", - "language-ruby": "0.68.1", + "language-ruby": "0.68.2", "language-ruby-on-rails": "0.25.0", "language-sass": "0.45.0", "language-shellscript": "0.21.0", From f671d5c5cdc6921c24bd73aea9c6edd30a1ce253 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Fri, 11 Mar 2016 17:32:13 -0500 Subject: [PATCH 176/273] :arrow_up: language-ruby@0.68.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 77f54798b..4612c9745 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "language-php": "0.37.0", "language-property-list": "0.8.0", "language-python": "0.43.0", - "language-ruby": "0.68.2", + "language-ruby": "0.68.3", "language-ruby-on-rails": "0.25.0", "language-sass": "0.45.0", "language-shellscript": "0.21.0", From 63ec05416165bb75179b30562a900133c03bcf53 Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Fri, 11 Mar 2016 16:51:50 -0800 Subject: [PATCH 177/273] Rename environment -> environmentHelpers --- ...nt-spec.js => environment-helpers-spec.js} | 38 +++++++++---------- src/atom-environment.coffee | 4 +- ...{environment.js => environment-helpers.js} | 0 3 files changed, 21 insertions(+), 21 deletions(-) rename spec/{environment-spec.js => environment-helpers-spec.js} (76%) rename src/{environment.js => environment-helpers.js} (100%) diff --git a/spec/environment-spec.js b/spec/environment-helpers-spec.js similarity index 76% rename from spec/environment-spec.js rename to spec/environment-helpers-spec.js index 8d845a3f8..4d0e7d4aa 100644 --- a/spec/environment-spec.js +++ b/spec/environment-helpers-spec.js @@ -2,7 +2,7 @@ /* eslint-env jasmine */ import child_process from 'child_process' -import environment from '../src/environment' +import environmentHelpers from '../src/environment-helpers' import os from 'os' import _ from 'underscore-plus' @@ -32,18 +32,18 @@ describe('Environment handling', () => { describe('needsPatching', () => { it('returns true if PWD is unset', () => { delete options.env.PWD - expect(environment.needsPatching(options)).toBe(true) + expect(environmentHelpers.needsPatching(options)).toBe(true) options.env.PWD = undefined - expect(environment.needsPatching(options)).toBe(true) + expect(environmentHelpers.needsPatching(options)).toBe(true) options.env.PWD = null - expect(environment.needsPatching(options)).toBe(true) + expect(environmentHelpers.needsPatching(options)).toBe(true) options.env.PWD = false - expect(environment.needsPatching(options)).toBe(true) + expect(environmentHelpers.needsPatching(options)).toBe(true) }) it('returns false if PWD is set', () => { options.env.PWD = 'xterm' - expect(environment.needsPatching(options)).toBe(false) + expect(environmentHelpers.needsPatching(options)).toBe(false) }) }) @@ -53,7 +53,7 @@ describe('Environment handling', () => { return } delete options.env.PWD - environment.normalize(options) + environmentHelpers.normalize(options) expect(process._originalEnv).toBeDefined() expect(process._originalEnv).toBeTruthy() expect(process.env).toBeDefined() @@ -76,27 +76,27 @@ describe('Environment handling', () => { describe('needsPatching', () => { it('returns false if PWD is set or unset', () => { delete options.env.PWD - expect(environment.needsPatching(options)).toBe(false) + expect(environmentHelpers.needsPatching(options)).toBe(false) options.env.PWD = undefined - expect(environment.needsPatching(options)).toBe(false) + expect(environmentHelpers.needsPatching(options)).toBe(false) options.env.PWD = null - expect(environment.needsPatching(options)).toBe(false) + expect(environmentHelpers.needsPatching(options)).toBe(false) options.env.PWD = false - expect(environment.needsPatching(options)).toBe(false) + expect(environmentHelpers.needsPatching(options)).toBe(false) options.env.PWD = '/' - expect(environment.needsPatching(options)).toBe(false) + expect(environmentHelpers.needsPatching(options)).toBe(false) }) it('returns false for linux', () => { options.platform = 'linux' options.PWD = '/' - expect(environment.needsPatching(options)).toBe(false) + expect(environmentHelpers.needsPatching(options)).toBe(false) }) it('returns false for windows', () => { options.platform = 'win32' options.PWD = 'c:\\' - expect(environment.needsPatching(options)).toBe(false) + expect(environmentHelpers.needsPatching(options)).toBe(false) }) }) @@ -106,7 +106,7 @@ describe('Environment handling', () => { return } delete options.env.PWD - environment.normalize(options) + environmentHelpers.normalize(options) expect(process._originalEnv).toBeUndefined() expect(process.env).toBeDefined() expect(process.env).toBeTruthy() @@ -130,7 +130,7 @@ describe('Environment handling', () => { }) it('returns an object containing the information from the user\'s shell environment', () => { - let env = environment.getFromShell() + let env = environmentHelpers.getFromShell() expect(env.FOO).toEqual('BAR') expect(env.TERM).toEqual('xterm-something') expect(env.PATH).toEqual('/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path') @@ -145,14 +145,14 @@ describe('Environment handling', () => { }) it('returns undefined', () => { - expect(environment.getFromShell()).toBeUndefined() + expect(environmentHelpers.getFromShell()).toBeUndefined() }) it('leaves the environment as-is when normalize() is called', () => { options.platform = 'darwin' delete options.env.PWD - expect(environment.needsPatching(options)).toBe(true) - environment.normalize(options) + expect(environmentHelpers.needsPatching(options)).toBe(true) + environmentHelpers.normalize(options) expect(process.env).toBeDefined() expect(process._originalEnv).toBeUndefined() }) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 97ec3c5d4..a173443ce 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -4,7 +4,7 @@ path = require 'path' _ = require 'underscore-plus' {deprecate} = require 'grim' -environment = require('./environment') +environmentHelpers = require('./environment-helpers') {CompositeDisposable, Disposable, Emitter} = require 'event-kit' fs = require 'fs-plus' {mapSourcePosition} = require 'source-map-support' @@ -128,7 +128,7 @@ class AtomEnvironment extends Model # Call .loadOrCreate instead constructor: (params={}) -> - environment.normalize(params) + environmentHelpers.normalize(params) {@blobStore, @applicationDelegate, @window, @document, configDirPath, @enablePersistence, onlyLoadBaseStyleSheets} = params @unloaded = false diff --git a/src/environment.js b/src/environment-helpers.js similarity index 100% rename from src/environment.js rename to src/environment-helpers.js From 01a1a1d80c104300dc57842a54caddbb69433424 Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Fri, 11 Mar 2016 16:57:02 -0800 Subject: [PATCH 178/273] Swap _.clone for Object.assign --- spec/environment-helpers-spec.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/environment-helpers-spec.js b/spec/environment-helpers-spec.js index 4d0e7d4aa..20ec15d9f 100644 --- a/spec/environment-helpers-spec.js +++ b/spec/environment-helpers-spec.js @@ -4,7 +4,6 @@ import child_process from 'child_process' import environmentHelpers from '../src/environment-helpers' import os from 'os' -import _ from 'underscore-plus' describe('Environment handling', () => { let originalEnv @@ -15,7 +14,7 @@ describe('Environment handling', () => { delete process._originalEnv options = { platform: process.platform, - env: _.clone(process.env) + env: Object.assign({}, process.env) } }) From c99a272f0166c5063ab281cc54c0921da96e911a Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Sat, 12 Mar 2016 16:10:45 -0500 Subject: [PATCH 179/273] :arrow_up: language-json@0.17.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4612c9745..748cf9840 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "language-hyperlink": "0.16.0", "language-java": "0.17.0", "language-javascript": "0.110.0", - "language-json": "0.17.5", + "language-json": "0.17.6", "language-less": "0.29.0", "language-make": "0.21.0", "language-mustache": "0.13.0", From 4798d6d7ce5e44ec16f0121e344bee94f7cdfc80 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Sun, 13 Mar 2016 13:18:14 -0400 Subject: [PATCH 180/273] :arrow_up: tree-view@0.203.1 Refs #10983 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 748cf9840..efaca8685 100644 --- a/package.json +++ b/package.json @@ -112,7 +112,7 @@ "symbols-view": "0.112.0", "tabs": "0.92.0", "timecop": "0.33.1", - "tree-view": "0.203.0", + "tree-view": "0.203.1", "update-package-dependencies": "0.10.0", "welcome": "0.34.0", "whitespace": "0.32.2", From ad91f0ffc20331962099793ac4f757122f5fffd5 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Sun, 13 Mar 2016 15:55:39 -0400 Subject: [PATCH 181/273] :arrow_up: packages to fix Electron deprecations about@1.4.1 link@0.31.1 open-on-github@1.0.1 settings-view@0.232.5 Refs atom/atom#10983 --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index efaca8685..8d1c6371a 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "one-light-syntax": "1.2.0", "solarized-dark-syntax": "1.0.0", "solarized-light-syntax": "1.0.0", - "about": "1.4.0", + "about": "1.4.1", "archive-view": "0.61.1", "autocomplete-atom-api": "0.10.0", "autocomplete-css": "0.11.0", @@ -98,13 +98,13 @@ "incompatible-packages": "0.25.1", "keybinding-resolver": "0.35.0", "line-ending-selector": "0.3.1", - "link": "0.31.0", + "link": "0.31.1", "markdown-preview": "0.158.0", "metrics": "0.53.1", "notifications": "0.62.4", - "open-on-github": "1.0.0", + "open-on-github": "1.0.1", "package-generator": "0.41.1", - "settings-view": "0.232.4", + "settings-view": "0.232.5", "snippets": "1.0.1", "spell-check": "0.67.0", "status-bar": "1.1.1", From 579b6b7a04180d0476b849a808f6c0002f194682 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Sun, 13 Mar 2016 18:02:50 -0400 Subject: [PATCH 182/273] :arrow_up: settings-view@0.232.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8d1c6371a..cbff93802 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "notifications": "0.62.4", "open-on-github": "1.0.1", "package-generator": "0.41.1", - "settings-view": "0.232.5", + "settings-view": "0.232.6", "snippets": "1.0.1", "spell-check": "0.67.0", "status-bar": "1.1.1", From ed744c12a9d9d0a7945504f07919216b5f5346a0 Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Mon, 14 Mar 2016 08:43:16 -0700 Subject: [PATCH 183/273] Move location of call to environmentHelpers.normalize --- src/atom-environment.coffee | 2 -- src/initialize-application-window.coffee | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index a173443ce..8c79d66f6 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -4,7 +4,6 @@ path = require 'path' _ = require 'underscore-plus' {deprecate} = require 'grim' -environmentHelpers = require('./environment-helpers') {CompositeDisposable, Disposable, Emitter} = require 'event-kit' fs = require 'fs-plus' {mapSourcePosition} = require 'source-map-support' @@ -128,7 +127,6 @@ class AtomEnvironment extends Model # Call .loadOrCreate instead constructor: (params={}) -> - environmentHelpers.normalize(params) {@blobStore, @applicationDelegate, @window, @document, configDirPath, @enablePersistence, onlyLoadBaseStyleSheets} = params @unloaded = false diff --git a/src/initialize-application-window.coffee b/src/initialize-application-window.coffee index 10f321ded..ea811f515 100644 --- a/src/initialize-application-window.coffee +++ b/src/initialize-application-window.coffee @@ -1,11 +1,15 @@ # Like sands through the hourglass, so are the days of our lives. module.exports = ({blobStore}) -> + environmentHelpers = require('./environment-helpers') path = require 'path' require './window' {getWindowLoadSettings} = require './window-load-settings-helpers' {resourcePath, isSpec, devMode, env} = getWindowLoadSettings() + # Set baseline environment + environmentHelpers.normalize({env: env}) + # Add application-specific exports to module search path. exportsPath = path.join(resourcePath, 'exports') require('module').globalPaths.push(exportsPath) From d1c8fff86c89e326847385da623f13c64534c2b7 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 14 Mar 2016 13:42:05 -0400 Subject: [PATCH 184/273] Pull line length out into its own variable. --- src/buffered-process.coffee | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/buffered-process.coffee b/src/buffered-process.coffee index 183a1d99a..53934c02d 100644 --- a/src/buffered-process.coffee +++ b/src/buffered-process.coffee @@ -115,8 +115,9 @@ class BufferedProcess buffered += data lastNewlineIndex = data.lastIndexOf('\n') if lastNewlineIndex isnt -1 - onLines(buffered.substring(0, lastNewlineIndex + bufferedLength + 1)) - buffered = buffered.substring(lastNewlineIndex + bufferedLength + 1) + lineLength = lastNewlineIndex + bufferedLength + 1 + onLines(buffered.substring(0, lineLength)) + buffered = buffered.substring(lineLength) stream.on 'close', => return if @killed From 66971abe25e9ec1aed48d7bcbfabe4d8f0ba7bee Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 14 Mar 2016 14:12:31 -0400 Subject: [PATCH 185/273] Don't need that trailing space. --- spec/buffered-process-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/buffered-process-spec.coffee b/spec/buffered-process-spec.coffee index 04cff0b6d..dd166f0dc 100644 --- a/spec/buffered-process-spec.coffee +++ b/spec/buffered-process-spec.coffee @@ -97,7 +97,7 @@ describe "BufferedProcess", -> expect(ChildProcess.spawn.argsForCall[0][1][1]).toBe '/c' expect(ChildProcess.spawn.argsForCall[0][1][2]).toBe '"dir"' - it "calls the specified stdout, stderr, and exit callbacks ", -> + it "calls the specified stdout, stderr, and exit callbacks", -> stdout = '' stderr = '' exitCallback = jasmine.createSpy('exit callback') From d441da9c38a0629ce022f4e5e4013ad1b41daf9e Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 14 Mar 2016 14:12:47 -0400 Subject: [PATCH 186/273] Test it with a lot of content. --- spec/buffered-process-spec.coffee | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/spec/buffered-process-spec.coffee b/spec/buffered-process-spec.coffee index dd166f0dc..3d1a66bf8 100644 --- a/spec/buffered-process-spec.coffee +++ b/spec/buffered-process-spec.coffee @@ -114,3 +114,26 @@ describe "BufferedProcess", -> runs -> expect(stderr).toContain 'apm - Atom Package Manager' expect(stdout).toEqual '' + + it "calls the specified stdout callback only with whole lines", -> + exitCallback = jasmine.createSpy('exit callback') + baseContent = "There are dozens of us! Dozens! It's as Ann as the nose on Plain's face. Can you believe that the only reason the club is going under is because it's in a terrifying neighborhood? She calls it a Mayonegg. Waiting for the Emmys. BTW did you know won 6 Emmys and was still canceled early by Fox? COME ON. I'll buy you a hundred George Michaels that you can teach to drive! Never once touched my per diem. I'd go to Craft Service, get some raw veggies, bacon, Cup-A-Soup…baby, I got a stew goin'" + content = (baseContent for _ in [1..200]).join('\n') + outputAlwaysEndsWithStew = true + process = new BufferedProcess + command: '/bin/echo' + args: [content] + options: {} + stdout: (lines) -> + endLength = 10 + end = baseContent.substr(baseContent.length - endLength, endLength) + lineEndsWithStew = lines.substr(lines.length - endLength, endLength) is end + expect(lineEndsWithStew).toBeTrue + + outputAlwaysEndsWithStew = outputAlwaysEndsWithStew && lineEndsWithStew + exit: exitCallback + + waitsFor -> exitCallback.callCount is 1 + + runs -> + expect(outputAlwaysEndsWithStew).toBeTrue From 3601c1c2a869ac1d1d5fc73e9873384c6dde0b86 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 14 Mar 2016 14:18:06 -0400 Subject: [PATCH 187/273] Test the whole output too. --- spec/buffered-process-spec.coffee | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spec/buffered-process-spec.coffee b/spec/buffered-process-spec.coffee index 3d1a66bf8..fbaee801f 100644 --- a/spec/buffered-process-spec.coffee +++ b/spec/buffered-process-spec.coffee @@ -119,13 +119,16 @@ describe "BufferedProcess", -> exitCallback = jasmine.createSpy('exit callback') baseContent = "There are dozens of us! Dozens! It's as Ann as the nose on Plain's face. Can you believe that the only reason the club is going under is because it's in a terrifying neighborhood? She calls it a Mayonegg. Waiting for the Emmys. BTW did you know won 6 Emmys and was still canceled early by Fox? COME ON. I'll buy you a hundred George Michaels that you can teach to drive! Never once touched my per diem. I'd go to Craft Service, get some raw veggies, bacon, Cup-A-Soup…baby, I got a stew goin'" content = (baseContent for _ in [1..200]).join('\n') + stdout = '' + endLength = 10 outputAlwaysEndsWithStew = true process = new BufferedProcess command: '/bin/echo' args: [content] options: {} stdout: (lines) -> - endLength = 10 + stdout += lines + end = baseContent.substr(baseContent.length - endLength, endLength) lineEndsWithStew = lines.substr(lines.length - endLength, endLength) is end expect(lineEndsWithStew).toBeTrue @@ -137,3 +140,4 @@ describe "BufferedProcess", -> runs -> expect(outputAlwaysEndsWithStew).toBeTrue + expect(stdout).toBe content += '\n' From e69b3bb839e534bed55f2128a5e0eb4be99c12ae Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Mon, 14 Mar 2016 11:17:59 -0700 Subject: [PATCH 188/273] :arrow_up: tree-view Signed-off-by: Katrina Uychaco (cherry picked from commit 70728d8e94b06bb7fc98f5a67e54511fe2208363) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cbff93802..6798d6d02 100644 --- a/package.json +++ b/package.json @@ -112,7 +112,7 @@ "symbols-view": "0.112.0", "tabs": "0.92.0", "timecop": "0.33.1", - "tree-view": "0.203.1", + "tree-view": "0.203.2", "update-package-dependencies": "0.10.0", "welcome": "0.34.0", "whitespace": "0.32.2", From 0c67fd61ffb0250f556a317496c6a2588aeae1fe Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 14 Mar 2016 14:57:58 -0400 Subject: [PATCH 189/273] Hi lint. --- spec/buffered-process-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/buffered-process-spec.coffee b/spec/buffered-process-spec.coffee index fbaee801f..1f524d66a 100644 --- a/spec/buffered-process-spec.coffee +++ b/spec/buffered-process-spec.coffee @@ -133,7 +133,7 @@ describe "BufferedProcess", -> lineEndsWithStew = lines.substr(lines.length - endLength, endLength) is end expect(lineEndsWithStew).toBeTrue - outputAlwaysEndsWithStew = outputAlwaysEndsWithStew && lineEndsWithStew + outputAlwaysEndsWithStew = outputAlwaysEndsWithStew and lineEndsWithStew exit: exitCallback waitsFor -> exitCallback.callCount is 1 From 50f8f8e7e9770a857ec534a7cfb9d6837ffb56ff Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 14 Mar 2016 16:28:36 -0400 Subject: [PATCH 190/273] Match GitRepository's responses to null paths. Fixes https://github.com/atom/git-diff/issues/93. --- src/git-repository-async.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/git-repository-async.js b/src/git-repository-async.js index f80f46a13..3b33a5003 100644 --- a/src/git-repository-async.js +++ b/src/git-repository-async.js @@ -442,6 +442,9 @@ export default class GitRepositoryAsync { // Returns a {Promise} which resolves to a {Boolean} that's true if the `path` // is ignored. isPathIgnored (_path) { + // NB: We're matching the behavior of `GitRepository` here. + if (!_path) return Promise.resolve(false) + return this.getRepo() .then(repo => { const relativePath = this.relativize(_path, repo.workdir()) @@ -518,6 +521,10 @@ export default class GitRepositoryAsync { // Returns a {Promise} which resolves to a status {Number} or null if the // path is not in the cache. getCachedPathStatus (_path) { + // NB: I don't love this, but we're matching the behavior of + // `GitRepository` here for API compatibility. + if (!_path) return null + return this.relativizeToWorkingDirectory(_path) .then(relativePath => this.pathStatusCache[relativePath]) } From a2a6ed05c5dcafa37668884f4b00bba9873b644e Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 14 Mar 2016 16:40:55 -0400 Subject: [PATCH 191/273] And again. --- src/git-repository-async.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/git-repository-async.js b/src/git-repository-async.js index 3b33a5003..d0903acd8 100644 --- a/src/git-repository-async.js +++ b/src/git-repository-async.js @@ -660,6 +660,11 @@ export default class GitRepositoryAsync { } return this._diffBlobToBuffer(blob, text, options) }) + .catch(e => { + // NB: I don't love this, but we're matching the behavior of + // `GitRepository` here for API compatibility. + return {} + }) } // Checking Out From 164b363a32494b6adc14c43707546db692a78e05 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Mon, 14 Mar 2016 20:26:37 -0400 Subject: [PATCH 192/273] :arrow_up: language-csharp@0.12.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6798d6d02..e98962865 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "language-c": "0.51.1", "language-clojure": "0.19.1", "language-coffee-script": "0.46.1", - "language-csharp": "0.11.0", + "language-csharp": "0.12.0", "language-css": "0.36.0", "language-gfm": "0.85.0", "language-git": "0.12.1", From 9c8d947628ea186eb4c98ffe80c1e0bd1c824831 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Mon, 14 Mar 2016 22:33:56 -0400 Subject: [PATCH 193/273] :arrow_up: language-clojure@0.20.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e98962865..e0332ffa6 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "whitespace": "0.32.2", "wrap-guide": "0.38.1", "language-c": "0.51.1", - "language-clojure": "0.19.1", + "language-clojure": "0.20.0", "language-coffee-script": "0.46.1", "language-csharp": "0.12.0", "language-css": "0.36.0", From 1457e27249252668a81291a39cbd97e7d39c4f0c Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Tue, 15 Mar 2016 09:56:03 -0400 Subject: [PATCH 194/273] :arrow_up: language-sass@0.46.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e0332ffa6..8d42f8d5a 100644 --- a/package.json +++ b/package.json @@ -140,7 +140,7 @@ "language-python": "0.43.0", "language-ruby": "0.68.3", "language-ruby-on-rails": "0.25.0", - "language-sass": "0.45.0", + "language-sass": "0.46.0", "language-shellscript": "0.21.0", "language-source": "0.9.0", "language-sql": "0.20.0", From 0a6e51f665910c2d36e40dbda978b77e49c2e549 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 15 Mar 2016 10:35:44 -0400 Subject: [PATCH 195/273] :arrow_up: package-generator@1.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8d42f8d5a..398caecf9 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "metrics": "0.53.1", "notifications": "0.62.4", "open-on-github": "1.0.1", - "package-generator": "0.41.1", + "package-generator": "1.0.0", "settings-view": "0.232.6", "snippets": "1.0.1", "spell-check": "0.67.0", From 34698d57687a78ffe76136c3e69f95026c8fe400 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 15 Mar 2016 10:43:57 -0400 Subject: [PATCH 196/273] Revert "And again." This reverts commit a2a6ed05c5dcafa37668884f4b00bba9873b644e. --- src/git-repository-async.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/git-repository-async.js b/src/git-repository-async.js index d0903acd8..3b33a5003 100644 --- a/src/git-repository-async.js +++ b/src/git-repository-async.js @@ -660,11 +660,6 @@ export default class GitRepositoryAsync { } return this._diffBlobToBuffer(blob, text, options) }) - .catch(e => { - // NB: I don't love this, but we're matching the behavior of - // `GitRepository` here for API compatibility. - return {} - }) } // Checking Out From 8f9ab771a79d7b9f26604ed5333943de03e0b690 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 15 Mar 2016 10:44:00 -0400 Subject: [PATCH 197/273] Revert "Match GitRepository's responses to null paths." This reverts commit 50f8f8e7e9770a857ec534a7cfb9d6837ffb56ff. --- src/git-repository-async.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/git-repository-async.js b/src/git-repository-async.js index 3b33a5003..f80f46a13 100644 --- a/src/git-repository-async.js +++ b/src/git-repository-async.js @@ -442,9 +442,6 @@ export default class GitRepositoryAsync { // Returns a {Promise} which resolves to a {Boolean} that's true if the `path` // is ignored. isPathIgnored (_path) { - // NB: We're matching the behavior of `GitRepository` here. - if (!_path) return Promise.resolve(false) - return this.getRepo() .then(repo => { const relativePath = this.relativize(_path, repo.workdir()) @@ -521,10 +518,6 @@ export default class GitRepositoryAsync { // Returns a {Promise} which resolves to a status {Number} or null if the // path is not in the cache. getCachedPathStatus (_path) { - // NB: I don't love this, but we're matching the behavior of - // `GitRepository` here for API compatibility. - if (!_path) return null - return this.relativizeToWorkingDirectory(_path) .then(relativePath => this.pathStatusCache[relativePath]) } From 15b13e3ddc15d608d5c839a9ee160a3d1a6b56a8 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 15 Mar 2016 10:49:36 -0400 Subject: [PATCH 198/273] Note the changes to GitRepository. --- src/git-repository-async.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/git-repository-async.js b/src/git-repository-async.js index f80f46a13..c5984eed4 100644 --- a/src/git-repository-async.js +++ b/src/git-repository-async.js @@ -15,6 +15,12 @@ const submoduleMode = 57344 // TODO: compose this from libgit2 constants // Just using this for _.isEqual and _.object, we should impl our own here import _ from 'underscore-plus' +// For the most part, this class behaves the same as `GitRepository`, with a few +// notable differences: +// * Errors are generally propagated out to the caller instead of being +// swallowed within `GitRepositoryAsync`. +// * Methods accepting a path shouldn't be given a null path, unless it is +// specifically allowed as noted in the method's documentation. export default class GitRepositoryAsync { static open (path, options = {}) { // QUESTION: Should this wrap Git.Repository and reject with a nicer message? From 047a62f9e15608e5d71b42966d96682530a25c6e Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 15 Mar 2016 12:05:16 -0400 Subject: [PATCH 199/273] :arrow_up: git-diff@1.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 398caecf9..b36a3614b 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "exception-reporting": "0.37.0", "find-and-replace": "0.197.4", "fuzzy-finder": "1.0.3", - "git-diff": "1.0.0", + "git-diff": "1.0.1", "go-to-line": "0.30.0", "grammar-selector": "0.48.1", "image-view": "0.57.0", From 147518d86dcf6a413eb31d8502465a433a1a3c3c Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 15 Mar 2016 12:05:24 -0400 Subject: [PATCH 200/273] :arrow_up: status-bar@1.1.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b36a3614b..d9a22fd07 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "settings-view": "0.232.6", "snippets": "1.0.1", "spell-check": "0.67.0", - "status-bar": "1.1.1", + "status-bar": "1.1.2", "styleguide": "0.45.2", "symbols-view": "0.112.0", "tabs": "0.92.0", From 7703240bdff0f0aad5640556ace0bd5e11eae700 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 15 Mar 2016 13:59:07 -0400 Subject: [PATCH 201/273] :arrow_up: notifications@0.63.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d9a22fd07..351d91cd4 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "link": "0.31.1", "markdown-preview": "0.158.0", "metrics": "0.53.1", - "notifications": "0.62.4", + "notifications": "0.63.0", "open-on-github": "1.0.1", "package-generator": "1.0.0", "settings-view": "0.232.6", From 1d149c8f92f37934c7bdd9e1501b15f3eb6905e4 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Tue, 15 Mar 2016 16:36:54 -0700 Subject: [PATCH 202/273] :arrow_up: apm Signed-off-by: Michelle Tilley --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 4b599bc39..2f0fcf519 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "1.7.1" + "atom-package-manager": "1.8.0" } } From 627adc673934254345dbe9d73a97acb9df6a72bf Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Tue, 15 Mar 2016 16:41:11 -0700 Subject: [PATCH 203/273] :arrow_up: settings-view Signed-off-by: Michelle Tilley --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 351d91cd4..0ec40757d 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "notifications": "0.63.0", "open-on-github": "1.0.1", "package-generator": "1.0.0", - "settings-view": "0.232.6", + "settings-view": "0.233.0", "snippets": "1.0.1", "spell-check": "0.67.0", "status-bar": "1.1.2", From 690397c91c3e3d485f2ef71de894871d02d2bd56 Mon Sep 17 00:00:00 2001 From: joshaber Date: Wed, 16 Mar 2016 11:57:49 -0400 Subject: [PATCH 204/273] :arrow_up: notifications@0.63.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0ec40757d..b766d9b4f 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "link": "0.31.1", "markdown-preview": "0.158.0", "metrics": "0.53.1", - "notifications": "0.63.0", + "notifications": "0.63.1", "open-on-github": "1.0.1", "package-generator": "1.0.0", "settings-view": "0.233.0", From f48069c5f848b5ae624b110a1df7800e919eb142 Mon Sep 17 00:00:00 2001 From: joshaber Date: Wed, 16 Mar 2016 12:40:40 -0400 Subject: [PATCH 205/273] :arrow_up: settings@0.234.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b766d9b4f..a3246926f 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "notifications": "0.63.1", "open-on-github": "1.0.1", "package-generator": "1.0.0", - "settings-view": "0.233.0", + "settings-view": "0.234.0", "snippets": "1.0.1", "spell-check": "0.67.0", "status-bar": "1.1.2", From 215f1207897cb9faa4de7c187b155be1a20e869d Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 17 Mar 2016 10:34:02 -0400 Subject: [PATCH 206/273] :arrow_up: status-bar@1.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a3246926f..6a5c18986 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "settings-view": "0.234.0", "snippets": "1.0.1", "spell-check": "0.67.0", - "status-bar": "1.1.2", + "status-bar": "1.2.0", "styleguide": "0.45.2", "symbols-view": "0.112.0", "tabs": "0.92.0", From e3a5a93b88e4ff9bbee47c26d72b8cd24fea87e1 Mon Sep 17 00:00:00 2001 From: Daniel Hengeveld Date: Thu, 17 Mar 2016 15:45:24 +0100 Subject: [PATCH 207/273] :arrow_up: settings@0.235.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a3246926f..29df10850 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "notifications": "0.63.1", "open-on-github": "1.0.1", "package-generator": "1.0.0", - "settings-view": "0.234.0", + "settings-view": "0.235.0", "snippets": "1.0.1", "spell-check": "0.67.0", "status-bar": "1.1.2", From 292233f6cba59e1133cf41e297a9b1a5ce7e711a Mon Sep 17 00:00:00 2001 From: Hubot Date: Thu, 17 Mar 2016 12:11:31 -0500 Subject: [PATCH 208/273] 1.8.0-dev --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c75ef505d..4a6f1504d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "1.7.0-dev", + "version": "1.8.0-dev", "description": "A hackable text editor for the 21st Century.", "main": "./src/browser/main.js", "repository": { From acbd34931259f6d0364409c0520d4ae037fdcbe4 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 17 Mar 2016 13:43:06 -0400 Subject: [PATCH 209/273] Revert ":arrow_up: status-bar@1.2.0" This reverts commit 215f1207897cb9faa4de7c187b155be1a20e869d. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4a6f1504d..4d1a1e7e8 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "settings-view": "0.235.0", "snippets": "1.0.1", "spell-check": "0.67.0", - "status-bar": "1.2.0", + "status-bar": "1.1.2", "styleguide": "0.45.2", "symbols-view": "0.112.0", "tabs": "0.92.0", From ffe13db768c8d8df52005737ccc8fa44ada14d51 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 17 Mar 2016 15:51:33 -0400 Subject: [PATCH 210/273] Revert "Revert ":arrow_up: status-bar@1.2.0"" This reverts commit acbd34931259f6d0364409c0520d4ae037fdcbe4. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4d1a1e7e8..4a6f1504d 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "settings-view": "0.235.0", "snippets": "1.0.1", "spell-check": "0.67.0", - "status-bar": "1.1.2", + "status-bar": "1.2.0", "styleguide": "0.45.2", "symbols-view": "0.112.0", "tabs": "0.92.0", From 4e9fa72fd115294cbd3292ecbfe321c9928d51f8 Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Thu, 17 Mar 2016 13:06:53 -0700 Subject: [PATCH 211/273] :arrow_up: about --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4d1a1e7e8..8160c0bae 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "one-light-syntax": "1.2.0", "solarized-dark-syntax": "1.0.0", "solarized-light-syntax": "1.0.0", - "about": "1.4.1", + "about": "1.4.2", "archive-view": "0.61.1", "autocomplete-atom-api": "0.10.0", "autocomplete-css": "0.11.0", From 7863ffbac7162f5f61ee011aa0a0a16d03e7dca1 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 17 Mar 2016 22:03:16 -0400 Subject: [PATCH 212/273] :arrow_up: incompatible-packages@0.26 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4a6f1504d..30f0d8281 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "go-to-line": "0.30.0", "grammar-selector": "0.48.1", "image-view": "0.57.0", - "incompatible-packages": "0.25.1", + "incompatible-packages": "0.26", "keybinding-resolver": "0.35.0", "line-ending-selector": "0.3.1", "link": "0.31.1", From 85526198f7a31fa742ca087b428476b362f164ee Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 17 Mar 2016 22:03:26 -0400 Subject: [PATCH 213/273] :arrow_up: line-ending-selector@0.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 30f0d8281..6cc55f0f8 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "image-view": "0.57.0", "incompatible-packages": "0.26", "keybinding-resolver": "0.35.0", - "line-ending-selector": "0.3.1", + "line-ending-selector": "0.4", "link": "0.31.1", "markdown-preview": "0.158.0", "metrics": "0.53.1", From 145396a73f6068a2179f029d21fd082c2bd63732 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 17 Mar 2016 22:05:15 -0400 Subject: [PATCH 214/273] Hwoops --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 6cc55f0f8..bf59741d0 100644 --- a/package.json +++ b/package.json @@ -95,9 +95,9 @@ "go-to-line": "0.30.0", "grammar-selector": "0.48.1", "image-view": "0.57.0", - "incompatible-packages": "0.26", + "incompatible-packages": "0.26.0", "keybinding-resolver": "0.35.0", - "line-ending-selector": "0.4", + "line-ending-selector": "0.4.0", "link": "0.31.1", "markdown-preview": "0.158.0", "metrics": "0.53.1", From 1c5ad8db0fa56bf689a66d6dafb7417866007859 Mon Sep 17 00:00:00 2001 From: Robert Fruchtman Date: Thu, 17 Mar 2016 19:11:07 -0700 Subject: [PATCH 215/273] destory -> destroy --- 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 38d4839b0..97139f6bb 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -624,7 +624,7 @@ describe "Workspace", -> expect(pane.getItems()).toEqual [editor1, editor2] describe "when replacing a pending item which is the last item in a second pane", -> - it "does not destory the pane even if core.destroyEmptyPanes is on", -> + it "does not destroy the pane even if core.destroyEmptyPanes is on", -> atom.config.set('core.destroyEmptyPanes', true) editor1 = null editor2 = null From 543015af9795a42790ebf6594ee82506474956a8 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 17 Mar 2016 22:19:38 -0400 Subject: [PATCH 216/273] :arrow_up: incompatible-packages@0.26.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bf59741d0..27ebb38a6 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "go-to-line": "0.30.0", "grammar-selector": "0.48.1", "image-view": "0.57.0", - "incompatible-packages": "0.26.0", + "incompatible-packages": "0.26.1", "keybinding-resolver": "0.35.0", "line-ending-selector": "0.4.0", "link": "0.31.1", From dd5886e135369689094946d35463483039b6afd9 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 17 Mar 2016 22:19:48 -0400 Subject: [PATCH 217/273] :arrow_up: line-ending-selector@0.4.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 27ebb38a6..16e84fc62 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "image-view": "0.57.0", "incompatible-packages": "0.26.1", "keybinding-resolver": "0.35.0", - "line-ending-selector": "0.4.0", + "line-ending-selector": "0.4.1", "link": "0.31.1", "markdown-preview": "0.158.0", "metrics": "0.53.1", From bb8f114dcb432f9424db1654e6cb4e6c37283c33 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Fri, 18 Mar 2016 09:56:33 -0700 Subject: [PATCH 218/273] Remove an unnecessary call to then(). I see that this file has a little use of async/await and many uses of `then()`. Things would be much less verbose and much more linear if async/await were used throughout. Would Atom be open to a PR that changes this? For bonus points, we could also replace `'use babel'` with `/* @flow */` at the top of the file :) --- src/git-repository-async.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/git-repository-async.js b/src/git-repository-async.js index c5984eed4..82546b525 100644 --- a/src/git-repository-async.js +++ b/src/git-repository-async.js @@ -158,8 +158,7 @@ export default class GitRepositoryAsync { if (!this.projectAtRoot) { this.projectAtRoot = this.getRepo() - .then(repo => this.project.relativize(repo.workdir())) - .then(relativePath => relativePath === '') + .then(repo => this.project.relativize(repo.workdir()) === '') } return this.projectAtRoot From 5c03894227dca96e6a630acb07da6c9596f910c9 Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Sun, 20 Mar 2016 22:22:33 -0700 Subject: [PATCH 219/273] Revert "Allow pasting white space when `autoIndentOnPaste` is enabled" This reverts commit 0088053de47b5ec0566eedcd24fd7393e7ddc1a6. --- src/selection.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/selection.coffee b/src/selection.coffee index e208ea55a..b89772f57 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -378,7 +378,7 @@ class Selection extends Model indentAdjustment = @editor.indentLevelForLine(precedingText) - options.indentBasis @adjustIndent(remainingLines, indentAdjustment) - if options.autoIndent and NonWhitespaceRegExp.test(text) and not NonWhitespaceRegExp.test(precedingText) and remainingLines.length > 0 + if options.autoIndent and not NonWhitespaceRegExp.test(precedingText) and remainingLines.length > 0 autoIndentFirstLine = true firstLine = precedingText + firstInsertedLine desiredIndentLevel = @editor.languageMode.suggestedIndentForLineAtBufferRow(oldBufferRange.start.row, firstLine) From 32a1d21a0debe14f159b3cbf945827d4fb7bdf30 Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Mon, 21 Mar 2016 14:03:25 -0700 Subject: [PATCH 220/273] :arrow_up: apm --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 2f0fcf519..8ab76e484 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "1.8.0" + "atom-package-manager": "1.9.0" } } From 439825ea37b3e420328cd8d61c15014865a1ad5a Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Mon, 21 Mar 2016 14:32:45 -0700 Subject: [PATCH 221/273] :arrow_up: settings-view --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1c0d8f7ba..b6752d56e 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "notifications": "0.63.1", "open-on-github": "1.0.1", "package-generator": "1.0.0", - "settings-view": "0.235.0", + "settings-view": "0.235.1", "snippets": "1.0.1", "spell-check": "0.67.0", "status-bar": "1.2.0", From c5ed25a1315c4b66593415077ef84248ecf8a2a4 Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Mon, 21 Mar 2016 15:32:42 -0700 Subject: [PATCH 222/273] :arrow_up: apm --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index 8ab76e484..ba3415e1d 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "1.9.0" + "atom-package-manager": "1.9.1" } } From fd17457c172838c0a919ff74944ba68ab9770391 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 21 Mar 2016 17:15:27 -0600 Subject: [PATCH 223/273] Revert "Add spec for inserting white-space-only lines" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 746afb98ade993c5598ab8e80413825accbcaf82. @BinaryMuse Heads up this is the test associated with the other commit you reverted. Had to revert it as well to get the build green. Didn’t see a revert on beta so I’m assuming this is good enough? --- spec/selection-spec.coffee | 8 -------- 1 file changed, 8 deletions(-) diff --git a/spec/selection-spec.coffee b/spec/selection-spec.coffee index 319e2d438..ec40e32cc 100644 --- a/spec/selection-spec.coffee +++ b/spec/selection-spec.coffee @@ -83,11 +83,3 @@ describe "Selection", -> selection.setBufferRange([[2, 0], [2, 10]]) selection.destroy() expect(selection.marker.isDestroyed()).toBeTruthy() - - describe ".insertText(text, options)", -> - it "allows pasting white space only lines when autoIndent is enabled", -> - selection.setBufferRange [[0, 0], [0, 0]] - selection.insertText(" \n \n\n", autoIndent: true) - expect(buffer.lineForRow(0)).toBe " " - expect(buffer.lineForRow(1)).toBe " " - expect(buffer.lineForRow(2)).toBe "" From 449abd73646af35e7ef4830450963ca1c2b7fb38 Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Mon, 21 Mar 2016 16:27:41 -0700 Subject: [PATCH 224/273] Revert "Revert "Add spec for inserting white-space-only lines"" This reverts commit fd17457c172838c0a919ff74944ba68ab9770391. --- spec/selection-spec.coffee | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/spec/selection-spec.coffee b/spec/selection-spec.coffee index ec40e32cc..319e2d438 100644 --- a/spec/selection-spec.coffee +++ b/spec/selection-spec.coffee @@ -83,3 +83,11 @@ describe "Selection", -> selection.setBufferRange([[2, 0], [2, 10]]) selection.destroy() expect(selection.marker.isDestroyed()).toBeTruthy() + + describe ".insertText(text, options)", -> + it "allows pasting white space only lines when autoIndent is enabled", -> + selection.setBufferRange [[0, 0], [0, 0]] + selection.insertText(" \n \n\n", autoIndent: true) + expect(buffer.lineForRow(0)).toBe " " + expect(buffer.lineForRow(1)).toBe " " + expect(buffer.lineForRow(2)).toBe "" From 64308bbacb5f253562a059cfce6853859a859cd1 Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Mon, 21 Mar 2016 16:27:48 -0700 Subject: [PATCH 225/273] Revert "Revert "Allow pasting white space when `autoIndentOnPaste` is enabled"" This reverts commit 5c03894227dca96e6a630acb07da6c9596f910c9. --- src/selection.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/selection.coffee b/src/selection.coffee index b89772f57..e208ea55a 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -378,7 +378,7 @@ class Selection extends Model indentAdjustment = @editor.indentLevelForLine(precedingText) - options.indentBasis @adjustIndent(remainingLines, indentAdjustment) - if options.autoIndent and not NonWhitespaceRegExp.test(precedingText) and remainingLines.length > 0 + if options.autoIndent and NonWhitespaceRegExp.test(text) and not NonWhitespaceRegExp.test(precedingText) and remainingLines.length > 0 autoIndentFirstLine = true firstLine = precedingText + firstInsertedLine desiredIndentLevel = @editor.languageMode.suggestedIndentForLineAtBufferRow(oldBufferRange.start.row, firstLine) From 34f9ad8710293505a74d3ea6d8c7431ad480c102 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 22 Mar 2016 11:20:55 +0100 Subject: [PATCH 226/273] Add top/bottom ruler before/after a block decoration --- spec/text-editor-component-spec.js | 11 +++++++--- src/block-decorations-component.coffee | 29 ++++++++++++++++++-------- src/lines-tile-component.coffee | 4 ++-- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index 37a9751e1..1d1e4eb9f 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -1840,17 +1840,22 @@ describe('TextEditorComponent', function () { expect(component.lineNodeForScreenRow(2).dataset.screenRow).toBe("2") }) - it('measures block decorations taking into account both top and bottom margins', async function () { + it('measures block decorations taking into account both top and bottom margins of the element and its children', async function () { let [item, blockDecoration] = createBlockDecorationBeforeScreenRow(0, {className: "decoration-1"}) + let child = document.createElement("div") + child.style.height = "7px" + child.style.width = "30px" + child.style.marginBottom = "20px" + item.appendChild(child) atom.styles.addStyleSheet( - 'atom-text-editor .decoration-1 { width: 30px; height: 30px; margin-top: 10px; margin-bottom: 5px; }', + 'atom-text-editor .decoration-1 { width: 30px; margin-top: 10px; }', {context: 'atom-text-editor'} ) await nextAnimationFramePromise() // causes the DOM to update and to retrieve new styles await nextAnimationFramePromise() // applies the changes - expect(component.tileNodesForLines()[0].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + 30 + 10 + 5 + "px") + expect(component.tileNodesForLines()[0].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + 10 + 7 + 20 + "px") expect(component.tileNodesForLines()[0].style.webkitTransform).toBe("translate3d(0px, 0px, 0px)") expect(component.tileNodesForLines()[1].style.height).toBe(TILE_SIZE * editor.getLineHeightInPixels() + "px") expect(component.tileNodesForLines()[1].style.webkitTransform).toBe(`translate3d(0px, ${component.tileNodesForLines()[0].offsetHeight}px, 0px)`) diff --git a/src/block-decorations-component.coffee b/src/block-decorations-component.coffee index 0cfa7974f..6e0a2091c 100644 --- a/src/block-decorations-component.coffee +++ b/src/block-decorations-component.coffee @@ -26,7 +26,10 @@ class BlockDecorationsComponent for id, blockDecorationState of @oldState.blockDecorations unless @newState.blockDecorations.hasOwnProperty(id) - @blockDecorationNodesById[id].remove() + blockDecorationNode = @blockDecorationNodesById[id] + blockDecorationNode.previousSibling.remove() + blockDecorationNode.nextSibling.remove() + blockDecorationNode.remove() delete @blockDecorationNodesById[id] delete @oldState.blockDecorations[id] @@ -41,19 +44,27 @@ class BlockDecorationsComponent for decorationId, blockDecorationNode of @blockDecorationNodesById style = getComputedStyle(blockDecorationNode) decoration = @newState.blockDecorations[decorationId].decoration - marginBottom = parseInt(style.marginBottom) ? 0 - marginTop = parseInt(style.marginTop) ? 0 - @presenter.setBlockDecorationDimensions( - decoration, - blockDecorationNode.offsetWidth, - blockDecorationNode.offsetHeight + marginTop + marginBottom - ) + topRuler = blockDecorationNode.previousSibling + bottomRuler = blockDecorationNode.nextSibling + + width = blockDecorationNode.offsetWidth + height = bottomRuler.offsetTop - topRuler.offsetTop + @presenter.setBlockDecorationDimensions(decoration, width, height) createAndAppendBlockDecorationNode: (id) -> blockDecorationState = @newState.blockDecorations[id] + blockDecorationClass = "atom--block-decoration-#{id}" + topRuler = document.createElement("div") blockDecorationNode = @views.getView(blockDecorationState.decoration.getProperties().item) - blockDecorationNode.id = "atom--block-decoration-#{id}" + bottomRuler = document.createElement("div") + topRuler.classList.add(blockDecorationClass) + blockDecorationNode.classList.add(blockDecorationClass) + bottomRuler.classList.add(blockDecorationClass) + + @container.appendChild(topRuler) @container.appendChild(blockDecorationNode) + @container.appendChild(bottomRuler) + @blockDecorationNodesById[id] = blockDecorationNode @updateBlockDecorationNode(id) diff --git a/src/lines-tile-component.coffee b/src/lines-tile-component.coffee index defcc0d8a..f4a7313ca 100644 --- a/src/lines-tile-component.coffee +++ b/src/lines-tile-component.coffee @@ -149,7 +149,7 @@ class LinesTileComponent if newLineState.screenRow isnt oldLineState.screenRow insertionPoint.dataset.screenRow = newLineState.screenRow - precedingBlockDecorationsSelector = newLineState.precedingBlockDecorations.map((d) -> "#atom--block-decoration-#{d.id}").join(',') + precedingBlockDecorationsSelector = newLineState.precedingBlockDecorations.map((d) -> ".atom--block-decoration-#{d.id}").join(',') if precedingBlockDecorationsSelector isnt oldLineState.precedingBlockDecorationsSelector insertionPoint.setAttribute("select", precedingBlockDecorationsSelector) @@ -180,7 +180,7 @@ class LinesTileComponent if newLineState.screenRow isnt oldLineState.screenRow insertionPoint.dataset.screenRow = newLineState.screenRow - followingBlockDecorationsSelector = newLineState.followingBlockDecorations.map((d) -> "#atom--block-decoration-#{d.id}").join(',') + followingBlockDecorationsSelector = newLineState.followingBlockDecorations.map((d) -> ".atom--block-decoration-#{d.id}").join(',') if followingBlockDecorationsSelector isnt oldLineState.followingBlockDecorationsSelector insertionPoint.setAttribute("select", followingBlockDecorationsSelector) From cf2233445586dad1d090f238345ed288f0a177cc Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 22 Mar 2016 11:50:54 +0100 Subject: [PATCH 227/273] Add invisible class to invisible block decorations --- src/block-decorations-component.coffee | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/block-decorations-component.coffee b/src/block-decorations-component.coffee index 6e0a2091c..c63fbdd2b 100644 --- a/src/block-decorations-component.coffee +++ b/src/block-decorations-component.coffee @@ -69,15 +69,13 @@ class BlockDecorationsComponent @updateBlockDecorationNode(id) updateBlockDecorationNode: (id) -> - newBlockDecorationState = @newState.blockDecorations[id] - oldBlockDecorationState = @oldState.blockDecorations[id] blockDecorationNode = @blockDecorationNodesById[id] - if newBlockDecorationState.isVisible + if @newState.blockDecorations[id].isVisible + blockDecorationNode.previousSibling.classList.remove("atom--invisible-block-decoration") blockDecorationNode.classList.remove("atom--invisible-block-decoration") + blockDecorationNode.nextSibling.classList.remove("atom--invisible-block-decoration") else + blockDecorationNode.previousSibling.classList.add("atom--invisible-block-decoration") blockDecorationNode.classList.add("atom--invisible-block-decoration") - - if oldBlockDecorationState.screenRow isnt newBlockDecorationState.screenRow - blockDecorationNode.dataset.screenRow = newBlockDecorationState.screenRow - oldBlockDecorationState.screenRow = newBlockDecorationState.screenRow + blockDecorationNode.nextSibling.classList.add("atom--invisible-block-decoration") From 137af3879807a9bcf72e3677be0af1044ec90bb2 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 22 Mar 2016 14:08:25 +0100 Subject: [PATCH 228/273] Add back screen row to block decorations nodes --- src/block-decorations-component.coffee | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/block-decorations-component.coffee b/src/block-decorations-component.coffee index c63fbdd2b..35aec3921 100644 --- a/src/block-decorations-component.coffee +++ b/src/block-decorations-component.coffee @@ -69,9 +69,11 @@ class BlockDecorationsComponent @updateBlockDecorationNode(id) updateBlockDecorationNode: (id) -> + newBlockDecorationState = @newState.blockDecorations[id] + oldBlockDecorationState = @oldState.blockDecorations[id] blockDecorationNode = @blockDecorationNodesById[id] - if @newState.blockDecorations[id].isVisible + if newBlockDecorationState.isVisible blockDecorationNode.previousSibling.classList.remove("atom--invisible-block-decoration") blockDecorationNode.classList.remove("atom--invisible-block-decoration") blockDecorationNode.nextSibling.classList.remove("atom--invisible-block-decoration") @@ -79,3 +81,7 @@ class BlockDecorationsComponent blockDecorationNode.previousSibling.classList.add("atom--invisible-block-decoration") blockDecorationNode.classList.add("atom--invisible-block-decoration") blockDecorationNode.nextSibling.classList.add("atom--invisible-block-decoration") + + if oldBlockDecorationState.screenRow isnt newBlockDecorationState.screenRow + blockDecorationNode.dataset.screenRow = newBlockDecorationState.screenRow + oldBlockDecorationState.screenRow = newBlockDecorationState.screenRow From d6933af487993250020024c652aebdd923154a21 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 22 Mar 2016 14:38:04 -0600 Subject: [PATCH 229/273] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b6752d56e..4b0d92b89 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "service-hub": "^0.7.0", "source-map-support": "^0.3.2", "temp": "0.8.1", - "text-buffer": "8.4.1", + "text-buffer": "8.4.2", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "yargs": "^3.23.0" From fc564873c28e51aeb38ab23383bb6e4485003842 Mon Sep 17 00:00:00 2001 From: simurai Date: Wed, 23 Mar 2016 13:43:42 +0900 Subject: [PATCH 230/273] :arrow_up: one-dark/light-ui@v1.3.0 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4b0d92b89..8b1a6187a 100644 --- a/package.json +++ b/package.json @@ -66,8 +66,8 @@ "atom-light-ui": "0.43.0", "base16-tomorrow-dark-theme": "1.1.0", "base16-tomorrow-light-theme": "1.1.1", - "one-dark-ui": "1.2.0", - "one-light-ui": "1.2.0", + "one-dark-ui": "1.3.0", + "one-light-ui": "1.3.0", "one-dark-syntax": "1.2.0", "one-light-syntax": "1.2.0", "solarized-dark-syntax": "1.0.0", From c2242e46c24def201b2a5d3eff26f429391543c1 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 23 Mar 2016 10:31:26 +0100 Subject: [PATCH 231/273] =?UTF-8?q?Read=20state=20from=20StorageFolder=20w?= =?UTF-8?q?hen=20it=20can=E2=80=99t=20be=20found=20in=20StateStore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/atom-environment-spec.coffee | 28 ++++++++++++++++++++++++++++ src/atom-environment.coffee | 11 ++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index 3283b63d6..2ba0164e6 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -4,6 +4,7 @@ temp = require 'temp' Package = require '../src/package' ThemeManager = require '../src/theme-manager' AtomEnvironment = require '../src/atom-environment' +StorageFolder = require '../src/storage-folder' describe "AtomEnvironment", -> describe 'window sizing methods', -> @@ -179,6 +180,33 @@ describe "AtomEnvironment", -> atom.loadState().then (state) -> expect(state).toEqual({stuff: 'cool'}) + it "loads state from the storage folder when it can't be found in atom.stateStore", -> + jasmine.useRealClock() + + storageFolderState = {foo: 1, bar: 2} + serializedState = {someState: 42} + loadSettings = _.extend(atom.getLoadSettings(), {initialPaths: [temp.mkdirSync("project-directory")]}) + spyOn(atom, 'getLoadSettings').andReturn(loadSettings) + spyOn(atom, 'serialize').andReturn(serializedState) + spyOn(atom, 'getConfigDirPath').andReturn(temp.mkdirSync("config-directory")) + atom.project.setPaths(atom.getLoadSettings().initialPaths) + + waitsForPromise -> + atom.stateStore.connect() + + runs -> + storageFolder = new StorageFolder(atom.getConfigDirPath()) + storageFolder.storeSync(atom.getStateKey(loadSettings.initialPaths), storageFolderState) + + waitsForPromise -> + atom.loadState().then (state) -> expect(state).toEqual(storageFolderState) + + waitsForPromise -> + atom.saveState() + + waitsForPromise -> + atom.loadState().then (state) -> expect(state).toEqual(serializedState) + it "saves state on keydown, mousedown, and when the editor window unloads", -> spyOn(atom, 'saveState') diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index 8c79d66f6..a34065bbd 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -11,6 +11,7 @@ Model = require './model' WindowEventHandler = require './window-event-handler' StylesElement = require './styles-element' StateStore = require './state-store' +StorageFolder = require './storage-folder' {getWindowLoadSettings, setWindowLoadSettings} = require './window-load-settings-helpers' registerDefaultCommands = require './register-default-commands' @@ -853,7 +854,12 @@ class AtomEnvironment extends Model loadState: -> if @enablePersistence if stateKey = @getStateKey(@getLoadSettings().initialPaths) - @stateStore.load(stateKey) + @stateStore.load(stateKey).then (state) => + if state + state + else + # TODO: remove this when every user has migrated to the IndexedDb state store. + @getStorageFolder().load(stateKey) else @applicationDelegate.getTemporaryWindowState() else @@ -882,6 +888,9 @@ class AtomEnvironment extends Model else null + getStorageFolder: -> + @storageFolder ?= new StorageFolder(@getConfigDirPath()) + getConfigDirPath: -> @configDirPath ?= process.env.ATOM_HOME From 80146ae631411e0fd5d6d276c2c4a105c1c147ff Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 23 Mar 2016 10:52:34 +0100 Subject: [PATCH 232/273] Assign the supplied configDirPath to an instance variable --- src/atom-environment.coffee | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index a34065bbd..f4dc49060 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -128,7 +128,7 @@ class AtomEnvironment extends Model # Call .loadOrCreate instead constructor: (params={}) -> - {@blobStore, @applicationDelegate, @window, @document, configDirPath, @enablePersistence, onlyLoadBaseStyleSheets} = params + {@blobStore, @applicationDelegate, @window, @document, @configDirPath, @enablePersistence, onlyLoadBaseStyleSheets} = params @unloaded = false @loadTime = null @@ -148,10 +148,10 @@ class AtomEnvironment extends Model @notifications = new NotificationManager - @config = new Config({configDirPath, resourcePath, notificationManager: @notifications, @enablePersistence}) + @config = new Config({@configDirPath, resourcePath, notificationManager: @notifications, @enablePersistence}) @setConfigSchema() - @keymaps = new KeymapManager({configDirPath, resourcePath, notificationManager: @notifications}) + @keymaps = new KeymapManager({@configDirPath, resourcePath, notificationManager: @notifications}) @tooltips = new TooltipManager(keymapManager: @keymaps) @@ -160,16 +160,16 @@ class AtomEnvironment extends Model @grammars = new GrammarRegistry({@config}) - @styles = new StyleManager({configDirPath}) + @styles = new StyleManager({@configDirPath}) @packages = new PackageManager({ - devMode, configDirPath, resourcePath, safeMode, @config, styleManager: @styles, + devMode, @configDirPath, resourcePath, safeMode, @config, styleManager: @styles, commandRegistry: @commands, keymapManager: @keymaps, notificationManager: @notifications, grammarRegistry: @grammars, deserializerManager: @deserializers, viewRegistry: @views }) @themes = new ThemeManager({ - packageManager: @packages, configDirPath, resourcePath, safeMode, @config, + packageManager: @packages, @configDirPath, resourcePath, safeMode, @config, styleManager: @styles, notificationManager: @notifications, viewRegistry: @views }) From 25a4c4c293e61ca0971ff1f5a86af68f299c8cfe Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 23 Mar 2016 10:53:37 +0100 Subject: [PATCH 233/273] Clear StorageFolder when --clear-window-state is supplied --- src/atom-environment.coffee | 4 +++- src/storage-folder.coffee | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index f4dc49060..6ef46dc2a 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -139,7 +139,9 @@ class AtomEnvironment extends Model @stateStore = new StateStore('AtomEnvironments', 1) - @stateStore.clear() if clearWindowState + if clearWindowState + @getStorageFolder().clear() + @stateStore.clear() @deserializers = new DeserializerManager(this) @deserializeTimings = {} diff --git a/src/storage-folder.coffee b/src/storage-folder.coffee index 06beae56a..327697672 100644 --- a/src/storage-folder.coffee +++ b/src/storage-folder.coffee @@ -6,6 +6,14 @@ class StorageFolder constructor: (containingPath) -> @path = path.join(containingPath, "storage") if containingPath? + clear: -> + return unless @path? + + try + fs.removeSync(@path) + catch error + console.warn "Error deleting #{statePath}", error.stack, error + storeSync: (name, object) -> return unless @path? From f69c5bdee436f44ac5b71f0761968a180570b726 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 23 Mar 2016 12:11:27 +0100 Subject: [PATCH 234/273] Oops. --- src/storage-folder.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storage-folder.coffee b/src/storage-folder.coffee index 327697672..280eb8b5c 100644 --- a/src/storage-folder.coffee +++ b/src/storage-folder.coffee @@ -12,7 +12,7 @@ class StorageFolder try fs.removeSync(@path) catch error - console.warn "Error deleting #{statePath}", error.stack, error + console.warn "Error deleting #{@path}", error.stack, error storeSync: (name, object) -> return unless @path? From cbb911cde8652d7aff6c2a0080d7ca9e5bac7641 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 23 Mar 2016 13:43:54 +0100 Subject: [PATCH 235/273] :green_heart: --- spec/atom-environment-spec.coffee | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/spec/atom-environment-spec.coffee b/spec/atom-environment-spec.coffee index 2ba0164e6..5fd4b11f1 100644 --- a/spec/atom-environment-spec.coffee +++ b/spec/atom-environment-spec.coffee @@ -173,7 +173,7 @@ describe "AtomEnvironment", -> waitsForPromise -> atom.saveState().then -> atom.loadState().then (state) -> - expect(state).toBeNull() + expect(state).toBeFalsy() waitsForPromise -> loadSettings.initialPaths = [dir2, dir1] @@ -188,15 +188,14 @@ describe "AtomEnvironment", -> loadSettings = _.extend(atom.getLoadSettings(), {initialPaths: [temp.mkdirSync("project-directory")]}) spyOn(atom, 'getLoadSettings').andReturn(loadSettings) spyOn(atom, 'serialize').andReturn(serializedState) - spyOn(atom, 'getConfigDirPath').andReturn(temp.mkdirSync("config-directory")) + spyOn(atom, 'getStorageFolder').andReturn(new StorageFolder(temp.mkdirSync("config-directory"))) atom.project.setPaths(atom.getLoadSettings().initialPaths) waitsForPromise -> atom.stateStore.connect() runs -> - storageFolder = new StorageFolder(atom.getConfigDirPath()) - storageFolder.storeSync(atom.getStateKey(loadSettings.initialPaths), storageFolderState) + atom.getStorageFolder().storeSync(atom.getStateKey(loadSettings.initialPaths), storageFolderState) waitsForPromise -> atom.loadState().then (state) -> expect(state).toEqual(storageFolderState) From 986822aef628c532a76883f4ac26891317f24c91 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Wed, 23 Mar 2016 16:14:18 -0400 Subject: [PATCH 236/273] :arrow_up: language-shellscript@0.21.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8b1a6187a..331986a93 100644 --- a/package.json +++ b/package.json @@ -141,7 +141,7 @@ "language-ruby": "0.68.3", "language-ruby-on-rails": "0.25.0", "language-sass": "0.46.0", - "language-shellscript": "0.21.0", + "language-shellscript": "0.21.1", "language-source": "0.9.0", "language-sql": "0.20.0", "language-text": "0.7.1", From 53684f665fbadefdb5f85bfc485444fe3cbacc86 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Wed, 23 Mar 2016 16:19:03 -0400 Subject: [PATCH 237/273] :arrow_up: language-yaml@0.25.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 331986a93..743d6bb9d 100644 --- a/package.json +++ b/package.json @@ -148,7 +148,7 @@ "language-todo": "0.27.0", "language-toml": "0.18.0", "language-xml": "0.34.4", - "language-yaml": "0.25.1" + "language-yaml": "0.25.2" }, "private": true, "scripts": { From 1cb89634023134f86cd82fbdbd11cfe0d6d77a25 Mon Sep 17 00:00:00 2001 From: ardhipoetra Date: Thu, 24 Mar 2016 18:03:07 +0100 Subject: [PATCH 238/273] fix link in ISSUE_TEMPLATE --- ISSUE_TEMPLATE.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 73ff2f50d..8144a4b62 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -1,8 +1,8 @@ ### Prerequisites -* [ ] Can you reproduce the problem in [safe mode](https://atom.io/docs/latest/hacking-atom-debugging#check-if-the-problem-shows-up-in-safe-mode)? -* [ ] Are you running the [latest version of Atom](https://atom.io/docs/latest/hacking-atom-debugging#update-to-the-latest-version)? -* [ ] Did you check the [debugging guide](https://atom.io/docs/latest/hacking-atom-debugging)? +* [ ] Can you reproduce the problem in [safe mode](http://flight-manual.atom.io/hacking-atom/sections/debugging/#check-if-the-problem-shows-up-in-safe-mode)? +* [ ] Are you running the [latest version of Atom](http://flight-manual.atom.io/hacking-atom/sections/debugging/#update-to-the-latest-version)? +* [ ] Did you check the [debugging guide](flight-manual.atom.io/hacking-atom/sections/debugging/)? * [ ] Did you check the [FAQs on Discuss](https://discuss.atom.io/c/faq)? * [ ] Are you reporting to the [correct repository](https://github.com/atom/atom/blob/master/CONTRIBUTING.md#atom-and-packages)? * [ ] Did you [perform a cursory search](https://github.com/issues?q=is%3Aissue+user%3Aatom+-repo%3Aatom%2Felectron) to see if your bug or enhancement is already reported? From 2016d0b6134f6efabbc270afd7e1b1d978d23009 Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Thu, 24 Mar 2016 12:36:16 -0700 Subject: [PATCH 239/273] :arrow_up: snippets@1.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 743d6bb9d..267aed7ed 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "open-on-github": "1.0.1", "package-generator": "1.0.0", "settings-view": "0.235.1", - "snippets": "1.0.1", + "snippets": "1.0.2", "spell-check": "0.67.0", "status-bar": "1.2.0", "styleguide": "0.45.2", From e0f41d1af4b48b273ee113f6a5aa9f2cb4657bf3 Mon Sep 17 00:00:00 2001 From: "Mark H. Wilkinson" Date: Fri, 25 Mar 2016 00:05:10 +0000 Subject: [PATCH 240/273] Fix typo in error message. --- src/text-editor-element.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 2a9b5e262..a0ec1b7fa 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -92,7 +92,7 @@ class TextEditorElement extends HTMLElement @emitter.emit("did-change-scroll-left", arguments...) initialize: (model, {@views, @config, @themes, @workspace, @assert, @styles, @grammars}, @autoHeight = true, @scrollPastEnd = true) -> - throw new Error("Must pass a config parameter when initializing TextEditorElements") unless @views? + throw new Error("Must pass a views parameter when initializing TextEditorElements") unless @views? throw new Error("Must pass a config parameter when initializing TextEditorElements") unless @config? throw new Error("Must pass a themes parameter when initializing TextEditorElements") unless @themes? throw new Error("Must pass a workspace parameter when initializing TextEditorElements") unless @workspace? From 694d288e1669309cf03eba20e58447edf18d652b Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 25 Mar 2016 10:31:13 -0400 Subject: [PATCH 241/273] Cache the workdir and path. --- src/git-repository-async.js | 59 ++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/src/git-repository-async.js b/src/git-repository-async.js index 82546b525..943a98841 100644 --- a/src/git-repository-async.js +++ b/src/git-repository-async.js @@ -43,6 +43,8 @@ export default class GitRepositoryAsync { this.emitter = new Emitter() this.subscriptions = new CompositeDisposable() this.pathStatusCache = {} + this.workdir = null + this.path = null // NB: These needs to happen before the following .openRepository call. this.openedPath = _path @@ -142,13 +144,24 @@ export default class GitRepositoryAsync { // Public: Returns a {Promise} which resolves to the {String} path of the // repository. getPath () { - return this.getRepo().then(repo => repo.path().replace(/\/$/, '')) + return this.getRepo().then(repo => { + if (!this.path) { + this.path = repo.path().replace(/\/$/, '') + } + return this.path + }) } // Public: Returns a {Promise} which resolves to the {String} working // directory path of the repository. getWorkingDirectory () { - return this.getRepo().then(repo => repo.workdir()) + return this.getRepo().then(repo => { + if (!this.workdir) { + this.workdir = repo.workdir() + } + + return this.workdir + }) } // Public: Returns a {Promise} that resolves to true if at the root, false if @@ -157,8 +170,8 @@ export default class GitRepositoryAsync { if (!this.project) return Promise.resolve(false) if (!this.projectAtRoot) { - this.projectAtRoot = this.getRepo() - .then(repo => this.project.relativize(repo.workdir()) === '') + this.projectAtRoot = this.getWorkingDirectory() + .then(wd => this.project.relativize(wd) === '') } return this.projectAtRoot @@ -170,8 +183,8 @@ export default class GitRepositoryAsync { // // Returns a {Promise} which resolves to the relative {String} path. relativizeToWorkingDirectory (_path) { - return this.getRepo() - .then(repo => this.relativize(_path, repo.workdir())) + return this.getWorkingDirectory() + .then(wd => this.relativize(_path, wd)) } // Public: Makes a path relative to the repository's working directory. @@ -447,10 +460,9 @@ export default class GitRepositoryAsync { // Returns a {Promise} which resolves to a {Boolean} that's true if the `path` // is ignored. isPathIgnored (_path) { - return this.getRepo() - .then(repo => { - const relativePath = this.relativize(_path, repo.workdir()) - return Git.Ignore.pathIsIgnored(repo, relativePath) + return Promise.all([this.getRepo(), this.getWorkingDirectory()]) + .then(([repo, wd]) => { + const relativePath = this.relativize(_path, wd) }) .then(ignored => Boolean(ignored)) } @@ -488,9 +500,9 @@ export default class GitRepositoryAsync { // status bit for the path. refreshStatusForPath (_path) { let relativePath - return this.getRepo() - .then(repo => { - relativePath = this.relativize(_path, repo.workdir()) + return Promise.all([this.getRepo(), this.getWorkingDirectory()]) + .then(([repo, wd]) => { + relativePath = this.relativize(_path, wd) return this._getStatus([relativePath]) }) .then(statuses => { @@ -598,12 +610,12 @@ export default class GitRepositoryAsync { getDiffStats (_path) { return this.getRepo() .then(repo => Promise.all([repo, repo.getHeadCommit()])) - .then(([repo, headCommit]) => Promise.all([repo, headCommit.getTree()])) - .then(([repo, tree]) => { + .then(([repo, headCommit]) => Promise.all([repo, headCommit.getTree(), this.getWorkingDirectory()])) + .then(([repo, tree, wd]) => { const options = new Git.DiffOptions() options.contextLines = 0 options.flags = Git.Diff.OPTION.DISABLE_PATHSPEC_MATCH - options.pathspec = this.relativize(_path, repo.workdir()) + options.pathspec = this.relativize(_path, wd) if (process.platform === 'win32') { // Ignore eol of line differences on windows so that files checked in // as LF don't report every line modified when the text contains CRLF @@ -640,9 +652,9 @@ export default class GitRepositoryAsync { // * `newLines` The {Number} of lines in the new hunk getLineDiffs (_path, text) { let relativePath = null - return this.getRepo() - .then(repo => { - relativePath = this.relativize(_path, repo.workdir()) + return Promise.all([this.getRepo(), this.getWorkingDirectory()]) + .then(([repo, wd]) => { + relativePath = this.relativize(_path, wd) return repo.getHeadCommit() }) .then(commit => commit.getEntry(relativePath)) @@ -678,10 +690,10 @@ export default class GitRepositoryAsync { // Returns a {Promise} that resolves or rejects depending on whether the // method was successful. checkoutHead (_path) { - return this.getRepo() - .then(repo => { + return Promise.all([this.getRepo(), this.getWorkingDirectory()]) + .then(([repo, wd]) => { const checkoutOptions = new Git.CheckoutOptions() - checkoutOptions.paths = [this.relativize(_path, repo.workdir())] + checkoutOptions.paths = [this.relativize(_path, wd)] checkoutOptions.checkoutStrategy = Git.Checkout.STRATEGY.FORCE | Git.Checkout.STRATEGY.DISABLE_PATHSPEC_MATCH return Git.Checkout.head(repo, checkoutOptions) }) @@ -873,13 +885,14 @@ export default class GitRepositoryAsync { // submodule names with {GitRepositoryAsync} values. async _refreshSubmodules () { const repo = await this.getRepo() + const wd = await this.getWorkingDirectory() const submoduleNames = await repo.getSubmoduleNames() for (const name of submoduleNames) { const alreadyExists = Boolean(this.submodules[name]) if (alreadyExists) continue const submodule = await Git.Submodule.lookup(repo, name) - const absolutePath = path.join(repo.workdir(), submodule.path()) + const absolutePath = path.join(wd, submodule.path()) const submoduleRepo = GitRepositoryAsync.open(absolutePath, {openExactPath: true, refreshOnWindowFocus: false}) this.submodules[name] = submoduleRepo } From 7294b95b70dd2b4be55a970e5e399eda5289b9fd Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 25 Mar 2016 10:49:22 -0400 Subject: [PATCH 242/273] Skip the first reload event. --- src/git-repository-async.js | 8 +++++++- src/git-repository.coffee | 9 ++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/git-repository-async.js b/src/git-repository-async.js index 943a98841..668183ba7 100644 --- a/src/git-repository-async.js +++ b/src/git-repository-async.js @@ -1056,9 +1056,15 @@ export default class GitRepositoryAsync { } } + // TextBuffers will emit a reload event when they're first loaded. We don't + // need to refresh in that case. + let firstReload = true bufferSubscriptions.add( buffer.onDidSave(refreshStatusForBuffer), - buffer.onDidReload(refreshStatusForBuffer), + buffer.onDidReload(() => { + if (!firstReload) refreshStatusForBuffer() + firstReload = false + }), buffer.onDidChangePath(refreshStatusForBuffer), buffer.onDidDestroy(() => { bufferSubscriptions.dispose() diff --git a/src/git-repository.coffee b/src/git-repository.coffee index 0513c2293..bc4f57161 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -448,7 +448,14 @@ class GitRepository bufferSubscriptions = new CompositeDisposable bufferSubscriptions.add buffer.onDidSave(getBufferPathStatus) - bufferSubscriptions.add buffer.onDidReload(getBufferPathStatus) + + # TextBuffers will emit a reload event when they're first loaded. We don't + # need to refresh in that case. + firstReload = true + bufferSubscriptions.add buffer.onDidReload(-> + getBufferPathStatus() unless firstReload + firstReload = false + ) bufferSubscriptions.add buffer.onDidChangePath(getBufferPathStatus) bufferSubscriptions.add buffer.onDidDestroy => bufferSubscriptions.dispose() From aee053dc10f0382244e6b030c4b486e08b0d1c00 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 25 Mar 2016 12:46:49 -0400 Subject: [PATCH 243/273] Whoops. Bring back pathIsIgnored. --- src/git-repository-async.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/git-repository-async.js b/src/git-repository-async.js index 668183ba7..edd85390b 100644 --- a/src/git-repository-async.js +++ b/src/git-repository-async.js @@ -148,6 +148,7 @@ export default class GitRepositoryAsync { if (!this.path) { this.path = repo.path().replace(/\/$/, '') } + return this.path }) } @@ -463,6 +464,7 @@ export default class GitRepositoryAsync { return Promise.all([this.getRepo(), this.getWorkingDirectory()]) .then(([repo, wd]) => { const relativePath = this.relativize(_path, wd) + return Git.Ignore.pathIsIgnored(repo, relativePath) }) .then(ignored => Boolean(ignored)) } From 39dcd59994d11e1cefde849bb5080f47460eb69f Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 25 Mar 2016 13:36:38 -0400 Subject: [PATCH 244/273] Fix the specs. --- spec/git-repository-async-spec.js | 6 +++--- spec/git-spec.coffee | 22 +++++++++++++--------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/spec/git-repository-async-spec.js b/spec/git-repository-async-spec.js index 900d81bfb..25623ae27 100644 --- a/spec/git-repository-async-spec.js +++ b/spec/git-repository-async-spec.js @@ -483,9 +483,10 @@ describe('GitRepositoryAsync', () => { describe('buffer events', () => { let repo + let workingDirectory beforeEach(() => { - const workingDirectory = copyRepository() + workingDirectory = copyRepository() atom.project.setPaths([workingDirectory]) // When the path is added to the project, the repository is refreshed. We @@ -512,10 +513,9 @@ describe('GitRepositoryAsync', () => { }) it('emits a status-changed event when a buffer is reloaded', async () => { + fs.writeFileSync(path.join(workingDirectory, 'other.txt'), 'changed') const editor = await atom.workspace.open('other.txt') - fs.writeFileSync(editor.getPath(), 'changed') - const statusHandler = jasmine.createSpy('statusHandler') repo.onDidChangeStatus(statusHandler) editor.getBuffer().reload() diff --git a/spec/git-spec.coffee b/spec/git-spec.coffee index 3afd4da75..db42f3fc8 100644 --- a/spec/git-spec.coffee +++ b/spec/git-spec.coffee @@ -290,10 +290,11 @@ describe "GitRepository", -> expect(repo.isStatusNew(status)).toBe false describe "buffer events", -> - [editor] = [] + [editor, workingDirectory] = [] beforeEach -> - atom.project.setPaths([copyRepository()]) + workingDirectory = copyRepository() + atom.project.setPaths([workingDirectory]) waitsForPromise -> atom.workspace.open('other.txt').then (o) -> editor = o @@ -310,13 +311,16 @@ describe "GitRepository", -> it "emits a status-changed event when a buffer is reloaded", -> fs.writeFileSync(editor.getPath(), 'changed') - statusHandler = jasmine.createSpy('statusHandler') - atom.project.getRepositories()[0].onDidChangeStatus statusHandler - editor.getBuffer().reload() - expect(statusHandler.callCount).toBe 1 - expect(statusHandler).toHaveBeenCalledWith {path: editor.getPath(), pathStatus: 256} - editor.getBuffer().reload() - expect(statusHandler.callCount).toBe 1 + waitsForPromise -> + atom.workspace.open(path.join(workingDirectory, 'other.txt')).then (o) -> editor = o + runs -> + statusHandler = jasmine.createSpy('statusHandler') + atom.project.getRepositories()[0].onDidChangeStatus statusHandler + editor.getBuffer().reload() + expect(statusHandler.callCount).toBe 1 + expect(statusHandler).toHaveBeenCalledWith {path: editor.getPath(), pathStatus: 256} + editor.getBuffer().reload() + expect(statusHandler.callCount).toBe 1 it "emits a status-changed event when a buffer's path changes", -> fs.writeFileSync(editor.getPath(), 'changed') From 952f4aae0e4f3be06b5896c06a22973dbb19e5c9 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 25 Mar 2016 14:33:43 -0400 Subject: [PATCH 245/273] Revert "Skip the first reload event." This reverts commit 7294b95b70dd2b4be55a970e5e399eda5289b9fd. --- src/git-repository-async.js | 8 +------- src/git-repository.coffee | 9 +-------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/git-repository-async.js b/src/git-repository-async.js index edd85390b..56b8ae117 100644 --- a/src/git-repository-async.js +++ b/src/git-repository-async.js @@ -1058,15 +1058,9 @@ export default class GitRepositoryAsync { } } - // TextBuffers will emit a reload event when they're first loaded. We don't - // need to refresh in that case. - let firstReload = true bufferSubscriptions.add( buffer.onDidSave(refreshStatusForBuffer), - buffer.onDidReload(() => { - if (!firstReload) refreshStatusForBuffer() - firstReload = false - }), + buffer.onDidReload(refreshStatusForBuffer), buffer.onDidChangePath(refreshStatusForBuffer), buffer.onDidDestroy(() => { bufferSubscriptions.dispose() diff --git a/src/git-repository.coffee b/src/git-repository.coffee index bc4f57161..0513c2293 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -448,14 +448,7 @@ class GitRepository bufferSubscriptions = new CompositeDisposable bufferSubscriptions.add buffer.onDidSave(getBufferPathStatus) - - # TextBuffers will emit a reload event when they're first loaded. We don't - # need to refresh in that case. - firstReload = true - bufferSubscriptions.add buffer.onDidReload(-> - getBufferPathStatus() unless firstReload - firstReload = false - ) + bufferSubscriptions.add buffer.onDidReload(getBufferPathStatus) bufferSubscriptions.add buffer.onDidChangePath(getBufferPathStatus) bufferSubscriptions.add buffer.onDidDestroy => bufferSubscriptions.dispose() From 1548ceff4add8e4ac6e87964046dc847436319d3 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 25 Mar 2016 12:57:47 -0600 Subject: [PATCH 246/273] :arrow_up: text-buffer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 267aed7ed..5a8b87319 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "service-hub": "^0.7.0", "source-map-support": "^0.3.2", "temp": "0.8.1", - "text-buffer": "8.4.2", + "text-buffer": "8.4.3", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "yargs": "^3.23.0" From 2f58c404726e7e8949a8263be58f1f811ad1b4e4 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 25 Mar 2016 15:12:06 -0400 Subject: [PATCH 247/273] Pass subscriptions through to the async layer. --- src/git-repository.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/git-repository.coffee b/src/git-repository.coffee index 0513c2293..87fa488da 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -136,7 +136,7 @@ class GitRepository # # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. onDidDestroy: (callback) -> - @emitter.on 'did-destroy', callback + @async.onDidDestroy callback ### Section: Event Subscription @@ -154,7 +154,7 @@ class GitRepository # # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. onDidChangeStatus: (callback) -> - @emitter.on 'did-change-status', callback + @async.onDidChangeStatus callback # Public: Invoke the given callback when a multiple files' statuses have # changed. For example, on window focus, the status of all the paths in the @@ -165,7 +165,7 @@ class GitRepository # # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. onDidChangeStatuses: (callback) -> - @emitter.on 'did-change-statuses', callback + @async.onDidChangeStatuses callback ### Section: Repository Details From 3aae2054f7a88bc167384afe687a72013a4dc5dd Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 25 Mar 2016 15:14:12 -0400 Subject: [PATCH 248/273] Grab status from the underlying async layer. --- src/git-repository.coffee | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/git-repository.coffee b/src/git-repository.coffee index 87fa488da..6547557d8 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -83,7 +83,6 @@ class GitRepository asyncOptions.subscribeToBuffers = false @async = GitRepositoryAsync.open(path, asyncOptions) - @statuses = {} @upstream = {ahead: 0, behind: 0} for submodulePath, submoduleRepo of @repo.submodules submoduleRepo.upstream = {ahead: 0, behind: 0} @@ -317,7 +316,7 @@ class GitRepository getDirectoryStatus: (directoryPath) -> directoryPath = "#{@relativize(directoryPath)}/" directoryStatus = 0 - for path, status of @statuses + for path, status of @async.getCachedPathStatuses() directoryStatus |= status if path.indexOf(directoryPath) is 0 directoryStatus @@ -333,15 +332,8 @@ class GitRepository repo = @getRepo(path) relativePath = @relativize(path) - currentPathStatus = @statuses[relativePath] ? 0 pathStatus = repo.getStatus(repo.relativize(path)) ? 0 pathStatus = 0 if repo.isStatusIgnored(pathStatus) - if pathStatus > 0 - @statuses[relativePath] = pathStatus - else - delete @statuses[relativePath] - if currentPathStatus isnt pathStatus - @emitter.emit 'did-change-status', {path, pathStatus} pathStatus @@ -351,7 +343,7 @@ class GitRepository # # Returns a status {Number} or null if the path is not in the cache. getCachedPathStatus: (path) -> - @statuses[@relativize(path)] + @async.getCachedPathStatuses()[@relativize(path)] # Public: Returns true if the given status indicates modification. # From 4ecc6aac90961ab8bd3c8211c0acecdc6428f2ee Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 25 Mar 2016 15:14:32 -0400 Subject: [PATCH 249/273] Grab the branch from the async layer. --- src/git-repository.coffee | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/git-repository.coffee b/src/git-repository.coffee index 6547557d8..0e1d3980a 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -470,7 +470,9 @@ class GitRepository # # Returns a promise that resolves when the repository has been refreshed. refreshStatus: -> - asyncRefresh = @async.refreshStatus() + asyncRefresh = @async.refreshStatus().then => + @branch = @async.branch + syncRefresh = new Promise (resolve, reject) => @handlerPath ?= require.resolve('./repository-status-handler') @@ -487,7 +489,6 @@ class GitRepository @statuses = statuses @upstream = upstream - @branch = branch @submodules = submodules for submodulePath, submoduleRepo of @getRepo().submodules From c9ff5db064a4150701530cb959a7b20864524a42 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 25 Mar 2016 15:15:10 -0400 Subject: [PATCH 250/273] Don't update status anymore in the sync layer. --- src/git-repository.coffee | 12 +----------- src/repository-status-handler.coffee | 19 +------------------ 2 files changed, 2 insertions(+), 29 deletions(-) diff --git a/src/git-repository.coffee b/src/git-repository.coffee index 0e1d3980a..a40ee69d1 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -476,18 +476,8 @@ class GitRepository syncRefresh = new Promise (resolve, reject) => @handlerPath ?= require.resolve('./repository-status-handler') - relativeProjectPaths = @project?.getPaths() - .map (path) => @relativize(path) - .map (path) -> if path.length > 0 then path + '/**' else '*' - @statusTask?.terminate() - @statusTask = Task.once @handlerPath, @getPath(), relativeProjectPaths, ({statuses, upstream, branch, submodules}) => - statusesUnchanged = _.isEqual(statuses, @statuses) and - _.isEqual(upstream, @upstream) and - _.isEqual(branch, @branch) and - _.isEqual(submodules, @submodules) - - @statuses = statuses + @statusTask = Task.once @handlerPath, @getPath(), ({upstream, submodules}) => @upstream = upstream @submodules = submodules diff --git a/src/repository-status-handler.coffee b/src/repository-status-handler.coffee index 2fda9a335..adae7bc4f 100644 --- a/src/repository-status-handler.coffee +++ b/src/repository-status-handler.coffee @@ -5,32 +5,15 @@ module.exports = (repoPath, paths = []) -> repo = Git.open(repoPath) upstream = {} - statuses = {} submodules = {} - branch = null if repo? - # Statuses in main repo - workingDirectoryPath = repo.getWorkingDirectory() - repoStatus = (if paths.length > 0 then repo.getStatusForPaths(paths) else repo.getStatus()) - for filePath, status of repoStatus - statuses[filePath] = status - - # Statuses in submodules for submodulePath, submoduleRepo of repo.submodules submodules[submodulePath] = branch: submoduleRepo.getHead() upstream: submoduleRepo.getAheadBehindCount() - workingDirectoryPath = submoduleRepo.getWorkingDirectory() - for filePath, status of submoduleRepo.getStatus() - absolutePath = path.join(workingDirectoryPath, filePath) - # Make path relative to parent repository - relativePath = repo.relativize(absolutePath) - statuses[relativePath] = status - upstream = repo.getAheadBehindCount() - branch = repo.getHead() repo.release() - {statuses, upstream, branch, submodules} + {upstream, submodules} From 380df728084035b6a05a9ed5ef211b45f917306d Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 25 Mar 2016 15:15:24 -0400 Subject: [PATCH 251/273] All emissions will propagate out from the async layer. --- src/git-repository.coffee | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/git-repository.coffee b/src/git-repository.coffee index a40ee69d1..6ab6f3e85 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -1,7 +1,7 @@ {basename, join} = require 'path' _ = require 'underscore-plus' -{Emitter, Disposable, CompositeDisposable} = require 'event-kit' +{Disposable, CompositeDisposable} = require 'event-kit' fs = require 'fs-plus' GitRepositoryAsync = require './git-repository-async' GitUtils = require 'git-utils' @@ -69,7 +69,6 @@ class GitRepository null constructor: (path, options={}) -> - @emitter = new Emitter @subscriptions = new CompositeDisposable @repo = GitUtils.open(path) @@ -107,11 +106,6 @@ class GitRepository # This destroys any tasks and subscriptions and releases the underlying # libgit2 repository handle. This method is idempotent. destroy: -> - if @emitter? - @emitter.emit 'did-destroy' - @emitter.dispose() - @emitter = null - if @statusTask? @statusTask.terminate() @statusTask = null @@ -486,7 +480,4 @@ class GitRepository resolve() - unless statusesUnchanged - @emitter.emit 'did-change-statuses' - return Promise.all([asyncRefresh, syncRefresh]) From f001c832632793ce5a0b7f9f8a2e7271bb43b1c3 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 25 Mar 2016 15:26:18 -0400 Subject: [PATCH 252/273] Bring back some synchronous event emitting. Preserve the previous behavior of emitting synchronously with observed change. --- src/git-repository.coffee | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/git-repository.coffee b/src/git-repository.coffee index 6ab6f3e85..793efd08d 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -1,7 +1,7 @@ {basename, join} = require 'path' _ = require 'underscore-plus' -{Disposable, CompositeDisposable} = require 'event-kit' +{Emitter, Disposable, CompositeDisposable} = require 'event-kit' fs = require 'fs-plus' GitRepositoryAsync = require './git-repository-async' GitUtils = require 'git-utils' @@ -69,6 +69,7 @@ class GitRepository null constructor: (path, options={}) -> + @emitter = new Emitter @subscriptions = new CompositeDisposable @repo = GitUtils.open(path) @@ -86,6 +87,8 @@ class GitRepository for submodulePath, submoduleRepo of @repo.submodules submoduleRepo.upstream = {ahead: 0, behind: 0} + @statusesByPath = {} + {@project, @config, refreshOnWindowFocus} = options refreshOnWindowFocus ?= true @@ -106,6 +109,11 @@ class GitRepository # This destroys any tasks and subscriptions and releases the underlying # libgit2 repository handle. This method is idempotent. destroy: -> + if @emitter? + @emitter.emit 'did-destroy' + @emitter.dispose() + @emitter = null + if @statusTask? @statusTask.terminate() @statusTask = null @@ -129,7 +137,7 @@ class GitRepository # # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. onDidDestroy: (callback) -> - @async.onDidDestroy callback + @emitter.on 'did-destroy', callback ### Section: Event Subscription @@ -147,7 +155,7 @@ class GitRepository # # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. onDidChangeStatus: (callback) -> - @async.onDidChangeStatus callback + @emitter.on 'did-change-status', callback # Public: Invoke the given callback when a multiple files' statuses have # changed. For example, on window focus, the status of all the paths in the @@ -321,13 +329,22 @@ class GitRepository # Returns a {Number} representing the status. This value can be passed to # {::isStatusModified} or {::isStatusNew} to get more information. getPathStatus: (path) -> + repo = @getRepo(path) + relativePath = @relativize(path) + currentPathStatus = @statusesByPath[relativePath] ? @async.getCachedPathStatuses()[relativePath] ? 0 + # Trigger events emitted on the async repo as well @async.refreshStatusForPath(path) - repo = @getRepo(path) - relativePath = @relativize(path) pathStatus = repo.getStatus(repo.relativize(path)) ? 0 pathStatus = 0 if repo.isStatusIgnored(pathStatus) + if pathStatus > 0 + @statusesByPath[relativePath] = pathStatus + else + delete @statusesByPath[relativePath] + + if currentPathStatus isnt pathStatus + @emitter.emit 'did-change-status', {path, pathStatus} pathStatus @@ -465,6 +482,7 @@ class GitRepository # Returns a promise that resolves when the repository has been refreshed. refreshStatus: -> asyncRefresh = @async.refreshStatus().then => + @statusesByPath = {} @branch = @async.branch syncRefresh = new Promise (resolve, reject) => From fff1e8f3d1a3ef4b99f0625ec24f803412e4d788 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 25 Mar 2016 15:36:44 -0400 Subject: [PATCH 253/273] Cache the results of calling getPathStatus so we're consistent across calls. --- src/git-repository.coffee | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/git-repository.coffee b/src/git-repository.coffee index 793efd08d..27f7d7b7d 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -318,7 +318,7 @@ class GitRepository getDirectoryStatus: (directoryPath) -> directoryPath = "#{@relativize(directoryPath)}/" directoryStatus = 0 - for path, status of @async.getCachedPathStatuses() + for path, status of _.extend({}, @async.getCachedPathStatuses(), @statusesByPath) directoryStatus |= status if path.indexOf(directoryPath) is 0 directoryStatus @@ -331,7 +331,16 @@ class GitRepository getPathStatus: (path) -> repo = @getRepo(path) relativePath = @relativize(path) - currentPathStatus = @statusesByPath[relativePath] ? @async.getCachedPathStatuses()[relativePath] ? 0 + + # This is a bit particular. If a package calls `getPathStatus` like this: + # - change the file + # - getPathStatus + # - change the file + # - getPathStatus + # We need to preserve the guarantee that each call to `getPathStatus` will + # synchronously emit 'did-change-status'. So we need to keep a cache of the + # statuses found from this call. + currentPathStatus = @getCachedRelativePathStatus(relativePath) ? 0 # Trigger events emitted on the async repo as well @async.refreshStatusForPath(path) @@ -354,7 +363,11 @@ class GitRepository # # Returns a status {Number} or null if the path is not in the cache. getCachedPathStatus: (path) -> - @async.getCachedPathStatuses()[@relativize(path)] + relativePath = @relativize(path) + @getCachedRelativePathStatus(relativePath) + + getCachedRelativePathStatus: (relativePath) -> + @statusesByPath[relativePath] ? @async.getCachedPathStatuses()[relativePath] # Public: Returns true if the given status indicates modification. # From 6b26863012905187d199d34fb755c080c5384858 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 25 Mar 2016 15:41:05 -0400 Subject: [PATCH 254/273] Revert "Fix the specs." This reverts commit 39dcd59994d11e1cefde849bb5080f47460eb69f. --- spec/git-repository-async-spec.js | 6 +++--- spec/git-spec.coffee | 22 +++++++++------------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/spec/git-repository-async-spec.js b/spec/git-repository-async-spec.js index 25623ae27..900d81bfb 100644 --- a/spec/git-repository-async-spec.js +++ b/spec/git-repository-async-spec.js @@ -483,10 +483,9 @@ describe('GitRepositoryAsync', () => { describe('buffer events', () => { let repo - let workingDirectory beforeEach(() => { - workingDirectory = copyRepository() + const workingDirectory = copyRepository() atom.project.setPaths([workingDirectory]) // When the path is added to the project, the repository is refreshed. We @@ -513,9 +512,10 @@ describe('GitRepositoryAsync', () => { }) it('emits a status-changed event when a buffer is reloaded', async () => { - fs.writeFileSync(path.join(workingDirectory, 'other.txt'), 'changed') const editor = await atom.workspace.open('other.txt') + fs.writeFileSync(editor.getPath(), 'changed') + const statusHandler = jasmine.createSpy('statusHandler') repo.onDidChangeStatus(statusHandler) editor.getBuffer().reload() diff --git a/spec/git-spec.coffee b/spec/git-spec.coffee index db42f3fc8..3afd4da75 100644 --- a/spec/git-spec.coffee +++ b/spec/git-spec.coffee @@ -290,11 +290,10 @@ describe "GitRepository", -> expect(repo.isStatusNew(status)).toBe false describe "buffer events", -> - [editor, workingDirectory] = [] + [editor] = [] beforeEach -> - workingDirectory = copyRepository() - atom.project.setPaths([workingDirectory]) + atom.project.setPaths([copyRepository()]) waitsForPromise -> atom.workspace.open('other.txt').then (o) -> editor = o @@ -311,16 +310,13 @@ describe "GitRepository", -> it "emits a status-changed event when a buffer is reloaded", -> fs.writeFileSync(editor.getPath(), 'changed') - waitsForPromise -> - atom.workspace.open(path.join(workingDirectory, 'other.txt')).then (o) -> editor = o - runs -> - statusHandler = jasmine.createSpy('statusHandler') - atom.project.getRepositories()[0].onDidChangeStatus statusHandler - editor.getBuffer().reload() - expect(statusHandler.callCount).toBe 1 - expect(statusHandler).toHaveBeenCalledWith {path: editor.getPath(), pathStatus: 256} - editor.getBuffer().reload() - expect(statusHandler.callCount).toBe 1 + statusHandler = jasmine.createSpy('statusHandler') + atom.project.getRepositories()[0].onDidChangeStatus statusHandler + editor.getBuffer().reload() + expect(statusHandler.callCount).toBe 1 + expect(statusHandler).toHaveBeenCalledWith {path: editor.getPath(), pathStatus: 256} + editor.getBuffer().reload() + expect(statusHandler.callCount).toBe 1 it "emits a status-changed event when a buffer's path changes", -> fs.writeFileSync(editor.getPath(), 'changed') From 8ee1c3274ba9ee9f2ef9388ea0aa27ec5a9de4cd Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 25 Mar 2016 17:13:06 -0400 Subject: [PATCH 255/273] Always update the cached status path. --- src/git-repository.coffee | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/git-repository.coffee b/src/git-repository.coffee index 27f7d7b7d..2821ea42f 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -347,10 +347,7 @@ class GitRepository pathStatus = repo.getStatus(repo.relativize(path)) ? 0 pathStatus = 0 if repo.isStatusIgnored(pathStatus) - if pathStatus > 0 - @statusesByPath[relativePath] = pathStatus - else - delete @statusesByPath[relativePath] + @statusesByPath[relativePath] = pathStatus if currentPathStatus isnt pathStatus @emitter.emit 'did-change-status', {path, pathStatus} From fdebbf12acd266600d6564eb2bdf1fa612e28643 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 25 Mar 2016 17:14:09 -0400 Subject: [PATCH 256/273] If we're been destroyed then we won't have an async anymore. --- src/git-repository.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/git-repository.coffee b/src/git-repository.coffee index 2821ea42f..30d99791d 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -493,7 +493,7 @@ class GitRepository refreshStatus: -> asyncRefresh = @async.refreshStatus().then => @statusesByPath = {} - @branch = @async.branch + @branch = @async?.branch syncRefresh = new Promise (resolve, reject) => @handlerPath ?= require.resolve('./repository-status-handler') From 5fc111a104e389959a94acd4cb6a31619e073814 Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Sat, 26 Mar 2016 15:50:07 -0700 Subject: [PATCH 257/273] :memo: Add standard global notation --- src/notification-manager.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/notification-manager.coffee b/src/notification-manager.coffee index 46c781c20..3d8b1895c 100644 --- a/src/notification-manager.coffee +++ b/src/notification-manager.coffee @@ -3,6 +3,9 @@ Notification = require '../src/notification' # Public: A notification manager used to create {Notification}s to be shown # to the user. +# +# An instance of this class is always available as the `atom.notifications` +# global. module.exports = class NotificationManager constructor: -> From b5f866b6fc5f3110d263c2ae323d1588d84885e9 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 28 Mar 2016 14:49:26 +0200 Subject: [PATCH 258/273] Correctly (un)subscribe to model events on PaneAxisElement attach/detach --- spec/pane-axis-element-spec.coffee | 34 +++++++++++++++++++++ spec/pane-container-element-spec.coffee | 6 ++++ src/pane-axis-element.coffee | 39 ++++++++++++++++--------- 3 files changed, 65 insertions(+), 14 deletions(-) create mode 100644 spec/pane-axis-element-spec.coffee diff --git a/spec/pane-axis-element-spec.coffee b/spec/pane-axis-element-spec.coffee new file mode 100644 index 000000000..702e9c5fc --- /dev/null +++ b/spec/pane-axis-element-spec.coffee @@ -0,0 +1,34 @@ +PaneAxis = require '../src/pane-axis' +PaneContainer = require '../src/pane-container' +Pane = require '../src/pane' + +buildPane = -> + new Pane({ + applicationDelegate: atom.applicationDelegate, + config: atom.config, + deserializerManager: atom.deserializers, + notificationManager: atom.notifications + }) + +describe "PaneAxisElement", -> + it "correctly subscribes and unsubscribes to the underlying model events on attach/detach", -> + container = new PaneContainer(config: atom.config, applicationDelegate: atom.applicationDelegate) + axis = new PaneAxis + axis.setContainer(container) + axisElement = atom.views.getView(axis) + + panes = [buildPane(), buildPane(), buildPane()] + + jasmine.attachToDOM(axisElement) + axis.addChild(panes[0]) + expect(axisElement.children[0]).toBe(atom.views.getView(panes[0])) + + axisElement.remove() + axis.addChild(panes[1]) + expect(axisElement.children[2]).toBeUndefined() + + jasmine.attachToDOM(axisElement) + expect(axisElement.children[2]).toBe(atom.views.getView(panes[1])) + + axis.addChild(panes[2]) + expect(axisElement.children[4]).toBe(atom.views.getView(panes[2])) diff --git a/spec/pane-container-element-spec.coffee b/spec/pane-container-element-spec.coffee index fe57e89af..f56d12fe6 100644 --- a/spec/pane-container-element-spec.coffee +++ b/spec/pane-container-element-spec.coffee @@ -10,6 +10,7 @@ describe "PaneContainerElement", -> paneAxis = new PaneAxis paneAxisElement = new PaneAxisElement().initialize(paneAxis, atom) + jasmine.attachToDOM(paneAxisElement) expect(childTagNames()).toEqual [] @@ -41,6 +42,8 @@ describe "PaneContainerElement", -> 'atom-pane-axis' ] + paneAxisElement.remove() + it "transfers focus to the next pane if a focused pane is removed", -> container = new PaneContainer(config: atom.config, confirm: atom.confirm.bind(atom)) containerElement = atom.views.getView(container) @@ -60,6 +63,7 @@ describe "PaneContainerElement", -> it "builds appropriately-oriented atom-pane-axis elements", -> container = new PaneContainer(config: atom.config, confirm: atom.confirm.bind(atom)) containerElement = atom.views.getView(container) + jasmine.attachToDOM(containerElement) pane1 = container.getActivePane() pane2 = pane1.splitRight() @@ -80,6 +84,8 @@ describe "PaneContainerElement", -> expect(verticalPanes[0]).toBe atom.views.getView(pane2) expect(verticalPanes[1]).toBe atom.views.getView(pane3) + containerElement.remove() + describe "when the resize element is dragged ", -> [container, containerElement] = [] diff --git a/src/pane-axis-element.coffee b/src/pane-axis-element.coffee index eaa26a9fe..363f895c6 100644 --- a/src/pane-axis-element.coffee +++ b/src/pane-axis-element.coffee @@ -2,20 +2,8 @@ PaneResizeHandleElement = require './pane-resize-handle-element' class PaneAxisElement extends HTMLElement - createdCallback: -> - @subscriptions = new CompositeDisposable - - detachedCallback: -> - @subscriptions.dispose() - - initialize: (@model, {@views}) -> - throw new Error("Must pass a views parameter when initializing TextEditorElements") unless @views? - - @subscriptions.add @model.onDidAddChild(@childAdded.bind(this)) - @subscriptions.add @model.onDidRemoveChild(@childRemoved.bind(this)) - @subscriptions.add @model.onDidReplaceChild(@childReplaced.bind(this)) - @subscriptions.add @model.observeFlexScale(@flexScaleChanged.bind(this)) - + attachedCallback: -> + @subscriptions ?= @subscribeToModel() @childAdded({child, index}) for child, index in @model.getChildren() switch @model.getOrientation() @@ -23,8 +11,31 @@ class PaneAxisElement extends HTMLElement @classList.add('horizontal', 'pane-row') when 'vertical' @classList.add('vertical', 'pane-column') + + detachedCallback: -> + @subscriptions.dispose() + @subscriptions = null + @childRemoved({child}) for child in @model.getChildren() + + switch @model.getOrientation() + when 'horizontal' + @classList.remove('horizontal', 'pane-row') + when 'vertical' + @classList.remove('vertical', 'pane-column') + + initialize: (@model, {@views}) -> + throw new Error("Must pass a views parameter when initializing TextEditorElements") unless @views? + this + subscribeToModel: -> + subscriptions = new CompositeDisposable + subscriptions.add @model.onDidAddChild(@childAdded.bind(this)) + subscriptions.add @model.onDidRemoveChild(@childRemoved.bind(this)) + subscriptions.add @model.onDidReplaceChild(@childReplaced.bind(this)) + subscriptions.add @model.observeFlexScale(@flexScaleChanged.bind(this)) + subscriptions + isPaneResizeHandleElement: (element) -> element?.nodeName.toLowerCase() is 'atom-pane-resize-handle' From 3d4611ce4ca8597cd10c8700d22248cd25590e44 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 28 Mar 2016 14:52:40 +0200 Subject: [PATCH 259/273] Remove conditional assignment HTML nodes are guaranteed to be detached before being re-attached, so we are always sure that `subscriptions` is null on attach and non-null on detach. --- src/pane-axis-element.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pane-axis-element.coffee b/src/pane-axis-element.coffee index 363f895c6..ee8019bb1 100644 --- a/src/pane-axis-element.coffee +++ b/src/pane-axis-element.coffee @@ -3,7 +3,7 @@ PaneResizeHandleElement = require './pane-resize-handle-element' class PaneAxisElement extends HTMLElement attachedCallback: -> - @subscriptions ?= @subscribeToModel() + @subscriptions = @subscribeToModel() @childAdded({child, index}) for child, index in @model.getChildren() switch @model.getOrientation() From 8adf47b1c2fb902ab2f60b0feaf6790680c37b70 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 28 Mar 2016 16:40:39 +0200 Subject: [PATCH 260/273] Allow element to work without attaching it to DOM --- spec/pane-container-element-spec.coffee | 6 ------ src/pane-axis-element.coffee | 27 ++++++++++--------------- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/spec/pane-container-element-spec.coffee b/spec/pane-container-element-spec.coffee index f56d12fe6..fe57e89af 100644 --- a/spec/pane-container-element-spec.coffee +++ b/spec/pane-container-element-spec.coffee @@ -10,7 +10,6 @@ describe "PaneContainerElement", -> paneAxis = new PaneAxis paneAxisElement = new PaneAxisElement().initialize(paneAxis, atom) - jasmine.attachToDOM(paneAxisElement) expect(childTagNames()).toEqual [] @@ -42,8 +41,6 @@ describe "PaneContainerElement", -> 'atom-pane-axis' ] - paneAxisElement.remove() - it "transfers focus to the next pane if a focused pane is removed", -> container = new PaneContainer(config: atom.config, confirm: atom.confirm.bind(atom)) containerElement = atom.views.getView(container) @@ -63,7 +60,6 @@ describe "PaneContainerElement", -> it "builds appropriately-oriented atom-pane-axis elements", -> container = new PaneContainer(config: atom.config, confirm: atom.confirm.bind(atom)) containerElement = atom.views.getView(container) - jasmine.attachToDOM(containerElement) pane1 = container.getActivePane() pane2 = pane1.splitRight() @@ -84,8 +80,6 @@ describe "PaneContainerElement", -> expect(verticalPanes[0]).toBe atom.views.getView(pane2) expect(verticalPanes[1]).toBe atom.views.getView(pane3) - containerElement.remove() - describe "when the resize element is dragged ", -> [container, containerElement] = [] diff --git a/src/pane-axis-element.coffee b/src/pane-axis-element.coffee index ee8019bb1..07439b914 100644 --- a/src/pane-axis-element.coffee +++ b/src/pane-axis-element.coffee @@ -3,7 +3,17 @@ PaneResizeHandleElement = require './pane-resize-handle-element' class PaneAxisElement extends HTMLElement attachedCallback: -> - @subscriptions = @subscribeToModel() + @subscriptions ?= @subscribeToModel() + @childAdded({child, index}) for child, index in @model.getChildren() + + detachedCallback: -> + @subscriptions.dispose() + @subscriptions = null + @childRemoved({child}) for child in @model.getChildren() + + initialize: (@model, {@views}) -> + throw new Error("Must pass a views parameter when initializing TextEditorElements") unless @views? + @subscriptions ?= @subscribeToModel() @childAdded({child, index}) for child, index in @model.getChildren() switch @model.getOrientation() @@ -11,21 +21,6 @@ class PaneAxisElement extends HTMLElement @classList.add('horizontal', 'pane-row') when 'vertical' @classList.add('vertical', 'pane-column') - - detachedCallback: -> - @subscriptions.dispose() - @subscriptions = null - @childRemoved({child}) for child in @model.getChildren() - - switch @model.getOrientation() - when 'horizontal' - @classList.remove('horizontal', 'pane-row') - when 'vertical' - @classList.remove('vertical', 'pane-column') - - initialize: (@model, {@views}) -> - throw new Error("Must pass a views parameter when initializing TextEditorElements") unless @views? - this subscribeToModel: -> From 22665c24d1fd87e050b61d994b145941b79c2183 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 28 Mar 2016 13:38:25 -0400 Subject: [PATCH 261/273] :arrow_up: tree-view@0.203.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5a8b87319..c0d50aba4 100644 --- a/package.json +++ b/package.json @@ -112,7 +112,7 @@ "symbols-view": "0.112.0", "tabs": "0.92.0", "timecop": "0.33.1", - "tree-view": "0.203.2", + "tree-view": "0.203.3", "update-package-dependencies": "0.10.0", "welcome": "0.34.0", "whitespace": "0.32.2", From 51831b332d3296db2c8b31bc0a1d8f01b9e0b4e7 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 28 Mar 2016 14:50:04 -0400 Subject: [PATCH 262/273] Take the submodule into account in more instances. Fixes https://github.com/atom/git-diff/issues/97. --- src/git-repository-async.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/git-repository-async.js b/src/git-repository-async.js index 82546b525..fe81890d3 100644 --- a/src/git-repository-async.js +++ b/src/git-repository-async.js @@ -596,7 +596,7 @@ export default class GitRepositoryAsync { // * `added` The {Number} of added lines. // * `deleted` The {Number} of deleted lines. getDiffStats (_path) { - return this.getRepo() + return this.getRepo(_path) .then(repo => Promise.all([repo, repo.getHeadCommit()])) .then(([repo, headCommit]) => Promise.all([repo, headCommit.getTree()])) .then(([repo, tree]) => { @@ -640,7 +640,7 @@ export default class GitRepositoryAsync { // * `newLines` The {Number} of lines in the new hunk getLineDiffs (_path, text) { let relativePath = null - return this.getRepo() + return this.getRepo(_path) .then(repo => { relativePath = this.relativize(_path, repo.workdir()) return repo.getHeadCommit() @@ -678,7 +678,7 @@ export default class GitRepositoryAsync { // Returns a {Promise} that resolves or rejects depending on whether the // method was successful. checkoutHead (_path) { - return this.getRepo() + return this.getRepo(_path) .then(repo => { const checkoutOptions = new Git.CheckoutOptions() checkoutOptions.paths = [this.relativize(_path, repo.workdir())] From 5b722fe0b742c582be52a5a10db29b65bc285d23 Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 28 Mar 2016 14:54:27 -0400 Subject: [PATCH 263/273] :arrow_up: nodegit@0.12.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c0d50aba4..57374cc62 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "less-cache": "0.23", "line-top-index": "0.2.0", "marked": "^0.3.4", - "nodegit": "0.11.9", + "nodegit": "0.12.0", "normalize-package-data": "^2.0.0", "nslog": "^3", "oniguruma": "^5", From 76f9f43e6aec3d53b1b23b893648eac238090a60 Mon Sep 17 00:00:00 2001 From: Damien Guard Date: Tue, 22 Mar 2016 17:26:30 -0700 Subject: [PATCH 264/273] Fix clean command to actually work when paths missing --- script/clean | 50 +++++++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/script/clean b/script/clean index 0c947baf2..cc4933f95 100755 --- a/script/clean +++ b/script/clean @@ -1,11 +1,10 @@ #!/usr/bin/env node -var cp = require('./utils/child-process-wrapper.js'); +var childProcess = require('./utils/child-process-wrapper.js'); var fs = require('fs'); var path = require('path'); var os = require('os'); var isWindows = process.platform === 'win32'; -var removeCommand = isWindows ? 'rmdir /S /Q ' : 'rm -rf '; var productName = require('../package.json').productName; process.chdir(path.dirname(__dirname)); @@ -13,10 +12,10 @@ var home = process.env[isWindows ? 'USERPROFILE' : 'HOME']; var tmpdir = os.tmpdir(); // Windows: Use START as a way to ignore error if Atom.exe isnt running -var killatom = isWindows ? 'START taskkill /F /IM ' + productName + '.exe' : 'pkill -9 ' + productName + ' || true'; +var killAtomCommand = isWindows ? 'START taskkill /F /IM ' + productName + '.exe' : 'pkill -9 ' + productName + ' || true'; +//childProcess.safeExec(killAtomCommand); -var commands = [ - killatom, +var pathsToRemove = [ [__dirname, '..', 'node_modules'], [__dirname, '..', 'build', 'node_modules'], [__dirname, '..', 'apm', 'node_modules'], @@ -32,37 +31,30 @@ var commands = [ [home, '.atom', 'electron'], [tmpdir, 'atom-build'], [tmpdir, 'atom-cached-atom-shells'], -]; -var run = function() { - var next = commands.shift(); - if (!next) - process.exit(0); +].map(function(pathSegments) { + return path.resolve.apply(null, pathSegments); +}); - if (Array.isArray(next)) { - var pathToRemove = path.resolve.apply(path.resolve, next); - if (fs.existsSync(pathToRemove)) { - if (isWindows) { - removeFolderRecursive(pathToRemove); - } else { - next = removeCommand + pathToRemove; - cp.safeExec(next, run); - } - } - else { - return run(); - } +pathsToRemove.forEach(function(pathToRemove) { + if (fs.existsSync(pathToRemove)) { + removePath(pathToRemove); } - else - cp.safeExec(next, run); -}; -run(); +}); + +function removePath(pathToRemove) { + if (isWindows) { + removePathOnWindows(pathToRemove); + } else { + childProcess.safeExec('rm -rf ' + pathToRemove); + } +} // Windows has a 260-char path limit for rmdir etc. Just recursively delete in Node. -var removeFolderRecursive = function(folderPath) { +function removePathOnWindows(folderPath) { fs.readdirSync(folderPath).forEach(function(entry, index) { var entryPath = path.join(folderPath, entry); if (fs.lstatSync(entryPath).isDirectory()) { - removeFolderRecursive(entryPath); + removePathOnWindows(entryPath); } else { fs.unlinkSync(entryPath); } From df4e552596663b066927dd88db06a801f96c4185 Mon Sep 17 00:00:00 2001 From: Damien Guard Date: Tue, 22 Mar 2016 17:26:41 -0700 Subject: [PATCH 265/273] Exclude PATH entries with msbuild.exe to fix node-gyp on Windows --- script/build | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/script/build b/script/build index a40a02e13..ca5569d0f 100755 --- a/script/build +++ b/script/build @@ -2,9 +2,24 @@ var cp = require('./utils/child-process-wrapper.js'); var runGrunt = require('./utils/run-grunt.js'); var path = require('path'); +var fs = require('fs'); process.chdir(path.dirname(__dirname)); +if (process.platform === 'win32') { + process.env['PATH'] = process.env['PATH'] + .split(';') + .filter(function(p) { + if (fs.existsSync(path.resolve(p, 'msbuild.exe'))) { + console.log('Excluding "' + p + '" from PATH to avoid msbuild.exe mismatch') + return false; + } else { + return true; + } + }) + .join(';'); +} + cp.safeExec('node script/bootstrap', function() { // build/node_modules/.bin/grunt "$@" var args = process.argv.slice(2); From 8d2de5fe73e95f216a28c46f16cefc1a88c2b446 Mon Sep 17 00:00:00 2001 From: Damien Guard Date: Tue, 22 Mar 2016 18:10:12 -0700 Subject: [PATCH 266/273] :art: --- build/tasks/codesign-task.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/tasks/codesign-task.coffee b/build/tasks/codesign-task.coffee index 6c99795c0..2a061742b 100644 --- a/build/tasks/codesign-task.coffee +++ b/build/tasks/codesign-task.coffee @@ -3,7 +3,7 @@ path = require 'path' module.exports = (grunt) -> {spawn} = require('./task-helpers')(grunt) - grunt.registerTask 'codesign:exe', 'Codesign atom.exe and Update.exe', -> + grunt.registerTask 'codesign:exe', 'CodeSign Atom.exe and Update.exe', -> done = @async() spawn {cmd: 'taskkill', args: ['/F', '/IM', 'atom.exe']}, -> cmd = process.env.JANKY_SIGNTOOL ? 'signtool' @@ -14,13 +14,13 @@ module.exports = (grunt) -> updateExePath = path.resolve(__dirname, '..', 'node_modules', 'grunt-electron-installer', 'vendor', 'Update.exe') spawn {cmd, args: [updateExePath]}, (error) -> done(error) - grunt.registerTask 'codesign:installer', 'Codesign AtomSetup.exe', -> + grunt.registerTask 'codesign:installer', 'CodeSign AtomSetup.exe', -> done = @async() cmd = process.env.JANKY_SIGNTOOL ? 'signtool' atomSetupExePath = path.resolve(grunt.config.get('atom.buildDir'), 'installer', 'AtomSetup.exe') spawn {cmd, args: [atomSetupExePath]}, (error) -> done(error) - grunt.registerTask 'codesign:app', 'Codesign Atom.app', -> + grunt.registerTask 'codesign:app', 'CodeSign Atom.app', -> done = @async() unlockKeychain (error) -> From 36c6e892969d24312da0ac5381dd1c53dbe4a99f Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Mon, 28 Mar 2016 18:49:11 -0400 Subject: [PATCH 267/273] :arrow_up: language-c@0.51.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 57374cc62..5c6d08e66 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "welcome": "0.34.0", "whitespace": "0.32.2", "wrap-guide": "0.38.1", - "language-c": "0.51.1", + "language-c": "0.51.2", "language-clojure": "0.20.0", "language-coffee-script": "0.46.1", "language-csharp": "0.12.0", From e547cac79587ad095fba71ab9b98d2cadbc61911 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Mon, 28 Mar 2016 18:49:29 -0400 Subject: [PATCH 268/273] :arrow_up: language-less@0.29.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5c6d08e66..0234a4196 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,7 @@ "language-java": "0.17.0", "language-javascript": "0.110.0", "language-json": "0.17.6", - "language-less": "0.29.0", + "language-less": "0.29.1", "language-make": "0.21.0", "language-mustache": "0.13.0", "language-objective-c": "0.15.1", From 9063173ba30ba3dcab3af773b32530cf524e2be6 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Mon, 28 Mar 2016 18:49:47 -0400 Subject: [PATCH 269/273] :arrow_up: language-python@0.43.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0234a4196..32d66ebf2 100644 --- a/package.json +++ b/package.json @@ -137,7 +137,7 @@ "language-perl": "0.32.0", "language-php": "0.37.0", "language-property-list": "0.8.0", - "language-python": "0.43.0", + "language-python": "0.43.1", "language-ruby": "0.68.3", "language-ruby-on-rails": "0.25.0", "language-sass": "0.46.0", From ce26b2f7d815327fbc2a96246561a6652e9a7e21 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Mon, 28 Mar 2016 18:50:07 -0400 Subject: [PATCH 270/273] :arrow_up: language-ruby@0.68.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 32d66ebf2..896cbe363 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "language-php": "0.37.0", "language-property-list": "0.8.0", "language-python": "0.43.1", - "language-ruby": "0.68.3", + "language-ruby": "0.68.4", "language-ruby-on-rails": "0.25.0", "language-sass": "0.46.0", "language-shellscript": "0.21.1", From 435dcc7bdbea89e18020a90aac0bdcf1ed97e648 Mon Sep 17 00:00:00 2001 From: Wliu <50Wliu@users.noreply.github.com> Date: Mon, 28 Mar 2016 21:15:16 -0400 Subject: [PATCH 271/273] :arrow_up: language-json@0.18.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 896cbe363..dbeb5c61c 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "language-hyperlink": "0.16.0", "language-java": "0.17.0", "language-javascript": "0.110.0", - "language-json": "0.17.6", + "language-json": "0.18.0", "language-less": "0.29.1", "language-make": "0.21.0", "language-mustache": "0.13.0", From 4b3ca21e2909802b6ba86de40c0d56548f811793 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 29 Mar 2016 11:26:39 -0400 Subject: [PATCH 272/273] Cache the workdir per-repo. --- src/git-repository-async.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/git-repository-async.js b/src/git-repository-async.js index 931bbb949..17d293c14 100644 --- a/src/git-repository-async.js +++ b/src/git-repository-async.js @@ -43,7 +43,6 @@ export default class GitRepositoryAsync { this.emitter = new Emitter() this.subscriptions = new CompositeDisposable() this.pathStatusCache = {} - this.workdir = null this.path = null // NB: These needs to happen before the following .openRepository call. @@ -157,11 +156,11 @@ export default class GitRepositoryAsync { // directory path of the repository. getWorkingDirectory (_path) { return this.getRepo(_path).then(repo => { - if (!this.workdir) { - this.workdir = repo.workdir() + if (!repo.cachedWorkdir) { + repo.cachedWorkdir = repo.workdir() } - return this.workdir + return repo.cachedWorkdir }) } From edcceeed5bd845bbcaa8a4a0bd838802eb78e6e0 Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Tue, 29 Mar 2016 14:30:07 -0700 Subject: [PATCH 273/273] :arrow_up: apm (cherry picked from commit c6319ea60284fb8fe65f6cbd10873d59cfe697cf) --- apm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apm/package.json b/apm/package.json index ba3415e1d..6623876f9 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "1.9.1" + "atom-package-manager": "1.9.2" } }