From 538500042c7d3878aa0afb7060343ff1e05bf400 Mon Sep 17 00:00:00 2001 From: Collin Donahue-Oponski Date: Mon, 16 Nov 2015 22:05:23 -0700 Subject: [PATCH 01/23] :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 02/23] :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 a62965dc62336f8b344eefc20c8a0440edf69435 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 25 Feb 2016 09:25:13 -0800 Subject: [PATCH 03/23] 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 04/23] 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 05/23] 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 4769e601bf9e3e0595789a276a29f0cd2e1e5b5a Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Mon, 29 Feb 2016 11:27:38 -0800 Subject: [PATCH 06/23] 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 c849216084d248402c3d9a81fe7d55cacc0b7545 Mon Sep 17 00:00:00 2001 From: Jonathan Willis Date: Mon, 29 Feb 2016 14:49:19 -0500 Subject: [PATCH 07/23] 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 9a938064cb72ecce7ebed2a795fd53727591a3f0 Mon Sep 17 00:00:00 2001 From: Lee Dohm Date: Mon, 29 Feb 2016 14:09:01 -0800 Subject: [PATCH 08/23] :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 09/23] 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 10/23] :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 11/23] :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 12/23] 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 13/23] 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 14/23] 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 15/23] 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 16/23] 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 17/23] 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 18/23] :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 19/23] :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 20/23] 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 21/23] 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 22/23] :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 da0ce2a7bde9003b0b432247a13e9d4673729f80 Mon Sep 17 00:00:00 2001 From: Thomas Johansen Date: Tue, 1 Mar 2016 18:54:11 +0100 Subject: [PATCH 23/23] :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,